Перейти к основному содержимому

Pkg и Plots в Julia

Разработчику Архитектору

Дальше: управление потоком · справочник Julia


Pkg и Plots в Julia

Pkg — встроенный менеджер пакетов Julia (реестр General на GitHub). Plots.jl — унифицированный API поверх бэкендов (GR, Plotly, PyPlot) для научной визуализации.

Julia сочетает удобство скриптового языка и производительность JIT-компиляции — см. раздел Julia. Практикум по шагам — окружение Pkg, Project.toml, DataFrames, первые графики, бэкенды, типичные ошибки.

ШагТемаЗачем
1REPL-режим pkgУстановка пакетов
2Project.toml и ManifestВоспроизводимость
3Активация окруженияИзолировать проект
4DataFrames + CSVТаблицы как в R
5Plots.jl — линии и scatterПервые графики
6Бэкенды и subplotsВыбор рендерера
7Сквозной analysis.jlЗакрепление
8Запуск и notebookCLI и Pluto
МатериалЗачем
Основы JuliaREPL, синтаксис, массивы
Типы и диспетчеризацияBroadcast sin.(x)
Управление потокомif, циклы
Первая программаУстановка Julia
tidyverse в RТот же CSV в R
pandasАналог в Python
Анализ данныхТеория ETL

Навигация по блоку Julia

VS Code + Julia

Расширение Julia в VS Code / Cursor запускает REPL с активным окружением проекта. Установка Julia — в первой программе.


Шаг 1 — REPL-режим Pkg

В Julia REPL нажмите ] — приглашение сменится на pkg>:

# pkg> режим (после нажатия ])
add Plots DataFrames CSV
status
st
rm OldPackage

Выход из pkg-режима — Backspace или Ctrl+C.

Те же операции из обычного режима:

using Pkg
Pkg.add("Plots")
Pkg.add(["DataFrames", "CSV"])
Pkg.status()
Pkg.rm("OldPackage")

Разбор:

  • add записывает пакет в активный Project.toml и обновляет Manifest.toml.
  • status показывает прямые зависимости проекта.
  • Первая установка пакета компилирует его — это может занять минуты.

Реестр General: github.com/JuliaRegistries/General.


Шаг 2 — структура проекта

myanalysis/
├── Project.toml
├── Manifest.toml
├── analysis.jl
└── data/
└── sales.csv

Project.toml

name = "MyAnalysis"
uuid = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
version = "0.1.0"
authors = ["You <you@example.com>"]

[deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"

[compat]
julia = "1.10"
Plots = "1.39"
ФайлРоль
Project.tomlИмя проекта, прямые зависимости, compat
Manifest.tomlПолный lock всех транзитивных версий

Коммитьте Manifest.toml в приложениях — так коллеги получат те же версии. Для библиотек иногда коммитят только Project.toml.

Аналог: venv + requirements.txt в Python, renv в R — tidyverse 104.


Шаг 3 — активация окружения

using Pkg
Pkg.activate(".")
Pkg.instantiate() # установить из Manifest

В скрипте первые строки:

using Pkg
Pkg.activate(@__DIR__)

@__DIR__ — каталог файла скрипта; окружение подхватывается при запуске из любой папки.

Запуск из терминала:

julia --project=. analysis.jl

Флаг --project=. эквивалентен Pkg.activate для одной сессии.

Совместимость версий

# pkg>
add DataFrames@1.6
update

Секция [compat] ограничивает допустимые версии. Julia 1.x следует SemVer; мажорные обновления пакетов могут ломать API — фиксируйте Manifest перед релизом отчёта.


Шаг 4 — DataFrames и CSV

using Pkg
Pkg.activate(@__DIR__)

using DataFrames, CSV

df = CSV.read("data/sales.csv", DataFrame)
first(df, 5)
describe(df)

Фильтрация и агрегаты:

using Statistics

positive = filter(row -> row.amount > 0, df)

by_region = combine(
groupby(positive, :region),
:amount => sum => :total,
:amount => length => :n,
:amount => mean => :avg
)

sort!(by_region, :total, rev=true)

Сравнение с dplyr — tidyverse:

ЗадачаR (dplyr)Julia (DataFrames)
Фильтрfilter(amount > 0)filter(row -> row.amount > 0, df)
Группировкаgroup_by(region)groupby(df, :region)
Агрегатsummarise(total = sum(amount))combine(..., :amount => sum => :total)

Точка в sin.(x) и row.amountbroadcast и доступ к полям — см. типы.


Шаг 5 — Plots.jl, первый график

using Plots
gr() # бэкенд GR — быстрый локально

x = 0:0.1:2π
y = sin.(x)

plot(x, y,
label="sin",
title="Демо",
xlabel="x",
ylabel="y",
linewidth=2
)

savefig("sin.png")

Разбор:

  • 0:0.1:2π — диапазон с шагом 0.1.
  • sin.(x) — поэлементный синус (broadcast).
  • plot создаёт новый график; savefig пишет PNG в текущий каталог.
  • gr() выбирает бэкенд GR до первого plot.

Несколько серий на одном графике

plot(x, sin.(x), label="sin", color=:blue)
plot!(x, cos.(x), label="cos", color=:red)

Суффикс ! — добавить на текущий график (plot!, scatter!).

Scatter и histogram

scatter(df.amount, df.price,
xlabel="Amount",
ylabel="Price",
legend=false,
alpha=0.6
)

histogram(df.amount,
bins=20,
title="Распределение amount",
xlabel="Amount",
fillalpha=0.5
)

Столбчатый график из агрегата

bar(by_region.region, by_region.total,
xlabel="Region",
ylabel="Total",
legend=false,
color=:steelblue
)

Шаг 6 — бэкенды и subplots

BackendКогда использовать
GRЛокально, быстро, PNG/PDF
PlotlyJSИнтерактив в браузере
PyPlotПривычный matplotlib
PGFPlotsXLaTeX-публикации
UnicodePlotsТерминал без GUI
using PlotlyJS
plotlyjs()

plot(x, sin.(x), label="sin")
# интерактивное окно или HTML

Установка бэкенда:

# pkg>
add PlotlyJS

Subplots

p1 = plot(x, sin.(x), title="sin")
p2 = plot(x, cos.(x), title="cos")
plot(p1, p2, layout=(2, 1), size=(800, 600))
savefig("sin_cos.png")

layout=(rows, cols) задаёт сетку. size — пиксели итоговой картинки.

Plots и Makie

Plots.jl — единый простой API для старта. Makie.jl — современная grammar-of-graphics с большими возможностями 3D и интерактива. Для отчётов часто хватает Plots + GR.


Шаг 7 — сквозной analysis.jl

# analysis.jl
using Pkg
Pkg.activate(@__DIR__)

using CSV, DataFrames, Statistics, Plots

gr()

# 1. Загрузка
df = CSV.read("data/sales.csv", DataFrame)

# 2. Очистка
clean = filter(row -> row.amount > 0, df)

# 3. Агрегат по регионам
summary_df = combine(
groupby(clean, :region),
:amount => sum => :total
)
sort!(summary_df, :total, rev=true)

# 4. Графики
bar(summary_df.region, summary_df.total,
title="Продажи по регионам",
xlabel="Регион",
ylabel="Сумма",
legend=false
)
savefig("report/bar.png")

dates = sort(unique(clean.date))
# упрощённо: линия сумм по дате (если date в данных)
by_date = combine(groupby(clean, :date), :amount => sum => :daily_total)
plot(by_date.date, by_date.daily_total,
marker=:circle,
title="Динамика по дням",
xlabel="Дата",
ylabel="Сумма"
)
savefig("report/line.png")

println("Готово: report/bar.png, report/line.png")

Создайте каталоги заранее:

mkdir -p myanalysis/data myanalysis/report

Сравните вывод с tidyverse pipeline на том же sales.csv.


Шаг 8 — запуск, notebook, CI

Терминал

cd myanalysis
julia --project=. analysis.jl

Pluto.jl

# pkg>
add Pluto
using Pluto
Pluto.run()

Notebook с реактивными ячейками — удобно для исследования данных.

IJulia (Jupyter)

Pkg.add("IJulia")

Минимальный CI

- uses: julia-actions/setup-julia@v2
with:
version: '1.10'
- run: julia --project=. -e 'using Pkg; Pkg.instantiate(); include("analysis.jl")'

Связь с разделом анализа данных

ЗадачаJulia-пакет
Таблицы, ETLDataFrames, CSV
СтатистикаStatsBase, HypothesisTests
MLFlux.jl, MLJ
Большие данныеArrow, DuckDB.jl
ВизуализацияPlots, Makie

Обзор — анализ данных; big data — 3.11/11; численные методы — математическое программирование.

Plots.jl, ggplot2 и matplotlib

АспектPlots.jlggplot2matplotlib
APIЕдиный слойGrammar of graphicsИмперативный + OO
Большие массивыХорошо с GRСреднеЗависит от backend
Экосистема statsРастётЗрелаяЗрелая

Julia удобна, когда один язык и считает, и рисует на больших массивах без вызова Python.


Типичные ошибки Pkg и Plots

СимптомПричинаРешение
Package X not foundНе в [deps]Pkg.add("X"), instantiate
Разные версии на машинахНет Manifest в gitКоммит Manifest.toml
Долгий precompileПервый addНормально; кэш в ~/.julia
Конфликт версийНесовместимый compatPkg.resolve(), правка [compat]
Пустой графикНеверные столбцыnames(df), describe
GR не найденНет пакета GRadd Plots подтянет GR
Старый график в файлеsavefig без имениЯвный путь savefig("out.png")
Медленный первый plotJIT компиляцияВторой вызов быстрее

Практический чек-лист

  1. mkdir myanalysis && cd myanalysis
  2. Julia: ] activate .add CSV DataFrames Plots
  3. Положить sales.csv в data/
  4. Написать analysis.jl с activate, read → filter → plot → savefig
  5. julia --project=. analysis.jl — файлы в report/
  6. Закоммитить Project.toml и Manifest.toml
  7. Сравнить с R tidyverse на том же CSV

