Когда мы создаем инфографику или постеры с данными, мы хотим привлечь внимание читателя: для этого изображение должно быть эстетически привлекательным и при этом убедительно доносить нашу мысль. Есть множество графических библиотек для создания графиков с помощью 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

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

Комментарии (1)


  1. havenoheart
    07.07.2023 09:47

    Спасибо за полезный материал, попробую на практике)