Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing a rectangle or bar between two points in a 3D scatter plot in Python and matplotlib

I have a 3D scatter plot which, on one of its planes, plots 2 points for each date. I've asked about how to draw a LINE between every pair of points, and received an answer for which I'm thankful. What I want now is to draw a BAR or a RECTANGLE to connect the points instead of just a line.

Here's what the plot looks like at the moment, but I want it to look a bit like the plot from the 3D bar demo from matplolib's docs except with the bars "floating" instead of anchored to the axis.

I've tried using Axes3D.bar (as explained on the matplotlib page) but it expects me to supply a "height" for each bar instead of two actual coordinates, and that height will be anchored to the axis.

This is the code, and any help is appreciated.

import matplotlib.pyplot
from mpl_toolkits.mplot3d import Axes3D

dates       = [20020514, 20020515, 20020516, 20020517, 20020520]
highs       = [1135, 1158, 1152, 1158, 1163]
lows        = [1257, 1253, 1259, 1264, 1252]
upperLimits = [1125.0, 1125.0, 1093.75, 1125.0, 1125.0]
lowerLimits = [1250.0, 1250.0, 1156.25, 1250.0, 1250.0]

zaxisvalues0= [0, 0, 0, 0, 0]
zaxisvalues1= [1, 1, 1, 1, 1]
zaxisvalues2= [2, 2, 2, 2, 2]

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

ax.plot(dates, zaxisvalues1, lowerLimits, color = 'b')
ax.plot(dates, zaxisvalues2, upperLimits, color = 'r')

for i,j,k,h in zip(dates,zaxisvalues0,lows,highs):
    ax.plot([i,i],[j,j],[k,h],color = 'g')

ax.scatter(dates, zaxisvalues0, highs, color = 'g', marker = "o")
ax.scatter(dates, zaxisvalues0, lows, color = 'y', marker = "^")

matplotlib.pyplot.show()
like image 821
Zambi Avatar asked Jan 16 '23 16:01

Zambi


2 Answers

I think it'll be easier to use a PolyCollection. Is this close to what you are after?

enter image description here

import matplotlib.pyplot
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.collections import PolyCollection
import random

dates       = [20020514, 20020515, 20020516, 20020517, 20020520]
highs       = [1135, 1158, 1152, 1158, 1163]
lows        = [1257, 1253, 1259, 1264, 1252]
upperLimits = [1125.0, 1125.0, 1093.75, 1125.0, 1125.0]
lowerLimits = [1250.0, 1250.0, 1156.25, 1250.0, 1250.0]

zaxisvalues0= [0, 0, 0, 0, 0]
zaxisvalues1= [1, 1, 1, 1, 1]
zaxisvalues2= [2, 2, 2, 2, 2]

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

ax.plot(dates, zaxisvalues1, lowerLimits, color = 'b')
ax.plot(dates, zaxisvalues2, upperLimits, color = 'r')

verts = []; fcs = []
for i in range(len(dates)-1):
   xs = [dates[i],dates[i+1],dates[i+1],dates[i],dates[i]] # each box has 4 vertices, give it 5 to close it, these are the x coordinates
   ys = [highs[i],highs[i+1],lows[i+1],lows[i], highs[i]]  # each box has 4 vertices, give it 5 to close it, these are the y coordinates
   verts.append(zip(xs,ys))
   fcs.append((random.random(),random.random(),random.random(),0.6))

poly = PolyCollection(verts, facecolors = fcs, closed = False)
ax.add_collection3d(poly, zs=[zaxisvalues0[0]] * len(verts), zdir='y') # in the "z" just use the same coordinate

ax.scatter(dates, zaxisvalues0, highs, color = 'g', marker = "o")
ax.scatter(dates, zaxisvalues0, lows, color = 'y', marker = "^")

matplotlib.pyplot.show()
like image 97
Mark Avatar answered Jan 30 '23 19:01

Mark


You should be able to make a mix between:

3D bar demo from matplolib's docs

and

Bar stacked example

ie to draw bars in a 3D graph, but use the "bottom" parameter to set the starting heigh of your bars.

Alexis

like image 30
Alexis Avatar answered Jan 30 '23 19:01

Alexis