Как нарисовать блок по нескольким осям на matplotlib, используя положение топора в качестве эталона - PullRequest
4 голосов
/ 23 апреля 2019

Я хотел бы нарисовать прямоугольник на нескольких осях, используя координаты одного топора в качестве ориентира. Простой код, который я не генерирую, это

import matplotlib.pyplot as plt
import numpy as np

fig, (ax1, ax2) = plt.subplots(2, 1, sharex=False, sharey=False, figsize=(15,9))

x = 2 * np.pi * np.arange(1000) / 1000 
y1 = np.sin(x)
y2 = np.cos(x)

ax1.plot(x,y1)
ax2.plot(x,y2)
plt.show()

Это генерирует следующий рисунок:

enter image description here

Я хотел бы получить следующий рисунок, используя x кординаты из ax2 для указания позиции:

enter image description here

Ответы [ 2 ]

1 голос
/ 23 апреля 2019

Вопрос в том, какой цели должен служить прямоугольник.Если это просто прямоугольник, связанный с ax2, но простирающийся до верхнего края ax1, можно создать прямоугольник, например

import matplotlib.pyplot as plt
import numpy as np

fig, (ax1, ax2) = plt.subplots(2, 1, sharex=False, sharey=False, figsize=(15,9))

x = 2 * np.pi * np.arange(1000) / 1000 
y1 = np.sin(x)
y2 = np.cos(x)

ax1.plot(x,y1)
ax2.plot(x,y2)

rect = plt.Rectangle((1,0), width=1, height=2+fig.subplotpars.wspace,
                     transform=ax2.get_xaxis_transform(), clip_on=False,
                     edgecolor="k", facecolor="none", linewidth=3)
ax2.add_patch(rect)

plt.show()

enter image description here

Но это, конечно, останется там, где оно есть, даже если пределы ax1 изменятся.Это желаемое?

Так что, возможно, более интересное решение - это то, где прямоугольник следует координатам в обеих осях.Следующее будет работать только в Matplotlib 3.1, который на сегодняшний день доступен только в качестве предварительного выпуска
(pip install --pre --upgrade matplotlib)

import matplotlib.pyplot as plt
from matplotlib.patches import ConnectionPatch
import numpy as np

fig, (ax1, ax2) = plt.subplots(2, 1, sharex=False, sharey=False, figsize=(15,9))

x = 2 * np.pi * np.arange(1000) / 1000 
y1 = np.sin(x)
y2 = np.cos(x)

ax1.plot(x,y1)
ax2.plot(x,y2)

def rectspan(x1, x2, ax1, ax2, **kwargs):
    line1, = ax1.plot([x1, x1, x2, x2],[0,1,1,0], 
                      transform=ax1.get_xaxis_transform(), **kwargs)
    line2, = ax2.plot([x1, x1, x2, x2],[1,0,0,1], 
                      transform=ax2.get_xaxis_transform(), **kwargs)
    for x in (x1, x2):
        p = ConnectionPatch((x,1), (x,0), 
                            coordsA=ax2.get_xaxis_transform(),
                            coordsB=ax1.get_xaxis_transform(), **kwargs)
        ax1.add_artist(p)

rectspan(1, 2, ax1, ax2, color="k", linewidth=3)
plt.show()

enter image description here

1 голос
/ 23 апреля 2019

Определенно есть более простой способ сделать это с помощью патча Rectangle, но это временное решение. Идея состоит в том, чтобы иметь 4 строки: 2 горизонтальные, которые ограничены ax1 и ax2 соответственно, и 2 вертикальные, которые охватывают ax1 и ax2. Для последних двух вы используете ConnectionPatch, охватывающий обе оси. Чтобы иметь верхнее и нижнее значение y для горизонтальных и вертикальных линий, вы используете функцию get_ylim(). Идея построения вертикальных линий пришла от этого официального примера и этого ответа от ImportanceOfBeingErnest

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import ConnectionPatch

fig, (ax1, ax2) = plt.subplots(2, 1, sharex=False, sharey=False, figsize=(15,9))

x = 2 * np.pi * np.arange(1000) / 1000 
y1 = np.sin(x)
y2 = np.cos(x)

ax1.plot(x,y1)
ax2.plot(x,y2)

y_up, y_down = ax1.get_ylim(), ax2.get_ylim()

ax1.hlines(max(y_up), 1, 2, linewidth=4)
ax2.hlines(min(y_down), 1, 2, linewidth=4)

line1 = ConnectionPatch(xyA=[1,min(y_down)], xyB=[1,max(y_up)], coordsA="data", coordsB="data",
                      axesA=ax2, axesB=ax1, color="k", lw=4)
line2 = ConnectionPatch(xyA=[2,min(y_down)], xyB=[2,max(y_up)], coordsA="data", coordsB="data",
                      axesA=ax2, axesB=ax1, color="k", lw=4)

ax2.add_artist(line1)
ax2.add_artist(line2)

plt.show()

enter image description here

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