Синхронизация двойных осей x в двойном (под) графике в интерактивном Matplotlib? - PullRequest
0 голосов
/ 16 октября 2019

В принципе, я хочу добиться того же, что и в https://stackoverflow.com/a/58413766/6197439 - за исключением двух графиков.

Пример кода для этого вставлен ниже, и вот анимированный рисунок того, как этоведет себя:

Figure_1

Дело в том:

  • Я должен сделать двойную ось twiny из ax2 (нижний участок), поэтому он рисуется под общей осью x внизу - иначе он рисуется ниже верхнего графика (и перекрывая верхнюю часть нижнего графика)
  • После запуска я сначала перетаскиваюнижний подпункт - обе оси следуют так, как должны
  • Если я увеличу нижний подплот, обе оси X масштабируются должным образом - но у двойных осей не все метки (поэтому у меня on_xlims_change, что помогло исправить это в связанном посте, где был только один сюжет - но здесь я не могу заставить его работать)
  • Если затем я перетаскиваю верхний участок - перемещается только оригинальная ось х,двойная / двойниковая клонированная ось X не (GIF не показывает это, но то же самое относится и к зумувходя также в верхний подзаговор)

Я пытался использовать обратный вызов на обоих и на ax и ax2, и я не мог получить улучшенное поведение - однако, обратите внимание, что gifпоказывает поведение, как в коде, размещенном здесь (где обратный вызов не используется).

Итак, как я могу заставить двойную / сдвоенную ось X следовать исходной общей оси X - через масштабирование и панорамирование, как в верхнем, так и в нижнем сюжете?

Код:

#!/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]
y2_seq = [0.3*x**2 for x in x_seq]

#
# Scatter plot
fig, (ax, ax2) = plt.subplots(2, 1, sharex=True, figsize=(9, 6), dpi=120, gridspec_kw={'height_ratios': [2, 1]}) # two rows, one column
# Remove horizontal space between axes
fig.subplots_adjust(hspace=0)

ax.plot(x_seq, y_seq)
ax2.plot(x_seq, y2_seq)

# https://stackoverflow.com/questions/31803817/how-to-add-second-x-axis-at-the-bottom-of-the-first-one-in-matplotlib
ax22 = ax2.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.1))

factor = 655
old_xlims = ax2.get_xlim()
new_xlims = (factor*old_xlims[0], factor*old_xlims[1])
old_tlocs = ax2.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 = axes.get_xticks()
  new_tlocs = [i*factor for i in old_tlocs]
  ax22.set_xticks(new_tlocs)

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

#
# Show
plt.show()

1 Ответ

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

Я думаю, что у меня есть решение (код ниже):

Figure_1

.... благодаря комментарию @ImportanceOfBeingErnest:

axes.get_xticks() получает вам галочки до изменения.

Ну, по крайней мере, теперь имеет смысл, почему это было так трудно настроить :) Жаль, что я не нашелэта информация ранее ... У людей, похоже, были проблемы с ней:

Я думаю, что я попытался бы поделиться всеми тремя осями

Единственная информация, которую я нашелна это:

По-видимому, можно использовать ax1.get_shared_x_axes().join(ax1, ax2) -> однако это объединение не в смысле «соединения» массива со строкой в ​​Python и не в смысле добавления to массив, по-видимому, в смысле набора (dis) join (t) - так что вы можете объединить три элемента, что я и пытался (и похоже, работает):

ax.get_shared_x_axes().join(ax, ax2, ax22)

Это правильно?

и просто используйте другой форматер на последнем.

Здесь есть приличная информация:

Итак, наконец, мой код:

#!/usr/bin/env python3

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

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

#
# Scatter plot
fig, (ax, ax2) = plt.subplots(2, 1, sharex=True, figsize=(9, 6), dpi=100, gridspec_kw={'height_ratios': [2, 1]}) # two rows, one column
# Remove horizontal space between axes
fig.subplots_adjust(hspace=0)

# https://stackoverflow.com/questions/31803817/how-to-add-second-x-axis-at-the-bottom-of-the-first-one-in-matplotlib
ax22 = ax2.twiny() # instantiate a second axes that shares the same y-axis
#~ ax.get_shared_x_axes().join(ax, ax22) # SO:42718823
ax.get_shared_x_axes().join(ax, ax2, ax22)
#~ ax.autoscale() # <-- needed if no axes limits are explicitely set. SO:42718823
# 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.1))

ax.plot(x_seq, y_seq)
ax2.plot(x_seq, y2_seq)

factor = 655

# FuncFormatter can be used as a decorator
@ticker.FuncFormatter
def major_formatter(x, pos):
  #return "[%.2f]" % x
  return int(factor*x)

ax22.xaxis.set_major_formatter(major_formatter)

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