Module 05 - project build an example

Hide code cell content
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
plt.style.use('fivethirtyeight')
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import fsolve
plt.style.use('fivethirtyeight')
from matplotlib import rc

plt.rc('text', usetex=True)
plt.rc('font', family='sans')

Module 05 - project build an example#

This is your chance to build something important to you and/or your career. If you’re interested in cars you can create a drivetrain model. If you want to get into biomechanics you can model an orthopedic joint or build a 2D model of someone walking. If you love toys (I know Prof. Cooper does!) you can model a yoyo spinning on a cord or a spinning top or measure the coefficient of restitution of a bouncy ball on concrete.

Some tips:

  • start simple its often easier to add complexity rather than remove complexity if you’re considering a 6-DOF system, try a 1-DOF part, then add components incrementally

  • use what you have you have working models for four-bar linkages, pendulums, and a yoyo despinning mechanism can you take your system and model a piece of it as a pendulum? is angular momentum conserved?

  • communicate let us know what you’re working on simple sketches are great! don’t get hung up on a final result until you have some sketches and conversations

  • always draw a FBD this step is so often skipped, but its really where the bulk of your engineering work is decided. The FBD is your main contribution to any engineering project, everything else is a combination of puzzle-solving and applied mathematics

l1 = 0.25 #m length of my forearm
l2 = 0.3 #m length of my bicep and shoulder
l3 = 0.55 #m length of both my forearm and bicep and shoulder
a1 = np.pi/2
dy = 0
dx = 0.41 #the measured distance between my two shoulders, meaning l1 and l3
Fbar = lambda a1,x: np.array([l1*np.sin(a1)+l2*np.sin(x[0])-l3*np.sin(x[1])-dy,
                           l1*np.cos(a1)+l2*np.cos(x[0])-l3*np.cos(x[1])-dx])
a1 = np.linspace(0, 2*np.pi)
a2 = np.zeros(len(a1))
a3 = np.zeros(len(a1))
xsol = np.array([0, np.pi/4])
for i in range(len(a1)):
    xsol = fsolve(lambda x: Fbar(a1[i], x), xsol)
    a2[i] = xsol[0]
    a3[i] = xsol[1]
plt.plot(a1, a2, label = r'$\theta_2$')
plt.plot(a1, a3, label = r'$\theta_3$')
plt.xlabel(r'$\theta_1$ (radian)')
plt.ylabel('output angle (radian)')
plt.legend();
#this looks like the swing I am trying to achieve since the links are limited in their range
/tmp/ipykernel_2178/2052099194.py:14: RuntimeWarning: The iteration is not making good progress, as measured by the 
  improvement from the last ten iterations.
  xsol = fsolve(lambda x: Fbar(a1[i], x), xsol)
/tmp/ipykernel_2178/2052099194.py:14: RuntimeWarning: The iteration is not making good progress, as measured by the 
  improvement from the last five Jacobian evaluations.
  xsol = fsolve(lambda x: Fbar(a1[i], x), xsol)
Error in callback <function _draw_all_if_interactive at 0x7f4f9db85280> (for post_execute), with arguments args (),kwargs {}:
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/subprocess.py:424, in check_output(timeout, *popenargs, **kwargs)
    422     kwargs['input'] = empty
--> 424 return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
    425            **kwargs).stdout

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:505, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    503     kwargs['stderr'] = PIPE
--> 505 with Popen(*popenargs, **kwargs) as process:
    506     try:

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:951, 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)
    948             self.stderr = io.TextIOWrapper(self.stderr,
    949                     encoding=encoding, errors=errors)
--> 951     self._execute_child(args, executable, preexec_fn, close_fds,
    952                         pass_fds, cwd, env,
    953                         startupinfo, creationflags, shell,
    954                         p2cread, p2cwrite,
    955                         c2pread, c2pwrite,
    956                         errread, errwrite,
    957                         restore_signals,
    958                         gid, gids, uid, umask,
    959                         start_new_session)
    960 except:
    961     # Cleanup if the child failed starting.

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:1837, 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)
   1836         err_msg = os.strerror(errno_num)
-> 1837     raise child_exception_type(errno_num, err_msg, err_filename)
   1838 raise child_exception_type(err_msg)

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.9.21/x64/lib/python3.9/site-packages/matplotlib/pyplot.py:268, in _draw_all_if_interactive()
    266 def _draw_all_if_interactive() -> None:
    267     if matplotlib.is_interactive():
--> 268         draw_all()

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/site-packages/matplotlib/backend_bases.py:1905, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
   1903 if not self._is_idle_drawing:
   1904     with self._idle_draw_cntx():
-> 1905         self.draw(*args, **kwargs)

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

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/figure.py:3162, in Figure.draw(self, renderer)
   3159             # ValueError can occur when resizing a window.
   3161     self.patch.draw(renderer)
-> 3162     mimage._draw_list_compositing_images(
   3163         renderer, self, artists, self.suppressComposite)
   3165     renderer.close_group('figure')
   3166 finally:

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axes/_base.py:3137, in _AxesBase.draw(self, renderer)
   3134 if artists_rasterized:
   3135     _draw_rasterized(self.figure, artists_rasterized, renderer)
-> 3137 mimage._draw_list_compositing_images(
   3138     renderer, self, artists, self.figure.suppressComposite)
   3140 renderer.close_group('axes')
   3141 self.stale = False

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1424, in Axis.draw(self, renderer)
   1421 renderer.open_group(__name__, gid=self.get_gid())
   1423 ticks_to_draw = self._update_ticks()
-> 1424 tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer)
   1426 for tick in ticks_to_draw:
   1427     tick.draw(renderer)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1351, in Axis._get_ticklabel_bboxes(self, ticks, renderer)
   1349 if renderer is None:
   1350     renderer = self.figure._get_renderer()
-> 1351 return ([tick.label1.get_window_extent(renderer)
   1352          for tick in ticks if tick.label1.get_visible()],
   1353         [tick.label2.get_window_extent(renderer)
   1354          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1351, in <listcomp>(.0)
   1349 if renderer is None:
   1350     renderer = self.figure._get_renderer()
-> 1351 return ([tick.label1.get_window_extent(renderer)
   1352          for tick in ticks if tick.label1.get_visible()],
   1353         [tick.label2.get_window_extent(renderer)
   1354          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/text.py:959, in Text.get_window_extent(self, renderer, dpi)
    954     raise RuntimeError(
    955         "Cannot get window extent of text w/o renderer. You likely "
    956         "want to call 'figure.draw_without_rendering()' first.")
    958 with cbook._setattr_cm(self.figure, dpi=dpi):
--> 959     bbox, info, descent = self._get_layout(self._renderer)
    960     x, y = self.get_unitless_position()
    961     x, y = self.get_transform().transform((x, y))

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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, dpi=self.figure.dpi)
    376 min_dy = (lp_h - lp_d) * self._linespacing
    378 for i, line in enumerate(lines):

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/site-packages/matplotlib/backends/backend_agg.py:212, in RendererAgg.get_text_width_height_descent(self, s, prop, ismath)
    210 _api.check_in_list(["TeX", True, False], ismath=ismath)
    211 if ismath == "TeX":
--> 212     return super().get_text_width_height_descent(s, prop, ismath)
    214 if ismath:
    215     ox, oy, width, height, descent, font_image = \
    216         self.mathtext_parser.parse(s, self.dpi, prop)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/backend_bases.py:597, in RendererBase.get_text_width_height_descent(self, s, prop, ismath)
    593 fontsize = prop.get_size_in_points()
    595 if ismath == 'TeX':
    596     # todo: handle properties
--> 597     return self.get_texmanager().get_text_width_height_descent(
    598         s, fontsize, renderer=self)
    600 dpi = self.points_to_pixels(72)
    601 if ismath:

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/subprocess.py:424, in check_output(timeout, *popenargs, **kwargs)
    422     kwargs['input'] = empty
--> 424 return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
    425            **kwargs).stdout

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:505, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    503     kwargs['stderr'] = PIPE
--> 505 with Popen(*popenargs, **kwargs) as process:
    506     try:

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:951, 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)
    948             self.stderr = io.TextIOWrapper(self.stderr,
    949                     encoding=encoding, errors=errors)
--> 951     self._execute_child(args, executable, preexec_fn, close_fds,
    952                         pass_fds, cwd, env,
    953                         startupinfo, creationflags, shell,
    954                         p2cread, p2cwrite,
    955                         c2pread, c2pwrite,
    956                         errread, errwrite,
    957                         restore_signals,
    958                         gid, gids, uid, umask,
    959                         start_new_session)
    960 except:
    961     # Cleanup if the child failed starting.

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:1837, 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)
   1836         err_msg = os.strerror(errno_num)
-> 1837     raise child_exception_type(errno_num, err_msg, err_filename)
   1838 raise child_exception_type(err_msg)

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.9.21/x64/lib/python3.9/site-packages/IPython/core/formatters.py:340, in BaseFormatter.__call__(self, obj)
    338     pass
    339 else:
--> 340     return printer(obj)
    341 # Finally look for special method names
    342 method = get_real_method(obj, self.print_method)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/IPython/core/pylabtools.py:152, in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    149     from matplotlib.backend_bases import FigureCanvasBase
    150     FigureCanvasBase(fig)
--> 152 fig.canvas.print_figure(bytes_io, **kw)
    153 data = bytes_io.getvalue()
    154 if fmt == 'svg':

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/backend_bases.py:2175, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2172     # we do this instead of `self.figure.draw_without_rendering`
   2173     # so that we can inject the orientation
   2174     with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2175         self.figure.draw(renderer)
   2176 if bbox_inches:
   2177     if bbox_inches == "tight":

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/figure.py:3162, in Figure.draw(self, renderer)
   3159             # ValueError can occur when resizing a window.
   3161     self.patch.draw(renderer)
