Почему я не могу применить диапазон осей масштабирования к двойной оси, как я могу диапазон панорамирования, для интерактивного сюжета matplotlib? - PullRequest
0 голосов
/ 16 октября 2019

Приведенный ниже пример кода изменен на основе Matplotlib: Определение xlim и ylim после увеличения

По сути, в этом примере я хочу иметь двойную ось x;и я хочу, чтобы вторая (удвоенная) ось х вела себя как оригинальная. Таким образом, ссылка использует обратный вызов, чтобы сделать это. Однако:

  • Пока я только панорамирую сюжет, все в порядке - двойная копия синхронизируется с исходной осью X
  • После масштабирования - что-то идет не так, и, видимо,неверный диапазон применяется к двойной оси - ДАЖЕ ЕСЛИ при печати диапазонов в обратном вызове дает ожидаемый диапазон для чертежа после масштабирования
  • Как только я начинаю перетаскивать после масштабирования, две оси перетаскиваются соответственно - однакоТак как исходное условие предыдущего шага неверно, то есть эта часть
  • Теперь я добавил дополнительный вызов для обратного вызова при отпускании кнопки - поэтому, как только я освобождаю кнопку от движения перетаскивания, ТОГДА две оси снова синхронизируются ?? !!

Вот анимированный GIF (Matplotlib 3.1.1, Python 3.7.4 на MSYS2 / MINGW64 на Windows 10):

enter image description here

Я действительно, действительно не понимаю этого. Почему, когда я просто перемещаю / перетаскиваю график, ax.get_xlim() дает правильные числа, а ax22.set_xlim() применяет их - но когда я zoom сюжет, ax.get_xlim() дает правильные числа, но ax22.set_xlim() НЕ применяет их (точнее, применяет их, но поздно - то есть применяет данные из предыдущего запроса в текущем запросе) ???? !!! Что это за колдовство?!

И как я могу настроить двойной ax22 для синхронизации с исходной осью ax, независимо от того, перетаскиваю ли я или увеличиваю в интерактивном режиме?

код:

#!/usr/bin/env python3

import matplotlib
print("matplotlib.__version__ {}".format(matplotlib.__version__))
import matplotlib.pyplot as plt

#
# Some toy data
x_seq = [x / 100.0 for x in range(1, 100)]
y_seq = [x**2 for x in x_seq]

#
# Scatter plot
fig, ax = plt.subplots(1, 1)
ax.plot(x_seq, y_seq)

# https://stackoverflow.com/questions/31803817/how-to-add-second-x-axis-at-the-bottom-of-the-first-one-in-matplotlib
ax22 = ax.twiny() # instantiate a second axes that shares the same y-axis
# Move twinned axis ticks and label from top to bottom
ax22.xaxis.set_ticks_position("bottom")
ax22.xaxis.set_label_position("bottom")
# Offset the twin axis below the host
ax22.spines["bottom"].set_position(("axes", -0.06))

ax22.set_xlim(*ax.get_xlim())

#
# Declare and register callbacks
def on_xlims_change(axes):
  print("updated xlims: ", ax.get_xlim())
  ax22.set_xlim(*ax.get_xlim())

ax.callbacks.connect('xlim_changed', on_xlims_change)
fig.canvas.mpl_connect('button_release_event', on_xlims_change)

#
# Show
plt.show()

1 Ответ

0 голосов
/ 16 октября 2019

Благодаря @ImportanceOfBeingErnest - я думаю, что теперь у меня есть пример, который ведет себя так, как я хочу - также для диапазонов различных осей:

Figure_1

По сути, без обратного вызова и с ручной настройкой меток все работает так, как упомянуто @ImportanceOfBeingErnest - за исключением того, что при масштабировании старый набор меток останется (и поэтому при увеличении вы можете увидеть 10 отметок на исходной оси, но только 1 галочка на двойном);поэтому здесь обратный вызов используется только для «следования» за исходными метками оси:

#!/usr/bin/env python3

import matplotlib
print("matplotlib.__version__ {}".format(matplotlib.__version__))
import matplotlib.pyplot as plt

#
# Some toy data
x_seq = [x / 100.0 for x in range(1, 100)]
y_seq = [x**2 for x in x_seq]

#
# Scatter plot
fig, ax = plt.subplots(1, 1)
ax.plot(x_seq, y_seq)

# https://stackoverflow.com/questions/31803817/how-to-add-second-x-axis-at-the-bottom-of-the-first-one-in-matplotlib
ax22 = ax.twiny() # instantiate a second axes that shares the same y-axis
# Move twinned axis ticks and label from top to bottom
ax22.xaxis.set_ticks_position("bottom")
ax22.xaxis.set_label_position("bottom")
# Offset the twin axis below the host
ax22.spines["bottom"].set_position(("axes", -0.06))

factor = 655
old_xlims = ax.get_xlim()
new_xlims = (factor*old_xlims[0], factor*old_xlims[1])
old_tlocs = ax.get_xticks()
new_tlocs = [i*factor for i in old_tlocs]
print("old_xlims {} new_xlims {} old_tlocs {} new_tlocs {}".format(old_xlims, new_xlims, old_tlocs, new_tlocs))
ax22.set_xticks(new_tlocs)
ax22.set_xlim(*new_xlims)

def on_xlims_change(axes):
  old_tlocs = ax.get_xticks()
  new_tlocs = [i*factor for i in old_tlocs]
  ax22.set_xticks(new_tlocs)

ax.callbacks.connect('xlim_changed', on_xlims_change)

#
# Show
plt.show()

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