Когда мы создаем инфографику или постеры с данными, мы хотим привлечь внимание читателя: для этого изображение должно быть эстетически привлекательным и при этом убедительно доносить нашу мысль. Есть множество графических библиотек для создания графиков с помощью Python. Одна из них — это хорошо известная Matplotlib. Но графики, построенные ее стандартными средствами, часто выглядят скучными, и, чтобы оживить их, нужно потратить много времени.
Команда VK Cloud перевела статью о библиотеках тем для Matplotlib, а именно — о теме CyberPunk. Автор рассказывает, как ее загрузить, настроить и применять.
Фигура Matplotlib с подграфиками в стиле mplcyberpunk. Изображение автора
Немного вводных о теме
Киберпанк — популярный жанр фантастики, для которого характерны изображения мрачных антиутопических обществ с высоким уровнем развития технологий и отторжением традиционной человеческой культуры. Киберпанку часто придают футуристический вид: неоновые огни и яркие, смелые цвета.
Изображение создано автором в Midjourney Basic Plan (a bustling dystopian cyberpunk-themed futuristic city street featuring places with lots of street vendors. Shops and area surrounded with bright neon lights. Rainy and dark atmosphere. Photorealistic. — ar 3:2)
Тема CyberPunk привносит эти яркие неоновые цвета в Matplotlib. А чтобы применить этот стиль, нужно всего две строки кода на Python.
Пример фигуры, сделанной в Matplotlib в стиле CyberPunk. Изображение от dhaitz из CyberPunk Readme
Помните, что графики в этом стиле подойдут не для всех публикаций. Кроме того, такая гамма не воспринимается людьми с некоторыми нарушениями зрения. Так что перед использованием этого стиля оцените требования своей аудитории.
Импорт библиотек и создание данных
Перед созданием визуализаций надо импортировать несколько библиотек: matplotlib, pandas и numpy. Мы будем использовать их для создания, хранения и визуализации наших данных.
import matplotlib.pyplot as plt
import pandas as pd
import mplcyberpunk
import numpy as np
После импорта библиотек можно создать учебные данные с помощью следующего кода:
# Create a list of categories
categories = ['A', 'B', 'C', 'D']
# Create a DataFrame with 4 columns and 4 rows
data = {
'Category': categories,
'Value1': np.random.randint(0, 20, 4),
'Value2': np.random.randint(0, 20, 4),
'Value3': np.random.randint(0, 20, 4),
}
df = pd.DataFrame(data)
Этот код генерирует датафрейм Pandas, который состоит из четырех столбцов: один категориальный, а остальные — столбцы с произвольными целыми числами.
Столбчатые диаграммы в цветах Cyberpunk
Начнем с популярных столбчатых диаграмм. Чтобы создать такую диаграмму, воспользуемся методом
.plot()
в pandas и поставим значение x, которое является категориальной переменной. Еще нам нужно задать значение False
для stacked
и значение bar
для kind
.df.plot(x='Category', kind='bar', stacked=False, alpha=0.8, figsize=(10,10))
Когда мы выполняем этот код, получается базовая фигура Matplotlib:
Базовая столбчатая диаграмма в Matplotlib, созданная из df.plot. Изображение автора
В целом неплохо. Но не хватает изюминки, оформление можно значительно улучшить.
Для этого нужно добавить в
df.plot()
одну-единственную строку кода. Так мы применим к графику тему CyberPunk.with plt.style.context('cyberpunk'):
df.plot(x='Category', kind='bar', stacked=False, alpha=0.8,
figsize=(10,10))
Получаем следующую столбчатую диаграмму:
Столбчатая диаграмма Matplotlib в стиле mplcyberpunk. Изображение автора
У диаграммы появился темный фон, а у столбцов — «неоновая подсветка». В этом стиле у столбчатой диаграммы могут получиться слишком яркие цвета, поэтому нужно применить Alpha Value.
Линейные графики
То же самое можно проделать и с линейными графиками. Сначала вызовем
df.plot()
, но для kind
изменим значение bar
на line
. Еще в линейные графики можно добавить маркеры, которые помогают понять, где находятся наши данные. Это полезно, если в значениях между категориями очень маленькие изменения.df.plot(x='Category', kind='line',
lw=3, marker='.', ms=20,
figsize=(10,10))
Базовый линейный график Matplotlib, созданный с помощью df.plot. Изображение автора
Чтобы применить тему CyberPunk, нужно добавить в код
with plt.style.context(‘cyberpunk’):
.with plt.style.context('cyberpunk'):
df.plot(x='Category', kind='line',
lw=3, marker='.', ms=20,
figsize=(10,10))
Если выполнить этот код, появится следующий линейный график:
Библиотека темы CyberPunk поддерживает несколько дополнительных функций, например подсвечивание линий:
with plt.style.context('cyberpunk'):
df.plot(x='Category', kind='line',
lw=3, marker='.', ms=20,
figsize=(10,10))
mplcyberpunk.make_lines_glow()
Линейный график Matplotlib в стиле mplcyberpunk с эффектом подсвечивания линий. Изображение автора
А еще можно добавить заливку прозрачного градиента под линиями:
with plt.style.context('cyberpunk'):
df.plot(x='Category', kind='line',
lw=3, marker='.', ms=20,
figsize=(10,10))
mplcyberpunk.add_gradient_fill(alpha_gradientglow=0.4)
Линейный график Matplotlib в стиле mplcyberpunk с градиентной заливкой под линиями. Изображение автора
Градиентная заливка хорошо подходит, если на графике одна-две линии. Но если применить этот эффект для трех линий и более, они начнут сливаться друг с другом.
Лепестковые диаграммы в стиле CyberPunk
Лепестковые диаграммы часто используют для визуализации данных. Они позволяют сравнивать датасеты, одновременно отображая несколько переменных на двухмерном графике.
Чтобы лепестковые диаграммы хорошо смотрелись, в Matplotlib понадобится код подлиннее.
from matplotlib.patches import Patch
# Set up the data so that we can close the 'loop' of the area
categories = [*categories, categories[0]]
values_1 = [*data['Value1'], data['Value1'][0]]
values_2 = [*data['Value2'], data['Value2'][0]]
values_3 = [*data['Value3'], data['Value3'][0]]
# Set up the label potisions around the circle circumference
label_loc = np.linspace(start=0, stop=2 * np.pi, num=len(categories))
# Set up the figure
fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))
# Add our data as separate axes
ax.plot(label_loc, values_1, lw=2)
ax.plot(label_loc, values_2, lw=2)
ax.plot(label_loc, values_3, lw=2)
# Apply a fill to our lines
ax.fill(label_loc, values_1, alpha=0.3)
ax.fill(label_loc, values_2, alpha=0.3)
ax.fill(label_loc, values_3, alpha=0.3)
# Convert the lines and labels to a polar grid
lines, labels = plt.thetagrids(np.degrees(label_loc), labels=categories)
# Setup the radial lines
ax.set_ylim(0, 20)
ax.set_yticks(np.arange(0, 20, 2))
# Create custom legend handles
values_1_legend = Patch(facecolor='C0', alpha=0.5, label='Values1')
values_2_legend = Patch(facecolor='C1', alpha=0.5, label='Values2')
values_3_legend = Patch(facecolor='C2', alpha=0.5, label='Values3')
# Add a legend with custom position and handles
ax.legend(handles=[values_1_legend, values_2_legend, values_3_legend],
bbox_to_anchor=(1.3, 0.2), fontsize=20,
frameon=True)
plt.show()
При выполнении этого кода мы получим следующую лепестковую диаграмму со стандартной темой Matplotlib.
Базовая лепестковая диаграмма в Matplotlib. Изображение автора
Давайте используем те же строки, что и раньше, чтобы применить к базовой лепестковой диаграмме тему CyberPunk. Но сначала понадобится изменить границы и сетку.
with plt.style.context('cyberpunk'):
fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))
# Add our data as separate axes
ax.plot(label_loc, values_1, lw=2)
ax.plot(label_loc, values_2, lw=2)
ax.plot(label_loc, values_3, lw=2)
# Apply a fill to our lines
ax.fill(label_loc, values_1, alpha=0.3)
ax.fill(label_loc, values_2, alpha=0.3)
ax.fill(label_loc, values_3, alpha=0.3)
# Convert the lines and labels to a polar grid
lines, labels = plt.thetagrids(np.degrees(label_loc), labels=categories)
# Set up the grid and line properties
ax.tick_params(axis='both', which='major', pad=30, labelsize=15)
ax.spines['polar'].set_linewidth(3)
edge_color = (1, 1, 1, 0.2)
ax.spines['polar'].set_color(edge_color)
ax.grid(color='white', alpha=0.3)
# Setup the radial lines
ax.set_ylim(0, 20)
ax.set_yticks(np.arange(0, 20, 2))
# Create custom legend handles
values_1_legend = Patch(facecolor='C0', alpha=0.5, label='Values1')
values_2_legend = Patch(facecolor='C1', alpha=0.5, label='Values2')
values_3_legend = Patch(facecolor='C2', alpha=0.5, label='Values3')
# Add a legend with custom position and handles
ax.legend(handles=[values_1_legend, values_2_legend, values_3_legend],
bbox_to_anchor=(1.3, 0.2), fontsize=20,
frameon=True)
mplcyberpunk.add_glow_effects()
plt.show()
Если теперь выполнить код, то получим лепестковую диаграмму в стиле CyberPunk.
Подробнее изучить создание лепестковых диаграмм можно в другой моей статье: «Создаем изумительные лепестковые диаграммы в Matplotlib».
Подграфики в стиле CyberPunk
При создании фигур в Matplotlib часто нужно строить несколько графиков. Их типы зависят от того, что вы собираетесь визуально представить. В этом примере мы покажем, как создать фигуру Matplotlib с четырьмя подграфиками: двумя линейными, одной диаграммой рассеяния и одной столбчатой диаграммой.
Чтобы не забыть применить стиль CyberPunk, давайте добавим строку:
with plt.style.context(‘cyberpunk’):
Чтобы применить какой-нибудь спецэффект из библиотеки Mplcyberpunk, например подсвечивание линий, нужно указать ось, к которой мы применим этот стиль. Для этого нужно указать объект
ax
к параметру ax
. Например: mplcyberpunk.make_lines_glow(ax=ax4)
with plt.style.context('cyberpunk'):
fig = plt.figure(figsize=(15, 10))
ax1 = plt.subplot2grid((2,3), (0,0))
ax2 = plt.subplot2grid((2,3), (0,1))
ax3 = plt.subplot2grid((2,3), (0,2))
ax4 = plt.subplot2grid((2,3), (1,0), colspan=3)
# Line Plot 1
x_data = np.linspace(0, 20, 50)
y_data_clean = np.sin(x_data)
noise = np.random.normal(0, 2, y_data_clean.shape)
y_data_noise = y_data_clean + noise
ax1.plot(x_data, y_data_noise)
ax1.plot(x_data, y_data_clean, lw=2)
ax1.set_title('Plot 1', fontsize=14)
# Scatter Plots
ax2.scatter(x=(np.random.randint(0, 20, 100)), y=np.random.randint(0,20, 100))
ax2.scatter(x=(np.random.randint(0, 20, 100)), y=np.random.randint(0,20, 100))
ax2.set_title('Plot 2', fontsize=14)
# Bar Chart
bar_values = np.array(["A", "B", "C", "D"])
bar_heights = ([20, 10, 5, 7])
bar_heights_2 = ([10, 15, 2, 18])
bar_width = 0.35
bar_pos_1 = np.arange(len(bar_values))
bar_pos_2 = [x + bar_width for x in bar_pos_1]
# Make sure the bars are offset from each other
ax3.bar(x=bar_pos_1, height=bar_heights, width=bar_width, label='Group 1')
ax3.bar(x=bar_pos_2, height=bar_heights_2, width=bar_width, label='Group 2')
ax3.set_xticks([r + bar_width / 2 for r in range(len(bar_heights))])
ax3.set_xticklabels(bar_values)
ax3.set_title('Plot 3', fontsize=14)
# Bottom Axis
values = np.arange(0, 10, 0.1)
sine_wave1 = np.sin(values)
sine_wave2 = sine_wave1 * 2
sine_wave3 = sine_wave1 + 0.5
ax4.plot(sine_wave1)
ax4.plot(sine_wave2)
ax4.plot(sine_wave3)
ax4.set_title('Plot 4', fontsize=14)
mplcyberpunk.make_lines_glow(ax=ax1)
mplcyberpunk.make_lines_glow(ax=ax4)
plt.suptitle('Interesting Inforgraphic Using CyberPunk', fontsize=25)
plt.show()
При выполнении кода мы получаем такой график:
Фигура Matplotlib с несколькими подграфиками в стиле cyberpunk. Изображение автора
Заключение
Библиотека стилей CyberPunk помогает легко и быстро превратить скучные фигуры Matplotlib в футуристические изображения, и для этого нужно всего несколько строк кода. Но, как я упомянул в начале статьи, прежде чем применить эту тему, важно четко представить свою аудиторию и цель, которую вы хотите достичь визуализацией.
Удачного творчества с CyberPunking!
Все описанное здесь вы можете повторить в JupyterHub в ML Platform от VK Cloud. Для тестирования мы начисляем новым пользователям 3000 бонусных рублей и будем рады вашей обратной связи.
Stay tuned
Присоединяйтесь к телеграм-каналу «Данные на стероидах». В нем вы найдете все об инструментах и подходах к извлечению максимальной пользы из работы с данными: регулярные дайджесты, полезные статьи, а также анонсы конференций и вебинаров.
havenoheart
Спасибо за полезный материал, попробую на практике)