Skip to content
ReEmission 1.0.0 documentation
⌘ K
ReEmission 1.0.0 documentation

Contents:

  • About the Library
  • Theoretical Background
  • Configuration
  • Installation
    • Installing RE-Emission
    • About Docker
    • Building the ReEmission Docker Image
    • Using the ReEmission Docker Image
  • Usage
  • Running the ReEmission Docker Container
  • Tutorials
  • Demo
  • JSON file format description
  • Configuration
  • Reporting Calculation Outputs
  • Visualisation
  • Integration with GeoCARET
  • Python API reference
    • Model (Main)
    • Input Model
    • Reservoir Model
    • Catchment Model
    • Post-impoundment catchment
    • Emissions
    • Emission Profile Calculator
    • MonthlyTemperature
    • Biogenic Factors
    • Presenter
    • Utility functions
    • Auxiliary functions
    • Constants
    • Mixins
    • Document \(\LaTeX\) Compiler
    • Custom Exceptions
    • App Logger
    • External Data Downloader
    • Global variables
    • Main
    • SALib Integration
    • Postprocessing
  • License
ReEmission 1.0.0 documentation
/
NOTE:

bdfc08b349cd4ca5861650da4c9d9291

Sensitivity Analysis and Probabilistic Estimation of Reservoir Emissions

This notebook demonstrates how to:

  1. Run parametric uncertainty analysis with SALib and the Sobol method

  2. Visualize the parametric sensitivity / uncertainty on various plots

  3. Compute the sensitivities across many scenarios (e.g. reservoirs)

  4. Present emission predictions as probability density plots

NOTE:

  • Requires SALib library - Python implementations of commonly used sensitivity analysis methods, including Sobol, Morris, and FAST methods - see: https://app.readthedocs.org/projects/salib/downloads/pdf/stable/

< Modifying Configuration Parametrers | Contents

Open in Colab

QUICK DESCRIPTION:

In this example, we leverage Re-Emission’s capability to dynamically alter its configuration parameters, such as emission model regression coefficients, pre-impoundment emissions or nutrient exports to perform sensitivity analysis and Monte-Carlo simulations of reservoir emissions under parametric uncertainties. The analysis is performed using Python’s SALib package. ReEmission’s salib module contains interfaces to SALib methods and functions allowing seamless integration with SALib enabling global sensitivity analysis to parametric uncertainties as well as input uncertainties.

This notebook performs a simple analysis to briefly demonstrate the capability of ReEmission’s salib module. For simplicity, it is restricted to testing model sensitivity to parametric uncertainties stemming from emission regression equations only. Sensitivity to other parametric uncertainties and to input uncertainties have not been investigated here.

[1]:
import pathlib
import os
from typing import List
from functools import partial
import gdown
from rich import print as rprint
%matplotlib inline
import matplotlib.pyplot as plt
try:
    import reemission
except ImportError:
    print("Unable to import reemission. Please ensure it is installed.")
    %pip install git+https://github.com/tomjanus/reemission.git --quiet
from reemission.salib.runners import SALibProblem, SobolAnalyser # type: ignore
from reemission.salib.wrappers import ReEmissionSALibWrapper # type: ignore
from reemission.salib.visualize import SobolResultVisualizer, SobolScenarioResultsVisualizer # type: ignore
from reemission.salib.specloaders import (
    ReEmissionSALibSpecLoader,
    set_unit_input_distribution_using_rel_diffrence)  # type: ignore
from reemission.input import Inputs  # type: ignore
from reemission.salib.runners import SobolResults, SobolScenarioResults  # type: ignore

# Constants
REL_DIFF = 0.1

# Get the directory where this notebook is located
notebook_dir = pathlib.Path().resolve()

# Define file paths relative to notebook location
inputs_file = notebook_dir / 'inputs_sensitivity_test.json'
spec_file = notebook_dir / 'uncertain_parameter_specification.yaml'

if not inputs_file.exists():
    # Download the required input file from an external link
    !gdown 1YHjA9HfulLV6wqwzryHZiFFc1kvXKFWL -O {str(inputs_file)}

