Hist1d.plot() and Hist2d.plot()#

Default plotting methods#

Hist1d and Hist2d provide methods for basic plotting, as showcased by the following examples:

import matplotlib.pyplot as plt

import atompy as ap

plt.style.use("atom")

hist = ap.Hist1d((1, 2, 3, 4), (0, 1, 2, 3, 4))
hist.plot(drawstyle="steps-mid")

(Source code, png, hires.png, pdf)

../_images/plot1.png
import matplotlib.pyplot as plt

import atompy as ap

plt.style.use("atom")

hist = ap.Hist1d((1, 2, 3, 4), (0, 1, 2, 3, 4))

_, axs = plt.subplots(1, 2, layout="compressed")

hist.plot(axs[0], plot_fmt="o")
hist.pad_with(0).plot(axs[1], drawstyle="steps-mid")
plt.show()

(Source code, png, hires.png, pdf)

../_images/plot_in_axes.png
import matplotlib.pyplot as plt
import numpy as np

import atompy as ap

plt.style.use("atom")

rng = np.random.default_rng(42)
lim = (-2, 2)
size = 1_000

hist = ap.Hist2d(
    *np.histogram2d(*rng.normal(size=(2, size)), range=(lim, lim)),
    title="A 2D Histogram",
    xlabel="X Label",
    ylabel="Y Label",
    zlabel="Intensity",
)

fig, ax, cb = hist.plot()

plt.show()

(Source code, png, hires.png, pdf)

../_images/plot2.png
import matplotlib.pyplot as plt
import numpy as np

import atompy as ap

plt.style.use("atom")

rng = np.random.default_rng(42)
lim = (-2, 2)
size = 1_000

hist = ap.Hist2d(
    *np.histogram2d(*rng.normal(size=(2, size)), range=(lim, lim)),
    xlabel="X Label",
    ylabel="Y Label",
    zlabel="Intensity",
)

fig, axs = plt.subplots(ncols=2, layout="compressed", figsize=(6.0, 3.0))

cmaps = "viridis", "cividis"

for ax, cmap in zip(axs, cmaps):
    ax.set_box_aspect(1)
    hist.plot(ax=ax, title=cmap, cmap=cmap)

(Source code, png, hires.png, pdf)

../_images/plot_in_axes1.png

Custom plotting methods#

It is possible to create a derived class inheriting from Hist1d or Hist2d, and implementing a custom plotting methods for these.

The following example showcases the perks of this approach. Note that the plotting method uses a custom layout engine (similar to tight_layout()) provided by mplutils.

import matplotlib.pyplot as plt
import mplutils as mplu

import atompy as ap

MAX_ENERGY = 25.0
MAX_MOMENTUM = 1.5


class EnergyHist1d(ap.Hist1d):
    def plot(self, ax):
        fig, ax = super().plot_step(ax=ax, start_at="auto")
        fig.set_layout_engine(mplu.FixedLayoutEngine())
        mplu.set_axes_size(3, aspect=1.0 / 1.618, ax=ax, anchor="W")
        ax.set_ylim(bottom=0)
        ax.set_xlim(self.limits[0], MAX_ENERGY)
        return fig, ax


class EnergyVsAngleHist(ap.Hist2d):
    def plot(self, ax):
        fig, ax, _ = super().plot(ax=ax, cmap="viridis")
        fig.set_layout_engine(mplu.FixedLayoutEngine())
        mplu.set_axes_size(3, aspect=1.0 / 1.618, ax=ax, anchor="W")
        ax.set_ylim(0, MAX_ENERGY)
        return fig, ax


class MomentumMap(ap.Hist2d):
    def plot(self, ax):
        fig, ax, _ = super().plot(ax=ax, cmap="atom")
        fig.set_layout_engine(mplu.FixedLayoutEngine())
        mplu.set_axes_size(3, ax=ax, anchor="W")
        ax.set_xlim(-MAX_MOMENTUM, MAX_MOMENTUM)
        ax.set_ylim(-MAX_MOMENTUM, MAX_MOMENTUM)
        return fig, ax


histos = []
fname = "example.root"

base = "He_Compton/electrons/momenta"
histos.append(MomentumMap.from_root(fname, f"{base}/px_vs_py"))
histos.append(MomentumMap.from_root(fname, f"{base}/px_vs_pz"))
histos.append(MomentumMap.from_root(fname, f"{base}/py_vs_pz"))
base = "He_Compton/electrons/energy"
histos.append(EnergyVsAngleHist.from_root(fname, f"{base}/phi_vs_electron_energy"))
histos.append(EnergyVsAngleHist.from_root(fname, f"{base}/ctheta_vs_electron_energy"))
histos.append(EnergyHist1d.from_root(fname, f"{base}/electron_energy"))

plt.style.use("atom")
fig, axs = plt.subplots(2, 3)

for histo, ax in zip(histos, axs.flat):
    histo.plot(ax)

plt.show()

(Source code, png, hires.png, pdf)

../_images/custom_plot_method.png