Source code for cobra.summary.reaction_summary

"""Provide the reaction summary class."""


import logging
from textwrap import dedent, shorten
from typing import TYPE_CHECKING, Optional, Union

import pandas as pd

from cobra.flux_analysis import flux_variability_analysis, pfba
from cobra.summary import Summary


if TYPE_CHECKING:
    from cobra import Model, Reaction, Solution


[docs]logger = logging.getLogger(__name__)
[docs]class ReactionSummary(Summary): """ Define the reaction summary. See Also -------- Summary : Parent that defines further attributes. MetaboliteSummary ModelSummary """ def __init__( self, *, reaction: "Reaction", model: "Model", solution: Optional["Solution"] = None, fva: Optional[Union[float, pd.DataFrame]] = None, **kwargs, ) -> None: """ Initialize a reaction summary. Parameters ---------- reaction: cobra.Reaction The reaction object whose summary we intend to get. model : cobra.Model The metabolic model in which to generate a reaction summary. solution : cobra.Solution, optional A previous model solution to use for generating the summary. If ``None``, the summary method will generate a parsimonious flux distribution (default None). fva : pandas.DataFrame or float, optional Whether or not to include flux variability analysis in the output. If given, `fva` should either be a previous FVA solution matching the model or a float between 0 and 1 representing the fraction of the optimum objective to be searched (default None). Other Parameters ---------------- kwargs : Further keyword arguments are passed on to the parent class. See Also -------- Summary : Parent that has further default parameters. MetaboliteSummary ModelSummary """ super(ReactionSummary, self).__init__(**kwargs) self._reaction = reaction.copy() self._generate(model, solution, fva)
[docs] def _generate( self, model: "Model", solution: Optional["Solution"], fva: Optional[Union[float, pd.DataFrame]], ) -> None: """ Prepare the data for the summary instance. Parameters ---------- model : cobra.Model The metabolic model for which to generate a metabolite summary. solution : cobra.Solution, optional A previous model solution to use for generating the summary. If ``None``, the summary method will generate a parsimonious flux distribution. fva : pandas.DataFrame or float, optional Whether or not to include flux variability analysis in the output. If given, `fva` should either be a previous FVA solution matching the model or a float between 0 and 1 representing the fraction of the optimum objective to be searched. """ super()._generate(model=model, solution=solution, fva=fva) if solution is None: logger.info("Generating new parsimonious flux distribution.") solution = pfba(model) if isinstance(fva, float): logger.info("Performing flux variability analysis.") fva = flux_variability_analysis( model, reaction_list=[self._reaction], fraction_of_optimum=fva, ) # Create the basic flux table. self._flux = pd.DataFrame( data={"flux": [solution[self._reaction.id]]}, index=[self._reaction.id], ) if fva is not None: self._flux = self._flux.join(fva)
[docs] def _string_flux( self, threshold: float, float_format: str, ) -> str: """ Transform a flux data frame to a string. Parameters ---------- threshold : float Hide fluxes below the threshold from being displayed. float_format : str Format string for floats. Returns ------- str A string representation of the flux (with ranges). """ if "minimum" in self._flux.columns and "maximum" in self._flux.columns: frame = self._flux.loc[ (self._flux["flux"].abs() >= threshold) | (self._flux["minimum"].abs() >= threshold) | (self._flux["maximum"].abs() >= threshold), :, ].copy() return ( f"{frame.at[self._reaction.id, 'flux']:{float_format}} " f"[{frame.at[self._reaction.id, 'minimum']:{float_format}}; " f"{frame.at[self._reaction.id, 'maximum']:{float_format}}]" ) else: frame = self._flux.loc[self._flux["flux"].abs() >= threshold, :].copy() return f"{frame.at[self._reaction.id, 'flux']:{float_format}}"
[docs] def to_string( self, names: bool = False, threshold: Optional[float] = None, float_format: str = ".4G", column_width: int = 79, ) -> str: """ Return a pretty string representation of the reaction summary. Parameters ---------- names : bool, optional Whether or not elements should be displayed by their common names (default False). threshold : float, optional Hide fluxes below the threshold from being displayed. If no value is given, the model tolerance is used (default None). float_format : str, optional Format string for floats (default '.4G'). column_width : int, optional The maximum column width for each row (default 79). Returns ------- str The summary formatted as a pretty string. """ threshold = self._normalize_threshold(threshold) if names: header = shorten(self._reaction.name, width=column_width, placeholder="...") else: header = shorten(self._reaction.id, width=column_width, placeholder="...") flux = self._string_flux(threshold, float_format) return dedent( f""" {header} {'=' * len(header)} {self._reaction.build_reaction_string(use_metabolite_names=names)} Bounds: {self._reaction.lower_bound}, {self._reaction.upper_bound} Flux: {flux} """
)
[docs] def to_html( self, names: bool = False, threshold: Optional[float] = None, float_format: str = ".4G", ) -> str: """ Return a rich HTML representation of the reaction summary. Parameters ---------- names : bool, optional Whether or not elements should be displayed by their common names (default False). threshold : float, optional Hide fluxes below the threshold from being displayed. If no value is given, the model tolerance is used (default None). float_format : str, optional Format string for floats (default '.4G'). Returns ------- str The summary formatted as HTML. """ threshold = self._normalize_threshold(threshold) if names: header = self._reaction.name else: header = self._reaction.id flux = self._string_flux(threshold, float_format) return ( f"<h3>{header}</h3>"
f"<p>{self._reaction.build_reaction_string(use_metabolite_names=names)}</p>" f"<p>Bounds: {self._reaction.lower_bound}, {self._reaction.upper_bound}</p>" f"<p>Flux: {flux}</p>" )