@MasterCopipaster

Как работать в ООП стиле в matplotlib — производить операции с графиками как с объектами?

Я хочу работать в программе с двумя разными графиками.
И пытаюсь сделать какой то класс который будет их "воплощать"
Суть в том что это должны быть два независимых друг от друга объекта.
Но все примеры которые я нахожу по matplotlib написаны в процедурном стиле.
Я сначала думал что будет довольно легко это сделать и написал что то вроде:

import matplotlib.pyplot as plt


class plotCreator:

    def __init__(self, series, name):
        self.plot = plt.plot(series)
        self.plot.ylabel(name)

    def save(self, name):
        self.plot.savefig(name)


series_one = [1, 2, 3, 4]
series_two = [4, 3, 2, 1]

img1 = plotCreator(series_one,'series_one')
img2 = plotCreator(series_two,'series_two')

img1.save('series_one.png')
img2.save('series_two.png')


Однако при запуске я получаю ошибку
AttributeError: 'list' object has no attribute 'ylabel'


Очивидно что plt.plot(series) не возвращает инстанс.
Как быть? как реализовать мою задумку?
  • Вопрос задан
  • 137 просмотров
Решения вопроса 1
Maksim_64
@Maksim_64
Data Analyst
Ну что ты имеешь ввиду под ООП стилем, не очень ясно из твоего примера. Во первых matplotlib имеет два интерфейса один matlab интерфейс а второй как раз таки ООП интерфейс.

например
import matplotlib.pyplot as plt
import numpy as np
X = np.linspace(-3,3,100)
fig, ax = plt.subplots(2,1, figsize=(12,6))
ax[0].plot(X, np.sin(X))
ax[0].set_title('sin(x)')
ax[1].plot(X,np.cos(X))
ax[1].set_title('cos(x)')
plt.show();

Вот это пример двух графиков (поменять количество очень легко), на одной фигуре расположение и все остальное легко конфигурируется, вместо например xlabel и им подобным set_xlabel. Я продемонстрировал с title как устанавливать свой title для каждого графика отдельно. В документации этот подход упомянут, как explicit API еще его называют Объектно-ориентированный интерфейс. ax - это коллекция твоих графиков. a[0] - первый график и.т.д

Так, как ты пытаешься ничего не получится. У тебя объект у которого ты пытаешься вызвать метод ylabel это список, а не то что ты думаешь.

В matplotlib есть фигура и на ней ты можешь разместить столько графиков столько захочешь, в такой системе координат в которой захочешь и разместить их на этой фигуре так как захочешь.

ДОПОЛНЕНИЕ К ОТВЕТУ.

На случай, если OOP имелся ввиду python'вский а не OOP как интерфейс matplotlib.
Смотри, если же тебе хочется создать свою структуру данных и на этой структуре запускать метод plot со всеми matplotlib возможностями, например pandas так делает. У pandas series или фрейма есть метод plot, если его запустить он тебе нарисует график напрммер.

import pandas as pd

df = pd.DataFrame({
    'Stock A':100 * np.cumprod(1 +  np.random.normal(0.01,0.05,30)),
    'Stock B':100 * np.cumprod(1 + np.random.normal(-0.01,0.05,30))
}, index = pd.date_range('2023-01-01',freq='1D',periods=30))
df.plot();

Я сделал фрейм две фейковых акции обе стартуют со 100 рублей стоимости и затем одна имеет ожидание случайное нормальное распределение с одним процентом роста другая с одним процентом снижения в день. И вызвал метод plot. И он построит график, так вот если ты хочешь ПРИКРУТИТЬ метод plot для своего класса то можно сделать вот так.

import numpy as np
import matplotlib.pyplot as plt


class plotCreator:

    def __init__(self, x, y,**kwargs):
        self.x = x
        self.y = y
        self.axes_kwargs = kwargs
    def plot(self, ax=None, **kwargs):
        if ax is None:
            ax = plt.gca()
        ax.plot(self.x, self.y, **kwargs)
        ax.set(**self.axes_kwargs)
        return ax
        

X = np.linspace(-2*np.pi,2*np.pi,100)
y1 = np.cos(X)
y2 = np.sin(X)

img1 = plotCreator(X, y1,xlabel='X',title='cos(X)',ylabel='cos(X)')
img1.plot().figure.savefig('cos.png');

plt.cla()

img2 = plotCreator(X, y2,xlabel='X',title='sin(X)',ylabel='sin(X)')
img2.plot().figure.savefig('sin.png');


Вообщем, работает, надо конечно до ума доводить (код мягко говоря так себе) ну это уже сам, конечно. Тут имей ввиду, после каждого создания экземпляра класса и вызова метода plot нужно чистить фигуру plt.cla() вот этим методом а то он естественно рисовать на одном и том axes будет. Остальное kwargs экземпляра класса это методы axes, (xlabel, ylabel) и им подобные, kwargs метода plot, это как рисовать, стили линии, толщина, цвет и т.д. (color, lw, alpha, и.т.д)

В общем в виде черновика можно вот так. А так придется вчитываться в доки, как все это по уму обставить и привести код к приличному виду в общем время придется потратить.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы