orlandpm / Math-for-Programmers

Source code for the book, Math for Programmers
840 stars 391 forks source link

[Fix] chapter 3: fix draw3d error #26

Open hirotaka opened 5 months ago

hirotaka commented 5 months ago

Running the following code with a newer version(3.9.0) of matplotlib seems to result in an error.

draw3d(
    Points3D((2,2,2),(1,-2,-2)),
    Arrow3D((2,2,2)),
    Arrow3D((1,-2,-2)),
    Segment3D((2,2,2), (1,-2,-2))
)

This can be resolved by correcting the problem, as stated in the comments on StackOverflow.

https://stackoverflow.com/a/74122407/1968614

Error:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
File ~/.asdf/installs/python/3.12.4/lib/python3.12/site-packages/IPython/core/formatters.py:343, in BaseFormatter.__call__(self, obj)
    341     pass
    342 else:
--> 343     return printer(obj)
    344 # Finally look for special method names
    345 method = get_real_method(obj, self.print_method)

File ~/.asdf/installs/python/3.12.4/lib/python3.12/site-packages/IPython/core/pylabtools.py:170, in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    167     from matplotlib.backend_bases import FigureCanvasBase
    168     FigureCanvasBase(fig)
--> 170 fig.canvas.print_figure(bytes_io, **kw)
    171 data = bytes_io.getvalue()
    172 if fmt == 'svg':

File ~/.asdf/installs/python/3.12.4/lib/python3.12/site-packages/matplotlib/backend_bases.py:2189, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2186     # we do this instead of `self.figure.draw_without_rendering`
   2187     # so that we can inject the orientation
   2188     with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2189         self.figure.draw(renderer)
   2190 if bbox_inches:
   2191     if bbox_inches == "tight":

File ~/.asdf/installs/python/3.12.4/lib/python3.12/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 ~/.asdf/installs/python/3.12.4/lib/python3.12/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 ~/.asdf/installs/python/3.12.4/lib/python3.12/site-packages/matplotlib/figure.py:3155, in Figure.draw(self, renderer)
   3152             # ValueError can occur when resizing a window.
   3154     self.patch.draw(renderer)
-> 3155     mimage._draw_list_compositing_images(
   3156         renderer, self, artists, self.suppressComposite)
   3158     renderer.close_group('figure')
   3159 finally:

File ~/.asdf/installs/python/3.12.4/lib/python3.12/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 ~/.asdf/installs/python/3.12.4/lib/python3.12/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 ~/.asdf/installs/python/3.12.4/lib/python3.12/site-packages/mpl_toolkits/mplot3d/axes3d.py:439, in Axes3D.draw(self, renderer)
    435 zorder_offset = max(axis.get_zorder()
    436                     for axis in self._axis_map.values()) + 1
    437 collection_zorder = patch_zorder = zorder_offset
--> 439 for artist in sorted(collections_and_patches,
    440                      key=lambda artist: artist.do_3d_projection(),
    441                      reverse=True):
    442     if isinstance(artist, mcoll.Collection):
    443         artist.zorder = collection_zorder

File ~/.asdf/installs/python/3.12.4/lib/python3.12/site-packages/mpl_toolkits/mplot3d/axes3d.py:440, in Axes3D.draw.<locals>.<lambda>(artist)
    435 zorder_offset = max(axis.get_zorder()
    436                     for axis in self._axis_map.values()) + 1
    437 collection_zorder = patch_zorder = zorder_offset
    439 for artist in sorted(collections_and_patches,
--> 440                      key=lambda artist: artist.do_3d_projection(),
    441                      reverse=True):
    442     if isinstance(artist, mcoll.Collection):
    443         artist.zorder = collection_zorder

AttributeError: 'FancyArrow3D' object has no attribute 'do_3d_projection'
<Figure size 640x480 with 1 Axes>
notevenaperson commented 3 months ago

Switched to your branch myself. Thanks for taking the bullet.

yongjunchai commented 2 months ago

Thanks for the PR.