【问题标题】:Drawing a rectangle or bar between two points in a 3D scatter plot in Python and matplotlib在 Python 和 matplotlib 中的 3D 散点图中的两点之间绘制矩形或条形
【发布时间】:2012-05-15 11:41:16
【问题描述】:

我有一个 3D 散点图,它在其中一个平面上为每个日期绘制 2 个点。我已经问过about how to draw a LINE between every pair of points,并收到了我很感激的答案。我现在想要的是绘制一个 BAR 或 RECTANGLE 来连接点,而不仅仅是一条线。

我尝试使用 Axes3D.bar(如 matplotlib 页面上所述),但它希望我为每个条形提供一个“高度”而不是两个实际坐标,并且该高度将锚定到轴上。

这是代码,感谢任何帮助。

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()

【问题讨论】:

    标签: python matplotlib mplot3d


    【解决方案1】:

    我认为使用 PolyCollection 会更容易。这是否接近您所追求的?

    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()
    

    【讨论】:

    • 谢谢。尽管这不是我希望实现的目标,但您的代码确实令人大开眼界。我应该阅读 PolyCollections 课程。非常感谢您评论代码 - 它真的很有帮助。通过返回原始代码并将“linewidth = 5”添加到 for 循环中的 ax.plot 命令,我已经接近了我想要的。它画了一条线,但足够粗,看起来像条形/矩形。
    【解决方案2】:

    您应该能够混合使用:

    3D bar demo from matplolib's docs

    Bar stacked example

    即在 3D 图表中绘制条形图,但使用“bottom”参数设置条形图的起始高度。

    亚历克西斯

    【讨论】:

    • 感谢您的提示,但我无法让它工作。我尝试用以下代码替换原始代码中的 Mark for 循环:ax.bar(dates, zaxisvalues2, highs) 但它在错误的平面上绘制了条形图。我尝试了 zaxisvalue0 和 zaxisvalues1,我尝试改组顺序,但到目前为止没有运气。
    • 也许这就是你要找的hist3D example。然后,您可以使用 zpos 设置框的最低边缘(例如,获取 hist3D 示例并将第 16 行更改为 zpos = hist.flatten() )。
    • 对于错误平面问题,可以通过参数zdir来修复,例如ax.bar(dates, highs,zdir='y',bottom=highs, zs=0,颜色 = 'b')
    【解决方案3】:

    感谢亚历克西斯和马克的帮助。我想现在已经解决了。

    我使用 Alexis 的提示来使用 'zdir' 属性。

    至于错平面问题,可以通过参数zdir修复, 例如 ax.bar(dates, highs,zdir='y',bottom=highs, zs=0, color = 'b') – Alexis

    起初,它生成的柱线高度是应有的两倍,因为它是从底部测量的(即“低点”值),然后向其添加一个高度(从“高点”值开始)。

    所以我最终引入了一个新列表“位移”,它测量每个高点和每个低点之间的距离(在此过程中发现我的低点和高点互换了。呃,抱歉)。所以现在我正在绘制“位移”而不是高点。

    我为 Alexis 的线条添加了宽度、对齐方式、边缘颜色和 alpha(用于透明度);然后加厚了 ax.scatter 图的标记。现在代码可以工作了(嗯,几乎,除了第 4 条上的箭头高于它应该是......嗯)

    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()
    

    这是结果:

    【讨论】:

    • 赞比,你的第四个箭头的最后一个问题来自你的 for 循环:你在低点有重复的值,所以 lows.index(i) 总是返回 1for 1158。更改 for i in range(len(lows)):\\ disp = highs[i] - lows[i]
    • 谢谢亚历克西斯。你刚刚为我节省了几个小时试图修复第 4 个小节的时间。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 2022-01-02
    • 2013-08-06
    • 2019-02-03
    • 2013-07-07
    相关资源
    最近更新 更多