2

OK I have some code that I'm using to plot 3d charts in matplotlib (based on this great answer here). Here's the simplified version:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib

plt.close("all")

data1 = pd.DataFrame.from_dict(
    {
        "0": {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10},
        "1": {0: 10, 1: 0, 2: 1, 3: 2, 4: 3, 5: 4, 6: 5, 7: 6, 8: 7, 9: 8, 10: 9},
        "2": {0: 9, 1: 10, 2: 0, 3: 1, 4: 2, 5: 3, 6: 4, 7: 5, 8: 6, 9: 7, 10: 8},
        "3": {0: 8, 1: 9, 2: 10, 3: 0, 4: 1, 5: 2, 6: 3, 7: 4, 8: 5, 9: 6, 10: 7},
        "4": {0: 7, 1: 8, 2: 9, 3: 10, 4: 0, 5: 1, 6: 2, 7: 3, 8: 4, 9: 5, 10: 6},
        "5": {0: 6, 1: 7, 2: 8, 3: 9, 4: 10, 5: 0, 6: 1, 7: 2, 8: 3, 9: 4, 10: 5},
        "6": {0: 5, 1: 6, 2: 7, 3: 8, 4: 9, 5: 10, 6: 0, 7: 1, 8: 2, 9: 3, 10: 4},
        "7": {0: 4, 1: 5, 2: 6, 3: 7, 4: 8, 5: 9, 6: 10, 7: 0, 8: 1, 9: 2, 10: 3},
        "8": {0: 3, 1: 4, 2: 5, 3: 6, 4: 7, 5: 8, 6: 9, 7: 10, 8: 0, 9: 1, 10: 2},
        "9": {0: 2, 1: 3, 2: 4, 3: 5, 4: 6, 5: 7, 6: 8, 7: 9, 8: 10, 9: 0, 10: 1},
        "10": {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10, 10: 0},
    }
)
data2 = pd.DataFrame.from_dict(
    {
        "0": {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10},
        "1": {0:np.nan,1:0.0,2:1.0,3:2.0,4:3.0,5:4.0,6:5.0,7:6.0,8:7.0,9:8.0,10:9.0,},
        "2":{0:np.nan,1:np.nan,2:0.0,3:1.0,4:2.0,5:3.0,6:4.0,7:5.0,8:6.0,9:7.0,10:8.0,},
        "3":{0:np.nan,1:np.nan,2:np.nan,3:0.0,4:1.0,5:2.0,6:3.0,7:4.0,8:5.0,9:6.0,10:7.0,},
        "4":{0:np.nan,1:np.nan,2:np.nan,3:np.nan,4:0.0,5:1.0,6:2.0,7:3.0,8:4.0,9:5.0,10:6.0,},
        "5":{0:np.nan,1:np.nan,2:np.nan,3:np.nan,4:np.nan,5:0.0,6:1.0,7:2.0,8:3.0,9:4.0,10:5.0,},
        "6":{0:np.nan,1:np.nan,2:np.nan,3:np.nan,4:np.nan,5:np.nan,6:0.0,7:1.0,8:2.0,9:3.0,10:4.0,},
        "7":{0:np.nan,1:np.nan,2:np.nan,3:np.nan,4:np.nan,5:np.nan,6:np.nan,7:0.0,8:1.0,9:2.0,10:3.0,},
        "8":{0:np.nan,1:np.nan,2:np.nan,3:np.nan,4:np.nan,5:np.nan,6:np.nan,7:np.nan,8:0.0,9:1.0,10:2.0,},
        "9":{0:np.nan,1:np.nan,2:np.nan,3:np.nan,4:np.nan,5:np.nan,6:np.nan,7:np.nan,8:np.nan,9:0.0,10:1.0,},
        "10":{0:np.nan,1:np.nan,2:np.nan,3:np.nan,4:np.nan,5:np.nan,6:np.nan,7:np.nan,8:np.nan,9:np.nan,10:0.0,},
    }
)

fig=plt.figure(figsize=(8,3))
ax1=fig.add_subplot(121, projection="3d")
ax2=fig.add_subplot(122, projection="3d")

#thickness of the bars
dx, dy = 1, 1

# set up positions for the bars
xpos = np.arange(data1.shape[0])
ypos = np.arange(data1.shape[1])

# create meshgrid
# print xpos before and after this block if not clear
xpos, ypos = np.meshgrid(xpos, ypos)
xpos = xpos.flatten()
ypos = ypos.flatten()

# the bars starts from 0 attitude
zpos = np.zeros(data1.shape).flatten()

# the bars' heights
dz1 = data1.values.ravel()
dz2 = data2.values.ravel()

ma = np.nanmax(data1.values)
norm = matplotlib.colors.Normalize(vmin=0, vmax=10, clip=True)

# # plot
ax1.bar3d(xpos, ypos, zpos, dx, dy, dz1, shade=True, ec="k", lw=0.1)
ax2.bar3d(xpos, ypos, zpos, dx, dy, dz2, shade=True, ec="k", lw=0.1)

# set up the axes furniture
for ax in [ax1, ax2]:

    ax.set_xticks(xpos + dx / 2)
    ax.set_yticks(ypos + dy / 2)
    ax.w_yaxis.set_ticklabels([])
    ax.w_xaxis.set_ticklabels([])
    ax.w_zaxis.set_ticklabels([])
    ax.set_zlim(0, 10.5)
    ax.set_xlim(0, 10.5)
    ax.set_ylim(0, 10.5)

    # name the axes
    ax.set_xlabel("x")
    ax.set_ylabel("y")
    ax.set_zlabel("z")

plt.show()

It results in a figure that looks like this:

a figure showing a maplotlib graph where some of the columns are out of sequence

The graph on the left shows everything in the right place (though you might have to run the code and rotate the graph to see for yourself) but the one on the right plots the bars out of sequence and we end up with something a bit... odd.

My question is

  1. what's going on here, and
  2. is there any way of fixing this within matplotlib, if so how?

Thanks!

7
  • Graph looks OK, it'll be clear if you let matplotlib show the labels. The y axis goes in the different direction as you (and I) may have thought. Try adjusting view point of the axis if you don't feel like that perticular view. Commented Apr 1, 2021 at 18:58
  • Not fussed about the labelling - this is a simplified bit of code, and I must have snuck something in by mistake. It's the order that the bars are displayed in on the right that's the problem. Matplotlib is rendering earlier bars behind later bars. Commented Apr 1, 2021 at 19:08
  • Yes, that's what I mean by direction of y being different. By default it's pointing inward as shown in the plot. If you want the different ordering, you will need to adjust the view point. Commented Apr 1, 2021 at 19:11
  • 2
    Ah, I see what you mean. Maybe bar3d is not playing well with np.nan, see if dz2 = data2.fillna(0).values.ravel() helps Commented Apr 1, 2021 at 19:16
  • 1
    Also try to filter out the nan values notnas = ~np.isnan(dz2) ; ax2.bar3d(xpos[notnas], ypos[notnas], zpos[notnas], dx, dy, dz2[notnas], shade=True, ec="k", lw=0.1) will not plot the nan as 0. Commented Apr 1, 2021 at 19:21

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.