Упражнения

  1. Создайте проект с activate . и добавьте только CSV и DataFrames; выведите describe для sales.csv.
  2. Постройте histogram и density для столбца amount на одном layout=(2,1).
  3. Переключите бэкенд на plotlyjs() и сохраните интерактивный HTML (подсказка: plotly() extension).
  4. Зафиксируйте [compat] julia = "1.10" и проверьте Pkg.status() на второй машине с instantiate.
  5. Перепишите combine(groupby(...)) в цикл по groupby — сравните читаемость с dplyr.

FAQ

Нужен ли отдельный conda/venv? Нет. Julia Pkg — встроенные окружения на проект.

Где хранятся пакеты? ~/.julia (или %USERPROFILE%\.julia на Windows). Каталог большой — не коммитьте в git.

Plots или Makie? Plots — быстрый старт; Makie — сложные 3D и кастомная графика.

Почему первый запуск долгий? JIT компилирует методы под конкретные типы. Повторные вызовы быстрее.

Как обновить пакеты? ] up или Pkg.update(); проверьте, что отчёты воспроизводятся.

Есть ли renv для Julia? Роль renv выполняют Project.toml + Manifest.toml.


Глоссарий

ТерминОпределение
PkgВстроенный менеджер пакетов Julia
GeneralОсновной реестр пакетов
Project.tomlМанифест прямых зависимостей
Manifest.tomlLock-файл всех версий
activateПривязка сессии к окружению проекта
instantiateУстановка пакетов по Manifest
compatОграничения совместимости версий
BackendДвижок отрисовки Plots (GR, Plotly…)
BroadcastПоэлементные операции с точкой .
precompileКэш скомпилированного пакета

Что дальше

  • Makie.jl — grammar-of-graphics и 3D.
  • BenchmarkTools — профилирование hot loops.
  • PackageCompiler.jl — standalone binary.
  • DifferentialEquations — модели и визуализация траекторий.
  • Теория типов — типы и диспетчеризация.
Итог

Pkg даёт воспроизводимое окружение; Plots — быстрый путь от численного эксперимента к картинке для отчёта. Освойте activate, Manifest и один бэкенд (GR) — дальше масштабируйте на анализ данных.

Production-отчёты

Фиксируйте версию Julia в CI, коммитьте Manifest.toml, сохраняйте графики с явным dpi и размером. Для публикаций рассмотрите PGFPlotsX или экспорт SVG.


Шаг 9 — атрибуты графика Plots

plot(x, sin.(x),
label="sin",
linewidth=3,
linecolor=:blue,
linestyle=:dash,
marker=:circle,
markersize=4,
background_color=:white,
foreground_color=:black,
grid=true,
legend=:topright,
size=(900, 500),
dpi=150
)
АтрибутЭффект
linewidthТолщина линии
linestyle:solid, :dash, :dot
markerМаркер точки
alphaПрозрачность
sizeРазмер canvas в пикселях
dpiПлотность при сохранении