-> 3162     mimage._draw_list_compositing_images(
   3163         renderer, self, artists, self.suppressComposite)
   3165     renderer.close_group('figure')
   3166 finally:

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axes/_base.py:3137, in _AxesBase.draw(self, renderer)
   3134 if artists_rasterized:
   3135     _draw_rasterized(self.figure, artists_rasterized, renderer)
-> 3137 mimage._draw_list_compositing_images(
   3138     renderer, self, artists, self.figure.suppressComposite)
   3140 renderer.close_group('axes')
   3141 self.stale = False

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1424, in Axis.draw(self, renderer)
   1421 renderer.open_group(__name__, gid=self.get_gid())
   1423 ticks_to_draw = self._update_ticks()
-> 1424 tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer)
   1426 for tick in ticks_to_draw:
   1427     tick.draw(renderer)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1351, in Axis._get_ticklabel_bboxes(self, ticks, renderer)
   1349 if renderer is None:
   1350     renderer = self.figure._get_renderer()
-> 1351 return ([tick.label1.get_window_extent(renderer)
   1352          for tick in ticks if tick.label1.get_visible()],
   1353         [tick.label2.get_window_extent(renderer)
   1354          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1351, in <listcomp>(.0)
   1349 if renderer is None:
   1350     renderer = self.figure._get_renderer()
-> 1351 return ([tick.label1.get_window_extent(renderer)
   1352          for tick in ticks if tick.label1.get_visible()],
   1353         [tick.label2.get_window_extent(renderer)
   1354          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/text.py:959, in Text.get_window_extent(self, renderer, dpi)
    954     raise RuntimeError(
    955         "Cannot get window extent of text w/o renderer. You likely "
    956         "want to call 'figure.draw_without_rendering()' first.")
    958 with cbook._setattr_cm(self.figure, dpi=dpi):
--> 959     bbox, info, descent = self._get_layout(self._renderer)
    960     x, y = self.get_unitless_position()
    961     x, y = self.get_transform().transform((x, y))

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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, dpi=self.figure.dpi)
    376 min_dy = (lp_h - lp_d) * self._linespacing
    378 for i, line in enumerate(lines):

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/site-packages/matplotlib/backends/backend_agg.py:212, in RendererAgg.get_text_width_height_descent(self, s, prop, ismath)
    210 _api.check_in_list(["TeX", True, False], ismath=ismath)
    211 if ismath == "TeX":
--> 212     return super().get_text_width_height_descent(s, prop, ismath)
    214 if ismath:
    215     ox, oy, width, height, descent, font_image = \
    216         self.mathtext_parser.parse(s, self.dpi, prop)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/backend_bases.py:597, in RendererBase.get_text_width_height_descent(self, s, prop, ismath)
    593 fontsize = prop.get_size_in_points()
    595 if ismath == 'TeX':
    596     # todo: handle properties
--> 597     return self.get_texmanager().get_text_width_height_descent(
    598         s, fontsize, renderer=self)
    600 dpi = self.points_to_pixels(72)
    601 if ismath:

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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
<Figure size 640x480 with 1 Axes>
rA = l1*np.vstack([np.cos(a1), np.sin(a1)])
rB = rA + l2*np.vstack([np.cos(a2), np.sin(a2)])
rC = rB - l3*np.vstack([np.cos(a3), np.sin(a3)])
rP = rA + l2/2*np.vstack([np.cos(a2), np.sin(a2)])
links_x_locations = np.vstack([np.zeros(len(a1)), 
                              rA[0, :],
                              rB[0, :],
                              rC[0, :]])
links_y_locations = np.vstack([np.zeros(len(a1)), 
                              rA[1, :],
                              rB[1, :],
                              rC[1, :]])
i = 10
plt.plot(links_x_locations[:, i], 
        links_y_locations[:, i], 'k-o')
plt.plot(rA[0,:], rA[1,:], label = 'hinge A')
plt.plot(rB[0,:], rB[1,:], label = 'hinge B')
plt.plot(rC[0,:], rC[1,:], label = 'hinge C')
plt.plot(rP[0,:], rP[1,:], label = 'midpoint AB')
plt.legend()
plt.title('Paths and orientation for\n'+ 
          r'$\theta_1$ = {:.1f}, $\theta_2$ = {:.1f}, $\theta_3$ = {:.1f}'.format(a1[i], a2[i], a3[i]))
plt.axis('equal');
Error in callback <function _draw_all_if_interactive at 0x7f4f9db85280> (for post_execute), with arguments args (),kwargs {}:
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/subprocess.py:424, in check_output(timeout, *popenargs, **kwargs)
    422     kwargs['input'] = empty
--> 424 return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
    425            **kwargs).stdout

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:505, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    503     kwargs['stderr'] = PIPE
--> 505 with Popen(*popenargs, **kwargs) as process:
    506     try:

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:951, 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)
    948             self.stderr = io.TextIOWrapper(self.stderr,
    949                     encoding=encoding, errors=errors)
--> 951     self._execute_child(args, executable, preexec_fn, close_fds,
    952                         pass_fds, cwd, env,
    953                         startupinfo, creationflags, shell,
    954                         p2cread, p2cwrite,
    955                         c2pread, c2pwrite,
    956                         errread, errwrite,
    957                         restore_signals,
    958                         gid, gids, uid, umask,
    959                         start_new_session)
    960 except:
    961     # Cleanup if the child failed starting.

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:1837, 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)
   1836         err_msg = os.strerror(errno_num)
-> 1837     raise child_exception_type(errno_num, err_msg, err_filename)
   1838 raise child_exception_type(err_msg)

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.9.21/x64/lib/python3.9/site-packages/matplotlib/pyplot.py:268, in _draw_all_if_interactive()
    266 def _draw_all_if_interactive() -> None:
    267     if matplotlib.is_interactive():
--> 268         draw_all()

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/site-packages/matplotlib/backend_bases.py:1905, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
   1903 if not self._is_idle_drawing:
   1904     with self._idle_draw_cntx():
-> 1905         self.draw(*args, **kwargs)

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

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/figure.py:3162, in Figure.draw(self, renderer)
   3159             # ValueError can occur when resizing a window.
   3161     self.patch.draw(renderer)
-> 3162     mimage._draw_list_compositing_images(
   3163         renderer, self, artists, self.suppressComposite)
   3165     renderer.close_group('figure')
   3166 finally:

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axes/_base.py:3101, in _AxesBase.draw(self, renderer)
   3098     for spine in self.spines.values():
   3099         artists.remove(spine)
-> 3101 self._update_title_position(renderer)
   3103 if not self.axison:
   3104     for _axis in self._axis_map.values():

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axes/_base.py:3045, in _AxesBase._update_title_position(self, renderer)
   3043 top = max(top, bb.ymax)
   3044 if title.get_text():
-> 3045     ax.yaxis.get_tightbbox(renderer)  # update offsetText
   3046     if ax.yaxis.offsetText.get_text():
   3047         bb = ax.yaxis.offsetText.get_tightbbox(renderer)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1372, in Axis.get_tightbbox(self, renderer, for_layout_only)
   1369     renderer = self.figure._get_renderer()
   1370 ticks_to_draw = self._update_ticks()
-> 1372 self._update_label_position(renderer)
   1374 # go back to just this axis's tick labels
   1375 tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:2654, in YAxis._update_label_position(self, renderer)
   2650     return
   2652 # get bounding boxes for this axis and any siblings
   2653 # that have been set by `fig.align_ylabels()`
-> 2654 bboxes, bboxes2 = self._get_tick_boxes_siblings(renderer=renderer)
   2655 x, y = self.label.get_position()
   2656 if self.label_position == 'left':

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:2206, in Axis._get_tick_boxes_siblings(self, renderer)
   2204 axis = ax._axis_map[name]
   2205 ticks_to_draw = axis._update_ticks()
-> 2206 tlb, tlb2 = axis._get_ticklabel_bboxes(ticks_to_draw, renderer)
   2207 bboxes.extend(tlb)
   2208 bboxes2.extend(tlb2)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1351, in Axis._get_ticklabel_bboxes(self, ticks, renderer)
   1349 if renderer is None:
   1350     renderer = self.figure._get_renderer()
-> 1351 return ([tick.label1.get_window_extent(renderer)
   1352          for tick in ticks if tick.label1.get_visible()],
   1353         [tick.label2.get_window_extent(renderer)
   1354          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1351, in <listcomp>(.0)
   1349 if renderer is None:
   1350     renderer = self.figure._get_renderer()
-> 1351 return ([tick.label1.get_window_extent(renderer)
   1352          for tick in ticks if tick.label1.get_visible()],
   1353         [tick.label2.get_window_extent(renderer)
   1354          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/text.py:959, in Text.get_window_extent(self, renderer, dpi)
    954     raise RuntimeError(
    955         "Cannot get window extent of text w/o renderer. You likely "
    956         "want to call 'figure.draw_without_rendering()' first.")
    958 with cbook._setattr_cm(self.figure, dpi=dpi):
--> 959     bbox, info, descent = self._get_layout(self._renderer)
    960     x, y = self.get_unitless_position()
    961     x, y = self.get_transform().transform((x, y))

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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, dpi=self.figure.dpi)
    376 min_dy = (lp_h - lp_d) * self._linespacing
    378 for i, line in enumerate(lines):

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/site-packages/matplotlib/backends/backend_agg.py:212, in RendererAgg.get_text_width_height_descent(self, s, prop, ismath)
    210 _api.check_in_list(["TeX", True, False], ismath=ismath)
    211 if ismath == "TeX":
--> 212     return super().get_text_width_height_descent(s, prop, ismath)
    214 if ismath:
    215     ox, oy, width, height, descent, font_image = \
    216         self.mathtext_parser.parse(s, self.dpi, prop)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/backend_bases.py:597, in RendererBase.get_text_width_height_descent(self, s, prop, ismath)
    593 fontsize = prop.get_size_in_points()
    595 if ismath == 'TeX':
    596     # todo: handle properties
--> 597     return self.get_texmanager().get_text_width_height_descent(
    598         s, fontsize, renderer=self)
    600 dpi = self.points_to_pixels(72)
    601 if ismath:

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/subprocess.py:424, in check_output(timeout, *popenargs, **kwargs)
    422     kwargs['input'] = empty
--> 424 return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
    425            **kwargs).stdout

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:505, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    503     kwargs['stderr'] = PIPE
--> 505 with Popen(*popenargs, **kwargs) as process:
    506     try:

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:951, 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)
    948             self.stderr = io.TextIOWrapper(self.stderr,
    949                     encoding=encoding, errors=errors)
--> 951     self._execute_child(args, executable, preexec_fn, close_fds,
    952                         pass_fds, cwd, env,
    953                         startupinfo, creationflags, shell,
    954                         p2cread, p2cwrite,
    955                         c2pread, c2pwrite,
    956                         errread, errwrite,
    957                         restore_signals,
    958                         gid, gids, uid, umask,
    959                         start_new_session)
    960 except:
    961     # Cleanup if the child failed starting.

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:1837, 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)
   1836         err_msg = os.strerror(errno_num)
-> 1837     raise child_exception_type(errno_num, err_msg, err_filename)
   1838 raise child_exception_type(err_msg)

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.9.21/x64/lib/python3.9/site-packages/IPython/core/formatters.py:340, in BaseFormatter.__call__(self, obj)
    338     pass
    339 else:
--> 340     return printer(obj)
    341 # Finally look for special method names
    342 method = get_real_method(obj, self.print_method)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/IPython/core/pylabtools.py:152, in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    149     from matplotlib.backend_bases import FigureCanvasBase
    150     FigureCanvasBase(fig)
--> 152 fig.canvas.print_figure(bytes_io, **kw)
    153 data = bytes_io.getvalue()
    154 if fmt == 'svg':

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/backend_bases.py:2175, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2172     # we do this instead of `self.figure.draw_without_rendering`
   2173     # so that we can inject the orientation
   2174     with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2175         self.figure.draw(renderer)
   2176 if bbox_inches:
   2177     if bbox_inches == "tight":

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/figure.py:3162, in Figure.draw(self, renderer)
   3159             # ValueError can occur when resizing a window.
   3161     self.patch.draw(renderer)
-> 3162     mimage._draw_list_compositing_images(
   3163         renderer, self, artists, self.suppressComposite)
   3165     renderer.close_group('figure')
   3166 finally:

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axes/_base.py:3101, in _AxesBase.draw(self, renderer)
   3098     for spine in self.spines.values():
   3099         artists.remove(spine)
-> 3101 self._update_title_position(renderer)
   3103 if not self.axison:
   3104     for _axis in self._axis_map.values():

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axes/_base.py:3045, in _AxesBase._update_title_position(self, renderer)
   3043 top = max(top, bb.ymax)
   3044 if title.get_text():
-> 3045     ax.yaxis.get_tightbbox(renderer)  # update offsetText
   3046     if ax.yaxis.offsetText.get_text():
   3047         bb = ax.yaxis.offsetText.get_tightbbox(renderer)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1372, in Axis.get_tightbbox(self, renderer, for_layout_only)
   1369     renderer = self.figure._get_renderer()
   1370 ticks_to_draw = self._update_ticks()
-> 1372 self._update_label_position(renderer)
   1374 # go back to just this axis's tick labels
   1375 tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:2654, in YAxis._update_label_position(self, renderer)
   2650     return
   2652 # get bounding boxes for this axis and any siblings
   2653 # that have been set by `fig.align_ylabels()`
-> 2654 bboxes, bboxes2 = self._get_tick_boxes_siblings(renderer=renderer)
   2655 x, y = self.label.get_position()
   2656 if self.label_position == 'left':

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:2206, in Axis._get_tick_boxes_siblings(self, renderer)
   2204 axis = ax._axis_map[name]
   2205 ticks_to_draw = axis._update_ticks()
-> 2206 tlb, tlb2 = axis._get_ticklabel_bboxes(ticks_to_draw, renderer)
   2207 bboxes.extend(tlb)
   2208 bboxes2.extend(tlb2)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1351, in Axis._get_ticklabel_bboxes(self, ticks, renderer)
   1349 if renderer is None:
   1350     renderer = self.figure._get_renderer()
