Plotting heatmaps

The following specialized functions are available to generate heatmap plots from large parameter scans:

  • plot_tof – Turnover frequency of a gas-phase species

  • plot_dtof – Difference in TOF w.r.t. a reference scan (absolute or relative)

  • plot_selectivity – Selectivity (%) of a main product vs side products

  • plot_coverage – Coverage (%) of surface species on a site type (or total coverage)

  • plot_phasediagram – Dominant surface species phase map

  • plot_finaltime – Final simulated time (s)

  • plot_energyslope – Energy slope (|dE/d(step)| per area per step)

  • plot_issues – Yes/No map of runs with detected issues

Common parameters

These following parameters are available in most heatmap types:

  • ax (matplotlib.axes.Axes): Matplotlib axis to draw on.

  • x, y (str): Names of the scan dimensions. If the name contains "pressure", that axis is set to logarithmic scale and tick values are converted from log10 to absolute units for plotting.

  • scan_path (str): Path to the directory holding one subfolder per operating point.

  • cmap (str, optional): Matplotlib colormap name. Defaults vary by plot (see below).

  • show_points (bool, optional): Overlay white dots at each grid node (default = False).

  • show_colorbar (bool, optional): Draw a colorbar (default = True).

  • auto_title (bool, optional): Add title (default = False).

  • analysis_range (list[float], optional): Percentage window of the simulation data to analyze (default = [0, 100]).

  • range_type (str, optional): 'time' for simulated time windows or 'nevents' for number-of-events windows (default = 'time').

  • weights (str, optional): Averaging weights passed to KMCOutput. Possible values: 'time', 'events', or None (default = 'None').


TOF

Parameters specific to plot_tof:

  • gas_spec (str): Gas species key (e.g., 'H2', 'CO').

  • min_molec (int, optional): Minimum total production required for a valid TOF (default = 1).

  • levels (list or ndarray, optional): Contour levels to use in the plot.

  • show_max (bool, optional): Mark the global maximum with a golden * (default = False).

import numpy as np
import matplotlib.pyplot as plt
from zacrostools.heatmaps.tof import plot_tof

fig, axs = plt.subplots(1, figsize=(4.3, 3.5))
plot_tof(
    ax=axs,
    scan_path='simulation_results',
    x='pressure_CH4',
    y='pressure_CO2',
    gas_spec='H2',
    min_molec=0,
    analysis_range=[50, 100],
    range_type='time',
    levels=np.logspace(-1, 4, num=11),
    auto_title=True,
    show_points=False,
    show_colorbar=True
)
plt.tight_layout()
plt.savefig('tof_heatmap.png', dpi=300, bbox_inches='tight', transparent=False)
plt.show()
TOF heatmap

TOF difference

Parameters specific to plot_dtof:

  • difference_type (str):

    • 'absolute': ∆TOF = TOF(main) − TOF(ref)

    • 'relative': ∆TOF = (TOF(main) - TOF(ref)) / TOF(ref) * 100

    • 'ratio': ∆TOF = |TOF(main) / TOF(ref)|

  • scale (str, optional): 'log' uses LogNorm or 'lin' (only available for difference_type='absolute').

  • nlevels (int, optional): Number of discrete color levels.

  • min_tof_ref (float, optional): Mask cells whose reference TOF is below this threshold (default = 0).

  • check_issues (str, optional): run detect_issues on 'none', 'main', 'ref', or 'both'; flagged cells are masked.

import numpy as np
import matplotlib.pyplot as plt
from zacrostools.heatmaps.dtof import plot_dtof

fig, axs = plt.subplots(1, figsize=(4.3, 3.5))
plot_dtof(
    ax=axs,
    scan_path='simulation_results',
    scan_path_ref='simulation_results_reference',
    x='pressure_CH4',
    y='pressure_CO2',
    gas_spec='H2',
    difference_type='absolute',
    min_molec=0,
    analysis_range=[50, 100],
    range_type='time',
    levels=np.logspace(-1, 4, num=11),
    auto_title=True,
    show_points=False,
    show_colorbar=True
)
plt.tight_layout()
plt.savefig('dtof_heatmap.png', dpi=300, bbox_inches='tight', transparent=False)
plt.show()
∆TOF heatmap

