Search code examples
pythonmatplotlibpy2neo

How to create many 3D cylindrical plots on an axis system?


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.


Solution

  • 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