-> 1351 return ([tick.label1.get_window_extent(renderer)
   1352          for tick in ticks if tick.label1.get_visible()],
   1353         [tick.label2.get_window_extent(renderer)
   1354          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1351, in <listcomp>(.0)
   1349 if renderer is None:
   1350     renderer = self.figure._get_renderer()
-> 1351 return ([tick.label1.get_window_extent(renderer)
   1352          for tick in ticks if tick.label1.get_visible()],
   1353         [tick.label2.get_window_extent(renderer)
   1354          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/text.py:959, in Text.get_window_extent(self, renderer, dpi)
    954     raise RuntimeError(
    955         "Cannot get window extent of text w/o renderer. You likely "
    956         "want to call 'figure.draw_without_rendering()' first.")
    958 with cbook._setattr_cm(self.figure, dpi=dpi):
--> 959     bbox, info, descent = self._get_layout(self._renderer)
    960     x, y = self.get_unitless_position()
    961     x, y = self.get_transform().transform((x, y))

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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, dpi=self.figure.dpi)
    376 min_dy = (lp_h - lp_d) * self._linespacing
    378 for i, line in enumerate(lines):

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/site-packages/matplotlib/backends/backend_agg.py:212, in RendererAgg.get_text_width_height_descent(self, s, prop, ismath)
    210 _api.check_in_list(["TeX", True, False], ismath=ismath)
    211 if ismath == "TeX":
--> 212     return super().get_text_width_height_descent(s, prop, ismath)
    214 if ismath:
    215     ox, oy, width, height, descent, font_image = \
    216         self.mathtext_parser.parse(s, self.dpi, prop)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/backend_bases.py:597, in RendererBase.get_text_width_height_descent(self, s, prop, ismath)
    593 fontsize = prop.get_size_in_points()
    595 if ismath == 'TeX':
    596     # todo: handle properties
--> 597     return self.get_texmanager().get_text_width_height_descent(
    598         s, fontsize, renderer=self)
    600 dpi = self.points_to_pixels(72)
    601 if ismath:

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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
<Figure size 640x480 with 1 Axes>
drive_rate = 10 #rad/s
dFbar = lambda a1, a2, a3, dx: np.array([l1*drive_rate*np.sin(a1)+\
                                         l2*dx[0]*np.sin(a2)-\
                                         l3*dx[1]*np.sin(a3),\
                                         l1*drive_rate*np.cos(a1)+\
                                         l2*dx[0]*np.cos(a2)-\
                                         l3*dx[1]*np.cos(a3)])
da1 = np.ones(len(a1))*10
da2 = np.zeros(len(a1))
da3 = np.zeros(len(a1))
xsol = np.array([0, 0])


for i in range(len(a1)):
    xsol = fsolve(lambda dx: dFbar(a1[i], a2[i], a3[i], dx), xsol)
    da2[i] = xsol[0]
    da3[i] = xsol[1]
plt.plot(a1, da1, label = r'$\dot{\theta}_1$')
plt.plot(a1, da2, label = r'$\dot{\theta}_2$')
plt.plot(a1, da3, label = r'$\dot{\theta}_3$')
plt.legend()
plt.xlabel(r'$\theta_1$ (radian)')
plt.ylabel('output angular speed (radian/s)')
Text(0, 0.5, 'output angular speed (radian/s)')
Error in callback <function _draw_all_if_interactive at 0x7f4f9db85280> (for post_execute), with arguments args (),kwargs {}:
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/subprocess.py:424, in check_output(timeout, *popenargs, **kwargs)
    422     kwargs['input'] = empty
--> 424 return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
    425            **kwargs).stdout

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:505, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    503     kwargs['stderr'] = PIPE
--> 505 with Popen(*popenargs, **kwargs) as process:
    506     try:

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:951, 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)
    948             self.stderr = io.TextIOWrapper(self.stderr,
    949                     encoding=encoding, errors=errors)
--> 951     self._execute_child(args, executable, preexec_fn, close_fds,
    952                         pass_fds, cwd, env,
    953                         startupinfo, creationflags, shell,
    954                         p2cread, p2cwrite,
    955                         c2pread, c2pwrite,
    956                         errread, errwrite,
    957                         restore_signals,
    958                         gid, gids, uid, umask,
    959                         start_new_session)
    960 except:
    961     # Cleanup if the child failed starting.

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:1837, 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)
   1836         err_msg = os.strerror(errno_num)
-> 1837     raise child_exception_type(errno_num, err_msg, err_filename)
   1838 raise child_exception_type(err_msg)

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.9.21/x64/lib/python3.9/site-packages/matplotlib/pyplot.py:268, in _draw_all_if_interactive()
    266 def _draw_all_if_interactive() -> None:
    267     if matplotlib.is_interactive():
--> 268         draw_all()

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/site-packages/matplotlib/backend_bases.py:1905, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
   1903 if not self._is_idle_drawing:
   1904     with self._idle_draw_cntx():
-> 1905         self.draw(*args, **kwargs)

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

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/figure.py:3162, in Figure.draw(self, renderer)
   3159             # ValueError can occur when resizing a window.
   3161     self.patch.draw(renderer)
-> 3162     mimage._draw_list_compositing_images(
   3163         renderer, self, artists, self.suppressComposite)
   3165     renderer.close_group('figure')
   3166 finally:

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axes/_base.py:3137, in _AxesBase.draw(self, renderer)
   3134 if artists_rasterized:
   3135     _draw_rasterized(self.figure, artists_rasterized, renderer)
-> 3137 mimage._draw_list_compositing_images(
   3138     renderer, self, artists, self.figure.suppressComposite)
   3140 renderer.close_group('axes')
   3141 self.stale = False

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1424, in Axis.draw(self, renderer)
   1421 renderer.open_group(__name__, gid=self.get_gid())
   1423 ticks_to_draw = self._update_ticks()
-> 1424 tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer)
   1426 for tick in ticks_to_draw:
   1427     tick.draw(renderer)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1351, in Axis._get_ticklabel_bboxes(self, ticks, renderer)
   1349 if renderer is None:
   1350     renderer = self.figure._get_renderer()
-> 1351 return ([tick.label1.get_window_extent(renderer)
   1352          for tick in ticks if tick.label1.get_visible()],
   1353         [tick.label2.get_window_extent(renderer)
   1354          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1351, in <listcomp>(.0)
   1349 if renderer is None:
   1350     renderer = self.figure._get_renderer()
-> 1351 return ([tick.label1.get_window_extent(renderer)
   1352          for tick in ticks if tick.label1.get_visible()],
   1353         [tick.label2.get_window_extent(renderer)
   1354          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/text.py:959, in Text.get_window_extent(self, renderer, dpi)
    954     raise RuntimeError(
    955         "Cannot get window extent of text w/o renderer. You likely "
    956         "want to call 'figure.draw_without_rendering()' first.")
    958 with cbook._setattr_cm(self.figure, dpi=dpi):
--> 959     bbox, info, descent = self._get_layout(self._renderer)
    960     x, y = self.get_unitless_position()
    961     x, y = self.get_transform().transform((x, y))

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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, dpi=self.figure.dpi)
    376 min_dy = (lp_h - lp_d) * self._linespacing
    378 for i, line in enumerate(lines):

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/site-packages/matplotlib/backends/backend_agg.py:212, in RendererAgg.get_text_width_height_descent(self, s, prop, ismath)
    210 _api.check_in_list(["TeX", True, False], ismath=ismath)
    211 if ismath == "TeX":
--> 212     return super().get_text_width_height_descent(s, prop, ismath)
    214 if ismath:
    215     ox, oy, width, height, descent, font_image = \
    216         self.mathtext_parser.parse(s, self.dpi, prop)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/backend_bases.py:597, in RendererBase.get_text_width_height_descent(self, s, prop, ismath)
    593 fontsize = prop.get_size_in_points()
    595 if ismath == 'TeX':
    596     # todo: handle properties
--> 597     return self.get_texmanager().get_text_width_height_descent(
    598         s, fontsize, renderer=self)
    600 dpi = self.points_to_pixels(72)
    601 if ismath:

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/subprocess.py:424, in check_output(timeout, *popenargs, **kwargs)
    422     kwargs['input'] = empty
--> 424 return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
    425            **kwargs).stdout

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:505, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    503     kwargs['stderr'] = PIPE
--> 505 with Popen(*popenargs, **kwargs) as process:
    506     try:

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:951, 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)
    948             self.stderr = io.TextIOWrapper(self.stderr,
    949                     encoding=encoding, errors=errors)
--> 951     self._execute_child(args, executable, preexec_fn, close_fds,
    952                         pass_fds, cwd, env,
    953                         startupinfo, creationflags, shell,
    954                         p2cread, p2cwrite,
    955                         c2pread, c2pwrite,
    956                         errread, errwrite,
    957                         restore_signals,
    958                         gid, gids, uid, umask,
    959                         start_new_session)
    960 except:
    961     # Cleanup if the child failed starting.

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/subprocess.py:1837, 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)
   1836         err_msg = os.strerror(errno_num)
-> 1837     raise child_exception_type(errno_num, err_msg, err_filename)
   1838 raise child_exception_type(err_msg)

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.9.21/x64/lib/python3.9/site-packages/IPython/core/formatters.py:340, in BaseFormatter.__call__(self, obj)
    338     pass
    339 else:
--> 340     return printer(obj)
    341 # Finally look for special method names
    342 method = get_real_method(obj, self.print_method)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/IPython/core/pylabtools.py:152, in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    149     from matplotlib.backend_bases import FigureCanvasBase
    150     FigureCanvasBase(fig)
--> 152 fig.canvas.print_figure(bytes_io, **kw)
    153 data = bytes_io.getvalue()
    154 if fmt == 'svg':

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/backend_bases.py:2175, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2172     # we do this instead of `self.figure.draw_without_rendering`
   2173     # so that we can inject the orientation
   2174     with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2175         self.figure.draw(renderer)
   2176 if bbox_inches:
   2177     if bbox_inches == "tight":

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/figure.py:3162, in Figure.draw(self, renderer)
   3159             # ValueError can occur when resizing a window.
   3161     self.patch.draw(renderer)
-> 3162     mimage._draw_list_compositing_images(
   3163         renderer, self, artists, self.suppressComposite)
   3165     renderer.close_group('figure')
   3166 finally:

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axes/_base.py:3137, in _AxesBase.draw(self, renderer)
   3134 if artists_rasterized:
   3135     _draw_rasterized(self.figure, artists_rasterized, renderer)
-> 3137 mimage._draw_list_compositing_images(
   3138     renderer, self, artists, self.figure.suppressComposite)
   3140 renderer.close_group('axes')
   3141 self.stale = False

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

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

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1424, in Axis.draw(self, renderer)
   1421 renderer.open_group(__name__, gid=self.get_gid())
   1423 ticks_to_draw = self._update_ticks()
