0

Are there libraries or methods in python that are capable of creating plots that look like this? (preferably based around MatPlotLib for the sake of embedding the plots in HTML pages) Prospective plot

My goal is to create 3D renderings of data that is read from a Neo4J database and model them as the cylinders above.

HaskellElephant
  • 9,819
  • 4
  • 38
  • 67
  • You should read [What topics can I ask about here?](https://stackoverflow.com/help/on-topic) especially #4 "Questions asking us to recommend or find a ... software library ... or other off-site resource are off-topic for Stack Overflow." Having said that matplotlib has 3D plotting abilities but [this not without problems](https://matplotlib.org/mpl_toolkits/mplot3d/faq.html) and they recommend Mayavi. – Mr. T Jul 17 '18 at 17:18

1 Answers1

2

The code below attempts to create a similar 3D plot (not cylindrical but rectangular) with legends from a dataframe. The plot is interactive. Resources: 1, 2, 3, 4 (Jupyter Notebook 5.0.0, Python 3.6.6)

Import libraries

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from mpl_toolkits.mplot3d import axes3d  
import matplotlib.patches as mpatches # for legends
%matplotlib notebook

Create a sample dataframe

# Create two sets of identical xpos and ypos 
# So taht the z-values are plotted at same location for stacking
xtemp = np.random.randint(1, 10, size=5)
ytemp = np.random.randint(1, 10, size=5)

df = pd.DataFrame({
    # category
    'season': ['S1']*5 + ['S2']*5 + ['S3']*5,
    #'wins': np.random.randint(1, 10, size=15),
    # define pos
    'xpos' : list(xtemp)+list(xtemp)+list(xtemp),
    'ypos' : list(ytemp)+list(ytemp)+list(ytemp),
    'zpos' : np.zeros(15),
    # define delta
    'dx': 0.8*np.ones(15),
    'dy': 0.8*np.ones(15),
    'dz': np.random.randint(1, 5, size=15), #np.ones(15)

})
df.head(5)

enter image description here

Plot the figure

Note: Figure are in two parts: (1) 2D plot for the N-S, E-W lines and (2) 3D bar plot

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

# ..................
# Line-1 on x-y plane
x = [4, 4]
y = [-3, 12]
ax.plot(x, y, zs=0, zdir='z', color='orange', alpha=0.8)


# Line-2 on x-y plane
y = [4, 4]
x = [-3, 12]
ax.plot(x, y, zs=0, zdir='z', color='blue', alpha=0.5)


# Creat multiple overlap plots within a loop

color = ['#6495ED', '#6E8B3D', '#FFB90F']
slist = ['S1', 'S2', 'S3']
stack_zpos = pd.Series(np.zeros(5)) 
for i in range(0,3):
    q = df[df['season']==slist[i]].reset_index(inplace=False)
    ax.bar3d(q.xpos, q.ypos, stack_zpos, q.dx, q.dy, q.dz, color=color[i], alpha=1)
    stack_zpos += q.dz  # values added here for stacking

Annotate lines and remove z-axis panes and grid lines

# Remove the z-axis panes, grids and lines
alpha = 0
ax.w_xaxis.set_pane_color((1.0, 1.0, 1.0, alpha))
ax.w_yaxis.set_pane_color((1.0, 1.0, 1.0, alpha))
#
ax.zaxis._axinfo["grid"]['color'] = (1.0, 1.0, 1.0, alpha)
ax.w_yaxis._axinfo["grid"]['linewidth'] = 0
ax.w_xaxis._axinfo["grid"]['linewidth'] = 0
#
ax.w_zaxis.line.set_lw(0.)
ax.set_zticks([])
#
ax.set_zlabel("") # remove z-axis label 'z'

# ..........
# Annotate the N, S, E, W lines on the x-y plane
zdirs = (None, 'x', 'y', 'z', (1, 1, 0), (1, 1, 1))
xs = (4, 4, -3, 12)
ys = (-3,12, 4, 4)
zs = (0, 0, 0, 0)

i=0 # Counter
nsew = ['N', 'S', 'E', 'W'] # list of labels
for zdir, x, y, z in zip(zdirs, xs, ys, zs):
    label = '{0}'.format(nsew[i])
    #label = 'N, S, E, W' #% (x, y, z, zdir)
    ax.text(x, y, z, label, zdir)
    i +=1 

Create and add legends to the plot

# Add legend
patch1 = mpatches.Patch(color=color[0], label=slist[0])
patch2 = mpatches.Patch(color=color[1], label=slist[1])
patch3 = mpatches.Patch(color=color[2], label=slist[2])

plt.legend(handles=[patch1, patch2,patch3])

Visualize plot

plt.show()

enter image description here

Nilesh Ingle
  • 1,777
  • 11
  • 17