uclchem.plot ============ .. py:module:: uclchem.plot .. autoapi-nested-parse:: Visualization utilities for UCLCHEM model outputs. This module provides specialized plotting functions for visualizing chemical abundances and reaction rates from UCLCHEM models. **Key Functions:** - :func:`plot_rate_summary` - Visualize top production/destruction reactions - :func:`plot_species` - Plot species abundances over time - :func:`create_abundance_plot` - Create publication-ready abundance plots - :func:`draw_panel_abundances` - Draw species abundance panel (Panel A) - :func:`draw_panel_rates` - Draw production/destruction rate panel (Panel B) - :func:`draw_panel_rate_constants` - Draw mean rate-constant bar chart (Panel C) - :func:`plot_rates_deepdive` - Compose all three panels into a deepdive figure **Example Usage:** >>> import uclchem >>> >>> model = uclchem.model.Cloud({}) >>> model.check_error() Model ran successfully >>> >>> physics_df, chemistry_df, rate_constants_df = model.get_dataframes( ... with_rate_constants=True, ... joined=False, ... ) >>> # Making a plot of the abundances over time >>> fig, ax = uclchem.plot.create_abundance_plot( ... model.get_joined_dataframes(), # need both "Time" and abundance columns in one dataframe ... ["H", "$H", "H2O", "$H2O", "CH3OH", "$CH3OH"], ... ) >>> >>> # Making a plot of the main formation and destruction reactions >>> # at a specific timepoint >>> network = uclchem.makerates.network.Network.from_csv() >>> dy, reaction_rates = uclchem.analysis.rate_constants_to_dy_and_rates( ... physics_df, ... chemistry_df, ... rate_constants_df, ... network=network, ... ) >>> production_df, destruction_df = uclchem.analysis.get_production_and_destruction( ... "H2O", ... reaction_rates, ... ) >>> >>> # Plot top 5 reactions at a specific timestep >>> uclchem.plot.plot_rate_summary( ... production_df, ... destruction_df, ... step=50, ... top_k_rates=5 ... ) # doctest: +SKIP **Note:** Most plotting functionality is available through the model objects themselves via methods like :meth:`~uclchem.model.AbstractModel.create_abundance_plot`. **See Also:** - :mod:`uclchem.analysis` - Analysis tools that include plotting functions - :mod:`uclchem.model` - Model classes with built-in plotting methods Submodules ---------- .. toctree:: :titlesonly: :maxdepth: 1 compositions/index.rst panels/index.rst Package Contents ---------------- Functions ~~~~~~~~~ .. autoapisummary:: uclchem.plot.create_abundance_plot uclchem.plot.draw_panel_abundances uclchem.plot.draw_panel_rate_constants uclchem.plot.draw_panel_rates uclchem.plot.plot_rate_summary uclchem.plot.plot_rates_deepdive uclchem.plot.plot_species .. py:function:: create_abundance_plot(df: pandas.DataFrame, species: list[str], figsize: tuple[float, float] = (16, 9), plot_file: str | pathlib.Path | None = None, plot_kwargs: dict[str, Any] | None = None) -> tuple[matplotlib.pyplot.Figure, matplotlib.pyplot.Axes] Create a plot of the abundance of a list of species through time. :param df: Pandas dataframe containing the UCLCHEM output, see ``uclchem.analysis.read_output_file``, ``uclchem.model.load_model`` or ``uclchem.model.Model.get_dataframes``. :type df: pd.DataFrame :param species: list of strings containing species names. Using a $ instead of # or @ will plot the sum of surface and bulk abundances. :type species: list[str] :param figsize: Size of figure, width by height in inches. Defaults to (16, 9). :type figsize: tuple[float, float] :param plot_file: Path to file where figure will be saved. If None, figure is not saved. Defaults to None. :type plot_file: str | Path | None :param plot_kwargs: keyword arguments passed to ``ax.plot``. Default = None. :type plot_kwargs: dict[str, Any] | None :returns: * **fig** (*plt.Figure*) -- created Figure object * **ax** (*plt.Axes*) -- created axis object .. py:function:: draw_panel_abundances(ax: matplotlib.pyplot.Axes, time: pandas.Series, species: str, chem: pandas.DataFrame, companion: list[str] | None = None, *, reactant_species: set[str] | None = None, color_registry: dict[str, str] | None = None) -> matplotlib.pyplot.Axes Draw species abundances onto *ax* (Panel A of a deepdive figure). The target *species* is drawn in black at full weight. Each entry in *companion* is drawn in a tab20 color; species that appear in *reactant_species* get a thicker, more opaque line to signal their direct chemical involvement. :param ax: Axes to draw on. :type ax: plt.Axes :param time: Time series (years) for the x-axis. :type time: pd.Series :param species: UCLCHEM name of the primary species. :type species: str :param chem: Chemistry (abundance) DataFrame, already filtered to the desired time range. :type chem: pd.DataFrame :param companion: Additional species to overlay. Pass ``None`` (default) to show only *species*. :type companion: list[str] | None :param reactant_species: Species that appear as reactants in the top reactions; these are rendered with higher visual weight. Default: empty set. :type reactant_species: set[str] | None :param color_registry: Shared color map (species name → hex string). Pass the same dict to multiple panel calls to keep colors consistent. A fresh registry is created when ``None`` is passed. Default: ``None``. :type color_registry: dict[str, str] | None :returns: **ax** -- The modified axes. :rtype: plt.Axes .. py:function:: draw_panel_rate_constants(ax: matplotlib.pyplot.Axes, time: pandas.Series, prod_k: pandas.DataFrame, dest_k: pandas.DataFrame, top_prod: list[str] | None = None, top_dest: list[str] | None = None, *, top_k: int | None = 5, bar: bool = False, color_registry: dict[str, str] | None = None) -> matplotlib.pyplot.Axes Draw rate constants onto *ax* (Panel C of a deepdive figure). By default draws rate constants as time series so trends are visible. Pass ``bar=True`` for a mean bar chart; a warning is emitted for any reaction whose rate constant varies significantly over time (CV > 1 %). :param ax: Axes to draw on. :type ax: plt.Axes :param time: Time series (years) for the x-axis. :type time: pd.Series :param prod_k: Rate-constant DataFrame for production reactions, already filtered to the desired time range. :type prod_k: pd.DataFrame :param dest_k: Rate-constant DataFrame for destruction reactions. :type dest_k: pd.DataFrame :param top_prod: Reaction column names to include for production. When ``None``, the top *top_k* reactions by mean rate constant are selected. Default: ``None``. :type top_prod: list[str] | None :param top_dest: Reaction column names to include for destruction. When ``None``, the top *top_k* reactions by mean rate constant are selected. Default: ``None``. :type top_dest: list[str] | None :param top_k: Number of top reactions to show when *top_prod* / *top_dest* are ``None``. Pass ``None`` to show all. Default: 5. :type top_k: int | None :param bar: If ``True``, draw a mean bar chart instead of time series. Default: ``False``. :type bar: bool :param color_registry: Shared color map (reaction string → hex string). A fresh registry is created when ``None`` is passed. Default: ``None``. :type color_registry: dict[str, str] | None :returns: **ax** -- The modified axes. :rtype: plt.Axes .. py:function:: draw_panel_rates(ax: matplotlib.pyplot.Axes, time: pandas.Series, prod_rates: pandas.DataFrame, dest_rates: pandas.DataFrame, top_prod: list[str] | None = None, top_dest: list[str] | None = None, *, top_k: int | None = 5, color_registry: dict[str, str] | None = None) -> matplotlib.pyplot.Axes Draw production and destruction rates onto *ax* (Panel B of a deepdive figure). Total formation and destruction envelopes are always drawn in black. Reactions listed in *top_prod* / *top_dest* are drawn individually in tab20 colors; remaining reactions are summed into a gray "Other" line. :param ax: Axes to draw on. :type ax: plt.Axes :param time: Time series (years) for the x-axis. :type time: pd.Series :param prod_rates: Per-reaction production rates (abundance wrt H s⁻¹), already filtered to the desired time range. :type prod_rates: pd.DataFrame :param dest_rates: Per-reaction destruction rates (absolute values), already filtered. :type dest_rates: pd.DataFrame :param top_prod: Reaction column names to draw individually for production. When ``None``, the top *top_k* reactions by mean rate are selected. Default: ``None``. :type top_prod: list[str] | None :param top_dest: Reaction column names to draw individually for destruction. When ``None``, the top *top_k* reactions by mean rate are selected. Default: ``None``. :type top_dest: list[str] | None :param top_k: Number of top reactions to show individually when *top_prod* / *top_dest* are ``None``. Pass ``None`` to show all reactions. Default: 5. :type top_k: int | None :param color_registry: Shared color map (reaction string → hex string). Pass the same dict to multiple panel calls to keep colors consistent. A fresh registry is created when ``None`` is passed. Default: ``None``. :type color_registry: dict[str, str] | None :returns: **ax** -- The modified axes. :rtype: plt.Axes .. py:function:: plot_rate_summary(production_df: pandas.DataFrame, destruction_df: pandas.DataFrame, step: int, xlabel: str = 'Reaction rate (abundance wrt H / s)', top_k_rates: int = 5) -> list[matplotlib.pyplot.Axes] Create a summary of the top k production and destruction reactions. :param production_df: dataframe with reaction rates of formation reactions of species of interest :type production_df: pd.DataFrame :param destruction_df: dataframe with reaction rates of destruction reactions of species of interest :type destruction_df: pd.DataFrame :param step: time index of dataframes to plot. :type step: int :param xlabel: xlabel. Default: "Reaction rate (abundance wrt H / s)" :type xlabel: str :param top_k_rates: Plot top k formation and destruction reactions. Default: 5 :type top_k_rates: int :returns: **axs** -- axes of the plot :rtype: list[plt.Axes] .. py:function:: plot_rates_deepdive(species: str, physics_df: pandas.DataFrame, chemistry_df: pandas.DataFrame, rate_constants_df: pandas.DataFrame, network: uclchem.makerates.network.Network | None = None, *, filter_threshold: float = 0.01, filter_window: tuple[float, float] = (10000.0, 1000000.0), filter_freeze: bool = True, max_species_show: int = 12, figsize: tuple[float, float] = (8, 12), output_path: pathlib.Path | str | None = None, fig: matplotlib.figure.FigureBase | None = None, color_registry: dict[str, str] | None = None) -> tuple[matplotlib.figure.FigureBase, matplotlib.pyplot.Axes, matplotlib.pyplot.Axes, matplotlib.pyplot.Axes] Create a three-panel chemical deep-dive figure for *species*. **Panel A** (top): Abundances of *species* and the reactant species involved in its top production and destruction reactions. **Panel B** (bottom): Individual production (solid) and destruction (dashed) reaction rates, plus totals. **Panel C** (middle): Bar chart of mean rate constants for the top reactions, colored to match Panel B. :param species: UCLCHEM species name to analyze, e.g. ``"HCO+"``. :type species: str :param physics_df: Physics DataFrame from :meth:`~uclchem.model.AbstractModel.get_dataframes`. :type physics_df: pd.DataFrame :param chemistry_df: Chemistry (abundance) DataFrame. :type chemistry_df: pd.DataFrame :param rate_constants_df: Rate-constants DataFrame (``with_rate_constants=True``). :type rate_constants_df: pd.DataFrame :param network: Pre-loaded :class:`~uclchem.makerates.network.Network`. If ``None`` the default network is loaded via :meth:`~uclchem.makerates.network.Network.from_csv`. :type network: Network | None :param filter_threshold: Reactions whose rate never exceeds this fraction of the per-step maximum within *filter_window* are excluded. Default: ``0.01``. :type filter_threshold: float :param filter_window: ``(t_min, t_max)`` in years used for reaction filtering and ranking. Default: ``(1e4, 1e6)``. :type filter_window: tuple[float, float] :param filter_freeze: If ``True`` (default), exclude freeze-out reactions. :type filter_freeze: bool :param max_species_show: Maximum number of companion species to draw in Panel A. Default: ``12``. :type max_species_show: int :param figsize: Figure width × height in inches. Ignored when *fig* is provided. Default: ``(8, 12)``. :type figsize: tuple[float, float] :param output_path: If provided, save the figure as both ``.pdf`` and ``.png``. Only meaningful when *fig* is a top-level :class:`~matplotlib.figure.Figure`. Default: ``None``. :type output_path: Path | str | None :param fig: Existing figure or sub-figure to draw into. Pass a :class:`~matplotlib.figure.SubFigure` obtained from ``parent.subfigures()`` to embed this plot inside a larger layout. If ``None`` (default) a new figure is created. :type fig: matplotlib.figure.FigureBase | None :param color_registry: Mutable mapping from species / reaction name to hex color string. Pass the same dict to multiple calls to keep colors consistent across subfigures. If ``None`` (default) a fresh registry is created internally. :type color_registry: dict[str, str] | None :returns: * **fig** (*matplotlib.figure.FigureBase*) -- The figure (or sub-figure) containing all three panels. * **ax_abundances** (*plt.Axes*) -- Panel A — species abundances. * **ax_rates** (*plt.Axes*) -- Panel B — production / destruction rates. * **ax_rate_constants** (*plt.Axes*) -- Panel C — mean rate-constant bar chart. .. rubric:: Notes .. todo:: Return a ``pd.DataFrame`` of per-reaction rates at the final timestep so callers can export to CSV / Excel. .. py:function:: plot_species(ax: matplotlib.pyplot.Axes, df: pandas.DataFrame, species: list[str], legend: bool = True, plot_kwargs: dict[str, Any] | None = None) -> matplotlib.pyplot.Axes Plot the abundance of a list of species through time directly onto an axis. :param ax: An axis object to plot on :type ax: plt.Axes :param df: A dataframe created by ``uclchem.analysis.read_output_file``, ``uclchem.model.load_model`` or ``uclchem.model.Model.get_dataframes``. :type df: pd.DataFrame :param species: A list of species names to be plotted. If species name starts with "$" instead of "#" or "@", plots the sum of surface and bulk abundances :type species: list[str] :param legend: Whether to add a legend to the plot. Default = True. :type legend: bool :param plot_kwargs: keyword arguments passed to ``ax.plot``. Default = None. :type plot_kwargs: dict[str, Any] | None :returns: **ax** -- Modified input axis is returned :rtype: plt.Axes :raises KeyError: if no ``"Time"`` column is present in ``df``.