Работая над улучшением ответа на этот вопрос , я зашел в тупик.
Чего я хочу добиться , так это создать «искусственный» 3D-водопад в matplotlib
, где отдельные линейные графики (или, возможно, любой другой тип графика) смещены в пиксельных координатах фигуры и нанесены позади друг с другом. Эта часть уже работает нормально, и, используя мой пример кода (см. Ниже), вы сможете построить десять эквивалентных линий, которые смещены на fig.dpi/10.
в направлениях x и y и нанесены друг за другом через zorder
.
Обратите внимание, что я также добавил fill_between()
, чтобы сделать "глубинный сигнал" zorder
более заметным.

Где я застрял - это то, что я хотел бы добавить «третью ось», то есть линию (позже, возможно, отформатированную с некоторыми галочками), которая правильно выравнивается с основанием (то есть [0 , 0] в единицах данных) каждой строки.
Эта проблема, возможно, еще более осложняется тем фактом, что это не одноразовая вещь (т. Е. Решения не должны работать только в статических пиксельных координатах), а должны корректно вести себя при масштабировании, особенно при интерактивной работе .
Как видите, настройка, например, xlim
позволяет изменять масштаб строк «как ожидалось» (лучше всего, если вы попробуете это интерактивно), но красная линия (будущая ось), которую я пытался вставить, не транспонируется так же, как основы каждого линейный участок.
То, что я не ищу - это решения, основанные на mpl_toolkits.mplot3d
Axes3D
, так как это приведет к множеству других проблем , касающихся zorder и zoom, это именно то, чего я пытаюсь избежать, придумав свой собственный «фальшивый 3D-сюжет».
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.transforms import Affine2D,IdentityTransform
def offset(myFig,myAx,n=1,xOff=60,yOff=60):
"""
this function will apply a shift of n*dx, n*dy
where e.g. n=2, xOff=10 would yield a 20px offset in x-direction
"""
## scale by fig.dpi to have offset in pixels!
dx, dy = xOff/myFig.dpi , yOff/myFig.dpi
t_data = myAx.transData
t_off = mpl.transforms.ScaledTranslation( n*dx, n*dy, myFig.dpi_scale_trans)
return t_data + t_off
fig,axes=plt.subplots(nrows=1, ncols=3,figsize=(10,5))
ys=np.arange(0,5,0.5)
print(len(ys))
## just to have the lines colored in some uniform way
cmap = mpl.cm.get_cmap('viridis')
norm=mpl.colors.Normalize(vmin=ys.min(),vmax=ys.max())
## this defines the offset in pixels
xOff=10
yOff=10
for ax in axes:
## plot the lines
for yi,yv in enumerate(ys):
zo=(len(ys)-yi)
ax.plot([0,0.5,1],[0,1,0],color=cmap(norm(yv)),
zorder=zo, ## to order them "behind" each other
## here we apply the offset to each plot:
transform=offset(fig,ax,n=yi,xOff=xOff,yOff=yOff)
)
### optional: add a fill_between to make layering more obvious
ax.fill_between([0,0.5,1],[0,1,0],0,
facecolor=cmap(norm(yv)),edgecolor="None",alpha=0.1,
zorder=zo-1, ## to order them "behind" each other
## here we apply the offset to each plot:
transform=offset(fig,ax,n=yi,xOff=xOff,yOff=yOff)
)
##################################
####### this is the important bit:
ax.plot([0,2],[0,2],color='r',zorder=100,clip_on=False,
transform=ax.transData+mpl.transforms.ScaledTranslation(0.,0., fig.dpi_scale_trans)
)
## make sure to set them "manually", as autoscaling will fail due to transformations
for ax in axes:
ax.set_ylim(0,2)
axes[0].set_xlim(0,1)
axes[1].set_xlim(0,2)
axes[2].set_xlim(0,3)
### Note: the default fig.dpi is 100, hence an offset of of xOff=10px will become 30px when saving at 300dpi!
# plt.savefig("./test.png",dpi=300)
plt.show()
Обновление:
Теперь я включил анимацию ниже, которая показывает, как сложенные линии ведут себя при масштабировании / панорамировании, и как их «базовая линия» (синие кружки) перемещается вместе с графиком вместо статического решения OriginLineTrans
(зеленая линия). ) или моя преобразованная линия (красная, пунктирная).
Точки присоединения наблюдают различные преобразования и могут быть вставлены с помощью:
ax.scatter([0],[0],edgecolors="b",zorder=200,facecolors="None",s=10**2,)
ax.scatter([0],[0],edgecolors="b",zorder=200,facecolors="None",s=10**2,transform=offset(fig,ax,n=len(ys)-1,xOff=xOff,yOff=yOff),label="attachment points")
