Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Patch3D constructor fundamentally incorrect. #23624

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
oscargus opened this issue Aug 15, 2022 · 4 comments
Open

Patch3D constructor fundamentally incorrect. #23624

oscargus opened this issue Aug 15, 2022 · 4 comments

Comments

@oscargus
Copy link
Member

oscargus commented Aug 15, 2022

Summary

Consider the following code:

def __init__(self, *args, zs=(), zdir='z', **kwargs):
super().__init__(*args, **kwargs)
self.set_3d_properties(zs, zdir)
def set_3d_properties(self, verts, zs=0, zdir='z'):
zs = np.broadcast_to(zs, len(verts))
self._segment3d = [juggle_axes(x, y, z, zdir)
for ((x, y), z) in zip(verts, zs)]

set_3d_properties should be passed a verts argument, but is not passed that in the constructor.

It is not clear how to get rid of that.

A few points worth considering:

  • PathPatch3D does take a path as the first argument. Doing something similar, i.e. have a verts instead of *args will break subclassing as done in e.g. [Bug]: unavoidable DeprecationWarning when using Patch3D #21740
  • setting a default verts=None in set_3d_properties and then set it to get_verts may be a feasible solution, but will break as _path2s is not set here. For subclasses defining their own get_path or _path2d it would make sense though.
  • It is possible to call set_3d_properties with an empty verts, but the only benefit is that _segment3d is set (to an empty list.

This seems to have been the case since the very first commit of mplot3d.

Proposed fix

I see a few possible solutions:

  1. Dropping the __init__ method completely. A bit weird since one can pass zs and zdir to all other 3D methods.
  2. Add a verts kw args so that one can construct the patch directly. This seems to not be the case for Patch though which must be subclassed(?).
  3. Passing verts=self.get_verts() which will allow subclasses to work properly, but disallows instantiating a Patch3D directly.
  4. 3 with a try-except for get_verts()

4 is probably the safest.

@tacaswell
Copy link
Member

We have never noticed this before because I do not think we ever actually call this __init__, but instead "promote" Patch objects to become Patch3D objects.

Given that Patch3D does inherit from Patch, I think putting a version of

def _get_patch_verts(patch):
"""Return a list of vertices for the path of a patch."""
trans = patch.get_patch_transform()
path = patch.get_path()
polygons = path.to_polygons(trans)
return polygons[0] if len(polygons) else np.array([])
def patch_2d_to_3d(patch, z=0, zdir='z'):
"""Convert a Patch to a Patch3D object."""
verts = _get_patch_verts(patch)
patch.__class__ = Patch3D
patch.set_3d_properties(verts, z, zdir)
in to the init (which should work so long as the super().__init__ is done ) maybe the right thing to do (version of 3).

@timhoffm
Copy link
Member

We have never noticed this before because I do not think we ever actually call this __init__, but instead "promote" Patch objects to become Patch3D objects.

I haven't looked into the issue or the proposed solutions. I just want to note: If we never use __init__, it's a viable option to raise NotImplemented from there. Patch3D is our class and no user should have any reason to instantiate that explicitly. if neither we nor a user calls __init__, there's no need to implement it (as strange as that may sound for __init__ 😄 ).

@tacaswell
Copy link
Member

Raising NotImplemented in __init__ would certainly indicate "There are 🐲 's here!"

@timhoffm
Copy link
Member

To be precise, we’d need to raise NotImplementedError.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants