Source code for upxo.repqual.grain_network_repr_assesser

# -*- coding: utf-8 -*-
"""
Created on Fri Jun  7 10:10:42 2024

@author: Dr. Sunil Anandatheertha
"""
import sys
import numpy as np
import pandas as pd
from copy import deepcopy
import matplotlib.pyplot as plt
from collections import namedtuple
from matplotlib import cm
from scipy import stats
import seaborn as sns
from scipy.stats import mannwhitneyu
from scipy.stats import ks_2samp
from scipy.stats import kruskal
from scipy.stats import entropy
from upxo.ggrowth.mcgs import mcgs
from upxo.pxtalops.Characterizer import mcgs_mchar_2d
from upxo._sup import dataTypeHandlers as dth
from upxo.geoEntities.mulpoint2d import MPoint2d
from upxo.interfaces.user_inputs.excel_commons import read_excel_range
from upxo.interfaces.user_inputs.excel_commons import write_array_to_excel
from upxo._sup.data_ops import find_outliers_iqr, distance_between_two_points
from scipy.interpolate import griddata
import matplotlib.ticker as ticker
from scipy.stats import entropy
from scipy.stats import gaussian_kde
from mpl_toolkits.axes_grid1 import make_axes_locatable
from upxo.statops.stattests import test_rand_distr_autocorr
from upxo.statops.stattests import test_rand_distr_runs
from upxo.statops.stattests import test_rand_distr_chisquare
from upxo.statops.stattests import test_rand_distr_kolmogorovsmirnov
from upxo.statops.stattests import test_rand_distr_kullbackleibler
import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from networkx.algorithms import community
from scipy.stats import wasserstein_distance, ks_2samp, energy_distance
try:
    import netlsd
    _NETLSD_AVAILABLE = True
except ImportError:
    _NETLSD_AVAILABLE = False
from upxo._sup.data_ops import calculate_angular_distance as calc_angdist
from upxo._sup.data_ops import calculate_density_bins
from upxo._sup.data_ops import approximate_to_bin_means
from upxo.netops import kmake
from tqdm import tqdm
from upxo.netops.kmake import make_gid_net_from_neighlist

import upxo.netops.kmake as kmake
import upxo.netops.kcmp as kcmp
import upxo.netops.kchar as kchar

NUMBERS = dth.dt.NUMBERS
ITERABLES = dth.dt.ITERABLES
RNG = np.random.default_rng()
DCOPY = deepcopy