if not spec_file.exists():
    # Download the required input file from an external link
    !gdown 1punHksgsZhj7Tq7IPPLCLqa0AHkDrLmx -O {str(spec_file)}

2. Sensitivity Analysis using Re-Emission

  • Confidence intervals for some parameters were derived from G-Res Tool Technical Documentation

[2]:

sc_results: List[SobolResults] = [] sc_names: List[str] = [] seed = 42 selected_reservoir_index = 1 # Run SOBOL analysis for a subset of UK reservoirs - can take a bit of time inputs = Inputs.fromfile("inputs_sensitivity_test.json") reservoirs_list_uk = list(inputs.inputs.keys()) rprint(f"Number of reservoirs: {len(reservoirs_list_uk)}") selected_reservoirs = reservoirs_list_uk[:] uk_input_file = pathlib.Path("inputs_sensitivity_test.json").resolve() spec_file = "uncertain_parameter_specification.yaml" inputs = Inputs.fromfile(uk_input_file) for res_no, reservoir in enumerate(selected_reservoirs): rprint(f"Running SOBOL analysis for reservoir: {reservoir} - {res_no + 1} out of {len(selected_reservoirs)}") selected_input = inputs.get_input(reservoir) # Use a single reservoir # Set the relative +/- difference for the inputs with missing distributions rel_difference: float = 0.1 # Load the SALib specification for the re-emission model reemission_salib_spec = ReEmissionSALibSpecLoader( spec_file=spec_file, input=selected_input, missing_input_dist_handler = partial( set_unit_input_distribution_using_rel_diffrence, rel_difference=rel_difference) ) # Var names for visualization var_names = reemission_salib_spec.var_name_map # Create a list of variables from the SALib specification reemission_variables = reemission_salib_spec.list_of_variables # Create a list of accessors from the SALib specification accessors = reemission_salib_spec.accessors reemission_salib_problem = SALibProblem.from_variables( reemission_variables ) reemission_salib_model = ReEmissionSALibWrapper.from_variables( variables = reemission_variables, input = selected_input, emission = 'total_net', accessors = accessors ) analyser = SobolAnalyser( problem = reemission_salib_problem, variables = reemission_variables, model = reemission_salib_model, num_samples = 512 ) sc_result = analyser.run_sobol() object.__setattr__(sc_result, 'nominal_output', sc_result.nominal_output[0]) sc_results.append(sc_result) sc_names.append(reservoir) sc_results = SobolScenarioResults( sc_names=sc_names, results=sc_results ) var_names = sc_results.var_names visualizer = SobolResultVisualizer( sc_results.results[selected_reservoir_index], par_name_map = var_names) scenario_visualizer = SobolScenarioResultsVisualizer(sc_results) fig, axes = plt.subplots(2, 2, figsize=(10, 8)) axes = axes.flatten() scenario_visualizer.plot_S1_ST( ax=axes[0], x_label_rotation = 90, title=f'Sobol Indices for regression coefficients') scenario_visualizer.plot_variance_contributions_by_group( ax=axes[1], title="Variance contributions by uncertainty group",) scenario_visualizer.plot_outputs_per_scenarios( ax=axes[2], #scenario_names = [f'{ix}' for ix in range(len(sc_results.scenario_names))], x_label_rotation = 90, sorting='desc', title="Total net emission predictions for multiple reservoirs", width=0.085, component_colors=['#ff7f0e', '#1f77b4', '#2ca02c', '#9467bd', '#d62728', '#8c564b']) visualizer.plot_output_kde( ax=axes[3], xlims=(-1400,-1000), title=f"Total net emissions under parameter uncertainty - {sc_names[selected_reservoir_index]}") fig.savefig(pathlib.Path('reemission_sobol_paper.png'))
Number of reservoirs: 5
Running SOBOL analysis for reservoir: Katrine - 1 out of 5
/opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/SALib/util/__init__.py:274: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  names = list(pd.unique(groups))
Running SOBOL analysis for reservoir: Black Esk - 2 out of 5
Running SOBOL analysis for reservoir: Whiteadder - 3 out of 5
Running SOBOL analysis for reservoir: St Mary's - 4 out of 5
Running SOBOL analysis for reservoir: Alaw - 5 out of 5
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:250, in TexManager._run_checked_subprocess(cls, command, tex, cwd)
    249 try:
--> 250     report = subprocess.check_output(
    251         command, cwd=cwd if cwd is not None else cls._texcache,
    252         stderr=subprocess.STDOUT)
    253 except FileNotFoundError as exc:

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/subprocess.py:466, in check_output(timeout, *popenargs, **kwargs)
    464     kwargs['input'] = empty
--> 466 return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
    467            **kwargs).stdout

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/subprocess.py:548, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    546     kwargs['stderr'] = PIPE
--> 548 with Popen(*popenargs, **kwargs) as process:
    549     try:

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/subprocess.py:1026, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize, process_group)
   1023             self.stderr = io.TextIOWrapper(self.stderr,
   1024                     encoding=encoding, errors=errors)
-> 1026     self._execute_child(args, executable, preexec_fn, close_fds,
   1027                         pass_fds, cwd, env,
   1028                         startupinfo, creationflags, shell,
   1029                         p2cread, p2cwrite,
   1030                         c2pread, c2pwrite,
   1031                         errread, errwrite,
   1032                         restore_signals,
   1033                         gid, gids, uid, umask,
   1034                         start_new_session, process_group)
   1035 except:
   1036     # Cleanup if the child failed starting.

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/subprocess.py:1955, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group)
   1954 if err_filename is not None:
-> 1955     raise child_exception_type(errno_num, err_msg, err_filename)
   1956 else:

FileNotFoundError: [Errno 2] No such file or directory: 'latex'

The above exception was the direct cause of the following exception:

RuntimeError                              Traceback (most recent call last)
Cell In[2], line 66
     64 fig, axes = plt.subplots(2, 2, figsize=(10, 8))
     65 axes = axes.flatten()
---> 66 scenario_visualizer.plot_S1_ST(
     67     ax=axes[0],
     68     x_label_rotation = 90,
     69     title=f'Sobol Indices for regression coefficients')
     71 scenario_visualizer.plot_variance_contributions_by_group(
     72     ax=axes[1],
     73     title="Variance contributions by uncertainty group",)
     75 scenario_visualizer.plot_outputs_per_scenarios(
     76     ax=axes[2],
     77     #scenario_names = [f'{ix}' for ix in range(len(sc_results.scenario_names))],
   (...)     81     width=0.085,
     82     component_colors=['#ff7f0e', '#1f77b4', '#2ca02c', '#9467bd', '#d62728', '#8c564b'])

File ~/work/reemission/reemission/src/reemission/salib/visualize.py:131, in SobolScenarioResultsVisualizer.plot_S1_ST(self, ax, title, x_label_rotation, confidence_level, tight_layout)
    129 ax.legend()
    130 if tight_layout:
--> 131     plt.tight_layout()
    132 return ax

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/pyplot.py:2844, in tight_layout(pad, h_pad, w_pad, rect)
   2836 @_copy_docstring_and_deprecators(Figure.tight_layout)
   2837 def tight_layout(
   2838     *,
   (...)   2842     rect: tuple[float, float, float, float] | None = None,
   2843 ) -> None:
