1

Assuming that I have three Python pandas DataFrames:

df_sale = pd.DataFrame([[20,30,10], [30,20,20], [20,40,40]], columns=list("ABC"))

    A   B   C
0   20  30  10
1   30  20  20
2   20  40  40

df_people = pd.DataFrame([[2,3,1], [3,2,2], [2,4,4]], columns=list("ABC"))

    A   B   C
0   2   3   1
1   3   2   2
2   2   4   4

df_department = pd.DataFrame([[1,2,1], [1,1,2], [2,1,1]], columns=list("ABC"))

    A   B   C
0   1   2   1
1   1   1   2
2   2   1   1

How do I plot a 3D bar chart with all these 3 dataframes in the same place?

I want the X axis to be ['A', 'B', 'C'], Y axis to be the name of dataframes ['df_sale', 'df_people', 'df_department'], and Z axis to show the numbers.

1 Answer 1

2

You could use matplotlib's 3D bars.

import pandas as pd
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt

columns = ['A', 'B', 'C']
df_names = ['sale', 'people', 'department']
df = [pd.DataFrame([[20,30,10], [30,20,20], [20,40,40]], columns=columns), pd.DataFrame([[2,3,1], [3,2,2], [2,4,4]], columns=columns), pd.DataFrame([[1,2,1], [1,1,2], [2,1,1]], columns=columns)]

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

#make sure x and y axis get the right tick labels
plt.xticks([i for i in range(len(columns))], columns)
plt.yticks([i for i in range(len(df_names))], df_names)

#define a list for x positions
xs = list()
for i in range(len(df)):
    for j in range(len(columns)):
         xs.append(i + j * 0.1)

for c1, c in enumerate(['r', 'g', 'b']):
    ys = list()
    for i in range(len(columns)):
        ys.extend(df[c1].ix[:,i:i+1].unstack().tolist())
    cs = [c] * len(xs)    
    ax.bar(xs, ys, zs=c1, zdir='y', color=cs, alpha=0.5, width=0.1)

plt.show()

enter image description here


Multicolors and legend

import matplotlib
colors = ['r', 'g', 'b', 'c', 'm', 'y', '#eeefff', '#feefff', '#aeefff']
for c1 in range(3):
    ys = list()
    for i in range(len(columns)):
        ys.extend(df[c1].ix[:,i:i+1].unstack().tolist())
    ax.bar(xs, ys, zs=c1, zdir='y', color=colors, alpha=0.5, width=0.1)

legend = list()
for i, c in enumerate(colors):
    legend.append(matplotlib.patches.Patch(color=c, label='value {0} of column {1}'.format(i % 3, columns[i // 3])))
plt.legend(handles=legend, loc=4, bbox_to_anchor=(.9, 0), mode="expand")
plt.show()

enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

Hi Max, thanks for your answer and this solves most of my questions. But I wonder what if the index names are not number [0,1,2,3...]. df[c1].ix[:,i:i+1] this part only works with numbers. Also, is there a way to color the three bars together with different colors? e.g. the bars fall under 'A', 'Sales'. What if we want to color them as red, green blue. Since they may represent time (Jan, Feb, Mar). And the same colors apply to people and department. And in the end we add legend for the colors. Is this doable? Thanks!
pandas ix documentation: "A primarily label-location based indexer, with integer position fallback", i.e. you are good.

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.