-> 1424 tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer)
   1426 for tick in ticks_to_draw:
   1427     tick.draw(renderer)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1351, in Axis._get_ticklabel_bboxes(self, ticks, renderer)
   1349 if renderer is None:
   1350     renderer = self.figure._get_renderer()
-> 1351 return ([tick.label1.get_window_extent(renderer)
   1352          for tick in ticks if tick.label1.get_visible()],
   1353         [tick.label2.get_window_extent(renderer)
   1354          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/axis.py:1351, in <listcomp>(.0)
   1349 if renderer is None:
   1350     renderer = self.figure._get_renderer()
-> 1351 return ([tick.label1.get_window_extent(renderer)
   1352          for tick in ticks if tick.label1.get_visible()],
   1353         [tick.label2.get_window_extent(renderer)
   1354          for tick in ticks if tick.label2.get_visible()])

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/text.py:959, in Text.get_window_extent(self, renderer, dpi)
    954     raise RuntimeError(
    955         "Cannot get window extent of text w/o renderer. You likely "
    956         "want to call 'figure.draw_without_rendering()' first.")
    958 with cbook._setattr_cm(self.figure, dpi=dpi):
--> 959     bbox, info, descent = self._get_layout(self._renderer)
    960     x, y = self.get_unitless_position()
    961     x, y = self.get_transform().transform((x, y))

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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, dpi=self.figure.dpi)
    376 min_dy = (lp_h - lp_d) * self._linespacing
    378 for i, line in enumerate(lines):

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/site-packages/matplotlib/backends/backend_agg.py:212, in RendererAgg.get_text_width_height_descent(self, s, prop, ismath)
    210 _api.check_in_list(["TeX", True, False], ismath=ismath)
    211 if ismath == "TeX":
--> 212     return super().get_text_width_height_descent(s, prop, ismath)
    214 if ismath:
    215     ox, oy, width, height, descent, font_image = \
    216         self.mathtext_parser.parse(s, self.dpi, prop)

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages/matplotlib/backend_bases.py:597, in RendererBase.get_text_width_height_descent(self, s, prop, ismath)
    593 fontsize = prop.get_size_in_points()
    595 if ismath == 'TeX':
    596     # todo: handle properties
--> 597     return self.get_texmanager().get_text_width_height_descent(
    598         s, fontsize, renderer=self)
    600 dpi = self.points_to_pixels(72)
    601 if ismath:

File /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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.9.21/x64/lib/python3.9/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
<Figure size 640x480 with 1 Axes>

Proposed Outline:#

Background#

  • What are you trying to model? I am trying to simulate a good golf swing with the circular shape of the shoulders. The model is simplified because it acts in a four-bar linkage design. The bicep and forearm of one arm (made into two links, l1 and l2) and the other entire arm (l3). Free body diagram and motion of golf swing is shown in the jpeg (l1 and l2 should be switched). IMG_5C3DE768BA33-1.jpeg

    I used my model from the Module 2, the four bar linkage design. It still could use work, but the general idea is there. Firstly, I defined my variable values l1 is the length of my forearm, l2 is the length of bicep, l3 is the length of the other arm, and dx is the length between my two shoulders (the model of the graph called ‘Path and Orientation For…’ shows this in birds-eye-view of my model). I then defined the motion of the hinges and their angles, plotted in the first graph ‘output angle vs. theta 1’ and second graph ‘Paths and Orientation for.’ I then found the angular velocity plotted in third graph, ‘output angular speed vs theta.’ My assumptions are that the model returns back to the same place as the start of the swing right before hitting the ball otherwise it cannot hit the ball. My constraints are that one arm has no hinge while the other does; this allows for a good and extended backswing but limits the front swing because it cannot move passed the full extension of the arm containing l1 and l2. This is due to the fact that l3 cannot bend to allow for the extension of the back arm (l1 and l2). The equations are used are in my code above. I used my Newton-Euler equations and constraint vectors to define postions of linkages. My analysis is shown above and graphs of my work are displayed above to demonstrate the angles, angular speed, and hinge movement.

    Originally I set up my linkage to run just the back arm: one link was the entire arm (including forearm and bicep), one link was the stationary collor bone area, and one link represented the spine. This model was not suitable to demonstrate the swing and professor helped me to change my model to include both arms and making one arm represented as a whole and and the second arm split at the elbow. This allowed me to meet my goal because it allowed for a fuller and more complete demonstration and analysis of the rotation of the golf swing.I have played golf my whole life and always knew the importance of the back swing but never realized how important the front swing is. Without full extension the ball cannot go its full potential. Since beginning this project I have focused more on my front swing and I have seen improvement in my game and reduced problems such as slicing (if you are a righty you hit the ball to the right and vice versa), as I thought my problem was my backswing but it was jut the lazy follow-through of my front swing that made me push the ball. I could improve the analysis of this device by splitting my front arm (l3) to have a hinge to allow for full extension of the front swing.