Визуализация данных на Python

Графики для анализа и для статьи: Matplotlib, палитры, seaborn, Plotly и HoloViews

Вячеслав Федоров

Лекция 11

Разработка и применение ПО

в физических исследованиях

plt

Содержание

От выбора вида графика до интерактивной страницы

01

Зачем график

02

Фигура и оси

03

Графики для статьи

04

Поля и палитры

05

Статистика

06

Интерактивность

Цель лекции

Показывать данные так, чтобы график не вводил в заблуждение ни автора, ни читателя

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

Библиотеки

визуализации

БиблиотекаЧто даётРезультат
Matplotlibфигура и оси, любой вид графикаPNG, PDF, SVG
seabornстатистика из таблицыповерх Matplotlib
pandas .plotбыстрый взгляд на столбцыповерх Matplotlib
Plotlyподсказки, масштаб, 3DHTML
Bokeh, Panelстраницы и панели мониторингаHTML, сервер
HoloViewsописание данных вместо графикабэкенды bokeh, matplotlib, plotly

Для физика

Статья — Matplotlib, разбор сырых данных — Plotly или HoloViews, мониторинг установки — Panel.

Пояснение

Основа почти всех статичных графиков Python — Matplotlib: seaborn и pandas строят поверх него.

Зачем график

Квартет Энскомба, выбор вида графика, честное изображение данных

01

Зачем график

Фигура и оси

Графики для статьи

Поля и палитры

Статистика

Интерактивность

Квартет

Энскомба

СтатистикаВсе четыре набора
среднее x9,00
среднее y7,50
дисперсия x11,00
дисперсия y4,12–4,13
корреляция0,816–0,817
прямаяy = 0,500 x + 3,00

Ф. Энскомб, 1973: четыре набора по 11 точек с одинаковыми средними, дисперсиями, корреляцией и прямой регрессии устроены совершенно по-разному.

Важно

Сводные статистики не заменяют взгляда на данные: график — первый шаг анализа, а не последний.

Демонстрация:

квартет Энскомба

01

Четыре набора по 11 точек

02

Средние, дисперсии, корреляция и прямая регрессии

03

Четыре графика рассеяния в одной фигуре

Что наблюдается

Средние 9 и 7,5 совпадают, дисперсия y — 4,12–4,13, корреляция — 0,816–0,817; у всех прямая y = 0,5x + 3. График сохранён в anscombe.png.

root@lab — запись со стенда

Результат:

квартет Энскомба

Четыре графика рассеяния квартета Энскомба с одинаковой прямой регрессии

Что наблюдается

I — линейная связь с шумом, II — гладкая нелинейная кривая, III — прямая с одним выбросом, IV — наклон задаёт единственная точка. Прямая регрессии у всех одна.

Выбор

вида графика

ЗадачаВид графикаГде искать
распределение величиныгистограмма, ящик с усамиhist, boxplot
зависимость y(x)линияplot
связь двух величинточечная диаграммаscatter
измерения с погрешностьюточки с отрезкамиerrorbar
поле на сеткецветовая карта, изолинииimshow, contour
много параметровпараллельные координатыPlotly

Пояснение

Каталог видов графиков по назначению — «Периодическая таблица методов визуализации» (visual-literacy.org).

Важно

Круговые и объёмные диаграммы сравнивать трудно: длину глаз оценивает точнее, чем угол и площадь.

Честный

график

01

Подписи осей

величина и единицы: «Ток пучка, мА»

02

Масштаб

линейный или логарифмический — по смыслу; у столбцов ось начинается с нуля

03

Сравнимые панели

общие шкалы: sharex, sharey

04

Палитра

по смыслу величины, без радуги jet

05

Минимум украшений

без объёма, теней и лишних рамок

Важно

Обрезанная ось у столбцовой диаграммы многократно преувеличивает разницу.

Для физика

Спектры и профили пучка с большим динамическим диапазоном — в логарифмическом масштабе.

Фигура и оси

