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()
I think it'll be easier to use a PolyCollection. Is this close to what you are after?
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()
You should be able to make a mix between:
3D bar demo from matplolib's docs
and
ie to draw bars in a 3D graph, but use the "bottom" parameter to set the starting heigh of your bars.
Alexis
Thanks for your help Alexis and Mark. I think it's sorted out now.
I've used Alexis' tip for using the 'zdir' property.
As for the wrong plane problem, you can fix it with parameter zdir, for instance ax.bar(dates, highs,zdir='y',bottom=highs, zs=0, color = 'b') – Alexis
At first it was generating bars that are twice as high as they should be, because it was measuring from the bottom (ie the 'lows' value) and then ADDING to it a height (from the 'highs' value).
So I ended up introducing a new list, 'displacements', which measures the distance between each high and each low (and in the process discovered that I had my lows and highs swapped around. Duh, sorry about that). So now I'm plotting 'displacements' rather than highs.
I added to Alexis' line a width, alignment, edgecolor and alpha (for transparency); then thickened the markers for the ax.scatter plots. Now the code works (well, almost, except for that arrow on the 4th bar being higher than it should be... hmmm)
import matplotlib.pyplot
from mpl_toolkits.mplot3d import Axes3D
dates = [20020514, 20020515, 20020516, 20020517, 20020520]
lows = [1135, 1158, 1152, 1158, 1163]
highs = [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')
ax.scatter(dates, zaxisvalues0, highs, color = 'g', marker = "^", linewidth=4)
ax.scatter(dates, zaxisvalues0, lows, color = 'y', marker = "o", linewidth=4)
displacements = []
for i in lows:
position = lows.index(i)
disp = highs[position] - i
displacements.append(disp)
ax.bar(dates, displacements, zdir='y', bottom=lows, zs=0, width=0.2, align='center', alpha=0.6, edgecolor='k')
matplotlib.pyplot.show()
This is the result:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.