Достижение результатов, подобных ggplot в matplotlib, с использованием Rust-крейта plotters
Следующий код на Rust — это самое близкое, что мне удалось получить к примеру ggplot из matplotlib с использованием Rust-крейта plotters.
Код на Rust
src/main.rs
use plotters::prelude::*;
use plotters::style::{RGBColor, ShapeStyle};
use std::error::Error;
const GGPLOT_RED: RGBColor = RGBColor(0xE2, 0x4A, 0x33);
fn main() -> Result<(), Box<dyn Error>> {
// Создаём область рисования и настраиваем график
let root = BitMapBackend::new("sine_wave_plot.png", (1024, 768)).into_drawing_area();
// общий фон фигуры (оставляем белым)
root.fill(&WHITE)?;
// Определяем область графика (мы сделаем панель построения светло-серой, чтобы она была фоном сетки)
let mut chart = ChartBuilder::on(&root)
.caption("Sine Wave", ("sans-serif", 30).into_font())
.margin(24)
.x_label_area_size(50)
.y_label_area_size(50)
.build_cartesian_2d(0f64..2f64 * std::f64::consts::PI, -1.2f64..1.2f64)?;
// Заполняем область построения светло-серым, чтобы это было фоном сетки
// matplotlib ggplot: axes.facecolor = E5E5E5
chart.plotting_area().fill(&RGBColor(0xE5, 0xE5, 0xE5))?;
// Настраиваем сетку (стиль, подобный ggplot, с тонкими линиями сетки)
chart.configure_mesh()
.x_labels(10)
.y_labels(5)
.x_label_formatter(&|x| format!("{:.1}π", x / std::f64::consts::PI))
.y_label_formatter(&|y| format!("{:.1}", y))
.x_desc("Angle (radians)")
.y_desc("Amplitude")
// matplotlib ggplot: axes.labelcolor/xtick.color/ytick.color = 555555
.label_style(TextStyle::from(("sans-serif", 12).into_font()).color(&RGBColor(0x55, 0x55, 0x55)))
.axis_desc_style(TextStyle::from(("sans-serif", 16).into_font()).color(&RGBColor(0x55, 0x55, 0x55)))
// matplotlib ggplot: grid.color = white (основная сетка); второстепенная сетка по умолчанию выключена
.max_light_lines(0)
.bold_line_style(ShapeStyle::from(&WHITE).stroke_width(1))
.light_line_style(ShapeStyle::from(&WHITE).stroke_width(1))
// matplotlib ggplot: axes.edgecolor = white, axes.linewidth = 1
.axis_style(ShapeStyle::from(&WHITE).stroke_width(1))
// обеспечиваем наружные деления (отрицательное значение указывало бы внутрь)
.set_all_tick_mark_size(5)
.draw()?;
// Генерируем точки данных синусоиды
let mut sine_data = Vec::new();
for i in 0..=1000 {
let x = i as f64 * 2.0 * std::f64::consts::PI / 1000.0;
sine_data.push((x, x.sin()));
}
// Рисуем синусоиду
chart.draw_series(LineSeries::new(
sine_data,
ShapeStyle::from(&GGPLOT_RED).stroke_width(2),
))?
.label("sin(x)")
.legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], ShapeStyle::from(&GGPLOT_RED).stroke_width(3)));
// Рисуем легенду
chart.configure_series_labels()
.background_style(&RGBColor(0xE5, 0xE5, 0xE5).mix(0.9))
.border_style(&WHITE)
.label_font(("sans-serif", 14))
.position(SeriesLabelPosition::UpperRight)
.draw()?;
Ok(())
}Cargo.toml
[package]
name = "plottest"
version = "0.1.0"
edition = "2021"
[dependencies]
plotters = "0.3.5"
Эталонный код на Python
sine_wave_plot.py
#!/usr/bin/env python3
"""Создаёт график синусоиды в стиле ggplot и сохраняет его в `sine_wave_plot_py.png`.
Использование:
python3 plot_sine.py
Установка зависимостей:
python3 -m pip install -r requirements.txt
"""
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
plt.style.use("ggplot")
# Данные
x = np.linspace(0, 2 * np.pi, 1000)
y = np.sin(x)
# Размер фигуры, приближённый к 1024x768 при 100 DPI
fig, ax = plt.subplots(figsize=(10.24, 7.68))
ax.plot(x, y, color="red", alpha=0.8, linewidth=2, label="sin(x)")
# Форматируем деления оси X в кратных π
def pi_label(value, _pos):
val = value / np.pi
if abs(val) < 1e-6:
return "0"
return f"{val:.1f}π"
ax.xaxis.set_major_locator(plt.MaxNLocator(10))
ax.xaxis.set_major_formatter(FuncFormatter(pi_label))
# Подписи, заголовок, легенда
ax.set_xlabel("Angle (radians)", fontsize=16)
ax.set_ylabel("Amplitude", fontsize=16)
ax.set_title("Sine Wave", fontsize=24, fontweight="bold")
ax.legend(fontsize=12)
# Сетка и компоновка
ax.grid(True)
plt.tight_layout()
# Сохранение файла
plt.savefig("sine_wave_plot_py.png", dpi=100)
# Раскомментируйте для интерактивного отображения
# plt.show()
Обсуждение различий
Примечание: Я не пытался каким-либо образом подобрать размер шрифта и т.д.
Как видите, с некоторыми ручными усилиями два графика выглядят весьма похоже. Однако, поскольку сглаживание не реализовано в крейте plotters на данный момент (по состоянию на 2026-01-30), график на Rust выглядит значительно более «зубчатым», чем график в matplotlib.
Когда речь заходит о графиках для публикаций, это является существенным недостатком, и по этой причине я не могу рекомендовать его. Будем надеяться, что сглаживание будет реализовано в будущем.
Крупный план сглаживания в Python

Крупный план «сглаживания» в Rust (отсутствует)

Check out similar posts by category:
Rust, Python, Data Visualization
If this post helped you, please consider buying me a coffee or donating via PayPal to support research & publishing of new posts on TechOverflow