Skip to content
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

[Bug]: Incorrect zorder of bar elements in a 3d histogram #25534

Closed
mapfiable opened this issue Mar 23, 2023 · 7 comments
Closed

[Bug]: Incorrect zorder of bar elements in a 3d histogram #25534

mapfiable opened this issue Mar 23, 2023 · 7 comments

Comments

@mapfiable
Copy link

mapfiable commented Mar 23, 2023

Bug summary

I am trying to create a 3d histogram following the solution suggested here, which is based on [this matplotlib demo](Create 3D histogram of 2D data). In the finished plot however, the zorder of the bar sides are all messed up.

Code for reproduction

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm


# source: https://stackoverflow.com/a/56923189/5472354
def gaus2d(x=0, y=0, mx=0, my=0, sx=1, sy=1):
    return 1. / (2. * np.pi * sx * sy) * np.exp(
        -((x - mx) ** 2. / (2. * sx ** 2.) + (y - my) ** 2. / (2. * sy ** 2.)))

sample_radius = 5
n_samples = 11
x = np.linspace(-sample_radius, sample_radius, num=n_samples)
y = np.linspace(-sample_radius, sample_radius, num=n_samples)
z = gaus2d(*np.meshgrid(x, y))


fig = plt.figure(constrained_layout=True)
ax = fig.add_subplot(111, projection='3d')
ax.axis('off')
ax.margins(0)

hist, xedges, yedges = np.histogram2d(x, y, bins=n_samples)
xpos, ypos = np.meshgrid(xedges[:-1] + xedges[1:], yedges[:-1] + yedges[1:])

xpos = xpos.flatten() / 2.
ypos = ypos.flatten() / 2.
zpos = np.zeros_like(xpos)

dx = xedges[1] - xedges[0]
dy = yedges[1] - yedges[0]
dz = z.flatten()

cmap = cm.get_cmap('viridis')
max_height = np.max(dz)
min_height = np.min(dz)

rgba = [cmap((k-min_height)/max_height) for k in dz]

ax.bar3d(
    xpos, ypos, zpos, dx, dy, dz, color=rgba, zsort='average', shade=True
)

plt.show()

Actual outcome

grafik

Expected outcome

A plot where the zorder is correct (although I have to admit, the result looks like a neat art piece).

Additional information

I would guess it has something to do with the zsort argument, but I actually didn't manage to find the documentation for bar3d, only this post. I tried all three possibilities, but none of them worked. Is bar3d depreciated?

Operating system

Windows 10

Matplotlib Version

3.6.1

Matplotlib Backend

backend_interagg

Python version

3.9.7

Jupyter version

No response

Installation

conda

@mapfiable
Copy link
Author

I just tested it with matplotlib version 3.7.1 and get the same result.

@jklymak
Copy link
Member

jklymak commented Mar 23, 2023

Can you make an example w/o astropy?

@mapfiable
Copy link
Author

@jklymak sure, I updated the MWE.

@ksunden
Copy link
Member

ksunden commented Mar 23, 2023

For reference, the docs for bar3d:

https://matplotlib.org/stable/api/_as_gen/mpl_toolkits.mplot3d.axes3d.Axes3D.bar3d.html

And the zsort param comes from:

https://matplotlib.org/stable/api/_as_gen/mpl_toolkits.mplot3d.art3d.Poly3DCollection.html#mpl_toolkits.mplot3d.art3d.Poly3DCollection

See also:

#12620
#16071
#13728
#25333

That said, I'm going to close as a duplicate of #13728, which is already open and essentially the same.

@ksunden ksunden closed this as not planned Won't fix, can't repro, duplicate, stale Mar 23, 2023
@mapfiable
Copy link
Author

@ksunden I see, thanks a lot for the quick feedback! Sorry, I wasn't aware of the other issues. Somehow I didn't manage to find them. If I understand correctly, this behaviour is because of a missing proper 3d engine, which unfortunately will not come any time soon?

Btw, I "fixed" this by saving the figure as an svg file and then manually reordering the different elements.

@ksunden
Copy link
Member

ksunden commented Mar 23, 2023

yeah, there may be a path to properly ordering at least the narrow case of bar charts (which have only orthogonal rectangles, so there might be something that can be done there)

Essentially, the three (I'm pretty sure we only draw visible sides) polygons for each bar need to be drawn together and in a back to front as a unit.

Currently the Poly3DCollection has no such grouping of polygons, so each side is determined what effective zorder (because the whole collection only has one actual zorder in relation to any other object) that bar has. and since the "average" "min" or "max" position of each of those polys is not consistent between bars which one should take precedence, adjacent bars are drawn between the sets.

A general solution is not likely to be had in the near-medium term.

@mapfiable
Copy link
Author

That's a shame, but understandable. The general case is not an easy thing to fix. Thanks a lot for the explanations!

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

No branches or pull requests

3 participants