Галерея графиков Engee¶
В этом наборе примеров мы покажем, как выглядят самые разные виды графиков в Engee, и какими средствами достигается такой результат – примеры данных и кода.
Правильно подобранный тип графика позволяют сохранить или донести до слушателя нужную информацию в очень красноречивой, при этом лаконичной форме. Графики берут информацию из переменных, которые должны существовать в рабочей области памяти (должны быть видны в окне Переменные). Их отображение, как правило, осуществляется из интерактивных скриптов ngscript, сразу после соответствующих ячеек с кодом. Конечно, есть исключения
- графики в формате Unicode можно отображать и в командной строке, однако при наличии графических интерактивных графиков, такой ограниченный формат может быть нужен разве что для нужд специального графического дизайна;
- графики можно сохранять в файловое хранилище и открывать как файлы из файлового браузера (иногда это полезно).
Самая простая и часто используемая команда для выводов графиков – функция plot()
из библиотеки Plots
для вывода графиков.
Библиотека Plots в Engee подключается автоматически.
При этом в экосистеме Engee/Julia есть еще множество библиотек для вывода красивых графиков, некоторые мы рассмотрим в этой демонстрации:
StatsPlots
для вывода сложных статистических графиков,GMT
илиGeneral Mapping Tools
для вывода географических карт.
Мы также советуем не избегать библиотек, позволяющих создавать гораздо более насыщенные и профессиональные визуализации, например:
Makie
для очень качественной визуализации сложных данных,Luxor
– язык для создания векторной двухмерной графики.
Когда библиотека вывода построила график, она передает его в графическое окружение, и здесь есть варианты:
- окружение
gr
(которое включено по умолчанию) строит быстрые, экономные и не интеравтивные графики (включается командойgr()
), которые можно сохранить при помощи контекстного меню plotly
илиplotlyjs
создают интерактивное полотно, на котором график можно масштабировать, вращать и сохранять при помощи кнопок интерфейса (переключиться на них можно, соответственно, командамиplotly()
иplotlyjs()
)
А еще для вывода графиков вы можете выбрать растровый (png
) или векторный (svg
) формат. Указав внутри команд gr/plotly/plotlyjs
аргумент fmt=:svg
вы получите очень изящный, масштабируемый график в векторном формате, однако при наличии большого количества элементов на графике, особенно если он будет интерактивным, его вывод потребует больше ресурсов. Другое дело – растровые графики (fmt=:png
). Они быстрее строятся и не требуют таких ресурсов при перерисовке.
Остальные элементы рецепта идеального графика вы найдете ниже.
А теперь, приглашаем – в галерею графиков!
gr()
plot([1,2,3], [1,3,7])
Анализ данных¶
Построение столбчатой диаграммы по таблице данных.
using DataFrames, HTTP, CSV;
# Открыть данные из файла
data = sort( CSV.File( "data/city.csv" ) |> DataFrame, ["population"], rev=true );
# (или) Загрузить данные с сервера
#url = "https://raw.githubusercontent.com/hflabs/city/master/city.csv"
#data = sort( CSV.File( HTTP.get(url).body) |> DataFrame, ["population"], rev=true );
bar( first(data, 8).population, label="Население, чел.", xrotation = 30 )
xticks!( 1:8, first(data, 8).address )
Изучение корреляции многомерных данных при помощи библиотеки StatsPlots
и функции corrplor
.
using StatsPlots, DataFrames, LaTeXStrings
M = randn( 1000, 4 )
M[:,2] .+= 0.8sqrt.(abs.(M[:,1])) .- 0.5M[:,3] .+ 5
M[:,3] .-= 0.7M[:,1].^2 .+ 2
corrplot( M, label = [L"$x_i$" for i=1:4],
xtickfontsize=4, ytickfontsize=6,
guidefontcolor=:blue, yguidefontsize=15, yguidefontrotation=-45.0 )
Функция marginalkde
из библиотеки StatsPlots
using StatsPlots
x = randn(1024)
y = randn(1024)
marginalkde(x, x+y)
using DataFrames, Statistics
# Создадим данные
df = DataFrame(Возраст=rand(4), Баланс=rand(4), Должность=rand(4), Зарплата=rand(4))
cols = [:Возраст, :Баланс, :Должность] # Выберем часть данных
M = cor(Matrix(df[!,cols])) # Ковариационная матрица
# График
(n,m) = size(M)
heatmap( M, fc=cgrad([:white,:dodgerblue4]), xticks=(1:m,cols), xrot=90, yticks=(1:m,cols), yflip=true, leg=false )
annotate!( [(j, i, text(round(M[i,j],digits=3), 10,"Arial",:black)) for i in 1:n for j in 1:m] )
Обычная гистограмма: функция histogram
using Random
Random.seed!(2018)
x = randn(1000)
y = randn(1000)
z = randn(1000)
histogram(x, bins=20, alpha=0.4, label="A")
histogram!(y, bins=20, alpha=0.6, label="B")
histogram!(z, bins=20, alpha=0.8, label="C")
График распределения двухмерной выборки: функция histogram2d
x = randn(10^4)
y = randn(10^4)
histogram2d(x, y)
Объемный график двухмерной гистограммы при помощи wireframe
using StatsBase
x = randn(10^4)
y = randn(10^4)
h = StatsBase.fit( Histogram, (x, y), nbins=20 )
wireframe( midpoints(h.edges[1]), midpoints(h.edges[2]), h.weights )
Совмещение графиков с различным оформлением
using Random
Random.seed!(1)
plot( Plots.fakedata(100, 12),
layout = 4,
palette = cgrad.([:grays :blues :heat :lightrainbow]),
bg_inside = [:orange :pink :darkblue :black],
seriestype= [:line :scatter :histogram :line] )
Облако слов (wordcloud):
import Pkg; Pkg.add(["WordCloud"], io=devnull);
using WordCloud, HTTP
# Загрузить текст из файла
content = read( open("data/Википедия - Математика.txt", "r"), String )
# Или загрузить данные с сервера
#url = "https://ru.wikipedia.org/wiki/Математика"
#resp = HTTP.request("GET", url, redirect=true)
#content = resp.body |> String |> html2text
stopwords = ["с", "в", "и", "от", "или", "под", "как", "на", "из", "это", "об", "что", "по", "млн", "за", "при", "www", "для", "не", "со", "но", "то"];
stopwords = vcat(stopwords, string.(collect(1:100)));
wc = wordcloud( processtext( content, maxnum=100, stopwords=stopwords ),
mask=shape(ellipse, 600, 400, color=(0.98, 0.97, 0.99), backgroundcolor=1, backgroundsize=(700, 550)),
masksize=:original, colors=:seaborn_icefire_gradient, angles=[0] ) |> generate!
paint(wc, "$(@__DIR__)/fromweb.svg")
wc
Анимация¶
Создание GIF-анимации при помощи команды @animate
, запускающей в цикле стороннюю функцию, которая рисует 150 окружностей уменьшающегося радиуса, с растущим показателем прозрачности. Кроме прочих, можно также использовать формат mp4
.
@userplot CirclePlot
@recipe function f(cp::CirclePlot)
x, y, i = cp.args
n = length(x)
inds = circshift(1:n, 1 - i)
linewidth --> range(0, 10, length = n)
seriesalpha --> range(0, 1, length = n)
aspect_ratio --> 1
label --> false
x[inds], y[inds]
end
n = 150
t = range(0, 2π, length = n)
x = sin.(t)
y = cos.(t)
anim = @animate for i ∈ 1:n
circleplot(x, y, i)
end
gif(anim, "$(@__DIR__)/anim_fps15.gif", fps = 15)
Вращающийся объект (геометрия задана в STL файле)
import Pkg; Pkg.add(["Meshes", "MeshIO"], io=devnull);
using Meshes, MeshIO, FileIO
gr();
obj = load( "$(@__DIR__)/data/lion.stl" );
@gif for az in 0:10:359
p = plot( camera = (az, -20), axis=nothing, border=:none, aspect_ratio=:equal, size=(400,400) )
for i in obj
m = Matrix([i[1] i[2] i[3] i[1]])'
if m[1,1] > 0 plot!( p, m[:,1], m[:,2], m[:,3], lc=:green, label=:none, lw=.4, aspect=:equal )
else plot!( p, m[:,1], m[:,2], m[:,3], lc=:gray, label=:none, lw=.4, aspect=:equal )
end
end
end
Вывод матриц и изображений¶
Функция heatmap
include( "$(@__DIR__)/data/peaks.jl" );
(x, y, z) = peaks()
heatmap(x, y, z)
using LaTeXStrings
x = range( -1.3, 1.3, 501 );
y = range( -1.3, 1.3, 501 );
X = repeat( x, outer = [1,501] )
Y = repeat( y', outer = [501,1] )
#C = ones( size(X) ) .* ( 0.360284 + 0.100376*1im );
C = ones( size(X) ) .* ( -0.75 + 0.1im );
Z_max = 1e6; it_max = 50;
Z = Complex.( X, Y );
B = zeros( size(C) );
for k = 1:it_max
Z = Z.^2 .+ C;
B = B .+ ( abs.(Z) .< 2 );
end
heatmap( B,
aspect_ratio = :equal,
cbar=false,
axis=([], false),
color=:jet )
title!( L"Julia Set $(c=0.360284+0.100376i)$" )
Вывод иллюстраций из файлов: библиотека Images
using Images
load( "$(@__DIR__)/data/640px-Business_Centre_of_Moscow_2.jpg" )
Графики в декартовых координатах¶
Вывод двух тригонометрических функций, заданных векторами, на декартовой координатной плоскости.
x = 0:0.1:2pi
y1 = cos.(x)
y2 = sin.(x)
plot(x, y1, c="blue", linewidth=3, label="cos")
plot!(x, y2, c="red", line=:dash, label="sin")
title!("Тригонометрические функции")
xlabel!("Угол (рад)")
ylabel!("sin(x) и cos(x)")
# Отдельной командой установим границы осей
plot!( xlims=(0,2pi), ylims=(-2, 2) )
Заполнение площади под графиком (аргумент fillrange
)
using Distributions
x = range(-3, 3, 100 )
y = pdf.( Normal(0,1), x )
ix = abs.(x) .< 1
plot( x[ix], y[ix], fillrange = zero(x[ix]), fc=:blues, leg=false)
plot!( x, y, grid=false, lc=:black, widen=false )
График с заполнением (area
)
x = 1:10;
areaData = x .* rand(10,5) .* 5;
cur_colors = theme_palette(:default)
plot()
for i in 1:size(areaData,2)
plot!( areaData[i,:], fillcolor = cur_colors[i], fillrange = 0, fillalpha=.5 )
end
plot!()
Накопляющийся график с заполнением
x = 1:10;
areaData = x .* rand(10,5);
cur_colors = theme_palette(:default)
plot()
for i in size(areaData,2):-1:1
plot!( sum(areaData[:,1:i], dims=2), fillcolor = cur_colors[i], fillrange = 0, lw=0 )
end
plot!()
График с доверительными интервалами (аргументы xerr
и yerr
)
using Random
Random.seed!(2018)
f(x) = 2 * x + 1
x = 0:0.1:2
n = length(x)
y = f.(x) + randn(n)
plot( x, y,
xerr = 0.1 * rand(n),
yerr = rand(n),
marker = (:circle, :red) )
Трехмерный график
t = 0:pi/100:10pi;
x1 = sin.(1 * t)
y1 = cos.(1 * t)
x2 = sin.(2 * t)
y2 = cos.(2 * t)
plot(
plot( x1, y1, t, leg=false, lw=2 ),
plot( x2, y2, t, leg=false, lw=2 )
)
Гладкий и ступенчатый графики, объединенные при помощи аргумента layout
x = range( 1, 2pi, length=50 )
plot( x, [sin.(x) sin.(x)],
seriestype=[:line :step],
layout = (2, 1) )
Параметрический график в 3D
t = range(0, stop=10, length=1000)
x = cos.(t)
y = sin.(t)
z = sin.(5t)
plot( x, y, z )
Графики в полярных координатах¶
Стрелки к точкам, формирующим спираль (график quiver
)
cur_colors = theme_palette(:roma);
th = range( 0, 3*pi/2, 10 );
r = range( 5, 20, 10 );
c = collect(1:10)
X = r .* cos.(th)
Y = r .* sin.(th)
quiver( r.*0, r.*0, quiver=(th,r), aspect_ratio=:equal, proj=:polar,
line_z=repeat(c, inner=4), c=:roma, cbar=false, lw=2 )
Функция pie
x = [ "Энтузиасты", "Экспериментаторы", "Ученые" ]
y = [0.4,0.35,0.25]
pie(x, y, title="Кто использует Julia",l = 0.5)
Функция polar
θ = range(0, 2π, length=50)
r = 1 .+ cos.(θ) .* sin.(θ).^2
plot(θ, r, proj=:polar, lims=(0,1.5))
Ступенчатый график в полярных координатах (график rose
)
using Random
Random.seed!(2018)
n = 24
R = rand(n+1)
θ = 0:2pi/n:2pi
plot( θ, R, proj=:polar, line=:steppre, lims=(0,1) )
График в полярных координатах, заданный при помощи функции
θ = range( 0, 8π, length=1000 )
fr(θ) = sin( 5/4 * θ )
plot( θ, fr.(θ), proj=:polar, lims=(0,1) )
Пузырьковая диаграмма в полярных координатах
include( "$(@__DIR__)/data/planetData.jl" );
scatter( angle, distance, ms=diameter, mc = c,
proj=:polar, legend=false,
markerstrokewidth=1, markeralpha=.7 )
title!( "Планеты Солнечной системы" )
Географические карты¶
Нанесение обозначений на карту (библиотека GMT
, функции coast
и scatter
)
using Pkg; Pkg.add("GMT", io=devnull)
import GMT
GMT.coast(
region="0/40/30/60+r",
proj=(name=:laea, center=[10,50]),
frame=:ag, res=:low, area=500, shore=:thick, borders=1,
water=:blue,
# Выделим несколько стран другими цветами
DCW=((country="DE", pen=(1,:red)), (country="GB,IT,FR", fill=:green), (country="FI,NO,SE", fill=:yellow)),
figsize=2.8
)
GMT.scatter!( rand(5:15, 12), rand(47:55, 12), fmt=:png,
marker=:circle, markeredgecolor=0, size=0.0, markerfacecolor=:orange, show=true )
Отображение карты с рельефом океанов. При первом запуске, карта будет загружена с сервера.
using Pkg; Pkg.add("GMT", io=devnull)
import GMT
GMT.grdimage( "@earth_relief_20m_g", proj=:Winkel,
colorbar=true, coast=false, show=true )
Дискретные данные¶
Горизонтально расположенная столбчатая диаграмма (функция bar
)
ticklabel = string.( collect('а':'м') )
bar(1:12, orientation=:h, yticks=(1:12, ticklabel), yflip=true)
Столбчатые диаграммы bar
и groupedbar
using StatsPlots
include( "$(@__DIR__)/data/BostonTemp.jl" );
plots_id = [1,2,3];
groupedbar( hcat([Temperatures[i,:] for i in plots_id]...),
xticks=(1:12, Months),
label = [Years[i] for i in plots_id]',
color = reshape(palette(:tab10)[1:3], (1,3)) )
Диаграмма stem
(ствол-лист)
x1 = range( 0, 2pi, 50 );
x2 = range( pi, 3pi, 50 );
X = [x1, x2];
Y = [cos.(x1), 0.5.*sin.(x2)];
plot( X, Y, line=:stem, marker=:circle )
Трехмерная stem
-диаграмма
X = repeat( range(0,1,10), outer = [1,10] )
Y = repeat( range(0,1,10)', outer = [10,1] )
Z = exp.(X.+Y)
plot( X, Y, Z, line=:stem, color=:skyblue, markercolor=:white, marker=:circle, leg=false )
Контурные графики¶
График обтекания цилиндра ламинарным потоком.
Аналитическая аппроксимация этой функции рассчитывается при помощи уравнения:
$$\psi = U sin \theta \left ( r - \frac{R^2}{r} \right )$$
include( "$(@__DIR__)/data/flowAroundCylinder.jl" );
(r, theta, x, y, streamline, pressure) = flowAroundCylinder();
plot( x, y, streamline, levels=60, seriestype=:contour,
xlim = [-5,5], ylim=[-5,5], cbar=false, linewidth=2,
leg=false, color=:haline )
(xx,yy) = circle( 0, 0, 1 );
plot!( xx, yy, lw=2, lc=:black )
Заполненный контурный график (статическое давление вокруг цилиндра, обтекаемого ламинарным потоком)
include( "$(@__DIR__)/data/flowAroundCylinder.jl" );
(r, theta, x, y, streamline, pressure) = flowAroundCylinder();
plot( x, y, pressure, seriestype=:contourf, xlim = [-5,5], ylim=[-5,5], cbar=false, linewidth=1, leg=false )
(xx,yy) = circle( 0, 0, 1 );
plot!( xx, yy, lw=2, lc=:black )
Контурный график математических функций
# Подготовим данные
y = x = range( -7, 7, step=0.1 )
z = @. sin(x) + cos(y')
Plots.contour( x, y, z, color=:haline )
Поверхности и сетки¶
Параметр seriestype=:surface
# Подготовим данные
y = x = range( -7, 7, step=0.1 )
z = @. sin(x) + cos(y')
plot( x, y, z, st=:surface, color=:cool )
Параметр seriestype=:wireframe
# Подготовим данные
y = x = range( -7, 7, step=0.5 )
z = @. sin(x) + cos(y')
plot( x, y, z, st=:wireframe )
График двухмерной функции
include( "$(@__DIR__)/data/peaks.jl" );
(x,y,z) = peaks();
plot( x, y, z; levels=20, st=:surface )
Построим график функции "сомбреро". При использовании gr()
аргумент hidesurface
не используется. Но при использовании plotly()
аргумент hidesurface=false
позволяет одновременно вывести и поверхность, и контурный график на ней.
x = y = range( -8, 8, length=41 )
f(x,y) = sin.(sqrt.(x.*x+y.*y))./sqrt.(x.*x+y.*y)
# в gr() этот способ позволяет увидеть график поверхности позади графика линий
p = plot( x, y, f, st=:surface, fillalpha=0.7, cbar=false )
plot!( p, x, y, f, st=:wireframe )
# в plotly() есть более удобный синтаксис
#wireframe( x, y, f, hidesurface=false )
Точечные графики и пузырьковые диаграммы¶
Пузырьковая диаграмма
using Random: seed!
seed!(28)
xyz = randn(100, 3)
scatter( xyz[:, 1], xyz[:, 2], marker_z=xyz[:, 3],
label="Окружности",
colormap=:plasma, cbar=false,
markersize=15 * abs.(xyz[:, 3]),
xlimits=[-3,3], ylimits=[-3,3]
)
Трехмерный точечный график с назначением отдельного цвета каждой точке
using Colors, ColorSchemes
cs = ColorScheme([colorant"yellow", colorant"red"])
using CSV, DataFrames
df = DataFrame(CSV.File( "$(@__DIR__)/data/seamount.csv" ))
C = get( cs, df.z, :extrema )
scatter( df.x, df.y, df.z, c=C, leg=false )
Трехмерный точечный график с фиктивным пространством для цветовой гисторгаммы
using CSV, DataFrames
df = DataFrame(CSV.File( "$(@__DIR__)/data/seamount.csv" ))
cs = cgrad(:thermal)
C = get( cs, df.x, :extrema )
l = @layout [a{0.97w} b]
p1 = scatter( df.x, df.y, df.z, c=C, leg=false )
p2 = heatmap(rand(2,2), clims=(0,10), framestyle=:none, c=cgrad(cs), cbar=true, lims=(-1,0))
plot(p1, p2, layout=l)
Цвет и аннотации¶
Создадим цветовую палитру:
using Images
scheme = rand(RGB, 10)
Используем палитру чтобы раскрасить матрицу из случайных чисел и вывести как изображение:
matrix = rand(1:10, 20, 20)
img = scheme[ matrix ]
Создадим график из случайных точек с линиями и аннотациями:
x = 1:10
y = rand(10)
# Создадим точечный график
scatter(x, y)
# Нанесем вертивальные и горизонтальные линии на график
vline!( [5], color=:red, linestyle=:dash, label=:none )
hline!( [0.5], color=:blue, linestyle=:dot, label=:none )
# Нанесем аннотации на график (работает только в gr())
annotate!( 8, 0.52, text("Горизонтальная линия", :blue, :right, 8))
annotate!( 4.8, 0.7, text("Вертикальная линия", :red, 8, rotation = 90))