-> 2844     gcf().tight_layout(pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/figure.py:3640, in Figure.tight_layout(self, pad, h_pad, w_pad, rect)
   3638 previous_engine = self.get_layout_engine()
   3639 self.set_layout_engine(engine)
-> 3640 engine.execute(self)
   3641 if previous_engine is not None and not isinstance(
   3642     previous_engine, (TightLayoutEngine, PlaceHolderLayoutEngine)
   3643 ):
   3644     _api.warn_external('The figure layout has changed to tight')

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/layout_engine.py:188, in TightLayoutEngine.execute(self, fig)
    186 renderer = fig._get_renderer()
    187 with getattr(renderer, "_draw_disabled", nullcontext)():
--> 188     kwargs = get_tight_layout_figure(
    189         fig, fig.axes, get_subplotspec_list(fig.axes), renderer,
    190         pad=info['pad'], h_pad=info['h_pad'], w_pad=info['w_pad'],
    191         rect=info['rect'])
    192 if kwargs:
    193     fig.subplots_adjust(**kwargs)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/_tight_layout.py:266, in get_tight_layout_figure(fig, axes_list, subplotspec_list, renderer, pad, h_pad, w_pad, rect)
    261         return {}
    262     span_pairs.append((
    263         slice(ss.rowspan.start * div_row, ss.rowspan.stop * div_row),
    264         slice(ss.colspan.start * div_col, ss.colspan.stop * div_col)))
--> 266 kwargs = _auto_adjust_subplotpars(fig, renderer,
    267                                   shape=(max_nrows, max_ncols),
    268                                   span_pairs=span_pairs,
    269                                   subplot_list=subplot_list,
    270                                   ax_bbox_list=ax_bbox_list,
    271                                   pad=pad, h_pad=h_pad, w_pad=w_pad)
    273 # kwargs can be none if tight_layout fails...
    274 if rect is not None and kwargs is not None:
    275     # if rect is given, the whole subplots area (including
    276     # labels) will fit into the rect instead of the
   (...)    280     # auto_adjust_subplotpars twice, where the second run
    281     # with adjusted rect parameters.

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/_tight_layout.py:82, in _auto_adjust_subplotpars(fig, renderer, shape, span_pairs, subplot_list, ax_bbox_list, pad, h_pad, w_pad, rect)
     80 for ax in subplots:
     81     if ax.get_visible():
---> 82         bb += [martist._get_tightbbox_for_layout_only(ax, renderer)]
     84 tight_bbox_raw = Bbox.union(bb)
     85 tight_bbox = fig.transFigure.inverted().transform_bbox(tight_bbox_raw)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/artist.py:1402, in _get_tightbbox_for_layout_only(obj, *args, **kwargs)
   1396 """
   1397 Matplotlib's `.Axes.get_tightbbox` and `.Axis.get_tightbbox` support a
   1398 *for_layout_only* kwarg; this helper tries to use the kwarg but skips it
   1399 when encountering third-party subclasses that do not support it.
   1400 """
   1401 try:
-> 1402     return obj.get_tightbbox(*args, **{**kwargs, "for_layout_only": True})
   1403 except TypeError:
   1404     return obj.get_tightbbox(*args, **kwargs)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/axes/_base.py:4564, in _AxesBase.get_tightbbox(self, renderer, call_axes_locator, bbox_extra_artists, for_layout_only)
   4562 for axis in self._axis_map.values():
   4563     if self.axison and axis.get_visible():
-> 4564         ba = martist._get_tightbbox_for_layout_only(axis, renderer)
   4565         if ba:
   4566             bb.append(ba)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/artist.py:1402, in _get_tightbbox_for_layout_only(obj, *args, **kwargs)
   1396 """
   1397 Matplotlib's `.Axes.get_tightbbox` and `.Axis.get_tightbbox` support a
   1398 *for_layout_only* kwarg; this helper tries to use the kwarg but skips it
   1399 when encountering third-party subclasses that do not support it.
   1400 """
   1401 try:
-> 1402     return obj.get_tightbbox(*args, **{**kwargs, "for_layout_only": True})
   1403 except TypeError:
   1404     return obj.get_tightbbox(*args, **kwargs)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/axis.py:1353, in Axis.get_tightbbox(self, renderer, for_layout_only)
   1350     renderer = self.get_figure(root=True)._get_renderer()
   1351 ticks_to_draw = self._update_ticks()
-> 1353 self._update_label_position(renderer)
   1355 # go back to just this axis's tick labels
   1356 tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/axis.py:2448, in XAxis._update_label_position(self, renderer)
   2444     return
   2446 # get bounding boxes for this axis and any siblings
   2447 # that have been set by `fig.align_xlabels()`
-> 2448 bboxes, bboxes2 = self._get_tick_boxes_siblings(renderer=renderer)
   2449 x, y = self.label.get_position()
   2451 if self.label_position == 'bottom':
   2452     # Union with extents of the bottom spine if present, of the axes otherwise.

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/axis.py:2241, in Axis._get_tick_boxes_siblings(self, renderer)
   2239 axis = ax._axis_map[name]
   2240 ticks_to_draw = axis._update_ticks()
-> 2241 tlb, tlb2 = axis._get_ticklabel_bboxes(ticks_to_draw, renderer)
   2242 bboxes.extend(tlb)
   2243 bboxes2.extend(tlb2)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/axis.py:1332, in Axis._get_ticklabel_bboxes(self, ticks, renderer)
   1330 if renderer is None:
   1331     renderer = self.get_figure(root=True)._get_renderer()
-> 1332 return ([tick.label1.get_window_extent(renderer)
   1333          for tick in ticks if tick.label1.get_visible()],
   1334         [tick.label2.get_window_extent(renderer)
   1335          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/axis.py:1332, in <listcomp>(.0)
   1330 if renderer is None:
   1331     renderer = self.get_figure(root=True)._get_renderer()
-> 1332 return ([tick.label1.get_window_extent(renderer)
   1333          for tick in ticks if tick.label1.get_visible()],
   1334         [tick.label2.get_window_extent(renderer)
   1335          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/text.py:969, in Text.get_window_extent(self, renderer, dpi)
    964     raise RuntimeError(
    965         "Cannot get window extent of text w/o renderer. You likely "
    966         "want to call 'figure.draw_without_rendering()' first.")
    968 with cbook._setattr_cm(fig, dpi=dpi):
--> 969     bbox, info, descent = self._get_layout(self._renderer)
    970     x, y = self.get_unitless_position()
    971     x, y = self.get_transform().transform((x, y))

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/text.py:373, in Text._get_layout(self, renderer)
    370 ys = []
    372 # Full vertical extent of font, including ascenders and descenders:
--> 373 _, lp_h, lp_d = _get_text_metrics_with_cache(
    374     renderer, "lp", self._fontproperties,
    375     ismath="TeX" if self.get_usetex() else False,
    376     dpi=self.get_figure(root=True).dpi)
    377 min_dy = (lp_h - lp_d) * self._linespacing
    379 for i, line in enumerate(lines):

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/text.py:69, in _get_text_metrics_with_cache(renderer, text, fontprop, ismath, dpi)
     66 """Call ``renderer.get_text_width_height_descent``, caching the results."""
     67 # Cached based on a copy of fontprop so that later in-place mutations of
     68 # the passed-in argument do not mess up the cache.
---> 69 return _get_text_metrics_with_cache_impl(
     70     weakref.ref(renderer), text, fontprop.copy(), ismath, dpi)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/text.py:77, in _get_text_metrics_with_cache_impl(renderer_ref, text, fontprop, ismath, dpi)
     73 @functools.lru_cache(4096)
     74 def _get_text_metrics_with_cache_impl(
     75         renderer_ref, text, fontprop, ismath, dpi):
     76     # dpi is unused, but participates in cache invalidation (via the renderer).
---> 77     return renderer_ref().get_text_width_height_descent(text, fontprop, ismath)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/backends/backend_agg.py:211, in RendererAgg.get_text_width_height_descent(self, s, prop, ismath)
    209 _api.check_in_list(["TeX", True, False], ismath=ismath)
    210 if ismath == "TeX":
--> 211     return super().get_text_width_height_descent(s, prop, ismath)
    213 if ismath:
    214     ox, oy, width, height, descent, font_image = \
    215         self.mathtext_parser.parse(s, self.dpi, prop)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/backend_bases.py:566, in RendererBase.get_text_width_height_descent(self, s, prop, ismath)
    562 fontsize = prop.get_size_in_points()
    564 if ismath == 'TeX':
    565     # todo: handle properties
--> 566     return self.get_texmanager().get_text_width_height_descent(
    567         s, fontsize, renderer=self)
    569 dpi = self.points_to_pixels(72)
    570 if ismath:

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:363, in TexManager.get_text_width_height_descent(cls, tex, fontsize, renderer)
    361 if tex.strip() == '':
    362     return 0, 0, 0
--> 363 dvifile = cls.make_dvi(tex, fontsize)
    364 dpi_fraction = renderer.points_to_pixels(1.) if renderer else 1
    365 with dviread.Dvi(dvifile, 72 * dpi_fraction) as dvi:

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:295, in TexManager.make_dvi(cls, tex, fontsize)
    293     with TemporaryDirectory(dir=cwd) as tmpdir:
    294         tmppath = Path(tmpdir)
--> 295         cls._run_checked_subprocess(
    296             ["latex", "-interaction=nonstopmode", "--halt-on-error",
    297              f"--output-directory={tmppath.name}",
    298              f"{texfile.name}"], tex, cwd=cwd)
    299         (tmppath / Path(dvifile).name).replace(dvifile)
    300 return dvifile

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:254, in TexManager._run_checked_subprocess(cls, command, tex, cwd)
    250     report = subprocess.check_output(
    251         command, cwd=cwd if cwd is not None else cls._texcache,
    252         stderr=subprocess.STDOUT)
    253 except FileNotFoundError as exc:
--> 254     raise RuntimeError(
    255         f'Failed to process string with tex because {command[0]} '
    256         'could not be found') from exc
    257 except subprocess.CalledProcessError as exc:
    258     raise RuntimeError(
    259         '{prog} was not able to process the following string:\n'
    260         '{tex!r}\n\n'
   (...)    267             exc=exc.output.decode('utf-8', 'backslashreplace'))
    268         ) from None

RuntimeError: Failed to process string with tex because latex could not be found
Error in callback <function _draw_all_if_interactive at 0x7f74ba828400> (for post_execute), with arguments args (),kwargs {}:
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:250, in TexManager._run_checked_subprocess(cls, command, tex, cwd)
    249 try:
--> 250     report = subprocess.check_output(
    251         command, cwd=cwd if cwd is not None else cls._texcache,
    252         stderr=subprocess.STDOUT)
    253 except FileNotFoundError as exc:

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/subprocess.py:466, in check_output(timeout, *popenargs, **kwargs)
    464     kwargs['input'] = empty
--> 466 return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
    467            **kwargs).stdout

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/subprocess.py:548, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    546     kwargs['stderr'] = PIPE
--> 548 with Popen(*popenargs, **kwargs) as process:
    549     try:

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/subprocess.py:1026, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize, process_group)
   1023             self.stderr = io.TextIOWrapper(self.stderr,
   1024                     encoding=encoding, errors=errors)
-> 1026     self._execute_child(args, executable, preexec_fn, close_fds,
   1027                         pass_fds, cwd, env,
   1028                         startupinfo, creationflags, shell,
   1029                         p2cread, p2cwrite,
   1030                         c2pread, c2pwrite,
   1031                         errread, errwrite,
   1032                         restore_signals,
   1033                         gid, gids, uid, umask,
   1034                         start_new_session, process_group)
   1035 except:
   1036     # Cleanup if the child failed starting.

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/subprocess.py:1955, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group)
   1954 if err_filename is not None:
-> 1955     raise child_exception_type(errno_num, err_msg, err_filename)
   1956 else:

FileNotFoundError: [Errno 2] No such file or directory: 'latex'

The above exception was the direct cause of the following exception:

RuntimeError                              Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/pyplot.py:279, in _draw_all_if_interactive()
    277 def _draw_all_if_interactive() -> None:
    278     if matplotlib.is_interactive():
--> 279         draw_all()

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/_pylab_helpers.py:131, in Gcf.draw_all(cls, force)
    129 for manager in cls.get_all_fig_managers():
    130     if force or manager.canvas.figure.stale:
--> 131         manager.canvas.draw_idle()

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/backend_bases.py:1893, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
   1891 if not self._is_idle_drawing:
   1892     with self._idle_draw_cntx():
-> 1893         self.draw(*args, **kwargs)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/backends/backend_agg.py:382, in FigureCanvasAgg.draw(self)
    379 # Acquire a lock on the shared font cache.
    380 with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
    381       else nullcontext()):