Selectivity

Parameters specific to plot_selectivity:

  • main_product (str) and side_products (list[str], required).

  • min_molec (int, optional): Minimum combined production (main + sides) to accept the value (default = 0).

  • levels (list or ndarray, optional): Contour levels to use in the plot.

import matplotlib.pyplot as plt
from zacrostools.heatmaps.selectivity import plot_selectivity

fig, axs = plt.subplots(1, figsize=(4.3, 3.5))
plot_selectivity(
    ax=axs,
    scan_path='simulation_results',
    x='pressure_CH4',
    y='pressure_CO2',
    main_product='H2',
    side_products=['H2O'],
    min_molec=100,
    analysis_range=[50, 100],
    range_type='time',
    auto_title=True,
    show_points=False,
    show_colorbar=True
)
plt.tight_layout()
plt.savefig('selectivity_heatmap.png', dpi=300, bbox_inches='tight', transparent=False)
plt.show()
Selectivity heatmap

Coverage

Parameters specific to plot_coverage:

  • surf_spec (str or list): Surface species for which coverage is calculated. Use 'all' to plot total coverage.

  • site_type (str, optional): Site type to consider (default = 'StTp1').

import matplotlib.pyplot as plt
from zacrostools.heatmaps.coverage import plot_coverage

fig, axs = plt.subplots(1, figsize=(4.3, 3.5))
plot_coverage(
    ax=axs,
    scan_path='simulation_results',
    x='pressure_CH4',
    y='pressure_CO2',
    surf_spec='all',
    site_type='tC',
    analysis_range=[50, 100],
    range_type='time',
    weights='time',
    auto_title=True,
    show_points=False,
    show_colorbar=True
)
plt.tight_layout()
plt.savefig('coverage_heatmap.png', dpi=300, bbox_inches='tight', transparent=False)
plt.show()
Coverage heatmap

Phase diagram

Parameters specific to plot_phasediagram:

  • site_type (str, optional): Site type to consider (default = 'StTp1').

  • min_coverage (float or int, optional): Minimum total coverage (%) to consider a dominant species (default = 50.0).

  • tick_labels (dict or None, optional): Mapping of colorbar tick labels to lists of surface species.

import matplotlib.pyplot as plt
from zacrostools.heatmaps.phasediagram import plot_phasediagram

fig, axs = plt.subplots(1, figsize=(4.3, 3.5))
tick_labels = {  # for phase diagram plots
    '$CH_{x}$': ['CH3*', 'CH3_Pt*', 'CH2*', 'CH2_Pt*', 'CH*', 'CH_Pt*', 'C*', 'C_Pt*'],
    '$CHO/COH$': ['CHO*', 'CHO_Pt*', 'COH*', 'COH_Pt*'],
    '$CO$': ['CO*', 'CO_Pt*'],
    '$COOH$': ['COOH*', 'COOH_Pt*'],
    '$CO_{2}$': ['CO2*', 'CO2_Pt*'],
    '$H$': ['H*', 'H_Pt*'],
    '$H_{2}O$': ['H2O*', 'H2O_Pt*'],
    '$OH$': ['OH*', 'OH_Pt*'],
    '$O$': ['O*', 'O_Pt*'],
}
plot_phasediagram(
    ax=axs,
    scan_path='simulation_results',
    x='pressure_CH4',
    y='pressure_CO2',
    min_coverage=50.0,
    site_type='tC',
    tick_labels=tick_labels,
    analysis_range=[50, 100],
    range_type='time',
    weights='time',
    auto_title=True,
    show_points=False,
    show_colorbar=True
)
plt.tight_layout()
plt.savefig('phasediagram_heatmap.png', dpi=300, bbox_inches='tight', transparent=False)
plt.show()
Phase diagram heatmap

Final time

Parameters specific to plot_finaltime:

  • levels (list or ndarray, optional): Contour levels to use in the plot.

import numpy as np
import matplotlib.pyplot as plt
from zacrostools.heatmaps.finaltime import plot_finaltime

fig, axs = plt.subplots(1, figsize=(4.3, 3.5))
plot_finaltime(
    ax=axs,
    scan_path='simulation_results',
    x='pressure_CH4',
    y='pressure_CO2',
    levels=np.logspace(-5, 7, num=13),
    auto_title=True,
    show_points=False,
    show_colorbar=True
)
plt.tight_layout()
plt.savefig('finaltime_heatmap.png', dpi=300, bbox_inches='tight', transparent=False)
plt.show()
Final time heatmap

Energy slope

Parameters specific to plot_energyslope:

  • levels (list or ndarray, optional): Contour levels to use in the plot.

import matplotlib.pyplot as plt
from zacrostools.heatmaps.energyslope import plot_energyslope

fig, axs = plt.subplots(1, figsize=(4.3, 3.5))
plot_energyslope(
    ax=axs,
    scan_path='simulation_results',
    x='pressure_CH4',
    y='pressure_CO2',
    range_type='nevents',
    auto_title=True,
    show_points=False,
    show_colorbar=True
)
plt.tight_layout()
plt.savefig('energyslope_heatmap.png', dpi=300, bbox_inches='tight', transparent=False)
plt.show()
Energy slope heatmap

Issues

Parameters specific to plot_issues:

  • energy_slope_thr (float, optional): Absolute energy-slope threshold (default = 5.0e-10).

  • time_r2 (float, optional): Minimum acceptable R² for linearity of time vs events (default = 0.95).

  • max_points (int, optional): Maximum number of sampled points used inside detect_issues for the diagnostics (default = 100).

  • verbose (bool, optional): If True, prints paths of simulations with detected issues (default = False).

import matplotlib.pyplot as plt
from zacrostools.heatmaps.issues import plot_issues

fig, axs = plt.subplots(1, figsize=(4.3, 3.5))
plot_issues(
    ax=axs,
    scan_path='simulation_results',
    x='pressure_CH4',
    y='pressure_CO2',
    analysis_range=[50, 100],
    verbose=True,
    auto_title=True,
    show_points=False,
    show_colorbar=True
)
plt.tight_layout()
plt.savefig('issues_heatmap.png', dpi=300, bbox_inches='tight', transparent=False)
plt.show()
Issues heatmap

Building a multi-panel figure

You can combine multiple heatmaps into a single figure. Below is a compact example with 4 rows × 3 columns using a common scan and consistent analysis window.

import numpy as np
import matplotlib.pyplot as plt
from zacrostools.heatmaps.tof import plot_tof
from zacrostools.heatmaps.dtof import plot_dtof
from zacrostools.heatmaps.selectivity import plot_selectivity
from zacrostools.heatmaps.coverage import plot_coverage
from zacrostools.heatmaps.phasediagram import plot_phasediagram
from zacrostools.heatmaps.finaltime import plot_finaltime

# Plot parameters
scan_path = 'simulation_results'
x_variable = 'pressure_CH4'
y_variable = 'pressure_CO2'

analysis_range = [50, 100]      # Ignore first 50 % of total simulated time (equilibration)
range_type = 'time'
weights = 'time'

min_molec_tof = 0               # For TOF and selectivity
min_molec_selectivity = 100     # For TOF and selectivity
min_coverage = 50               # (in %) To plot phase diagrams

auto_title = True
show_points = False
show_colorbar = True

# Define labels for phase diagram heatmaps
tick_labels = { 
    '$CH_{x}$': ['CH3*', 'CH3_Pt*', 'CH2*', 'CH2_Pt*', 'CH*', 'CH_Pt*', 'C*', 'C_Pt*'],
    '$CHO/COH$': ['CHO*', 'CHO_Pt*', 'COH*', 'COH_Pt*'],
    '$CO$': ['CO*', 'CO_Pt*'],
    '$COOH$': ['COOH*', 'COOH_Pt*'],
    '$CO_{2}$': ['CO2*', 'CO2_Pt*'],
    '$H$': ['H*', 'H_Pt*'],
    '$H_{2}O$': ['H2O*', 'H2O_Pt*'],
    '$OH$': ['OH*', 'OH_Pt*'],
    '$O$': ['O*', 'O_Pt*'],
}

fig, axs = plt.subplots(4, 3, figsize=(8.8, 8), sharey='row', sharex='col')

for n, product in enumerate(['CO', 'H2', 'H2O']):
    plot_tof(
        ax=axs[0, n], scan_path=scan_path, x=x_variable, y=y_variable,
        gas_spec=product, min_molec=min_molec_tof,
        analysis_range=analysis_range, range_type=range_type, levels=np.logspace(-1, 4, num=11),
        auto_title=auto_title, show_points=show_points, show_colorbar=show_colorbar)

for n, site_type in enumerate(['tC', 'tM', 'Pt']):
    plot_coverage(
        ax=axs[1, n], scan_path=scan_path, x=x_variable, y=y_variable,
        surf_spec='all', site_type=site_type,
        analysis_range=analysis_range, range_type=range_type, weights=weights,
        auto_title=auto_title, show_points=show_points, show_colorbar=show_colorbar)

for n, site_type in enumerate(['tC', 'tM', 'Pt']):
    plot_phasediagram(
        ax=axs[2, n], scan_path=scan_path, x=x_variable, y=y_variable,
        min_coverage=min_coverage, site_type=site_type, tick_labels=tick_labels,
        analysis_range=analysis_range, range_type=range_type, weights=weights,
        auto_title=auto_title, show_points=show_points, show_colorbar=show_colorbar)

plot_selectivity(
    ax=axs[3, 0], scan_path=scan_path, x=x_variable, y=y_variable,
    main_product='H2', side_products=['H2O'], min_molec=min_molec_selectivity,
    analysis_range=analysis_range, range_type=range_type,
    auto_title=auto_title, show_points=show_points, show_colorbar=show_colorbar)

plot_finaltime(
    ax=axs[3, 1], scan_path=scan_path, x=x_variable, y=y_variable,
    levels=np.logspace(-7, 7, num=15), auto_title=auto_title, show_points=show_points, show_colorbar=show_colorbar)

plot_dtof(
    ax=axs[3, 2], scan_path=scan_path, x=x_variable, y=y_variable,
    scan_path_ref='simulation_results_reference', gas_spec='H2', min_molec=0, levels=np.logspace(-1, 4, num=11),
    analysis_range=analysis_range, range_type=range_type,
    auto_title=auto_title, show_points=show_points, show_colorbar=show_colorbar)

# Hide axis labels of intermediate subplots
for i in range(3):
    for j in range(3):
        axs[i, j].set_xlabel('')
for i in range(3):
    for j in range(1, 3):
        axs[i, j].set_ylabel('')

plt.tight_layout()
plt.savefig('multiple_heatmaps.png', dpi=300, bbox_inches='tight', transparent=False)
plt.show()

Multiple heatmaps

Customizing text sizes and colorbars

You can adjust tick sizes, label fonts, and title placement using standard Matplotlib APIs. Example for a single TOF subplot:

import numpy as np
import matplotlib.pyplot as plt
from zacrostools.heatmaps.tof import plot_tof

fig, axs = plt.subplots(1, figsize=(4.3, 3.5))
cp = plot_tof(
    ax=axs,
    scan_path='simulation_results',
    x='pressure_CH4',
    y='pressure_CO2',
    gas_spec='H2',
    min_molec=0,
    analysis_range=[50, 100],
    range_type='time',
    levels=np.logspace(-1, 4, num=11),
    auto_title=True,
    show_points=False,
    show_colorbar=False
)
# Adjust size of axis ticks
axs.tick_params(axis='both', which='major', labelsize=14)
# Adjust font size of axis labels
axs.set_xlabel(axs.get_xlabel(), fontsize=18)
axs.set_ylabel(axs.get_ylabel(), fontsize=18)
# Adjust font size and position of axis title
axs.set_title(axs.get_title(), fontsize=20, loc='center', pad=-170)
# Create colorbar and adjust the size of its tick labels
cbar = plt.colorbar(cp, ax=axs)
cbar.ax.tick_params(labelsize=14)

plt.tight_layout()
plt.savefig('tof_heatmap_custom.png', dpi=300, bbox_inches='tight', transparent=False)
plt.show()
TOF heatmap custom