def plot_ipf(self, **kwargs): """ Create the inverse pole figure for direction Z. :param ax: a reference to a pyplot ax to draw the poles. :param mk: marker used to plot the poles (square by default). :param bool ann: Annotate the pole with the coordinates of the vector if True (False by default). """ ax = kwargs.get('ax') self.plot_pf_background(ax, labels=False) # now plot the sample axis for grain in self.microstructure.grains: g = Orientation.Rodrigues2OrientationMatrix(grain['orientation']) if self.axis == 'Z': axis = self.z elif self.axis == 'Y': axis = self.y else: axis = self.x axis_rot = g.dot(axis) kwargs['col'] = self.get_color_from_field(grain) self.plot_crystal_dir(axis_rot, **kwargs) if self.verbose: print('plotting ', self.axis, ' in crystal CS:', axis_rot) ax.axis([-1.1, 1.1, -1.1, 1.1]) ax.axis('off') ax.set_title('%s-axis inverse %s projection' % (self.axis, self.proj))
def create_pf_contour(self, ax=None, ang_step=10): """Compute the distribution of orientation and plot it using contouring. This plot the distribution of orientation in the microstructure associated with this PoleFigure instance, as a continuous distribution using angular bining with the specified step. the distribution is constructed at runtime by discretizing the angular space and counting the number of poles in each bin. Then the plot_pf_contour method is called to actually plot the data. .. warning:: This function has not been tested properly, use at your own risk. :param ax: a reference to a pyplot ax to draw the contours. :param int ang_step: angular step in degrees to use for constructing the orientation distribution data (10 degrees by default) """ # discretise the angular space (azimuth and altitude) ang_step *= np.pi / 180 # change to radians n_phi = int(1 + 2 * np.pi / ang_step) n_psi = int(1 + 0.5 * np.pi / ang_step) phis = np.linspace(0, 2 * np.pi, n_phi) psis = np.linspace(0, np.pi / 2, n_psi) xv, yv = np.meshgrid(phis, psis) values = np.zeros((n_psi, n_phi), dtype=int) for grain in self.microstructure.grains: g = Orientation.Rodrigues2OrientationMatrix(grain['orientation']) gt = g.transpose() for hkl_plane in self.poles: c = hkl_plane.normal() c_rot = gt.dot(c) # handle poles pointing down if c_rot[2] < 0: c_rot *= -1 # make unit vector have z>0 if c_rot[1] >= 0: phi = np.arccos(c_rot[0] / np.sqrt(c_rot[0]**2 + c_rot[1]**2)) else: phi = 2 * np.pi - np.arccos( c_rot[0] / np.sqrt(c_rot[0]**2 + c_rot[1]**2)) psi = np.arccos(c_rot[2]) # since c_rot is normed i_phi = int((phi + 0.5 * ang_step) / ang_step) % n_phi j_psi = int((psi + 0.5 * ang_step) / ang_step) % n_psi values[j_psi, i_phi] += 1 if self.proj == 'stereo': # double check which one is flat/stereo x = (2 * yv / np.pi) * np.cos(xv) y = (2 * yv / np.pi) * np.sin(xv) else: x = np.sin(yv) * np.cos(xv) y = np.sin(yv) * np.sin(xv) # close the pole figure by duplicating azimuth=0 values[:, -1] = values[:, 0] self.plot_pf_contour(ax, x, y, values)
def plot_pf(self, ax=None, mk='o', ann=False): """Create the direct pole figure. :param ax: a reference to a pyplot ax to draw the poles. :param mk: marker used to plot the poles (disc by default). :param bool ann: Annotate the pole with the coordinates of the vector if True (False by default). """ self.plot_pf_background(ax) kwargs = {'ax': ax, 'mk': mk, 'ann': ann} if self.resize_markers: # compute the max grain volume to normalize volume_max = max(self.microstructure.get_grain_volumes()) for grain in self.microstructure.grains: g = Orientation.Rodrigues2OrientationMatrix(grain['orientation']) gt = g.transpose() if self.resize_markers: kwargs['mksize'] = 0.15 * np.sqrt( grain['volume'] / volume_max) * 1000 label = '' if self.map_field == 'grain_id': label = 'grain ' + str(grain['idnumber']) kwargs['lab'] = label for i, hkl_plane in enumerate(self.poles): if i > 0: kwargs['lab'] = '' c = hkl_plane.normal() c_rot = gt.dot(c) if self.verbose: h, k, l = hkl_plane.miller_indices() print('plotting (%d%d%d) with normal %s in sample CS ' '(corrected for pf axis): %s' % (h, k, l, c, c_rot)) col = self.get_color_from_field(grain) kwargs['col'] = col self.plot_pf_dir(c_rot, **kwargs) ax.axis([-1.1, 1.1, -1.1, 1.1]) if self.pflegend and self.map_field == 'grain_id': ax.legend(bbox_to_anchor=(0.05, 1), loc=1, numpoints=1, prop={'size': 10}) ax.axis('off') ax.set_title('{%s} direct %s projection' % (self.family, self.proj))
def test_RodriguesConversion(self): rod = [0.1449, -0.0281, 0.0616] g = Orientation.Rodrigues2OrientationMatrix(rod) calc_rod = Orientation.OrientationMatrix2Rodrigues(g) for i in range(3): self.assertAlmostEquals(calc_rod[i], rod[i])
def plot_sst(self, **kwargs): """ Create the inverse pole figure in the unit standard triangle. :param ax: a reference to a pyplot ax to draw the poles. :param mk: marker used to plot the poles (square by default). :param bool ann: Annotate the pole with the coordinates of the vector if True (False by default). """ # first draw the boundary of the symmetry domain limited by 3 hkl plane # normals, called here A, B and C symmetry = self.lattice.get_symmetry() ax = kwargs.get('ax') if symmetry is Symmetry.cubic: sst_poles = [(0, 0, 1), (1, 0, 1), (1, 1, 1)] ax.axis([-0.05, 0.45, -0.05, 0.40]) elif symmetry is Symmetry.hexagonal: sst_poles = [(0, 0, 1), (2, -1, 0), (1, 0, 0)] ax.axis([-0.05, 1.05, -0.05, 0.6]) else: print('unsuported symmetry: %s' % symmetry) A = HklPlane(*sst_poles[0], lattice=self.lattice) B = HklPlane(*sst_poles[1], lattice=self.lattice) C = HklPlane(*sst_poles[2], lattice=self.lattice) self.plot_line_between_crystal_dir(A.normal(), B.normal(), ax=ax, col='k') self.plot_line_between_crystal_dir(B.normal(), C.normal(), ax=ax, col='k') self.plot_line_between_crystal_dir(C.normal(), A.normal(), ax=ax, col='k') # display the 3 crystal axes poles = [A, B, C] v_align = ['top', 'top', 'bottom'] for i in range(3): hkl = poles[i] c_dir = hkl.normal() c = c_dir + self.z c /= c[2] # SP'/SP = r/z with r=1 pole_str = '%d%d%d' % hkl.miller_indices() if symmetry is Symmetry.hexagonal: pole_str = '%d%d%d%d' % HklPlane.three_to_four_indices( *hkl.miller_indices()) ax.annotate(pole_str, (c[0], c[1] - (2 * (i < 2) - 1) * 0.01), xycoords='data', fontsize=12, horizontalalignment='center', verticalalignment=v_align[i]) # now plot the sample axis if self.resize_markers: # compute the max grain volume to normalize volume_max = max(self.microstructure.get_grain_volumes()) for grain in self.microstructure.grains: g = Orientation.Rodrigues2OrientationMatrix(grain['orientation']) if self.resize_markers: kwargs['mksize'] = 0.15 * np.sqrt( grain['volume'] / volume_max) * 1000 # compute axis and apply SST symmetry if self.axis == 'Z': axis = self.z elif self.axis == 'Y': axis = self.y else: axis = self.x axis_rot = self.sst_symmetry(g.dot(axis)) label = '' if self.map_field == 'grain_id': label = 'grain ' + str(grain['idnumber']) kwargs['lab'] = label kwargs['col'] = self.get_color_from_field(grain) self.plot_crystal_dir(axis_rot, **kwargs) if self.verbose: print('plotting %s in crystal CS: %s' % (self.axis, axis_rot)) ax.axis('off') ax.set_title('%s-axis SST inverse %s projection' % (self.axis, self.proj))