# <<BEGIN-copyright>>
# <<END-copyright>>
"""Base classes for covariances: matrix, axes."""
import copy, numpy
from . import tokens
from xData import ancestry as ancestryModule
from xData import axes as axesModule
from xData import gridded as griddedModule
from xData import array as arrayModule
from xData import XYs as XYsModule
from xData import link as linkModule
from xData import values as valuesModule
from pqu import PQU
__metaclass__ = type
lowerEps = 1e-8
upperEps = 1e-8
[docs]class covarianceMatrix( ancestryModule.ancestry ):
"""
Base class for all covariances. covarianceMatrix contains a label, a covariance 'type' which might be 'absolute',
'relative' or 'correlation', and an optional 'productFrame' for outgoing distribution covariances.
Matrix data is stored in an :py:class:`xData.gridded.gridded2d` class. May be diagonal, symmetric, sparse, etc
"""
moniker = 'covarianceMatrix'
def __init__(self, label, type=tokens.absoluteToken, matrix=None, productFrame=None):
"""
:param label: refers either to a style (i.e., 'eval'), or to the index inside a 'mixed' covariance
:param type: 'relative' or 'absolute'
:type type: str
:param productFrame: for outgoing distributions, indicates whether the covariance applies to lab or COM
:type productFrame: str
:param matrix: the covariance matrix itself
:type matrix: :py:class:`xData.gridded.gridded2d`
:return:
:rtype: covarianceMatrix
"""
ancestryModule.ancestry.__init__( self )
self.__label = label
self.type = type #: 'relative' or 'absolute'
self.productFrame = productFrame
self.matrix = matrix #: a :py:class:`xData.gridded.gridded2d` instance containing the matrix
self.matrix.setAncestor( self )
@property
def label( self ) :
return( self.__label )
@label.setter
def label( self, value ) :
if( value is not None ) :
if( not( isinstance( value, str ) ) ) : raise TypeError( 'label must be a string' )
self.__label = value
[docs] def getValue( self, x, y ):
ix = self.matrix.axes[2].getIndexOfValue(x)
# BRB6 hardwired
if self.matrix.axes[1].style=='link': iy=self.matrix.axes[2].getIndexOfValue(y)
else: iy=self.matrix.axes[1].getIndexOfValue(y)
return self.matrix.array.constructArray()[ix,iy]
[docs] def getRowBounds(self,unit=None):
"""Get the bounds of the row. If unit is specified, return the bounds in that unit."""
factor = 1
if unit:
factor = PQU.PQU(1, self.matrix.axes[-1].unit).getValueAs(unit)
return( self.matrix.axes[-1].values[0] * factor, self.matrix.axes[-1].values[-1] * factor )
[docs] def getColumnBounds(self,unit=None):
"""Get the bounds of the column. If unit is specified, return the bounds in that unit."""
if self.matrix.axes[-2].style=='link': return self.getRowBounds(unit)
factor = 1
if unit:
factor = PQU.PQU(1, self.matrix.axes[-1].unit).getValueAs(unit)
return( self.matrix.axes[-1].values[0] * factor, self.matrix.axes[-1].values[-1] * factor )
[docs] def isSymmetric(self):
"""
Simple test to determin if an underlying matrix is symmetric
:return:
"""
if ( self.matrix.array.compression == arrayModule.diagonal.moniker or
self.matrix.array.symmetry in (arrayModule.symmetryUpperToken,arrayModule.symmetryLowerToken) ):
return True
# could still be symmetric even if it doesn't use compression
arr = self.matrix.array.constructArray()
return numpy.all( arr==arr.T )
[docs] def convertAxesToUnits( self, units ):
"""
Converts all the axes' units.
The parameter ``units`` should be a list of units with the same length as self.axes
"""
if not type( units ) in [ list, tuple ]: raise TypeError("units argument must be a list or tuple of strings")
if len( units ) != len( self.matrix.axes ): raise ValueError("requested units list has a different length than the number of axes")
for i,a in enumerate( self.matrix.axes ):
if isinstance(a,axesModule.grid): a.convertToUnit( units[i] )
elif isinstance(a,axesModule.axis): a.unit=units[i]
else: raise TypeError()
[docs] def convertUnits( self, unitMap ):
self.matrix.axes.convertUnits(unitMap)
if self.type == 'absolute':
factor = self.matrix.axes[0].convertUnits( unitMap )
if factor != 1:
self.matrix.offsetScaleValues( 0, factor )
[docs] def toCovarianceMatrix( self ):
"""
Return self, converted to a `base` instance. Since it already is one, we just return a copy.
:return:
"""
return copy.copy( self ) # copy.deepcopy( self )
[docs] def getCorrelationMatrix( self ):
"""
Returns the correlation matrix generated from self's covariance matrix. This is
essentially a copy of self, but renormalized by the uncertainty:
correlation[i,j] = covariance[i,j]/sqrt(covariance[i,i])/sqrt(covariance[j,j])
We reuse the covariance matrix class so that we can do plotting, etc. If you have
a correlation matrix, you can safely recover it provided you have the uncertainty
vector.
Currently only works for a square covariance matrix and not a off-diagonal part of
another covariance.
"""
# Check if is full, square covariance matrix
if not self.isSymmetric():
raise TypeError( "Can only extract correlation matrices from symmetric covariance matrices" )
# Rescale result matrix
theCorrelationMatrix = self.matrix.array.constructArray()
theUncertainty = copy.copy( numpy.diag( theCorrelationMatrix ) )
theUncertainty[ theUncertainty < 0.0 ] = 0.0
theUncertainty = numpy.sqrt( theUncertainty )
for i1 in range( theCorrelationMatrix.shape[0] ):
for i2 in range( theCorrelationMatrix.shape[1] ):
theCorrelationMatrix[i1,i2] /= ( theUncertainty[i1] * theUncertainty[i2] )
# Return the result
tridata = theCorrelationMatrix[numpy.tri(theCorrelationMatrix.shape[0])==1.0].tolist()
correlation = griddedModule.gridded2d(
axes=self.matrix.axes.copy(),#FIXME: unresolvedLinks still unresolved!
array=arrayModule.full(shape=theCorrelationMatrix.shape, data=tridata, symmetry=arrayModule.symmetryLowerToken) )
correlation.axes[0].unit = ''
return correlation
[docs] def toAbsolute( self, rowData=None, colData=None ):
'''
Rescales self (if it is a relative covariance) using XYs1d rowData and colData
to convert self into an absolute covariance matrix.
:param XYs1d rowData: an XYs1d instance containing data to rescale covariance in the "row direction"
if it isn't given, we'll compute it from the corresponding data in the reactionSuite
:param XYs1d colData: an XYs1d instance containing data to rescale covariance in the "col direction"
if it isn't given, we'll compute it from the corresponding data in the reactionSuite
.. note: If the column axis is a link, only rowData is needed.
If neither rowData nor colData are specified, you'd better hope that the covariance is already
absolute because this will throw an error.
:returns: a copy of self, but rescaled and with the type set to absoluteToken
'''
result = copy.copy( self ) #copy.deepcopy( self )
if self.type==tokens.absoluteToken: return result
# Make sure we have usable row data to rescale with
if rowData is None:
rowData=copy.copy(self.ancestor.ancestor.rowData.link).toPointwise_withLinearXYs(lowerEps=lowerEps, upperEps=upperEps)
if not isinstance( rowData, XYsModule.XYs1d ):
raise TypeError( 'rowData must be of type XYs1d, found %s' % type(rowData) )
gRowData = rowData.group( self.matrix.axes[2].values )
# Only generate the column rescaling if we need to
if not self.matrix.axes[1].style=='link':
if colData is None:
colData = copy.copy(self.ancestor.ancestor.colData.link).toPointwise_withLinearXYs(lowerEps=lowerEps, upperEps=upperEps)
if not isinstance( colData, XYsModule.XYs1d ):
raise TypeError( 'colData must be of type XYs1d, found %s' % type(colData) )
gColData = colData.group( self.matrix.axes[1].values )
else:
colData=rowData
gColData=gRowData
# Rescale!
newData = []
for i,row in enumerate(self.matrix.array.constructArray()[0:len(gRowData)]):
newRow = []
for j, cell in enumerate(row[0:len(gColData)]):
newRow.append( gRowData[i]*gColData[j]*cell )
newData.append( newRow )
result.matrix.data = newData
result.type=tokens.absoluteToken
# Set the final units
if rowData.axes[0].unit == colData.axes[0].unit:
if rowData.axes[0].unit!='': result.matrix.axes[0].unit = rowData.axes[0].unit+'**2'
else:
result.matrix.axes[0].unit = rowData.axes[0].unit+'*'+colData.axes[0].unit
return result
[docs] def toRelative( self, rowData=None, colData=None ):
'''
Rescales self (if it is a absolute covariance) using XYs1d rowData and colData
to convert self into a relative covariance matrix.
:param XYs1d rowData: an XYs1d instance containing data to rescale covariance in the "row direction"
if it isn't given, we'll compute it from the corresponding data in the reactionSuite
:param XYs1d colData: an XYs1d instance containing data to rescale covariance in the "col direction"
if it isn't given, we'll compute it from the corresponding data in the reactionSuite
.. note:: If the column axis is a link, only rowData is needed.
If neither rowData nor colData are specified, you'd better hope that the covariance is already
relative because this will throw an error.
:returns: a copy of self, but rescaled and with the type set to relativeToken
'''
result = copy.copy( self ) #copy.deepcopy( self )
if self.type==tokens.relativeToken: return result
# Make sure we have usable row data to rescale with
if rowData is None:
rowData = copy.copy(self.ancestor.ancestor.rowData.link).toPointwise_withLinearXYs(lowerEps=lowerEps, upperEps=upperEps)
if not isinstance( rowData, XYsModule.XYs1d ):
raise TypeError( 'rowData must be of type XYs1d, found %s' % type(rowData) )
gRowData = rowData.group( self.matrix.axes[2].values )
# Only generate the column rescaling if we need to
if not self.matrix.axes[1].style=='link':
if colData is None:
colData = copy.copy(self.ancestor.ancestor.columnData.link).toPointwise_withLinearXYs(lowerEps=lowerEps, upperEps=upperEps)
if not isinstance( colData, XYsModule.XYs1d ):
raise TypeError( 'colData must be of type XYs1d, found %s' % type(colData) )
gColData = colData.group( self.matrix.axes[1].values )
else: gColData = gRowData
# Rescale!
newData = []
for i,row in enumerate(self.matrix.array.constructArray()):
newRow = []
for j, cell in enumerate(row):
newRow.append( cell/gRowData[i]/gColData[j] )
newData.append( newRow )
result.matrix.data = newData
result.type=tokens.relativeToken
# Set the final units
result.matrix.axes[0].unit = ''
return result
[docs] def check( self, info ):
"""Check if uncertainty in the bounds passed into the checker.
Requires specification of the data ("theData") if the covariance is not relative.
I was not creative when I coded this, so it will fail when theData.getValue( x )
doesn't exist or is a function of more than one value. """
from fudge.gnds import warning
warnings = []
if self.isSymmetric() and info['checkUncLimits']:
A = self.matrix.array.constructArray()
relative = self.type == 'relative'
if relative:
varMin = info['minRelUnc']*info['minRelUnc']
varMax = info['maxRelUnc']*info['maxRelUnc']
for idx in range( A.shape[0] ):
if not relative:
if info['theData'] is not None:
uncMin = info['minRelUnc'] * info['theData'].getValue(
0.5*(self.axes[2].grid[idx]+self.axes[2].grid[idx+1]) )
uncMax = info['maxRelUnc'] * info['theData'].getValue(
0.5*(self.axes[2].grid[idx]+self.axes[2].grid[idx+1]) )
varMin = uncMin*uncMin
varMax = uncMax*uncMax
else:
#warnings.append( "WARNING: can't check absolute uncertainties without data to compare to!\n" )
break
if varMin <= A[idx,idx] and varMax >= A[idx,idx]: pass # unc is where is should be
elif varMin >= A[idx,idx]: # uncertainty too small
warnings.append( warning.varianceTooSmall( idx, A[idx,idx], self ) )
else: # uncertainty too big
warnings.append( warning.varianceTooLarge( idx, A[idx,idx], self ) )
# FIXME: is this the right place for eigenvalue checks? They used to live in fudge.core.math.matrix,
# but that no longer exists
vals, vecs = numpy.linalg.eigh( A )
if min(vals) < info['negativeEigenTolerance']:
warnings.append( warning.negativeEigenvalues( len(vals[vals<0]), min(vals), self ))
minpos, maxpos = min(vals[vals>=0]),max(vals[vals>=0])
# Check that the condition number of the matrix is reasonable
if minpos/maxpos < info['eigenvalueRatioTolerance'] and A.size != 1:
warnings.append( warning.badEigenvalueRatio( minpos/maxpos, self ) )
return warnings
[docs] def fix( self, **kw ):
"""Fix uncertainty using the bounds passed into the fixer.
Requires specification of the data ("theData") if the covariance is not relative.
I was not creative when I coded this, so it will fail when theData.getValue( x )
doesn't exist or is a function of more than one value. """
warnings = []
if self.isSymmetric() and kw['fixUncLimits']:
A = numpy.matrix( self.matrix.data )
relative = self.type == 'relative'
for idx in range( A.shape[0] ):
eMin = self.axes[2].grid[idx]
eMax = self.axes[2].grid[idx+1]
if relative:
uncMin = kw['minRelUnc']
uncMax = kw['maxRelUnc']
else:
uncMin = kw['theData'].getValue( 0.5*(eMax+eMin) )
uncMax = kw['theData'].getValue( 0.5*(eMax+eMin) )
uncMin2 = uncMin*uncMin
uncMax2 = uncMax*uncMax
#eThresh = threshold.getValueAs( component.axes[0].units )
if uncMin2 <= A[idx,idx] <= uncMax2: pass # unc is where is should be
elif uncMin2 >= A[idx,idx]:
if idx+1 < A.shape[0] and A[idx+1,idx+1] >= uncMin2: A[idx,idx] = A[idx+1,idx+1]
else: A[idx,idx] = uncMin2
# else: # above threshold and uncertainty out of bounds
# continue #skip this fix for now
# if uncMin2 > A[idx,idx]: # uncertainty too small
# print ' WARNING: bin', idx, 'uncertainty is too small!!!', '(', uncMin2, '>', A[idx,idx], ')'
# if A[idx, idx] == 0.0:
# for jdx in range( idx+1, A.shape[0] ):
# A[idx,jdx] = 0.0
# A[jdx,idx] = 0.0
# A[idx,idx] == uncMin2
# else:
# for jdx in range( idx+1, A.shape[0] ):
# A[idx,jdx] *= uncMin / math.sqrt( A[idx,idx] )
# A[jdx,idx] = A[idx,jdx]
# A[idx,idx] == uncMin2
# else: # uncertainty too big
# print ' WARNING: bin', idx, 'uncertainty is too big!!!', '(', A[idx,idx], '>', uncMax2, ')'
# for jdx in range( idx+1, A.shape[0] ):
# A[idx,jdx] *= uncMax / math.sqrt( A[idx,idx] )
# A[jdx,idx] = A[idx,jdx]
# A[idx,idx] = uncMax2
self.data = A.tolist()
return warnings + self.matrix.fix( **kw )
[docs] def group( self, groupBoundaries = ( None, None ), groupUnit = ( None, None ) ):
'''
Group the matrix in self
:param groupBoundaries: a 2 element list containing the group boundaries for the rows
and columns (respectively) of the covariance to be regrouped
rows go in the first element, columns in the second
:param groupUnit: a 2 element list containing the units in which group boundaries are
specified for the rows and columns (respectively) of the covariance
to be regrouped
:returns: the regrouped matrix (an xData.array.full as the array in a gridded2d.matrix)
.. note:: We still need to do flux weighting
.. rubric:: Regrouping Theory
Given a function :math:`f(E)`, we write the grouped data using fudge's ``flat`` interpolation
scheme. We note that we could write this scheme as an expansion over basis functions:
.. math::
f(E) = \sum_{i=0}^{N+1} w_i(E) * f_i
where the weight functions :math:`w_i(E)` are
.. math::
w_i(E) = 1 \;\\text{for}\; E_i <= E <= E_{i+1}; \;\; 0 \;\\textrm{otherwise}
These weights are an orthogonal (bot not orthonormal) basis, with
.. math::
(E_{i+1}-E_i) \delta_{ij} = \int dE w_i(E) * w_j(E)
So, to transform from basis :math:`w_i(E)` to :math:`v_i(E)` (which has group boundaries
:math:`[ E'_0, ... ]`), do:
.. math::
f'_j = \sum_i m_{ji} f_i
where :math:`f'` is the regrouped function coefficients and :math:`m_{ji}` is the matrix
.. math::
m_{ij} = (E'_{i+1}-E'_i)^{-1} \int dE v_i(E) w_j(E)
.. rubric:: Applying regrouping theory to covariance matrices
When we are given a covariance matrix :math:`c_{ij}` in ENDF, it is meant to be interpreted
as a grouped covariance in both the direction of the matrix rows and the matrix
columns. Therefore, we must regroup in both the row direction and the column
direction. The ENDF format gives both the group boundaries for the rows and columns.
In other words, ENDF gives us the following rule for evaluating the continuous row-
column covariance:
.. math::
c( E1, E2 ) = \sum_{ij} w_i(E1) w_j(E2) c_{ij}
Computing :math:`m_{ij}` as before,
.. math::
cc_{ij} = \sum_{i',j'} m_{ii'} c_{i'j'} m_{j'j}
It is straightforward to generalize to the case where the row and column bases are
different.
In the routine below, we abuse :py:class:`xData.XYs1d` to specify the functions
:math:`w_i(E)` and use the :py:func:`XYs1d.groupOneFunction()` method to perform the integrals to get
the regrouping matrix. We do this separately for the rows and the columns.
The matrix multiplication that converts a covariance from one pair of bases (group
structures) to another is accomplished using numpy.
.. rubric:: An explanation of fudge's 'flat' interpolation
Suppose we have a function :math:`f(E)` specified using fudge's `'flat'` interpolation.
Then we have :math:`N` entries :math:`[f_0, f_1, ..., f_{N-1}]` and a set of group
boundaries :math:`[E_0, E_1, ..., E_N]` and the following rule for interpolation:
* Below :math:`E_0`, :math:`f(E)` evaluates to :math:`0.0`
* From :math:`E_0 \\rightarrow E_1`, :math:`f(E)` evaluates to :math:`f_0`
* From :math:`E_1 \\rightarrow E_2`, :math:`f(E)` evaluates to :math:`f_1`
* ...
* From :math:`E_{i} \\rightarrow E_{i+1}`, :math:`f(E)` evaluates to :math:`f_i`
* ...
* From :math:`E_{N-1} \\rightarrow E_N`, :math:`f(E)` evaluates to :math:`f_{N-1}`
* Above :math:`E_N`, :math:`f(E)` evaluates to :math:`0.0`
'''
# determine where to get the settings for the potentially mirrored second axis
if self.matrix.axes[1].style == 'link': axis1index = 2
else: axis1index = 1
# setup the old axes in a form we can (ab)use in the XYs1d class
axes2_ = axesModule.axes( labelsUnits={1:( self.matrix.axes[2].label, self.matrix.axes[2].unit ),0:( 'dummy', '' )} )
axes1_ = axesModule.axes( labelsUnits={1:( self.matrix.axes[axis1index].label, self.matrix.axes[axis1index].unit ),0:( 'dummy', '' )} )
# define basis functions for the rows and columns
basis2 = XYsModule.XYs1d( axes=axes2_, data=[ ( x, 0.0 ) for x in self.matrix.axes[2].values ], interpolation='flat' )
basis1 = XYsModule.XYs1d( axes=axes1_, data=[ ( x, 0.0 ) for x in self.matrix.axes[axis1index].values ], interpolation='flat' )
basis2 = basis2.convertAxisToUnit( 1, groupUnit[0] )
basis1 = basis1.convertAxisToUnit( 1, groupUnit[1] )
# build the regrouping matrices for the two bases
w0 = []
for idx in range( self.matrix.array.shape[0] ):
basis2[idx] = ( basis2[idx][0], 1.0 )
w0.append( basis2.groupOneFunction( groupBoundaries[0], norm = 'dx' ) )
basis2[idx] = ( basis2[idx][0], 0.0 )
w0 = numpy.mat( w0 )
w1 = []
for j in range( self.matrix.array.shape[1] ):
basis1[j] = ( basis1[j][0], 1.0 )
w1.append( basis1.groupOneFunction( groupBoundaries[1], norm = 'dx' ) )
basis1[j] = ( basis1[j][0], 0.0 )
w1 = numpy.mat( w1 )
# set up the regrouped covariance matrix
grouped = copy.copy( self )
grouped.matrix.axes[2].data = groupBoundaries[0]
grouped.matrix.axes[1].data = groupBoundaries[1]
grouped.matrix.axes[2].unit = groupUnit[0]
grouped.matrix.axes[1].unit = groupUnit[1]
odata = numpy.mat( self.matrix.array.constructArray() )
gdata = w0.T * odata * w1
trigdata = gdata[numpy.tri(gdata.shape[0])==1.0].tolist()[0]
grouped.matrix.array = arrayModule.full(shape=gdata.shape,data=trigdata,symmetry=arrayModule.symmetryLowerToken)
return grouped
[docs] def getUncertaintyVector( self, theData=None, relative=True ):
"""
Get an XYs1d object containing uncertainty for this matrix.
Convert relative/absolute if requested (if so, must also pass central values as theData)
Examples:
- if the covariance matrix is relative and we want relative uncertainty vector, just do:
> matrix.getUncertaintyVector()
- if we want the absolute matrix instead:
> matrix.getUncertaintyVector( theData=<XYs1d instance>, relative=False )
"""
if not self.isSymmetric():
raise ValueError("getUncertaintyVector only applies to symmetric matrices!")
energies = list( self.matrix.axes[-1].values )
diag = numpy.diagonal( self.matrix.array.constructArray() ).copy()
diag[ diag < 0.0 ] = 0.0
diag = list( numpy.sqrt( diag ) )
diag.append( diag[-1] ) # point corresponding to final energy bin
yunit = self.matrix.axes[0].unit
if yunit != '': # get square root of the unit
yunit = PQU.PQU(1,yunit).sqrt().getUnitSymbol()
axes_ = axesModule.axes(
labelsUnits={1:('energy_in',self.matrix.axes[2].unit),
0:('uncertainty',yunit)} )
uncert = XYsModule.XYs1d( zip( energies, copy.deepcopy( diag ) ), axes = axes_, interpolation = 'flat' )
uncert = uncert.changeInterpolation('lin-lin',accuracy=1e-3,lowerEps=1e-8,upperEps=1e-8)
# do we need to convert absolute->relative or vice versa?
if (relative and self.type==tokens.absoluteToken) or (not relative and self.type==tokens.relativeToken):
if theData is None:
theData = self.ancestor.rowData.link.toPointwise_withLinearXYs( lowerEps = 1e-8, upperEps = 1e-8 )
try:
theData = theData.toPointwise_withLinearXYs( lowerEps = 1e-8, upperEps = 1e-8 )
uncert, theData = uncert.mutualify(1e-8, 1e-8, False, theData, 1e-8, 1e-8, False)
if relative: #convert absolute to relative
uncert /= theData
else: #relative to absolute
uncert *= theData
except Exception as err:
print len( uncert ), uncert.copyDataToXYs()[0], uncert.copyDataToXYs()[-1]
print len( theData ), theData.copyDataToXYs()[0], theData.copyDataToXYs()[-1]
raise Exception( err.message )
return uncert
[docs] def plot( self, title = None, scalelabel = None, xlim=None, ylim=None, xlog=False, ylog=False ):
"""
:param title:
:param scalelabel:
:param xlim:
:param ylim:
:param xlog:
:param ylog:
:return:
"""
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.collections import QuadMesh
# determine where to get the settings for the potentially mirrored second axis
if self.matrix.axes[1].style == 'link': axis1index = 2
else: axis1index = 1
x = self.matrix.axes[2].values
y = self.matrix.axes[axis1index].values
X, Y = np.meshgrid( x, y )
XY = np.hstack((X.ravel()[:,np.newaxis], Y.ravel()[:,np.newaxis]))
Z = (self.matrix.array.constructArray()).ravel()
ax = plt.subplot(1,1,1)
if title is None: title = str( self.toXLink() )
plt.suptitle(title)
qc = QuadMesh(
meshWidth=len(x)-1,
meshHeight=len(y)-1,
coordinates=XY,
# showedges=True,
antialiased=True,
shading='flat',
transOffset=ax.transData)
qc.set_array(Z)
ax.add_collection(qc,autolim=True)
if xlim is None: ax.set_xlim( x[0], x[-1] )
else: ax.set_xlim( xlim[0], xlim[1] )
if ylim is None: ax.set_ylim( y[0], y[-1] )
else: ax.set_ylim( ylim[0], ylim[1] )
if xlog: ax.set_xscale( 'log' )
if ylog: ax.set_yscale( 'log' )
xlabel = self.matrix.axes[2].label + ' (' + self.matrix.axes[2].unit +')'
ylabel = self.matrix.axes[axis1index].label + ' (' + self.matrix.axes[axis1index].unit +')'
ax.set_xlabel( xlabel )
ax.set_ylabel( ylabel )
cbar = plt.colorbar(qc)
if scalelabel is not None: cbar.set_label(scalelabel)
else: cbar.set_label(str(self.type)+' covariance ('+str(self.matrix.axes[0].unit)+')')
plt.show()
[docs] def toXMLList( self, indent = '', **kwargs ) :
"""
:param indent:
:param kwargs:
:return:
"""
indent2 = indent + kwargs.get( 'incrementalIndent', ' ' )
xmlString = [ '%s<%s' % ( indent, self.moniker ) ]
if self.label is not None: xmlString[0] += ' label="%s"' % self.label
xmlString[0] += ' type="%s"' % self.type
if self.productFrame is not None:
xmlString[0] += ' productFrame="%s"' % self.productFrame
xmlString[0] += '>'
xmlString += self.matrix.toXMLList( indent2, **kwargs )
xmlString[-1] += '</%s>' % self.moniker
return xmlString
[docs] @staticmethod
def parseXMLNode(element, xPath, linkData):
"""Translate <covarianceMatrix> element from xml into python class."""
xPath.append( element.tag )
matrix_ = griddedModule.gridded2d.parseXMLNode( element[0], xPath, linkData )
CM = covarianceMatrix( label = element.get('label'), type=element.get('type'), matrix=matrix_,
productFrame=element.get('productFrame') )
xPath.pop()
return CM