2

I have a table that contains three different time characteristics according to two different parameters. I want to plot those parameters on x and y-axis and show bars of the three different times on the z-axis. I have created a simple bar plot where I plot one of the time characteristics:

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

columns = ['R','Users','A','B','C']

df=pd.DataFrame({'R':[2,2,2,4,4,4,6,6,6,8,8],
              'Users':[80,400,1000,80,400,1000,80,400,1000,80,400],
              'A':[ 0.05381,0.071907,0.08767,0.04493,0.051825,0.05295,0.05285,0.0804,0.0967,0.09864,0.1097],
             'B':[0.04287,0.83652,5.49683,0.02604,.045599,2.80836,0.02678,0.32621,1.41399,0.19025,0.2111],
                'C':[0.02192,0.16217,0.71645, 0.25314,5.12239,38.92758,1.60807,262.4874,8493,11.6025,6288]},
                 columns=columns)



fig = plt.figure()
ax = plt.axes(projection="3d")

num_bars = 11
x_pos = df["R"]
y_pos = df["Users"]
z_pos = [0] * num_bars
x_size = np.ones(num_bars)/4
y_size = np.ones(num_bars)*50
z_size = df["A"]

ax.bar3d(x_pos, y_pos, z_pos, x_size, y_size, z_size, color='aqua')
plt.show()

This produces a simple 3d barplot:

enter image description here

However, I would like to plot similar bars next to the existing ones for the rest two columns (B and C) in a different color and add a plot legend as well. I could not figure out how to achieve this.

As a side question, is it as well possible to show only values from df at x- and y-axis? The values are 2-4-6-8 and 80-400-1000, I do not wish pyplot to add additional values on those axis.

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Ruli
  • 2,592
  • 12
  • 30
  • 40
  • How would you like to handle the fact that your data points span very large ranges? If you simply plot your values as given, the very large values (e.g. 8493) will shadow all small values (e.g. 0.02192). – David M. Feb 13 '21 at 13:38
  • @DavidM. I am aware of that, I will probably change it to log scale after I solve this – Ruli Feb 13 '21 at 16:36

1 Answers1

4

I have managed to find a solution myself. To solve the problem with values I have added one to all times (to avoid negative log) and used np.log on all time columns. The values got on scale 0-10 this way and the plot got way easier to read. After that I used loop to go over each column and create corresponding values, positions and colors which I have added all to one list. I moved y_pos for each column so the columns do not plot on same position.

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

columns = ['R','Users','A','B','C']

df=pd.DataFrame({'R':[2,2,2,4,4,4,6,6,6,8,8],
              'Users':[80,400,1000,80,400,1000,80,400,1000,80,400],
              'A':[ 0.05381,0.071907,0.08767,0.04493,0.051825,0.05295,0.05285,0.0804,0.0967,0.09864,0.1097],
             'B':[0.04287,0.83652,5.49683,0.02604,.045599,2.80836,0.02678,0.32621,1.41399,0.19025,0.2111],
                'C':[0.02192,0.16217,0.71645, 0.25314,5.12239,38.92758,1.60807,262.4874,8493,11.6025,6288]},
                 columns=columns)

fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection="3d")

df["A"] = np.log(df["A"]+1)
df["B"] = np.log(df["B"]+1)
df["C"] = np.log(df["C"]+1)

colors = ['r', 'g', 'b']

num_bars = 11
x_pos = []
y_pos = []
x_size = np.ones(num_bars*3)/4
y_size = np.ones(num_bars*3)*50
c = ['A','B','C']
z_pos = []
z_size = []
z_color = []
for i,col in enumerate(c):
    x_pos.append(df["R"])
    y_pos.append(df["Users"]+i*50)
    z_pos.append([0] * num_bars)
    z_size.append(df[col])
    z_color.append([colors[i]] * num_bars)
    
x_pos = np.reshape(x_pos,(33,))
y_pos = np.reshape(y_pos,(33,))
z_pos = np.reshape(z_pos,(33,))
z_size = np.reshape(z_size,(33,))
z_color = np.reshape(z_color,(33,))

ax.bar3d(x_pos, y_pos, z_pos, x_size, y_size, z_size, color=z_color)

plt.xlabel('R')
plt.ylabel('Users')
ax.set_zlabel('Time')

from matplotlib.lines import Line2D

legend_elements = [Line2D([0], [0], marker='o', color='w', label='A',markerfacecolor='r', markersize=10),
                  Line2D([0], [0], marker='o', color='w', label='B',markerfacecolor='g', markersize=10),
                   Line2D([0], [0], marker='o', color='w', label='C',markerfacecolor='b', markersize=10)
                  ]
                   
# Make legend
ax.legend(handles=legend_elements, loc='best')
# Set view
ax.view_init(elev=35., azim=35)
plt.show()

Final plot:

enter image description here

Ruli
  • 2,592
  • 12
  • 30
  • 40