Два интерфейса, устройство фигуры, виды графиков, сохранение в файл

02

Зачем график

Фигура и оси

Графики для статьи

Поля и палитры

Статистика

Интерактивность

Два

интерфейса

pyplot: скрытая текущая фигура

import matplotlib.pyplot as plt
 
plt.plot(t, current)
plt.xlabel('Время, мкс')
plt.savefig('a.png')

Объекты: фигура и оси названы явно

fig, ax = plt.subplots(figsize=(7, 3))
ax.plot(t, current)
ax.set_xlabel('Время, мкс')
fig.savefig('a.png')

Пояснение

Явные fig и ax — в любом коде длиннее нескольких строк: видно, к каким осям относится вызов.

Устройство

фигуры

Figure — холст и файл

Axes — оси с координатами

Line2D: ax.plot

Legend: ax.legend

Text: ax.annotate

Patch: ax.bar

XAxis и YAxis: деления, подписи, пределы

fig.savefig — сохраняет весь холст

ОбъектЧто это
Figureхолст: поля, заголовок, файл
Axesобласть графика с координатами
Axisшкала: пределы, деления, масштаб
Artistвсё нарисованное: линии, текст

Пояснение

На одной фигуре несколько осей: plt.subplots(2, 1) возвращает фигуру и массив из двух осей.

Основные

виды графиков

ax.plot(t, current)               # линия
ax.scatter(x, y, s=10)            # точки
ax.errorbar(k, s, 0.02, fmt='o')  # погрешности
ax.hist(age, bins=16)             # гистограмма
ax.bar(labels, values)            # столбцы
ax.fill_between(z, -a, a)         # полоса
ax.imshow(img, cmap='viridis')    # поле
ax.contour(X, Y, Z, levels=10)    # изолинии
ax.set_xscale('log')              # масштаб

Пояснение

Каждый метод возвращает созданный объект: линию, набор точек, изображение — для последующей настройки.

Для физика

Галерея matplotlib.org/stable/gallery: вид графика подбирается по рисунку, код берётся готовым.

Сохранение

и форматы

ФорматУстройствоДля чего
PNGрастр, плотность dpiслайды, веб
SVGвекторвеб, правка в редакторе
PDFвектор, шрифты внутристатья, LaTeX

fig.tight_layout()
fig.savefig('waveform.png', dpi=300)
fig.savefig('waveform.pdf')

Важно

На машине без экрана Matplotlib выбирает бэкенд Agg: plt.show() ничего не покажет, графики сохраняются в файлы.

Пояснение

В Jupyter фигура показывается под ячейкой сама, savefig нужен только для файла.

Демонстрация:

форматы файла

01

Осциллограмма с шумом и сглаживание Савицкого—Голея

02

Сохранение в PNG 150 и 300 dpi, SVG и PDF

03

Размеры изображений в точках

04

Просмотр в браузере: http.server

Что наблюдается

PNG 150 dpi — 66 КиБ и 1200×480 точек, 300 dpi — 151 КиБ и 2400×960; SVG — 86 КиБ, PDF — 38 КиБ. http.server отдаёт файлы браузеру.

root@lab — запись со стенда

Результат:

осциллограмма

Осциллограмма тока пучка: сырой сигнал и сглаженная кривая с подписанным максимумом

Что наблюдается

Максимум сглаженного сигнала — 4,16 мА при 3,51 мкс; надпись со стрелкой — annotate, легенда собрана из label.

Графики для статьи

Подписи с формулами, погрешности, компоновка, размер и стиль

03

Зачем график

Фигура и оси

Графики для статьи

Поля и палитры

Статистика

Интерактивность

Подписи

и формулы

ax.errorbar(k, meas, yerr=0.02, fmt='o',
            capsize=3, label='экран')
ax.plot(k, model, color='crimson', label='модель')
ax.set_xlabel(r'Сила линзы $k$, м$^{-1}$')
ax.set_ylabel(r'Размер пучка $\sigma$, мм')
ax.legend()

Пояснение

