Module pychnosz.utils.expression
Expression utilities for formatted labels and text.
This module provides Python equivalents of the R functions in util.expression.R: - ratlab(): Create formatted text for activity ratios - expr_species(): Format chemical formula for display - syslab(): Create formatted text for thermodynamic systems
Author: CHNOSZ Python port
Functions
def add_legend(ax,
labels: list = None,
loc: str = 'best',
frameon: bool = False,
fontsize: float = 9,
**kwargs)-
Expand source code
def add_legend(ax, labels: list = None, loc: str = 'best', frameon: bool = False, fontsize: float = 9, **kwargs): """ Add a legend to a diagram with matplotlib or Plotly formatting. This is a convenience function that adds a legend with sensible defaults matching R CHNOSZ legend styling. Works with both matplotlib and Plotly figures. Parameters ---------- ax : matplotlib.axes.Axes or plotly.graph_objs.Figure Axes/Figure object to add legend to. For interactive diagrams, pass the figure from d['fig'] or d['ax']. labels : list of str Legend labels (can be from describe_property, describe_basis, etc.) loc : str, default 'best' Legend location. Options: 'best', 'upper left', 'upper right', 'lower left', 'lower right', 'right', 'center left', 'center right', 'lower center', 'upper center', 'center' For Plotly: 'best' defaults to 'lower right' frameon : bool, default False Whether to draw a frame around the legend (R bty="n" equivalent) fontsize : float, default 9 Font size for legend text (R cex=0.9 equivalent) **kwargs Additional arguments passed to matplotlib legend() or Plotly annotation Returns ------- matplotlib.legend.Legend or plotly.graph_objs.Figure The legend object (matplotlib) or the figure (Plotly) Examples -------- >>> from pychnosz.utils.expression import add_legend, describe_property >>> # Matplotlib diagram with plot_it=False >>> d1 = diagram(a, interactive=False, plot_it=False) >>> dprop = describe_property(["T", "P"], [300, 1000]) >>> add_legend(d1['ax'], dprop, loc='lower right') >>> # Display the figure in Jupyter: >>> from IPython.display import display >>> display(d1['fig']) >>> # Or save it: >>> d1['fig'].savefig('diagram.png') >>> # Plotly diagram >>> d1 = diagram(a, interactive=True, plot_it=False) >>> dprop = describe_property(["T", "P"], [300, 1000]) >>> add_legend(d1['fig'], dprop, loc='lower right') >>> d1['fig'].show() Notes ----- Common R legend locations and their matplotlib equivalents: - "bottomright" → "lower right" - "topleft" → "upper left" - "topright" → "upper right" - "bottomleft" → "lower left" When using plot_it=False, you need to explicitly display the figure after adding legends. In Jupyter notebooks, use display(d['fig']) or d['fig'].show() for Plotly diagrams. Outside Jupyter, use plt.show() or save with d['fig'].savefig(). """ if labels is None: raise ValueError("labels must be provided") # Detect if this is a Plotly figure is_plotly = _is_plotly_figure(ax) if is_plotly: return _add_plotly_legend(ax, labels, loc, frameon, fontsize, **kwargs) else: return _add_matplotlib_legend(ax, labels, loc, frameon, fontsize, **kwargs)Add a legend to a diagram with matplotlib or Plotly formatting.
This is a convenience function that adds a legend with sensible defaults matching R CHNOSZ legend styling. Works with both matplotlib and Plotly figures.
Parameters
ax:matplotlib.axes.Axesorplotly.graph_objs.Figure- Axes/Figure object to add legend to. For interactive diagrams, pass the figure from d['fig'] or d['ax'].
labels:listofstr- Legend labels (can be from describe_property, describe_basis, etc.)
loc:str, default'best'- Legend location. Options: 'best', 'upper left', 'upper right', 'lower left', 'lower right', 'right', 'center left', 'center right', 'lower center', 'upper center', 'center' For Plotly: 'best' defaults to 'lower right'
frameon:bool, defaultFalse- Whether to draw a frame around the legend (R bty="n" equivalent)
fontsize:float, default9- Font size for legend text (R cex=0.9 equivalent)
**kwargs- Additional arguments passed to matplotlib legend() or Plotly annotation
Returns
matplotlib.legend.Legendorplotly.graph_objs.Figure- The legend object (matplotlib) or the figure (Plotly)
Examples
>>> from pychnosz.utils.expression import add_legend, describe_property >>> # Matplotlib diagram with plot_it=False >>> d1 = diagram(a, interactive=False, plot_it=False) >>> dprop = describe_property(["T", "P"], [300, 1000]) >>> add_legend(d1['ax'], dprop, loc='lower right') >>> # Display the figure in Jupyter: >>> from IPython.display import display >>> display(d1['fig']) >>> # Or save it: >>> d1['fig'].savefig('diagram.png')>>> # Plotly diagram >>> d1 = diagram(a, interactive=True, plot_it=False) >>> dprop = describe_property(["T", "P"], [300, 1000]) >>> add_legend(d1['fig'], dprop, loc='lower right') >>> d1['fig'].show()Notes
Common R legend locations and their matplotlib equivalents: - "bottomright" → "lower right" - "topleft" → "upper left" - "topright" → "upper right" - "bottomleft" → "lower left"
When using plot_it=False, you need to explicitly display the figure after adding legends. In Jupyter notebooks, use display(d['fig']) or d['fig'].show() for Plotly diagrams. Outside Jupyter, use plt.show() or save with d['fig'].savefig().
def describe_basis(ibasis: list = None,
digits: int = 1,
oneline: bool = False,
molality: bool = False,
use_pH: bool = True) ‑> list-
Expand source code
def describe_basis(ibasis: list = None, digits: int = 1, oneline: bool = False, molality: bool = False, use_pH: bool = True) -> list: """ Create formatted text describing basis species activities/fugacities. This function generates formatted strings for displaying the chemical activities or fugacities of basis species, typically for plot legends. Parameters ---------- ibasis : list of int, optional Indices of basis species to describe (1-based). If None, describes all. digits : int, default 1 Number of decimal places to display oneline : bool, default False If True, combine all species on one line (not fully implemented) molality : bool, default False If True, use molality (m) instead of activity (a) use_pH : bool, default True If True, display H+ as pH instead of log a_H+ Returns ------- list of str Formatted basis species descriptions Examples -------- >>> from pychnosz.core.basis import basis >>> basis(["H2O", "H+", "O2"], [-10, -7, -80]) >>> describe_basis([2, 3]) ['pH = 7.0', 'log $f_{O_2}$ = -80.0'] >>> describe_basis() # All basis species ['log $a_{H_2O}$ = -10.0', 'pH = 7.0', 'log $f_{O_2}$ = -80.0'] Notes ----- This is used to create legend entries showing the basis species activities used in thermodynamic calculations. """ from ..core.basis import get_basis basis_df = get_basis() if basis_df is None: raise RuntimeError("Basis species are not defined") # Default to all basis species if ibasis is None: ibasis = list(range(1, len(basis_df) + 1)) # Convert to 0-based indexing ibasis_0 = [i - 1 for i in ibasis] descriptions = [] for i in ibasis_0: species_name = basis_df.index[i] state = basis_df.iloc[i]['state'] logact = basis_df.iloc[i]['logact'] # Check if logact is numeric try: logact_val = float(logact) is_numeric = True except (ValueError, TypeError): is_numeric = False if is_numeric: # Handle H+ specially with pH if species_name == "H+" and use_pH: pH_val = -logact_val val_formatted = format(round(pH_val, digits), f'.{digits}f') descriptions.append(f"pH = {val_formatted}") else: # Format the activity/fugacity val_formatted = format(round(logact_val, digits), f'.{digits}f') # Determine if it's activity or fugacity based on state if state in ['aq', 'liq', 'cr']: a_or_f = "a" if not molality else "m" else: a_or_f = "f" # Format the species name species_formatted = _format_species_latex(species_name) descriptions.append(f"log ${a_or_f}_{{{species_formatted}}}$ = {val_formatted}") else: # Non-numeric value (buffer) if species_name == "H+" and use_pH: descriptions.append(f"pH = {logact}") else: # For buffers, just show the buffer name if state in ['aq', 'liq', 'cr']: a_or_f = "a" if not molality else "m" else: a_or_f = "f" species_formatted = _format_species_latex(species_name) descriptions.append(f"${a_or_f}_{{{species_formatted}}}$ = {logact}") return descriptionsCreate formatted text describing basis species activities/fugacities.
This function generates formatted strings for displaying the chemical activities or fugacities of basis species, typically for plot legends.
Parameters
ibasis:listofint, optional- Indices of basis species to describe (1-based). If None, describes all.
digits:int, default1- Number of decimal places to display
oneline:bool, defaultFalse- If True, combine all species on one line (not fully implemented)
molality:bool, defaultFalse- If True, use molality (m) instead of activity (a)
use_pH:bool, defaultTrue- If True, display H+ as pH instead of log a_H+
Returns
listofstr- Formatted basis species descriptions
Examples
>>> from pychnosz.core.basis import basis >>> basis(["H2O", "H+", "O2"], [-10, -7, -80]) >>> describe_basis([2, 3]) ['pH = 7.0', 'log $f_{O_2}$ = -80.0']>>> describe_basis() # All basis species ['log $a_{H_2O}$ = -10.0', 'pH = 7.0', 'log $f_{O_2}$ = -80.0']Notes
This is used to create legend entries showing the basis species activities used in thermodynamic calculations.
def describe_basis_html(ibasis: list = None,
digits: int = 1,
oneline: bool = False,
molality: bool = False,
use_pH: bool = True) ‑> list-
Expand source code
def describe_basis_html(ibasis: list = None, digits: int = 1, oneline: bool = False, molality: bool = False, use_pH: bool = True) -> list: """ Create HTML-formatted text describing basis species (for Plotly). This function generates HTML-formatted strings for displaying the chemical activities or fugacities of basis species, typically for plot legends in interactive diagrams. Parameters ---------- ibasis : list of int, optional Indices of basis species to describe (1-based). If None, describes all. digits : int, default 1 Number of decimal places to display oneline : bool, default False If True, combine all species on one line (not fully implemented) molality : bool, default False If True, use molality (m) instead of activity (a) use_pH : bool, default True If True, display H+ as pH instead of log a_H+ Returns ------- list of str HTML-formatted basis species descriptions Examples -------- >>> from pychnosz.core.basis import basis >>> basis(["H2O", "H+", "O2"], [-10, -7, -80]) >>> describe_basis_html([2, 3]) ['pH = 7.0', 'log <i>f</i><sub>O<sub>2</sub></sub> = -80.0'] >>> describe_basis_html([4]) # CO2 ['log <i>f</i><sub>CO<sub>2</sub></sub> = -1.0'] Notes ----- Use this instead of describe_basis() when creating legends for interactive (Plotly) diagrams. """ if not _HTML_DEPS_AVAILABLE: raise ImportError( "describe_basis_html() requires 'WORMutils' package.\n" "Install with: pip install WORMutils" ) from ..core.basis import get_basis basis_df = get_basis() if basis_df is None: raise RuntimeError("Basis species are not defined") # Default to all basis species if ibasis is None: ibasis = list(range(1, len(basis_df) + 1)) # Convert to 0-based indexing ibasis_0 = [i - 1 for i in ibasis] descriptions = [] for i in ibasis_0: species_name = basis_df.index[i] state = basis_df.iloc[i]['state'] logact = basis_df.iloc[i]['logact'] # Check if logact is numeric try: logact_val = float(logact) is_numeric = True except (ValueError, TypeError): is_numeric = False if is_numeric: # Handle H+ specially with pH if species_name == "H+" and use_pH: pH_val = -logact_val val_formatted = format(round(pH_val, digits), f'.{digits}f') descriptions.append(f"pH = {val_formatted}") else: # Format the activity/fugacity val_formatted = format(round(logact_val, digits), f'.{digits}f') # Determine if it's activity or fugacity based on state if state in ['aq', 'liq', 'cr']: a_or_f = "a" if not molality else "m" else: a_or_f = "f" # Format the species name using HTML species_formatted = chemlabel(species_name) descriptions.append(f"log <i>{a_or_f}</i><sub>{species_formatted}</sub> = {val_formatted}") else: # Non-numeric value (buffer) if species_name == "H+" and use_pH: descriptions.append(f"pH = {logact}") else: # For buffers, just show the buffer name if state in ['aq', 'liq', 'cr']: a_or_f = "a" if not molality else "m" else: a_or_f = "f" species_formatted = chemlabel(species_name) descriptions.append(f"<i>{a_or_f}</i><sub>{species_formatted}</sub> = {logact}") return descriptionsCreate HTML-formatted text describing basis species (for Plotly).
This function generates HTML-formatted strings for displaying the chemical activities or fugacities of basis species, typically for plot legends in interactive diagrams.
Parameters
ibasis:listofint, optional- Indices of basis species to describe (1-based). If None, describes all.
digits:int, default1- Number of decimal places to display
oneline:bool, defaultFalse- If True, combine all species on one line (not fully implemented)
molality:bool, defaultFalse- If True, use molality (m) instead of activity (a)
use_pH:bool, defaultTrue- If True, display H+ as pH instead of log a_H+
Returns
listofstr- HTML-formatted basis species descriptions
Examples
>>> from pychnosz.core.basis import basis >>> basis(["H2O", "H+", "O2"], [-10, -7, -80]) >>> describe_basis_html([2, 3]) ['pH = 7.0', 'log <i>f</i><sub>O<sub>2</sub></sub> = -80.0']>>> describe_basis_html([4]) # CO2 ['log <i>f</i><sub>CO<sub>2</sub></sub> = -1.0']Notes
Use this instead of describe_basis() when creating legends for interactive (Plotly) diagrams.
def describe_property(property: list = None,
value: list = None,
digits: int = 0,
oneline: bool = False,
ret_val: bool = False) ‑> list-
Expand source code
def describe_property(property: list = None, value: list = None, digits: int = 0, oneline: bool = False, ret_val: bool = False) -> list: """ Create formatted text describing thermodynamic properties and their values. This function generates formatted strings for displaying property-value pairs in legends, typically for temperature, pressure, and other conditions. Parameters ---------- property : list of str Property names (e.g., ["T", "P"]) value : list Property values (e.g., [300, 1000]) digits : int, default 0 Number of decimal places to display oneline : bool, default False If True, combine all properties on one line (not implemented) ret_val : bool, default False If True, return only values with units (not property names) Returns ------- list of str Formatted property descriptions Examples -------- >>> describe_property(["T", "P"], [300, 1000]) ['$T$ = 300 °C', '$P$ = 1000 bar'] >>> describe_property(["T"], [25], digits=1) ['$T$ = 25.0 °C'] Notes ----- This is used to create legend entries showing the conditions used in thermodynamic calculations. """ if property is None or value is None: raise ValueError("property or value is None") descriptions = [] for i in range(len(property)): prop = property[i] val = value[i] # Get property symbol if prop == "T": prop_str = "$T$" if val == "Psat" or val == "NA": val_str = "$P_{sat}$" else: val_formatted = format(round(float(val), digits), f'.{digits}f') val_str = f"{val_formatted} °C" elif prop == "P": prop_str = "$P$" if val == "Psat" or val == "NA": val_str = "$P_{sat}$" else: val_formatted = format(round(float(val), digits), f'.{digits}f') val_str = f"{val_formatted} bar" elif prop == "pH": prop_str = "pH" val_formatted = format(round(float(val), digits), f'.{digits}f') val_str = val_formatted elif prop == "Eh": prop_str = "Eh" val_formatted = format(round(float(val), digits), f'.{digits}f') val_str = f"{val_formatted} V" elif prop == "IS": prop_str = "$IS$" val_formatted = format(round(float(val), digits), f'.{digits}f') val_str = val_formatted else: prop_str = f"${prop}$" val_formatted = format(round(float(val), digits), f'.{digits}f') val_str = val_formatted if ret_val: descriptions.append(val_str) else: descriptions.append(f"{prop_str} = {val_str}") return descriptionsCreate formatted text describing thermodynamic properties and their values.
This function generates formatted strings for displaying property-value pairs in legends, typically for temperature, pressure, and other conditions.
Parameters
property:listofstr- Property names (e.g., ["T", "P"])
value:list- Property values (e.g., [300, 1000])
digits:int, default0- Number of decimal places to display
oneline:bool, defaultFalse- If True, combine all properties on one line (not implemented)
ret_val:bool, defaultFalse- If True, return only values with units (not property names)
Returns
listofstr- Formatted property descriptions
Examples
>>> describe_property(["T", "P"], [300, 1000]) ['$T$ = 300 °C', '$P$ = 1000 bar']>>> describe_property(["T"], [25], digits=1) ['$T$ = 25.0 °C']Notes
This is used to create legend entries showing the conditions used in thermodynamic calculations.
def describe_property_html(property: list = None,
value: list = None,
digits: int = 0,
oneline: bool = False,
ret_val: bool = False) ‑> list-
Expand source code
def describe_property_html(property: list = None, value: list = None, digits: int = 0, oneline: bool = False, ret_val: bool = False) -> list: """ Create HTML-formatted text describing thermodynamic properties (for Plotly). This function generates HTML-formatted strings for displaying thermodynamic properties and their values, typically for plot legends in interactive diagrams. Parameters ---------- property : list of str Property names (e.g., ["T", "P"]) value : list Property values digits : int, default 0 Number of decimal places to display oneline : bool, default False If True, format on one line (not implemented) ret_val : bool, default False If True, return only values without property names Returns ------- list of str HTML-formatted property descriptions Examples -------- >>> describe_property_html(["T", "P"], [300, 1000]) ['<i>T</i> = 300 °C', '<i>P</i> = 1000 bar'] Notes ----- Use this instead of describe_property() when creating legends for interactive (Plotly) diagrams. """ if property is None or value is None: raise ValueError("property or value is None") descriptions = [] for i in range(len(property)): prop = property[i] val = value[i] # Get property symbol (HTML format) if prop == "T": prop_str = "<i>T</i>" if val == "Psat" or val == "NA": val_str = "<i>P</i><sub>sat</sub>" else: val_formatted = format(round(float(val), digits), f'.{digits}f') val_str = f"{val_formatted} °C" elif prop == "P": prop_str = "<i>P</i>" if val == "Psat" or val == "NA": val_str = "<i>P</i><sub>sat</sub>" else: val_formatted = format(round(float(val), digits), f'.{digits}f') val_str = f"{val_formatted} bar" elif prop == "pH": prop_str = "pH" val_formatted = format(round(float(val), digits), f'.{digits}f') val_str = val_formatted elif prop == "Eh": prop_str = "Eh" val_formatted = format(round(float(val), digits), f'.{digits}f') val_str = f"{val_formatted} V" elif prop == "IS": prop_str = "<i>IS</i>" val_formatted = format(round(float(val), digits), f'.{digits}f') val_str = val_formatted else: prop_str = f"<i>{prop}</i>" val_formatted = format(round(float(val), digits), f'.{digits}f') val_str = val_formatted if ret_val: descriptions.append(val_str) else: descriptions.append(f"{prop_str} = {val_str}") return descriptionsCreate HTML-formatted text describing thermodynamic properties (for Plotly).
This function generates HTML-formatted strings for displaying thermodynamic properties and their values, typically for plot legends in interactive diagrams.
Parameters
property:listofstr- Property names (e.g., ["T", "P"])
value:list- Property values
digits:int, default0- Number of decimal places to display
oneline:bool, defaultFalse- If True, format on one line (not implemented)
ret_val:bool, defaultFalse- If True, return only values without property names
Returns
listofstr- HTML-formatted property descriptions
Examples
>>> describe_property_html(["T", "P"], [300, 1000]) ['<i>T</i> = 300 °C', '<i>P</i> = 1000 bar']Notes
Use this instead of describe_property() when creating legends for interactive (Plotly) diagrams.
def expr_species(formula: str, state: str | None = None, use_state: bool = False) ‑> str-
Expand source code
def expr_species(formula: str, state: Optional[str] = None, use_state: bool = False) -> str: """ Format a chemical species formula for display. This is a simplified version that returns LaTeX-formatted strings suitable for matplotlib. The R version returns plotmath expressions. Parameters ---------- formula : str Chemical formula state : str, optional Physical state (aq, cr, gas, liq) use_state : bool, default False Whether to include state in the formatted output Returns ------- str LaTeX-formatted formula string Examples -------- >>> expr_species("H2O") '$H_{2}O$' >>> expr_species("Ca+2") '$Ca^{2+}$' >>> expr_species("SO4-2") '$SO_{4}^{2-}$' """ formatted = _format_species_latex(formula) if use_state and state: # Add state subscript return f"${formatted}_{{{state}}}$" else: return f"${formatted}$"Format a chemical species formula for display.
This is a simplified version that returns LaTeX-formatted strings suitable for matplotlib. The R version returns plotmath expressions.
Parameters
formula:str- Chemical formula
state:str, optional- Physical state (aq, cr, gas, liq)
use_state:bool, defaultFalse- Whether to include state in the formatted output
Returns
str- LaTeX-formatted formula string
Examples
>>> expr_species("H2O") '$H_{2}O$'>>> expr_species("Ca+2") '$Ca^{2+}$'>>> expr_species("SO4-2") '$SO_{4}^{2-}$' def ratlab(top: str = 'K+',
bottom: str = 'H+',
molality: bool = False,
reverse_charge: bool = False) ‑> str-
Expand source code
def ratlab(top: str = "K+", bottom: str = "H+", molality: bool = False, reverse_charge: bool = False) -> str: """ Create formatted text label for activity ratio. This function generates a LaTeX-formatted string suitable for use as axis labels in matplotlib plots, showing the ratio of activities of two ions raised to appropriate powers based on their charges. Parameters ---------- top : str, default "K+" Chemical formula for the numerator ion bottom : str, default "H+" Chemical formula for the denominator ion molality : bool, default False If True, use 'm' (molality) instead of 'a' (activity) reverse_charge : bool, default False If True, reverse charge order in formatting (e.g., "Fe+3" becomes "Fe^{3+}") If False, keep original order (e.g., "Fe+3" becomes "Fe^{+3}") Returns ------- str LaTeX-formatted string for the activity ratio label Examples -------- >>> ratlab("K+", "H+") 'log($a_{K^{+}}$ / $a_{H^{+}}$)' >>> ratlab("Ca+2", "H+") 'log($a_{Ca^{+2}}$ / $a_{H^{+}}^{2}$)' >>> ratlab("Ca+2", "H+", reverse_charge=True) 'log($a_{Ca^{2+}}$ / $a_{H^{+}}^{2}$)' >>> ratlab("Mg+2", "Ca+2") 'log($a_{Mg^{+2}}$ / $a_{Ca^{+2}}$)' Notes ----- The exponents are determined by the charges of the ions to maintain charge balance in the ratio. For example, for Ca+2/H+, the H+ term is squared because Ca has a +2 charge. The output format is compatible with matplotlib's LaTeX rendering. In R CHNOSZ, this uses plotmath expressions; here we use LaTeX strings that matplotlib can render. """ # Get the charges of the ions makeup_top = makeup(top) makeup_bottom = makeup(bottom) Z_top = makeup_top.get('Z', 0) Z_bottom = makeup_bottom.get('Z', 0) # The exponents for charge balance # If top has charge +2 and bottom has +1, bottom gets exponent 2 exp_bottom = abs(Z_top) exp_top = abs(Z_bottom) # Format exponents (don't show if = 1) exp_top_str = "" if exp_top == 1 else f"^{{{int(exp_top)}}}" exp_bottom_str = "" if exp_bottom == 1 else f"^{{{int(exp_bottom)}}}" # Format the ion formulas for display top_formatted = _format_species_latex(top, reverse_charge=reverse_charge) bottom_formatted = _format_species_latex(bottom, reverse_charge=reverse_charge) # Choose activity or molality symbol a = "m" if molality else "a" # Build the expression # Format: log(a_top^exp / a_bottom^exp) numerator = f"${a}_{{{top_formatted}}}{exp_top_str}$" denominator = f"${a}_{{{bottom_formatted}}}{exp_bottom_str}$" label = f"log({numerator} / {denominator})" return labelCreate formatted text label for activity ratio.
This function generates a LaTeX-formatted string suitable for use as axis labels in matplotlib plots, showing the ratio of activities of two ions raised to appropriate powers based on their charges.
Parameters
top:str, default"K+"- Chemical formula for the numerator ion
bottom:str, default"H+"- Chemical formula for the denominator ion
molality:bool, defaultFalse- If True, use 'm' (molality) instead of 'a' (activity)
reverse_charge:bool, defaultFalse- If True, reverse charge order in formatting (e.g., "Fe+3" becomes "Fe^{3+}") If False, keep original order (e.g., "Fe+3" becomes "Fe^{+3}")
Returns
str- LaTeX-formatted string for the activity ratio label
Examples
>>> ratlab("K+", "H+") 'log($a_{K^{+}}$ / $a_{H^{+}}$)'>>> ratlab("Ca+2", "H+") 'log($a_{Ca^{+2}}$ / $a_{H^{+}}^{2}$)'>>> ratlab("Ca+2", "H+", reverse_charge=True) 'log($a_{Ca^{2+}}$ / $a_{H^{+}}^{2}$)'>>> ratlab("Mg+2", "Ca+2") 'log($a_{Mg^{+2}}$ / $a_{Ca^{+2}}$)'Notes
The exponents are determined by the charges of the ions to maintain charge balance in the ratio. For example, for Ca+2/H+, the H+ term is squared because Ca has a +2 charge.
The output format is compatible with matplotlib's LaTeX rendering. In R CHNOSZ, this uses plotmath expressions; here we use LaTeX strings that matplotlib can render.
def ratlab_html(top: str = 'K+', bottom: str = 'H+', molality: bool = False) ‑> str-
Expand source code
def ratlab_html(top: str = "K+", bottom: str = "H+", molality: bool = False) -> str: """ Create HTML-formatted text label for activity ratio (for Plotly/HTML rendering). This function generates an HTML-formatted string suitable for use with Plotly interactive plots, showing the ratio of activities of two ions raised to appropriate powers based on their charges. This is a companion function to ratlab() which produces LaTeX format for matplotlib. Use ratlab_html() when creating labels for diagram(..., interactive=True). Parameters ---------- top : str, default "K+" Chemical formula for the numerator ion bottom : str, default "H+" Chemical formula for the denominator ion molality : bool, default False If True, use 'm' (molality) instead of 'a' (activity) Returns ------- str HTML-formatted string for the activity ratio label Examples -------- >>> ratlab_html("K+", "H+") 'log(a<sub>K<sup>+</sup></sub>/a<sub>H<sup>+</sup></sub>)' >>> ratlab_html("Ca+2", "H+") 'log(a<sub>Ca<sup>2+</sup></sub>/a<sup>2</sup><sub>H<sup>+</sup></sub>)' >>> ratlab_html("Mg+2", "Ca+2") 'log(a<sub>Mg<sup>2+</sup></sub>/a<sub>Ca<sup>2+</sup></sub>)' Notes ----- The exponents are determined by the charges of the ions to maintain charge balance in the ratio. For example, for Ca+2/H+, the H+ term is squared because Ca has a +2 charge. The output format uses HTML tags (<sub>, <sup>) compatible with Plotly. For matplotlib plots with LaTeX rendering, use ratlab() instead. Requires: WORMutils (for chemlabel) and chemparse (for parse_formula) See Also -------- ratlab : LaTeX version for matplotlib """ if not _HTML_DEPS_AVAILABLE: raise ImportError( "ratlab_html() requires 'WORMutils' and 'chemparse' packages.\n" "Install with: pip install WORMutils chemparse" ) # Parse the formulas to get charges top_formula = parse_formula(top) if "+" in top_formula.keys(): top_charge = top_formula["+"] elif "-" in top_formula.keys(): top_charge = -top_formula["-"] else: raise ValueError("Cannot create an ion ratio involving one or more neutral species.") bottom_formula = parse_formula(bottom) if "+" in bottom_formula.keys(): bottom_charge = bottom_formula["+"] elif "-" in bottom_formula.keys(): bottom_charge = -bottom_formula["-"] else: raise ValueError("Cannot create an ion ratio involving one or more neutral species.") # Convert to integers if whole numbers if top_charge.is_integer(): top_charge = int(top_charge) if bottom_charge.is_integer(): bottom_charge = int(bottom_charge) # The exponents for charge balance # If top has charge +2 and bottom has +1, bottom gets exponent 2 exp_bottom = abs(top_charge) exp_top = abs(bottom_charge) # Format exponents as superscripts (don't show if = 1) if exp_top != 1: top_exp_str = "<sup>" + str(exp_top) + "</sup>" else: top_exp_str = "" if exp_bottom != 1: bottom_exp_str = "<sup>" + str(exp_bottom) + "</sup>" else: bottom_exp_str = "" # Choose activity or molality symbol if molality: sym = "m" else: sym = "a" # Format the chemical formulas with chemlabel top_formatted = chemlabel(top) bottom_formatted = chemlabel(bottom) # Build the HTML expression # Format: log(a_top^exp / a_bottom^exp) return f"log({sym}{top_exp_str}<sub>{top_formatted}</sub>/{sym}{bottom_exp_str}<sub>{bottom_formatted}</sub>)"Create HTML-formatted text label for activity ratio (for Plotly/HTML rendering).
This function generates an HTML-formatted string suitable for use with Plotly interactive plots, showing the ratio of activities of two ions raised to appropriate powers based on their charges.
This is a companion function to ratlab() which produces LaTeX format for matplotlib. Use ratlab_html() when creating labels for diagram(…, interactive=True).
Parameters
top:str, default"K+"- Chemical formula for the numerator ion
bottom:str, default"H+"- Chemical formula for the denominator ion
molality:bool, defaultFalse- If True, use 'm' (molality) instead of 'a' (activity)
Returns
str- HTML-formatted string for the activity ratio label
Examples
>>> ratlab_html("K+", "H+") 'log(a<sub>K<sup>+</sup></sub>/a<sub>H<sup>+</sup></sub>)'>>> ratlab_html("Ca+2", "H+") 'log(a<sub>Ca<sup>2+</sup></sub>/a<sup>2</sup><sub>H<sup>+</sup></sub>)'>>> ratlab_html("Mg+2", "Ca+2") 'log(a<sub>Mg<sup>2+</sup></sub>/a<sub>Ca<sup>2+</sup></sub>)'Notes
The exponents are determined by the charges of the ions to maintain charge balance in the ratio. For example, for Ca+2/H+, the H+ term is squared because Ca has a +2 charge.
The output format uses HTML tags (, ) compatible with Plotly. For matplotlib plots with LaTeX rendering, use ratlab() instead.
Requires: WORMutils (for chemlabel) and chemparse (for parse_formula)
See Also
ratlab()- LaTeX version for matplotlib
def set_title(ax_or_fig, title: str, fontsize: float = 12, **kwargs)-
Expand source code
def set_title(ax_or_fig, title: str, fontsize: float = 12, **kwargs): """ Set title on a matplotlib axes or Plotly figure. This function provides a unified interface for setting titles on both matplotlib and Plotly plots, allowing seamless switching between interactive=True and interactive=False. Parameters ---------- ax_or_fig : matplotlib.axes.Axes or plotly.graph_objs.Figure Axes or Figure object to set title on title : str The title text fontsize : float, default 12 Font size for the title **kwargs Additional arguments passed to matplotlib set_title() or Plotly update_layout() Returns ------- matplotlib.text.Text or plotly.graph_objs.Figure The title object (matplotlib) or the figure (Plotly) Examples -------- >>> from pychnosz.utils.expression import set_title, syslab >>> # Matplotlib diagram >>> d1 = diagram(a, interactive=False, plot_it=False) >>> title_text = syslab(["H2O", "CO2", "CaO", "MgO", "SiO2"]) >>> set_title(d1['ax'], title_text, fontsize=12) >>> # Display the figure in Jupyter: >>> from IPython.display import display >>> display(d1['fig']) >>> # Plotly diagram >>> d1 = diagram(a, interactive=True, plot_it=False) >>> title_text = syslab_html(["H2O", "CO2", "CaO", "MgO", "SiO2"]) >>> set_title(d1['ax'], title_text, fontsize=12) >>> d1['fig'].show() Notes ----- When using plot_it=False, you need to explicitly display the figure after setting the title. In Jupyter notebooks, use display(d['fig']) or d['fig'].show() for Plotly diagrams. Outside Jupyter, use plt.show() or save with d['fig'].savefig(). """ is_plotly = _is_plotly_figure(ax_or_fig) if is_plotly: # Plotly figure title_dict = {'text': title, 'x': 0.5, 'xanchor': 'center'} if fontsize: title_dict['font'] = {'size': fontsize} ax_or_fig.update_layout(title=title_dict, **kwargs) return ax_or_fig else: # Matplotlib axes return ax_or_fig.set_title(title, fontsize=fontsize, **kwargs)Set title on a matplotlib axes or Plotly figure.
This function provides a unified interface for setting titles on both matplotlib and Plotly plots, allowing seamless switching between interactive=True and interactive=False.
Parameters
ax_or_fig:matplotlib.axes.Axesorplotly.graph_objs.Figure- Axes or Figure object to set title on
title:str- The title text
fontsize:float, default12- Font size for the title
**kwargs- Additional arguments passed to matplotlib set_title() or Plotly update_layout()
Returns
matplotlib.text.Textorplotly.graph_objs.Figure- The title object (matplotlib) or the figure (Plotly)
Examples
>>> from pychnosz.utils.expression import set_title, syslab >>> # Matplotlib diagram >>> d1 = diagram(a, interactive=False, plot_it=False) >>> title_text = syslab(["H2O", "CO2", "CaO", "MgO", "SiO2"]) >>> set_title(d1['ax'], title_text, fontsize=12) >>> # Display the figure in Jupyter: >>> from IPython.display import display >>> display(d1['fig'])>>> # Plotly diagram >>> d1 = diagram(a, interactive=True, plot_it=False) >>> title_text = syslab_html(["H2O", "CO2", "CaO", "MgO", "SiO2"]) >>> set_title(d1['ax'], title_text, fontsize=12) >>> d1['fig'].show()Notes
When using plot_it=False, you need to explicitly display the figure after setting the title. In Jupyter notebooks, use display(d['fig']) or d['fig'].show() for Plotly diagrams. Outside Jupyter, use plt.show() or save with d['fig'].savefig().
def syslab(system: list = None, dash: str = '-') ‑> str-
Expand source code
def syslab(system: list = None, dash: str = "-") -> str: """ Create formatted text for thermodynamic system. This generates a label showing the components of a thermodynamic system, separated by dashes (or other separator). Parameters ---------- system : list of str, optional List of component formulas. Default: ["K2O", "Al2O3", "SiO2", "H2O"] dash : str, default "-" Separator between components Returns ------- str LaTeX-formatted string for the system label Examples -------- >>> syslab(["K2O", "Al2O3", "SiO2", "H2O"]) '$K_{2}O-Al_{2}O_{3}-SiO_{2}-H_{2}O$' >>> syslab(["CaO", "MgO", "SiO2"], dash="–") '$CaO–MgO–SiO_{2}$' """ if system is None: system = ["K2O", "Al2O3", "SiO2", "H2O"] # Format each component formatted_components = [] for component in system: formatted = _add_subscripts(component) formatted_components.append(formatted) # Join with separator label = dash.join(formatted_components) # Wrap in LaTeX math mode return f"${label}$"Create formatted text for thermodynamic system.
This generates a label showing the components of a thermodynamic system, separated by dashes (or other separator).
Parameters
system:listofstr, optional- List of component formulas. Default: ["K2O", "Al2O3", "SiO2", "H2O"]
dash:str, default"-"- Separator between components
Returns
str- LaTeX-formatted string for the system label
Examples
>>> syslab(["K2O", "Al2O3", "SiO2", "H2O"]) '$K_{2}O-Al_{2}O_{3}-SiO_{2}-H_{2}O$'>>> syslab(["CaO", "MgO", "SiO2"], dash="–") '$CaO–MgO–SiO_{2}$' def syslab_html(system: list = None, dash: str = '-') ‑> str-
Expand source code
def syslab_html(system: list = None, dash: str = "-") -> str: """ Create HTML-formatted text for thermodynamic system (for Plotly). This generates a label showing the components of a thermodynamic system, separated by dashes (or other separator), using HTML formatting compatible with Plotly instead of LaTeX. Parameters ---------- system : list of str, optional List of component formulas. Default: ["K2O", "Al2O3", "SiO2", "H2O"] dash : str, default "-" Separator between components Returns ------- str HTML-formatted string for the system label Examples -------- >>> syslab_html(["K2O", "Al2O3", "SiO2", "H2O"]) 'K<sub>2</sub>O-Al<sub>2</sub>O<sub>3</sub>-SiO<sub>2</sub>-H<sub>2</sub>O' >>> syslab_html(["CaO", "MgO", "SiO2"], dash="–") 'CaO–MgO–SiO<sub>2</sub>' Notes ----- Use this function instead of syslab() when creating titles for interactive (Plotly) diagrams. The HTML formatting is compatible with Plotly's rendering. Requires: WORMutils (for chemlabel) """ if not _HTML_DEPS_AVAILABLE: raise ImportError( "syslab_html() requires 'WORMutils' package.\n" "Install with: pip install WORMutils" ) if system is None: system = ["K2O", "Al2O3", "SiO2", "H2O"] # Format each component using HTML via chemlabel formatted_components = [] for component in system: formatted = chemlabel(component) formatted_components.append(formatted) # Join with separator (no HTML wrapper needed) label = dash.join(formatted_components) return labelCreate HTML-formatted text for thermodynamic system (for Plotly).
This generates a label showing the components of a thermodynamic system, separated by dashes (or other separator), using HTML formatting compatible with Plotly instead of LaTeX.
Parameters
system:listofstr, optional- List of component formulas. Default: ["K2O", "Al2O3", "SiO2", "H2O"]
dash:str, default"-"- Separator between components
Returns
str- HTML-formatted string for the system label
Examples
>>> syslab_html(["K2O", "Al2O3", "SiO2", "H2O"]) 'K<sub>2</sub>O-Al<sub>2</sub>O<sub>3</sub>-SiO<sub>2</sub>-H<sub>2</sub>O'>>> syslab_html(["CaO", "MgO", "SiO2"], dash="–") 'CaO–MgO–SiO<sub>2</sub>'Notes
Use this function instead of syslab() when creating titles for interactive (Plotly) diagrams. The HTML formatting is compatible with Plotly's rendering.
Requires: WORMutils (for chemlabel)