####################################################################################################################################
####################################################################################################################################
####
#### 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)
####################################################################################################################################