Source code for aloe.plotting.pcplotter

import numpy as np
from scipy import stats

import matplotlib
#matplotlib.use("Qt5Agg")   # use PyQt5
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection,Line3DCollection
from matplotlib.patches import FancyArrowPatch
from mpl_toolkits.mplot3d import proj3d
from matplotlib.ticker import MultipleLocator
from matplotlib import rc

import os


[docs]def makeLabelList2D(bracket1,bracket2,IndexArray): ''' returns the 2D indices formated with chosen bracket ''' LabelList=list() for ix in range(IndexArray.shape[1]): #print(IndexArray[:,ix]) formattedline =(bracket1+'%i,%i'+bracket2) % ( tuple(IndexArray[:,ix]) ) LabelList.append(formattedline) return np.array(LabelList)
[docs]class PCPlotter(object): def __init__(self,primary,secondary=None,plane_quad=None, grid2D=None,plane_PC=None,BI=None): #primary plot coordinate list self.primary=primary # secondary data for comparison if secondary is not None: self.secondary = secondary else: self.secondary =None # best fit plane vertices if plane_quad is not None: self.plane_quad = plane_quad else: self.plane_quad = None # best fit in plane: all grid points if grid2D is not None: self.grid2D = grid2D else: self.grid2D = None # in-plane experimental scan points from PC fit if plane_PC is not None: self.plane_PC = plane_PC else: self.plane_PC = None # beam indices for PC value list if BI is not None: self.BI = BI else: self.BI = None self.PLOT_SCAN_LABELS=True
[docs] def plot(self,plotdir='.', show=False, plot3d=False): ''' plot projection centers ''' if not os.path.exists(plotdir): print('pcplotter, creating dir: ',plotdir) os.makedirs(plotdir) primary=self.primary if self.secondary is not None: secondary=self.secondary if self.secondary is not None: error_vecs= self.secondary - self.primary #errors=np.ravel(np.abs(error_vecs[:,1])) # check xyz errors=np.linalg.norm( error_vecs, axis=1) #print(errors) #errors=np.mean(np.abs(secondary[:,0] - primary[:,0])) #print("Mean error of projective primary:", np.mean(errors)) print("Median error of projective fit:", np.median(errors)) fig = plt.figure() plt.hist(errors,bins=71) plt.title('projective geometry model: estimation of single-pattern error\n' +'median of errors={0: >#05.2f} $\mu m$'. format(float(np.median(errors)))) plt.ylabel('number of measurements', color='k', fontsize=22) plt.xlabel(r'$|PC_{\mathrm{exp}}-PC_{\mathrm{projective}}|$ ($\mu m$)', color='k',fontsize=22) plt.savefig(plotdir+'PCXYZ_ERRORS.png',dpi=300,bbox_inches = 'tight') if show: plt.show() plt.close() if (self.grid2D is not None): # this plot is in the SAMPLE SYSTEM # (x axis opposite direction to Detector-X) X_AXIS_FACTOR=-1.0 fig, ax = plt.subplots(1,1) plt.rc('xtick', labelsize=14) plt.rc('ytick', labelsize=14) #plt.title(title,fontsize=26) ax.set_ylabel(r'Y$_{SAMPLE}$ ($\mu m$)', color='k', fontsize=22) ax.set_xlabel(r'X$_{SAMPLE}$ ($\mu m$)', color='k',fontsize=22) ax.scatter(X_AXIS_FACTOR*self.grid2D.T[0],self.grid2D.T[1],s=8,c='lightblue',alpha=0.9, lw=0) # experimental points if self.plane_PC is not None: #print(self.plane_PC.T[0], self.plane_PC.T[1]) ax.scatter(X_AXIS_FACTOR*self.plane_PC.T[0], self.plane_PC.T[1], s=5, c='k', alpha=0.9, lw=0) # labels if self.PLOT_SCAN_LABELS: labels = makeLabelList2D('(',')',self.BI.T[0:2]) # todo: logging #print(labels) #print(self.plane_PC.T[0], self.plane_PC.T[1]) for label, x, y in zip(labels, np.ravel(X_AXIS_FACTOR*self.plane_PC.T[0]), np.ravel(self.plane_PC.T[1])): ax.annotate( label, zorder=105, xy = (x, y), xytext = (0, 10), fontsize=6, color='black', #weight='bold', textcoords = 'offset points', ha = 'center', va = 'bottom', bbox = dict(boxstyle = 'round,pad=0.2', fc = 'yellow', alpha = 0.6), arrowprops = dict(arrowstyle = '-', connectionstyle = 'arc3,rad=0')) ax.grid(True) ax.invert_xaxis() ax.yaxis.tick_right() ax.yaxis.set_label_position("right") ax.set_aspect('equal', 'datalim') plt.savefig(plotdir+'SCAN_SAMPLE.png',dpi=300,bbox_inches = 'tight') if show: plt.show() plt.close() fig, ax = plt.subplots(1,1) #ax = fig.add_subplot(221) plt.rc('xtick', labelsize=14) plt.rc('ytick', labelsize=14) #plt.title(title,fontsize=26) ax.set_ylabel(r'$\Delta$PC$_Y$ ($\mu m$)', color='k', fontsize=22) ax.set_xlabel(r'$\Delta$PC$_X$ ($\mu m$)', color='k',fontsize=22) ax.scatter(primary.T[0],primary.T[1],s=12,c='r',alpha=0.9, lw=0) if self.secondary is not None: ax.scatter(secondary.T[0],secondary.T[1],s=5,c='b',alpha=0.9,lw=0) ax.grid(True) ax.set_aspect('equal', 'datalim') plt.savefig(plotdir+'PCXY.png',dpi=300,bbox_inches = 'tight') if show: plt.show() plt.close() fig, ax = plt.subplots(1,1) #ax = fig.add_subplot(222) plt.rc('xtick', labelsize=14) plt.rc('ytick', labelsize=14) #plt.title(title,fontsize=26) ax.set_ylabel(r'$\Delta$PC$_Z$ ($\mu m$)', color='k', fontsize=22) ax.set_xlabel(r'$\Delta$PC$_X$ ($\mu m$)', color='k',fontsize=22) ax.scatter(primary.T[0],primary.T[2],s=22,c='red',alpha=1.0,lw=0) if self.secondary is not None: plt.scatter(secondary.T[0],secondary.T[2],s=10,c='blue',alpha=1.0,lw=0) ax.grid(True) ax.set_aspect('equal', 'datalim') ax.invert_yaxis() plt.savefig(plotdir+'PCXZ.png',dpi=300,bbox_inches = 'tight') if show: plt.show() plt.close() fig, ax = plt.subplots(1,1) #ax = fig.add_subplot(223) plt.rc('xtick', labelsize=14) plt.rc('ytick', labelsize=14) #plt.title(title,fontsize=26) ax.set_ylabel(r'$\Delta$PC$_Y$ ($\mu m$)', color='k', fontsize=22) ax.set_xlabel(r'$\Delta$PC$_Z$ ($\mu m$)', color='k',fontsize=22) #plt.gca().invert_yaxis() # consistent with y measured from top of pattern ax.scatter(primary.T[2],primary.T[1],s=22,c='r',alpha=1.0,lw=0) if self.secondary is not None: ax.scatter(secondary.T[2],secondary.T[1],s=10,c='b',alpha=1.0,lw=0) #plt.plot(primary.T[2],fittedY,'y-' ) ax.grid(True) ax.set_aspect('equal', 'datalim') ax.invert_xaxis() plt.savefig(plotdir+'PCYZ.png',dpi=300,bbox_inches = 'tight') if show: plt.show() plt.close() # ---------- 3D PLOT ---------------- if plot3d: rc('font',size=16) #rc('font',family='serif') rc('axes',labelsize=16) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # best fit PLANE if self.plane_quad is not None: quad_verts=[self.plane_quad_3d] ax.add_collection3d( Poly3DCollection(quad_verts, facecolors='b', linewidths=1, alpha=0.4) ) ax.scatter(primary.T[0],primary.T[2],primary.T[1], c='r', s=8, marker='o',lw=0.1, edgecolors='k',alpha=1.0) plt.grid(True) #if self.secondary is not None: #ax.scatter(secondary.T[0],secondary.T[2],secondary.T[1],s=16, c='b', marker='o',lw=0,alpha=0.3) ax.set_xlabel('\n'+r'$\Delta$PC$_X$ ($\mu m$)') ax.set_ylabel('\n\n'+r'$\Delta$PC$_Z$ ($\mu m$)') ax.set_zlabel('\n\n'+r'$\Delta$PC$_Y$ ($\mu m$)') #plt.title(r'sample plane tilt relative to detector plane'+'\n' # +r'$\tau_X$={0: >#05.2f}'. format(float(np.degrees(self.xtilt_rad))) # +r'° $\nu_Z$= {0: >#05.2f}'. format(float(np.degrees(self.ztilt_rad)))+'° \n' ) min3d=np.min(primary) max3d=np.max(primary) ax.set_xlim3d(min3d, max3d) ax.set_ylim3d(min3d, max3d) ax.set_zlim3d(min3d, max3d) [t.set_va('center') for t in ax.get_yticklabels()] [t.set_ha('left') for t in ax.get_yticklabels()] [t.set_va('center') for t in ax.get_xticklabels()] [t.set_ha('right') for t in ax.get_xticklabels()] [t.set_va('center') for t in ax.get_zticklabels()] [t.set_ha('left') for t in ax.get_zticklabels()] ax.xaxis._axinfo['tick']['inward_factor'] = 0 ax.xaxis._axinfo['tick']['outward_factor'] = 0.4 ax.yaxis._axinfo['tick']['inward_factor'] = 0 ax.yaxis._axinfo['tick']['outward_factor'] = 0.4 ax.zaxis._axinfo['tick']['inward_factor'] = 0 ax.zaxis._axinfo['tick']['outward_factor'] = 0.4 ax.zaxis._axinfo['tick']['outward_factor'] = 0.4 ax.xaxis.set_major_locator(MultipleLocator(3000)) ax.yaxis.set_major_locator(MultipleLocator(3000)) ax.zaxis.set_major_locator(MultipleLocator(3000)) plt.gca().invert_yaxis() # view from detector along negative Z plt.savefig(plotdir+'PCXYZ_FIT.png',dpi=300) # ,bbox_inches = 'tight') if show: plt.show() plt.close()