{ "cells": [ { "cell_type": "markdown", "metadata": { "nbsphinx": "hidden" }, "source": [ "This notebook is part of the `kikuchipy` documentation https://kikuchipy.org.\n", "Links to the documentation won't work from the notebook." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Load and save data\n", "\n", "## Load patterns\n", "\n", "### From a file\n", "\n", "kikuchipy can read or write experimental EBSD patterns and EBSD master patterns\n", "from or to many formats (see [supported formats](#Supported-EBSD-formats)). To\n", "load patterns from a file use the [load()](../reference.rst#kikuchipy.io._io.load)\n", "function. Let's import the necessary libraries and read the Nickel EBSD test\n", "data set directly from file (not via\n", "[kikuchipy.data.nickel_ebsd_small()](../reference.rst#kikuchipy.data.nickel_ebsd_small)):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Exchange inline for notebook or qt5 (from pyqt) for interactive plotting\n", "%matplotlib inline\n", "\n", "import tempfile\n", "import dask.array as da\n", "import hyperspy.api as hs\n", "import kikuchipy as kp\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "\n", "datadir = \"../../kikuchipy/data/\"\n", "nordif_ebsd = \"nordif/Pattern.dat\"\n", "s = kp.load(datadir + nordif_ebsd)\n", "s" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or, load the stereographic projection of the northern hemisphere of an EBSD master\n", "pattern for a 20 keV beam energy from a modified version of EMsoft's master\n", "pattern file, returned from their `EMEBSDmaster.f90` program:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "emsoft_master_pattern = \"emsoft_ebsd_master_pattern/ni_mc_mp_20kv_uint8_gzip_opts9.h5\"\n", "s_mp = kp.load(filename=datadir + emsoft_master_pattern)\n", "s_mp" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Both the stereographic and the square Lambert projections of this master pattern\n", "data is available via\n", "[kikuchipy.data.nickel_ebsd_master_pattern_small()](../reference.rst#kikuchipy.data.nickel_ebsd_master_pattern_small).\n", "\n", "All file readers support accessing the data's metadata without loading it into\n", "memory (with the [Dask library](https://docs.dask.org/en/latest)), which can be\n", "useful when processing large data sets, one data chunk at a time, to avoid memory\n", "errors:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_lazy = kp.load(datadir + nordif_ebsd, lazy=True)\n", "print(s_lazy)\n", "s_lazy.data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Parts or all of the data can be read into memory by calling\n", "[compute()](http://hyperspy.org/hyperspy-doc/current/api/hyperspy._signals.lazy.html#hyperspy._signals.lazy.LazySignal.compute):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_lazy_copy = s_lazy.inav[:2, :].deepcopy()\n", "s_lazy_copy.compute()\n", "s_lazy_copy" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_lazy.compute()\n", "s_lazy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "Note\n", "\n", "When lazily loaded EBSD patterns are processed, they are processed chunk by\n", "chunk, which can lead to longer processing times, so processing lazy\n", "data sets should be done with some care. See the relevant\n", "[HyperSpy user guide](http://hyperspy.org/hyperspy-doc/current/user_guide/big_data.html)\n", "for some tips.\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Data can be visualized by navigating the navigation space, showing the signal\n", "in each navigation point:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s.plot()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Upon loading, kikuchipy tries to read all scan information from the file and\n", "store it in the `original_metadata` attribute:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# s.original_metadata # Long output" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some information may also be stored in a standard location in the `metadata`\n", "attribute, where it can be used by EBSD class methods:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s.metadata" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "Warning\n", "\n", "The `Acquisition_instrument.SEM.Detector.EBSD` and `Sample.Phases` metadata\n", "nodes are deprecated and will be removed in v0.6.\n", "\n", "There are three main reasons for this change: the first is that only the static\n", "background array stored in the\n", "`Acquisition_instrument.SEM.Detector.EBSD.static_background` node is used\n", "internally, and so the remaining metadata is unnecessary. The background pattern\n", "will be stored in its own `EBSD.static_background` property instead. The second\n", "is that keeping track of the unnecessary metadata makes writing and maintaining\n", "input/ouput plugins challenging. The third is that the\n", "[EBSD.xmap](../reference.rst#kikuchipy.signals.EBSD.xmap) and\n", "[EBSD.detector](../reference.rst#kikuchipy.signals.EBSD.detector) properties,\n", "which keeps track of the\n", "[CrystalMap](https://orix.readthedocs.io/en/stable/reference.html#orix.crystal_map.CrystalMap)\n", "and [EBSDDetector](../reference.rst#kikuchipy.detectors.EBSDDetector) for a\n", "signal, respectively, should be used instead of the more \"static\" metadata.\n", "\n", "
\n", "\n", "The number of patterns in horizontal and vertical direction, pattern size in\n", "pixels, scan step size and detector pixel size is stored in the `axes_manager`\n", "attribute:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(s.axes_manager)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This information can be modified directly, and information in `metadata` and\n", "`axes_manager` can be modified by the\n", "[EBSD](../reference.rst#kikuchipy.signals.EBSD) class methods\n", "[set_scan_calibration()](../reference.rst#kikuchipy.signals.EBSD.set_scan_calibration) and\n", "[set_detector_calibration()](../reference.rst#kikuchipy.signals.EBSD.set_detector_calibration).\n", "For example, to set or change detector pixel size:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s.set_experimental_parameters(\n", " beam_energy=15, # kV\n", " xpc=0.5073,\n", " static_background=plt.imread(datadir + \"nordif/Background acquisition pattern.bmp\"),\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In addition to the `metadata`, `original_metadata` and `axes_manager` properties,\n", "kikuchipy tries to read a\n", "[CrystalMap](https://orix.readthedocs.io/en/stable/reference.html#crystalmap) instance\n", "with indexing results into a `xmap` property and an\n", "[EBSDDetector](../reference.rst#kikuchipy.detectors.EBSDDetector)\n", "instance into a `detector` property:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s.xmap # This is None unless it is set or read" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s.detector" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s.static_background # This is None unless it is set" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "Warning\n", "\n", "EBSD methods inherited from HyperSpy that changes the pattern\n", "array in any way, like cropping the navigation shape with\n", "``EBSD.inav``, will not crop the ``CrystalMap`` stored in the\n", "``xmap`` property. This also goes for the detector and static\n", "background pattern properties. Remember for example to crop\n", "the background pattern accordingly before calling\n", "``EBSD.remove_static_background()`` after ``EBSD.isig`` is\n", "used to crop the patterns.\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### From a NumPy array\n", "\n", "An `EBSD` or `EBSDMasterPattern` signal can also be created directly from a\n", "`numpy.ndarray`. To create a data set of (60 x 60) pixel patterns in a\n", "(10 x 20) grid, i.e. 10 and 20 patterns in the horizontal and vertical scan\n", "directions respectively, of random intensities:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_np = kp.signals.EBSD(np.random.random((20, 10, 60, 60)))\n", "s_np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### From a Dask array\n", "\n", "When processing large data sets, it is useful to load data lazily with the\n", "Dask library. This can be done upon reading patterns [from a file](#From-a-file)\n", "by setting `lazy=True` when using the `load()` function, or directly from a\n", "`dask.array.Array`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_da = kp.signals.LazyEBSD(da.random.random((20, 10, 60, 60), chunks=(2, 10, 60, 60)))\n", "print(s_da)\n", "s_da.data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### From a HyperSpy signal\n", "\n", "HyperSpy provides the method\n", "[set_signal_type()](http://hyperspy.org/hyperspy-doc/current/api/hyperspy.signal.html#hyperspy.signal.BaseSignal.set_signal_type)\n", "to change between [BaseSignal](http://hyperspy.org/hyperspy-doc/current/api/hyperspy.signal.html#hyperspy.signal.BaseSignal) subclasses, of which\n", "`EBSD`, `EBSDMasterPattern` and\n", "[VirtualBSEImage](../reference.rst#kikuchipy.signals.VirtualBSEImage) are three. To\n", "get one of these objects from a [HyperSpy Signal2D](http://hyperspy.org/hyperspy-doc/current/api/hyperspy._signals.signal2d.html?highlight=signal2d#hyperspy._signals.signal2d.Signal2D)\n", "object:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_hs = hs.signals.Signal2D(np.random.random((20, 10, 60, 60)))\n", "s_hs" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_hs.set_signal_type(\"EBSD\")\n", "s_hs" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_hs.set_signal_type(\"VirtualBSEImage\")\n", "s_hs" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_hs.set_signal_type(\"EBSDMasterPattern\")\n", "s_hs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Save patterns\n", "\n", "To save experimental EBSD patterns to file use the\n", "[save()](../reference.rst#kikuchipy.signals.EBSD.save) method. For example, to save\n", "an `EBSD` signal in an HDF5 file, with file name `patterns.h5`, in our default\n", "[h5ebsd format](#h5ebsd):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "temp_dir = tempfile.mkdtemp() + \"/\"\n", "s.save(temp_dir + \"patterns\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "Warning\n", "\n", "If we want to overwrite an existing file:\n", "\n", "```python\n", "s.save(\"patterns.h5\", overwrite=True)\n", "```\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we want to save patterns in NORDIF's binary .dat format instead:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s.save(temp_dir + \"patterns.dat\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To save an `EBSDMasterPattern` to an HDF5 file, we use the [save method inherited from HyperSpy](http://hyperspy.org/hyperspy-doc/current/api/hyperspy.signal.html#hyperspy.signal.BaseSignal.save)\n", "to write to [their HDF5 specification](http://hyperspy.org/hyperspy-doc/current/user_guide/io.html#hspy-hyperspy-s-hdf5-specification):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_hs.save(temp_dir + \"master_pattern.hspy\")\n", "s_hs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "These master patterns can then be read into an `EBSDMasterPattern` signal again\n", "via HyperSpy's\n", "[load()](http://hyperspy.org/hyperspy-doc/current/api/hyperspy.io.html#hyperspy.io.load):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_mp2 = hs.load(temp_dir + \"master_pattern.hspy\", signal_type=\"EBSDMasterPattern\")\n", "s_mp2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "Note\n", "\n", "To save results from statistical decomposition (machine learning) of patterns to\n", "file see the section\n", "[Saving and loading results](http://hyperspy.org/hyperspy-doc/current/user_guide/mva.html#saving-and-loading-results)\n", "in HyperSpy's user guide. Note that the file extension `.hspy` must be used upon\n", "saving, `s.save('patterns.hspy')`, as the default extension in kikuchipy, `.h5`,\n", "yields a kikuchipy h5ebsd file where the decomposition results aren't saved. The\n", "saved patterns can then be reloaded using HyperSpy's `load()` function and\n", "passing the `signal_type=\"EBSD\"` parameter\n", "[as explained above](#From-a-HyperSpy-signal).\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Supported EBSD formats\n", "\n", "Currently, kikuchipy has readers and writers for the following formats:\n", "\n", "| Format | Read | Write |\n", "| ------------------------------------------------------------------- | ---- | ----- |\n", "| [EMsoft simulated EBSD HDF5](#EMsoft-simulated-EBSD-HDF5) | Yes | No |\n", "| [EMsoft EBSD master pattern HDF5](#EMsoft-EBSD-master-pattern-HDF5) | Yes | No |\n", "| [Bruker Nano h5ebsd](#h5ebsd) | Yes | No |\n", "| [EDAX TSL h5ebsd](#h5ebsd) | Yes | No |\n", "| [kikuchipy h5ebsd](#h5ebsd) | Yes | Yes |\n", "| [NORDIF binary](#NORDIF-binary) | Yes | Yes |\n", "| [NORDIF calibration patterns](#NORDIF-calibration-patterns) | Yes | No |\n", "| [Oxford Instruments binary](#Oxford-Instruments-binary) | Yes | No |\n", "\n", "
\n", "\n", "Note\n", "\n", "If you want to process your patterns with kikuchipy, but use an unsupported EBSD\n", "vendor software, or if you want to write your processed patterns to a vendor\n", "format that does not support writing, please request this feature in our\n", "[issue tracker](https://github.com/pyxem/kikuchipy/issues).\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### EMsoft simulated EBSD HDF5\n", "\n", "Dynamically simulated EBSD patterns returned by EMsoft's `EMEBSD.f90` program\n", "as HDF5 files can be read as an `EBSD` signal:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "emsoft_ebsd = \"emsoft_ebsd/simulated_ebsd.h5\" # Dummy data set\n", "s_sim = kp.load(filename=datadir + emsoft_ebsd)\n", "s_sim" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, the EMsoft simulated EBSD\n", "[file_reader()](../reference.rst#kikuchipy.io.plugins.emsoft_ebsd.file_reader) is\n", "called, which takes the optional argument `scan_size`. Passing\n", "`scan_size=(2, 5)` will reshape the pattern data shape from `(10, 10, 10)` to\n", "`(2, 5, 10, 10)`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_sim2 = kp.load(filename=datadir + emsoft_ebsd, scan_size=(2, 5))\n", "print(s_sim2)\n", "print(s_sim2.data.shape)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Simulated EBSD patterns can be written to the\n", "[kikuchipy h5ebsd format](#h5ebsd), the [NORDIF binary format](#NORDIF-binary),\n", "or to HDF5 files using HyperSpy's HDF5 specification\n", "[as explained above](#Save-patterns)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### EMsoft EBSD master pattern HDF5\n", "\n", "Master patterns returned by EMsoft's `EMEBSDmaster.f90` program as HDF5 files\n", "can be read as an `EBSDMasterPattern` signal:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_mp = kp.load(filename=datadir + emsoft_master_pattern)\n", "\n", "print(s_mp)\n", "print(s_mp.projection)\n", "print(s_mp.hemisphere)\n", "print(s_mp.phase)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, the EMsoft EBSD master pattern\n", "[file_reader()](../reference.rst#kikuchipy.io.plugins.emsoft_ebsd_master_pattern.file_reader)\n", "is called, which takes the optional arguments `projection`, `hemisphere` and\n", "`energy`. The stereographic projection is read by default. Passing\n", "`projection=\"lambert\"` will read the square Lambert projection instead. The\n", "northern hemisphere is read by default. Passing `hemisphere=\"south\"` or\n", "`hemisphere=\"both\"` will read the southern hemisphere projection or both,\n", "respectively. Master patterns for all beam energies are read by default. Passing\n", "`energy=(10, 20)` or `energy=15` will read the master pattern(s) with beam\n", "energies from 10 to 20 keV, or just 15 keV, respectively:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_mp = kp.load(\n", " datadir + emsoft_master_pattern, projection=\"lambert\", hemisphere=\"both\", energy=20\n", ")\n", "\n", "print(s_mp)\n", "print(s_mp.projection)\n", "print(s_mp.hemisphere)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Master patterns can be written to HDF5 files using HyperSpy's HDF5 specification\n", "[as explained above](#Save-patterns).\n", "\n", "See Jackson et al. (2019) for a\n", "hands-on tutorial explaining how to simulate these patterns with EMsoft, and\n", "Callahan & De Graef (2013) for\n", "details of the underlying theory." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### h5ebsd\n", "\n", "The h5ebsd format\n", "Jackson et al. (2014) is based on the\n", "[HDF5 open standard](https://www.hdfgroup.org/solutions/hdf5/) (Hierarchical Data Format\n", "version 5). HDF5 files can be read and edited using e.g. the HDF Group's reader\n", "[HDFView](https://www.hdfgroup.org/downloads/hdfview) or the Python package\n", "used by kikuchipy, [h5py](https://docs.h5py.org/en/stable). Upon loading an HDF5\n", "file with extension .h5, .hdf5, or .h5ebsd, the correct reader is determined\n", "from the file. Supported h5ebsd formats are listed in the\n", "[table above](#Supported-EBSD-formats).\n", "\n", "If an h5ebsd file contains multiple scans, as many scans as desirable can be\n", "read from the file. For example, if the file contains two scans with names\n", "``My awes0m4 Xcan #! with a long title`` and ``Scan 2``:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "kikuchipy_ebsd = \"kikuchipy_h5ebsd/patterns.h5\"\n", "s_awsm, s2 = kp.load(\n", " filename=datadir + kikuchipy_ebsd,\n", " scan_group_names=[\"My awes0m4 Xcan #! with a long title\", \"Scan 2\"],\n", ")\n", "print(s_awsm)\n", "print(s2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, the h5ebsd\n", "[file_reader()](../reference.rst#kikuchipy.io.plugins.h5ebsd.file_reader) is\n", "called. If only `Scan 2` is to be read, `scan_group_names=\"Scan 2\"` can be\n", "passed:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s2 = kp.load(filename=datadir + kikuchipy_ebsd, scan_group_names=\"Scan 2\")\n", "s2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `scan_group_names` parameter is unnecessary if only the first scan in the\n", "file is to be read, since reading only the first scan in the file is the default\n", "behaviour.\n", "\n", "So far, only [saving patterns](#Save-patterns) to kikuchipy's own h5ebsd format\n", "is supported. It is possible to write a new scan with a scan name `Scan x`,\n", "where `x` is an integer, to an existing, but closed, h5ebsd file in the\n", "kikuchipy format, e.g. one containing only `Scan 1`, by passing:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "new_file = \"patterns_new.h5\"\n", "s2.save(temp_dir + new_file, scan_number=1)\n", "s_awsm.save(filename=temp_dir + new_file, add_scan=True, scan_number=2)\n", "\n", "s2_new, s_awsm_new = kp.load(\n", " filename=temp_dir + new_file, scan_group_names=[\"Scan 1\", \"Scan 2\"]\n", ")\n", "print(s2_new)\n", "print(s_awsm_new)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, the h5ebsd\n", "[file_writer()](../reference.rst#kikuchipy.io.plugins.h5ebsd.file_writer) is\n", "called.\n", "\n", "
\n", "\n", "Note\n", " \n", "The `EBSD.xmap` and `EBSD.detector` properties are so far not written to this\n", "file format.\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### NORDIF binary\n", "\n", "Patterns acquired using NORDIF's acquisition software are stored in a binary\n", "file usually named \"Pattern.dat\". Scan information is stored in a separate text\n", "file usually named \"Setting.txt\", and both files usually reside in the same\n", "directory. If this is the case, the patterns can be loaded by passing the file\n", "name as the only parameter. If this is not the case, the setting file can be\n", "passed upon loading:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_nordif = kp.load(\n", " filename=datadir + nordif_ebsd, setting_file=datadir + \"nordif/Setting.txt\"\n", ")\n", "s_nordif" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, the NORDIF\n", "[file_reader()](../reference.rst#kikuchipy.io.plugins.nordif.file_reader) is\n", "called. If the scan information, i.e. scan and pattern size, in the setting file\n", "is incorrect or the setting file is not available, patterns can be loaded by\n", "passing:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_nordif = kp.load(\n", " filename=datadir + nordif_ebsd, scan_size=(1, 9), pattern_size=(60, 60)\n", ")\n", "s_nordif" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If a static background pattern named \"Background acquisition pattern.bmp\" is\n", "stored in the same directory as the pattern file, this is stored in\n", "``EBSD.static_background`` upon loading.\n", "\n", "Patterns can also be [saved to a NORDIF binary file](#Save-patterns), upon\n", "which the NORDIF\n", "[file_writer()](../reference.rst#kikuchipy.io.plugins.nordif.file_writer) is\n", "called. Note, however, that so far no new setting file, background pattern, or\n", "calibration patterns are created upon saving." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### NORDIF calibration patterns\n", "\n", "NORDIF calibration patterns in bitmap format named \"Calibration (x,y).bmp\",\n", "where \"x\" and \"y\" correspond to coordinates listed in the NORDIF setting file,\n", "usually named \"Setting.txt\", can be loaded" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_nordif_cal = kp.load(filename=datadir + \"nordif/Setting.txt\")\n", "s_nordif_cal" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, the NORDIF calibration patterns\n", "[file_reader()](../reference.rst#kikuchipy.io.plugins.nordif_calibration_patterns.file_reader) is\n", "called. Lazy loading is not supported for this reader, thus the `lazy` parameter\n", "is not used.\n", "\n", "If a static background pattern named \"Background calibration pattern.bmp\" is\n", "stored in the same directory as the pattern file, this is stored in\n", "``EBSD.static_background`` upon loading." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Oxford Instruments binary\n", "\n", "Uncompressed patterns stored in the Oxford Instruments binary .ebsp file format,\n", "with intensities as 8-bit or 16-bit unsigned integer, can be read" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "oxford_binary_path = datadir + \"oxford_binary/\"\n", "s_oxford = kp.load(filename=oxford_binary_path + \"patterns.ebsp\")\n", "s_oxford" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, the Oxford Instruments binary\n", "[file_reader()](../reference.rst#kikuchipy.io.plugins.oxford_binary.file_reader) is\n", "called.\n", "\n", "Every pattern's flattened index into the 2D navigation map, as well as their\n", "entry in the file (map order isn't always the same as file order) can be\n", "retrieved from `s_oxford.original_metadata.map1d_id` and\n", "`s_oxford.original_metadata.file_order`, respectively. If available in the file,\n", "every pattern's row and column beam position in microns can be retrieved from\n", "`s_oxford.original_metadata.beam_y` and `s_oxford.original_metadata.beam_x`,\n", "respectively. All these are 1D arrays." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_oxford.original_metadata" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If the beam positions aren't present in the file, the returned signal will have\n", "a single navigation dimension the size of the number of patterns.\n", "\n", "Files with only the non-indexed patterns can also be read. The returned signal\n", "will then have a single navigation dimension the size of the number of patterns.\n", "The flattened index into the 2D navigation map mentioned above can be useful to\n", "determine the location of each non-indexed pattern." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## From kikuchipy into other software\n", "\n", "Patterns saved in the [h5ebsd format](#h5ebsd) can be read by the\n", "dictionary indexing and related routines in\n", "[EMsoft](http://vbff.materials.cmu.edu/EMsoft) using the `EMEBSD` reader. Those\n", "routines in EMsoft also have a `NORDIF` reader.\n", "\n", "Patterns saved in the [h5ebsd format](#h5ebsd) can of course be read\n", "in Python like any other HDF5 data set:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbsphinx-thumbnail": { "tooltip": "Loading and saving EBSD and EBSD master patterns from and to various file formats" }, "tags": [ "nbsphinx-thumbnail" ] }, "outputs": [], "source": [ "import h5py\n", "\n", "with h5py.File(datadir + kikuchipy_ebsd, mode=\"r\") as f:\n", " dset = f[\"Scan 2/EBSD/Data/patterns\"]\n", " print(dset)\n", " patterns = dset[()]\n", " print(patterns.shape)\n", " plt.figure()\n", " plt.imshow(patterns[0], cmap=\"gray\")\n", " plt.axis(\"off\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Load and save virtual BSE images\n", "\n", "One or more virtual backscatter electron (BSE) images in a\n", "[VirtualBSEImage](../reference.rst#kikuchipy.signals.VirtualBSEImage) signal can be\n", "read and written to file using one of HyperSpy's many readers and writers. If\n", "they are only to be used internally in HyperSpy, they can be written to and read\n", "back from HyperSpy's HDF5 specification\n", "[as explained above for EBSD master patterns](#Save-patterns).\n", "\n", "If we want to write the images to image files, HyperSpy also provides a series\n", "of image readers/writers, as explained in their\n", "[IO user guide](http://hyperspy.org/hyperspy-doc/current/user_guide/io.html#images).\n", "If we wanted to write them as a stack of TIFF images:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Get virtual image from generator\n", "vbse_gen = kp.generators.VirtualBSEGenerator(s)\n", "print(vbse_gen)\n", "\n", "print(vbse_gen.grid_shape)\n", "vbse = vbse_gen.get_images_from_grid()\n", "print(vbse)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "vbse.rescale_intensity()\n", "vbse.unfold_navigation_space() # 1D navigation space required for TIFF\n", "vbse" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "vbse_fname = \"vbse.tif\"\n", "vbse.save(temp_dir + vbse_fname) # Easily read into e.g. ImageJ" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also write them to e.g. `png` or `bmp` files with `Matplotlib`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "nav_size = vbse.axes_manager.navigation_size\n", "_ = [plt.imsave(temp_dir + f\"vbse{i}.png\", vbse.inav[i].data) for i in range(nav_size)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Read the TIFF stack back into a `VirtualBSEImage` signal:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "vbse2 = hs.load(temp_dir + vbse_fname, signal_type=\"VirtualBSEImage\")\n", "vbse2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbsphinx": "hidden" }, "outputs": [], "source": [ "# Remove files written to disk in this user guide\n", "import os\n", "\n", "for file in [\n", " \"patterns.h5\",\n", " \"patterns_new.h5\",\n", " \"patterns.dat\",\n", " \"master_pattern.hspy\",\n", " \"vbse.tif\",\n", "]:\n", " os.remove(temp_dir + file)\n", "for i in range(25):\n", " os.remove(temp_dir + f\"vbse{i}.png\")\n", "os.rmdir(temp_dir)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.13" } }, "nbformat": 4, "nbformat_minor": 4 }