This demo shows you how to use the post
formatoption to apply your own post processing scripts.
It requires the 'demo.nc'
netCDF file, netCDF4
and the
psy-maps plugin.
In [1]:
import psyplot.project as psy
%matplotlib inline
%config InlineBackend.close_figures = False
In [2]:
sp = psy.plot.mapvector('demo.nc', name=[['u', 'v']], plot='stream',
color='red', title='%b %Y')
print(sp)
It is hard to see the continents below this amount of arrows. So we might want to enhance our plot with cartopy's stock_img.
But since there is now formatoption for it, we can now either define a
new plotter and add the formatoption, or we use the post
formatoption.
In [3]:
sp.update(enable_post=True,
post='self.stock_img = self.ax.stock_img()')
sp.show()
The first parameter enable_post=True
sets the enable_post
attribute of the plotter to True
. This attribute is by default set to
False
because it is always a security vulnerability to use the built-in
exec
function which is used by the post
formatoption. We could, however,
already have included this in our first definition of the project via
sp = psy.plot.mapvector('demo.nc', name=[['u', 'v']], plot='stream', color='red',
enable_post=True)
The second parameter post='self.ax.stock_img()'
updates the
post
formatoption. It accepts an executable python script as a string. Note that
we make use of the self
variable, the only variable that is given to the script.
It is the Formatoption instance that performs the
update. Hence you can access all the necessary attributes and informations:
self.ax
self.ax.figure
self.data
self.raw_data
self.plotter
title
through self.plotter.title
For example, let's add another feature that adds the mean of the plotted
variables to the plot. For this, let's first have a look into the plot_data
attribute of the plotter which includes the data that is visualized and
that is accessible through the data
attribute of the post
formatoption:
In [4]:
sp.plotters[0].plot_data
Out[4]:
It is a 3-dimensional array, where the first dimension consists of
the zonal wind speed 'u'
and the meridional wind speed 'v'
. So
let's add their means as a text to the plot:
In [5]:
sp.update(post="""
self.stock_img = self.ax.stock_img()
umean = self.data[0].mean().values
vmean = self.data[1].mean().values
abs_mean = ((self.data[0]**2 + self.data[1]**2)**0.5).mean().values
self.text = self.ax.text(
0., -0.15,
'u: %1.4f m/s, v: %1.4f m/s, wind speed: %1.4f m/s' % (
umean, vmean, abs_mean),
transform=self.ax.transAxes)""")
sp.show()
psyplot is intended to work interactively. By default, the post
formatoption
is only updated when you personally update it. However, you can modify this
timing using the post_timing
formatoption. It can be either
'never'
: The default which requires a manual update'replot'
: To update it when the data changes'always'
: To always update it.For example, in the current setting, when we change the data to the second time step via
In [6]:
sp.update(time=1)
print(sp)
sp.show()
Our means are not updated, for this, we have to
post_timing
to 'replot'
post
script to not plot two texts
above each other
In [7]:
sp.update(post_timing='replot', post="""
self.stock_img = self.ax.stock_img()
umean = self.data[0].mean().values
vmean = self.data[1].mean().values
abs_mean = ((self.data[0]**2 + self.data[1]**2)**0.5).mean().values
if hasattr(self, 'text'):
text = self.text
else:
text = self.ax.text(0., -0.15, '',
transform=self.ax.transAxes)
text.set_text(
'u: %1.4f m/s, v: %1.4f m/s, wind speed: %1.4f m/s' % (
umean, vmean, abs_mean))""")
sp.show()
Now, if we update to the third timestep, our means are also calculated
In [8]:
sp.update(time=2)
sp.show()
In [9]:
d = sp.save_project()
However, when loading the project, the enable_post
attribute is
(for security reasons) again set to False
. So if you are sure you
can trust the post processing scripts in the post
formatoption,
load your project with enable_post=True
In [10]:
psy.close('all')
sp = psy.Project.load_project(d, enable_post=True)
In [11]:
psy.close('all')