Рисование прямоугольника или полосы между двумя точками на трехмерном графике рассеяния в Python и matplotlib

У меня есть трехмерный график рассеяния, который на одной из его плоскостей отображает 2 точки для каждой даты. Я спросил о том, как провести линию между каждой парой точек, и получил ответ, за который я благодарен. Теперь я хочу нарисовать БАР или ПРЯМОУГОЛЬНИК, чтобы соединить точки, а не просто линию.

Вот как выглядит график на данный момент, но я хочу, чтобы он немного походил на график из демонстрации 3D-бара из документов Matplolib, за исключением того, что столбцы "плавают" вместо привязки к оси.

Я пытался использовать 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()

3 ответа

Я думаю, что будет проще использовать 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()

Вы должны быть в состоянии сделать смесь между:

3D бар демо из документации Матплолиба

а также

Пример сложенного бара

то есть рисовать бары на трехмерном графике, но используйте параметр "bottom", чтобы установить начальную высоту ваших баров.

Alexis

Спасибо за вашу помощь Алексис и Марк. Я думаю, что это разобрано сейчас.

Я использовал подсказку Alexis для использования свойства 'zdir'.

Что касается проблемы с неправильной плоскостью, вы можете исправить ее с помощью параметра zdir, например, ax.bar(даты, максимумы,zdir='y', нижние = максимумы, zs=0, цвет = 'b') - Alexis

Сначала он генерировал бары, которые в два раза выше, чем они должны быть, потому что он измерял снизу (т.е. значение "минимумы"), а затем добавлял к нему высоту (из значения "максимумы").

Поэтому я закончил тем, что ввел новый список, "смещения", который измеряет расстояние между каждым максимумом и каждым минимумом (и в процессе обнаружил, что мои минимумы и максимумы менялись местами. Дух, извините за это). Так что теперь я строю смещения, а не максимумы.

Я добавил к строке Алексея ширину, выравнивание, цвет кромки и альфа (для прозрачности); затем утолщенные маркеры для графиков топора. Теперь код работает (ну, почти, за исключением того, что стрелка на 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()

Это результат:

участок

Другие вопросы по тегам