Уведомления

Группа в Telegram: @pythonsu

#1 Сен. 12, 2021 01:38:14

Yyy
Зарегистрирован: 2021-09-10
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Matplotlib при сохранении графика не наследуется часть настроек

Привет.
Формирую график таким кодом:

 font = {"family" : "monospace",
        "size" : 12}
plt.rc("font", **font)
fig, ax1 = plt.subplots()
ax1.grid(ls="-", lw=.7)
ax1.tick_params(axis="both", labelsize=12)
ax1.set_xlabel("Date")
plt.setp(ax1.get_xticklabels(), rotation=90)
ax2 = ax1.twinx()
ax1.plot(date, p1, color='red', label="Param1")
ax2.plot(date, p2, color='blue', label="Param2", linestyle='--')
ax2.axhspan(29, 40, color='gray', alpha=0.4)
ax1.legend(loc="upper left", fontsize=10, ncol=1)
ax2.legend(loc="upper right", fontsize=10, ncol=1)
plt.savefig(plot_file, dpi=300, bbox_inches="tight")
plt.show()

Показ выводит такое - https://i.ibb.co/vh1R1kM/Screenshot-from-2021-09-12-01-30-15.png
А сохраненный файл такое - https://i.ibb.co/vm2WzTs/saved.png
Пробовал играться с настройками dpi, размером фигуры, форматами внутри savefig и figure- все бестолку. Подскажите, как получить при сохранении 1 к 1 то, что показало plt.show()?

Ну и еще небольшой вопрос. Я нашел временный выход для размещения легенды обоих графиков в разных углах, но как это сделать корректно в одном углу? Если я задаю расположение на уровне ax1 до переноса параметров на ax2 или напрямую через plt, в итоге получаю наложение легенды одного графика на легенду другого графика.

Отредактировано Yyy (Сен. 12, 2021 01:41:36)

Прикреплённый файлы:
attachment saved.png (175,8 KБ)

Офлайн

#2 Сен. 12, 2021 08:06:55

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  252  -
Профиль   Отправить e-mail  

Matplotlib при сохранении графика не наследуется часть настроек

Yyy
как получить при сохранении 1 к 1 то, что показало plt.show()?
Нажимать кнопку сохранения картинки в окошке которое вы показали.

У вас разный размер фигуры. Сделайте нужный вам меняя figsize.
 figure(figsize=(8, 6), dpi=80)

Yyy
в итоге получаю наложение легенды одного графика на легенду другого графика.
Легенды очевидно не пересекутся если у вас одна легенда.
https://stackoverflow.com/questions/5484922/secondary-axis-with-twinx-how-to-add-to-legend
 ...
lns1 = ax.plot(time, Swdown, '-', label = 'Swdown')
lns2 = ax.plot(time, Rn, '-', label = 'Rn')
ax2 = ax.twinx()
lns3 = ax2.plot(time, temp, '-r', label = 'temp')
# added these three lines
lns = lns1+lns2+lns3
labs = [l.get_label() for l in lns]
ax.legend(lns, labs)



Офлайн

#3 Сен. 12, 2021 10:42:18

Yyy
Зарегистрирован: 2021-09-10
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Matplotlib при сохранении графика не наследуется часть настроек

doza_and
Нажимать кнопку сохранения картинки в окошке которое вы показали.
Вариант, конечно, но не продуктивный. В моем случае графики должны строиться автоматически, потому что их для одного набора данных несколько десятков, а набор данных периодически пополняется.

doza_and
У вас разный размер фигуры. Сделайте нужный вам меняя figsize.
Я пытался это сделать через figure в моем варианте, где я создаю подграфики с помощью plt.subplots(). Сейчас еще раз перечитал документацию и сделал через add_subplot.
 plt.rcParams["font.size"] = "8"
fig = plt.figure(figsize=(19.20, 10.80), dpi=86)
a1 = fig.add_subplot()
a1.plot(date, p1, color='red', label="Param1")
a1.grid(ls="-", lw=.7)
a1.tick_params(axis="both")
a1.set_xlabel("Date")
a2 = a1.twinx()
a2.plot(date, p2, color='blue', label="Param2", linestyle='--')
fig.legend(labels=("P1", "P2"), loc="upper left")
plt.setp(a1.get_xticklabels(), rotation=90)
a2.axhspan(29, 40, color='gray', alpha=0.4)
plt.savefig(plot_file)
plt.show()

Заодно и проблема с легендой решилась. Параметры объекта figure начали работать в таком варианте. Ваш вариант с объединением легенд тоже рабочий, только чуть сложнее, хотя результат тот же.

К слову, когда начинал использовать matplotlib после llibreoffice calc, ожидал что есть автоматическая подстройка под объем данных в части размера шрифта для обозначения величин на осях, чтобы при высокой плотности заполнения или шрифт уменьшался, или пропускались значения через 1+. Пока не наблюдаю этого. Буду копать в документации или пытаться привязать сам к объему данных, вроде шрифт 8 при кол-во значений по оси x до 60, шрифт 6 для значеий до 120 и т.п.
Спасибо за помощь.

Отредактировано Yyy (Сен. 12, 2021 10:57:57)

Офлайн

#4 Сен. 12, 2021 13:54:35

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  252  -
Профиль   Отправить e-mail  

Matplotlib при сохранении графика не наследуется часть настроек

Yyy
Пока не наблюдаю этого. Буду копать в документации или пытаться привязать
Странно что не наблюдаете. Вообще если не пичкать лишними опциями matplotlib то все из коробки отлично работает с прореживанием надписей на осях. Ну может есть проблемы с datetime?

удет конструктивнее если выложите данные и скрипт. Тогда можно будет понять что у вас там лишнее.



Офлайн

#5 Сен. 12, 2021 16:06:59

Yyy
Зарегистрирован: 2021-09-10
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Matplotlib при сохранении графика не наследуется часть настроек

doza_and
удет конструктивнее если выложите данные и скрипт. Тогда можно будет понять что у вас там лишнее.
Файл с данными - https://dropmefiles.com/ydTKa
Формат - csv, разделитель - точка с запятой. Я почистил его от лишней для этого примера информации.
Скрипт
 #!/usr/bin/env python3
import csv
from matplotlib import pyplot as plt
# Plots
date = []
p1 = []
p2 = []
src_file = '1.csv'
with open(src_file, 'r') as f:
    reader = csv.reader(f, delimiter=';', quotechar='\'')
    for line in reader:
        month = int(line[0])
        if month in range(6,9):
            date.append("2021-{}-{}".format(line[0].zfill(2), line[1].zfill(2)))
            p1.append(int(line[3]))
            p2.append(int(line[2]))
plot_file = "plot-6-8.png"
fig = plt.figure(figsize=(19.20, 10.80), dpi=100)
plt.rcParams = {"font.size" : 12,
                "font.family" : "monospace"}
a1 = fig.add_subplot()
a1.plot(date, p1, color='red')
a1.grid(ls="-", lw=.7)
a1.tick_params(axis="both", length=10, pad=5)
a1.set_xlabel("Date")
a2 = a1.twinx()
a2.plot(date, p2, color='blue', linestyle='--')
fig.legend(labels=("P1", "P2"), loc="upper left")
plt.setp(a1.get_xticklabels(), rotation=90)
for label in a1.get_xaxis().get_ticklabels()[1::2]:
    label.set_visible(False)
plt.savefig(plot_file)
plt.show()

Удалось немного вручную подкорректировать расположение значений на оси х. Теперь они под 90 градусов и отображаются только четные. Опять же, это все вручную. Надо это как то автоматизировать…

Извините, еще немного воспользуюсь вашим интересом к этой теме. В matplotlib есть удобная функция рисования axvspan (и axhline тоже). В моем случае она хорошо вписывается для отображения области на графике p1, когда график p2 находился выше какого-то значения по оси у. Проблема в том, что сделать это судя по всему можно только вручную. Я сейчас пишу алгоритм вычисления периодов (дней подряд), когда значение в графике p2 было выше какого-то предела, потому загоню все эти данные в список списков и в цикле буду строить для каждого вложенного списка зону пересечения с помощью axvspan. На всякий случай уточню, действительно ли нет уже готового инструмента для этого? В приложении пример, как я вижу итог моей задачи на результирующем графике. Основная цель - выделение значений на оси х (дат), когда значения p2 превосходили заданное, для улучшения читаемости.

P.S. Не тот файл в приложении. Правильный тут - https://i.ibb.co/xDMkSRD/plot-6-8.png

Отредактировано Yyy (Сен. 12, 2021 16:19:23)

Прикреплённый файлы:
attachment plot-6-8-с-объяснением.png (172,2 KБ)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version