Source code for paramonte.vis.GridPlot

####################################################################################################################################
####################################################################################################################################
####
####   MIT License
####
####   ParaMonte: plain powerful parallel Monte Carlo library.
####
####   Copyright (C) 2012-present, The Computational Data Science Lab
####
####   This file is part of the ParaMonte library.
####
####   Permission is hereby granted, free of charge, to any person obtaining a 
####   copy of this software and associated documentation files (the "Software"), 
####   to deal in the Software without restriction, including without limitation 
####   the rights to use, copy, modify, merge, publish, distribute, sublicense, 
####   and/or sell copies of the Software, and to permit persons to whom the 
####   Software is furnished to do so, subject to the following conditions:
####
####   The above copyright notice and this permission notice shall be 
####   included in all copies or substantial portions of the Software.
####
####   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
####   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
####   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
####   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
####   DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
####   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
####   OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
####
####   ACKNOWLEDGMENT
####
####   ParaMonte is an honor-ware and its currency is acknowledgment and citations.
####   As per the ParaMonte library license agreement terms, if you use any parts of 
####   this library for any purposes, kindly acknowledge the use of ParaMonte in your 
####   work (education/research/industry/development/...) by citing the ParaMonte 
####   library as described on this page:
####
####       https://github.com/cdslaborg/paramonte/blob/main/ACKNOWLEDGMENT.md
####
####################################################################################################################################
####################################################################################################################################

import numpy as np
import typing as tp
#import pandas as pd
import weakref as wref
from copy import deepcopy as dcopy

import _paramonte as pm
from paramonte.vis._BasePlot import BasePlot
from paramonte.vis.LineScatterPlot import LineScatterPlot
from paramonte.vis.DensityPlot import DensityPlot

Struct = pm.Struct
newline = pm.newline

####################################################################################################################################
#### GridPlot class
####################################################################################################################################

[docs]class GridPlot(BasePlot): """ This is the GridPlot class for generating instances of histogram and contour figures in two and three dimensions based on a wide range of plotting tools from the matplotlib, seaborn, and other Python libraries. Normally, the public users are not supposed to use this class directly, although they can for the purposes other than plotting the ParaMonte simulation files. **Parameters** plotType A string indicating the name of the plot to be constructed. dataFrame (optional) A pandas dataFrame whose data will be plotted. methodName (optional) The name of the ParaMonte sample requesting the BasePlot. reportEnabled (optional) A boolean whose value indicates whether guidelines should be printed in the standard output. resetPlot (optional) A function that resets the properties of the plot as desired from outside. If provided, a pointer to this function will be saved for future internal usage. **Attributes** All of the parameters described above, are implicitly stored in the object. columns An attribute that determines the columns of dataFrame to be visualized. It can have three forms: 1. A list of column indices in dataFrame. 2. A list of column names in dataFrame.columns. 3. A ``range(start,stop,step)`` of column indices. Examples: 1. ``xcolumns = [0,1,4,3]`` 2. ``xcolumns = ["SampleLogFunc","SampleVariable1"]`` 3. ``xcolumns = range(17,7,-2)`` The default behavior includes up to 5 columns of the dataFrame. ccolumn A string or integer that determines the column of the dataFrame to serve as the color-values corresponding to each point in the plot. Examples: 1. ``ccolumn = 7`` 2. ``ccolumn = "SampleLogFunc"`` 3. ``ccolumn = None`` **NOTE** The value of ``ccolumns`` has precedence over all other color properties of individual plotting tools, unless ``ccolumns = None``. For example, any value of the ``c`` component of the ``scatter.kws`` component of the ``LineScatterPlot`` object will be overridden by the specified value for ``ccolumns``. rows An attribute that determines the rows of dataFrame to be visualized. It can be either: 1. A ``range(start,stop,step)``, or, 2. A list of row indices in dataFrame.index. Examples: 1. ``rows = range(17,7,-2)`` 2. ``rows = [i for i in range(7,17)]`` The default behavior includes all rows of the dataFrame. set A structure with two attributes: enabled A boolean indicating whether a call to the ``set()`` function of the seaborn library should be made or not. kws A structure whose components are directly passed as keyword arguments to the ``set()`` function. Example usage: .. code-block:: python set.kws.style = "darkgrid" **NOTE** If a desired property is missing among the ``kws`` attributes, simply add the field and its value to the component. axes (available only in 1D and 2D plots) A structure with one attribute: kws A structure whose components are directly passed as keyword arguments to the ``gca()`` function of the matplotlib library. Example usage: .. code-block:: python axes.kws.facecolor = "w" **NOTE** If a desired property is missing among the ``kws`` attributes, simply add the field and its value to the component. figure A structure with two attributes: enabled A boolean indicating whether a call to the ``figure()`` function of the matplotlib library should be made or not. If a call is made, a new figure will be generated. Otherwise, the current active figure will be used. kws A structure whose components are directly passed as keyword arguments to the ``figure()`` function of the matplotlib library. Example usage: .. code-block:: python figure.kws.facecolor = "w" **NOTE** If a desired property is missing among the ``kws`` attributes, simply add the field and its value to the component. pairgrid A structure with one attribute: kws A structure whose components are directly passed as keyword arguments to the ``PairGrid()`` class of the seaborn library to generate a pairgrid. Example usage: .. code-block:: python pairgrid.kws.dropna = True **NOTE** Passing some keywords, like ``corner`` attribute, to the PairGrid will cause potential conflicts with other attributes of ParaMonte's GridPlot. Use this attribute with caution. That said, if a desired property is missing among the ``kws`` attributes, simply add the field and its value to the component. colorbar (exists only for plots that require colorbar) A structure with two attributes: enabled A boolean indicating whether a call to the ``colorbar()`` function of the matplotlib library should be made or not. If a call is made, a new figure will be generated. Otherwise, the current active figure will be used. kws A structure whose components are directly passed as keyword arguments to the ``colorbar()`` function of the matplotlib library. **NOTE** If a desired property is missing among the ``kws`` attributes, simply add the field and its value to the component. A colorbar will be added to a plot only if a color-mappings is requested in the plot. plotType A structure with three attributes: upper A structure whose components determine what plots can and should be added to the upper corner of the grid plot. lower A structure whose components determine what plots can and should be added to the lower corner of the grid plot. diag A structure whose components determine what plots can and should be added to the diagonal of the grid plot. Each of the above structures has three components: enabled A boolean that determines if the subplots in the corresponding section of the grid plot should be added or not. names A list of strings that represent the types of plots that can be added to the corresponding section of the grid plot. value A string whose value can be one of the elements of the ``names`` attribute explained in the above. It determines the type of the subplot to be added to the corresponding section of the grid plot. Example usage: .. code-block:: python plotType.upper.enabled = False # no upper corner plots plotType.lower.value = "scatter" # add scatter to lower layout A structure whose components are directly passed to the corresponding plotting tools of the ParaMonte library to draw the corresponding subplots, if they are activated. Example usage: .. code-block:: python layout.contour.contour.kws.colors = "blue" currentFig A structure whose attributes are the outputs of various plotting tools used to make the current figure. These include the handle to the current figure, the handle to the current axes in the plot, the handle to the colorbar (if any exists), and other Python plotting tools used to make to generate the figure. **Returns** self An object of class ``GridPlot``. --------------------------------------------------------------------------- """ ################################################################################################################################ #### __init__ ################################################################################################################################ def __init__( self , plotType # : str , dataFrame = None # : tp.Optional[ pd.DataFrame ] = None , methodName = "ParaMonte" # : tp.Optional[ str ] = "ParaMonte" , reportEnabled = True # : tp.Optional[ bool ] = True , resetPlot = None ): super().__init__( plotType = plotType , dataFrame = dataFrame , methodName = methodName , reportEnabled = reportEnabled , resetPlot = resetPlot ) self._reset() if resetPlot is None: self._resetPlot = self._reset self._progress.note() ################################################################################################################################ #### _reset ################################################################################################################################
[docs] def _reset(self): super()._reset() self.columns = None self.ccolumn = [] # use the default colormap data (which is the data count) self.pairgrid = Struct() self.pairgrid.kws = Struct() self.colorbar = Struct() self.colorbar.enabled = True self.colorbar.kws = Struct() ############################################################################################################################ #### setup corner types ############################################################################################################################ cornerNames = [ "line" , "scatter" , "lineScatter" , "contourf" , "contour" ] self.plotType = Struct() self.plotType.diag = Struct() self.plotType.diag.enabled = True self.plotType.diag.value = "histplot" self.plotType.diag.names = ["histplot"] self.plotType.upper = Struct() self.plotType.upper.enabled = True self.plotType.upper.value = "lineScatter" self.plotType.upper.names = dcopy(cornerNames) self.plotType.lower = Struct() self.plotType.lower.enabled = True self.plotType.lower.value = "contour" self.plotType.lower.names = dcopy(cornerNames) ############################################################################################################################ #### setup subplot templates ############################################################################################################################ template = Struct() # target template.target = Struct() template.target.axvline = Struct() template.target.axvline.kws = Struct() template.target.axhline = Struct() template.target.axhline.kws = Struct() template.target.scatter = Struct() template.target.scatter.kws = Struct() template.target.axvline.kws.linewidth = 0.5 template.target.axvline.kws.linestyle = "-" template.target.axvline.kws.zorder = 1000 template.target.axvline.kws.color = "orangered" template.target.axhline.kws.linewidth = 0.5 template.target.axhline.kws.linestyle = "-" template.target.axhline.kws.zorder = 1000 template.target.axhline.kws.color = "orangered" template.target.scatter.kws.s = 20 template.target.scatter.kws.color = "orangered" template.target.scatter.kws.zorder = 1002 # contour template.contour = Struct() template.contour.enabled = True template.contour.kws = Struct() template.contour.kws.cmap = "winter" template.contour.kws.alpha = 1 template.contour.kws.levels = 10 template.contour.kws.linewidths = 1 template.contour.kws.linestyles = "solid" # contourf template.contourf = Struct() template.contourf.enabled = True template.contourf.kws = Struct() template.contourf.kws.cmap = "Blues" template.contourf.kws.alpha = 1 template.contourf.kws.levels = 50 # histplot template.histplot = Struct() template.histplot.enabled = True template.histplot.kws = Struct() template.histplot.kws.kde = False template.histplot.kws.bins = "auto" template.histplot.kws.stat = "count" template.histplot.kws.kde_kws = dict() template.histplot.kws.binwidth = None template.histplot.kws.binrange = None template.histplot.kws.multiple = "stack" template.histplot.kws.element = "step" template.histplot.kws.legend = False template.histplot.kws.shrink = 1 template.histplot.kws.color = None template.histplot.kws.fill = True template.histplot.kws.common_norm = True template.histplot.kws.common_bins = False template.histplot.kws.line_kws = dict() template.histplot.kws.line_kws["linewidth"] = 0 template.histplot.kws.line_kws["linestyle"] = "-" # legend template template.legend = Struct() template.legend.enabled = False template.legend.kws = Struct() # colorbar template template.colorbar = Struct() template.colorbar.enabled = False template.colorbar.kws = Struct() # line / scatter / lineScatter template.scatter = Struct() template.scatter.enabled = True template.scatter.kws = Struct() template.scatter.kws.s = 2 template.scatter.kws.c = None template.scatter.kws.cmap = "winter" template.scatter.kws.alpha = 1 template.scatter.kws.edgecolor = None template.scatter.kws.zorder = 2 template.plot = Struct() template.plot.enabled = False template.plot.kws = Struct() template.plot.kws.linewidth = 1 template.plot.kws.zorder = 1 template.lineCollection = Struct() template.lineCollection.enabled = True template.lineCollection.kws = Struct() template.lineCollection.kws.cmap = "winter" template.lineCollection.kws.alpha = 1 template.lineCollection.kws.linewidth = 1 # figure template.figure = Struct() template.figure.kws = Struct() template.figure.enabled = False ############################################################################################################################ #### setup subplots layout ############################################################################################################################ self.layout = Struct() self.layout.contour = Struct() self.layout.contour.figure = dcopy(template.figure) self.layout.contour.contour = dcopy(template.contour) self.layout.contour.colorbar = dcopy(template.colorbar) #self.layout.contour.target = dcopy(template.target) self.layout.contour.noiseDensity = 1.e-3 self.layout.contour.limits = None self.layout.contour.gridSize = 512 self.layout.contourf = Struct() self.layout.contourf.figure = dcopy(template.figure) self.layout.contourf.contourf = dcopy(template.contourf) self.layout.contourf.colorbar = dcopy(template.colorbar) #self.layout.contourf.target = dcopy(template.target) self.layout.contourf.noiseDensity = 1.e-5 self.layout.contourf.limits = None self.layout.contourf.gridSize = 512 self.layout.histplot = Struct() self.layout.histplot.figure = dcopy(template.figure) self.layout.histplot.histplot = dcopy(template.histplot) self.layout.histplot.legend = dcopy(template.legend) #self.layout.histplot.target = dcopy(template.target) self.layout.line = Struct() self.layout.line.figure = dcopy(template.figure) self.layout.line.plot = dcopy(template.plot) self.layout.line.lineCollection = dcopy(template.lineCollection) self.layout.line.colorbar = dcopy(template.colorbar) self.layout.line.legend = dcopy(template.legend) #self.layout.line.target = dcopy(template.target) self.layout.scatter = Struct() self.layout.scatter.figure = dcopy(template.figure) self.layout.scatter.scatter = dcopy(template.scatter) self.layout.scatter.colorbar = dcopy(template.colorbar) self.layout.scatter.legend = dcopy(template.legend) #self.layout.scatter.target = dcopy(template.target) self.layout.lineScatter = Struct() self.layout.lineScatter.figure = dcopy(template.figure) self.layout.lineScatter.plot = dcopy(template.plot) self.layout.lineScatter.scatter = dcopy(template.scatter) self.layout.lineScatter.lineCollection = dcopy(template.lineCollection) self.layout.lineScatter.colorbar = dcopy(template.colorbar) self.layout.lineScatter.legend = dcopy(template.legend) #self.layout.lineScatter.target = dcopy(template.target) self.layout.lineScatter.plot.enabled = True self.layout.lineScatter.plot.kws.alpha = 0.2 self.layout.lineScatter.plot.kws.color = "grey" self.layout.lineScatter.plot.kws.linewidth = 0.75 self.layout.lineScatter.lineCollection.enabled = False ############################################################################################################################ self._isdryrun = True self.make() self._isdryrun = False
################################################################################################################################ #### __call__ ################################################################################################################################
[docs] def __call__( self , reself : tp.Optional[ bool ] = False , **kwargs ): """ Call the ``make()`` method of the current instance of the class. **Parameters** Any arguments that can be passed to the ``make()`` method of the plot object. **Returns** Any return value from the ``make()`` method of the plot object. """ return self.make(reself, **kwargs)
################################################################################################################################ #### make ################################################################################################################################
[docs] def make( self , reself : tp.Optional[ bool ] = False , **kwargs ): """ Generate a grid plot from the selected columns of the object's dataFrame. **Parameters** reself A logical variable. If ``True``, an instance of the object will be returned to the calling routine upon exit. The default value is ``False``. **Returns** The object self if ``reself = True`` otherwise, ``None``. However, this method causes side-effects by manipulating the existing attributes of the object. """ for key in kwargs.keys(): if hasattr(self,key): setattr(self, key, kwargs[key]) elif key=="dataFrame": setattr( self, "_dfref", wref.ref(kwargs[key]) ) else: raise Exception ( "Unrecognized input '"+key+"' class attribute detected." + newline + self._getDocString() ) self._cEnabled = self.ccolumn is not None ############################################################################################################################ #### verify the plot types to draw ############################################################################################################################ if self.plotType.upper.enabled and (not (isinstance(self.plotType.upper.value,str) and self.plotType.upper.value in self.plotType.upper.names)): raise Exception ( "Unrecognized input value for the \"plotType.upper.value\" of the GridPlot object." + newline + "The possible plot type names are given in \"plotType.upper.value\" of the object." + newline + self._getDocString() ) if self.plotType.lower.enabled and (not (isinstance(self.plotType.lower.value,str) and self.plotType.lower.value in self.plotType.lower.names)): raise Exception ( "Unrecognized input value for the \"plotType.lower.value\" of the GridPlot object." + newline + "The possible plot type names are given in \"plotType.lower.value\" of the object." + newline + self._getDocString() ) if self.plotType.diag.enabled and (not (isinstance(self.plotType.diag.value,str) and self.plotType.diag.value in self.plotType.diag.names)): raise Exception ( "Unrecognized input value for the \"plotType.diag.value\" of the GridPlot object." + newline + "The possible plot type names are given in \"plotType.diag.value\" of the object." + newline + self._getDocString() ) ############################################################################################################################ ############################################################################################################################ if self._isdryrun: return ############################################################################################################################ ############################################################################################################################ import seaborn as sns import matplotlib.pyplot as plt plt.ion() # turn on the interactive mode. Used to detach the figure from the command line in ipython ############################################################################################################################ #### generate figure and axes if needed ############################################################################################################################ self._constructBasePlot() ############################################################################################################################ #### check data type ############################################################################################################################ self._checkDataType() ############################################################################################################################ #### check rows presence. This must be checked here, because it depends on the integrity of the in input dataFrame. ############################################################################################################################ if self.rows is None: self.rows = range(len(self._dfref().index)) ############################################################################################################################ #### check columns presence. This must be checked here, because it depends on the integrity of the in input dataFrame. ############################################################################################################################ # assign x columns to plot #if isinstance(self.columns,list): try: self._colnames, self._colindex = pm.dfutils.getColNamesIndex(self._dfref().columns,self.columns) colindexlen = len(self._colindex) except: raise Exception ( "The columns component of the current GridPlot object must point to" + newline + "the names of a set of the columns of the input dataFrame to the GridPlot" + newline + "class constructor." + newline + self._getDocString() ) if colindexlen==0: raise Exception ( "The length of the ``columns`` component of the GridPlot object cannot be zero." + newline + self._getDocString() ) # set color data if self._cEnabled: if isinstance(self.ccolumn,str) or isinstance(self.ccolumn,int): self._ccolname, self._ccolindex = pm.dfutils.getColNamesIndex(self._dfref().columns,self.ccolumn) #self._cdata = self._dfref().iloc[self.rows,self._colindex[0]].values.flatten() elif isinstance(self.ccolumn,list) and len(self.ccolumn)==0: self._ccolname = "Count" self._ccolindex = [] else: raise Exception ( "The ccolumn component of the current GridPlot object must point to" + newline + "the names of a column of the input dataFrame to the GridPlot" + newline + "class constructor. It represents the set of values that will " + newline + "be used to colormap the subplots, where needed." + newline + self._getDocString() ) self._ccolindexlen = len(self._ccolindex) if self._ccolindexlen>1: raise Exception ( "The length of the ``ccolumn`` component of the GridPlot object cannot be larger than 1." + newline + self._getDocString() ) ############################################################################################################################ #### make pairgrid plot ############################################################################################################################ self.currentFig.pairgrid = sns.PairGrid( self._dfref()[self._colnames].iloc[self.rows,:], **vars(self.pairgrid.kws) ) self.currentFig.figure = self.currentFig.pairgrid.fig ############################################################################################################################ #### hide axes as requested ############################################################################################################################ if not self.plotType.upper.enabled: self.hide("upper") if not self.plotType.lower.enabled: self.hide("lower") if not self.plotType.diag.enabled: self.hide("diag") ############################################################################################################################ #### adjust subplot interspaces ############################################################################################################################ self.currentFig.pairgrid.fig.tight_layout() self.currentFig.pairgrid.fig.subplots_adjust(hspace = 0.05, wspace = 0.05) ############################################################################################################################ #### add subplots ############################################################################################################################ self._nrow = len(self.currentFig.pairgrid.axes[:]) nrowMinusOne = self._nrow - 1 self._ntot = self._nrow**2 self._ntotStr = str(self._ntot) self.currentFig.subplotGrid = [ [ [] for j in range(self._nrow) ] for i in range(self._nrow) ] counter = 0 dataMin = np.zeros(self._nrow) dataMax = np.zeros(self._nrow) dataMargin = np.zeros(self._nrow) ############################################################################################################################ #### add the diagonal subplots ############################################################################################################################ avgDiagTime = 0 # must be defined here for later default use, when diag is disabled. if self.plotType.diag.enabled: #self._progress.note( msg = "generating diagonal subplots... ", end = "" ) self._progress.timer.toc() self.currentFig.pairgrid.map_diag( sns.histplot, **vars(self.layout.histplot.histplot.kws) ) self._progress.timer.toc() avgDiagTime = self._progress.timer.delta / self._nrow #if self._reportEnabled: # self._progress.timer.toc() # print( "done in " + str(np.round(self._progress.timer.delta,6)) + " seconds." ) ############################################################################################################################ #### add the off-diagonal subplots ############################################################################################################################ for irow, axRow in enumerate(self.currentFig.pairgrid.axes[:]): # compute data range #dataMin[irow] = np.min( self._dfref().iloc[self.rows,self._colindex[irow]].values.flatten() ) #dataMax[irow] = np.max( self._dfref().iloc[self.rows,self._colindex[irow]].values.flatten() ) #dataMargin[irow] = (dataMax[irow] - dataMin[irow]) / 10 for icol, ax in enumerate(axRow): counter += 1 plotEnabled = False self._progress.note( msg = "generating subplot #" + str(counter) + ": (" + str(irow) + "," + str(icol) + ") out of " + self._ntotStr + "... ", end = "" ) if icol==irow and self.plotType.diag.enabled: plotEnabled = True requestedPlotType = self.plotType.diag.value if self.plotType.diag.value=="histplot": RequestedPlotClass = DensityPlot if icol>irow and self.plotType.upper.enabled: plotEnabled = True requestedPlotType = self.plotType.upper.value RequestedPlotClass = DensityPlot if "contour" in self.plotType.upper.value else LineScatterPlot if icol<irow and self.plotType.lower.enabled: plotEnabled = True requestedPlotType = self.plotType.lower.value RequestedPlotClass = DensityPlot if "contour" in self.plotType.lower.value else LineScatterPlot if plotEnabled: self.currentFig.subplotGrid[irow][icol] = RequestedPlotClass( plotType = requestedPlotType , dataFrame = self._dfref() , methodName = self._methodName , reportEnabled = False , resetPlot = None ) # set properties from the template propsDist = dcopy( vars( getattr(self.layout,requestedPlotType) ) ) for key, val in propsDist.items(): setattr(self.currentFig.subplotGrid[irow][icol], key, val) self.currentFig.subplotGrid[irow][icol].rows = self.rows self.currentFig.subplotGrid[irow][icol].xcolumns = self._colnames[icol] if not self.currentFig.subplotGrid[irow][icol]._type.is1d: self.currentFig.subplotGrid[irow][icol].ycolumns = self._colnames[irow] if "contourf"==self.currentFig.subplotGrid[irow][icol]._type.name: if not self._cEnabled: self.currentFig.subplotGrid[irow][icol].contourf.kws.cmap = None # adding colors only makes a unicolor square subplot #if "colors" not in vars(self.currentFig.subplotGrid[irow][icol].contourf.kws).keys(): # self.currentFig.subplotGrid[irow][icol].contourf.kws.colors = "k" elif "contour" in self.currentFig.subplotGrid[irow][icol]._type.name: if not self._cEnabled: self.currentFig.subplotGrid[irow][icol].contour.kws.cmap = None #if "colors" not in vars(self.currentFig.subplotGrid[irow][icol].contour.kws).keys(): #if "colors" in vars(self.layput.contour.contour.kws).keys(): # self.currentFig.subplotGrid[irow][icol].contour.kws.colors = "k" else: self.currentFig.subplotGrid[irow][icol].ccolumns = self.ccolumn # make plot plt.sca(ax) if icol!=irow: self.currentFig.subplotGrid[irow][icol].make() # set the ticks and labels if self.plotType.lower.enabled: if icol > 0: ax.set_ylabel("") if irow < nrowMinusOne: ax.set_xlabel("") elif self.plotType.upper.enabled: if icol > irow: ax.set_ylabel("") ax.set_xlabel("") # report progress if self._reportEnabled: self._progress.timer.toc() if irow==icol: delta = avgDiagTime else: delta = self._progress.timer.delta print( "done in " + str(np.round(delta,6)) + " seconds." ) ############################################################################################################################ plt.subplots_adjust(hspace=0.15, wspace=0.15) # add colorbar self._addColorBar() ############################################################################################################################ if reself: return self
################################################################################################################################ #### _addColorBar ################################################################################################################################
[docs] def _addColorBar(self): if self._cEnabled and self.colorbar.enabled: self._progress.note( msg = "generating colorbar... ", end = "" ) mappable = None isDensityMappable = False # search for line / scatter mappable if mappable is None and self.plotType.upper.enabled: if mappable is None and "scatter" in self.plotType.upper.value.lower(): mappable = self.currentFig.subplotGrid[0][1].currentFig.scatterList[0] if mappable is None and "line"==self.plotType.upper.value and self.layout.line.lineCollection.enabled: mappable = self.currentFig.subplotGrid[0][1].currentFig.lineCollectionList[0] if mappable is None and "lineScatter"==self.plotType.upper.value and self.layout.lineScatter.lineCollection.enabled: mappable = self.currentFig.subplotGrid[0][1].currentFig.lineCollectionList[0] if mappable is None and self.plotType.lower.enabled: if mappable is None and "scatter" in self.plotType.lower.value.lower(): mappable = self.currentFig.subplotGrid[1][0].currentFig.scatterList[0] if mappable is None and "line"==self.plotType.upper.value and self.layout.line.lineCollection.enabled: mappable = self.currentFig.subplotGrid[1][0].currentFig.lineCollectionList[0] if mappable is None and "lineScatter"==self.plotType.upper.value and self.layout.lineScatter.lineCollection.enabled: mappable = self.currentFig.subplotGrid[1][0].currentFig.lineCollectionList[0] # search for contour mappable if mappable is None and self.plotType.upper.enabled: if mappable is None and "contour"==self.plotType.upper.value.lower(): mappable = self.currentFig.subplotGrid[0][1].currentFig.contourList[0] isDensityMappable = True if mappable is None and "contourf" in self.plotType.upper.value.lower(): mappable = self.currentFig.subplotGrid[0][1].currentFig.contourfList[0] isDensityMappable = True if mappable is None and self.plotType.lower.enabled: if mappable is None and "contour"==self.plotType.lower.value.lower(): mappable = self.currentFig.subplotGrid[1][0].currentFig.contourList[0] isDensityMappable = True if mappable is None and "contourf" in self.plotType.lower.value.lower(): mappable = self.currentFig.subplotGrid[1][0].currentFig.contourfList[0] isDensityMappable = True # add colorbar if mappable is not None: self.colorbar.kws.mappable = mappable self.colorbar.kws.ax = self.currentFig.pairgrid.axes self.currentFig.colorbar = self.currentFig.figure.colorbar( **vars(self.colorbar.kws) ) if isDensityMappable: colorBarLabel = "Density" elif self._ccolindexlen==0: colorBarLabel = "Count from the Series Start" else: colorBarLabel = self._ccolname[0] self.currentFig.colorbar.set_label(colorBarLabel) self.currentFig.figure.set_figwidth(self.currentFig.figure.get_figwidth()*1.3333) self._progress.timer.toc() delta = self._progress.timer.delta msg = "done in " + str(np.round(delta,6)) + " seconds." else: msg = "No mappable were found in the current GridPlot. skipping..." if self._reportEnabled: print( msg, end = newline )
################################################################################################################################ #### hide ################################################################################################################################
[docs] def hide(self,part="all"): """ Hides the requested part of the grid plot. **Parameters** part A string with the following possible values: "lower" hides the lower triangle of the grid plot. "upper" hides the upper triangle of the grid plot. "diag" hides the diagonal of the grid plot. "all" hides all grid plots and the colorbar. "colorbar" hides the colorbar of the grid plot. The string can also be a mix of the above keywords, separated by the ``+`` sign or some other delimiter. For example, ``"lower+upper+colorbar"`` **Returns** None """ allhidden = "all" in part if allhidden or ("upper" in part): self.currentFig.pairgrid.map_upper(_hide_current_axis) if allhidden or ("lower" in part): self.currentFig.pairgrid.map_lower(_hide_current_axis) colnames = pm.dfutils.getColNamesIndex(self._dfref().columns,self.columns)[0] if not allhidden: for i in range(len(colnames)): ax=self.currentFig.pairgrid.axes[:][i][i] ax.set_xlabel(colnames[i]) ax.set_ylabel(colnames[i]) ax.xaxis.set_tick_params(which="both", labelbottom=True) ax.yaxis.set_tick_params(which="both", labelbottom=True) if allhidden or ("diag" in part): self.currentFig.pairgrid.map_diag(_hide_current_axis) if allhidden or ("colorbar" in part): self.currentFig.colorbar.remove()
#self.currentFig.figure.set_figwidth(self.currentFig.figure.get_figwidth()*1.3333) ################################################################################################################################ #### show ################################################################################################################################
[docs] def show(self,part="all"): """ Shows the requested part of the grid plot. **Parameters** part a string with the following possible values: "lower" shows the lower triangle of the grid plot. "upper" shows the lower triangle of the grid plot. "diag" shows the diagonal of the grid plot. "all" shows all grid plots. "colorbar" shows the colorbar of the grid plot. The string can also be a mix of the above keywords, separated by the ``+`` sign or some other delimiter. For example, ``"lower+upper+colorbar"`` **Returns** None """ allshown = "all" in part if allshown or ("upper" in part): self.currentFig.pairgrid.map_upper(_show_current_axis) if allshown or ("lower" in part): self.currentFig.pairgrid.map_lower(_show_current_axis) colnames = pm.dfutils.getColNamesIndex(self._dfref().columns,self.columns)[0] colnamesLength=len(colnames) for i in range(colnamesLength): ax=self.currentFig.pairgrid.axes[:][i][i] if colnamesLength-1>i>0: ax.set_xlabel("") ax.set_ylabel("") ax.xaxis.set_tick_params(which="both", labelbottom=False) ax.yaxis.set_tick_params(which="both", labelbottom=False) elif i==0: ax.xaxis.set_tick_params(which="both", labelbottom=False) ax.set_xlabel("") else: ax.yaxis.set_tick_params(which="both", labelbottom=False) ax.set_ylabel("") if allshown or ("diag" in part): self.currentFig.pairgrid.map_diag(_show_current_axis) if allshown or ("colorbar" in part): self._addColorBar()
################################################################################################################################ #### addTarget ################################################################################################################################
[docs] def addTarget ( self , value : tp.Union[ np.ndarray , tp.List[float] , tp.Tuple[float] ] = None ): """ Call the target callable associated with each element of currentFig.subplotGrid of the GridPlot object to add target points and/or lines to all plots of the ``GridPlot`` figure. This method is supposed to be called only after a grid plot has been generated. **Parameters** value (optional) A numpy array, or list, or tuple whose length equals the number of columns/rows of the grid plot, each element of which represents the target value associated with the corresponding variable on the ``x`` axis of the plot, from the left to the right. Alternatively, ``value`` can be a string with the following possible value: "mode" The variable values corresponding to the mode of the "SampleLogFunc" column of the input dataFrame will be used. If no "SampleLogFunc" columns name exists in the input dataFrame, an exception will be raised. This is the **default value** for the input variable ``value``. "mean" The variable values corresponding to the mode of the "SampleLogFunc" column of the input dataFrame will be used. If no "SampleLogFunc" columns name exists in the input dataFrame, an exception will be raised. If not provided, the default will be set to the state (coordinates) of the mode of the "SampleLogFunc" column in the input dataFrame to the object. This would work only when the input dataFrame is the contents of a ParaMonte output chain or sample file. **Returns** None. However, this method causes side-effects by manipulating the existing attributes of the ``Target`` objects in ``currentFig.subplotGrid`` of the GridPlot object. """ if value is None: value="mode" if isinstance(value, str): if value=="mode": from _dfutils import getMaxLogFunc maxLogFunc = getMaxLogFunc(dataFrame=self._dfref().iloc[self.rows,:]) value = maxLogFunc.dfrow[self._colindex] elif value=="mean": value = self._dfref()[self._colnames].iloc[self.rows,:].mean() elif value=="median": value = self._dfref()[self._colnames].iloc[self.rows,:].median() else: from collections.abc import Iterable if not isinstance(value, Iterable): raise Exception ( newline + "The input argument ``value`` must be either a string or an array of target value." + newline + "Here is the help information for addTarget():" + newline + self.addTarget.__doc__ ) counter = 0 for irow, plotObjectRow in enumerate(self.currentFig.subplotGrid[:]): for icol, plotObject in enumerate(plotObjectRow): counter += 0 self._progress.note( msg = "generating target #" + str(counter) + ": (" + str(irow) + "," + str(icol) + ") out of " + self._ntotStr + "... ", end = "" ) #import matplotlib.pyplot as plt #plt.sca(self.currentFig.pairgrid.axes[irow][icol]) if icol>irow and self.plotType.upper.enabled: plotObject.target( value = [ value[icol], value[irow] ], axes = self.currentFig.pairgrid.axes[irow][icol] ) elif icol<irow and self.plotType.lower.enabled: plotObject.target( value = [ value[icol], value[irow] ], axes = self.currentFig.pairgrid.axes[irow][icol] ) elif icol==irow and self.plotType.diag.enabled: plotObject.target( value = [ value[icol], value[irow] ], axes = self.currentFig.pairgrid.axes[irow][icol] ) # report progress if self._reportEnabled: self._progress.timer.toc() delta = self._progress.timer.delta print( "done in " + str(np.round(delta,6)) + " seconds.", end = newline )
################################################################################################################################ #### _getDocString ################################################################################################################################
[docs] def _getDocString(self): docString = newline \ + "Here is the help information on the GridPlot class:" + newline \ + newline \ + self.__doc__ \ + super()._getDocString() return docString
################################################################################################################################ #### helpme ################################################################################################################################
[docs] def helpme(self, topic=None): """ Print the documentation for the input string topic. If the topic does not exist, the documentation for the object will be printed. **Parameters** topic (optional) A string containing the name of the object for which help is needed. **Returns** None **Example** .. code-block:: python :linenos: helpme() helpme("make") helpme("helpme") helpme("getLogLinSpace") """ try: exec("print(self."+topic+".__doc__)") except: print(self._getDocString()) return None
################################################################################################################################ ####################################################################################################################################
[docs]def _hide_current_axis(*args, **kwds): from matplotlib import pyplot as plt plt.gca().set_visible(False)
####################################################################################################################################
[docs]def _show_current_axis(*args, **kwds): from matplotlib import pyplot as plt plt.gca().set_visible(True)
####################################################################################################################################