Source code for pyts.plot.axform
from ..main import tsdata, tsrun # used to identify object types
import superaxes as supax
import psd
from base import indx, mpl
import numpy as np
[docs]class axesForm(object):
"""A base 'axesForm' class for for quickly plotting TurbSim data.
Parameters
----------
xlim : iterable(2) (default: [None, None])
Specify the xlims of the axes of these plots. The default
will simply select the limits automatically.
ylim : iterable(2) (default: [None, None])
Specify the ylims of the axes of these plots. The default
will simply select the limits automatically.
xscale : ('log' or 'linear')
specify whether the x-scale should be logarithmic or linear.
yscale : ('log' or 'linear')
specify whether the y-scale should be logarithmic or linear.
"""
method_map = {tsdata: '_calc_tsdata', tsrun: '_calc_tsrun'}
hide_ylabels = False
_lin_x_scale = 0
def __init__(self,
xlim=[None, None], ylim=[None, None],
xscale='linear', yscale='linear',):
self.xlim = xlim
self.ylim = ylim
self.xscale = xscale
self.yscale = yscale
[docs] def finalize(self, axes):
"""
This function 'finishes' the `axes` according to the
specifications in this axesForm.
Parameters
----------
axes : A :class:`superaxes.axgroup` instance.
"""
axes.hide('xticklabels', ax=axes[-1])
if self.hide_ylabels:
axes.hide('yticklabels')
if not self.hide_ylabels and hasattr(self, '_ylabel'):
for ax in axes:
ax.set_ylabel(self._ylabel)
if hasattr(self, '_xlabel'):
axes[-1].set_xlabel(self._xlabel)
if hasattr(self, '_title'):
axes[0].set_title(self._title)
if hasattr(self, '_grid_x'):
for ax in axes:
for val in self._grid_x:
ax.axvline(val, linestyle=':', color='k', zorder=-10)
if hasattr(self, '_labels'):
for ax in axes:
ax.annoteCorner(self._labels[ax.comp], pos='ul')
if hasattr(self, 'xtick_n'):
for ax in axes:
ax.xaxis.set_major_locator(
mpl.ticker.MaxNLocator(self.xtick_n))
for ax in axes:
ax.set_xlim(self.xlim)
for ax in axes:
ax.set_ylim(self.ylim)
def _calc(self, obj, comp):
"""
Call the appropriate 'calc' method depending on the object
class.
Parameters
----------
obj : object
An object containing data/information to be plotted.
comp : int,str
The component (u,v,w or 0,1,2) to compute.
Returns
-------
x : array_like
The x data to plot.
y : array_like
The y data to plot.
Notes
-----
This method is a parser for the individual '_calc_<obj>'
methods. It utilizes the :attr:`method_map` to determine which
method should be called for each `obj` object type.
"""
if comp.__class__ is str:
comp = indx[comp]
for cls, meth in self.method_map.iteritems():
if isinstance(obj, cls):
if not hasattr(self, meth):
return np.NaN, np.NaN
return getattr(self, meth)(obj, comp)
raise Exception('Object type %s not recognized for %s axes-type' %
(obj.__class__, self.__class__))
[docs] def plot(self, obj, axes, **kwargs):
"""
Plot the data in `obj` to `axes`.
Parameters
----------
obj : object
An object containing data to be plotted.
axes : :class:`superaxes.axgroup` instance
The axes into which that data should be plotted.
"""
for ax in axes:
x, y = self._calc(obj, ax.comp)
# print x, y, self._lin_x_scale
ax.plot(x / (10 ** self._lin_x_scale), y, **kwargs)
ax.set_xscale(self.xscale)
ax.set_yscale(self.yscale)
@property
def _xlabel(self,):
if self._lin_x_scale == 0:
return '$\mathrm{[m^2s^{-2}]}$'
else:
return '$\mathrm{[10^{%d}m^2s^{-2}]}$' % self._lin_x_scale
[docs]class prof(axesForm):
"A base axesForm for plotting vertical profiles."
yax = 'z'
_ylabel = '$z\,\mathrm{[m]}$'
hrel = 0.6
xtick_n = 3
[docs]class velprof(prof):
"""A 'mean velocity profile' axesForm format.
See also
--------
:class:`prof`
:class:`axesForm`
"""
xax = 'vel'
_title = 'Mean Velocity'
_xlabel = '$\mathrm{[m/s]}$'
def _calc_tsdata(self, tsdat, comp, igrid=None):
"""
The function that calculates x,y values for plotting
:class:`.tsdata` objects.
"""
return tsdat.uprof[comp, :, tsdat.ihub[1]], tsdat.z
def _calc_tsrun(self, tsr, comp, igrid=None):
"""
The function that calculates x,y values for plotting
:class:`.tsrun` objects.
"""
return tsr.prof[comp, :, tsr.grid.ihub[1]], tsr.grid.z
[docs]class tkeprof(prof):
"""A 'tke profile' axesForm.
See also
--------
:class:`prof`
:class:`axesForm`
"""
xax = 'tke'
_title = 'tke'
#_lin_x_scale = -2 # Units are 10^-2
def _calc_tsdata(self, tsdat, comp, igrid=None):
return tsdat.tke[comp, :, tsdat.ihub[1]], tsdat.z
def _calc_tsrun(self, tsr, comp, igrid=None):
return tsr.spec.tke[comp, :, tsr.grid.ihub[1]], tsr.grid.z
[docs]class Tiprof(prof):
"""A Turbulence intensity axesForm
See also
--------
:class:`prof`
:class:`axesForm`
"""
xax = 'Ti'
_title = 'Ti'
_lin_x_scale = 0
_ylabel = '%'
def _calc_tsdata(self, tsdat, comp, igrid=None):
tmp = (100 * np.std(tsdat.uturb[comp, :, tsdat.ihub[1]], axis=-1)
/ tsdat.uprof[0, :, tsdat.ihub[1]])
return tmp, tsdat.z
def _calc_tsrun(self, tsr, comp, igrid=None):
return (100 * np.sqrt(tsr.spec.tke[comp, :, tsr.grid.ihub[1]])
/ tsr.prof.u[:, tsr.grid.ihub[1]],
tsr.grid.z)
[docs]class stressprof(tkeprof):
"""A 'Reynold's stress profile' axesForm.
See also
--------
:class:`prof`
:class:`axesForm`
"""
xax = 'tke'
_title = 'stress'
_lin_x_scale = -2 # Units are 10^-2
_grid_x = [0]
_labels = {'u': r"$\overline{u'v'}$",
'v': r"$\overline{u'w'}$",
'w': r"$\overline{v'w'}$"}
def _calc_tsdata(self, tsdat, comp, igrid=None):
igrid = igrid or tsdat.ihub[1]
return tsdat.stress[comp, :, igrid], tsdat.z
def _calc_tsrun(self, tsr, comp, igrid=None):
igrid = igrid or tsr.grid.ihub[1]
return tsr.stress.array[comp, :, igrid], tsr.grid.z
[docs]class spec(axesForm):
"""A 'spectral' axesForm.
Parameters
----------
window_time_sec : float
the length of the fft window (seconds).
igrid : tuple,list (2), *optional* (default: i_hub)
The spatial-index of the grid-point that should be
plotted.
Notes
-----
This axesForm defaults to have 'log' x- and y-scales.
See also
--------
:class:`axesForm`
"""
hrel = 1
_title = 'spectrum'
yax = 'spec'
xax = 'freq'
_xlabel = '$f\,\mathrm{[Hz]}$'
_ylabel = '$\mathrm{[m^2s^{-2}/Hz]}$'
def __init__(self, window_time_sec=600, igrid=None,
xscale='log', yscale='log',
**kwargs):
axesForm.__init__(self, xscale=xscale, yscale=yscale, **kwargs)
self.window_time = window_time_sec
self.igrid = igrid
def _calc_tsdata(self, tsdat, comp, igrid=None):
nfft = int(self.window_time / tsdat.dt)
nfft += np.mod(nfft, 2)
igrid = igrid or self.igrid or tsdat.ihub
tmp = psd.psd(tsdat.uturb[comp][igrid],
1. / tsdat.dt,
nfft)
# print tmp
return tmp
def _calc_tsrun(self, tsr, comp, igrid=None):
igrid = igrid or self.igrid or tsr.grid.ihub
return tsr.grid.f, tsr.spec[comp][igrid]
[docs]class cohere(axesForm):
"""
A 'coherence' plotting format for showing coherence between two
points.
Parameters
----------
window_time_sec : float
the length of the fft window (seconds).
igrid0 : tuple,list (2), *optional* (default: i_hub)
The first spatial-index from which to estimate+plot
coherence.
igrid1 : tuple,list (2), *optional* (default: (0,0))
The second spatial-index from which to estimate+plot
coherence.
Notes
-----
This axesForm defaults to have a 'log' x-scale, and to have a
linear y-axis with ylim=[0, 1].
See also
--------
:class:`axesForm`
"""
hrel = 1
_title = 'coherence'
xax = 'freq'
yax = 'coh'
_xlabel = '$f\,\mathrm{[Hz]}$'
def __init__(self, window_time_sec=600, igrid0=None, igrid1=None,
xscale='log', ylim=[0, 1],
**kwargs):
axesForm.__init__(self, xscale=xscale, ylim=ylim, **kwargs)
self.window_time = 600
self.igrid0 = igrid0
self.igrid1 = igrid1
def _calc_tsdata(self, tsdat, comp, igrid0=None, igrid1=None):
nfft = int(self.window_time / tsdat.dt)
nfft += np.mod(nfft, 2)
igrid0 = igrid0 or self.igrid0 or tsdat.ihub
igrid1 = igrid1 or self.igrid1 or (0, 0)
return psd.coh(tsdat.uturb[comp][igrid0],
tsdat.uturb[comp][igrid1],
1. / tsdat.dt, nfft)
def _calc_tsrun(self, tsr, comp, igrid0=None, igrid1=None):
igrid0 = tsr.grid.sub2ind(igrid0 or self.igrid0 or tsr.grid.ihub)
igrid1 = tsr.grid.sub2ind(igrid1 or self.igrid1 or (0, 0))
return tsr.grid.f, tsr.cohere.calcCoh(tsr.grid.f,
comp, igrid0, igrid1) ** 2
[docs]class FigAxForm(supax.sfig):
"""The 'figure' class that uses and handles :class:`axesForm`.
Parameters
----------
fignum : integer,string
The figure number, or string, into which the data will be
plotted.
axforms : list of axForms (e.g. :class:`velprof`, :class:`tkeprof`)
These are the axes formats that will be plotted.
comp : list of velocity components (0,1,2 or 'u','v','w')
axsize : float, tuple, list (2)
The size of the axes. If 2 parameters are specified this
sets they set the horizontal and vertical size of the
axes.
frame : tuple(4) ,list(4)
This specifies the border around the axes (left, right,
bottom, top)
gap : tuple(2), list(2)
This specifies the gap between axes in the horizontal and
vertical directions.
tightgap : float
This specifies the horizontal spacing between axes that
have the same type of y-axis (specified in the formats
'yax' attribute).
Other inputs are passed directly to :meth:`superaxes.sfig.__init__`.
Notes
-----
This will create an NxM axes-grid, where N=len(comp), and
M=len(axforms).
The width of each axes is scaled by the 'hrel' attribute of each
axform.
"""
def __init__(self,
fignum,
axforms=[],
comp=['u', 'v', 'w'],
axsize=2,
frame=[.6, .3, 1, .3],
gap=[.2, 1],
tightgap=.2,
**kwargs):
if len(axforms) == 0:
raise Exception('At least one axes-type \
instance must be provided.')
sharex = np.tile(np.arange(len(axforms), dtype=np.uint8) + 1,
(len(comp), 1))
sharey = np.tile(np.arange(len(axforms), dtype=np.uint8) + 1,
(len(comp), 1))
hspacer = supax.simpleAxSpacer(len(axforms), axsize, gap[1], frame[2:])
vspacer = supax.simpleAxSpacer(len(comp), axsize, gap[0], frame[:2],
vertical=True)
last_yax = None
for idx, axt in enumerate(axforms):
if axt.yax == last_yax:
sharey[:, idx] = sharey[:, idx - 1]
hspacer.gap[idx] = tightgap
axt.hide_ylabels = True
last_yax = axt.yax
if hasattr(axt, 'hrel'):
hspacer.axsize[idx] *= axt.hrel
axp = supax.axPlacer(vspacer, hspacer)
supax.sfig.__init__(self, fignum, axp,
sharex=sharex, sharey=sharey, **kwargs)
self.comp = comp
for idx, axt in enumerate(axforms):
for c, ax in zip(comp, self.sax[:, idx]):
ax.comp = c
self.axforms = axforms
[docs] def plot(self, obj, **kwargs):
"""
Plot the data in `obj` to the figure according to the plotting formats.
Parameters
----------
obj : tsdata, tsrun, turbdata
A data or turbsim object to plot.
"""
for idx, axt in enumerate(self.axforms):
axt.plot(obj, self.sax[:, idx], **kwargs)
[docs] def finalize(self,):
"""
Finalize the figure according to the plotting formats.
"""
for idx, axt in enumerate(self.axforms):
axt.finalize(self.sax[:, idx])
for c, ax in zip(self.comp, self.ax[:, 0]):
p = ax.get_position().ymax
self.fig.text(0.02, p, '$' + c + '$', va='top', ha='left',
size='x-large', backgroundcolor='w')
[docs]def summfig(fignum=400, axforms=[velprof(), spec(600)], **kwargs):
return FigAxForm(fignum, axforms=axforms, **kwargs)