Source code for upxo.repqual.grain_network_repr_assesser_3D

# -*- coding: utf-8 -*-
"""
Created on Fri Sep  6 11:11:45 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(): """ Docstring. Usage ----- from upxo.repqual.grain_network_repr_assesser import KREPR Parameters ---------- upxogs_tgt, upxogs_smp: UPXO grain structure data tgset: dict Set of target grain structures. keys: int. grain strucyure IDs. values: must be any of the UPXO grain structure type. note: keys are usually tslice values, but can be user defined. Example: {0: <upxo.pxtal.mcgs2_temporal_slice.mcgs2_grain_structure at 0x2d37fcb54f0>, 1: <upxo.pxtal.mcgs2_temporal_slice.mcgs2_grain_structure at 0x2d37fcb5680>, 2: <upxo.pxtal.mcgs2_temporal_slice.mcgs2_grain_structure at 0x2d37fcb5810>, ...} sgset: dict Set of sample grain structures. keys: int. grain strucyure IDs. values: must be any of the UPXO grain structure type. note: keys are usually tslice values, but can be user defined. Example: {0: <upxo.pxtal.mcgs2_temporal_slice.mcgs2_grain_structure at 0x2d37fcb54f0>, 1: <upxo.pxtal.mcgs2_temporal_slice.mcgs2_grain_structure at 0x2d37fcb5680>, 2: <upxo.pxtal.mcgs2_temporal_slice.mcgs2_grain_structure at 0x2d37fcb5810>, ...} tkset: dict Set of networkx graphs of target grain structure neighbour networks. keys: int/float. Neighbour order, ordern value. values: dict keys: int. grain (node) IDs. values: list. contains neighbouring grain ids (gids), ie. node ids. note: keys are usually tslice values, but can be user defined. skset: dict Set of networkx graphs of sample grain structure neighbour networks. keys: int/float. Neighbour order, ordern value. values: dict keys: int. grain (node) IDs. values: list. contains neighbouring grain ids (gids), ie. node ids. note: keys are usually tslice values, but can be user defined. tnset: dict Set of UPXO returned target grain structure neighbour mapping. keys: int/float. Neighbour order, ordern value. values: dict keys: int. grain IDs. values: list. contains neighbouring grain ids (gids). note: keys are usually tslice values, but can be user defined. snset: dict Set of UPXO returned sample grain structure neighbour mapping. keys: int/float. Neighbour order, ordern value. values: dict keys: int. grain IDs. values: list. contains neighbouring grain ids (gids). note: keys are usually tslice values, but can be user defined. tmpset: dict Target morphological property set. keys: names of morphological properties. values: dict keys: O(n) values: dict keys: int. gid: grain id values values: list: neighbour gids. smpset: dict Sample morphological property set. keys: names of morphological properties. values: dict keys: O(n) values: dict keys: int. gid: grain id values values: list: neighbour gids. tid: list Contains usable values of target grain ids. MUST belong to tgset.keys() and/or tkset.keys() depending on study path. Note: if not set by the user, all tkset.keys() will be assigned !! sid: list Contains usable values of target grain ids. MUST belong to tgset.keys() and/or tkset.keys() depending on study path. Note: if not set by the user, all skset.keys() will be assigned !! ordern: list Contains values of the ordern. If not set by the user, ordern=1 will be assigned. mprop3d_flags, sprop3d_flags: all dict types mprop3d, sprop2d, sprop3d: all dict types rkf: dict Contains network (k) based R-Field (i.e. rkf) data. Thi smust be set before representativeness assessment is done. _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', 'mprop3d_flags', 'mprop3d', '_cim_',) mp_gspn_map = {'volnv': 'volnv', 'volsr': 'volsr', 'volch': 'volch', 'sanv': 'sanv', 'savi': 'savi', 'sasr': 'sasr', 'psa': 'psa', 'rat_sanv_volnv': 'rat_sanv_volnv', 'pernv': 'pernv', 'pervl': 'pervl', 'pergl': 'pergl', 'eqdia': 'eqdia', 'feqdia': 'feqdia', 'kx': 'kx', 'ky': 'ky', 'kz': 'kz', 'ksr': 'ksr', 'arbbox': 'arbbox', 'arellfit': 'arellfit', 'sol': 'sol', 'ecc': 'ecc', 'com': 'com', 'sph': 'sph', 'fn': 'fn', 'rnd': 'rnd', 'fdim': 'fdim', 'mi': 'mi',} def __init__(self, **kwargs): """Initialise the instance.""" self._cim_ = kwargs['_cim_'] # -------------------------------------------- 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'): """ Intiantiate 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() 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) kr.creation_method """ # 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, _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='input_dashboard.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='input_dashboard.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='input_dashboard.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='input_dashboard.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, char_tgt=True, char_smp=True, set_mprops_tgt=False, set_mprops_smp=False, 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', label_str_order=1, mpflags={'volnv': True, 'volsr': False, 'volch': False, 'sanv': True, 'savi': False, 'sasr': False, 'rat_sanv_volnv': True, 'psa': False, 'pernv': False, 'pervl': False, 'pergl': False, 'eqdia': False, 'feqdia': False, 'kx': False, 'ky': False, 'kz': False, 'ksr': False, 'arbbox': True, 'arellfit': False, 'sol': False, 'ecc': False, 'com': False, 'sph': False, 'fn': False, 'rnd': False, 'fdim': False, 'mi': False, }): """ 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 ------- import numpy as np from upxo.repqual.grain_network_repr_assesser_3D import KREPR import matplotlib.pyplot as plt neigh_orders=[3] kr = KREPR.from_gsgen(gstype_tgt='mcgs3d', gstype_smp='mcgs3d', is_smp_same_as_tgt = False, characterize_tgt=True, characterize_smp=True, set_mprops_tgt=False, set_mprops_smp=False, tgt_dashboard='input_dashboard.xls', smp_dashboard='input_dashboard.xls', ordern=neigh_orders, tsid_source='user', ssid_source='user', tid=np.arange(10, 20, 1), sid=np.arange(10, 20, 1), _cim_='from_gsgen') kr.set_mprop3d_flags(volnv=True, sanv=True, rat_sanv_volnv=True) kr.calculate_mprop3d(print_msg_tors=True, print_msg_prnm=True, print_msg_no=True, print_msg_gsid=False, print_msg_gid=False) kr.set_rkf(js=True, wd=True, ksp=True, ed=True, nlsd=True, degcen=False, btwcen=False, clscen=False, egnvcen=False) kr.calculate_rkf() """ '''IUf any keys are missing in mpflags, then make up the missing ones with False values.''' mpflags.update({key: False for key in cls.mp_gspn_map.keys() if key not in mpflags.keys()}) # ==================================================================== # ==================================================================== # TARGET GRAIN STRUCTURE # ==================================================================== # ==================================================================== 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 char_tgt: ngs = len(tid) print(50*'#', '\n Characterizing target gs database.', '\n', 10*'. ') for tid_count, _tid_ in enumerate(tid): print(f'Target gsid: {tid_count} of {ngs}, gs. no. {_tid_}') _def_ = tgt.gs[_tid_].char_morphology_of_grains _def_(label_str_order=label_str_order, make_pvgrid=False, find_neigh=[True, ordern], find_grain_voxel_locs=True, find_spatial_bounds_of_grains=True, find_grain_locations=True, force_compute=True,) # ==================================================================== if set_mprops_tgt: print(50*'#', '\n Calculating morpho props of target gs database.', '\n', 10*'. ') ngs = len(tid) for tid_count, _tid_ in enumerate(tid): print(f'Target gsid: {tid_count} of {ngs}') # tgt.gs[i].find_spatial_bounds_of_grains() gs = tgt.gs[_tid_] _msg_ = f'tslice {tid_count} of {ngs}, gs. no. {_tid_}' gs.set_mprops(volnv=mpflags['volnv'], eqdia=mpflags['eqdia'], eqdia_base_size_spec='volnv', arbbox=mpflags['arbbox'], arbbox_fmt='gid_dict', arellfit=mpflags['arellfit'], arellfit_metric='max', arellfit_calculate_efits=True, arellfit_efit_routine=1, arellfit_efit_regularize_data=True, solidity=mpflags['sol'], sol_nan_treatment='replace', sol_inf_treatment='replace', sol_nan_replacement=-1, sol_inf_replacement=-1, sanv=mpflags['sanv'], sanv_N=26, rat_sanv_volnv=mpflags['rat_sanv_volnv'], sanv_verbosity=1E2, disp_msg=_msg_) print(50*'#') # ==================================================================== # ==================================================================== # SAMPLE GRAIN STRUCTURE # ==================================================================== # ==================================================================== 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 sid pass sgset = {i: gs for i, gs in smp.gs.items()} else: smp = deepcopy(tgt) sgset = deepcopy(tgset) # ==================================================================== if char_smp: ngs = len(sid) print(50*'#', '\n Characterizing Sample gs database.', '\n', 10*'. ') for sid_count, _sid_ in enumerate(sid): print(f'Target gsid: {sid_count} of {ngs}, gs. no. {_sid_}') _def_ = smp.gs[_sid_].char_morphology_of_grains _def_(label_str_order=label_str_order, make_pvgrid=False, find_neigh=[True, ordern], find_grain_voxel_locs=True, find_spatial_bounds_of_grains=True, find_grain_locations=True, force_compute=True,) # ==================================================================== if set_mprops_smp: print(50*'#', '\n Calculating morpho props of sample gs database.', '\n', 10*'. ') ngs = len(sid) for sid_count, _sid_ in enumerate(sid): print(f'Target gsid: {sid_count} of {sid.size}') # tgt.gs[i].find_spatial_bounds_of_grains() gs = tgt.gs[_sid_] _msg_ = f'tslice {sid_count} of {ngs}, gs. no. {_sid_}' gs.set_mprops(volnv=mpflags['volnv'], eqdia=mpflags['eqdia'], eqdia_base_size_spec='volnv', arbbox=mpflags['arbbox'], arbbox_fmt='gid_dict', arellfit=mpflags['arellfit'], arellfit_metric='max', arellfit_calculate_efits=True, arellfit_efit_routine=1, arellfit_efit_regularize_data=True, solidity=mpflags['sol'], sol_nan_treatment='replace', sol_inf_treatment='replace', sol_nan_replacement=-1, sol_inf_replacement=-1, sanv=mpflags['sanv'], sanv_N=26, rat_sanv_volnv=mpflags['rat_sanv_volnv'], sanv_verbosity=1E2, disp_msg=_msg_) 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()
[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_mprop3d_flags(self, volnv=True, volsr=False, volch=False, sanv=True, savi=False, sasr=False, psa=False, pernv=False, pervl=False, pergl=False, eqdia=False, feqdia=False, kx=False, ky=False, kz=False, ksr=False, arbbox=True, arellfit=False, sol=False, ecc=False, com=False, sph=False, fn=False, rnd=False, mi=False, fdim=False, rat_sanv_volnv=True, iputs='flags', mpnames=('volnv',)): """ Set flags for operational 3D morpholohgical properties. Parameters ---------- volnv : bool, optional Volume by number of voxels, default True volsr : bool, optional Volume after gb surf reconstruction, default False volch : bool, optional Volume of convex hull, default False sanv : bool, optional Surface area by number of voxels, default True savi : bool, optional Surface area by voxel interfaces, default False sasr : bool, optional Surface area after gb surf reconstruction, default False psa : bool, optional Projected surface area, default False pernv : bool, optional Perimeter by number of voxels, default False pervl : bool, optional Perimeter by voxel edge lines, default False pergl : bool, optional Perimeter by geom. gb line segments, default False eqdia : bool, optional Equivalent diameter, default False feqdia : bool, optional Feret equivalent diameter, default False kx : bool, optional gb voxel local curvature in yz plane, default False ky : bool, optional gb voxel local curvature in xz plane, default False kz : bool, optional gb voxel local curvature in xy plane, default False ksr : bool, optional k computed from surf reconstruction, default False arbbox : bool, optional Aspect ratio by bounding box, default True arellfit : bool, optional Aspect ratio by ellipsoidal fit, default False sol : bool, optional Solidity of the grains, default False ecc : bool, optional Eccentricity of the grains, default False com : bool, optional Compactness of the grains, default False sph : bool, optional Sphericity of the grains, default False fn : bool, optional Flatness of the grains, default False rnd : bool, optional Roundness of the grains, default False mi : bool, optional Moment of inertia tensor, default False fdim : bool, optional Fractal dimension, default False rat_sanv_volnv : bool, optional Ratio of sanv to volnv, default True Returns ------- None Raises ------ ValueError Invalid mpnames if type(mpnames) not in dth.dt.ITERABLES or if len(mpnames) > 0. Only under iputs being input as 'mp_names'. """ if iputs not in ('flags', 'mp_names'): raise ValueError() # Validations if iputs == 'flags': self.mprop3d_flags = {'volnv': volnv, 'volsr': volsr, 'volch': volch, 'sanv': sanv, 'savi': savi, 'sasr': sasr, 'psa': psa, 'pernv': pernv, 'pervl': pervl, 'pergl': pergl, 'eqdia': eqdia, 'feqdia': feqdia, 'kx': kx, 'ky': ky, 'kz': kz, 'ksr': ksr, 'arbbox': arbbox, 'arellfit': arellfit, 'sol': sol, 'ecc': ecc, 'com': com, 'sph': sph, 'fn': fn, 'rnd': rnd, 'mi': mi, 'fdim': fdim, 'rat_sanv_volnv': rat_sanv_volnv,} elif iputs == 'mp_names': if type(mpnames) in dth.dt.ITERABLES and len(mpnames) > 0: self.mprop3d_flags = {mpn: True for mpn in mpnames} else: raise ValueError('Invalid mpnames.') self.mprop3d_flags.update({key: False for key in self.mp_gspn_map.keys() if key not in mpnames})
[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.') 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_mprop3d(self, print_msg_tors=True, print_msg_prnm=True, print_msg_no=True, print_msg_gsid=False, print_msg_gid=False ): """ Data structure -------------- kr.mprop3d: dict kr.mprop3d[tors]: dict kr.mprop3d[tors][prnm]: dict kr.mprop3d[tors][prnm][no]: dict kr.mprop3d[tors][prnm][no][gsid]: dict kr.mprop3d[tors][prnm][no][gsid][gid]: np.array kr.mprop3d[tors][prnm][no][gsid][gid][i]: float Where, mprop3d: 3d 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.mprop3d['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.mprop3d['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.mprop3d['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.mprop3d 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.mprop3d_flags reqprop = [prnm for prnm in mpflags.keys() if mpflags[prnm]] # ----------------------------------------------- if not reqprop: self.mprop3d['tgt'] = 'no prop names defined !!' self.mprop3d['smp'] = 'no prop names defined !!' print('No properties calculated as no prop names querried.') return # ----------------------------------------------- # ngs = len(list(self.tgset.keys())) ngs = self.tid.size for i, gs_i in enumerate(self.tid): gs = self.tgset[gs_i] gs.set_mprops(volnv=self.mprop3d_flags['volnv'], eqdia=self.mprop3d_flags['eqdia'], eqdia_base_size_spec='volnv', arbbox=self.mprop3d_flags['arbbox'], arbbox_fmt='gid_dict', arellfit=self.mprop3d_flags['arellfit'], arellfit_metric='max', arellfit_calculate_efits=True, arellfit_efit_routine=1, arellfit_efit_regularize_data=True, solidity=self.mprop3d_flags['sol'], sol_nan_treatment='replace', sol_inf_treatment='replace', sol_nan_replacement=-1, sol_inf_replacement=-1, sanv=self.mprop3d_flags['sanv'], sanv_N=26, rat_sanv_volnv=self.mprop3d_flags['rat_sanv_volnv'], sanv_verbosity=1E2, disp_msg=f'tslice {i} of {ngs}, gs. no. {gs_i}') ngs = self.sid.size for i, gs_i in enumerate(self.sid): gs = self.sgset[gs_i] gs.set_mprops(volnv=self.mprop3d_flags['volnv'], eqdia=self.mprop3d_flags['eqdia'], eqdia_base_size_spec='volnv', arbbox=self.mprop3d_flags['arbbox'], arbbox_fmt='gid_dict', arellfit=self.mprop3d_flags['arellfit'], arellfit_metric='max', arellfit_calculate_efits=True, arellfit_efit_routine=1, arellfit_efit_regularize_data=True, solidity=self.mprop3d_flags['sol'], sol_nan_treatment='replace', sol_inf_treatment='replace', sol_nan_replacement=-1, sol_inf_replacement=-1, sanv_N=26, rat_sanv_volnv=self.mprop3d_flags['rat_sanv_volnv'], sanv_verbosity=1E2, disp_msg=f'tslice {i} of {ngs}, gs. no. {gs_i}') # ----------------------------------------------- self.mprop3d = {'tgt': None, 'smp': None} for tors in self.mprop3d.keys(): if print_msg_tors: print(f'Building tors grain-netork-propety map data for {tors}') self.mprop3d[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 = np.array(list(self.tgset[gsid].mprop[mapname].values())) 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.mprop3d[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 calc_self_repr(self, order, recalc_neigh=True): """Return the self repr.""" raise NotImplementedError("calc_self_repr is not yet implemented.")
[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, } ): """ 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('Target GS ID', fontsize=lfs) AX.set_ylabel('Sample GS ID', 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) 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('Target GS ID', fontsize=lfs) AX.set_ylabel('Sample GS ID', 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) 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('Target GS ID', fontsize=lfs) AX.set_ylabel('Sample GS ID', 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) 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('Target GS ID', fontsize=lfs) AX.set_ylabel('Sample GS ID', 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) 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('Target GS ID', fontsize=lfs) AX.set_ylabel('Sample GS ID', 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) 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)