Когда я выполняю анализ ad-ho c в Jupyter Notebook, я часто хочу просматривать последовательности преобразований для некоторых Pandas DataFrame
в виде вертикально расположенных участков. Мой обычный быстрый и грязный метод состоит в том, чтобы вообще не использовать подзаговоры, а создать новую фигуру для каждого графика:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
df = pd.DataFrame({"a": range(100)}) # Some arbitrary DataFrame
df.plot(title="0 to 100")
plt.show()
df = df * -1 # Some transformation
df.plot(title="0 to -100")
plt.show()
df = df * 2 # Some other transformation
df.plot(title="0 to -200")
plt.show()
Этот метод имеет ограничения. Тики оси X не выровнены даже при одинаковом индексировании (поскольку ширина оси x зависит от меток оси Y), а выходные данные ячейки Jupyter содержат несколько отдельных встроенных изображений, а не одно, которое я могу сохранить или скопировать и вставить .
Насколько я знаю, правильное решение состоит в том, чтобы использовать plt.subplots()
:
fig, axes = plt.subplots(3, figsize=(20, 9))
df = pd.DataFrame({"a": range(100)}) # Arbitrary DataFrame
df.plot(ax=axes[0], title="0 to 100")
df = df * -1 # Some transformation
df.plot(ax=axes[1], title="0 to -100")
df = df * 2 # Some other transformation
df.plot(ax=axes[2], title="0 to -200")
plt.tight_layout()
plt.show()
Это дает именно тот результат, который я хотел бы получить. Однако он также вызывает раздражение, которое заставляет меня использовать первый метод по умолчанию: мне нужно подсчитать вручную количество созданных мной вспомогательных участков и обновить этот счетчик в нескольких разных местах по мере изменения кода.
В случае нескольких фигур добавить четвертый график так же просто, как вызвать df.plot()
и plt.show()
в четвертый раз. При использовании вспомогательных графиков эквивалентное изменение требует обновления счетчика вспомогательных участков, плюс арифметическое значение c, чтобы изменить размер выходного значения, заменив plt.subplots(3, figsize=(20, 9))
на plt.subplots(4, figsize=(20, 12))
. Каждому вновь добавленному субплоту необходимо знать, сколько других субплощадок уже существует (ax=axes[0]
, ax=axes[1]
, ax=axes[2]
и др. c.), Поэтому любые добавления или удаления требуют каскадных изменений для графиков ниже.
Это кажется , как будто это должно быть тривиально для автоматизации - это просто подсчет и умножение - но я нахожу невозможным реализовать с помощью API matplotlib / pyplot. Самое близкое, что я могу получить, - это следующее частичное решение, которое достаточно лаконично, но все еще требует явного подсчета:
n_subplots = 3 # Must still be updated manually as code changes
fig, axes = plt.subplots(n_subplots, figsize=(20, 3 * n_subplots))
i = 0 # Counts how many subplots have been added so far
df = pd.DataFrame({"a": range(100)}) # Arbitrary DataFrame
df.plot(ax=axes[i], title="0 to 100")
i += 1
df = df * -1 # Arbitrary transformation
df.plot(ax=axes[i], title="0 to -100")
i += 1
df = df * 2 # Arbitrary transformation
df.plot(ax=axes[i], title="0 to -200")
i += 1
plt.tight_layout()
plt.show()
Проблема root в том, что в любой момент вызова df.plot()
должен существовать axes
список известных размеров. Я подумывал о том, чтобы как-то отложить выполнение df.plot()
, например, добавив к списку лямбда-функций, которые можно посчитать до их последовательного вызова, но это кажется чрезмерной церемонией, чтобы избежать обновления целого числа вручную.
Есть ли более удобный способ сделать это? В частности, есть ли способ создать фигуру с «расширяемым» количеством вспомогательных участков, подходящую для специальных / интерактивных контекстов, где количество заранее неизвестно?
( Примечание: Этот вопрос может выглядеть как дубликат этого вопроса или этого , но принятые ответы на оба вопроса содержат именно ту проблему, которую я пытаюсь решить решить - что параметр nrows=
plt.subplots()
должен быть объявлен перед добавлением подзаговоров.)