Scattering Angles from EOB Data¶
This tutorial demonstrates how to compute scattering angles from hyperbolic encounters using Effective One Body (EOB) waveforms.
In hyperbolic encounters, two compact objects approach each other with sufficient energy to scatter rather than merge. The scattering angle quantifies the deflection of the trajectory.
Setup¶
First, we import the necessary modules:
%matplotlib inline
%config InlineBackend.figure_format = 'retina'
import PyART.models.teob as teob
from PyART.analysis.scattering_angle import ScatteringAngle
import matplotlib.pyplot as plt
from PyART.utils.utils import D1
import numpy as np
Define Configurations¶
We’ll test several different impact parameters (b) to see how they affect the scattering angle. Each configuration has:
b: impact parameter
chi1, chi2: dimensionless spins
E0: initial energy
p: dimensionless momentum parameter
configurations = [
{'b': 9.678, 'chi1':0., 'chi2':0., 'E0':1.0226, 'p':0.11456439, 'eob':None, 'scat':None},
{'b':10.000, 'chi1':0., 'chi2':0., 'E0':1.0226, 'p':0.11456439, 'eob':None, 'scat':None},
{'b':11.000, 'chi1':0., 'chi2':0., 'E0':1.0226, 'p':0.11456439, 'eob':None, 'scat':None},
{'b':12.000, 'chi1':0., 'chi2':0., 'E0':1.0226, 'p':0.11456439, 'eob':None, 'scat':None},
{'b':13.000, 'chi1':0., 'chi2':0., 'E0':1.0226, 'p':0.11456439, 'eob':None, 'scat':None},
]
n_conf = len(configurations)
# Initial separation and symmetric mass ratio
r0 = 100
nu = 0.25
Generate EOB Data and Compute Scattering Angles¶
For each configuration, we:
Set up the EOB parameters
Generate the EOB waveform
Compute the scattering angle (if not a capture)
cutoff_min = 25
for i in range(n_conf):
conf = configurations[i]
J0 = conf['p']*conf['b']/nu
eobpars = teob.CreateDict(r_hyp=r0, H_hyp=conf['E0'], J_hyp=J0, q=1,
chi1z=conf['chi1'], chi2z=conf['chi2'])
eob = teob.Waveform_EOB(pars=eobpars)
conf['eob'] = eob
E_final = eob.dyn['E'][-1]
print(f"Configuration {i+1}:")
print(f" Impact parameter b = {conf['b']:.3f}")
print(f" E0, J0 = {conf['E0']:.5f}, {J0:.5f}")
print(f" Final energy = {E_final:.5f}")
if E_final > 1:
# Scattering event (not a capture)
scat = ScatteringAngle(puncts=eob.dyn, nmin=2, nmax=10, n_extract=None,
hypfit=True,
r_cutoff_in_low=cutoff_min, r_cutoff_in_high=eob.dyn['r'][0],
r_cutoff_out_low=cutoff_min, r_cutoff_out_high=None, verbose=False)
conf['scat'] = scat
print(f" Scattering angle χ = {scat.chi:.2f}°")
else:
print(' Result: Capture!')
print()
Configuration 1:
Impact parameter b = 9.678
E0, J0 = 1.02260, 4.43502
Final energy = 1.00007
Scattering angle χ = 402.33°
Configuration 2:
Impact parameter b = 10.000
E0, J0 = 1.02260, 4.58258
Final energy = 1.01214
Scattering angle χ = 252.82°
Configuration 3:
Impact parameter b = 11.000
E0, J0 = 1.02260, 5.04083
Final energy = 1.01960
Scattering angle χ = 157.45°
Configuration 4:
Impact parameter b = 12.000
E0, J0 = 1.02260, 5.49909
Final energy = 1.02121
Scattering angle χ = 122.41°
Configuration 5:
Impact parameter b = 13.000
E0, J0 = 1.02260, 5.95735
Final energy = 1.02181
Scattering angle χ = 102.21°
Visualize Results¶
Now let’s plot the results for all scattering configurations:
Real part of the (2,2) mode strain
The Weyl scalar ψ₄
Radial distance vs time
Trajectories in the x-y plane with scattering angles
plt.figure(figsize=(12,9))
for conf in configurations:
eob = conf['eob']
scat = conf['scat']
if scat is None:
continue
# Plot waveform
plt.subplot(2,2,1)
plt.plot(eob.u, eob.hlm[(2,2)]['real'])
plt.xlim([-100, 100])
plt.xlabel('Time (M)')
plt.ylabel(r'Re[$h_{22}$]')
plt.title('Waveform (2,2) mode')
plt.grid(True, alpha=0.3)
# Plot psi4
dh = D1(eob.hlm[(2,2)]['z'], eob.u, 4)
psi4 = D1(dh, eob.u, 4)
b = conf['b']
chi_BH = conf['chi1']
plt.subplot(2,2,2)
plt.plot(eob.u, -psi4.real, label=f'b={b:.3f}, χ={chi_BH}')
plt.xlim([-100, 100])
plt.xlabel('Time (M)')
plt.ylabel(r'Re[$-\psi_4$]')
plt.title('Weyl scalar')
plt.legend()
plt.grid(True, alpha=0.3)
# Plot radial distance
x = eob.dyn['r']*np.cos(eob.dyn['phi'])
y = eob.dyn['r']*np.sin(eob.dyn['phi'])
r = np.sqrt(x**2 + y**2)
plt.subplot(2,2,3)
plt.plot(eob.dyn['t'], r)
plt.xlabel('Time (M)')
plt.ylabel('Radial distance r (M)')
plt.title('Radial distance vs time')
plt.grid(True, alpha=0.3)
# Plot trajectory
plt.subplot(2,2,4)
plt.plot(x, y, label=f'χ={scat.chi:.2f}°')
plt.xlabel('x (M)')
plt.ylabel('y (M)')
plt.title('Trajectories with scattering angles')
plt.legend()
plt.grid(True, alpha=0.3)
plt.axis('equal')
plt.tight_layout()
plt.show()
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:258, in TexManager._run_checked_subprocess(cls, command, tex, cwd)
257 try:
--> 258 report = subprocess.check_output(
259 command, cwd=cwd if cwd is not None else cls._cache_dir,
260 stderr=subprocess.STDOUT)
261 except subprocess.CalledProcessError as exc:
File /opt/hostedtoolcache/Python/3.11.15/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.15/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.15/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.15/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[4], line 56
52 plt.legend()
53 plt.grid(True, alpha=0.3)
54 plt.axis('equal')
55
---> 56 plt.tight_layout()
57 plt.show()
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/pyplot.py:2992, in tight_layout(pad, h_pad, w_pad, rect)
2984 @_copy_docstring_and_deprecators(Figure.tight_layout)
2985 def tight_layout(
2986 *,
(...) 2990 rect: tuple[float, float, float, float] | None = None,
2991 ) -> None:
-> 2992 gcf().tight_layout(pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/figure.py:3665, in Figure.tight_layout(self, pad, h_pad, w_pad, rect)
3663 previous_engine = self.get_layout_engine()
3664 self.set_layout_engine(engine)
-> 3665 engine.execute(self)
3666 if previous_engine is not None and not isinstance(
3667 previous_engine, (TightLayoutEngine, PlaceHolderLayoutEngine)
3668 ):
3669 _api.warn_external('The figure layout has changed to tight')
File /opt/hostedtoolcache/Python/3.11.15/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.15/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.15/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.15/x64/lib/python3.11/site-packages/matplotlib/artist.py:1485, in _get_tightbbox_for_layout_only(obj, *args, **kwargs)
1479 """
1480 Matplotlib's `.Axes.get_tightbbox` and `.Axis.get_tightbbox` support a
1481 *for_layout_only* kwarg; this helper tries to use the kwarg but skips it
1482 when encountering third-party subclasses that do not support it.
1483 """
1484 try:
-> 1485 return obj.get_tightbbox(*args, **{**kwargs, "for_layout_only": True})
1486 except TypeError:
1487 return obj.get_tightbbox(*args, **kwargs)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axes/_base.py:4758, in _AxesBase.get_tightbbox(self, renderer, call_axes_locator, bbox_extra_artists, for_layout_only)
4756 if self.axison and axis.get_visible():
4757 if for_layout_only:
-> 4758 ba = martist._get_tightbbox_for_layout_only(axis, renderer)
4759 else:
4760 ba = axis.get_tightbbox(renderer)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/artist.py:1485, in _get_tightbbox_for_layout_only(obj, *args, **kwargs)
1479 """
1480 Matplotlib's `.Axes.get_tightbbox` and `.Axis.get_tightbbox` support a
1481 *for_layout_only* kwarg; this helper tries to use the kwarg but skips it
1482 when encountering third-party subclasses that do not support it.
1483 """
1484 try:
-> 1485 return obj.get_tightbbox(*args, **{**kwargs, "for_layout_only": True})
1486 except TypeError:
1487 return obj.get_tightbbox(*args, **kwargs)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:1427, in Axis.get_tightbbox(self, renderer, for_layout_only)
1424 renderer = self.get_figure(root=True)._get_renderer()
1425 ticks_to_draw = self._update_ticks()
-> 1427 self._update_label_position(renderer)
1429 # go back to just this axis's tick labels
1430 tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:2615, in XAxis._update_label_position(self, renderer)
2611 return
2613 # get bounding boxes for this axis and any siblings
2614 # that have been set by `fig.align_xlabels()`
-> 2615 bboxes, bboxes2 = self._get_tick_boxes_siblings(renderer=renderer)
2616 x, y = self.label.get_position()
2618 if self.label_position == 'bottom':
2619 # Union with extents of the bottom spine if present, of the axes otherwise.
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:2403, in Axis._get_tick_boxes_siblings(self, renderer)
2401 axis = ax._axis_map[name]
2402 ticks_to_draw = axis._update_ticks()
-> 2403 tlb, tlb2 = axis._get_ticklabel_bboxes(ticks_to_draw, renderer)
2404 bboxes.extend(tlb)
2405 bboxes2.extend(tlb2)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:1404, in Axis._get_ticklabel_bboxes(self, ticks, renderer)
1402 def _get_ticklabel_bboxes(self, ticks, renderer):
1403 """Return lists of bboxes for ticks' label1's and label2's."""
-> 1404 return ([tick.label1.get_window_extent(renderer)
1405 for tick in ticks
1406 if tick.label1.get_visible() and tick.label1.get_in_layout()],
1407 [tick.label2.get_window_extent(renderer)
1408 for tick in ticks
1409 if tick.label2.get_visible() and tick.label2.get_in_layout()])
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:1404, in <listcomp>(.0)
1402 def _get_ticklabel_bboxes(self, ticks, renderer):
1403 """Return lists of bboxes for ticks' label1's and label2's."""
-> 1404 return ([tick.label1.get_window_extent(renderer)
1405 for tick in ticks
1406 if tick.label1.get_visible() and tick.label1.get_in_layout()],
1407 [tick.label2.get_window_extent(renderer)
1408 for tick in ticks
1409 if tick.label2.get_visible() and tick.label2.get_in_layout()])
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/text.py:1076, in Text.get_window_extent(self, renderer, dpi)
1071 raise RuntimeError(
1072 "Cannot get window extent of text w/o renderer. You likely "
1073 "want to call 'figure.draw_without_rendering()' first.")
1075 with cbook._setattr_cm(fig, dpi=dpi):
-> 1076 bbox, _, _ = self._get_layout(self._renderer)
1077 x, y = self.get_unitless_position()
1078 x, y = self.get_transform().transform((x, y))
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/text.py:465, in Text._get_layout(self, renderer)
462 break
463 if None in (min_ascent, min_descent):
464 # Fallback to font measurement.
--> 465 _, h, min_descent = _get_text_metrics_with_cache(
466 renderer, "lp", self._fontproperties,
467 ismath="TeX" if self.get_usetex() else False,
468 dpi=dpi)
469 min_ascent = h - min_descent
470 line_gap = 0
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/text.py:59, in _get_text_metrics_with_cache(renderer, text, fontprop, ismath, dpi)
52 get_text_metrics = _get_text_metrics_function(renderer)
53 # call the function to compute the metrics and return
54 #
55 # We pass a copy of the fontprop because FontProperties is both mutable and
56 # has a `__hash__` that depends on that mutable state. This is not ideal
57 # as it means the hash of an object is not stable over time which leads to
58 # very confusing behavior when used as keys in dictionaries or hashes.
---> 59 return get_text_metrics(text, fontprop.copy(), ismath, dpi)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/text.py:125, in _get_text_metrics_function.<locals>._text_metrics(text, fontprop, ismath, dpi)
120 raise RuntimeError(
121 "Trying to get text metrics for a renderer that no longer exists. "
122 "This should never happen and is evidence of a bug elsewhere."
123 )
124 # do the actual method call we need and return the result
--> 125 return local_renderer.get_text_width_height_descent(text, fontprop, ismath)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/backends/backend_agg.py:256, in RendererAgg.get_text_width_height_descent(self, s, prop, ismath)
254 _api.check_in_list(["TeX", True, False], ismath=ismath)
255 if ismath == "TeX":
--> 256 return super().get_text_width_height_descent(s, prop, ismath)
258 if ismath:
259 parse = self.mathtext_parser.parse(s, self.dpi, prop)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/backend_bases.py:589, in RendererBase.get_text_width_height_descent(self, s, prop, ismath)
585 fontsize = prop.get_size_in_points()
587 if ismath == 'TeX':
588 # todo: handle properties
--> 589 return self.get_texmanager().get_text_width_height_descent(
590 s, fontsize, renderer=self)
592 dpi = self.points_to_pixels(72)
593 if ismath:
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:369, in TexManager.get_text_width_height_descent(cls, tex, fontsize, renderer)
367 if tex.strip() == '':
368 return 0, 0, 0
--> 369 dvipath = cls.make_dvi(tex, fontsize)
370 dpi_fraction = renderer.points_to_pixels(1.) if renderer else 1
371 with dviread.Dvi(dvipath, 72 * dpi_fraction) as dvi:
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:301, in TexManager.make_dvi(cls, tex, fontsize)
298 with TemporaryDirectory(dir=dvipath.parent) as tmpdir:
299 Path(tmpdir, "file.tex").write_text(
300 cls._get_tex_source(tex, fontsize), encoding='utf-8')
--> 301 cls._run_checked_subprocess(
302 ["latex", "-interaction=nonstopmode", "-halt-on-error",
303 "-no-shell-escape", "file.tex"], tex, cwd=tmpdir)
304 Path(tmpdir, "file.dvi").replace(dvipath)
305 # Also move the tex source to the main cache directory, but
306 # only for backcompat.
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:274, in TexManager._run_checked_subprocess(cls, command, tex, cwd)
262 raise RuntimeError(
263 '{prog} was not able to process the following string:\n'
264 '{tex!r}\n\n'
(...) 271 exc=exc.output.decode('utf-8', 'backslashreplace'))
272 ) from None
273 except (FileNotFoundError, OSError) as exc:
--> 274 raise RuntimeError(
275 f'Failed to process string with tex because {command[0]} '
276 'could not be found') from exc
277 _log.debug(report)
278 return report
RuntimeError: Failed to process string with tex because latex could not be found
Error in callback <function _draw_all_if_interactive at 0x7fc694f9f880> (for post_execute), with arguments args (),kwargs {}:
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:258, in TexManager._run_checked_subprocess(cls, command, tex, cwd)
257 try:
--> 258 report = subprocess.check_output(
259 command, cwd=cwd if cwd is not None else cls._cache_dir,
260 stderr=subprocess.STDOUT)
261 except subprocess.CalledProcessError as exc:
File /opt/hostedtoolcache/Python/3.11.15/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.15/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.15/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.15/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.15/x64/lib/python3.11/site-packages/matplotlib/pyplot.py:300, in _draw_all_if_interactive()
298 def _draw_all_if_interactive() -> None:
299 if matplotlib.is_interactive():
--> 300 draw_all()
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/_pylab_helpers.py:133, in Gcf.draw_all(cls, force)
131 for manager in cls.get_all_fig_managers():
132 if force or manager.canvas.figure.stale:
--> 133 manager.canvas.draw_idle()
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/backend_bases.py:1989, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
1987 if not self._is_idle_drawing:
1988 with self._idle_draw_cntx():
-> 1989 self.draw(*args, **kwargs)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/backends/backend_agg.py:438, in FigureCanvasAgg.draw(self)
435 # Acquire a lock on the shared font cache.
436 with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
437 else nullcontext()):
--> 438 self.figure.draw(self.renderer)
439 # A GUI class may be need to update a window using this draw, so
440 # don't forget to call the superclass.
441 super().draw()
File /opt/hostedtoolcache/Python/3.11.15/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.15/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.15/x64/lib/python3.11/site-packages/matplotlib/figure.py:3282, in Figure.draw(self, renderer)
3279 # ValueError can occur when resizing a window.
3281 self.patch.draw(renderer)
-> 3282 mimage._draw_list_compositing_images(
3283 renderer, self, artists, self.suppressComposite)
3285 renderer.close_group('figure')
3286 finally:
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/image.py:133, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
131 if not_composite or not has_images:
132 for a in artists:
--> 133 a.draw(renderer)
134 else:
135 # Composite any adjacent images together
136 image_group = []
File /opt/hostedtoolcache/Python/3.11.15/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.15/x64/lib/python3.11/site-packages/matplotlib/axes/_base.py:3331, in _AxesBase.draw(self, renderer)
3328 for spine in self.spines.values():
3329 artists.remove(spine)
-> 3331 self._update_title_position(renderer)
3333 if not self.axison:
3334 for _axis in self._axis_map.values():
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axes/_base.py:3270, in _AxesBase._update_title_position(self, renderer)
3268 if title.get_text():
3269 for ax in axs:
-> 3270 ax.yaxis.get_tightbbox(renderer) # update offsetText
3271 # A hidden offset text (e.g. on the shared y axis of an
3272 # inner subplot) is not drawn, so it must not move the
3273 # title: its tight bbox is non-finite and would otherwise
3274 # push the title to infinity.
3275 if (ax.yaxis.offsetText.get_visible()
3276 and ax.yaxis.offsetText.get_text()):
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:1427, in Axis.get_tightbbox(self, renderer, for_layout_only)
1424 renderer = self.get_figure(root=True)._get_renderer()
1425 ticks_to_draw = self._update_ticks()
-> 1427 self._update_label_position(renderer)
1429 # go back to just this axis's tick labels
1430 tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:2842, in YAxis._update_label_position(self, renderer)
2838 return
2840 # get bounding boxes for this axis and any siblings
2841 # that have been set by `fig.align_ylabels()`
-> 2842 bboxes, bboxes2 = self._get_tick_boxes_siblings(renderer=renderer)
2843 x, y = self.label.get_position()
2845 if self.label_position == 'left':
2846 # Union with extents of the left spine if present, of the axes otherwise.
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:2403, in Axis._get_tick_boxes_siblings(self, renderer)
2401 axis = ax._axis_map[name]
2402 ticks_to_draw = axis._update_ticks()
-> 2403 tlb, tlb2 = axis._get_ticklabel_bboxes(ticks_to_draw, renderer)
2404 bboxes.extend(tlb)
2405 bboxes2.extend(tlb2)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:1404, in Axis._get_ticklabel_bboxes(self, ticks, renderer)
1402 def _get_ticklabel_bboxes(self, ticks, renderer):
1403 """Return lists of bboxes for ticks' label1's and label2's."""
-> 1404 return ([tick.label1.get_window_extent(renderer)
1405 for tick in ticks
1406 if tick.label1.get_visible() and tick.label1.get_in_layout()],
1407 [tick.label2.get_window_extent(renderer)
1408 for tick in ticks
1409 if tick.label2.get_visible() and tick.label2.get_in_layout()])
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:1404, in <listcomp>(.0)
1402 def _get_ticklabel_bboxes(self, ticks, renderer):
1403 """Return lists of bboxes for ticks' label1's and label2's."""
-> 1404 return ([tick.label1.get_window_extent(renderer)
1405 for tick in ticks
1406 if tick.label1.get_visible() and tick.label1.get_in_layout()],
1407 [tick.label2.get_window_extent(renderer)
1408 for tick in ticks
1409 if tick.label2.get_visible() and tick.label2.get_in_layout()])
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/text.py:1076, in Text.get_window_extent(self, renderer, dpi)
1071 raise RuntimeError(
1072 "Cannot get window extent of text w/o renderer. You likely "
1073 "want to call 'figure.draw_without_rendering()' first.")
1075 with cbook._setattr_cm(fig, dpi=dpi):
-> 1076 bbox, _, _ = self._get_layout(self._renderer)
1077 x, y = self.get_unitless_position()
1078 x, y = self.get_transform().transform((x, y))
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/text.py:465, in Text._get_layout(self, renderer)
462 break
463 if None in (min_ascent, min_descent):
464 # Fallback to font measurement.
--> 465 _, h, min_descent = _get_text_metrics_with_cache(
466 renderer, "lp", self._fontproperties,
467 ismath="TeX" if self.get_usetex() else False,
468 dpi=dpi)
469 min_ascent = h - min_descent
470 line_gap = 0
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/text.py:59, in _get_text_metrics_with_cache(renderer, text, fontprop, ismath, dpi)
52 get_text_metrics = _get_text_metrics_function(renderer)
53 # call the function to compute the metrics and return
54 #
55 # We pass a copy of the fontprop because FontProperties is both mutable and
56 # has a `__hash__` that depends on that mutable state. This is not ideal
57 # as it means the hash of an object is not stable over time which leads to
58 # very confusing behavior when used as keys in dictionaries or hashes.
---> 59 return get_text_metrics(text, fontprop.copy(), ismath, dpi)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/text.py:125, in _get_text_metrics_function.<locals>._text_metrics(text, fontprop, ismath, dpi)
120 raise RuntimeError(
121 "Trying to get text metrics for a renderer that no longer exists. "
122 "This should never happen and is evidence of a bug elsewhere."
123 )
124 # do the actual method call we need and return the result
--> 125 return local_renderer.get_text_width_height_descent(text, fontprop, ismath)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/backends/backend_agg.py:256, in RendererAgg.get_text_width_height_descent(self, s, prop, ismath)
254 _api.check_in_list(["TeX", True, False], ismath=ismath)
255 if ismath == "TeX":
--> 256 return super().get_text_width_height_descent(s, prop, ismath)
258 if ismath:
259 parse = self.mathtext_parser.parse(s, self.dpi, prop)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/backend_bases.py:589, in RendererBase.get_text_width_height_descent(self, s, prop, ismath)
585 fontsize = prop.get_size_in_points()
587 if ismath == 'TeX':
588 # todo: handle properties
--> 589 return self.get_texmanager().get_text_width_height_descent(
590 s, fontsize, renderer=self)
592 dpi = self.points_to_pixels(72)
593 if ismath:
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:369, in TexManager.get_text_width_height_descent(cls, tex, fontsize, renderer)
367 if tex.strip() == '':
368 return 0, 0, 0
--> 369 dvipath = cls.make_dvi(tex, fontsize)
370 dpi_fraction = renderer.points_to_pixels(1.) if renderer else 1
371 with dviread.Dvi(dvipath, 72 * dpi_fraction) as dvi:
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:301, in TexManager.make_dvi(cls, tex, fontsize)
298 with TemporaryDirectory(dir=dvipath.parent) as tmpdir:
299 Path(tmpdir, "file.tex").write_text(
300 cls._get_tex_source(tex, fontsize), encoding='utf-8')
--> 301 cls._run_checked_subprocess(
302 ["latex", "-interaction=nonstopmode", "-halt-on-error",
303 "-no-shell-escape", "file.tex"], tex, cwd=tmpdir)
304 Path(tmpdir, "file.dvi").replace(dvipath)
305 # Also move the tex source to the main cache directory, but
306 # only for backcompat.
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:274, in TexManager._run_checked_subprocess(cls, command, tex, cwd)
262 raise RuntimeError(
263 '{prog} was not able to process the following string:\n'
264 '{tex!r}\n\n'
(...) 271 exc=exc.output.decode('utf-8', 'backslashreplace'))
272 ) from None
273 except (FileNotFoundError, OSError) as exc:
--> 274 raise RuntimeError(
275 f'Failed to process string with tex because {command[0]} '
276 'could not be found') from exc
277 _log.debug(report)
278 return report
RuntimeError: Failed to process string with tex because latex could not be found
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:258, in TexManager._run_checked_subprocess(cls, command, tex, cwd)
257 try:
--> 258 report = subprocess.check_output(
259 command, cwd=cwd if cwd is not None else cls._cache_dir,
260 stderr=subprocess.STDOUT)
261 except subprocess.CalledProcessError as exc:
File /opt/hostedtoolcache/Python/3.11.15/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.15/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.15/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.15/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.15/x64/lib/python3.11/site-packages/matplotlib/backend_bases.py:2257, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
2254 # we do this instead of `self.figure.draw_without_rendering`
2255 # so that we can inject the orientation
2256 with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2257 self.figure.draw(renderer)
2258 else:
2259 renderer = None
File /opt/hostedtoolcache/Python/3.11.15/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.15/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.15/x64/lib/python3.11/site-packages/matplotlib/figure.py:3282, in Figure.draw(self, renderer)
3279 # ValueError can occur when resizing a window.
3281 self.patch.draw(renderer)
-> 3282 mimage._draw_list_compositing_images(
3283 renderer, self, artists, self.suppressComposite)
3285 renderer.close_group('figure')
3286 finally:
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/image.py:133, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
131 if not_composite or not has_images:
132 for a in artists:
--> 133 a.draw(renderer)
134 else:
135 # Composite any adjacent images together
136 image_group = []
File /opt/hostedtoolcache/Python/3.11.15/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.15/x64/lib/python3.11/site-packages/matplotlib/axes/_base.py:3331, in _AxesBase.draw(self, renderer)
3328 for spine in self.spines.values():
3329 artists.remove(spine)
-> 3331 self._update_title_position(renderer)
3333 if not self.axison:
3334 for _axis in self._axis_map.values():
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axes/_base.py:3270, in _AxesBase._update_title_position(self, renderer)
3268 if title.get_text():
3269 for ax in axs:
-> 3270 ax.yaxis.get_tightbbox(renderer) # update offsetText
3271 # A hidden offset text (e.g. on the shared y axis of an
3272 # inner subplot) is not drawn, so it must not move the
3273 # title: its tight bbox is non-finite and would otherwise
3274 # push the title to infinity.
3275 if (ax.yaxis.offsetText.get_visible()
3276 and ax.yaxis.offsetText.get_text()):
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:1427, in Axis.get_tightbbox(self, renderer, for_layout_only)
1424 renderer = self.get_figure(root=True)._get_renderer()
1425 ticks_to_draw = self._update_ticks()
-> 1427 self._update_label_position(renderer)
1429 # go back to just this axis's tick labels
1430 tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:2842, in YAxis._update_label_position(self, renderer)
2838 return
2840 # get bounding boxes for this axis and any siblings
2841 # that have been set by `fig.align_ylabels()`
-> 2842 bboxes, bboxes2 = self._get_tick_boxes_siblings(renderer=renderer)
2843 x, y = self.label.get_position()
2845 if self.label_position == 'left':
2846 # Union with extents of the left spine if present, of the axes otherwise.
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:2403, in Axis._get_tick_boxes_siblings(self, renderer)
2401 axis = ax._axis_map[name]
2402 ticks_to_draw = axis._update_ticks()
-> 2403 tlb, tlb2 = axis._get_ticklabel_bboxes(ticks_to_draw, renderer)
2404 bboxes.extend(tlb)
2405 bboxes2.extend(tlb2)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:1404, in Axis._get_ticklabel_bboxes(self, ticks, renderer)
1402 def _get_ticklabel_bboxes(self, ticks, renderer):
1403 """Return lists of bboxes for ticks' label1's and label2's."""
-> 1404 return ([tick.label1.get_window_extent(renderer)
1405 for tick in ticks
1406 if tick.label1.get_visible() and tick.label1.get_in_layout()],
1407 [tick.label2.get_window_extent(renderer)
1408 for tick in ticks
1409 if tick.label2.get_visible() and tick.label2.get_in_layout()])
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/axis.py:1404, in <listcomp>(.0)
1402 def _get_ticklabel_bboxes(self, ticks, renderer):
1403 """Return lists of bboxes for ticks' label1's and label2's."""
-> 1404 return ([tick.label1.get_window_extent(renderer)
1405 for tick in ticks
1406 if tick.label1.get_visible() and tick.label1.get_in_layout()],
1407 [tick.label2.get_window_extent(renderer)
1408 for tick in ticks
1409 if tick.label2.get_visible() and tick.label2.get_in_layout()])
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/text.py:1076, in Text.get_window_extent(self, renderer, dpi)
1071 raise RuntimeError(
1072 "Cannot get window extent of text w/o renderer. You likely "
1073 "want to call 'figure.draw_without_rendering()' first.")
1075 with cbook._setattr_cm(fig, dpi=dpi):
-> 1076 bbox, _, _ = self._get_layout(self._renderer)
1077 x, y = self.get_unitless_position()
1078 x, y = self.get_transform().transform((x, y))
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/text.py:465, in Text._get_layout(self, renderer)
462 break
463 if None in (min_ascent, min_descent):
464 # Fallback to font measurement.
--> 465 _, h, min_descent = _get_text_metrics_with_cache(
466 renderer, "lp", self._fontproperties,
467 ismath="TeX" if self.get_usetex() else False,
468 dpi=dpi)
469 min_ascent = h - min_descent
470 line_gap = 0
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/text.py:59, in _get_text_metrics_with_cache(renderer, text, fontprop, ismath, dpi)
52 get_text_metrics = _get_text_metrics_function(renderer)
53 # call the function to compute the metrics and return
54 #
55 # We pass a copy of the fontprop because FontProperties is both mutable and
56 # has a `__hash__` that depends on that mutable state. This is not ideal
57 # as it means the hash of an object is not stable over time which leads to
58 # very confusing behavior when used as keys in dictionaries or hashes.
---> 59 return get_text_metrics(text, fontprop.copy(), ismath, dpi)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/text.py:125, in _get_text_metrics_function.<locals>._text_metrics(text, fontprop, ismath, dpi)
120 raise RuntimeError(
121 "Trying to get text metrics for a renderer that no longer exists. "
122 "This should never happen and is evidence of a bug elsewhere."
123 )
124 # do the actual method call we need and return the result
--> 125 return local_renderer.get_text_width_height_descent(text, fontprop, ismath)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/backends/backend_agg.py:256, in RendererAgg.get_text_width_height_descent(self, s, prop, ismath)
254 _api.check_in_list(["TeX", True, False], ismath=ismath)
255 if ismath == "TeX":
--> 256 return super().get_text_width_height_descent(s, prop, ismath)
258 if ismath:
259 parse = self.mathtext_parser.parse(s, self.dpi, prop)
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/backend_bases.py:589, in RendererBase.get_text_width_height_descent(self, s, prop, ismath)
585 fontsize = prop.get_size_in_points()
587 if ismath == 'TeX':
588 # todo: handle properties
--> 589 return self.get_texmanager().get_text_width_height_descent(
590 s, fontsize, renderer=self)
592 dpi = self.points_to_pixels(72)
593 if ismath:
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:369, in TexManager.get_text_width_height_descent(cls, tex, fontsize, renderer)
367 if tex.strip() == '':
368 return 0, 0, 0
--> 369 dvipath = cls.make_dvi(tex, fontsize)
370 dpi_fraction = renderer.points_to_pixels(1.) if renderer else 1
371 with dviread.Dvi(dvipath, 72 * dpi_fraction) as dvi:
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:301, in TexManager.make_dvi(cls, tex, fontsize)
298 with TemporaryDirectory(dir=dvipath.parent) as tmpdir:
299 Path(tmpdir, "file.tex").write_text(
300 cls._get_tex_source(tex, fontsize), encoding='utf-8')
--> 301 cls._run_checked_subprocess(
302 ["latex", "-interaction=nonstopmode", "-halt-on-error",
303 "-no-shell-escape", "file.tex"], tex, cwd=tmpdir)
304 Path(tmpdir, "file.dvi").replace(dvipath)
305 # Also move the tex source to the main cache directory, but
306 # only for backcompat.
File /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/matplotlib/texmanager.py:274, in TexManager._run_checked_subprocess(cls, command, tex, cwd)
262 raise RuntimeError(
263 '{prog} was not able to process the following string:\n'
264 '{tex!r}\n\n'
(...) 271 exc=exc.output.decode('utf-8', 'backslashreplace'))
272 ) from None
273 except (FileNotFoundError, OSError) as exc:
--> 274 raise RuntimeError(
275 f'Failed to process string with tex because {command[0]} '
276 'could not be found') from exc
277 _log.debug(report)
278 return report
RuntimeError: Failed to process string with tex because latex could not be found
<Figure size 1200x900 with 4 Axes>
Summary¶
This tutorial demonstrated:
How to set up hyperbolic encounter parameters
How to generate EOB waveforms for scattering scenarios
How to compute scattering angles using the
ScatteringAngleclassHow to visualize the waveforms and trajectories
The scattering angle provides important information about the dynamics of hyperbolic encounters and can be used to validate EOB models against numerical relativity simulations.