Найти - Пользователи
Полная версия: Matplotlib при сохранении графика не наследуется часть настроек
Начало » Python для новичков » Matplotlib при сохранении графика не наследуется часть настроек
1
Yyy
Привет.
Формирую график таким кодом:

 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, в итоге получаю наложение легенды одного графика на легенду другого графика.
doza_and
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)
Yyy
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 и т.п.
Спасибо за помощь.
doza_and
Yyy
Пока не наблюдаю этого. Буду копать в документации или пытаться привязать
Странно что не наблюдаете. Вообще если не пичкать лишними опциями matplotlib то все из коробки отлично работает с прореживанием надписей на осях. Ну может есть проблемы с datetime?

удет конструктивнее если выложите данные и скрипт. Тогда можно будет понять что у вас там лишнее.
Yyy
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
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB