Skip to content

Commit 2d9bb6f

Browse files
committed
Several field subplots on same figure
The plot option of the field subcommand now uses the same logic as rprof and time to describe the list of variables to plot. The shrinkcb option of the field subcommand is removed since the size of colorbars is now automatically determined.
1 parent ced75a9 commit 2d9bb6f

File tree

8 files changed

+67
-60
lines changed

8 files changed

+67
-60
lines changed

docs/sources/cookbook/field.rst

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,44 @@ will plot the last snapshot of the temperature field.
1717

1818
::
1919

20-
% stagpy field -s : -o T,v3
20+
% stagpy field -s : -o T-v3
2121

2222
will plot all the snapshots of the temperature and the vertical/radial velocity
2323
on separate figures.
2424

2525
::
2626

27-
% stagpy field -s 3:8:2 -o T+stream
27+
% stagpy field -s 3:8:2 -o T,stream
2828

2929
will plot the temperature field with isocontours of the stream function from
3030
the third to the eighth snapshot, every two snapshots.
3131

3232
::
3333

34-
% stagpy field -o T -s 1:5 --vmin=0.8 --vmax=1.0
34+
% stagpy field -o T -s 1,5 --vmin=0.8 --vmax=1.0
3535
36-
will plot the temperature field from the first to the fifth snapshot while keeping the range of the colorbar fixed between 0.8 and 1.
36+
will plot the temperature field from the first and the fifth snapshot while
37+
keeping the range of the colorbar fixed between 0.8 and 1.
38+
39+
List of variables to plot
40+
-------------------------
41+
42+
The list of fields specified with the ``-o`` (or ``--plot``) option follows the
43+
same rules as for the ``rprof`` and ``time`` subcommands. Namely,
44+
``,``-separated variables are on the same subplots; ``.``-separated variables
45+
are on the same figure but different subplots; ``-``-separated variables are
46+
on different figures.
47+
48+
Note that only two fields can be on the same subplot, the first field is a
49+
color map and the second field can be either:
50+
51+
- a scalar field, isocontours are added to the plot;
52+
- a vector field (e.g. ``v`` for the ``(v1, v2, v3)`` vector), arrows are added
53+
to the plot.
54+
55+
For example, ``-o=T,v3`` asks for a temperature map with isocontour of the
56+
vertical velocity, while ``-o=T,v`` asks for a temperature map with velocity
57+
vectors on top of it.
58+
59+
If you ask for more than two fields on the same subplot, extra fields are
60+
ignored. ``-o=T,stream,v`` is therefore equivalent to ``-o=T,stream``.

docs/sources/cookbook/time.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ time 0.03.
3333

3434
::
3535

36-
% stagpy time -o vrms_Tmin,Tmean,Tmax.dTdt
36+
% stagpy time -o vrms-Tmin,Tmean,Tmax.dTdt
3737

3838
creates two figures. The first one contains the time series of the rms
3939
velocity. The second one contains two subplots, the first one with the time
@@ -42,7 +42,7 @@ time derivative of the mean temperature. The variable names can be found by
4242
running the ``% stagpy var`` command. The variables you want on the same
4343
subplot are separated by commas ``,``, the variables you want on different
4444
subplots are separated by dots ``.``, and the variables you want on different
45-
figures are separated by underscores ``_``.
45+
figures are separated by dashes ``-``.
4646

4747
::
4848

docs/sources/tuto.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ to have some help on the available options for one particular sub command.
3535

3636
A simple example would be::
3737

38-
% stagpy field -p path/to/run/ -o T,p -s 42
38+
% stagpy field -p path/to/run/ -o T-p -s 42
3939

4040
This asks StagPy to plot the temperature and pressure fields of snapshot 42
4141
of the run lying in ``./path/to/run``. When not specified, the path defaults to

stagpy/config.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def _index_collection(arg):
9696

9797
CONF_DEF['field'] = OrderedDict((
9898
('plot',
99-
Conf('T+stream', True, 'o',
99+
Conf('T,stream', True, 'o',
100100
{'nargs': '?', 'const': '', 'type': str},
101101
True, 'variables to plot (see stagpy var)')),
102102
('perturbation', switch_opt(False, None,
@@ -105,9 +105,6 @@ def _index_collection(arg):
105105
False, 'Shift plot horizontally')),
106106
('interpolate', switch_opt(True, None, 'apply Gouraud shading')),
107107
('colorbar', switch_opt(True, None, 'add color bar to plot')),
108-
('shrinkcb',
109-
Conf(0.5, False, None, {},
110-
True, 'color bar shrink factor')),
111108
('ix', Conf(None, True, None, {'type': int},
112109
False, 'x-index of slice for 3D fields')),
113110
('iy', Conf(None, True, None, {'type': int},

stagpy/field.py

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
"""Plot scalar and vector fields."""
22

3+
from itertools import chain
4+
35
import numpy as np
46
import matplotlib as mpl
57
import matplotlib.pyplot as plt
68
import matplotlib.patches as mpat
9+
from mpl_toolkits.axes_grid1 import make_axes_locatable
710

811
from . import conf, misc, phyvars
912
from .error import NotAvailableError
@@ -119,28 +122,6 @@ def get_meshes_vec(step, var):
119122
return xmesh, ymesh, vec1, vec2
120123

121124

122-
def set_of_vars(arg_plot):
123-
"""Build set of needed field variables.
124-
125-
Each var is a tuple, first component is a scalar field, second component is
126-
either:
127-
128-
- a scalar field, isocontours are added to the plot.
129-
- a vector field (e.g. 'v' for the (v1,v2,v3) vector), arrows are added to
130-
the plot.
131-
132-
Args:
133-
arg_plot (str): string with variable names separated with
134-
``,`` (figures), and ``+`` (same plot).
135-
Returns:
136-
set of str: set of needed field variables.
137-
"""
138-
sovs = set(tuple((var + '+').split('+')[:2])
139-
for var in arg_plot.split(','))
140-
sovs.discard(('', ''))
141-
return sovs
142-
143-
144125
def plot_scalar(step, var, field=None, axis=None, **extra):
145126
"""Plot scalar field.
146127
@@ -217,13 +198,15 @@ def plot_scalar(step, var, field=None, axis=None, **extra):
217198

218199
cbar = None
219200
if conf.field.colorbar:
220-
cbar = plt.colorbar(surf, shrink=conf.field.shrinkcb)
201+
cax = make_axes_locatable(axis).append_axes(
202+
'right', size="3%", pad=0.15)
203+
cbar = plt.colorbar(surf, cax=cax)
221204
cbar.set_label(meta.description +
222205
(' pert.' if conf.field.perturbation else '') +
223206
(' ({})'.format(unit) if unit else ''))
224207
if step.geom.spherical or conf.plot.ratio is None:
225-
plt.axis('equal')
226-
plt.axis('off')
208+
axis.set_aspect('equal')
209+
axis.set_axis_off()
227210
else:
228211
axis.set_aspect(conf.plot.ratio / axis.get_data_ratio())
229212
axis.set_adjustable('box')
@@ -283,13 +266,16 @@ def cmd():
283266
conf.core
284267
"""
285268
sdat = StagyyData()
286-
sovs = set_of_vars(conf.field.plot)
269+
lovs = misc.list_of_vars(conf.field.plot)
270+
# no more than two fields in a subplot
271+
lovs = [[slov[:2] for slov in plov] for plov in lovs]
287272
minmax = {}
288273
if conf.plot.cminmax:
289274
conf.plot.vmin = None
290275
conf.plot.vmax = None
276+
sovs = set(slov[0] for plov in lovs for slov in plov)
291277
for step in sdat.walk.filter(snap=True):
292-
for var, _ in sovs:
278+
for var in sovs:
293279
if var in step.fields:
294280
if var in phyvars.FIELD:
295281
dim = phyvars.FIELD[var].dim
@@ -302,18 +288,23 @@ def cmd():
302288
else:
303289
minmax[var] = np.nanmin(field), np.nanmax(field)
304290
for step in sdat.walk.filter(snap=True):
305-
for var in sovs:
306-
if var[0] not in step.fields:
307-
print("'{}' field on snap {} not found".format(var[0],
308-
step.isnap))
309-
continue
310-
opts = {}
311-
if var[0] in minmax:
312-
opts = dict(vmin=minmax[var[0]][0], vmax=minmax[var[0]][1])
313-
fig, axis, _, _ = plot_scalar(step, var[0], **opts)
314-
if valid_field_var(var[1]):
315-
plot_iso(axis, step, var[1])
316-
elif var[1]:
317-
plot_vec(axis, step, var[1])
318-
oname = '{}_{}'.format(*var) if var[1] else var[0]
291+
for vfig in lovs:
292+
fig, axes = plt.subplots(ncols=len(vfig), squeeze=False,
293+
figsize=(12 * len(vfig), 9))
294+
for axis, var in zip(axes[0], vfig):
295+
if var[0] not in step.fields:
296+
print("'{}' field on snap {} not found".format(var[0],
297+
step.isnap))
298+
continue
299+
opts = {}
300+
if var[0] in minmax:
301+
opts = dict(vmin=minmax[var[0]][0], vmax=minmax[var[0]][1])
302+
plot_scalar(step, var[0], axis=axis, **opts)
303+
if len(var) == 2:
304+
if valid_field_var(var[1]):
305+
plot_iso(axis, step, var[1])
306+
elif valid_field_var(var[1] + '1'):
307+
plot_vec(axis, step, var[1])
308+
oname = '_'.join(chain.from_iterable(vfig))
309+
plt.tight_layout(w_pad=3)
319310
misc.saveplot(fig, oname, step.isnap)

stagpy/misc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def list_of_vars(arg_plot):
7575
7676
Args:
7777
arg_plot (str): string with variable names separated with
78-
``_`` (figures), ``.`` (subplots) and ``,`` (same subplot).
78+
``-`` (figures), ``.`` (subplots) and ``,`` (same subplot).
7979
Returns:
8080
three nested lists of str
8181

tests/test_cli.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ def dir_isnap(request, repo_dir):
1010

1111
@pytest.fixture(params=[
1212
('stagpy field', ['stagpy_T_stream{:05d}.pdf']),
13-
('stagpy field -o=T,v3', ['stagpy_T{:05d}.pdf',
13+
('stagpy field -o=T.v3', ['stagpy_T_v3{:05d}.pdf']),
14+
('stagpy field -o=T-v3', ['stagpy_T{:05d}.pdf',
1415
'stagpy_v3{:05d}.pdf']),
1516
])
1617
def all_cmd_field(request, dir_isnap):

tests/test_field.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,3 @@ def test_get_meshes_vec(step):
2323
xmesh, ymesh, vec1, vec2 = stagpy.field.get_meshes_vec(step, 'v')
2424
assert len(vec1.shape) == 2
2525
assert xmesh.shape == ymesh.shape == vec1.shape == vec2.shape
26-
27-
28-
def test_set_of_vars():
29-
sovs = stagpy.field.set_of_vars('a+b,c,++,,d++e')
30-
expected = set([('a', 'b'), ('c', ''), ('d', '')])
31-
assert sovs == expected

0 commit comments

Comments
 (0)