Шаг 10 — групповые цвета из DataFrame

using CategoricalArrays

clean = copy(df)
clean.region = categorical(clean.region)

scatter(clean.amount, clean.price,
group=clean.region,
xlabel="Amount",
ylabel="Price",
legend=:topright
)

group раскрашивает серии по столбцу — аналог color = region в ggplot2.


Шаг 11 — статистические графики

using Statistics

histogram(df.amount, bins=30, normalize=:probability)
histogram(df.amount, bins=30, normalize=:density)

# boxplot по группам — вектор групп
boxplot(clean.region, clean.amount, legend=false)
# violin — через StatsPlots
# pkg> add StatsPlots
using StatsPlots
@df clean violin(:region, :amount, legend=false)

Шаг 12 — работа с датами

using Dates

clean = transform(clean, :date => ByRow(Date) => :date)
sort!(clean, :date)

by_date = combine(groupby(clean, :date), :amount => sum => :daily_total)

plot(by_date.date, by_date.daily_total,
marker=:circle,
xlabel="Дата",
ylabel="Сумма",
xrotation=45
)

Julia Dates похож на lubridate в R — см. tidyverse.


Шаг 13 — цепочка как в dplyr

using DataFrames, Statistics

result = df |>
(t -> filter(row -> t.amount > 0, t)) |>
(t -> groupby(t, :region)) |>
(g -> combine(g, :amount => sum => :total, :amount => mean => :avg)) |>
(t -> sort(t, :total, rev=true))

Оператор |> (pipe) в Julia 1.5+ читается как pipeline в R.

Альтернатива с DataFramesMeta:

# pkg> add DataFramesMeta
using DataFramesMeta

@chain df begin
@filter(:amount > 0)
@group_by(:region)
@summarize(:total = sum(:amount), :avg = mean(:amount))
@orderby(:total, order=Rev)
end

Шаг 14 — экспорт и интерактив

using Plots
gr()

p = plot(x, sin.(x), label="sin")
savefig(p, "out/sin.png")
savefig(p, "out/sin.pdf")

# PlotlyJS — HTML
using PlotlyJS
plotlyjs()
p2 = plot(x, cos.(x))
# savefig(p2, "out/cos.html") # при поддержке бэкенда

Для публикаций PDF через PGFPlotsX — векторная графика для LaTeX.


Шаг 15 — окружение в Jupyter и Pluto

IJulia

using Pkg
Pkg.add("IJulia")
# затем в Jupyter: New → Julia notebook

Первая ячейка:

using Pkg
Pkg.activate(".")
using CSV, DataFrames, Plots
gr()

Pluto

using Pluto
Pluto.run(1234)

Pluto реактивно пересчитывает ячейки при изменении зависимостей — удобно для обучения.


Шаг 16 — сравнение цикла и broadcast

# медленнее — scalar loop
y_loop = Vector{Float64}(undef, length(x))
for i in eachindex(x)
y_loop[i] = sin(x[i])
end

# быстрее — broadcast
y_bc = sin.(x)

@assert y_loop ≈ y_bc

Broadcast — основа производительности Julia на численных графиках. Теория — типы и диспетчеризация.


Шаг 17 — интеграция с разделом анализа

Этап аналитикиJuliaRPython
ЗагрузкаCSV.jlreadrpandas
Очисткаfilter transformdplyrpandas
ВизуализацияPlotsggplot2matplotlib
ОтчётPluto / JupyterR MarkdownQuarto

Сквозной контекст — анализ данных.


Дополнительные упражнения

  1. Постройте heatmap случайной матрицы 10×10 с color=:viridis.
  2. Сохраните один график в PNG 300 dpi и PDF — сравните размер файлов.
  3. Используйте @time для сравнения sin.(x) и цикла на x длиной 1_000_000.
  4. Добавьте StatsPlots и постройте violin по region.
  5. Создайте Pluto-notebook с activate и тремя ячейками read → plot → savefig.

Дополнительный FAQ

Почему график не обновляется в скрипте? plot возвращает объект; передайте его в savefig(plot, path).

Как задать шрифт? Зависит от бэкенда; GR поддерживает ограниченный набор. Для полного контроля — PGFPlotsX.

Нужен ли Python для PyPlot? Да, бэкенд PyPlot вызывает matplotlib — установите Python и PyCall.

Как ускорить повторные plot? Первый вызов компилирует; держите сессию Julia открытой или используйте --project в одном процессе.