[docs] class KREPR(): """ Grain-network representativeness assessor (2D K-topology / morphometrics). Compares **target** and **sample** grain structures via neighbour networks (NetworkX / UPXO netops), morphological property tables, and distribution distances (Wasserstein, KS, energy distance, optional NetLSD). Used by ``repgen2d`` ranking and standalone R-field studies. Import:: from upxo.repqual.grain_network_repr_assesser import KREPR Parameters / attributes ----------------------- upxogs_tgt, upxogs_smp Single UPXO grain-structure objects when used in one-vs-one mode. tgset, sgset : dict Sets of target / sample grain structures (keys often tslices). tkset, skset : dict Neighbour-network graphs (or adjacency dicts) for target / sample, keyed by neighbour order ``ordern``. tnset, snset : dict UPXO neighbour maps (gid → neighbour gids) by order. tmpset, smpset : dict Morphological property sets for target / sample. tid, sid : list Usable target / sample IDs (subset of set keys); default all keys. ordern : list Neighbour orders to analyse (default ``[1]`` if unset). mprop2d_flags, mprop3d_flags, sprop2d_flags, sprop3d_flags : dict Flags controlling which morphological properties are computed. mprop2d, mprop3d, sprop2d, sprop3d : dict Computed morphological property stores. rkf : dict Network-based R-field data; set before full representativeness runs. _cim_: str Class initiation method, not intended for user use. Author: Dr. Sunil Anandatheertha om jayanti man'gaLA kALi bhadrakALi kapAlini | durgA kshamA shivA dhAtri svAhA svadhA namOstute || """ __slots__ = ('gstype', 'upxogs_tgt', 'upxogs_smp', 'tgset', 'sgset', 'tkset', 'skset', 'tnset', 'snset', 'tmpset', 'smpset', 'tid', 'sid', 'ntid', 'nsid', 'ordern', 'dim', 'rkf_flags', 'rkf', 'mprop2d_flags', 'mprop3d_flags', 'mprop2d', 'mprop3d', 'mp_gspn_map', '_cim_',) def __init__(self, **kwargs): """Initialise the instance.""" self._cim_ = kwargs['_cim_'] # -------------------------------------------- self.mp_gspn_map = {'area_pix': 'area'} # -------------------------------------------- self.dim = namedtuple('dim', ['tgt', 'smp']) self.gstype = namedtuple('gstype', ['tgt', 'smp']) # ========================================================== # TEND TO DIFFERENT CLASS CREATOIPN METHODS if kwargs['_cim_'] == 'from_gs': # Validations self.gstype.tgt = kwargs['gstype_tgt'] self.gstype.smp = kwargs['gstype_smp'] # -------------------------------------------- self.upxogs_tgt = kwargs['upxogs_tgt'] self.upxogs_smp = kwargs['upxogs_smp'] tgset, sgset = kwargs['tgset'], kwargs['sgset'] self.tgset = {i: gs for i, gs in tgset.items()} self.sgset = {i: gs for i, gs in sgset.items()} # self.tid, self.sid = kwargs['tid'], kwargs['sid'] self.tkset, self.skset = None, None self.tnset, self.snset = None, None elif kwargs['_cim_'] == 'from_k': # Validations self.gstype.tgt, self.gstype.smp = None, None self.upxogs_tgt, self.upxogs_smp = None, None self.tgset, self.sgset = None, None self.tkset, self.skset = kwargs['tkset'], kwargs['skset'] # self.tid, self.sid = kwargs['tid'], kwargs['sid'] self.tnset, self.snset = None, None elif kwargs['_cim_'] == 'from_neigh': # Validations self.gstype.tgt, self.gstype.smp = None, None self.tgset, self.sgset = None, None self.tkset, self.skset = None, None self.tnset, self.snset = kwargs['tnset'], kwargs['snset'] self.tid, self.sid = kwargs['tid'], kwargs['sid'], elif kwargs['_cim_'] == 'from_gsgen': """ Note @dev: This branch is as of now, identical to 1st branch 'from_gs'. This is expected to change with further development. Continue to develop identical to 1st branch 'from_gs'. """ # Validations self.gstype.tgt = kwargs['gstype_tgt'] self.gstype.smp = kwargs['gstype_smp'] self.upxogs_tgt = kwargs['upxogs_tgt'] self.upxogs_smp = kwargs['upxogs_smp'] tgset, sgset = kwargs['tgset'], kwargs['sgset'] self.tgset = {i: gs for i, gs in tgset.items()} self.sgset = {i: gs for i, gs in sgset.items()} # self.tid, self.sid = kwargs['tid'], kwargs['sid'] self.tkset, self.skset = None, None self.tnset, self.snset = None, None # ========================================================== # Set the dimensioanlities of the problem. self.init_subdef_set_dim() self.init_subdef_set_gsid(kwargs) self.init_subdef_set_neighs(kwargs) self.init_subdef_set_networks() self.init_subdef_set_prop_flags() # ==========================================================
[docs] @classmethod def from_gs(cls, *, upxogs_tgt=None, upxogs_smp=None, tgset=None, sgset=None, ordern=[1], tsid_source='from_gs', ssid_source='from_gs', tid=None, sid=None, _cim_='from_gs', gstype_tgt='mcgs2d', gstype_smp='mcgs3d'): """ Instantiate network based repr class using UPXO grain structure. Parameters ---------- upxogs_tgt upxogs_smp tgset: dict Target grain structures. Defaults to None. sgset: dict Sample grain structures. Defaults to None. ordern: list Neighbour order-n to be used. Defaults to [1]. _cim_: str Class initiation method. Defaults to 'from_gs'. Not intended for user. Leave it alone. from upxo.ggrowth.mcgs import mcgs tgt = mcgs(study='independent', input_dashboard='input_dashboard.xls') tgt.simulate() tgt.detect_grains() tgt.char_morph_2d(tgt.m) tgset = {i: gs for i, gs in tgt.gs.items()} from upxo.repqual.grain_network_repr_assesser import KREPR kr = KREPR.from_gs(tgset=tgset, sgset=tgset, ordern=[1, 5]) kr.creation_method kr.calculate_mprop2d() kr.set_rkf(js=True, wd=True, ksp=True, ed=True, nlsd=True, degcen=False, btwcen=False, clscen=False, egnvcen=False) kr.calculate_rkf() kr.plot_rkf(neigh_orders=[1, 5], power=1, figsize=(7, 5), dpi=120, xtick_incr=5, ytick_incr=5, lfs=7, tfs=8, cmap='nipy_spectral', cbarticks=np.arange(0, 1.1, 0.1), cbfs=10, cbtitle='Measure of representativeness R(S|T)', cbfraction=0.046, cbpad=0.04, cbaspect=30, shrink=0.5, cborientation='vertical', flags={'rkf_js': False, 'rkf_wd': True, 'rkf_ksp': True, 'rkf_ed': True, 'rkf_nlsd': True, 'rkf_degcen': False, 'rkf_btwcen': False, 'rkf_clscen': False, 'rkf_egnvcen': False}) data_title = 'R-Field measure: Energy Distance' n_bins = 5 AD, AX = kr.calculate_uncertainty_angdist(rkf_measure='ed', neigh_orders=[1, 5], n_bins=n_bins, data_title=data_title, throw=True, plot_ad=False) kr.plot_ang_dist(AD, neigh_orders=[1, 5], n_bins=n_bins, figsize=(5, 5), dpi=150, data_title=data_title, cmap='nipy_spectral') kr.calculate_mprop2d() """ # Validations return cls(upxogs_tgt=upxogs_tgt, upxogs_smp=upxogs_smp, tgset=tgset, sgset=sgset, ordern=ordern, tsid_source=tsid_source, ssid_source=ssid_source, tid=tid, sid=sid, gstype_tgt=gstype_tgt, gstype_smp=gstype_smp, _cim_=_cim_)
[docs] @classmethod def from_neigh(cls, *, tnset=None, snset=None, ordern=[1], tsid_source='from_neigh', ssid_source='from_neigh', tid=None, sid=None, _cim_='from_neigh'): """ # Assuming 20 tslices being available witrh increments of tslice=1, # we will go through the folloing example. ordern = [1, 3] from upxo.ggrowth.mcgs import mcgs tgt = mcgs(study='independent', input_dashboard='mcgs2d_100x100_m50_q10_mcalg201.xls') tgt.simulate() tgt.detect_grains() tslices = np.array(list(tgt.gs.keys()))[1::10] tnset = {no: {tslice: None for tslice in tslices} for no in ordern} for no in ordern: for tslice in tslices: _ = tgt.gs[tslice].get_upto_nth_order_neighbors_all_grains tnn = _(no, include_parent=True, output_type='nparray') tnset[no][tslice] = tnn smp = mcgs(study='independent', input_dashboard='mcgs2d_100x100_m50_q10_mcalg201.xls') smp.simulate() smp.detect_grains() tslices = np.array(list(smp.gs.keys()))[1::10] snset = {no: {tslice: None for tslice in tslices} for no in ordern} for no in ordern: for tslice in tslices: _ = smp.gs[tslice].get_upto_nth_order_neighbors_all_grains snn = _(no, include_parent=True, output_type='nparray') snset[no][tslice] = snn from upxo.repqual.grain_network_repr_assesser import KREPR kr = KREPR.from_neigh(tnset=tnset, snset=tnset, tid=list(tnset.keys()), sid=list(snset.keys()), _cim_='from_neigh') kr.snset.keys() kr.snset[3].keys() kr.snset[3][11] kr.snset[3][11][40] # <-- O(3) Neigh gids of gid=40 of tslice = 11 kr.ordern kr.tid """ return cls(tnset=tnset, snset=snset, ordern=ordern, tsid_source=tsid_source, ssid_source=ssid_source, tid=tid, sid=sid, _cim_=_cim_)
[docs] @classmethod def from_k(cls, *, tkset=None, skset=None, ordern=[1], tsid_source='from_k', ssid_source='from_k', tid=None, sid=None,_cim_='from_k'): """ # Assuming 20 tslices being available witrh increments of tslice=1, # we will go through the folloing example. ordern = [1, 3] from upxo.ggrowth.mcgs import mcgs tgt = mcgs(study='independent', input_dashboard='mcgs2d_100x100_m50_q10_mcalg201.xls') tgt.simulate() tgt.detect_grains() tslices = np.array(list(tgt.gs.keys()))[1::10] tkset = {no: {tslice: None for tslice in tslices} for no in ordern} for no in ordern: for tslice in tslices: _ = tgt.gs[tslice].get_upto_nth_order_neighbors_all_grains tnn = _(no, include_parent=True, output_type='nparray') tnn_k = kmake.create_grain_network_nx(tnn) tkset[no][tslice] = tnn_k smp = mcgs(study='independent', input_dashboard='mcgs2d_100x100_m50_q10_mcalg201.xls') smp.simulate() smp.detect_grains() tslices = np.array(list(smp.gs.keys()))[1::10] skset = {no: {tslice: None for tslice in tslices} for no in ordern} for no in ordern: for tslice in tslices: _ = smp.gs[tslice].get_upto_nth_order_neighbors_all_grains snn = _(no, include_parent=True, output_type='nparray') snn_k = kmake.create_grain_network_nx(snn) skset[no][tslice] = snn_k from upxo.repqual.grain_network_repr_assesser import KREPR kr = KREPR.from_k(tkset=tkset, skset=tkset, tid=list(tkset.keys()), sid=list(skset.keys()), _cim_='from_k') kr.tkset kr.ordern kr.tid """ # Validations return cls(tkset=tkset, skset=skset, ordern=ordern, tsid_source=tsid_source, ssid_source=ssid_source, tid=tid, sid=sid, _cim_=_cim_)
[docs] @classmethod def from_gsgen(cls, gstype_tgt='mcgs2d', gstype_smp='mcgs3d', is_smp_same_as_tgt=False, characterize_tgt=True, characterize_smp=True, tgt_dashboard='input_dashboard_krepr1.xls', smp_dashboard='input_dashboard_krepr2.xls', ordern=[1], tsid_source='from_neigh', ssid_source='from_neigh', tid=None, sid=None, _cim_='from_gsgen'): """ Initiate KREPR by generating target and sample grain structure sets. Parameters ---------- gstype: str Type of grain structure needed. Could be deprecated later on. Defaults to 'mcgs'. is_smp_same_as_tgt: bool Defaults to False. tgt_dashboard: str Defaults to 'input_dashboard.xls'. smp_dashboard: str Defaults to 'input_dashboard.xls'. _cim_: str Defaults to 'from_gsgen'. Explanations ------------ Example ------- from upxo.repqual.grain_network_repr_assesser import KREPR kr = KREPR.from_gsgen(gstype='mcgs', is_smp_same_as_tgt = False, tgt_dashboard='input_dashboard.xls', smp_dashboard='input_dashboard.xls', _cim_='from_gsgen') kr.tgset kr.ordern kr.tid """ # -------------------------------------------------------- print('GENERATING TARGET GRAIN STRUCTURES') tgt = mcgs(study='independent', input_dashboard=tgt_dashboard) tgt.simulate() tgt.detect_grains() if tid is None: tid = list(tgt.gs.keys()) else: # validate user input tid pass tgset = {i: gs for i, gs in tgt.gs.items()} # -------------------------------------------------------- if not is_smp_same_as_tgt: print('GENERATING SAMPLE GRAIN STRUCTURES') smp = mcgs(study='independent', input_dashboard=smp_dashboard) smp.simulate() smp.detect_grains() if sid is None: sid = list(smp.gs.keys()) else: # validate user input tid pass sgset = {i: gs for i, gs in smp.gs.items()} else: smp = deepcopy(tgt) sgset = deepcopy(tgset) # -------------------------------------------------------- if characterize_tgt: print(50*'#', '\n Characterizing target grain structure database.', '\n', 10*'. ') for i in tid: print(f'Target gsid: {i} of len(tid)') tgt.gs[i].char_morph_2d() print(50*'#') if characterize_smp: print(50*'#', '\n Characterizing sample grain structure database.', '\n', 10*'. ') for i in sid: print(f'Target gsid: {i} of len(tid)') smp.gs[i].char_morph_2d() print(50*'#') # -------------------------------------------------------- return cls(gstype_tgt=gstype_tgt, gstype_smp=gstype_smp, upxogs_tgt=tgt, upxogs_smp=smp, tgset=tgset, sgset=sgset, ordern=ordern, tsid_source=tsid_source, ssid_source=ssid_source, tid=tid, sid=sid, _cim_=_cim_)
@property def creation_method(self): """Creation method.""" return self._cim_
[docs] def init_subdef_set_dim(self): """Init subdef set dim.""" if self.gstype.tgt and isinstance(self.gstype.tgt, str): if '2' in self.gstype.tgt: self.dim.tgt = 2 elif '3' in self.gstype.tgt: self.dim.tgt = 3 else: self.dim.tgt = 2.01 # Assumed to be 2D. else: self.dim.tgt = 2.01 # Assumed to be 2D. if self.gstype.smp and isinstance(self.gstype.smp, str): if '2' in self.gstype.smp: self.dim.smp = 2 elif '3' in self.gstype.smp: self.dim.smp = 3 else: self.dim.smp = 2.01 # Assumed to be 2D. else: self.dim.smp = 2.01 # Assumed to be 2D.
[docs] def init_subdef_set_gsid(self, data): """Init subdef set gsid.""" print('Setting grain structure IDs.') if data['tsid_source'] == 'from_gs': from_gs, from_k, from_neigh = True, False, False elif data['tsid_source'] == 'from_k': from_gs, from_k, from_neigh = False, True, False elif data['tsid_source'] == 'from_neigh': from_gs, from_k, from_neigh = False, False, True elif data['tsid_source'] == 'from_gsgen': from_gs, from_k, from_neigh = True, False, False elif data['tsid_source'] == 'user': from_gs, from_k, from_neigh = False, False, False if data['tsid_source'] in ('from_gs', 'from_k', 'from_neigh', 'from_gsgen'): self.set_tid(from_gs=from_gs, from_k=from_k, from_neigh=from_neigh, tid=data['tid']) elif data['tsid_source'] == 'user': self.tid = data['tid'] if data['ssid_source'] in ('from_gs', 'from_k', 'from_neigh', 'from_gsgen'): self.set_sid(from_gs=from_gs, from_k=from_k, from_neigh=from_neigh, sid=data['sid']) elif data['ssid_source'] == 'user': self.sid = data['sid'] self.ntid, self.nsid = len(self.tid), len(self.sid)
[docs] def init_subdef_set_neighs(self, data): """Init subdef set neighs.""" self.set_ordern(data['ordern']) self.find_neigh_order_n(saa=True, throw=False)
[docs] def init_subdef_set_networks(self): """Init subdef set networks.""" self.create_tgt_smp_networks(saa=True, throw=False)
[docs] def init_subdef_set_prop_flags(self): """Init subdef set prop flags.""" if 3 not in (self.dim.tgt, self.dim.smp): ''' This means that eiythewr: 1. target and sample grain strucures are given to be 2d, or 2. target or sample grain strucvtuer is assumed to be 2d. ''' self.set_mprop2d_flags() elif self.dim.tgt == self.dim.smp == 3: ''' This means that bth target and samnple grain strucruers are 3D. ''' self.set_mprop3d_flags() self.set_sprop3d_flags() elif 2 in (self.dim.tgt, self.dim.smp) or 3 in (self.dim.tgt, self.dim.smp): ''' This means that the target set and sample sets, each can contain mixture of 2D and 3D grain strucuersa. ''' self.set_mprop2d_flags() self.set_mprop3d_flags()
# self.set_sprop3d_flags()
[docs] def set_ordern(self, ordern): """ Set the n values in O(n). Parametyers ----------- ordern: list O(n) values Return ------ None """ if type(ordern) in NUMBERS: ordern = [abs(ordern)] elif type(ordern) in ITERABLES: if dth.ALL_NUM(ordern): ordern = [abs(on) for on in ordern] else: raise ValueError('Invalid datatype / datatye combinations.') self.ordern = ordern
[docs] def set_tid(self, from_gs=False, from_k=False, from_neigh=False, tid=None): """Set or update tid.""" if from_gs and not from_k and not from_neigh: self.tid = list(self.tgset.keys()) elif not from_gs and from_k and not from_neigh: self.tid = list(self.tkset.keys()) elif not from_gs and not from_k and from_neigh: self.tid = list(self.tnset.keys()) else: self.tid = tid
[docs] def set_sid(self, from_gs=False, from_k=False, from_neigh=False, sid=None): """Set or update sid.""" if from_gs and not from_k and not from_neigh: self.sid = list(self.sgset.keys()) elif not from_gs and from_k and not from_neigh: self.sid = list(self.skset.keys()) elif not from_gs and not from_k and from_neigh: self.sid = list(self.snset.keys()) else: self.sid = sid
[docs] def set_mprop2d_flags(self, area_pix=True, area_geo=False, gbl_pix=False, gbl_geo=False, eq_dia=False, ell_a=False, ell_b=False, inclination=False, aspect_ratio=False, roundness=False, circularity=False, solidity=False, formfactor=False, convexity=False, br=False, gbr=False, fractal_dimension=False ): """ Set flags for operational 2D morphological properties. Parameters ---------- area_pix: Pixel area of the grains. Defaults to True. area_geo: Geometric area of the grains. Defaults to False. gbl_pix: Pixel gb length of the grains. Defaults to False. gbl_geo: Geometric gb length of the grains. Defaults to False. eq_dia: Equivalent diameter of the grains. Defaults to False. ell_a: Fit ellipse's major axis length of grains. Defaults to False. ell_b: Fit ellipse's minor axis length of grains. Defaults to False. inclination: Morphological inclination of grains. Defaults to False. The input arguments for characterisaion module for mcgs 2d and their mapping with the above variables are: npixels: area_pix npixels_gb: gbl_pix area: gbl_pix (preferred as of now) eq_diameter: eq_dia perimeter: gbl_pix perimeter_crofton: not available yet compactness gb_length_px aspect_ratio solidity morph_ori circularity eccentricity feret_diameter major_axis_length minor_axis_length euler_number Data structures --------------- mprop2d_flags: dict """ # Validations self.mprop2d_flags = {'area_pix': area_pix, 'area_geo': area_geo, 'gbl_pix': gbl_pix, 'gbl_geo': gbl_geo, 'eq_dia': eq_dia, 'ell_a': ell_a, 'ell_b': ell_b, 'inclination': inclination, 'aspect_ratio': aspect_ratio, 'roundness': roundness, 'circularity': circularity, 'solidity': solidity, 'formfactor': formfactor, 'convexity': convexity, 'gbr': gbr, 'fractal_dimension': fractal_dimension }
[docs] def set_mprop3d_flags(self, volume_vox=False, volume_geo=False, eq_dia=False, gba_vox=False, gba_geo=False, gbl_vox=False, gbl_geo=False, ell_a=False, ell_b=False, ell_c=False, inclination=False, sphericity=False, aspectratio_lw=False, aspectratio_lh=False, aspectratio_wh=False, vol_surfarea_ratio=False, flatness=False, compactness=False, iso_parametric_quotient=False, convextity=False, shape_entropy=False ): """ Set flags for operational 3D morphological properties. Parameters ---------- volume_vox: Voxellated volume of the grains. Defaults to True. volume_geo: Geometric volume of the grains. Defaults to False. gba_vox: Voxellated gb surface area of grains. Defaults to False. gba_geo: Geometric gb surface area of grains. Defaults to False. gbl_vox: Voxellated gb length of grains. Defaults to False. gbl_geo: Geometric gb length of grains. Defaults to False. eq_dia: Equivalent diameter of the grains. Defaults to False. ell_a: Fit ellipsoid's 1st axis length of grains. Defaults to False. ell_b: Fit ellipsoid's 2nd axis length of grains. Defaults to False. ell_c: Fit ellipsoid's 3rd axis length of grains. Defaults to False. inclination: Morphological inclination of grains. Defaults to False. Data structures --------------- mprop3d_flags: dict """ # Validations self.mprop3d_flags = {'volume_vox': volume_vox, 'volume_geo': volume_geo, 'eq_dia': eq_dia, 'gba_vox': gba_vox, 'gba_geo': gba_geo, 'gbl_vox': gbl_vox, 'gbl_geo': gbl_geo, 'ell_a': ell_a, 'ell_b': ell_b, 'ell_c': ell_c, 'inclination': inclination, 'sphericity': sphericity, 'aspectratio_lw': aspectratio_lw, 'aspectratio_lh': aspectratio_lh, 'aspectratio_wh': aspectratio_wh, 'vol_surfarea_ratio': vol_surfarea_ratio, 'flatness': flatness, 'compactness': compactness, 'iso_parametric_quotient': iso_parametric_quotient, 'convextity': convextity, 'shape_entropy': shape_entropy}
[docs] def set_prop_flag(self, propname, propflagvalue): """Set or update prop flag.""" if not isinstance(propflagvalue, bool): raise TypeError(f'Invalid propflagvalue (={propflagvalue}) type. ', 'Must be bool.') ''' Your true colours are visible when you are weak. Your collegue's true colours are also known when you are weak. - Dr. SA ''' if not isinstance(propname, str): raise TypeError(f'Invalid propname (={propname}) type. ', 'Must be str.') if propname in self.mprop2d_flags.keys(): self.mprop2d_flags[propname] = propflagvalue elif propname in self.mprop3d_flags.keys(): self.mprop3d_flags[propname] = propflagvalue elif propname in self.sprop2d_flags.keys(): self.sprop2d_flags[propname] = propflagvalue elif propname in self.sprop3d_flags.keys(): self.sprop3d_flags[propname] = propflagvalue else: raise ValueError(f'Invalid property name: {propname}')
[docs] def calculate_mprop2d(self, print_msg_tors=True, print_msg_prnm=True, print_msg_no=True, print_msg_gsid=False, print_msg_gid=False ): """ Data structure -------------- kr.mprop2d: dict kr.mprop2d[tors]: dict kr.mprop2d[tors][prnm]: dict kr.mprop2d[tors][prnm][no]: dict kr.mprop2d[tors][prnm][no][gsid]: dict kr.mprop2d[tors][prnm][no][gsid][gid]: np.array kr.mprop2d[tors][prnm][no][gsid][gid][i]: float Where, mprop2d: 2d morphology properties tors: either 'tgt' or 'smp' prnm: property name no: neighbour order gsid: grain structure ID gid: grain ID i: prnm Property value of ith neighbour of gid grain of tors gid for O(n) = on. Data access ----------- kr.mprop2d['tgt']['area_pix'][O(n)][gsid][GID]. This contains a list of gids which are O(n) neighbours of GID grain. Example: gid = 2 kr.mprop2d['tgt']['area_pix'][1.25][8][gid] The correspionding neighbour data is: kr.tnset[1.25][8][gid] Note ---- len(kr.tnset[1.25][8][gid]) = kr.mprop2d['tgt']['area_pix'][1.25][8][gid].size @ Dev: Variables ---------------- mpflags: local copy of morpho prop flag. reqprop: keys in mpflags with True values. tors: target or sample: self.mprop2d keys. prnm: property name in the list of values in reqprop. no: neighbour order in list kr.ordern. gsid: Grain structue ID in self.tid gid: Grain IDs in local neighbour network. Author: Dr. Sunil Anandatheertha """ print(40*'#') mpflags = self.mprop2d_flags reqprop = [prnm for prnm in mpflags.keys() if mpflags[prnm]] # ----------------------------------------------- if not reqprop: self.mprop2d['tgt'] = 'no prop names defined !!' self.mprop2d['smp'] = 'no prop names defined !!' print('No properties calculated as no prop names querried.') return # ----------------------------------------------- self.mprop2d = {'tgt': None, 'smp': None} for tors in self.mprop2d.keys(): if print_msg_tors: print(f'Building tors grain-netork-propety map data for {tors}') self.mprop2d[tors] = {} for prnm in reqprop: if print_msg_prnm: print(f'Building tors grain-netork-propety map data for property: {prnm}') if print_msg_no: print(40*'-') kprop_on_level = {} for no in self.ordern: kprop_gsid_level = {} if print_msg_no: print(f'.... {tors}: O(n): {no}.') GSID = self.tid if tors == 'tgt' else self.sid if tors == 'smp' else None for igsid, gsid in enumerate(GSID): if print_msg_gsid: if igsid % 5 == 0: print(f'.... GSID n.: {igsid}/{len(self.tid)}.') mapname = self.mp_gspn_map[prnm] mprops = self.tgset[gsid].prop[mapname].to_numpy() kprop_gid_level = {} for gid in self.tnset[no][gsid].keys(): ''' ngids: neighbour grain ids. ''' if print_msg_gid: print(f'........ gid: {gid}') ngids = np.array(self.tnset[no][gsid][gid])-1 kprop_gid_level[gid] = mprops[ngids] kprop_gsid_level[gsid] = kprop_gid_level kprop_on_level[no] = kprop_gsid_level self.mprop2d[tors][prnm] = kprop_on_level
[docs] def estimate_upper_ordern_bycount(self, tors='tgt', gsid=1, on_start=1.0, on_max=10.0, on_incr=0.5, neigh_count_vf_max=0.8, include_parent=True, kdeplot=True, kdeplot_kwargs={'figsize': (5, 5), 'dpi': 120, 'fill': True, 'cmap': 'cividis', 'fs_xlabel': 12, 'fs_ylabel': 12, 'fs_legend': 10, 'fs_xticks': 10, 'fs_yticks': 10, 'legend_ncols': 2, 'legend_loc': 'best' }, statplot=True, statplot_kwargs={'stat': 'mean', 'figsize': (5, 5), 'dpi': 120}, gsplot=True, gsplot_kwargs={'figsize': (5, 5), 'dpi': 120}, ): """ Estimate O(n) needed to reach neigh_count_vf_max. Parameters ---------- tors: str Specify 'tgt' for Target and 'smp' for Sample. Defaults to 'tgt'. gsid: int Grain Structure ID. Defaults to 1. on_start: float Minimum O(n) value to start iterations from. on_start >= 1. Defaults to 1.0. on_max: float Maximum O(n) value to end iterating. on_max >= on_start. Defaults to 10.0. on_incr: float del(O(n)) increments to o(n) search space. on_incr >= 0.1. Defaults to 0.5. neigh_count_vf_max: float neigh_count_vf value to stop iterating. 0.11 < neigh_count_vf_max < 0.99, generally, although value may change depending on grain structure. Note: these bounds are not accurate. Defaults to 0.8. include_parent: bool Include gid in the neigh list of gid if True, else exclude. Defaults to True. plot_kde: bool Plot kdes of a list containing total number of neighbours of every gid in the grain structure for each O(n). Defaults to True. Returns ------- LON: float Limiting Order-n neighn_stats: dict keys: on of every iteration. value: dict (key, value): 'mean' neighn.min() 'min': neighn.min() 'max': neighn.max() 'std': neighn.std() 'var': neighn.var() 'iqr': stats.iqr(neighn): Inter-quartile range 'sem': stats.sem(neighn): Standard Error of the Mean Where, neighn = np.array([len(neighs) for neighs in ngh.values()]) ngh: dict: {gid: gid neighbours list} Ng: int Number of grains in the provided grain structure. Explanations ------------ As O(n) increases the number of order-n neighbours (N) for a gid increases. But, it cannot increase for ever. Its maximum value is the total number of grains in the grain structure. The ratio of N to total number of grains (i.e. neigh_count_vf) is then unity. However, for o(n) < O(n), neigh_count_vf < 1. This function helps determine o(n) for which neigh_count_vf < neigh_count_vf_max. The kde if plotted, will show the following trends: * Shift right as o(n) increases during iterations. * Peak drops initially as o(n) increases and as width increases. * Peak increase again as o(n) increases further and width decreases. * """ ''' tors='tgt' gsid=1 on_start=1 on_max=10 on_incr=0.2 neigh_count_vf_max=0.9 include_parent=True ''' # Validations. if tors == 'tgt': gs, GIDs = self.tgset[gsid], self.tgset[gsid].gid elif tors == 'smp': gs, GIDs = self.sgset[gsid], self.sgset[gsid].gid # ------------------------------------- neighn_stats, neighn_factor, on, kde_plot_i = {}, 0.0, on_start, 0 neighn_values = {} while neighn_factor < neigh_count_vf_max and on < on_max: print(f'O(n)={on}') # SOME CALCULATIONS ngh = self._find_neigh_order_n_(gs, ordern=on, include_parent=include_parent, output_type='list', print_msg=False) neighn = np.array([len(neighs) for neighs in ngh.values()]) neighn_values[on] = neighn neighn_stats[on] = {'distribution': neighn, 'count': neighn.size, 'mean': neighn.mean(), 'min': neighn.min(), 'max': neighn.max(), 'std': neighn.std(), 'var': neighn.var(), 'iqr': stats.iqr(neighn), 'sem': stats.sem(neighn)} on += on_incr neighn_factor = neighn.mean()/len(GIDs) else: if neighn_factor >= neigh_count_vf_max: print(f'O(n) max found for neigh_count_vf_max: {neigh_count_vf_max}') print(f'on: {on-on_incr}. neighn_factor: {neighn_factor}') elif on >= on_max: print(f'O(n) max found for the user set, on_max criteria: {neigh_count_vf_max}') print(f'on: {on-on_incr}. neighn_factor: {neighn_factor}') LON = np.round(on, 4) Ng = len(self.tgset[gsid].gid) ''' Following to wrap up kdeplot after all iterations have completed: ''' if kdeplot: plt.figure(figsize=kdeplot_kwargs['figsize'], dpi=kdeplot_kwargs['dpi']) cmap = cm.get_cmap(kdeplot_kwargs['cmap']) i, _neighn_max_ = 1, [] for _on_, neighn in neighn_values.items(): color = cmap(i / len(neighn_values.keys())) sns.kdeplot(neighn, color=color, fill=kdeplot_kwargs['fill'], label=f'O(n): {_on_}') _neighn_max_.append(max(neighn)) i += 1 plt.xlabel('GID neighbour counts for O(n)', fontsize=kdeplot_kwargs['fs_xlabel']) plt.ylabel('KDE density', fontsize=kdeplot_kwargs['fs_ylabel']) plt.legend(fontsize=kdeplot_kwargs['fs_legend'], ncols=kdeplot_kwargs['legend_ncols'], loc=kdeplot_kwargs['legend_loc']) plt.axvline(x=max(_neighn_max_), color='gray', linestyle='dashed', linewidth=0.5) plt.text(max(_neighn_max_)*1.02, 0.01, f'Ng: {Ng}', rotation=90) # ------------------------------------------------- if statplot: x = np.array(list(neighn_stats.keys())) y = np.array([neighn_stats[no]['mean'] for no in neighn_stats.keys()])/Ng neighn_std = np.array([neighn_stats[no]['std'] for no in neighn_stats.keys()])/Ng plt.figure(figsize=statplot_kwargs['figsize'], dpi=statplot_kwargs['dpi']) if statplot_kwargs['stat'] == 'mean': plt.fill_between(x, y-neighn_std, y+neighn_std, color='cyan', alpha=0.5, interpolate=True) plt.plot([x[0], x[-1]], [1, 1], '--k', lw=1) plt.errorbar(x, y, yerr=neighn_std, color='k', ecolor='b', lw=1) plt.xlabel('Neighbour order, O(n)', fontsize=12) plt.ylabel("N' = No. of neigh. grains / Ng", fontsize=12) plt.text(x[0], 0.9, f'Ng: {Ng}', bbox=dict(boxstyle="square", ec='black', fc='cyan', alpha=0.25), fontsize=12) if gsplot: gs.plotgs(figsize=gsplot_kwargs['figsize'], dpi=gsplot_kwargs['dpi']) # ------------------------------------------------- return LON, neighn_stats, Ng
# ------------------------------------- def _find_neigh_order_n_(self, gs, ordern=[1], include_parent=True, output_type='nparray', print_msg=False): """ find neigh order n .""" # non = gs.get_upto_nth_order_neighbors_all_grains(ordern, # include_parent=True, # output_type='nparray') non = gs.get_upto_nth_order_neighbors_all_grains_prob(ordern, recalculate=False, include_parent=True, print_msg=False) return non
[docs] def find_neigh_order_n(self, saa=True, throw=False): """Find neigh order n.""" # Validation ngh = self._find_neigh_order_n_ # -------------------------------------- print('Starting to extract neighbourhood data for target gs dataset') tnset = {on: {i: None for i in self.tid} for on in self.ordern} for on in self.ordern: for i in self.tid: if i % 10 == 0: print(f' O(n): {on}, gsID: {i}/{self.ntid}') tnset[on][i] = ngh(self.tgset[i], on) #tnset = {on: {i: ngh(self.tgset[i], on) # for i in self.tid} for on in self.ordern} # -------------------------------------- print('Starting to extract neighbourhood data for sample gs dataset') snset = {on: {i: None for i in self.sid} for on in self.ordern} for on in self.ordern: for i in self.sid: if i % 10 == 0: print(f' O(n): {on}, gsID: {i}/{self.nsid}') snset[on][i] = ngh(self.sgset[i], on) #snset = {on: {i: ngh(self.sgset[i], on) # for i in self.sid} for on in self.ordern} # -------------------------------------- if saa: self.tnset, self.snset = tnset, snset if throw: return tnset, snset
[docs] def create_gid_network(self, dataid='tgt', neigh_order=1, gsid=1): """ Create the network nx graph from the neighbours dictionary. Parameters ---------- dataid: str. Options: 'tgt' (default), 'smp'. neigh_order: int. Order of the raw neighbours data-structure. Defaults to 1. gsid: int. ID of the grain structure. Defaults to 1. Return ------ nxg: network nx graph. """ if dataid == 'tgt': neighlist = self.tnset[neigh_order][gsid] elif dataid == 'smp': neighlist = self.snset[neigh_order][gsid] kgid = kmake.make_gid_net_from_neighlist(neighlist) return kgid
[docs] def create_tgt_networks(self, saa=True, throw=False): """ Create networkx graphs for all target gs neighbours database. Parameters ---------- saa: bool. Save as attrbute of True. Defults to True. throw: bool. Return value if True. Defaults to False. Data structure -------------- dict(no1: dict(gsid1: dict(gid1: [12, 1, 16,..]))), no2: dict(gsid2: dict(gid2: [16, 15, 8,..]))),... noi: dict(gsidj: dict(gidk: [2, 86, 95,..]))),... noN: dict(gsidM: dict(gidG: [20, 15, 196,..]))),... ) Where, noi: an element of ordern list of size N. gsidj: jth grain structure's ID of a toytal of M grain structes. gidk: kth grain ID of all G grains. noi-gsidj-gidk: kth grain ID in the jth grain structure's neighbour network dictionary of the ith O(n) database. """ print(40*'-') print('Creating networks for target grain structure dataset.') tkset = {on: {i: None for i in self.tid} for on in self.ordern} for on in self.ordern: for tid in self.tid: if tid % 10 == 0: print(f' O(n) = {on}, gsID: {tid}/{self.ntid}') tkset[on][tid] = self.create_gid_network(dataid='tgt', neigh_order=on, gsid=tid) if saa: self.tkset = tkset if throw: return tkset
[docs] def create_smp_networks(self, saa=True, throw=False): """ Create networkx graphs for all sample gs neighbours database. Parameters ---------- saa: bool. Save as attrbute of True. Defults to True. throw: bool. Return value if True. Defaults to False. Data structure -------------- dict(no1: dict(gsid1: dict(gid1: [12, 1, 16,..]))), no2: dict(gsid2: dict(gid2: [16, 15, 8,..]))),... noi: dict(gsidj: dict(gidk: [2, 86, 95,..]))),... noN: dict(gsidM: dict(gidG: [20, 15, 196,..]))),... ) Where, noi: an element of ordern list of size N. gsidj: jth grain structure's ID of a toytal of M grain structes. gidk: kth grain ID of all G grains. noi-gsidj-gidk: kth grain ID in the jth grain structure's neighbour network dictionary of the ith O(n) database. """ print(40*'-') print('Creating networks for sample grain structure dataset.') skset = {on: {i: None for i in self.tid} for on in self.ordern} for on in self.ordern: for sid in self.sid: if sid % 10 == 0: print(f' O(n) = {on}, gsID: {sid}/{self.nsid}') skset[on][sid] = self.create_gid_network(dataid='smp', neigh_order=on, gsid=sid) if saa: self.skset = skset if throw: return skset
[docs] def create_tgt_smp_networks(self, saa=True, throw=False): """ Create networkx graphs for all tgt and smp gs neighbours database. Parameters ---------- saa: bool. Save as attrbute of True. Defults to True. throw: bool. Return value if True. Defaults to False. Data structure -------------- dict(no1: dict(gsid1: dict(gid1: [12, 1, 16,..]))), no2: dict(gsid2: dict(gid2: [16, 15, 8,..]))),... noi: dict(gsidj: dict(gidk: [2, 86, 95,..]))),... noN: dict(gsidM: dict(gidG: [20, 15, 196,..]))),... ) Where, noi: an element of ordern list of size N. gsidj: jth grain structure's ID of a toytal of M grain structes. gidk: kth grain ID of all G grains. noi-gsidj-gidk: kth grain ID in the jth grain structure's neighbour network dictionary of the ith O(n) database. """ tkset = self.create_tgt_networks(saa=False, throw=True) skset = self.create_smp_networks(saa=False, throw=True) if saa: self.tkset, self.skset = tkset, skset if throw: return tkset, skset
[docs] def set_rkf(self, js=False, wd=False, ksp=False, ed=False, nlsd=False, degcen=False, btwcen=False, clscen=False, egnvcen=False): """ Set rkf field calculation flags and initiate rkf dict accordingly. Parameters ---------- js: bool Jaccard similarity measure of representativeness. Defaults to True wd: bool Wasserstein distance measure of representativeness. Defaults to True ksp: bool K-S test P-value measure of representativeness. Defaults to False ed: bool Energy distance measure of representativeness. Defaults to True nlsd: bool NetLSD similarity measure of representativeness. Defaults to False degcen: bool Betweenness Centrality. How connected each grain is. Defaults to False. btwcen: bool Betweenness Centrality. How important a grain is in connecting others. Defaults to False. clscen: bool Closeness Centrality. How close a grain is to all other grains. Defaults to False. egnvcen: bool Eigenvector Centrality. How influential a grain is within the network. Defaults to False. Data structures --------------- kr.rkf[RMNAME] = {n: ZEROS for n in kr.ordern} Where, MNAME = Repr metric name in ('js', 'wd', 'ksp', 'ed', 'nlsd') ZEROS = np.zeros((len(kr.sid), len(kr.tid))) """ self.rkf_flags = {'js': js, 'wd': wd, 'ksp': ksp, 'ed': ed, 'nlsd': nlsd, 'degcen': degcen, 'btwcen': btwcen, 'clscen': clscen, 'egnvcen': egnvcen} self.initiate_rk_dict(js=js, wd=wd, ksp=ksp, ed=ed, nlsd=nlsd, degcen=degcen, btwcen=btwcen, clscen=clscen, egnvcen=egnvcen)
[docs] def initiate_rk_dict(self, js=False, wd=False, ksp=False, ed=False, nlsd=False, degcen=False, btwcen=False, clscen=False, egnvcen=False): """ Initiate dictionaries to store representativeness measures. Parameters ---------- js: bool Jaccard similarity measure of representativeness. Defaults to True wd: bool Wasserstein distance measure of representativeness. Defaults to True ksp: bool K-S test P-value measure of representativeness. Defaults to False ed: bool Energy distance measure of representativeness. Defaults to True nlsd: bool NetLSD similarity measure of representativeness. Defaults to False Data structures --------------- kr.rkf[RMNAME] = {n: ZEROS for n in kr.ordern} Where, MNAME = Repr metric name in ('js', 'wd', 'ksp', 'ed', 'nlsd') ZEROS = np.zeros((len(kr.sid), len(kr.tid))) """ print(40*'-') print('Creating R-field data structures.') self.rkf = {} nrc = len(self.sid), len(self.tid) data_structure = {n: np.zeros(nrc) for n in self.ordern} self.rkf['js'] = DCOPY(data_structure) if js else None self.rkf['wd'] = DCOPY(data_structure) if wd else None self.rkf['ksp'] = DCOPY(data_structure) if ksp else None self.rkf['ed'] = DCOPY(data_structure) if ed else None self.rkf['nlsd'] = DCOPY(data_structure) if nlsd else None self.rkf['degcen'] = DCOPY(data_structure) if degcen else None self.rkf['btwcen'] = DCOPY(data_structure) if btwcen else None self.rkf['clscen'] = DCOPY(data_structure) if clscen else None self.rkf['egnvcen'] = DCOPY(data_structure) if egnvcen else None
[docs] def calculate_kdeg(self, ktgt, ksmp): """ Calculate the node degrees of target and sample gs O(n) networks. Paramerters ----------- ktgt: target grain structure O(n) neighbour network graph. ksmp: sample grain structure O(n) neighbour network graph. Return ------ kd_tgt: node degrees of target gs O(n) neigh network graph. kd_smp: node degrees of sample gs O(n) neigh network graph. Data structures --------------- ktgt: networkx graph for target gs's O(n) neighbour netwprk dict data. ksmp: networkx graph for sample gs's O(n) neighbour netwprk dict data. kd_tgt: list: nodal degres of ktgt kd_smp: list: nodal degres of ksmp Exzplanations ------------- This def calls for calculate_kdegrees. Please refer to upxo.netops.kchar.calculate_kdegrees for complete documentaion. """ # Validations kd_tgt, kd_smp = kchar.calculate_kdegrees([ktgt, ksmp]) return kd_tgt, kd_smp
[docs] def calculate_kdeg_equal_binning(self, ktgt, ksmp): """ Calculate the node degrees of T and S gs O(n) k's and equally bin them. Paramerters ----------- ktgt: target grain structure O(n) neighbour network graph. ksmp: sample grain structure O(n) neighbour network graph. Return ------ kd_tgt: node degrees of target gs O(n) neigh network graph. kd_smp: node degrees of sample gs O(n) neigh network graph. Data structures --------------- ktgt: networkx graph for target gs's O(n) neighbour netwprk dict data. ksmp: networkx graph for sample gs's O(n) neighbour netwprk dict data. kd_tgt: list: nodal degres of ktgt kd_smp: list: nodal degres of ksmp Exzplanations ------------- This def calls for calculate_kdegrees_equalbinning. Please refer to upxo.netops.kchar.calculate_kdegrees_equalbinning for complete documentaion. Data is binned as per global min and max in degree and the distribtuion is re-computed using histogram. """ # Validations kd_tgt, kd_smp = kchar.calculate_kdegrees_equalbinning([ktgt, ksmp]) return kd_tgt, kd_smp
[docs] def calculate_rkf_js_pairwise(self, ktgt, ksmp): """ Calculate Jaccard similarity between ktgt and ksmp. Parameters ---------- ktgt: target grain structure O(n) neighbour network graph. ksmp: sample grain structure O(n) neighbour network graph. Return ------ r: representativeness level. Explanations ------------ Refer to calculate_rkfield_js for complete documentation. Location: upxo.netops.kcmp.calculate_rkfield_js Data structures --------------- ktgt: networkx graph for target gs's O(n) neighbour netwprk dict data. ksmp: networkx graph for sample gs's O(n) neighbour netwprk dict data. r: int between 0 and 1. Higher the value, greater is the representativeness. """ r = kcmp.calculate_rkfield_js(ktgt, ksmp) return r
[docs] def calculate_rkf_wd_pairwise(self, ktgt, ksmp, equal_bins=False): """ Calculate Jaccard similarity between ktgt and ksmp. Parameters ---------- ktgt: target grain structure O(n) neighbour network graph. ksmp: sample grain structure O(n) neighbour network graph. Return ------ r: representativeness level. Explanations ------------ Refer to calculate_rkfield_wd for complete documentation. Location: upxo.netops.kcmp.calculate_rkfield_wd Data structures --------------- ktgt: networkx graph for target gs's O(n) neighbour netwprk dict data. ksmp: networkx graph for sample gs's O(n) neighbour netwprk dict data. r: int between 0 and 1. Higher the value, greater is the representativeness. """ # Validations if equal_bins: kd_tgt, kd_smp = self.calculate_kdeg_equal_binning(ktgt, ksmp) else: kd_tgt, kd_smp = self.calculate_kdeg(ktgt, ksmp) r = kcmp.calculate_rkfield_wd(kd_tgt, kd_smp) return r
[docs] def calculate_rkf_ksp_pairwise(self, ktgt, ksmp, equal_bins=False): """ Calculate Jaccard similarity between ktgt and ksmp. Parameters ---------- ktgt: target grain structure O(n) neighbour network graph. ksmp: sample grain structure O(n) neighbour network graph. Return ------ r: representativeness level. Explanations ------------ Refer to calculate_rkfield_ksp for complete documentation. Location: upxo.netops.kcmp.calculate_rkfield_ksp Data structures --------------- ktgt: networkx graph for target gs's O(n) neighbour netwprk dict data. ksmp: networkx graph for sample gs's O(n) neighbour netwprk dict data. r: int between 0 and 1. Higher the value, greater is the representativeness. """ # Validations if equal_bins: kd_tgt, kd_smp = self.calculate_kdeg_equal_binning(ktgt, ksmp) else: kd_tgt, kd_smp = self.calculate_kdeg(ktgt, ksmp) r = kcmp.calculate_rkfield_ksp(kd_tgt, kd_smp) return r
[docs] def calculate_rkf_ed_pairwise(self, ktgt, ksmp, equal_bins=False): """ Calculate Jaccard similarity between ktgt and ksmp. Parameters ---------- ktgt: target grain structure O(n) neighbour network graph. ksmp: sample grain structure O(n) neighbour network graph. Return ------ r: representativeness level. Explanations ------------ Refer to calculate_rkfield_ed for complete documentation. Location: upxo.netops.kcmp.calculate_rkfield_ed Data structures --------------- ktgt: networkx graph for target gs's O(n) neighbour netwprk dict data. ksmp: networkx graph for sample gs's O(n) neighbour netwprk dict data. r: int between 0 and 1. Higher the value, greater is the representativeness. """ # Validations if equal_bins: kd_tgt, kd_smp = self.calculate_kdeg_equal_binning(ktgt, ksmp) else: kd_tgt, kd_smp = self.calculate_kdeg(ktgt, ksmp) r = kcmp.calculate_rkfield_ed(kd_tgt, kd_smp) return r
[docs] def calculate_rkf_nlsd_pairwise(self, ktgt, ksmp, timescales=np.logspace(-2, 2, 20), equal_bins=False): """ Calculate Jaccard similarity between ktgt and ksmp. Parameters ---------- ktgt: target grain structure O(n) neighbour network graph. ksmp: sample grain structure O(n) neighbour network graph. Return ------ r: representativeness level. Explanations ------------ Refer to calculate_rkfield_nlsd for complete documentation. Location: upxo.netops.kcmp.calculate_rkfield_nlsd Data structures --------------- ktgt: networkx graph for target gs's O(n) neighbour netwprk dict data. ksmp: networkx graph for sample gs's O(n) neighbour netwprk dict data. r: int between 0 and 1. Higher the value, greater is the representativeness. """ # Validations if equal_bins: kd_tgt, kd_smp = self.calculate_kdeg_equal_binning(ktgt, ksmp) else: kd_tgt, kd_smp = self.calculate_kdeg(ktgt, ksmp) r = kcmp.calculate_rkfield_nlsd(kd_tgt, kd_smp, timescales=timescales) return r
[docs] def calculate_rkf_js_on(self, neigh_order=1): """ Parameters ---------- notgt: neighbour order of interest for target nosmp: neighbour order of interest for sample """ print(f'Calculating RKF-JS for neighbour order {neigh_order}') # Validations tkset = list(self.tkset[neigh_order].values()) skset = list(self.skset[neigh_order].values()) DEF_rkf_js = self.calculate_rkf_js_pairwise for idtgt, ktgt in enumerate(tkset): for idsmp, ksmp in enumerate(skset): r = DEF_rkf_js(ktgt, ksmp) self.rkf['js'][neigh_order][idsmp, idtgt] = r
[docs] def calculate_rkf_wd_on(self, neigh_order=1, equal_bins=False): """Calculate rkf wd on.""" # Validations print(f'Calculating RKF-WD for neighbour order {neigh_order}') tkset = list(self.tkset[neigh_order].values()) skset = list(self.skset[neigh_order].values()) DEF_rkf_wd = self.calculate_rkf_wd_pairwise for idtgt, ktgt in enumerate(tkset): for idsmp, ksmp in enumerate(skset): r = DEF_rkf_wd(ktgt, ksmp, equal_bins=equal_bins) self.rkf['wd'][neigh_order][idsmp, idtgt] = r
[docs] def calculate_rkf_wd_on_generalized(self, neigh_order_tgt=1, neigh_order_smp=1, equal_bins=False): """Calculate rkf wd on generalized.""" # Validations print(f'Calculating RKF-JS for T-O({neigh_order_tgt})|S-O({neigh_order_smp})') tkset = list(self.tkset[neigh_order_tgt].values()) skset = list(self.skset[neigh_order_smp].values()) # --------------------------- DEF_rkf_wd = self.calculate_rkf_wd_pairwise rkf_wd = np.zeros((self.nsid, self.ntid)) # --------------------------- for idtgt, ktgt in enumerate(tkset): for idsmp, ksmp in enumerate(skset): r = DEF_rkf_wd(ktgt, ksmp, equal_bins=equal_bins) rkf_wd[idsmp, idtgt] = r
[docs] def calculate_rkf_ksp_on(self, neigh_order=1, equal_bins=False): """Calculate rkf ksp on.""" # Validations print(f'Calculating RKF-KSP for neighbour order {neigh_order}') tkset = list(self.tkset[neigh_order].values()) skset = list(self.skset[neigh_order].values()) DEF_rkf_ksp = self.calculate_rkf_ksp_pairwise for idtgt, ktgt in enumerate(tkset): for idsmp, ksmp in enumerate(skset): r = DEF_rkf_ksp(ktgt, ksmp, equal_bins=equal_bins) self.rkf['ksp'][neigh_order][idsmp, idtgt] = r
[docs] def calculate_rkf_ksp_on_generalized(self, neigh_order_tgt=1, neigh_order_smp=1, equal_bins=False): """Calculate rkf ksp on generalized.""" # Validations print(f'Calculating RKF-KSP for T-O({neigh_order_tgt})|S-O({neigh_order_smp})') tkset = list(self.tkset[neigh_order_tgt].values()) skset = list(self.skset[neigh_order_smp].values()) # --------------------------- DEF_rkf_ksp = self.calculate_rkf_ksp_pairwise rkf_ksp = np.zeros((self.nsid, self.ntid)) # --------------------------- for idtgt, ktgt in enumerate(tkset): for idsmp, ksmp in enumerate(skset): r = DEF_rkf_ksp(ktgt, ksmp, equal_bins=equal_bins) rkf_ksp[idsmp, idtgt] = r
[docs] def calculate_rkf_ed_on(self, neigh_order=1, equal_bins=False): """Calculate rkf ed on.""" # Validations print(f'Calculating RKF-ED for neighbour order {neigh_order}') tkset = list(self.tkset[neigh_order].values()) skset = list(self.skset[neigh_order].values()) DEF_rkf_ed = self.calculate_rkf_ed_pairwise for idtgt, ktgt in enumerate(tkset): for idsmp, ksmp in enumerate(skset): r = DEF_rkf_ed(ktgt, ksmp, equal_bins=equal_bins) self.rkf['ed'][neigh_order][idsmp, idtgt] = r
[docs] def calculate_rkf_ed_on_generalized(self, neigh_order_tgt=1, neigh_order_smp=1, equal_bins=False): """Calculate rkf ed on generalized.""" # Validations print(f'Calculating RKF-ED for T-O({neigh_order_tgt})|S-O({neigh_order_smp})') tkset = list(self.tkset[neigh_order_tgt].values()) skset = list(self.skset[neigh_order_smp].values()) # --------------------------- DEF_rkf_ed = self.calculate_rkf_ed_pairwise rkf_ed = np.zeros((self.nsid, self.ntid)) # --------------------------- for idtgt, ktgt in enumerate(tkset): for idsmp, ksmp in enumerate(skset): r = DEF_rkf_ed(ktgt, ksmp, equal_bins=equal_bins) rkf_ed[idsmp, idtgt] = r
[docs] def calculate_rkf_nlsd_on(self, neigh_order=1, timescales=np.logspace(-2, 2, 20), equal_bins=False): """Calculate rkf nlsd on.""" # Validations print(f'Calculating RKF-NLSD for neighbour order {neigh_order}') tkset = list(self.tkset[neigh_order].values()) skset = list(self.skset[neigh_order].values()) DEF_rkf_nlsd = self.calculate_rkf_nlsd_pairwise for idtgt, ktgt in enumerate(tkset): for idsmp, ksmp in enumerate(skset): r = DEF_rkf_nlsd(ktgt, ksmp, timescales=timescales, equal_bins=equal_bins) self.rkf['nlsd'][neigh_order][idsmp, idtgt] = r
[docs] def calculate_rkf_ed_nlsd_generalized(self, neigh_order_tgt=1, neigh_order_smp=1, equal_bins=False): """Calculate rkf ed nlsd generalized.""" # Validations print(f'Calculating RKF-NLSD for T-O({neigh_order_tgt})|S-O({neigh_order_smp})') tkset = list(self.tkset[neigh_order_tgt].values()) skset = list(self.skset[neigh_order_smp].values()) # --------------------------- DEF_rkf_nlsd = self.calculate_rkf_nlsd_pairwise rkf_nlsd = np.zeros((self.nsid, self.ntid)) # --------------------------- for idtgt, ktgt in enumerate(tkset): for idsmp, ksmp in enumerate(skset): r = DEF_rkf_nlsd(ktgt, ksmp, equal_bins=equal_bins) rkf_nlsd[idsmp, idtgt] = r
[docs] def calculate_rkf_js(self): """Calculate rkf js.""" for no in self.ordern: self.calculate_rkf_js_on(neigh_order=no)
[docs] def calculate_rkf_wd(self): """Calculate rkf wd.""" for no in self.ordern: self.calculate_rkf_wd_on(neigh_order=no)
[docs] def calculate_rkf_ksp(self): """Calculate rkf ksp.""" for no in self.ordern: self.calculate_rkf_ksp_on(neigh_order=no)
[docs] def calculate_rkf_ed(self): """Calculate rkf ed.""" for no in self.ordern: self.calculate_rkf_ed_on(neigh_order=no)
[docs] def calculate_rkf_nlsd(self, timescales=np.logspace(-2, 2, 20), equal_bins=False): """Calculate rkf nlsd.""" # Validations for no in self.ordern: self.calculate_rkf_nlsd_on(neigh_order=no, timescales=timescales, equal_bins=equal_bins)
[docs] def calculate_rkf_pairwise(self, neigh_order, idtgt, idsmp, prop='kdegree', printmsg=False): """Calculate rkf pairwise.""" # Validations ktgt = self.tkset[neigh_order][self.tid[idtgt]] ksmp = self.skset[neigh_order][self.sid[idsmp]] if self.rkf_flags['js']: r = self.calculate_rkf_js_pairwise(ktgt, ksmp) self.rkf['js'][neigh_order][idsmp, idtgt] = r if printmsg: printstr1 = f'RKF-JS for O({neigh_order})' printstr2 = f', tid={idtgt}, sid={idsmp} = {r}' print(printstr1+printstr2) if self.rkf_flags['wd']: r = self.calculate_rkf_wd_pairwise(ktgt, ksmp) self.rkf['wd'][neigh_order][idsmp, idtgt] = r if printmsg: printstr1 = f'RKF-WD for O({neigh_order})' printstr2 = f', tid={idtgt}, sid={idsmp} = {r}' print(printstr1+printstr2) if self.rkf_flags['ksp']: r = self.calculate_rkf_ksp_pairwise(ktgt, ksmp) self.rkf['ksp'][neigh_order][idsmp, idtgt] = r if printmsg: printstr1 = f'RKF-KSP for O({neigh_order})' printstr2 = f', tid={idtgt}, sid={idsmp} = {r}' print(printstr1+printstr2) if self.rkf_flags['ed']: r = self.calculate_rkf_ed_pairwise(ktgt, ksmp) self.rkf['ed'][neigh_order][idsmp, idtgt] = r if printmsg: printstr1 = f'RKF-ED for O({neigh_order})' printstr2 = f', tid={idtgt}, sid={idsmp} = {r}' print(printstr1+printstr2) if self.rkf_flags['nlsd']: r = self.calculate_rkf_nlsd_pairwise(ktgt, ksmp) self.rkf['nlsd'][neigh_order][idsmp, idtgt] = r if printmsg: printstr1 = f'RKF-NLSD for O({neigh_order})' printstr2 = f', tid={idtgt}, sid={idsmp} = {r}' print(printstr1+printstr2)
[docs] def calculate_rkf_pairwise_generalized(self, neigh_order_tgt, neigh_order_smp, idtgt, idsmp, prop='kdegree', printmsg=False): """Calculate rkf pairwise generalized.""" # Validations ktgt = self.tkset[neigh_order_tgt][idtgt] ksmp = self.skset[neigh_order_smp][idsmp] r_js, r_wd, r_ksp, r_ed, r_nlsd = None, None, None, None, None if self.rkf_flags['js']: r_js = self.calculate_rkf_js_pairwise(ktgt, ksmp) if printmsg: printstr1 = f'RKF-JS for T-O({neigh_order_tgt})|S-O({neigh_order_smp})' printstr2 = f', tid={idtgt}, sid={idsmp} = {r_js}' print(printstr1+printstr2) if self.rkf_flags['wd']: r_wd = self.calculate_rkf_wd_pairwise(ktgt, ksmp) if printmsg: printstr1 = f'RKF-WD for T-O({neigh_order_tgt})|S-O({neigh_order_smp})' printstr2 = f', tid={idtgt}, sid={idsmp} = {r_wd}' print(printstr1+printstr2) if self.rkf_flags['ksp']: r_ksp = self.calculate_rkf_ksp_pairwise(ktgt, ksmp) if printmsg: printstr1 = f'RKF-KSP for T-O({neigh_order_tgt})|S-O({neigh_order_smp})' printstr2 = f', tid={idtgt}, sid={idsmp} = {r_ksp}' print(printstr1+printstr2) if self.rkf_flags['ed']: r_ed = self.calculate_rkf_ed_pairwise(ktgt, ksmp) if printmsg: printstr1 = f'RKF-ED for T-O({neigh_order_tgt})|S-O({neigh_order_smp})' printstr2 = f', tid={idtgt}, sid={idsmp} = {r_ed}' print(printstr1+printstr2) if self.rkf_flags['nlsd']: r_nlsd = self.calculate_rkf_nlsd_pairwise(ktgt, ksmp) if printmsg: printstr1 = f'RKF-NLSD for T-O({neigh_order_tgt})|S-O({neigh_order_smp})' printstr2 = f', tid={idtgt}, sid={idsmp} = {r_nlsd}' print(printstr1 + printstr2) return r_js, r_wd, r_ksp, r_ed, r_nlsd
[docs] def calculate_rkf_no(self, neigh_order, prop='kdegree'): """Calculate rkf no.""" for I, idtgt in enumerate(self.tid, start=0): for J, idsmp in enumerate(self.sid, start=0): if idtgt % 5 == idsmp % 20 == 0: print(f' O(n): {neigh_order}, gsID pair: ({idtgt}-{idsmp})') self.calculate_rkf_pairwise(neigh_order, I, J, prop=prop)
[docs] def calculate_rkf(self, prop='kdegree'): """ Calculate the network R-Field values for entire tgt and smp database. Parmeters --------- prop: str property name. Defaults to 'kdegree'. Options include: * 'kdegree' * 'area_pixel' * 'volume_voxel' * 'gblength_pixel' * 'gblength_geom2' * 'gblength_voxel' * 'gblength_geom3' * 'gbarea_voxels' * 'gbarea_geom' * 'gbrough_r' * 'ntjp' Explanations ------------ User specified boolean flags in rkf_flags dictate which R-field metrics would be calculated. """ print('++++++++++++++++++++++++++++++++++++++') print(str(self.ordern), '-------------') print('++++++++++++++++++++++++++++++++++++++') for no in self.ordern: print(40*'-') print(f'Calculating R-field.') self.calculate_rkf_no(no, prop=prop)
[docs] def calculate_uncertainty_angdist(self, rkf_measure='js', neigh_orders=[1], n_bins=30, data_title='Jaccard sim. measure', throw=False, plot_ad=True): """Calculate uncertainty angdist.""" # Validations if rkf_measure in self.rkf_flags.keys(): if self.rkf_flags[rkf_measure]: DATA = self.rkf[rkf_measure] else: print(f'rkf_measure: {rkf_measure} not calculated.') return else: print(f'Invalid rkf_measure: {rkf_measure}.') return # --------------------------------------------- ANG_DISTANCE = {i: {'bin_means': None, 'min': None, 'mean': None, 'max': None, 'std': None, 'nbins': n_bins} for i in neigh_orders} # --------------------------------------------- for no in neigh_orders: print(f'Calculating uncertainty measure: Ang. Dist. for {rkf_measure} at O(n): {no}') bin_means, DATA_approx = approximate_to_bin_means(DATA[no], n_bins=n_bins) ang_dist_min = np.zeros_like(bin_means) ang_dist_mean = np.zeros_like(bin_means) ang_dist_max = np.zeros_like(bin_means) ang_dist_std = np.zeros_like(bin_means) for bm_i, bm in enumerate(bin_means): print(f'....U(RKF: {rkf_measure}) at O({no}): bin {bm_i}/{len(bin_means)} ') bm_locs = np.argwhere(DATA_approx == bm) bin_means_sparse = np.zeros((bm_locs.shape[0], bm_locs.shape[0])) ang_dist_sparse = np.zeros((bm_locs.shape[0], bm_locs.shape[0])) for i in range(bm_locs.shape[0]): for j in range(bm_locs.shape[0]): if i > j: # Only find the upper tri matrix, thats enough. ang_dist_sparse[j, i] = calc_angdist(bm_locs[j], bm_locs[i]) else: # Nothing left to do here. pass # plt.imshow(ang_dist_sparse) ang_dist_sparse = np.unique(ang_dist_sparse) ang_dist_sparse_compact = ang_dist_sparse[np.nonzero(ang_dist_sparse)[0]] if ang_dist_sparse_compact.size == 0: ang_dist_min[bm_i] = np.NaN ang_dist_mean[bm_i] = np.NaN ang_dist_max[bm_i] = np.NaN ang_dist_std[bm_i] = np.NaN else: ang_dist_min[bm_i] = ang_dist_sparse_compact.min() ang_dist_mean[bm_i] = ang_dist_sparse_compact.mean() ang_dist_max[bm_i] = ang_dist_sparse_compact.max() ang_dist_std[bm_i] = ang_dist_sparse_compact.std() ANG_DISTANCE[no]['bin_means'] = bin_means ANG_DISTANCE[no]['min'] = ang_dist_min ANG_DISTANCE[no]['mean'] = ang_dist_mean ANG_DISTANCE[no]['max'] = ang_dist_max ANG_DISTANCE[no]['std'] = ang_dist_std AX = self.plot_ang_dist(ANG_DISTANCE, n_bins=n_bins, neigh_orders=neigh_orders, figsize=(5, 5), dpi=150, data_title=data_title, cmap='nipy_spectral') if plot_ad else None if throw: return ANG_DISTANCE, AX
[docs] def plot_ang_dist(self, ANG_DISTANCE, n_bins, neigh_orders=[1], figsize=(5, 5), dpi=150, data_title='DATA TITLE', cmap='nipy_spectral', throw_axis=True ): """Visualise ang dist using Matplotlib or PyVista.""" plt.figure(figsize=figsize, dpi=dpi, constrained_layout=True) # Choose a colormap (e.g., 'viridis', 'plasma', 'tab20') cmap = cm.get_cmap(cmap) num_colors = len(neigh_orders) # Number of colors needed legends, legend_names = [], [] color_increment = 1.0 / (len(neigh_orders) + 1) # Add 1 to avoid using the last color in the colormap, which is often too light for i, neigh_order in enumerate(neigh_orders): color = cmap(color_increment * (i + 1)) # Use color_increment to space out the colors line_1, = plt.plot(ANG_DISTANCE[neigh_order]['bin_means'][:-1], ANG_DISTANCE[neigh_order]['mean'][:-1], linestyle='-', color=color, marker='s', markersize=5, markerfacecolor=color) fill_1 = plt.fill_between(ANG_DISTANCE[neigh_order]['bin_means'][:-1], ANG_DISTANCE[neigh_order]['mean'][:-1] - ANG_DISTANCE[neigh_order]['std'][:-1], ANG_DISTANCE[neigh_order]['mean'][:-1] + ANG_DISTANCE[neigh_order]['std'][:-1], color=color, alpha=0.2) legends.append((line_1, fill_1)) legend_names.append(f'Neigh order, O({neigh_order})') plt.margins(x=0) plt.legend(legends, legend_names, facecolor='none', edgecolor='none', loc=1) ax=plt.gca() ax.set_xlim(0, 1.0) ax.set_ylim(0, 1.6) ax.set_xlabel(data_title, fontsize=10) ax.set_ylabel('Uncertainty (Mean angular distance), @Iso-R-bins, radians', fontsize=10) ax.set_xticks(np.arange(0, 1.1, 0.1)) plt.grid(True, linestyle=':', color='gray', alpha=0.2) plt.text(0.025, 1.525, f'No. of bins: {n_bins}', fontsize=10) return ax ax.set_xlim(0.94, 1.0) ax.set_xticks(np.arange(0.94, 1.0, 0.02))
[docs] def plot_rkf(self, neigh_orders=[1], power=1, figsize=(7, 5), dpi=120, xtick_incr=2, ytick_incr=2, lfs=7, tfs=8, cmap='nipy_spectral', cbarticks=np.arange(0, 1.1, 0.1), cbfs=10, cbtitle='Measure of representativeness R(S|T)', cbfraction=0.046, cbpad=0.04, cbaspect=30, shrink=0.5, cborientation='vertical', flags={'rkf_js': False, 'rkf_wd': False, 'rkf_ksp': False, 'rkf_ed': False, 'rkf_nlsd': False, 'rkf_degcen': False, 'rkf_btwcen': False, 'rkf_clscen': False, 'rkf_egnvcen': False, }, xlabel='Target GS ID', ylabel='Sample GS ID', ): """ Example ------- import numpy as np from upxo.repqual.grain_network_repr_assesser import KREPR import matplotlib.pyplot as plt kr = KREPR.from_gsgen(gstype='mcgs', is_smp_same_as_tgt = False, tgt_dashboard='input_dashboard.xls', smp_dashboard='input_dashboard.xls', ordern=[1, 3, 5], tsid_source='from_gs', ssid_source='from_gs', tid=None, sid=None, _cim_='from_gsgen') kr.set_rkf(js=True, wd=True, ksp=False, ed=True, nlsd=False) kr.calculate_rkf() kr.plot_rkf(neigh_orders=[1, 3, 5], figsize=(7, 5), dpi=50, xtick_incr=2, ytick_incr=2, lfs=7, tfs=8, cmap='nipy_spectral', cbarticks=np.arange(0, 1.1, 0.1), cbfs=10, cbtitle='Measure of representativeness R(S|T)', cbfraction=0.046, cbpad=0.04, cbaspect=15, shrink=0.4, cborientation='vertical', plot_rkf_js=False) """ # Validations flag_js = self.rkf_flags['js'] and flags['rkf_js'] flag_wd = self.rkf_flags['wd'] and flags['rkf_wd'] flag_ksp = self.rkf_flags['ksp'] and flags['rkf_ksp'] flag_ed = self.rkf_flags['ed'] and flags['rkf_ed'] flag_nlsd = self.rkf_flags['nlsd'] and flags['rkf_nlsd'] flag_degcen = self.rkf_flags['degcen'] and flags['rkf_degcen'] flag_btwcen = self.rkf_flags['btwcen'] and flags['rkf_btwcen'] flag_clscen = self.rkf_flags['clscen'] and flags['rkf_clscen'] flag_egnvcen = self.rkf_flags['egnvcen'] and flags['rkf_egnvcen'] flags = [flag_js, flag_wd, flag_ksp, flag_ed, flag_nlsd, flag_degcen, flag_btwcen, flag_clscen, flag_egnvcen] if not any(flags): print('Nothing to plot') return # ------------------------------------------- fig, ax = plt.subplots(nrows=len(neigh_orders), ncols=np.argwhere(flags).size, figsize=figsize, dpi=dpi, constrained_layout=True, sharex=True, sharey=True) # ------------------------------------------- xticks = np.arange(0, len(self.tid), xtick_incr) yticks = np.arange(0, len(self.sid), ytick_incr) # ------------------------------------------- if len(neigh_orders) == 1 and np.argwhere(flags).size == 1: single_plot = True else: single_plot = False # --------------------- if len(neigh_orders) > 1 and np.argwhere(flags).size == 1: col_plot = True else: col_plot = False # --------------------- if len(neigh_orders) == 1 and np.argwhere(flags).size > 1: row_plot = True else: row_plot = False # --------------------- if not single_plot and not col_plot and not row_plot: matrix_type_plot = True else: matrix_type_plot = False # ------------------------------------------- R = 0 for no in neigh_orders: C = 0 if flag_js: # print(f'JS. no: {no}, R: {R}, C: {C}') if single_plot: AX = ax elif col_plot: AX = ax[R] elif row_plot: AX = ax[C] elif matrix_type_plot: AX = ax[R, C] data = np.power(self.rkf['js'][no], power) imh = AX.imshow(data, cmap=cmap, vmin=0, vmax=1) AX.set_xlabel(xlabel, fontsize=lfs) AX.set_ylabel(ylabel, fontsize=lfs) ts = f'Jaccard sim. measure,\n O(n)={no}' AX.set_title(ts, fontsize=tfs) AX.invert_yaxis() AX.set_xticks(xticks) AX.set_yticks(yticks) AX.tick_params(axis='both', which='major', labelsize=lfs) C += 1 if flag_wd: # print(f'WD. no: {no}, R: {R}, C: {C}') if single_plot: AX = ax elif col_plot: AX = ax[R] elif row_plot: AX = ax[C] elif matrix_type_plot: AX = ax[R, C] data = np.power(self.rkf['wd'][no], power) imh = AX.imshow(data, cmap=cmap, vmin=0, vmax=1) AX.set_xlabel(xlabel, fontsize=lfs) AX.set_ylabel(ylabel, fontsize=lfs) ts = f'Wasserstein distance based sim.\n measure, O(n)={no}' AX.set_title(ts, fontsize=tfs) AX.invert_yaxis() AX.set_xticks(xticks) AX.set_yticks(yticks) AX.tick_params(axis='both', which='major', labelsize=lfs) C += 1 if flag_ksp: # print(f'KSP. no: {no}, R: {R}, C: {C}') if single_plot: AX = ax elif col_plot: AX = ax[R] elif row_plot: AX = ax[C] elif matrix_type_plot: AX = ax[R, C] data = np.power(self.rkf['ksp'][no], power) imh = AX.imshow(data, cmap=cmap, vmin=0, vmax=1) AX.set_xlabel(xlabel, fontsize=lfs) AX.set_ylabel(ylabel, fontsize=lfs) ts = ['Kolmogorov-Smirnov P-value based\n sim.' f' measure, O(n)={no}. Inequal bins'] AX.set_title(ts[0], fontsize=tfs) AX.invert_yaxis() AX.set_xticks(xticks) AX.set_yticks(yticks) AX.tick_params(axis='both', which='major', labelsize=lfs) C += 1 if flag_ed: # print(f'ED. no: {no}, R: {R}, C: {C}') if single_plot: AX = ax elif col_plot: AX = ax[R] elif row_plot: AX = ax[C] elif matrix_type_plot: AX = ax[R, C] data = np.power(self.rkf['ed'][no], power) imh = AX.imshow(data, cmap=cmap, vmin=0, vmax=1) AX.set_xlabel(xlabel, fontsize=lfs) AX.set_ylabel(ylabel, fontsize=lfs) ts = f'Energy distance based\n sim. measure, O(n)={no}' AX.set_title(ts, fontsize=tfs) AX.invert_yaxis() AX.set_xticks(xticks) AX.set_yticks(yticks) AX.tick_params(axis='both', which='major', labelsize=lfs) C += 1 if flag_nlsd: # print(f'NLSD. no: {no}, R: {R}, C: {C}') if single_plot: AX = ax elif col_plot: AX = ax[R] elif row_plot: AX = ax[C] elif matrix_type_plot: AX = ax[R, C] data = np.power(self.rkf['nlsd'][no], power) imh = AX.imshow(data, cmap=cmap, vmin=0, vmax=1) AX.set_xlabel(xlabel, fontsize=lfs) AX.set_ylabel(ylabel, fontsize=lfs) ts = f'NetLSD sim. measure,\n O(n)={no}' AX.set_title(ts, fontsize=tfs) AX.invert_yaxis() AX.set_xticks(xticks) AX.set_yticks(yticks) AX.tick_params(axis='both', which='major', labelsize=lfs) C += 1 R += 1 if not single_plot: AX = ax[:] else: AX = ax cbar = plt.colorbar(imh, ax=AX, fraction=cbfraction, pad=cbpad, orientation=cborientation, aspect=cbaspect, shrink=shrink, ticks=cbarticks) cbar.set_label(cbtitle+f'. Power: {power}', fontsize=cbfs) cbar.ax.tick_params(labelsize=cbfs)