tjstienstra/symmeplot

Only modify axes once plot is ran

Opened this issue · 0 comments

Describe the bug
If you forget to run symmeplot.matplotlib.scene.Scene3D.plot, you can get a rather weird error because artists have not been added to the axes yet. This specifically occurs when you have attached a circle to a body.

To Reproduce
Steps to reproduce the behavior:

  1. Run the following code.
    from symmeplot.matplotlib import Scene3D
    import sympy.physics.mechanics as me
    import matplotlib.pyplot as plt
    
    scene = Scene3D(me.ReferenceFrame("N"), me.Point("N_0"))
    b = scene.add_body(me.RigidBody("N", scene.zero_point, scene.inertial_frame))
    b.attach_circle(scene.zero_point, 1, scene.inertial_frame.y)
    scene.lambdify_system(())
    scene.evaluate_system()
    # scene.plot()  # Forget to run plot.
    plt.show()
  2. Hover with your mouse over the figure.

This will throw the following error:

Traceback (most recent call last):
  File "...\site-packages\matplotlib\cbook.py", line 298, in process
    func(*args, **kwargs)
  File "...\site-packages\symmeplot\matplotlib\scene.py", line 182, in _hover
    plot_object = self._get_selected_object(event)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "...\site-packages\symmeplot\matplotlib\scene.py", line 164, in _get_selected_object
    if plot_object.contains(event):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "...\site-packages\symmeplot\matplotlib\plot_base.py", line 68, in contains
    return any(artist.contains(event)[0] for artist in self.artists)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "...\site-packages\symmeplot\matplotlib\plot_base.py", line 68, in <genexpr>
    return any(artist.contains(event)[0] for artist in self.artists)
               ^^^^^^^^^^^^^^^^^^^^^^
  File "...\site-packages\matplotlib\patches.py", line 160, in contains
    codes = self.get_path().codes
            ^^^^^^^^^^^^^^^
  File "...\site-packages\mpl_toolkits\mplot3d\art3d.py", line 454, in get_path
    self.axes.M = self.axes.get_proj()
                  ^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get_proj'

Expected behavior
Two changes should ideally be made:

  1. Scene3D should postpone modification of the axes such that no references will be made to the artists. This can be done by attaching the motion notify event in plot instead of in __init__.
  2. Additionally, plot should be modified such that it can only be run once. When ran a second time it should raise an error explaining the the scene has already been plotted and update should be used to update the objects in the figure.

Additional context
This issue was found in bicycle-kickplate-model #34.