--> 382     self.figure.draw(self.renderer)
    383     # A GUI class may be need to update a window using this draw, so
    384     # don't forget to call the superclass.
    385     super().draw()

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/artist.py:94, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     92 @wraps(draw)
     93 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 94     result = draw(artist, renderer, *args, **kwargs)
     95     if renderer._rasterizing:
     96         renderer.stop_rasterizing()

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     68     if artist.get_agg_filter() is not None:
     69         renderer.start_filter()
---> 71     return draw(artist, renderer)
     72 finally:
     73     if artist.get_agg_filter() is not None:

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/figure.py:3257, in Figure.draw(self, renderer)
   3254             # ValueError can occur when resizing a window.
   3256     self.patch.draw(renderer)
-> 3257     mimage._draw_list_compositing_images(
   3258         renderer, self, artists, self.suppressComposite)
   3260     renderer.close_group('figure')
   3261 finally:

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/image.py:134, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    132 if not_composite or not has_images:
    133     for a in artists:
--> 134         a.draw(renderer)
    135 else:
    136     # Composite any adjacent images together
    137     image_group = []

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     68     if artist.get_agg_filter() is not None:
     69         renderer.start_filter()
---> 71     return draw(artist, renderer)
     72 finally:
     73     if artist.get_agg_filter() is not None:

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/axes/_base.py:3190, in _AxesBase.draw(self, renderer)
   3187     for spine in self.spines.values():
   3188         artists.remove(spine)
