| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| Expand Up | @@ -132,11 +132,13 @@ def path_to_3d_segment(path, zs=0, zdir='z'): | |
| zs = np.ones(len(path)) * zs | ||
|
|
||
| seg = [] | ||
| codes = [] | ||
| pathsegs = path.iter_segments(simplify=False, curves=False) | ||
| for (((x, y), code), z) in zip(pathsegs, zs): | ||
| seg.append((x, y, z)) | ||
| codes.append(code) | ||
| seg3d = [juggle_axes(x, y, z, zdir) for (x, y, z) in seg] | ||
| return seg3d | ||
| return seg3d, codes | ||
|
|
||
| def paths_to_3d_segments(paths, zs=0, zdir='z'): | ||
| ''' | ||
| Expand All | @@ -147,9 +149,12 @@ def paths_to_3d_segments(paths, zs=0, zdir='z'): | |
| zs = np.ones(len(paths)) * zs | ||
|
|
||
| segments = [] | ||
| codes_list = [] | ||
| for path, pathz in zip(paths, zs): | ||
| segments.append(path_to_3d_segment(path, pathz, zdir)) | ||
| return segments | ||
| segs, codes = path_to_3d_segment(path, pathz, zdir) | ||
| segments.append(segs) | ||
| codes_list.append(codes) | ||
| return segments, codes_list | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualitySame thing here. Can't change the output API without some sort of transition period.
Sorry, something went wrong.
All reactions
|
||
|
|
||
| class Line3DCollection(LineCollection): | ||
| ''' | ||
| Expand Down Expand Up | @@ -196,7 +201,7 @@ def draw(self, renderer, project=False): | |
|
|
||
| def line_collection_2d_to_3d(col, zs=0, zdir='z'): | ||
| """Convert a LineCollection to a Line3DCollection object.""" | ||
| segments3d = paths_to_3d_segments(col.get_paths(), zs, zdir) | ||
| segments3d = paths_to_3d_segments(col.get_paths(), zs, zdir)[0] | ||
| col.__class__ = Line3DCollection | ||
| col.set_segments(segments3d) | ||
|
|
||
| Expand Down Expand Up | @@ -363,6 +368,8 @@ def __init__(self, verts, *args, **kwargs): | |
|
|
||
| PolyCollection.__init__(self, verts, *args, **kwargs) | ||
|
|
||
| self._codes3d = None | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityI am not quite understanding why this is needed, though. Doesn't the Polygons in the PolyCollection have their own codes?
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality@WeatherGod, you need to understand the existing code for my changes to make sense. Take a look at the Poly3DCollection class in art3d.py, which is derived from the 2D PolyCollection in collections.py. Poly3DCollection stores the 3D vertices in self._vec and self._segis. Each time Poly3DCollection.do_3d_projection is called, the 3D vertices are transformed and projected into 2D points that are stored in the usual PolyCollection._paths that are used for rendering. The root cause of issue #178 is that a 2D PolyCollection has both 2D vertices and 2D codes. The codes are used so that single arrays of vertices and codes can be used for multiple polygons, such as when a contour needs to render a hole polygon inside another polygon. Up until now, Poly3DCollection has had no understanding of these codes and so has rendered all the vertices as though they were a single polygon, causing incorrect rendering. My solution to this is to follow the existing (IMHO poor) implementation, and store the codes in Poly3DCollection as self._codes3d much like the vertices are stored as self._vec and self._segis. Each time do_3d_projection is called, both the stored vertices and codes are transformed/projected and used to update the PolyCollection._paths that are used for rendering. As an aside, the Poly3DCollection constructor is never called for 3D contours, instead the function poly_collection_2d_to_3d does some very nasty object creation without calling the constructor. I believe this is to avoid the base PolyCollection constructor being called, as this will complain that the vertices are not 2D. I put the line you have asked about in the constructor because it should be initialised whenever the constructor is called, but of course that argument also applies to self._vec and self._segis but this has not been done before for some reason. As I said at the top of the PR, my code changes are not elegant but they are consistent (i.e. no worse than) the existing code. I didn't really want to touch any of the mplot3d code, but as you said you didn't know how to solve the problem I thought I'd give it a try.
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityOk, I see it now. A 3d polygon with a hole would need a MOVETO, but that information is never really conveyed properly. As for your aside, you are absolutely right. I am the third maintainer of this codebase, and there is a lot of stuff in it that has been "don't touch because it might break". The reason for the oddity in the object creation is probably one borne of "getting the job done". The idea for most of these things is to let the 2D plotting functions do their jobs, and then augment them with the third dimension information.
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality@WeatherGod: You are correct, I have not explained the fix in the code but pretty much nothing is explained in the existing mplot3d code. As I keep saying, my changes are consistent with the existing code. The more I think about it the less I want my name associated with the mplot3d codebase, hence I am closing this PR. I have diagnosed the problem and come up with a fix, albeit possibly a poor fix, so you or someone else can use my code as the basis for an acceptable fix if you wish. You still owe me a pint as for figuring about the bug as you promised in #1299!
Sorry, something went wrong.
All reactions
|
||
|
|
||
| _zsort_functions = { | ||
| 'average': np.average, | ||
| 'min': np.min, | ||
| Expand Down Expand Up | @@ -419,6 +426,10 @@ def set_verts(self, verts, closed=True): | |
| # 2D verts will be updated at draw time | ||
| PolyCollection.set_verts(self, [], closed) | ||
|
|
||
| def set_verts_and_codes(self, verts, codes): | ||
| self.set_verts(verts, closed=False) | ||
| self._codes3d = codes | ||
|
|
||
| def set_3d_properties(self): | ||
| # Force the collection to initialize the face and edgecolors | ||
| # just in case it is a scalarmappable with a colormap. | ||
| Expand Down Expand Up | @@ -457,18 +468,24 @@ def do_3d_projection(self, renderer): | |
|
|
||
| # if required sort by depth (furthest drawn first) | ||
| if self._zsort: | ||
| z_segments_2d = [(self._zsortfunc(zs), zip(xs, ys), fc, ec) for | ||
| (xs, ys, zs), fc, ec in zip(xyzlist, cface, cedge)] | ||
| indices = range(len(xyzlist)) | ||
| z_segments_2d = [(self._zsortfunc(zs), zip(xs, ys), fc, ec, idx) | ||
| for (xs, ys, zs), fc, ec, idx in zip(xyzlist, cface, cedge, | ||
| indices)] | ||
| z_segments_2d.sort(key=lambda x: x[0], reverse=True) | ||
| else: | ||
| raise ValueError, "whoops" | ||
|
|
||
| segments_2d = [s for z, s, fc, ec in z_segments_2d] | ||
| PolyCollection.set_verts(self, segments_2d) | ||
| segments_2d = [s for z, s, fc, ec, idx in z_segments_2d] | ||
| if self._codes3d is not None: | ||
| codes = [self._codes3d[idx] for z, s, fc, ec, idx in z_segments_2d] | ||
| PolyCollection.set_verts_and_codes(self, segments_2d, codes) | ||
| else: | ||
| PolyCollection.set_verts(self, segments_2d) | ||
|
|
||
| self._facecolors2d = [fc for z, s, fc, ec in z_segments_2d] | ||
| self._facecolors2d = [fc for z, s, fc, ec, idx in z_segments_2d] | ||
| if len(self._edgecolors3d) == len(cface): | ||
| self._edgecolors2d = [ec for z, s, fc, ec in z_segments_2d] | ||
| self._edgecolors2d = [ec for z, s, fc, ec, idx in z_segments_2d] | ||
| else: | ||
| self._edgecolors2d = self._edgecolors3d | ||
|
|
||
| Expand Down Expand Up | @@ -508,9 +525,9 @@ def draw(self, renderer): | |
|
|
||
| def poly_collection_2d_to_3d(col, zs=0, zdir='z'): | ||
| """Convert a PolyCollection to a Poly3DCollection object.""" | ||
| segments_3d = paths_to_3d_segments(col.get_paths(), zs, zdir) | ||
| segments_3d, codes = paths_to_3d_segments(col.get_paths(), zs, zdir) | ||
| col.__class__ = Poly3DCollection | ||
| col.set_verts(segments_3d) | ||
| col.set_verts_and_codes(segments_3d, codes) | ||
| col.set_3d_properties() | ||
|
|
||
| def juggle_axes(xs, ys, zs, zdir): | ||
| Expand Down | ||
| Back | FazBrowse Home | New Git URL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThis changes the API of this function. The correct way to go about this is to deprecate this one and have a new function set up to replace it. Or, have a kwarg defaulting to False to indicate whether to return the codes as well.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality@WeatherGod: I have changed all code that calls this and the other function you have highlighted. I see these as internal (i.e. private) functions, even though they are do not have leading underscores.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThey are not private. These are public methods to objects that people do manipulate in the wild. You will have to go through the proper process for this change.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.