3d bar chart with dataframe

80 views Asked by At

datadata.csv(Pandas DataFrame)

Item    Action  Cost
Item1   UK  100
Item2   USA 425
Item3   China   4587
Item4   USA 1234
Item5   China   1705
Item6   USA 870
Item7   China   1578
Item8   UK  3721
Item9   UK  4107
Item10  UK  1527
Item11  USA 770

My code is...

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

# CSV 파일 읽기
data = pd.read_csv('datadata.csv')


xpos=np.arange(data.shape[0])
ypos=np.arange(data.shape[1])
zpos=np.zeros(data.shape).flatten()

dx = 0.5 * np.ones_like(zpos)
dy= 0.1 * np.ones_like(zpos)
dz = row['Cost']

# bar3d
fig = plt.figure(figsize=(12,9))
ax = fig.add_subplot(111, projection='3d')

# color
values = np.linspace(0.2, 1., data.shape[0])
cmaps = [cm.Blues, cm.Reds, cm.Greens]
colors = np.hstack([c(values) for c in cmaps]).reshape(-1, 4)

ax.bar3d(xposM.ravel(),yposM.ravel(),zpos,dx,dy,dz,color=colors, alpha=0.5)


# x, y, z Lable
ax.set_xlabel('Item')
ax.set_ylabel('Action')
ax.set_zlabel('Cost')


# x, y, z  tick 
ticks_x = np.arange(0.2, 11, 1)
ax.set_xticks(ticks_x)
ticks_y=np.arange(0.6,3,1)
ax.set_yticks(ticks_y)
ax.set_xticklabels(['Item1', 'Item2', 'Item3', 'Item4', 'Item5', 'Item6', 'Item7',
       'Item8', 'Item9', 'Item10', 'Item11'])
ax.set_xlim(0,11)
ax.set_yticklabels(['UK', 'USA', 'China'])
ax.set_ylim(0,3)
ax.set_zlim(0,4000)


plt.show()

What I got...

enter image description here

The z-axis data is not displayed accurately. How Can I draw bar3d with dataframe.

What I want to draw

enter image description here

1

There are 1 answers

0
Ratislaus On

It looks like there are multiple issues in your code. For example, the names "row", "xposM", "yposM" are not defined. Anyway, you need to extract unique action names from your data file and build the respective coordinate matrices for bar3d based on the number of those unique action names and the number of item names:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from collections import Counter

# read data from the CSV file
data = pd.read_csv('datadata.csv', delimiter='\t')

# get all cost values and their maximum
costs = data['Cost']
max_cost = max(costs)

# get all item values and their number
items = data['Item']
items_num = len(items)

# get all action values
all_actions = data['Action']

# get unique action values and their number
actions_nums = Counter(all_actions)
actions = list(actions_nums.keys())
actions_num = len(actions)

# make a list of coordinate matrices with values equal to indexes of data cells
_xx, _yy = np.meshgrid(np.arange(items_num), np.arange(actions_num))
# turn those matrices into contiguous flattened arrays, suitable for bar3d
x, y = _xx.ravel(), _yy.ravel()

# the number of color gradients should be equal to the number of actions
# TODO: generate this list automatically, depending on the number of unique action values
cmaps = [cm.Blues, cm.Reds, cm.Greens]

# make top values together with action-dependent colors (having item-dependent intensities) for all elements in coordinate matrices
top = []
colors = []
colors_values = np.flip(np.linspace(0.2, 1., items_num))

for i, a in zip(x, y):
    # not all actions are present for every item, so make data only for those available
    if all_actions[i] == actions[a]:
        cost = costs[i]
        top.append(cost)
        colors.append(cmaps[a](colors_values[i]))
    else:
        top.append(0) # absent data
        colors.append(cm.Greys(0))  # some default color for absent data

# bottom values are all zeros
bottom = np.zeros_like(top)

# width and depth values are the same for all bars
width = 0.5
depth = 0.1

# bar3d
fig = plt.figure(figsize=(12, 9))
ax = fig.add_subplot(111, projection='3d')
ax.bar3d(x, y, bottom, width, depth, top, color=colors, alpha=0.5)

# x, y, z labels
ax.set_xlabel('Item')
ax.set_ylabel('Action')
ax.set_zlabel('Cost')

# x, y, z  ticks
ticks_x = np.arange(0.2, items_num, 1)
ax.set_xticks(ticks_x)
ticks_y = np.arange(0.6, actions_num, 1)
ax.set_yticks(ticks_y)

# tick labels are based on the available item and action names
ax.set_xticklabels(items)
ax.set_yticklabels(actions)

# limits are based on the maximum values of the available item and action names as well as cost values
ax.set_xlim(0, items_num)
ax.set_ylim(0, actions_num)
ax.set_zlim(0, max_cost)

plt.show()

Voilà:

enter image description here