-> 3190 self._update_title_position(renderer)
   3192 if not self.axison:
   3193     for _axis in self._axis_map.values():

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/axes/_base.py:3134, in _AxesBase._update_title_position(self, renderer)
   3132 if title.get_text():
   3133     for ax in axs:
-> 3134         ax.yaxis.get_tightbbox(renderer)  # update offsetText
   3135         if ax.yaxis.offsetText.get_text():
   3136             bb = ax.yaxis.offsetText.get_tightbbox(renderer)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/axis.py:1353, in Axis.get_tightbbox(self, renderer, for_layout_only)
   1350     renderer = self.get_figure(root=True)._get_renderer()
   1351 ticks_to_draw = self._update_ticks()
-> 1353 self._update_label_position(renderer)
   1355 # go back to just this axis's tick labels
   1356 tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/axis.py:2675, in YAxis._update_label_position(self, renderer)
   2671     return
   2673 # get bounding boxes for this axis and any siblings
   2674 # that have been set by `fig.align_ylabels()`
-> 2675 bboxes, bboxes2 = self._get_tick_boxes_siblings(renderer=renderer)
   2676 x, y = self.label.get_position()
   2678 if self.label_position == 'left':
   2679     # Union with extents of the left spine if present, of the axes otherwise.

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/axis.py:2241, in Axis._get_tick_boxes_siblings(self, renderer)
   2239 axis = ax._axis_map[name]
   2240 ticks_to_draw = axis._update_ticks()