Где хранить большие данные? Arrow.jl, DuckDB.jl — см. big data в анализе.


Разбор analysis.jl — блоками

БлокОтветственность
Pkg.activateПравильное окружение
CSV.readВвод
filter / groupbyТрансформация
gr()Выбор рендерера
bar / plotВизуализация
savefigАртефакт для отчёта
printlnПодтверждение в CI

Полный walkthrough — myanalysis с тестом в CI

Структура

myanalysis/
├── Project.toml
├── Manifest.toml
├── data/sales.csv
├── src/
│ └── MyAnalysis.jl
├── test/
│ └── runtests.jl
└── analysis.jl

src/MyAnalysis.jl

module MyAnalysis

using CSV, DataFrames, Statistics

export load_sales, summarize_by_region

function load_sales(path::AbstractString)
CSV.read(path, DataFrame)
end

function summarize_by_region(df::DataFrame)
positive = filter(row -> row.amount > 0, df)
combined = combine(
groupby(positive, :region),
:amount => sum => :total,
:amount => length => :n
)
sort!(combined, :total, rev=true)
end

end

test/runtests.jl

using Test
using DataFrames
include("../src/MyAnalysis.jl")
using .MyAnalysis

@testset "summarize" begin
df = DataFrame(region=["N","N","S"], amount=[10.0, 5.0, 0.0])
result = summarize_by_region(df)
@test nrow(result) == 2
@test result[1, :total] == 15.0
end

Запуск тестов

# pkg> test
julia --project=. -e 'using Pkg; Pkg.test()'

analysis.jl — точка входа

using Pkg
Pkg.activate(@__DIR__)
using CSV, DataFrames, Plots
include("src/MyAnalysis.jl")
using .MyAnalysis

gr()
df = load_sales("data/sales.csv")
summary_df = summarize_by_region(df)
bar(summary_df.region, summary_df.total, legend=false)
savefig("report/bar.png")

Сравните summary_df с выводом tidyverse на том же файле.


Ссылки на смежные темы

ТемаМатериал
Основы Julia2.md
Broadcast4.md
Первая программа7.md
tidyverseR 104
Анализ данных3.11
Численные методы3.12

В подборках

Статья входит в маршрут Julia и сопоставляется с tidyverse в R и pandas в рамках анализа данных.



Практикум — шаг 9: StatsPlots

using StatsPlots
histogram(df.amount, bins=20, label="")

Практикум — шаг 10: DataFramesMeta

using DataFramesMeta

@chain df begin
@filter(:amount .> 0)
@transform(:tax = :amount .* 0.2)
@by(:region, :total = sum(:amount))
end

Практикум — шаг 11: Dates и группировка

using Dates

df[!, :month] = map(d -> Dates.month(d), df.date)
combine(groupby(df, :month), :amount => sum => :total)

Практикум — шаг 12: PackageCompiler (обзор)

using PackageCompiler
create_app("analysis.jl", "MyApp")

Standalone binary для отчётов без установки Julia на целевой машине.


Воркшоп Julia (60 мин)

МинЗадача
0–10activate + add
10–25CSV read
25–40combine groupby
40–55bar + savefig
55–60--project run

Troubleshooting Julia

СимптомРешение
Package not foundPkg.add, instantiate
Manifest driftcommit Manifest
precompile slowнорма первый раз
empty plotnames(df)

FAQ Julia

conda? — не нужен, Pkg встроен.

Plots vs Makie? — старт vs 3D.

Первый запуск медленный? — JIT warmup.

renv аналог? — Project + Manifest.



Дополнительные сценарии (Pkg/Plots)

Сценарий A: activate в скрипте

using Pkg; Pkg.activate(@__DIR__)

Сценарий B: pkg> add и status

# ] add CSV
# st

Сценарий C: GR backend

using Plots; gr()
plot(1:10, rand(10))
savefig("test.png")

Сценарий D: groupby combine

combine(groupby(df, :region), :amount => sum => :total)

Сценарий E: Manifest на второй машине

git clone ... && julia --project=. -e 'using Pkg; Pkg.instantiate()'

Упражнения — контрольная точка

  1. DataFramesMeta @chain pipeline.
  2. plotlyjs() + сохранение HTML.
  3. subplot sin/cos layout (2,1).
  4. CI с julia-actions/setup-julia.
  5. Тот же CSV что в R 104.
Содержание