PyMPDATA_examples.Shipway_and_Hill_2012.plot

  1import matplotlib
  2import numpy as np
  3from matplotlib import pylab, pyplot
  4
  5from .formulae import convert_to, si
  6
  7
  8def plot(
  9    var,
 10    mult,
 11    label,
 12    output,
 13    rng=None,
 14    threshold=None,
 15    cmap="copper",
 16    rasterized=False,
 17    figsize=None,
 18):
 19    lines = {3: ":", 6: "--", 9: "-", 12: "-."}
 20    colors = {3: "crimson", 6: "orange", 9: "navy", 12: "green"}
 21    fctr = 50  # rebin by fctr in time dimension (https://gist.github.com/zonca/1348792)
 22
 23    dt = (output["t"][1] - output["t"][0]) * fctr
 24    dz = output["z"][1] - output["z"][0]
 25    tgrid = np.concatenate(((output["t"][0] - dt / 2,), output["t"][0::fctr] + dt / 2))
 26    zgrid = np.concatenate(((output["z"][0] - dz / 2,), output["z"] + dz / 2))
 27    convert_to(zgrid, si.km)
 28
 29    fig = pyplot.figure(constrained_layout=True, figsize=figsize)
 30    gs = fig.add_gridspec(25, 5)
 31    ax1 = fig.add_subplot(gs[:-1, 0:3])
 32
 33    data = output[var] * mult
 34    lngth = data.shape[1] - 1
 35    assert (lngth // fctr) * fctr == lngth
 36
 37    tmp = np.empty((data.shape[0], (data.shape[1] - 1) // fctr + 1))
 38    tmp[:, 0] = data[:, 0]
 39    M, N = data[:, 1:].shape
 40    m, n = M, N // fctr
 41    tmp[:, 1:] = data[:, 1:].reshape((m, M // m, n, N // n)).mean(3).mean(1)
 42    data = tmp
 43
 44    if threshold is not None:
 45        data[data < threshold] = np.nan
 46    mesh = ax1.pcolormesh(
 47        tgrid / si.minutes,
 48        zgrid,
 49        data,
 50        cmap=cmap,
 51        rasterized=rasterized,
 52        vmin=None if rng is None else rng[0],
 53        vmax=None if rng is None else rng[1],
 54    )
 55
 56    ax1.set_xlabel("time [min]")
 57    ax1.set_xticks(list(lines.keys()))
 58    ax1.set_ylabel("z [km]")
 59    ax1.grid()
 60
 61    cbar = fig.colorbar(mesh, fraction=0.05, location="top")
 62    cbar.set_label(label)
 63
 64    ax2 = fig.add_subplot(gs[:-1, 3:], sharey=ax1)
 65    ax2.set_xlabel(label)
 66    ax2.grid()
 67    if rng is not None:
 68        ax2.set_xlim(rng)
 69
 70    last_t = -1
 71    for i, t in enumerate(output["t"]):
 72        x, z = output[var][:, i] * mult, output["z"].copy()
 73        convert_to(z, si.km)
 74        params = {"color": "black"}
 75        for line_t, line_s in lines.items():
 76            if last_t < line_t * si.minutes <= t:
 77                params["ls"] = line_s
 78                params["color"] = colors[line_t]
 79                ax2.step(x, z - (dz / si.km) / 2, where="pre", **params)
 80                ax1.axvline(t / si.minutes, **params)
 81        last_t = t
 82
 83
 84def plot_3d(psi, settings, options, r_min, r_max, max_height):
 85    max_psi = np.amax(psi / (1 / si.mg / si.um))
 86    if max_psi > max_height:
 87        raise ValueError(f"max(psi)={max_psi} > {max_height}")
 88    pylab.figure(figsize=(10, 5))
 89    ax = pylab.subplot(projection="3d")
 90    ax.view_init(75, 85)
 91
 92    cmap = matplotlib.colormaps["gray_r"]
 93    min_height = 0
 94
 95    dz = np.rot90(psi, 2).flatten()
 96    rgba = [cmap((k - min_height) / (1 + max_height)) for k in dz]
 97    dz[dz < 0.05 * max_height] = np.nan
 98    factor = 0.9
 99    ax.bar3d(
100        *[
101            arr.flatten()
102            for arr in np.meshgrid(
103                (settings.bin_boundaries[-2::-1] + settings.dr * (1 - factor) / 2)
104                / si.um,
105                (np.arange(settings.nz - 1, -1, -1) + (1 - factor) / 2)
106                * settings.dz
107                / si.km,
108            )
109        ],
110        z=0,
111        dx=factor * settings.dr / si.um,
112        dy=factor * settings.dz / si.km,
113        dz=dz / (1 / si.mg / si.um),
114        shade=True,
115        color=rgba,
116        lightsource=matplotlib.colors.LightSource(azdeg=-64, altdeg=15),
117        zsort="max",
118    )
119    ax.set_title(f"MPDATA iterations: {options.n_iters}")
120    ax.set_xlabel("droplet radius [μm]")
121    ax.set_ylabel("z [km]")
122    ax.set_zlabel("psi [1/μm 1/mg 1/m]")
123    ax.set_zlim(0, max_height / (1 / si.mg / si.um))
124    ax.set_zticks([0, max_height / (1 / si.mg / si.um)])
125    ax.set_ylim(settings.z_max / si.km, 0)
126    ax.set_xlim(r_max / si.um, r_min / si.um)
127    nticks = 6
128    ax.set_xticks((r_min + np.arange(nticks + 1) * (r_max - r_min) / nticks) / si.um)
def plot( var, mult, label, output, rng=None, threshold=None, cmap='copper', rasterized=False, figsize=None):
 9def plot(
10    var,
11    mult,
12    label,
13    output,
14    rng=None,
15    threshold=None,
16    cmap="copper",
17    rasterized=False,
18    figsize=None,
19):
20    lines = {3: ":", 6: "--", 9: "-", 12: "-."}
21    colors = {3: "crimson", 6: "orange", 9: "navy", 12: "green"}
22    fctr = 50  # rebin by fctr in time dimension (https://gist.github.com/zonca/1348792)
23
24    dt = (output["t"][1] - output["t"][0]) * fctr
25    dz = output["z"][1] - output["z"][0]
26    tgrid = np.concatenate(((output["t"][0] - dt / 2,), output["t"][0::fctr] + dt / 2))
27    zgrid = np.concatenate(((output["z"][0] - dz / 2,), output["z"] + dz / 2))
28    convert_to(zgrid, si.km)
29
30    fig = pyplot.figure(constrained_layout=True, figsize=figsize)
31    gs = fig.add_gridspec(25, 5)
32    ax1 = fig.add_subplot(gs[:-1, 0:3])
33
34    data = output[var] * mult
35    lngth = data.shape[1] - 1
36    assert (lngth // fctr) * fctr == lngth
37
38    tmp = np.empty((data.shape[0], (data.shape[1] - 1) // fctr + 1))
39    tmp[:, 0] = data[:, 0]
40    M, N = data[:, 1:].shape
41    m, n = M, N // fctr
42    tmp[:, 1:] = data[:, 1:].reshape((m, M // m, n, N // n)).mean(3).mean(1)
43    data = tmp
44
45    if threshold is not None:
46        data[data < threshold] = np.nan
47    mesh = ax1.pcolormesh(
48        tgrid / si.minutes,
49        zgrid,
50        data,
51        cmap=cmap,
52        rasterized=rasterized,
53        vmin=None if rng is None else rng[0],
54        vmax=None if rng is None else rng[1],
55    )
56
57    ax1.set_xlabel("time [min]")
58    ax1.set_xticks(list(lines.keys()))
59    ax1.set_ylabel("z [km]")
60    ax1.grid()
61
62    cbar = fig.colorbar(mesh, fraction=0.05, location="top")
63    cbar.set_label(label)
64
65    ax2 = fig.add_subplot(gs[:-1, 3:], sharey=ax1)
66    ax2.set_xlabel(label)
67    ax2.grid()
68    if rng is not None:
69        ax2.set_xlim(rng)
70
71    last_t = -1
72    for i, t in enumerate(output["t"]):
73        x, z = output[var][:, i] * mult, output["z"].copy()
74        convert_to(z, si.km)
75        params = {"color": "black"}
76        for line_t, line_s in lines.items():
77            if last_t < line_t * si.minutes <= t:
78                params["ls"] = line_s
79                params["color"] = colors[line_t]
80                ax2.step(x, z - (dz / si.km) / 2, where="pre", **params)
81                ax1.axvline(t / si.minutes, **params)
82        last_t = t
def plot_3d(psi, settings, options, r_min, r_max, max_height):
 85def plot_3d(psi, settings, options, r_min, r_max, max_height):
 86    max_psi = np.amax(psi / (1 / si.mg / si.um))
 87    if max_psi > max_height:
 88        raise ValueError(f"max(psi)={max_psi} > {max_height}")
 89    pylab.figure(figsize=(10, 5))
 90    ax = pylab.subplot(projection="3d")
 91    ax.view_init(75, 85)
 92
 93    cmap = matplotlib.colormaps["gray_r"]
 94    min_height = 0
 95
 96    dz = np.rot90(psi, 2).flatten()
 97    rgba = [cmap((k - min_height) / (1 + max_height)) for k in dz]
 98    dz[dz < 0.05 * max_height] = np.nan
 99    factor = 0.9
100    ax.bar3d(
101        *[
102            arr.flatten()
103            for arr in np.meshgrid(
104                (settings.bin_boundaries[-2::-1] + settings.dr * (1 - factor) / 2)
105                / si.um,
106                (np.arange(settings.nz - 1, -1, -1) + (1 - factor) / 2)
107                * settings.dz
108                / si.km,
109            )
110        ],
111        z=0,
112        dx=factor * settings.dr / si.um,
113        dy=factor * settings.dz / si.km,
114        dz=dz / (1 / si.mg / si.um),
115        shade=True,
116        color=rgba,
117        lightsource=matplotlib.colors.LightSource(azdeg=-64, altdeg=15),
118        zsort="max",
119    )
120    ax.set_title(f"MPDATA iterations: {options.n_iters}")
121    ax.set_xlabel("droplet radius [μm]")
122    ax.set_ylabel("z [km]")
123    ax.set_zlabel("psi [1/μm 1/mg 1/m]")
124    ax.set_zlim(0, max_height / (1 / si.mg / si.um))
125    ax.set_zticks([0, max_height / (1 / si.mg / si.um)])
126    ax.set_ylim(settings.z_max / si.km, 0)
127    ax.set_xlim(r_max / si.um, r_min / si.um)
128    nticks = 6
129    ax.set_xticks((r_min + np.arange(nticks + 1) * (r_max - r_min) / nticks) / si.um)