-> 2241 tlb, tlb2 = axis._get_ticklabel_bboxes(ticks_to_draw, renderer)
   2242 bboxes.extend(tlb)
   2243 bboxes2.extend(tlb2)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/axis.py:1332, in Axis._get_ticklabel_bboxes(self, ticks, renderer)
   1330 if renderer is None:
   1331     renderer = self.get_figure(root=True)._get_renderer()
-> 1332 return ([tick.label1.get_window_extent(renderer)
   1333          for tick in ticks if tick.label1.get_visible()],
   1334         [tick.label2.get_window_extent(renderer)
   1335          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/axis.py:1332, in <listcomp>(.0)
   1330 if renderer is None:
   1331     renderer = self.get_figure(root=True)._get_renderer()
-> 1332 return ([tick.label1.get_window_extent(renderer)
   1333          for tick in ticks if tick.label1.get_visible()],
   1334         [tick.label2.get_window_extent(renderer)
   1335          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/text.py:969, in Text.get_window_extent(self, renderer, dpi)
    964     raise RuntimeError(
    965         "Cannot get window extent of text w/o renderer. You likely "
    966         "want to call 'figure.draw_without_rendering()' first.")
    968 with cbook._setattr_cm(fig, dpi=dpi):
--> 969     bbox, info, descent = self._get_layout(self._renderer)
    970     x, y = self.get_unitless_position()
    971     x, y = self.get_transform().transform((x, y))

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/text.py:373, in Text._get_layout(self, renderer)
    370 ys = []
    372 # Full vertical extent of font, including ascenders and descenders:
--> 373 _, lp_h, lp_d = _get_text_metrics_with_cache(
    374     renderer, "lp", self._fontproperties,
    375     ismath="TeX" if self.get_usetex() else False,
    376     dpi=self.get_figure(root=True).dpi)
    377 min_dy = (lp_h - lp_d) * self._linespacing
    379 for i, line in enumerate(lines):

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/text.py:69, in _get_text_metrics_with_cache(renderer, text, fontprop, ismath, dpi)
     66 """Call ``renderer.get_text_width_height_descent``, caching the results."""
     67 # Cached based on a copy of fontprop so that later in-place mutations of
     68 # the passed-in argument do not mess up the cache.
---> 69 return _get_text_metrics_with_cache_impl(
     70     weakref.ref(renderer), text, fontprop.copy(), ismath, dpi)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/text.py:77, in _get_text_metrics_with_cache_impl(renderer_ref, text, fontprop, ismath, dpi)
     73 @functools.lru_cache(4096)
     74 def _get_text_metrics_with_cache_impl(
     75         renderer_ref, text, fontprop, ismath, dpi):
     76     # dpi is unused, but participates in cache invalidation (via the renderer).
---> 77     return renderer_ref().get_text_width_height_descent(text, fontprop, ismath)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/backends/backend_agg.py:211, in RendererAgg.get_text_width_height_descent(self, s, prop, ismath)
    209 _api.check_in_list(["TeX", True, False], ismath=ismath)
    210 if ismath == "TeX":
--> 211     return super().get_text_width_height_descent(s, prop, ismath)
    213 if ismath:
    214     ox, oy, width, height, descent, font_image = \
    215         self.mathtext_parser.parse(s, self.dpi, prop)

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/backend_bases.py:566, in RendererBase.get_text_width_height_descent(self, s, prop, ismath)
    562 fontsize = prop.get_size_in_points()
    564 if ismath == 'TeX':
    565     # todo: handle properties
--> 566     return self.get_texmanager().get_text_width_height_descent(
    567         s, fontsize, renderer=self)
    569 dpi = self.points_to_pixels(72)
    570 if ismath:

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:363, in TexManager.get_text_width_height_descent(cls, tex, fontsize, renderer)
    361 if tex.strip() == '':
    362     return 0, 0, 0
--> 363 dvifile = cls.make_dvi(tex, fontsize)
    364 dpi_fraction = renderer.points_to_pixels(1.) if renderer else 1
    365 with dviread.Dvi(dvifile, 72 * dpi_fraction) as dvi:

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:295, in TexManager.make_dvi(cls, tex, fontsize)
    293     with TemporaryDirectory(dir=cwd) as tmpdir:
    294         tmppath = Path(tmpdir)
--> 295         cls._run_checked_subprocess(
    296             ["latex", "-interaction=nonstopmode", "--halt-on-error",
    297              f"--output-directory={tmppath.name}",
    298              f"{texfile.name}"], tex, cwd=cwd)
    299         (tmppath / Path(dvifile).name).replace(dvifile)
    300 return dvifile

File /opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:254, in TexManager._run_checked_subprocess(cls, command, tex, cwd)
    250     report = subprocess.check_output(
    251         command, cwd=cwd if cwd is not None else cls._texcache,
    252         stderr=subprocess.STDOUT)
    253 except FileNotFoundError as exc:
--> 254     raise RuntimeError(
    255         f'Failed to process string with tex because {command[0]} '
    256         'could not be found') from exc
    257 except subprocess.CalledProcessError as exc:
    258     raise RuntimeError(
    259         '{prog} was not able to process the following string:\n'
    260         '{tex!r}\n\n'
   (...)    267             exc=exc.output.decode('utf-8', 'backslashreplace'))
    268         ) from None

RuntimeError: Failed to process string with tex because latex could not be found

Open in Colab

On this page

  • QUICK DESCRIPTION:
    • 2. Sensitivity Analysis using Re-Emission

© 2024, Tomasz Janus, University of Manchester, United Kingdom Built with Sphinx 8.1.3