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.axself.ax.figureself.dataself.raw_dataself.plottertitle through self.plotter.titleFor 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')