Текст в знаках доллара набирается mathtext — подмножеством TeX без установки LaTeX.

Важно

Строка с формулой помечается префиксом r, иначе обратный слеш обработает Python.

Пояснение

Полный LaTeX — text.usetex=True: нужен TeX, а для кириллицы — преамбула с T2A и babel.

Компоновка

и стиль

plt.rcParams.update({
    'figure.figsize': (3.4, 2.4),  # колонка
    'font.size': 9,
    'axes.grid': True})
 
fig, (up, down) = plt.subplots(
    2, 1, sharex=True,
    layout='constrained')
fig.align_ylabels()

01

Размер под колонку

около 8,6 см, 3,4 дюйма: шрифт в статье равен шрифту текста

02

Общие оси

sharex и sharey: подписи только у крайних

03

Один стиль

rcParams или файл стиля для всего набора

Для физика

Все рисунки статьи строит один скрипт: правка стиля обновляет весь набор.

Демонстрация:

скан линзой

01

25 измерений размера пучка при разной силе линзы

02

errorbar, модель и подписи с формулами

03

Сохранение в PNG и PDF

Что наблюдается

Минимум модели — 0,158 мм при k = 1,08 1/м, между точками скана; PDF занимает 17 КБ, PNG — 46 КБ.

root@lab — запись со стенда

Результат:

скан линзой

Размер пучка в зависимости от силы линзы: измерения с погрешностями и модель

Что наблюдается

Подписи с k, σ и степенью −1 набраны mathtext без LaTeX; точки с засечками — errorbar, линия — модель, сетка — rcParams.

Поля и палитры

imshow, pcolormesh и изолинии; последовательные, расходящиеся и качественные палитры

04

Зачем график

Фигура и оси

Графики для статьи

Поля и палитры

Статистика

Интерактивность

Поля

на сетке

ФункцияСеткаПример
imshowравномерная, ячейка — пиксельизображение, матрица
pcolormeshнеравномерная, узлыполе на неравномерной сетке
contour, contourfизолиниипотенциал, уровни поля
quiver, streamplotвекторное полесиловые линии

im = ax.imshow(By, cmap='RdBu_r', vmin=-lim, vmax=lim,
               origin='lower', extent=(x0, x1, y0, y1))
fig.colorbar(im, ax=ax, label='$B_y$, мТл')

Пояснение

extent задаёт физические границы: на осях метры вместо номеров пикселей.

Палитры

ТипПалитрыДля чего
последовательнаяviridis, magma, cividisзнакопостоянная величина
расходящаясяRdBu_r, coolwarmзнакопеременная, светлый центр — ноль
качественнаяtab10, Set2категории без порядка
радугаjet, rainbowне рекомендуются

Важно

У расходящейся палитры границы vmin и vmax симметричны, иначе белый смещается с нуля.

Пояснение

viridis монотонна по светлоте: читается в чёрно-белой печати и при нарушении цветового зрения.

Для физика

Профиль пучка и спектр с большим динамическим диапазоном — norm=LogNorm().

Объём

и поверхность

ax = fig.add_subplot(projection='3d')
ax.plot_surface(X, Y, Z, cmap='viridis')
ax.plot(x, y, z)                 # траектория
 
go.Figure(go.Surface(x=x, y=y, z=Z))   # Plotly

Важно

Значения с трёхмерной поверхности читаются плохо: для статьи — карта с изолиниями, для разбора — вращаемая поверхность Plotly.

Для физика

Траектории частиц в пространстве — ax.plot(x, y, z) или go.Scatter3d.

Демонстрация:

три палитры

01

Матрица отклика замкнутой орбиты 64×48

02

Три палитры: jet, viridis, RdBu_r с симметричными границами

03

Число палитр в Matplotlib

Что наблюдается

Значения от −11,8 до 11,9 мм/мрад; в Matplotlib 182 палитры вместе с обращёнными вариантами _r.

root@lab — запись со стенда

Результат:

три палитры

