Source code for particlespy.ptcl_class

# -*- coding: utf-8 -*-
"""
Created on Tue Jul 31 14:51:58 2018

@author: qzo13262
"""

import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage import interpolation
from particlespy.particle_save import save_plist
from sklearn import feature_extraction, cluster, preprocessing
import itertools as it
from mpl_toolkits.mplot3d import Axes3D

[docs]class particle(object): """A segmented particle object. Attributes ---------- properties : dict Dictionary of particle properties created by the ParticleAnalysis() function. origin : str Origin of particle data, e.g. filename or acquisition number. zone : str Zone axis of particle. mask : array Boolean array corresponding to the particle pixels on the original image. image : Hyperspy signal object Image of particle. maps : dict Dictionary containing elemental maps of the particle. spectrum : Hyperspy signal object Spectrum obtained from the particle. composition : dict Dictionary of composition values for the particle. """ def __init__(self): self.properties = {}
[docs] def set_origin(self, origin): """A container for the origin of data (filename, acquisition number etc.)""" self.origin = origin
[docs] def set_area(self, area, units): self.properties['area'] = {'value':area,'units':units}
[docs] def set_circdiam(self, circdiam, units): self.properties['equivalent circular diameter'] = {'value':circdiam,'units':units}
[docs] def set_axes_lengths(self,axeslengths,units): self.properties['major axis length'] = {'value':axeslengths[0],'units':units} self.properties['minor axis length'] = {'value':axeslengths[1],'units':units}
[docs] def set_circularity(self, circularity): self.properties['circularity'] = {'value':circularity,'units':None}
[docs] def set_eccentricity(self,eccentricity): self.properties['eccentricity'] = {'value':eccentricity,'units':None}
[docs] def set_intensity(self,intensity): self.properties['intensity'] = {'value':intensity,'units':None}
[docs] def set_property(self,propname,value,units): """ Give a particle() object an arbitrary property. Parameters ---------- propname : str The name of the property to set. value : The value of the property. units : The units of the property. Example ------- >>> particle.set_property('area',10.0,'nm') """ self.properties[propname] = {'value':value, 'units': units}
[docs] def set_zone(self, zone): self.zone = zone
[docs] def set_boundingbox(self, bbox): self.bbox = bbox
[docs] def set_mask(self, mask): self.mask = mask
[docs] def store_im(self,p_im): self.image = p_im
[docs] def maps_gen(self): self.maps = {}
[docs] def store_map(self,p_map,element): self.maps[element] = p_map
[docs] def store_spectrum(self,spectrum,stype): self.spectrum[stype] = spectrum
[docs] def store_composition(self,composition): self.composition = {el.metadata.Sample.elements[0]:el.data for el in composition}
[docs]class particle_list(object): """A particle list object.""" def __init__(self): self.list = []
[docs] def append(self,particle): self.list.append(particle)
[docs] def save(self,filename): save_plist(self,filename)
[docs] def plot(self,prop_list=['area'],**kwargs): """ Plots properties of all particles in the Particle_list. If one property given, displays a histogram of the chosen particle property. If two properties given, displays a scatter plot of the two properties. Parameters ---------- prop_list : str or list A particle property or a list of the names of the properties to plot. **kwargs Keyword arguments for matplotlib plotting functions. Examples -------- particles.plot('area', bins=20) particles.plot(['equivalent circular diameter','circularity']) """ if isinstance(prop_list,str): fig = plt.figure() ax = fig.add_subplot(111) self._plot_one_property(prop_list,ax,**kwargs) else: if len(prop_list) == 1: fig = plt.figure() ax = fig.add_subplot(111) self._plot_one_property(prop_list[0],ax,**kwargs) elif len(prop_list) == 2: fig = plt.figure() ax = fig.add_subplot(111) self._plot_two_properties(prop_list,ax,**kwargs) elif len(prop_list) == 3: fig3d = plt.figure() ax = fig3d.add_subplot(111, projection='3d') self._plot_three_properties(prop_list,ax,**kwargs) else: print("Can only plot a maximum of three properties, please change the length of the property list.") plt.show()
def _plot_one_property(self,prop,ax,**kwargs): property_list = [] for p in self.list: property_list.append(p.properties[prop]['value']) ax.hist(property_list,**kwargs) if self.list[0].properties[prop]['units'] == None: ax.set_xlabel(prop.capitalize()) else: ax.set_xlabel(prop.capitalize()+" ("+self.list[0].properties[prop]['units']+")") plt.ylabel("No. of particles") def _plot_two_properties(self,prop_list,ax,**kwargs): property_list_one = [] property_list_two = [] for p in self.list: property_list_one.append(p.properties[prop_list[0]]['value']) property_list_two.append(p.properties[prop_list[1]]['value']) ax.scatter(property_list_one,property_list_two,**kwargs) if self.list[0].properties[prop_list[0]]['units'] == None: ax.set_xlabel(prop_list[0].capitalize()) else: ax.set_xlabel(prop_list[0].capitalize()+" ("+self.list[0].properties[prop_list[0]]['units']+")") if self.list[0].properties[prop_list[1]]['units'] == None: ax.set_ylabel(prop_list[1].capitalize()) else: ax.set_ylabel(prop_list[1].capitalize()+" ("+self.list[0].properties[prop_list[1]]['units']+")") def _plot_three_properties(self, prop_list,ax,**kwargs): property_list_one = [] property_list_two = [] property_list_three = [] for p in self.list: property_list_one.append(p.properties[prop_list[0]]['value']) property_list_two.append(p.properties[prop_list[1]]['value']) property_list_three.append(p.properties[prop_list[2]]['value']) ax.scatter(property_list_one, property_list_two, property_list_three,**kwargs) if self.list[0].properties[prop_list[0]]['units'] == None: ax.set_xlabel(prop_list[0].capitalize()) else: ax.set_xlabel(prop_list[0].capitalize()+" ("+self.list[0].properties[prop_list[0]]['units']+")") if self.list[0].properties[prop_list[1]]['units'] == None: ax.set_ylabel(prop_list[1].capitalize()) else: ax.set_ylabel(prop_list[1].capitalize()+" ("+self.list[0].properties[prop_list[1]]['units']+")") if self.list[0].properties[prop_list[2]]['units'] == None: ax.set_zlabel(prop_list[2].capitalize()) else: ax.set_zlabel(prop_list[2].capitalize()+" ("+self.list[0].properties[prop_list[2]]['units']+")")
[docs] def normalize_boxing(self,even=False): """ Normalizes the size of all particle images so that their dimensions are equal. Example ------- >>> particles.normalize_boxing() """ dimensions = [] for particle in self.list: dimensions.append(particle.image.data.shape[0]) dimensions.append(particle.image.data.shape[1]) if even==True: if (max(dimensions) % 2) == 0: max_dim = max(dimensions) else: max_dim = max(dimensions) + 1 else: max_dim = max(dimensions) for i,particle in enumerate(self.list): x_diff = max_dim - particle.image.data.shape[0] y_diff = max_dim - particle.image.data.shape[1] minval = particle.image.data.min() new_im = np.full((max_dim,max_dim),minval) new_im[:particle.image.data.shape[0], :particle.image.data.shape[1]] = particle.image.data new_im = interpolation.shift(new_im,(x_diff/2,y_diff/2),cval=minval) particle.image.data = new_im particle.image.axes_manager[0].size = particle.image.data.shape[0] particle.image.axes_manager[1].size = particle.image.data.shape[1]
[docs] def cluster_particles(self,algorithm='Kmeans',properties=None,n_clusters=2,eps=0.2,min_samples=5): """ Cluster particles in to different populations based on specified properties. Parameters ---------- algorithm: str The algorithm to use for clustering. Options are 'Kmeans','DBSCAN','OPTICS','AffinityPropagation'. properties: list A list of the properties upon which to base the clustering. n_clusters: int The number of clusters to split the data into. Used for Kmeans. eps: float The distance between samples. Used for DBSCAN. min_samples: int The minimum number of samples within the eps distance to be classed as a cluster. Used for DBSCAN and OPTICS. Returns ------- List of Particle_list() objects. """ vec,feature_array = _extract_features(self,properties) feature_array = preprocessing.scale(feature_array) if algorithm=='Kmeans': cluster_out = cluster.KMeans(n_clusters=n_clusters).fit_predict(feature_array) start = 0 elif algorithm=='DBSCAN': cluster_out = cluster.DBSCAN(eps=eps,min_samples=min_samples).fit_predict(feature_array) start = -1 elif algorithm=='OPTICS': cluster_out = cluster.OPTICS(min_samples=min_samples).fit_predict(feature_array) start = -1 elif algorithm=='AffinityPropagation': cluster_out = cluster.AffinityPropagation().fit_predict(feature_array) start = 0 for i,p in enumerate(self.list): p.cluster_number = cluster_out[i] plist_clusters = [] for n in range(start,cluster_out.max()+1): p_list_new = particle_list() p_list_new.list = list(it.compress(self.list,[c==n for c in cluster_out])) plist_clusters.append(p_list_new) return(plist_clusters)
def _extract_features(particles,properties=None): if properties==None: properties = particles.list[0].properties properties_list = [] for particle in particles.list: properties_list.append({p:particle.properties[p]['value'] for p in properties}) vec = feature_extraction.DictVectorizer() vectorized = vec.fit_transform(properties_list).toarray() return(vec,vectorized)