From f0f0e16fd9e2e1ab7c3b863fde25ccac30b2a6a5 Mon Sep 17 00:00:00 2001 From: Carter Francis Date: Tue, 14 May 2024 15:12:30 -0500 Subject: [PATCH] Plotting: Add plotting of ipf --- pyxem/data/__init__.py | 9 ++- pyxem/data/simulated_si.py | 23 ++++++++ pyxem/signals/indexation_results.py | 87 ++++++++++++++++++++++++++++- 3 files changed, 115 insertions(+), 4 deletions(-) diff --git a/pyxem/data/__init__.py b/pyxem/data/__init__.py index 6ee3014be..e8ae31a3e 100644 --- a/pyxem/data/__init__.py +++ b/pyxem/data/__init__.py @@ -30,7 +30,13 @@ """ from pyxem.data.simulated_tilt import tilt_boundary_data -from pyxem.data.simulated_si import si_phase, si_tilt, si_grains, si_grains_simple +from pyxem.data.simulated_si import ( + si_phase, + si_tilt, + si_grains, + si_grains_simple, + si_rotations_line, +) from pyxem.data.simulation_fe import fe_bcc_phase, fe_fcc_phase, fe_multi_phase_grains from pyxem.data._data import ( au_grating, @@ -53,6 +59,7 @@ "si_tilt", "si_grains", "si_grains_simple", + "si_rotations_line", "fe_multi_phase_grains", "fe_fcc_phase", "fe_bcc_phase", diff --git a/pyxem/data/simulated_si.py b/pyxem/data/simulated_si.py index b4f09e1e9..7f6697af0 100644 --- a/pyxem/data/simulated_si.py +++ b/pyxem/data/simulated_si.py @@ -136,6 +136,29 @@ def si_grains_simple(seed=2, size=20, recip_pixels=128, return_rotations=False): return grains +def si_rotations_line(): + from orix.sampling import get_sample_reduced_fundamental + + p = si_phase() + gen = SimulationGenerator() + rotations = get_sample_reduced_fundamental(resolution=3, point_group=p.point_group) + sim = gen.calculate_diffraction2d( + phase=p, rotation=rotations, max_excitation_error=0.1, reciprocal_radius=2 + ) + dps = [] + for i in range(rotations.size): + dp = np.flipud(sim.irot[i].get_diffraction_pattern(sigma=5, shape=(256, 256))) + dps.append(dp) + line = Diffraction2D(np.array(dps)) + line.axes_manager.signal_axes[0].name = "kx" + line.axes_manager.signal_axes[1].name = "kx" + line.axes_manager.signal_axes[0].units = r"$\AA^{-1}$" + line.axes_manager.signal_axes[1].units = r"$\AA^{-1}$" + line.axes_manager.signal_axes[0].scale = 0.01 + line.axes_manager.signal_axes[1].scale = 0.01 + return line + + def simulated1dsi( num_points=200, accelerating_voltage=200, diff --git a/pyxem/signals/indexation_results.py b/pyxem/signals/indexation_results.py index 369b65d49..ab8d40ab1 100644 --- a/pyxem/signals/indexation_results.py +++ b/pyxem/signals/indexation_results.py @@ -29,6 +29,12 @@ from orix.plot import IPFColorKeyTSL from transforms3d.euler import mat2euler from diffsims.crystallography._diffracting_vector import DiffractingVector +from orix.vector import Vector3d +from orix.projections import StereographicProjection +from orix.plot.inverse_pole_figure_plot import _get_ipf_axes_labels +from orix.vector.fundamental_sector import _closed_edges_in_hemisphere +import numpy as np +import hyperspy.api as hs from pyxem.utils.indexation_utils import get_nth_best_solution from pyxem.signals.diffraction_vectors2d import DiffractionVectors2D @@ -274,9 +280,84 @@ def to_crystal_map(self) -> CrystalMap: def to_ipf_markers(self): """Convert the orientation map to a set of inverse pole figure markers which visualizes the best matching orientations in the - reduced S2 space.""" + reduced S2 space. + """ + if self._lazy: + raise ValueError( + "Cannot create markers from lazy signal. Please compute the signal first." + ) + if self.simulation.has_multiple_phases: + raise ValueError("Multiple phases found in simulation") - pass + orients = self.to_single_phase_orientations() + sector = self.simulation.phases.point_group.fundamental_sector + labels = _get_ipf_axes_labels( + sector.vertices, symmetry=self.simulation.phases.point_group + ) + s = StereographicProjection() + vectors = orients * Vector3d.zvector() + edges = _closed_edges_in_hemisphere(sector.edges, sector) + vectors = vectors.in_fundamental_sector(self.simulation.phases.point_group) + x, y = s.vector2xy(vectors) + ex, ey = s.vector2xy(edges) + tx, ty = s.vector2xy(sector.vertices) + + x = x.reshape(vectors.shape) + y = y.reshape(vectors.shape) + cor = self.data[..., 1] + + offsets = np.empty(shape=vectors.shape[:-1], dtype=object) + correlation = np.empty(shape=vectors.shape[:-1], dtype=object) + original_offset = np.vstack((ex, ey)).T + texts_offset = np.vstack((tx, ty)).T + + mins, maxes = original_offset.min(axis=0), original_offset.max(axis=0) + + original_offset = ( + (original_offset - ((maxes + mins) / 2)) / (maxes - mins) * 0.2 + ) + original_offset = original_offset + 0.85 + + texts_offset = (texts_offset - ((maxes + mins) / 2)) / (maxes - mins) * 0.2 + texts_offset = texts_offset + 0.85 + for i in np.ndindex(offsets.shape): + off = np.vstack((x[i], y[i])).T + norm_points = (off - ((maxes + mins) / 2)) / (maxes - mins) * 0.2 + norm_points = norm_points + 0.85 + offsets[i] = norm_points + correlation[i] = cor[i] / np.max(cor[i]) * 0.5 + + square = hs.plot.markers.Squares( + offsets=[[0.85, 0.85]], + widths=(0.3,), + units="width", + offset_transform="axes", + facecolor="white", + edgecolor="black", + ) + polygon_sector = hs.plot.markers.Polygons( + verts=original_offset[np.newaxis], + transform="axes", + alpha=1, + facecolor="none", + ) + + best_points = hs.plot.markers.Points( + offsets=offsets.T, + sizes=(4,), + offset_transform="axes", + alpha=correlation.T, + facecolor="green", + ) + + texts = hs.plot.markers.Texts( + texts=labels, + offsets=texts_offset, + sizes=(1,), + offset_transform="axes", + facecolor="k", + ) + return square, polygon_sector, best_points, texts def to_single_phase_markers( self, @@ -325,7 +406,7 @@ def to_single_phase_markers( inplace=False, lazy_output=lazy_output, ragged=True, - ).data + ).data.T kwargs["sizes"] = intensity coords = vectors.map(