Создание водопада / линейного участка в Matpotlib с использованием трансформаций - PullRequest
0 голосов
/ 21 сентября 2018

Я пытаюсь построить серию сигналов таким образом, чтобы они равномерно распределялись вдоль оси y.Я считаю, что matplotlib.transforms это путь.У меня есть что-то элементарное, работающее с использованием этого кода:

import matplotlib.transforms
import matplotlib as mp
import numpy as np
import pylab as pl
%matplotlib inline

ax = pl.gca()
n_levels = 10
t = np.arange(1000)/1000

offset_step = 1/(n_levels + 1)
for i in range(n_levels):
    offset = offset_step * (i + 1)
    o = mp.transforms.ScaledTranslation(0, offset, ax.transAxes)
    trans = mp.transforms.blended_transform_factory(ax.transData, ax.transData + o)
    y = np.sin(t*2*np.pi*10*i)
    p, = ax.plot(t, y, 'k-', transform=trans)

ax.axis(ymin=0, ymax=25)

Это создает следующий график.

actual

Даже при том, что фактические смещения в координатах осей0,09 0,18 ... 0,82 0,91, линии явно не появляются с такими точными смещениями!Что я делаю не так?

Редактировать: Чтобы ответить на некоторые вопросы, касающиеся того, почему я не могу просто применить смещение в пространстве данных, а не использовать преобразование.Это более простая форма более сложного преобразования, которое мне нужно сделать, когда я хочу иметь возможность масштабировать амплитуду отдельных линий без необходимости регулировать пределы по оси Y.Для этого действительное y-преобразование:

boxin = mp.transforms.Bbox([[0, 0], [1, 1]])
boxout = mp.transforms.Bbox([[0, 0], [1, 1]])
y_trans = mp.transforms.BboxTransform(boxin, boxout) + \
    axes.transData + \
    mp.transforms.ScaledTranslation(0, offset_step * (i + 1), axes.transAxes)

Затем в моем интерактивном приложении я могу изменить масштабирование каждого отдельного сигнала, используя:

scale = 2
box = np.array([[0, 0], [scale, scale]])
boxout.set_points(box)
figure.canvas.redraw()

Это действительно работаетЧто ж.Однако для различных вариантов n_levels мне нужно изначально настроить ymin и ymax при генерации графика, чтобы гарантировать, что линии расположены на одинаковом расстоянии вдоль оси y.Желаемый результат:

desired

Ответы [ 2 ]

0 голосов
/ 22 сентября 2018

Поскольку масштаб оси y здесь, по-видимому, не имеет значения, вы можете просто следовать цепочке преобразований шаг за шагом

  1. Начните с виртуального поля вокруг данных, в данном случае с [-1, 1].
  2. Преобразовать в единицу площади
  3. Преобразовать в виртуальный ящик высотой offset_step.
  4. Перевести это поле на i*offset_step (возможно, добавитьнемного места внизу)
  5. Добавить преобразование осей (поскольку все это происходит в координатах осей)

Полный пример:

import matplotlib.transforms as mtrans
import matplotlib as mpl
import numpy as np
import matplotlib.pyplot as plt

ax = plt.gca()
n_levels = 10
t = np.arange(1000)/1000
T = t*2*np.pi*10

offset_step = 1/(n_levels+1)
space = 1.25 # set to 1 to have no space between lines

# Transform from a virtual box around the sine (-1 .. 1 in y direction)
tfrom = mtrans.BboxTransformFrom(mtrans.Bbox([[0, -1*space],[1, 1*space]]))
# Transform to a box (0 .. offset_step)
tto = mtrans.BboxTransformTo(mtrans.Bbox([[0, 0],[1,offset_step]]))


for i in range(n_levels):
    # offset = steps + half the remainder to full axes
    offset = offset_step * i + (1-n_levels*offset_step)/2.
    # Translate by offset
    translate = mtrans.Affine2D().translate(0,offset)
    # chain all transforms
    y_trans = tfrom + tto + translate + ax.transAxes
    trans = mpl.transforms.blended_transform_factory(ax.transData, y_trans)
    # plot
    p, = ax.plot(t, np.sin(T*i), transform=trans)

plt.show()

enter image description here

0 голосов
/ 21 сентября 2018

Проблема заключалась в том, что transData уже включает transAxes, поэтому, когда я создавал масштабированный перевод, я дважды преобразовывал на transAxes.Хитрость заключается в том, чтобы установить для y-преобразования значение transLimits + transScale + масштабированный перевод:

import matplotlib.transforms
import matplotlib as mp
import numpy as np
import pylab as pl
%matplotlib inline

ax = pl.gca()
n_levels = 10
t = np.arange(1000)/1000

offset_step = 1/(n_levels + 1)
for i in range(n_levels):
    offset = offset_step * (i + 1)
    o = mp.transforms.ScaledTranslation(0, offset, ax.transAxes)
    y_trans = ax.transLimits + ax.transScale + o
    trans = mp.transforms.blended_transform_factory(ax.transData, y_trans)
    y = np.sin(t*2*np.pi*10*i)
    p, = ax.plot(t, y, 'k-', transform=trans)

. Это генерирует:

plot

Что точночто я хочу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...