{ "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": [ "# Visualizing patterns\n", "\n", "The [EBSD](../reference/generated/kikuchipy.signals.EBSD.rst) and [EBSDMasterPattern](../reference/generated/kikuchipy.signals.EBSDMasterPattern.rst) signals have a powerful and versatile [plot()](http://hyperspy.org/hyperspy-doc/current/api/hyperspy.signal.html#hyperspy.signal.BaseSignal.plot) method provided by HyperSpy.\n", "The method's uses are greatly detailed in HyperSpy's [visualization user guide](http://hyperspy.org/hyperspy-doc/current/user_guide/visualisation.html).\n", "This section details example uses specific to EBSD and EBSDMasterPattern signals.\n", "\n", "Let's import the necessary libraries and a nickel EBSD test data set Ă…nes et al. (2019)" ] }, { "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 matplotlib.pyplot as plt\n", "import numpy as np\n", "import pyvista as pv\n", "import skimage.exposure as ske\n", "import skimage.transform as skt\n", "\n", "import hyperspy.api as hs\n", "import kikuchipy as kp\n", "from orix import io, plot, quaternion, vector\n", "\n", "\n", "# See https://docs.pyvista.org/user-guide/jupyter/index.html\n", "pv.set_jupyter_backend(\"static\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Use kp.load(\"data.h5\") to load your own data\n", "s = kp.data.nickel_ebsd_large(allow_download=True) # External download\n", "s" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Navigate in custom map\n", "\n", "Correlating results from e.g. crystal and phase structure determination, i.e. indexing, with experimental patterns is important when validating the indexing results.\n", "When calling `plot()` without any input parameters, the navigator map is a grey scale image with pixel values corresponding to the sum of all detector intensities within that pattern" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s.plot()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The upper panel shows the navigation axes, in this case 2D.\n", "The current navigation position is highlighted in the upper left corner as a red square the size of one pixel.\n", "We can change the size of the square with +/-.\n", "The square can be moved either by the keyboard arrows or the mouse.\n", "The lower panel shows the pattern on the detector in the current navigation position.\n", "\n", "Any [BaseSignal](http://hyperspy.org/hyperspy-doc/current/api/hyperspy.signal.html#hyperspy.signal.BaseSignal) signal with a 2D `signal_shape` corresponding to the scan `navigation_shape` can be passed in to the `navgiator` parameter in [plot()](http://hyperspy.org/hyperspy-doc/current/api/hyperspy.signal.html#hyperspy.signal.BaseSignal.plot).\n", "This includes a virtual image showing diffraction contrast, any quality metric map, or an inverse pole figure (IPF) or phase map." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Virtual image\n", "\n", "A virtual backscatter electron (VBSE) image created from any detector region of interest with the [get_virtual_bse_intensity()](../reference/generated/kikuchipy.signals.EBSD.get_virtual_bse_intensity.rst) method or\n", "[get_rgb_image()](../reference/generated/kikuchipy.imaging.VirtualBSEImager.get_rgb_image.rst) explained in the [virtual backscatter electron imaging](virtual_backscatter_electron_imaging.ipynb) tutorial, can be used as a navigator for a scan `s`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "vbse_imager = kp.imaging.VirtualBSEImager(s)\n", "print(vbse_imager)\n", "print(vbse_imager.grid_shape)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "maps_vbse_rgb = vbse_imager.get_rgb_image(r=(3, 1), b=(3, 2), g=(3, 3))\n", "maps_vbse_rgb" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s.plot(navigator=maps_vbse_rgb, cmap=\"viridis\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Any image\n", "\n", "An image made into a [Signal2D](http://hyperspy.org/hyperspy-doc/current/api/hyperspy._signals.signal2d.html#hyperspy._signals.signal2d.Signal2D) can be used as navigators.\n", "This includes quality metric maps such as the [image quality map](feature_maps.ipynb#Image-quality), calculated using [get_image_quality()](../reference/generated/kikuchipy.signals.EBSD.get_image_quality.rst)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s.remove_static_background()\n", "s.remove_dynamic_background()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "maps_iq = s.get_image_quality()\n", "s_iq = hs.signals.Signal2D(maps_iq)\n", "s.plot(navigator=s_iq)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can obtain an RGB signal from an RGB image using [get_rgb_navigator()](../reference/generated/kikuchipy.draw.get_rgb_navigator.rst).\n", "Let's load an IPF-Z map representing orientations obtained from dictionary indexing in the [pattern matching](pattern_matching.ipynb) tutorial" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "maps_ipfz = plt.imread(\"../_static/image/visualizing_patterns/ni_large_rgb_z.png\")\n", "maps_ipfz = maps_ipfz[..., :3] # Drop the alpha channel\n", "s_ipfz = kp.draw.get_rgb_navigator(maps_ipfz)\n", "\n", "s.plot(navigator=s_ipfz, colorbar=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By overlaying the image quality map on the RGB image, we can visualize crystal directions within grains and the grain morphology in the same image" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "maps_iq_1d = maps_iq.ravel() # Flat array required by orix\n", "maps_ipfz_1d = maps_ipfz.reshape(-1, 3)\n", "fig = s.xmap.plot(maps_ipfz_1d, overlay=maps_iq_1d, return_figure=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By extracting the image array, we can use this map to navigate patterns in" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "maps_ipfz_iq = fig.axes[0].images[0].get_array()\n", "s_ipfz_iq = kp.draw.get_rgb_navigator(maps_ipfz_iq)\n", "s.plot(s_ipfz_iq)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot multiple signals\n", "\n", "HyperSpy provides the function [plot_signals()](http://hyperspy.org/hyperspy-doc/current/api/hyperspy.drawing.utils.html#hyperspy.drawing.utils.plot_signals) to plot multiple signals with the same navigator (detailed in their [documentation](http://hyperspy.org/hyperspy-doc/current/user_guide/visualisation.html#plotting-several-signals)).\n", "Among other uses, this function enables plotting of the experimental and best matching simulated patterns side by side.\n", "This can be a powerful visual validation of indexing results.\n", "See the [pattern matching tutorial](pattern_matching.ipynb#Validate-indexing-results) for a demonstration." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot master patterns\n", "\n", "[EBSDMasterPattern](../reference/generated/kikuchipy.signals.EBSDMasterPattern.rst) signals can be navigated along their energy axis and/or their upper/lower hemispheres.\n", "Let's reload the nickel master pattern used in the previous section, but this time in the stereographic projection." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "# Only a single energy, 20 keV\n", "mp_stereo = kp.data.nickel_ebsd_master_pattern_small(\n", " projection=\"stereographic\", hemisphere=\"both\"\n", ")\n", "print(mp_stereo.axes_manager)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As can be seen from the axes manager, the master pattern has two navigation axes, the upper and lower hemispheres.\n", "When plotting, we therefore get a navigation slider" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbsphinx-thumbnail": { "tooltip": "Ways to visualize the navigation (scan) and signal (detector) dimensions" }, "tags": [ "nbsphinx-thumbnail" ] }, "outputs": [], "source": [ "mp_stereo.plot()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can plot the master pattern on the sphere with [EBSDMasterPattern.plot_spherical()](../reference/generated/kikuchipy.signals.EBSDMasterPattern.plot_spherical.rst).\n", "This visualization requires the master pattern to be in the stereographic projection.\n", "If the corresponding phase is centrosymmetry, the upper and lower hemispheres are identical, so we only need one of them to cover the sphere.\n", "If the phase is non-centrosymmetric, however, both hemispheres must be loaded, as they are unequal.\n", "The initial orientation of the sphere corresponds to the orientation of the stereographic and Lambert projections." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "nbval-skip" ] }, "outputs": [], "source": [ "mp_stereo.plot_spherical(style=\"points\")" ] }, { "cell_type": "markdown", "metadata": { "raw_mimetype": "text/restructuredtext", "tags": [] }, "source": [ "`PyVista`, required for this plot, is an optional dependency of kikuchipy (see [the installation guide](../user/installation.rst#with-pip) for details).\n", "Here, the plot uses the static [Jupyter backend supported by PyVista](https://docs.pyvista.org/user-guide/jupyter/index.html).\n", "The backend was set in the first notebook cell.\n", "When running the notebook locally, we can make the plot interactive setting the backend to `\"trame\"`.\n", "We can pass `plotter_kwargs={\"notebook\": False}\"` to `plot_spherical()` if we want to plot the master pattern in a separate window." ] } ], "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.11.6" }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 4 }