Матрица отклика в палитрах jet, viridis и RdBu_r

Что наблюдается

В jet светлее всего промежуточные значения около ±3, а не наибольшие; viridis монотонна по светлоте; RdBu_r с симметричными границами показывает знак: белый — ноль.

Статистика

Быстрые графики pandas, seaborn: распределения, группы, доверительные интервалы

05

Зачем график

Фигура и оси

Графики для статьи

Поля и палитры

Статистика

Интерактивность

Графики

из pandas

df['Age'].plot.hist(bins=16)
df.boxplot(column='Age', by='Pclass')
log['p'].resample('1min').mean().plot()
ax = df.plot.scatter(x='Age', y='Fare')
ax.set_yscale('log')

Пояснение

Методы plot таблиц и столбцов строят графики Matplotlib и возвращают оси: оформление дописывается их методами.

Для физика

Быстрый взгляд на журнал или таблицу измерений — одна строка; для статьи те же оси оформляются по правилам третьей части.

seaborn

ФункцияЧто показывает
histplot, kdeplotраспределение
boxplot, violinplotраспределение по группам
barplot, pointplotсреднее с доверительным интервалом
scatterplot, regplotсвязь и регрессия
heatmapматрица, например корреляций
pairplotвсе пары столбцов

sns.barplot(df, x='Pclass', y='Survived',
            hue='пол', errorbar=('ci', 95))

Пояснение

Аргумент hue разбивает данные на группы по столбцу таблицы и сам строит легенду.

Пояснение

Грамматика графиков в духе ggplot2 из R — пакет plotnine.

Демонстрация:

seaborn на «Титанике»

01

Доли выживших по полу и классу каюты

02

barplot с 95-процентным доверительным интервалом

03

Гистограмма возраста по исходу

Что наблюдается

Выжили 97 % женщин первого класса и 14 % мужчин третьего; интервал — бутстреп с seed=0 для воспроизводимости.

root@lab — запись со стенда

Результат:

seaborn

Доли выживших по классу и полу и гистограмма возраста по исходу

Что наблюдается

Слева доли с интервалами, справа возраст: из 44 детей не старше пяти лет выжил 31, больше всего пассажиров в возрасте 20–25 лет.

Интерактивность

Plotly, HoloViews, Bokeh и Panel: подсказки, масштаб, слайдеры, панели

06

Зачем график

Фигура и оси

Графики для статьи

Поля и палитры

Статистика

Интерактивность

Plotly

import plotly.express as px
import plotly.graph_objects as go
 
fig = go.Figure()
fig.add_scatter(x=z, y=a,
    hovertemplate='z = %{x:.2f} м<br>a = %{y:.2f} мм')
fig.write_html('envelope.html', include_plotlyjs='cdn')
 
px.scatter(df, x='Age', y='Fare', color='Sex')

include_plotlyjsФайлСеть
'cdn'27 КиБнужен интернет
True4,6 МиБработает без сети

Пояснение

Миллион точек — go.Scattergl: отрисовка переложена на видеокарту.

HoloViews

dim_z = hv.Dimension('z', label='Положение', unit='м')
curve = hv.Curve((z, a), dim_z, dim_a)
layout = curve + points     # рядом
overlay = curve * points    # в одних осях
curves = {k: hv.Curve((z, envelope(k)), dim_z, dim_a)
          for k in ks}
hmap = hv.HoloMap(curves, kdims='k')
hv.save(hmap, 'scan.html', backend='bokeh')

Огибающая пучка при четырёх жёсткостях соленоидов, построенная HoloViews

Пояснение

Подписи осей с единицами HoloViews берёт из описания данных: «Радиус пучка (мм)».

Анимация

from matplotlib.animation import FuncAnimation
 
line, = ax.plot(x, wave(x, 0.0))
 
def update(i):
    line.set_ydata(wave(x, t[i]))
    return (line,)
 
anim = FuncAnimation(fig, update, frames=200)
anim.save('wave.gif', writer='pillow', fps=30)

Пояснение

