class ternaryfaces_folded: def __init__(self, ax, ellabels=['A', 'B', 'C', 'D'], offset=None, nintervals=10., outlinealpha=0.2): self.outlinealpha=outlinealpha self.nint=1.*nintervals self.delta=1./self.nint self.ternaryplot=TernaryPlot(ax, outline=False) self.ax=ax self.offset=offset #self.ax.set_xlim(-.1, 2.6) #self.ax.set_ylim(-.1, 3.**.5/2+.1) self.ax.set_ylim(-.1-3.**.5/4., .1+3.**.5/4.) self.cartendpts=numpy.float32([[0, 0], [.5, numpy.sqrt(3.)/2.], [1, 0]]) self.ellabels=ellabels self.scalefcn=lambda ntern:(self.nint-ntern)/self.nint shift=0. self.shift_ntern=[] perminds=[0, 1, 2] self.perminds_ntern=[] for ntern in range(int(self.nint)+1): self.shift_ntern+=[shift] shift+=self.delta*1.5+0.5*self.scalefcn(ntern) self.perminds_ntern+=[perminds] #if ntern%2==0: perminds=[perminds[i] for i in [1, 2, 0]] # else: # perminds=[perminds[i] for i in [1, 0, 2]] self.ax.set_xlim(-.1, shift+self.delta*1.5+1.*self.scalefcn(ntern)+.1) self.patch_xyc=lambda x, y, c, **kwargs:self.ax.add_patch(CirclePolygon((x, y),radius=self.delta/3.**.5,resolution=6, color=c, **kwargs)) self.outline() if offset is None: self.offset=self.delta def xy_ntern(self, x, y, ntern): if ntern%2==1: y=-1.*y+3.**.5/2 y-=3.**.5/2/2. y*=self.scalefcn(ntern) x*=self.scalefcn(ntern) x+=self.shift_ntern[ntern] return x, y def invert_xy_ntern(self, x, y, ntern): x-=self.shift_ntern[ntern] x/=self.scalefcn(ntern) y/=self.scalefcn(ntern) y+=3.**.5/2/2. if ntern%2==1: y=-1.*y+3.**.5/2 return x, y def outline(self): for ntern in range(int(self.nint)): for i, ep in enumerate(self.cartendpts): for ep2 in self.cartendpts[i+1:]: x, y=self.xy_ntern(numpy.array([ep[0], ep2[0]]), numpy.array([ep[1], ep2[1]]), ntern) self.ax.plot(x, y, 'k-', alpha=self.outlinealpha) def label(self, **kwargs):#takeabs is to avoid a negative sign for ~0 negative compositions for count, (va, y) in enumerate(zip(['top','bottom'], [-3.**.5/4.-self.offset, 3.**.5/4.+self.offset])): self.ax.text(count*.5, y, self.ellabels[count], ha='center', va=va, **kwargs) for i in range(0, int(self.nint)): y=(3.**.5/4.)*self.scalefcn(i)+self.offset yd=(3.**.5/4.)*self.scalefcn(i)+self.offset*1.5 if i%2==1: va='bottom' vad='top' yd*=-1 else: va='top' y*=-1 vad='bottom' x=self.shift_ntern[i+1]+.5*self.scalefcn(i+1) self.ax.text(x, y, self.ellabels[(i+2)%3], ha='center', va=va, **kwargs) if i==int(self.nint)-1: x+=self.scalefcn(i+1)+self.offset yd=0. vad='center' had='left' else: had='center' self.ax.text(x, yd, self.ellabels[3]+(r'$_{%d}$' %(int(round(100*(i+1)*self.delta)))), ha=had, va=vad, **kwargs) def toCart(self, quatcomps, ntern): qc=numpy.array(quatcomps) perminds=self.perminds_ntern[ntern] x, y=self.ternaryplot.toCart(qc[:, perminds]) x, y=self.xy_ntern(x, y, ntern) return x, y def scatter(self, quatcomps, c, s='patch', **kwargs): if s=='patch': patchfcn=lambda x, y, c:self.patch_xyc(x, y, c, **kwargs) else: patchfcn=None quatcomps=numpy.int32(numpy.round(quatcomps*self.nint)) for ntern in range(int(self.nint)): ba=quatcomps[:, -1]==ntern self.shellcomps=quatcomps[ba] shellc=c[ba] self.shellcomps=self.shellcomps[:, :-1]/(self.nint-ntern) if len(self.shellcomps)==0: continue x, y=self.toCart(self.shellcomps, ntern) if patchfcn is None: self.ax.scatter(x, y, c=shellc, **kwargs) else: map(patchfcn, x, y, shellc) ba=quatcomps[:, -1]==self.nint if True in ba: self.shellcomps=quatcomps[ba]#only 1 comp but might be duplicated shellc=c[ba] if patchfcn is None: for cv in shellc: self.ax.scatter(self.shift_ntern[-1], 0, c=cv, s=s, **kwargs) else: [patchfcn(self.shift_ntern[-1], 0, cv) for cv in shellc] def toComp(self, x, y, skipinds=range(4)):#takes a single x,y coord from the axes and gets the tirangle by trial and error and converts to a,b,c,d/ skipinds must be the same as that used in .scatter() c=numpy.zeros(4, dtype='float64') for ntern in range(int(self.nint)): xi, yi=self.invert_xy_ntern(x, y, ntern) abc=self.ternaryplot.toComp([[xi, yi]]) if numpy.all((abc>=0.)&(abc<=1.)): print ntern c[self.perminds_ntern[ntern]]=abc*(self.nint-ntern) c[-1]=ntern c*=self.delta return c xcrit, garb=self.xy_ntern(.5,0,ntern)#in the last ternay plot take the x mid-point. y value deosnt' matter if x>xcrit: return numpy.float64([0, 0, 0, 1]) return None
class ternaryfaces_shells: def __init__(self, ax, ellabels=['A', 'B', 'C', 'D'], offset=None, nintervals=10., outlinealpha=0.2, patchscale=1.): self.outlinealpha = outlinealpha self.nint = 1. * nintervals self.delta = 1. / self.nint self.ternaryplot = TernaryPlot(ax, outline=False) self.ax = ax self.ax.set_aspect(1.) #self.ax.set_xlim(-.1, 2.6) #self.ax.set_ylim(-.1, 3.**.5/2+.1) self.ax.set_ylim(-.1 - 3.**.5 / 4., .1 + 3.**.5 / 4.) self.cartendpts = numpy.float32([[0, 0], [.5, numpy.sqrt(3.) / 2.], [1, 0]]) self.ellabels = ellabels self.scalefcn = lambda nshell: (self.nint - 4. * nshell) / self.nint shift = 0. self.shift_nshell = [] for nshell in range(int(self.nint // 4) + 1): self.shift_nshell += [shift] shift += self.delta * 2. + 2. * self.scalefcn(nshell) self.ax.set_xlim(-.1, shift + self.delta + 1. * self.scalefcn(nshell)) #self.fig, self.axis = plt.subplot(nrows=nrows, ncols=ncols, sharex=True, sharey=True) #self.nrows = nrows #self.ncols = ncols self.point_list = [] self.patch_xyc = lambda x, y, c, **kwargs: self.ax.add_patch( CirclePolygon((x, y), radius=patchscale * self.delta / 3.**.5, resolution=6, color=c, **kwargs)) if outlinealpha > 0: self.outline() if offset is None: self.offset = self.delta self.qindsfortern_skipind = [ [1, 2, 3], [2, 3, 0], [3, 0, 1], [0, 1, 2] ] #sets the order of elements assuming mirror over y for skipA and skipC # def xy_skipind(self, x, y, skipind, nshell): if skipind % 2 == 0: y = -1. * y + 3.**.5 / 2 y -= 3.**.5 / 2 / 2. y *= self.scalefcn(nshell) x += ([0.5, 1, 1.5, 0.][skipind]) x *= self.scalefcn(nshell) x += self.shift_nshell[nshell] return x, y def invert_xy_skipind(self, x, y, skipind, nshell): x -= self.shift_nshell[nshell] x /= self.scalefcn(nshell) x -= ([0.5, 1, 1.5, 0.][skipind]) y /= self.scalefcn(nshell) y += 3.**.5 / 2 / 2. if skipind % 2 == 0: y = -1. * y + 3.**.5 / 2 return x, y def outline(self, **kwargs): for nshell in range(int(self.nint // 4) + int(self.nint % 4 > 0)): for skipind in range(4): skipfirstline = skipind != 3 for i, ep in enumerate(self.cartendpts): for ep2 in self.cartendpts[i + 1:]: if skipfirstline: skipfirstline = False continue x, y = self.xy_skipind(numpy.array([ep[0], ep2[0]]), numpy.array([ep[1], ep2[1]]), skipind, nshell) self.ax.plot(x, y, 'k-', alpha=self.outlinealpha, **kwargs) def label( self, onlyterns=False, allelements=False, primeelements=False, **kwargs ): #takeabs is to avoid a negative sign for ~0 negative compositions for va, xst, y, inds in zip( ['top', 'bottom'], [0, .5], [-3.**.5 / 4. - self.offset, 3.**.5 / 4. + self.offset], [[0, 2, 0], [1, 3, 1]]): for count, i in enumerate(inds): self.ax.text(xst + count * 1., y, self.ellabels[i], ha='center', va=va, **kwargs) if onlyterns: return for nshell in range(1, int(self.nint // 4) + int(self.nint % 4 > 0)): for va, xst, y, inds in zip(['top', 'bottom'], [0, .5], [ -3.**.5 / 4. * self.scalefcn(nshell) - self.offset, 3.**.5 / 4. * self.scalefcn(nshell) + self.offset ], [[2, 0], [3, 1]]): for count, i in enumerate(inds): l = self.ellabels[i] if primeelements: l += "$'$" * nshell else: l += (r'$_{%d}$' % int(round(100 * (1. - 3 * nshell * self.delta)))) x = (xst + (count + 1) * 1. ) * self.scalefcn(nshell) + self.shift_nshell[nshell] if allelements: temp = copy.copy(self.ellabels) temp.pop(i) l += ''.join([ el + (r'$_{%d}$' % int(round(100 * (nshell * self.delta)))) for el in temp ]) self.ax.text(x, y, l, ha='center', va=va, **kwargs) def toCart( self, quatcomps, skipinds=range(4), nshell=0 ): #binary and ternary lines need to be plotted multiple times so returns set of (inds,x,y) qc = numpy.array(quatcomps) #qc=qc[(qc==0.).sum(axis=1)>0] # x=numpy.empty(len(qc), dtype='float32') # y=numpy.empty(len(qc), dtype='float32') inds_x_y = [] for si in skipinds: inds = numpy.where(qc[:, si] == 0.)[0] if len(inds) == 0: continue xt, yt = self.ternaryplot.toCart( qc[inds][:, self.qindsfortern_skipind[si]]) x, y = self.xy_skipind(xt, yt, si, nshell) inds_x_y += [(inds, x, y)] return inds_x_y def scatter(self, quatcomps, c, skipinds=range(4), s='patch', **kwargs): if s == 'patch': patchfcn = lambda x, y, c: self.patch_xyc(x, y, c, **kwargs) else: patchfcn = None quatcomps = numpy.int32(numpy.round(quatcomps * self.nint)) for nshell in range(int(self.nint // 4) + int(self.nint % 4 > 0)): ba = ((quatcomps == nshell).sum(axis=1, dtype='int32') > 0) & ( (quatcomps >= nshell).prod(axis=1, dtype='int32') > 0) self.shellcomps = quatcomps[ba] shellc = c[ba] self.shellcomps = (self.shellcomps - nshell) / (self.nint - 4. * nshell) inds_x_y = self.toCart(self.shellcomps, skipinds=skipinds, nshell=nshell) for inds, x, y in inds_x_y: if patchfcn is None: #self.ax.scatter(x, y, c=shellc[inds], s=s, **kwargs) self.point_list.append( self.ax.scatter(x, y, c=shellc[inds], s=s, picker=True, **kwargs)) else: map(patchfcn, x, y, shellc[inds]) if self.nint % 4 == 0: #single point with no frame ba = (quatcomps == self.nint // 4).prod(axis=1, dtype='int32') > 0 if True in ba: self.shellcomps = quatcomps[ ba] #only 1 comp but might be duplicated shellc = c[ba] if patchfcn is None: for cv in shellc: #self.ax.scatter(self.shift_nshell[-1], 0, c=cv, s=s, **kwargs) self.point_list.append( self.ax.scatter(self.shift_nshell[-1], 0, c=cv, s=s, picker=True, **kwargs)) else: [patchfcn(self.shift_nshell[-1], 0, cv) for cv in shellc] #Returns a list with all the points in the scatterplot return self.point_list def quatscatter(self, quatcomps, c, skipinds=range(4), azim=-60, elev=30, alphaall=.2, alphashell=1., fontsize=14, outline=True, **kwargs): numsubs = int(self.nint // 4) + 1 quatcomps = numpy.int32(numpy.round(quatcomps * self.nint)) for nshell in range(int(self.nint // 4) + int(self.nint % 4 > 0)): ba = ((quatcomps == nshell).sum(axis=1, dtype='int32') > 0) & ( (quatcomps >= nshell).prod(axis=1, dtype='int32') > 0) shellcomps = quatcomps[ba] shellc = c[ba] q = QuaternaryPlot((1, numsubs, nshell + 1), outline=outline) if alphaall > 0: q.scatter(quatcomps * 1. / self.nint, c=c, alpha=alphaall, **kwargs) if alphashell > 0: q.scatter(shellcomps * 1. / self.nint, c=shellc, alpha=alphashell, **kwargs) if fontsize > 0: q.label(ha='center', va='center', fontsize=fontsize) q.set_projection(azim=azim, elev=elev) if self.nint % 4 == 0: #single point with no frame ba = (quatcomps == self.nint // 4).prod(axis=1, dtype='int32') > 0 if True in ba: shellcomps = quatcomps[ ba] #only 1 comp but might be duplicated shellc = c[ba] q = QuaternaryPlot((1, numsubs, numsubs), outline=outline) q.scatter(quatcomps * 1. / self.nint, c=c, alpha=alphaall, **kwargs) q.scatter(shellcomps * 1. / self.nint, c=shellc, alpha=alphashell, **kwargs) if fontsize > 0: q.label(ha='center', va='center', fontsize=fontsize) q.set_projection(azim=azim, elev=elev) def quatplot3D(self, quatcomps, c, skipinds=range(4), azim=-60, elev=30, alphaall=.2, alphashell=1., fontsize=14, outline=True, **kwargs): numsubs = int(self.nint // 4) + 1 quatcomps = numpy.int32(numpy.round(quatcomps * self.nint)) for nshell in range(int(self.nint // 4) + int(self.nint % 4 > 0)): ba = ((quatcomps == nshell).sum(axis=1, dtype='int32') > 0) & ( (quatcomps >= nshell).prod(axis=1, dtype='int32') > 0) shellcomps = quatcomps[ba] shellc = c[ba] q = QuaternaryPlot((1, numsubs, nshell + 1), outline=outline) if alphaall > 0: q.plot3D(quatcomps * 1. / self.nint, c, alpha=alphaall, **kwargs) if alphashell > 0: q.plot3D(shellcomps * 1. / self.nint, shellc, alpha=alphashell, **kwargs) if fontsize > 0: q.label(ha='center', va='center', fontsize=fontsize) q.set_projection(azim=azim, elev=elev) if self.nint % 4 == 0: #single point with no frame ba = (quatcomps == self.nint // 4).prod(axis=1, dtype='int32') > 0 if True in ba: shellcomps = quatcomps[ ba] #only 1 comp but might be duplicated shellc = c[ba] q = QuaternaryPlot((1, numsubs, numsubs), outline=outline) q.plot3D(quatcomps * 1. / self.nint, c, alpha=alphaall, **kwargs) q.plot3D(shellcomps * 1. / self.nint, shellc, alpha=alphashell, **kwargs) if fontsize > 0: q.label(ha='center', va='center', fontsize=fontsize) q.set_projection(azim=azim, elev=elev) def toComp( self, x, y, skipinds=range(4) ): #takes a single x,y coord from the axes and gets the tirangle by trial and error and converts to a,b,c,d/ skipinds must be the same as that used in .scatter() c = numpy.zeros(4, dtype='float64') for nshell in range(int(self.nint // 4) + int(self.nint % 4 > 0)): for si in skipinds: xi, yi = self.invert_xy_skipind(x, y, si, nshell) abc = self.ternaryplot.toComp([[xi, yi]]) if numpy.all((abc >= 0.) & (abc <= 1.)): c[self.qindsfortern_skipind[si]] = numpy.round( (abc * (self.nint - 4. * nshell) + nshell)) c[si] = nshell c *= self.delta return c if self.nint % 4 == 0: #if there is an equi-atomic single point outside the triangles, then count it as clicked if outside triagnels with x bigger than middle of the last triangle, xcrit, garb = self.xy_skipind( .5, 0, si, nshell ) #in the last ternay plot take the x mid-point. y value deosnt' matter if x > xcrit: return numpy.ones(4, dtype='float64') / 4. return None
Y = cmp.values / 100 #define subset Xsubset, Ysubset that is fed to the GPR model #and Xfit where fitting is done x = np.linspace(np.min(X[:, 0]), np.max(X[:, 0]), 50) y = np.linspace(np.min(X[:, 1]), np.max(X[:, 1]), 50) xv, yv = np.meshgrid(x, y) Xfit_ = np.array([xv.flatten(), yv.flatten()]) idx = [] for i in range(len(Xfit_.T)): if is_in_hull(Xfit_[:, i], X): idx.append(i) Xfit = Xfit_[:, idx] #%% Predict using gaussian process regressor kernel = RBF([1.0]) + WhiteKernel(noise_level=0.0336) gpr = GaussianProcessRegressor(kernel=kernel) gpr.fit(Xsubset, Ysubset) Ygpr, Ystd = gpr.predict(Xfit.T, return_std=True) #%% plot predictions ax = pylab.gca() stp = TernaryPlot(ax, ellabels=cmp.columns) x, y = stp.toCart(Ygpr) plt.scatter(x, y, s=10, c=Ystd) stp.label(fontsize=16) plt.colorbar() plt.show()
class ternaryfaces_shells: def __init__(self, ax, ellabels=['A', 'B', 'C', 'D'], offset=None, nintervals=10., outlinealpha=0.2, patchscale=1.): self.outlinealpha=outlinealpha self.nint=1.*nintervals self.delta=1./self.nint self.ternaryplot=TernaryPlot(ax, outline=False) self.ax=ax self.ax.set_aspect(1.) #self.ax.set_xlim(-.1, 2.6) #self.ax.set_ylim(-.1, 3.**.5/2+.1) self.ax.set_ylim(-.1-3.**.5/4., .1+3.**.5/4.) self.cartendpts=numpy.float32([[0, 0], [.5, numpy.sqrt(3.)/2.], [1, 0]]) self.ellabels=ellabels self.scalefcn=lambda nshell:(self.nint-4.*nshell)/self.nint shift=0. self.shift_nshell=[] for nshell in range(int(self.nint//4)+1): self.shift_nshell+=[shift] shift+=self.delta*2.+2.*self.scalefcn(nshell) self.ax.set_xlim(-.1, shift+self.delta+1.*self.scalefcn(nshell)) self.patch_xyc=lambda x, y, c, **kwargs:self.ax.add_patch(CirclePolygon((x, y),radius=patchscale*self.delta/3.**.5,resolution=6, color=c, **kwargs)) if outlinealpha>0: self.outline() if offset is None: self.offset=self.delta self.qindsfortern_skipind=[[1, 2, 3], [2, 3, 0], [3, 0, 1], [0, 1, 2]]#sets the order of elements assuming mirror over y for skipA and skipC def xy_skipind(self, x, y, skipind, nshell): if skipind%2==0: y=-1.*y+3.**.5/2 y-=3.**.5/2/2. y*=self.scalefcn(nshell) x+=([0.5, 1, 1.5, 0.][skipind]) x*=self.scalefcn(nshell) x+=self.shift_nshell[nshell] return x, y def invert_xy_skipind(self, x, y, skipind, nshell): x-=self.shift_nshell[nshell] x/=self.scalefcn(nshell) x-=([0.5, 1, 1.5, 0.][skipind]) y/=self.scalefcn(nshell) y+=3.**.5/2/2. if skipind%2==0: y=-1.*y+3.**.5/2 return x, y def outline(self, **kwargs): for nshell in range(int(self.nint//4)+int(self.nint%4>0)): for skipind in range(4): skipfirstline=skipind!=3 for i, ep in enumerate(self.cartendpts): for ep2 in self.cartendpts[i+1:]: if skipfirstline: skipfirstline=False continue x, y=self.xy_skipind(numpy.array([ep[0], ep2[0]]), numpy.array([ep[1], ep2[1]]), skipind, nshell) self.ax.plot(x, y, 'k-', alpha=self.outlinealpha, **kwargs) def label(self, onlyterns=False, allelements=False, primeelements=False, **kwargs):#takeabs is to avoid a negative sign for ~0 negative compositions for va, xst, y, inds in zip(['top', 'bottom'], [0, .5], [-3.**.5/4.-self.offset, 3.**.5/4.+self.offset], [[0, 2, 0], [1, 3, 1]]): for count, i in enumerate(inds): self.ax.text(xst+count*1., y, self.ellabels[i], ha='center', va=va, **kwargs) if onlyterns: return for nshell in range(1, int(self.nint//4)+int(self.nint%4>0)): for va, xst, y, inds in zip(['top', 'bottom'], [0, .5], [-3.**.5/4.*self.scalefcn(nshell)-self.offset, 3.**.5/4.*self.scalefcn(nshell)+self.offset], [[2, 0], [3, 1]]): for count, i in enumerate(inds): l=self.ellabels[i] if primeelements: l+="$'$"*nshell else: l+=(r'$_{%d}$' %int(round(100*(1.-3*nshell*self.delta)))) x=(xst+(count+1)*1.)*self.scalefcn(nshell)+self.shift_nshell[nshell] if allelements: temp=copy.copy(self.ellabels) temp.pop(i) l+=''.join([el+(r'$_{%d}$' %int(round(100*(nshell*self.delta)))) for el in temp]) self.ax.text(x, y, l, ha='center', va=va, **kwargs) def toCart(self, quatcomps, skipinds=range(4), nshell=0):#binary and ternary lines need to be plotted multiple times so returns set of (inds,x,y) qc=numpy.array(quatcomps) #qc=qc[(qc==0.).sum(axis=1)>0] # x=numpy.empty(len(qc), dtype='float32') # y=numpy.empty(len(qc), dtype='float32') inds_x_y=[] for si in skipinds: inds=numpy.where(qc[:, si]==0.)[0] if len(inds)==0: continue xt, yt=self.ternaryplot.toCart(qc[inds][:, self.qindsfortern_skipind[si]]) x, y=self.xy_skipind(xt, yt, si, nshell) inds_x_y+=[(inds, x, y)] return inds_x_y def scatter(self, quatcomps, c, skipinds=range(4), s='patch', **kwargs): if s=='patch': patchfcn=lambda x, y, c:self.patch_xyc(x, y, c, **kwargs) else: patchfcn=None quatcomps=numpy.int32(numpy.round(quatcomps*self.nint)) for nshell in range(int(self.nint//4)+int(self.nint%4>0)): ba=((quatcomps==nshell).sum(axis=1, dtype='int32')>0)&((quatcomps>=nshell).prod(axis=1, dtype='int32')>0) self.shellcomps=quatcomps[ba] shellc=c[ba] self.shellcomps=(self.shellcomps-nshell)/(self.nint-4.*nshell) inds_x_y=self.toCart(self.shellcomps, skipinds=skipinds, nshell=nshell) for inds, x, y in inds_x_y: if patchfcn is None: self.ax.scatter(x, y, c=shellc[inds], s=s, **kwargs) else: map(patchfcn, x, y, shellc[inds]) if self.nint%4==0: #single point with no frame ba=(quatcomps==self.nint//4).prod(axis=1, dtype='int32')>0 if True in ba: self.shellcomps=quatcomps[ba]#only 1 comp but might be duplicated shellc=c[ba] if patchfcn is None: for cv in shellc: self.ax.scatter(self.shift_nshell[-1], 0, c=cv, s=s, **kwargs) else: [patchfcn(self.shift_nshell[-1], 0, cv) for cv in shellc] def quatscatter(self, quatcomps, c, skipinds=range(4), azim=-60, elev=30, alphaall=.2, alphashell=1., fontsize=14, outline=True, **kwargs): numsubs=int(self.nint//4)+1 quatcomps=numpy.int32(numpy.round(quatcomps*self.nint)) for nshell in range(int(self.nint//4)+int(self.nint%4>0)): ba=((quatcomps==nshell).sum(axis=1, dtype='int32')>0)&((quatcomps>=nshell).prod(axis=1, dtype='int32')>0) shellcomps=quatcomps[ba] shellc=c[ba] q=QuaternaryPlot((1, numsubs, nshell+1), outline=outline) if alphaall>0: q.scatter(quatcomps*1./self.nint,c=c, alpha=alphaall, **kwargs) if alphashell>0: q.scatter(shellcomps*1./self.nint,c=shellc, alpha=alphashell, **kwargs) if fontsize>0: q.label(ha='center', va='center', fontsize=fontsize) q.set_projection(azim=azim, elev=elev) if self.nint%4==0: #single point with no frame ba=(quatcomps==self.nint//4).prod(axis=1, dtype='int32')>0 if True in ba: shellcomps=quatcomps[ba]#only 1 comp but might be duplicated shellc=c[ba] q=QuaternaryPlot((1, numsubs, numsubs), outline=outline) q.scatter(quatcomps*1./self.nint,c=c, alpha=alphaall, **kwargs) q.scatter(shellcomps*1./self.nint,c=shellc, alpha=alphashell, **kwargs) if fontsize>0: q.label(ha='center', va='center', fontsize=fontsize) q.set_projection(azim=azim, elev=elev) def quatplot3D(self, quatcomps, c, skipinds=range(4), azim=-60, elev=30, alphaall=.2, alphashell=1., fontsize=14, outline=True, **kwargs): numsubs=int(self.nint//4)+1 quatcomps=numpy.int32(numpy.round(quatcomps*self.nint)) for nshell in range(int(self.nint//4)+int(self.nint%4>0)): ba=((quatcomps==nshell).sum(axis=1, dtype='int32')>0)&((quatcomps>=nshell).prod(axis=1, dtype='int32')>0) shellcomps=quatcomps[ba] shellc=c[ba] q=QuaternaryPlot((1, numsubs, nshell+1), outline=outline) if alphaall>0: q.plot3D(quatcomps*1./self.nint,c, alpha=alphaall, **kwargs) if alphashell>0: q.plot3D(shellcomps*1./self.nint,shellc, alpha=alphashell, **kwargs) if fontsize>0: q.label(ha='center', va='center', fontsize=fontsize) q.set_projection(azim=azim, elev=elev) if self.nint%4==0: #single point with no frame ba=(quatcomps==self.nint//4).prod(axis=1, dtype='int32')>0 if True in ba: shellcomps=quatcomps[ba]#only 1 comp but might be duplicated shellc=c[ba] q=QuaternaryPlot((1, numsubs, numsubs), outline=outline) q.plot3D(quatcomps*1./self.nint,c, alpha=alphaall, **kwargs) q.plot3D(shellcomps*1./self.nint,shellc, alpha=alphashell, **kwargs) if fontsize>0: q.label(ha='center', va='center', fontsize=fontsize) q.set_projection(azim=azim, elev=elev) def toComp(self, x, y, skipinds=range(4)):#takes a single x,y coord from the axes and gets the tirangle by trial and error and converts to a,b,c,d/ skipinds must be the same as that used in .scatter() c=numpy.zeros(4, dtype='float64') for nshell in range(int(self.nint//4)+int(self.nint%4>0)): for si in skipinds: xi, yi=self.invert_xy_skipind(x, y, si, nshell) abc=self.ternaryplot.toComp([[xi, yi]]) if numpy.all((abc>=0.)&(abc<=1.)): c[self.qindsfortern_skipind[si]]=numpy.round((abc*(self.nint-4.*nshell)+nshell)) c[si]=nshell c*=self.delta return c if self.nint%4==0:#if there is an equi-atomic single point outside the triangles, then count it as clicked if outside triagnels with x bigger than middle of the last triangle, xcrit, garb=self.xy_skipind(.5,0,si, nshell)#in the last ternay plot take the x mid-point. y value deosnt' matter if x>xcrit: return numpy.ones(4, dtype='float64')/4. return None
class ternaryfaces: def __init__(self, ax, ellabels=['A', 'B', 'C', 'D'], offset=None, nintervals=10., outlinealpha=0.4): self.outlinealpha = outlinealpha self.ternaryplot = TernaryPlot(ax, outline=False) self.ax = ax self.ax.set_xlim(-.1, 2.6) self.ax.set_ylim(-.1, 3.**.5 / 2 + .1) self.cartendpts = numpy.float32([[0, 0], [.5, numpy.sqrt(3.) / 2.], [1, 0]]) self.ellabels = ellabels self.outline() self.nint = 1. * nintervals self.delta = 1. / self.nint self.patch_xyc = lambda x, y, c, **kwargs: self.ax.add_patch( CirclePolygon((x, y), radius=self.delta / 3.**.5, resolution=6, color=c, **kwargs)) if offset is None: self.offset = self.delta self.qindsfortern_skipind = [ [1, 2, 3], [2, 3, 0], [3, 0, 1], [0, 1, 2] ] #sets the order of elements assuming mirror over y for skipA and skipC def xy_skipind(self, x, y, skipind): x += ([0.5, 1, 1.5, 0.][skipind]) if skipind % 2 == 0: y = -1. * y + 3.**.5 / 2 return x, y def invert_xy_skipind(self, x, y, skipind): x -= ([0.5, 1, 1.5, 0.][skipind]) if skipind % 2 == 0: y = -1. * y + 3.**.5 / 2 return x, y def outline(self): for skipind in range(4): skipfirstline = skipind != 3 for i, ep in enumerate(self.cartendpts): for ep2 in self.cartendpts[i + 1:]: if skipfirstline: skipfirstline = False continue x, y = self.xy_skipind(numpy.array([ep[0], ep2[0]]), numpy.array([ep[1], ep2[1]]), skipind) self.ax.plot(x, y, 'k-', alpha=self.outlinealpha) def label( self, **kwargs ): #takeabs is to avoid a negative sign for ~0 negative compositions for va, xst, y, inds in zip(['top', 'bottom'], [0, .5], [-self.offset, 3.**.5 / 2 + self.offset], [[0, 2, 0], [1, 3, 1]]): for count, i in enumerate(inds): self.ax.text(xst + count * 1., y, self.ellabels[i], ha='center', va=va, **kwargs) def toCart( self, quatcomps, skipinds=range(4) ): #binary and ternary lines need to be plotted multiple times so returns set of (inds,x,y) qc = numpy.array(quatcomps) #qc=qc[(qc==0.).sum(axis=1)>0] # x=numpy.empty(len(qc), dtype='float32') # y=numpy.empty(len(qc), dtype='float32') inds_x_y = [] for si in skipinds: inds = numpy.where(qc[:, si] == 0.)[0] if len(inds) == 0: continue xt, yt = self.ternaryplot.toCart( qc[inds][:, self.qindsfortern_skipind[si]]) x, y = self.xy_skipind(xt, yt, si) inds_x_y += [(inds, x, y)] return inds_x_y def scatter(self, quatcomps, c, skipinds=range(4), s='patch', **kwargs): if s == 'patch': patchfcn = lambda x, y, c: self.patch_xyc(x, y, c, **kwargs) else: patchfcn = None inds_x_y = self.toCart(quatcomps, skipinds=skipinds) for inds, x, y in inds_x_y: if patchfcn is None: self.ax.scatter(x, y, c=c[inds], s=s, **kwargs) else: map(patchfcn, x, y, c[inds]) def toComp( self, x, y, skipinds=range(4) ): #takes a single x,y coord from the axes and gets the tirangle by trial and error and converts to a,b,c,d/ skipinds must be the same as that used in .scatter() c = numpy.zeros(4, dtype='float64') for si in skipinds: xi, yi = self.invert_xy_skipind(x, y, si) abc = self.ternaryplot.toComp([[xi, yi]]) if numpy.all((abc >= 0.) & (abc <= 1.)): c[self.qindsfortern_skipind[si]] = abc return c return None
z=numpy.zeros(3, dtype='float64') ctr2=numpy.ones(3, dtype='float64')/2. endmembers=[] lineendpairs=[] #iterate over 4 end members and draw a line from there to center of opposing face, e.g. (0,.33,.33,.33) for i in range(3): a=copy.copy(z) a[i]=1. b=copy.copy(ctr2) b[i]=0. q.line(a, b, fmt='b-') q.scatter([b], c='b', s=15) endmembers+=[a] lineendpairs+=[[a, b]] #convert the end members and pairs of endpts to cartesian xy_lineendpairs=[numpy.array(q.toCart(ls)).T for ls in lineendpairs] xy_endmembers=numpy.array(q.toCart(endmembers)).T #choose the composition of a phase and draw the trivial phase field lines phcomp=numpy.array([.5, .3, .2]) q.scatter([phcomp], c='r', s=20) for i in range(3): a=copy.copy(z) a[i]=1. q.line(a, phcomp, fmt='r-') # iterate over all 4 phase field triangular boundaries (triangle defined by 3 points, the phase p0 and 2 end members p1,p2) and all 4 composition lines. find intersections p0=numpy.array(q.toCart([phcomp])).T[0] xy_intr_dlist=[] for countends, (p1) in enumerate(xy_endmembers): for countlines, (l0, l1) in enumerate(xy_lineendpairs):
z = numpy.zeros(3, dtype='float64') ctr2 = numpy.ones(3, dtype='float64') / 2. endmembers = [] lineendpairs = [] #iterate over 4 end members and draw a line from there to center of opposing face, e.g. (0,.33,.33,.33) for i in range(3): a = copy.copy(z) a[i] = 1. b = copy.copy(ctr2) b[i] = 0. q.line(a, b, fmt='b-') q.scatter([b], c='b', s=15) endmembers += [a] lineendpairs += [[a, b]] #convert the end members and pairs of endpts to cartesian xy_lineendpairs = [numpy.array(q.toCart(ls)).T for ls in lineendpairs] xy_endmembers = numpy.array(q.toCart(endmembers)).T #choose the composition of a phase and draw the trivial phase field lines phcomp = numpy.array([.5, .3, .2]) q.scatter([phcomp], c='r', s=20) for i in range(3): a = copy.copy(z) a[i] = 1. q.line(a, phcomp, fmt='r-') # iterate over all 4 phase field triangular boundaries (triangle defined by 3 points, the phase p0 and 2 end members p1,p2) and all 4 composition lines. find intersections p0 = numpy.array(q.toCart([phcomp])).T[0] xy_intr_dlist = [] for countends, (p1) in enumerate(xy_endmembers): for countlines, (l0, l1) in enumerate(xy_lineendpairs):
class ternaryfaces: def __init__(self, ax, ellabels=['A', 'B', 'C', 'D'], offset=None, nintervals=10., outlinealpha=0.4): self.outlinealpha=outlinealpha self.ternaryplot=TernaryPlot(ax, outline=False) self.ax=ax self.ax.set_xlim(-.1, 2.6) self.ax.set_ylim(-.1, 3.**.5/2+.1) self.cartendpts=numpy.float32([[0, 0], [.5, numpy.sqrt(3.)/2.], [1, 0]]) self.ellabels=ellabels self.outline() self.nint=1.*nintervals self.delta=1./self.nint self.patch_xyc=lambda x, y, c, **kwargs:self.ax.add_patch(CirclePolygon((x, y),radius=self.delta/3.**.5,resolution=6, color=c, **kwargs)) if offset is None: self.offset=self.delta self.qindsfortern_skipind=[[1, 2, 3], [2, 3, 0], [3, 0, 1], [0, 1, 2]]#sets the order of elements assuming mirror over y for skipA and skipC def xy_skipind(self, x, y, skipind): x+=([0.5, 1, 1.5, 0.][skipind]) if skipind%2==0: y=-1.*y+3.**.5/2 return x, y def invert_xy_skipind(self, x, y, skipind): x-=([0.5, 1, 1.5, 0.][skipind]) if skipind%2==0: y=-1.*y+3.**.5/2 return x, y def outline(self): for skipind in range(4): skipfirstline=skipind!=3 for i, ep in enumerate(self.cartendpts): for ep2 in self.cartendpts[i+1:]: if skipfirstline: skipfirstline=False continue x, y=self.xy_skipind(numpy.array([ep[0], ep2[0]]), numpy.array([ep[1], ep2[1]]), skipind) self.ax.plot(x, y, 'k-', alpha=self.outlinealpha) def label(self, **kwargs):#takeabs is to avoid a negative sign for ~0 negative compositions for va, xst, y, inds in zip(['top', 'bottom'], [0, .5], [-self.offset, 3.**.5/2+self.offset], [[0, 2, 0], [1, 3, 1]]): for count, i in enumerate(inds): self.ax.text(xst+count*1., y, self.ellabels[i], ha='center', va=va, **kwargs) def toCart(self, quatcomps, skipinds=range(4)):#binary and ternary lines need to be plotted multiple times so returns set of (inds,x,y) qc=numpy.array(quatcomps) #qc=qc[(qc==0.).sum(axis=1)>0] # x=numpy.empty(len(qc), dtype='float32') # y=numpy.empty(len(qc), dtype='float32') inds_x_y=[] for si in skipinds: inds=numpy.where(qc[:, si]==0.)[0] if len(inds)==0: continue xt, yt=self.ternaryplot.toCart(qc[inds][:, self.qindsfortern_skipind[si]]) x, y=self.xy_skipind(xt, yt, si) inds_x_y+=[(inds, x, y)] return inds_x_y def scatter(self, quatcomps, c, skipinds=range(4), s='patch', **kwargs): if s=='patch': patchfcn=lambda x, y, c:self.patch_xyc(x, y, c, **kwargs) else: patchfcn=None inds_x_y=self.toCart(quatcomps, skipinds=skipinds) for inds, x, y in inds_x_y: if patchfcn is None: self.ax.scatter(x, y, c=c[inds], s=s, **kwargs) else: map(patchfcn, x, y, c[inds]) def toComp(self, x, y, skipinds=range(4)):#takes a single x,y coord from the axes and gets the tirangle by trial and error and converts to a,b,c,d/ skipinds must be the same as that used in .scatter() c=numpy.zeros(4, dtype='float64') for si in skipinds: xi, yi=self.invert_xy_skipind(x, y, si) abc=self.ternaryplot.toComp([[xi, yi]]) if numpy.all((abc>=0.)&(abc<=1.)): c[self.qindsfortern_skipind[si]]=abc return c return None