Кадр меняет данные готовых художников: set_data и set_ydata быстрее, чем новый plot на каждом шаге.

Пояснение

GIF записывает Pillow, MP4 — ffmpeg, который устанавливается отдельно.

Для физика

Эволюция волнового пакета во времени или огибающей вдоль тракта.

Выбор

инструмента

ЗадачаИнструмент
рисунок для статьиMatplotlib
разбор сырых данныхPlotly, HoloViews в Jupyter
скан по параметруHoloMap, DynamicMap
таблица pandas в браузереhvPlot: df.hvplot()
панель мониторинга установкиPanel: panel serve app.py

Пояснение

DynamicMap пересчитывает кадр по движению слайдера и требует работающего Python; HoloMap сохраняется в HTML, работающий без Python.

Для физика

Панель мониторинга вакуума или тока пучка — страница Panel без строки JavaScript.

Демонстрация:

Plotly и HoloViews

01

Огибающая пучка: уравнение огибающей, пять соленоидов

02

Plotly: HTML с plotly.js из сети и автономный

03

HoloViews: скан жёсткости в HTML со слайдером

04

Статичный PNG через бэкенд matplotlib

05

Размеры файлов

Что наблюдается

HTML с CDN — 26,9 КиБ, автономный — 4,6 МиБ; HoloMap из четырёх кадров — 51,5 КиБ, PNG — 78,5 КиБ. Радиус — от 2,36 до 7,13 мм.

root@lab — запись со стенда

Результат:

Plotly в браузере

Огибающая пучка в Plotly: радиус вдоль тракта с заливкой

Что наблюдается

Файл envelope-cdn.html в браузере: подсказка показывает z и a, рамка увеличивает фрагмент, двойной щелчок возвращает масштаб.

Итоги

лекции

01

График — первый шаг анализа: одинаковые статистики скрывают разные данные.

02

Вид графика, масштаб и палитра выбираются по смыслу данных; подпись оси — величина и единицы.

03

Matplotlib: явные fig и ax, PNG для слайдов, PDF для статьи, размер под колонку журнала.

04

viridis — для знакопостоянных, RdBu_r с симметричными границами — для знакопеременных; без jet.

05

seaborn — статистика из таблиц, Plotly и HoloViews — интерактивный разбор данных.

Упражнения

для самопроверки

01

Осциллограмма для статьи

PNG и PDF в ширину колонки 8,6 см, подписи с единицами, шрифт 9 пт

02

Профиль пучка

двумерная гауссиана на экране: imshow с extent, LogNorm, изолинии

03

Журнал установки

давление и ток из прошлой лекции на двух осях одна под другой с общей шкалой времени

04

Скан параметра

огибающая при разной жёсткости: HoloMap или Plotly со слайдером

Пояснение

Каждый рисунок проверяется на соответствие данным: пределы осей, единицы, палитра.

Для физика

Проект курса: все рисунки отчёта строит один скрипт.

Источники

1

Книга курса: глава «Визуализация на Python», приложение «Графики Matplotlib»

phys-dev.github.io/soft-dev-book

2

Matplotlib — документация и галерея

matplotlib.org/stable/gallery

3

seaborn — документация

seaborn.pydata.org

4

Plotly для Python; HoloViews и HoloViz — holoviews.org, holoviz.org

plotly.com/python

5

Anscombe F. J. Graphs in Statistical Analysis. – The American Statistician, 1973. – Vol. 27, No. 1

doi.org/10.1080/00031305.1973.10478966

6

Crameri F., Shephard G. E., Heron P. J. The misuse of colour in science communication. – Nature Communications, 2020. – Vol. 11

doi.org/10.1038/s41467-020-19160-7

7

Rougier N. Scientific Visualization: Python + Matplotlib. – 2021

github.com/rougier/scientific-visualization-book

8

Периодическая таблица методов визуализации

visual-literacy.org/periodic_table

Спасибо за внимание

Вопросы

phys-dev.github.io/soft-dev-book

hv