07: Vizualizace a manipulace s grafikou
Tento notebook je výukovým materiálem v předmětu BI-JUL.21 vyučovaném v zimním semestru akademického roku 2026/2027 Tomášem Kalvodou. Tvorba těchto materiálů byla podpořena NVS FIT.
Hlavní stránkou předmětu, kde jsou i další notebooky a zajímavé informace, je jeho Course Pages stránka.
versioninfo()1. Vizualizace
Nejen v Julia existuje celá řada nástrojů/knihoven pro vytváření různých grafů, diagramů a vizualizací. V Python ekosystému je asi nejpoúžívanější Matplotlib, který je k dispozici i v Julia (viz PyPlot.jl níže).
Všechny tyto nástroje se snaží dosáhnout podobných cílů a nabízejí různě kvalitní implementace. Dost často bývá otázkou vkusu, který z nástrojů použít. V tomto notebooku ukážeme tři možnosti:
Paleta možností je ale širší. Zmiňme alespoň následující (pro zájemce k prozkoumání):
Plots: nadstavba nad několika grafickými balíčky.Gadfly: atraktivní a interaktivní výstup.Winston: malý a rychlý, terminologií vychází s MATLABu.UnicodePlots: zajímavý nástroj vytvářející grafy pomocí unicode symbolů a fungující i v terminálu.
Možností je opravdu mnoho a tento notebook je spíše experimentální.
Při používání tohoto notebooku doporučuji vždy mezi sekcemi (různými balíčky) restartovat jádro. Moduly mají podobné zaměření a mohlo by dojít ke kolizím pojmenování metod.
1.1 GR.jl
Balíček GR.jl poskytuje Julia rozhranní k GR frameworku.
GR byl vyvinut skupinou Scientific IT-Systems z Peter Grünberg Institutu na Forschungszentrum Jülich.
- Mezi jeho přednosti patří rychlost.
- Mezi nevýhody bych zařadil nekvalitní dokumentaci a nekonzistenci API. (Chyba může být ale na straně Julia balíčku...)
Tento balíček pravděpodobně nemáte nainstalovaný, takže nejprve tento musíme nainstalovat (případně viz pokyny k instalaci systémových závislostí):
(@v1.11) pkg> add GRZde v notebooku projdeme jen ty nejužitečnější části balíčku. Také tento balíček použijeme jako jakéhosi průvodci po možnostech, u ostatních se totiž dost opakují. Zvídavého čtenáře odkazujeme na dokumentaci s ukázkami dalších typů grafů.
using GRTvorbu jednotlivých grafů můžeme oddělit zavoláním figure, případně subplot. K dispozici také je savefig.
plot a oplot
Pomocí plot nepřekvapivě vykreslíme 2D graf funkce. Poziční argumenty mohou mít následující význam:
- stejně dlouhé vektory
xayreprezentující souřadnice bodů, - vektor
xa funkce pro výpočet -nové hodnoty, - pouze vektor
y, nezávisle proměnná pak odpovídá indexům.
Dále plot přijímá několik keyword argumentů, nejzajímavější asi jsou:
title: titulek grafu (alternativně metodatitle),xlabel: titulek grafu (alternativně metodaxlabel),ylabel: titulek grafu (alternativně metodaylabel),xlim,ylim: rozsah jednotlivých os (alternativně metodyxlimaylim),
a metoda
legend: popisky jednotlivých grafů.
Následuje několik jednoduchých ukázek:
xs = LinRange(-10, 10, 100)
ys = sin.(xs)
figure()
plot(xs, ys, title="\$y=\\sin(x)\$", xlabel="\$x\$", ylabel="\$y\$", ylim=(-1.2, 1.2))Poznámka: Všimněte si, že vykreslení prvního grafu je (nejen zde, takřka vždy) výrazně pomalejší, než těch následujících. To je způsobeno probíhající JIT kompilací. Tento efekt je v Julia světě označován zkratkou TTFP (Time To First Plot). Tomuto efektu se lze v některých situacích částečně vyhnout pomocí PackageCompiler.jl.
Pokud chceme vykreslit více dat do jednoho obrázku, použijeme k tomu oplot, nastavení popisků atp. se bohužel bere z posledního volání oplus (lze to obejít nastavením těchto parametrů pomocí metod, ne pomocí keyword hodnot).
figure()
legend("\$\\sin\$", "\$\\cos\$")
plot(xs, ys, title="\$y=\\sin(x)\$", xlabel="\$x\$", ylabel="\$y\$", ylim=(-2.2, 1.2))
oplot(xs, cos, title="Trigonometrické funkce", xlabel="\$x\$", ylabel="\$y\$", ylim=(-1.2, 1.2))Styl čáry lze kontrolovat pomocí klíčů:
setlinetype: druh čáry (vizGR.LINETYPE_...),setlinewidth: šířka čáry,setlinecolorind: barva čáry (???).
figure()
setlinetype(GR.LINETYPE_DOUBLE_DOT)
plot(LinRange(-1, 1, 50), exp, linewidth=5)figure()
plot(LinRange(-1, 1, 3), exp, linewidth=10)Zde jsem se vzdal a proto:
Cvičení: ???
- Pokuste
*se změnit barvu čáry například na červenou.
* tj. úspěch není nutný.
figure()
setlinecolorind(GR.COLOR_BROWN) # ???
plot(LinRange(-1, 1, 50), exp)figure()
setlinecolorind(GR.COLOR_BROWN) # ???
plot(LinRange(-1, 1, 50), exp)Invalid keyword: linestyle
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:44
[2] create_context(dict::Dict{Symbol, Int64})
@ GR.jlgr ~/.julia/packages/GR/f4wDQ/src/jlgr.jl:899
[3] create_context
@ ~/.julia/packages/GR/f4wDQ/src/jlgr.jl:892 [inlined]
[4] plot(::LinRange{Float64, Int64}, ::Vararg{Union{…}}; kv::@Kwargs{linestyle::Int64})
@ GR.jlgr ~/.julia/packages/GR/f4wDQ/src/jlgr.jl:1919
[5] kwcall(::@NamedTuple{linestyle::Int64}, ::typeof(plot), ::LinRange{Float64, Int64}, ::Function)
@ GR.jlgr ~/.julia/packages/GR/f4wDQ/src/jlgr.jl:1918
[6] top-level scope
@ In[49]:5
[7] eval(m::Module, e::Any)
@ Core ./boot.jl:489
Some type information was truncated. Use `show(err)` to see complete types.# colored line drawing example
using LaTeXStrings
f(x) = x*exp(-2x*im)
x = 0:0.01:π
w = f.(x)
plot(real.(w), imag.(w), x, linewidth=5, title=L"f(x) = xe^{-2xi} \forall x \in [0,\pi]", xlabel=L"\Re e\{f(x)\}", ylabel=L"\Im e\{f(x)\}")methods(plot)- plot(p::GR.jlgr.PlotObject) in GR.jlgr at /home/kalvin/.julia/packages/GR/f4wDQ/src/jlgr.jl:145
- plot(path::String; kwargs...) in GR.jlgr at /home/kalvin/.julia/packages/GR/f4wDQ/src/jlgr.jl:3021
- plot(args::Union{AbstractString, Function, AbstractMatrix, AbstractVector}...; kv...) in GR.jlgr at /home/kalvin/.julia/packages/GR/f4wDQ/src/jlgr.jl:1918
figure()
xs = -1:0.1:1
plot(xs, exp.(xs), "g-", linewidth=10)x = collect(0:0.1:10)
p = plot(x, sin.(x))
setcolorrep(100, 0.8, 0.2, 0.2) # define a custom RGB color at index 100
setlinecolorind(100) # or: setlinecolorind(inqcolorfromrgb(0.2, 0.6, 0.8))
setlinewidth(2)
polyline(x, cos.(x)) # drawn in the plot's coordinates
updatews()
pscatter
Scatter plot vykresluje pouze jednotlivé body a neinterpoluje (lineárně) mezi nimi:
figure()
title("\$a_n = (-1)^n\$")
legend("\$a_n\$")
xlabel("\$n\$")
ylabel("\$a_n\$")
plot([(-1)^n for n=0:9])?legendfigure()
title("\$a_n = (-1)^n\$")
legend("\$a_n\$")
xlabel("\$n\$")
ylabel("\$a_n\$")
x = Float64[j for j=0:9]
y = Float64[(-1)^n for n=0:9]
scatter(x, y, xlim=(-0.2, 9.2), ylim=(-1.2, 1.2))figure()
title("\$a_n = (-1)^n\$")
legend("\$a_n\$")
xlabel("\$n\$")
ylabel("\$a_n\$")
x = Float64[j for j=0:9]
y = Float64[(-1)^n for n=0:9]
s = 4*ones(10)
c = rand(0:255, 10)
scatter(x, y, s, c, xlim=(-0.2, 9.2), ylim=(-1.2, 1.2))x10-element Vector{Float64}:
0.0
1.0
2.0
3.0
4.0
5.0
6.0
7.0
8.0
9.0y10-element Vector{Float64}:
1.0
-1.0
1.0
-1.0
1.0
-1.0
1.0
-1.0
1.0
-1.0s10-element Vector{Float64}:
4.0
4.0
4.0
4.0
4.0
4.0
4.0
4.0
4.0
4.0c10-element Vector{Int64}:
161
214
243
33
145
220
177
50
111
177figure()
x = [z/10 for z=0:10]
y = LinRange(0, 1, 11)
s = LinRange(1, 3, 11)
c = LinRange(0, 255, 11)
scatter(x, y, s, c)x11-element Vector{Float64}:
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0y11-element LinRange{Float64, Int64}:
0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0s11-element LinRange{Float64, Int64}:
1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0c11-element LinRange{Float64, Int64}:
0.0, 25.5, 51.0, 76.5, 102.0, 127.5, 153.0, 178.5, 204.0, 229.5, 255.0Můžeme snadno i změnit barevnou škálu.
figure()
ts = LinRange(0, 4pi, 40)
x = [t * sin(t) for t in ts]
y = [t * cos(t) for t in ts]
s = ts
c = LinRange(0, 255, 40)
scatter(x, y, s, c, colormap=GR.COLORMAP_INFERNO)plot3
plot3 je 3D analog čárového grafu. Přijímá tedy tři vektory x, y a z, jejichž složky popořadě tvoří jednotlivé body křivky.
ts = LinRange(0, 20, 400)
xs = [ sin(t) for t in ts ]
ys = [ cos(t) for t in ts ]
zs = ts
figure()
plot3(xs, ys, zs, xlabel="x", ylabel="y", zlabel="z", title="Šroubovice")histogram a hexbin, Cvičení
Histogram bere vektor x hodnot a jako keyword argument nbins udávající počet přihrádek.
Budeme ho ilustrovat na náhodném generátoru bodů na kružnici (vzpomeňte dřívější diskuzi).
n = 50_000
xs = rand(n) .- 0.5
ys = rand(n) .- 0.5;figure()
scatter(xs, ys, xlim=(-1.2,1.2), ylim=(-1.2,1.2))for j=1:length(xs)
r = sqrt(xs[j]^2 + ys[j]^2)
xs[j] /= r
ys[j] /= r
endfigure()
scatter(xs, ys)φs = [ atan(ys[j], xs[j]) for j=1:length(xs) ];figure()
histogram(φs, nbins=50, xlabel="\$\\varphi\$", ylabel="hits")savefig("test.pdf")savefig("test.png")savefig("test.svg")Takovýto generátor evidentně preferuje směry odpovídající osám kvadrantů.
Dvourozměrný ekvivalent histogramu (tj. pro dvousložková data) je metoda hexbin, která funguje analogicky, jen rovinu rozděluje na šestiúhelníky.
xs = rand(10^6)
ys = randn(10^6)
figure()
hexbin(xs, ys)xs = rand(10^6)
ys = randn(10^6)
figure()
hexbin(xs, ys, colormap=GR.COLORMAP_INFERNO, xlabel="A", ylabel="B")contour a contourf
Contour plot je vizualizace funkce dvou proměnných, která v jejím definičním oboru znázorňuje křivky, kde je daná funkce konstantní (tzv. kontury). Varianta s f v názvu vybarvuje plochy mezi konturami (fill).
Metody očekávají buď trojici vektorů x, y, z, kde x a y definují souřadnice mřížky a z obsahuje funkční hodnoty na této mřížce (tj. z je matice). Místo z můžeme předat funkci dvou proměnných.
figure()
contour(LinRange(-1, 1, 50), LinRange(-2, 2, 50), (x, y) -> 3x^2 + y^2,
colormap=GR.COLORMAP_AUTUMN, xlabel="\$x\$", ylabel="\$y\$")Pozor, jak se GR chová k pořadí os v buňce níže!
figure()
xs = LinRange(-10, 10, 150)
ys = LinRange(-15, 15, 100)
zs = [ sin(x)*cos(y) for y in ys, x in xs ]
contourf(xs, ys, zs)zs100×150 Matrix{Float64}:
-0.413286 -0.324264 -0.229408 … 0.229408 0.324264 0.413286
-0.288886 -0.226659 -0.160355 0.160355 0.226659 0.288886
-0.13816 -0.1084 -0.0766901 0.0766901 0.1084 0.13816
0.0251563 0.0197376 0.0139638 -0.0139638 -0.0197376 -0.0251563
0.18618 0.146077 0.103345 -0.103345 -0.146077 -0.18618
0.330237 0.259104 0.183309 … -0.183309 -0.259104 -0.330237
0.444201 0.34852 0.246569 -0.246569 -0.34852 -0.444201
0.517687 0.406177 0.287359 -0.287359 -0.406177 -0.517687
0.543997 0.42682 0.301964 -0.301964 -0.42682 -0.543997
0.520735 0.408568 0.289051 -0.289051 -0.408568 -0.520735
0.450019 0.353085 0.249798 … -0.249798 -0.353085 -0.450019
0.338295 0.265426 0.187782 -0.187782 -0.265426 -0.338295
0.195743 0.15358 0.108654 -0.108654 -0.15358 -0.195743
⋮ ⋱
0.338295 0.265426 0.187782 -0.187782 -0.265426 -0.338295
0.450019 0.353085 0.249798 -0.249798 -0.353085 -0.450019
0.520735 0.408568 0.289051 … -0.289051 -0.408568 -0.520735
0.543997 0.42682 0.301964 -0.301964 -0.42682 -0.543997
0.517687 0.406177 0.287359 -0.287359 -0.406177 -0.517687
0.444201 0.34852 0.246569 -0.246569 -0.34852 -0.444201
0.330237 0.259104 0.183309 -0.183309 -0.259104 -0.330237
0.18618 0.146077 0.103345 … -0.103345 -0.146077 -0.18618
0.0251563 0.0197376 0.0139638 -0.0139638 -0.0197376 -0.0251563
-0.13816 -0.1084 -0.0766901 0.0766901 0.1084 0.13816
-0.288886 -0.226659 -0.160355 0.160355 0.226659 0.288886
-0.413286 -0.324264 -0.229408 0.229408 0.324264 0.413286figure()
xs = LinRange(-10, 10, 150)
ys = LinRange(-15, 15, 100)
zs = [ exp(-(x - y)^2) for y in ys, x in xs ]
contourf(xs, ys, zs)heatmap
heatmap funguje v podstatě stejně jako contour, jen se nesnaží nalézt křivky konstantní hodnoty funkce (což je netriviální! Odpovídající algoritmus marching cubes algorithm (zde squares -- 2D varianta) byl ještě do relativně nedávná doby pod patentem.)
figure()
xs = LinRange(-10, 10, 200)
ys = LinRange(-10, 10, 200)
zs = [ sin(x)*cos(y/3) for x in xs, y in ys ]
heatmap(zs, colormap=GR.COLORMAP_FLAME)figure()
# Create example data
x = LinRange(-2, 2, 40)
y = LinRange(0, pi, 20)
z = sin.(x') .+ cos.(y)
# Draw the heatmap
heatmap(z)Z neznámého důvodu od jisté doby heatmap nefunguje v GR... :-/
?heatmapsearch: heatmap polarheatmap floatmax
Draw a heatmap.
This function uses the current colormap to display a two-dimensional array as a heatmap. The array is drawn with its first value in the bottom left corner, so in some cases it may be neccessary to flip the columns (see the example below).
By default the function will use the column and row indices for the x- and y-axes, respectively, so setting the axis limits is recommended. Also note that the values in the array must lie within the current z-axis limits so it may be neccessary to adjust these limits or clip the range of array values.
:param data: the heatmap data
Usage examples:
.. code-block:: julia
julia> # Create example data
julia> x = LinRange(-2, 2, 40)
julia> y = LinRange(0, pi, 20)
julia> z = sin.(x') .+ cos.(y)
julia> # Draw the heatmap
julia> heatmap(z)
imshow
Tato metoda je velmi užitečná. Umožňuje nám graficky znázornit matici.
h = [ i + j - 1 for i=1:10, j=1:10 ]
figure()
imshow(h, colormap=GR.COLORMAP_INFERNO)figure()
xs = LinRange(-10, 10, 200)
ys = LinRange(-10, 10, 200)
zs = [ sin(x)*cos(y/3) for x in xs, y in ys ]
imshow(zs, colormap=GR.COLORMAP_WINTER)figure()
xs = LinRange(-10, 10, 200)
ys = LinRange(-10, 10, 200)
zs = [ sin(x)*cos(y) for x in xs, y in ys ]
imshow(zs, colormap=GR.COLORMAP_FLAME)Cvičení: Julia v Julia
Uvažme zobrazení zadané předpisem , pro pevně zadanou konstantu . Zkoumáme pak množinu bodů , pro které je posloupnost omezená (mocnina zde nyní označuje opakované skládání zobrazení).
Přibližně se lze k této množině blížit takto: zvolme dostatečně velké a maximální počet iterací a pro z nějaké zvolené množiny (typicky mřížka) naměřme, kolik iterací musíme provést, než se dostaneme dále než od počátku.
Proveďte tento výpočet pro a .
function julia(c::Complex{Float64}, R::Float64, reals, imags; imax::Int64=1_000)
data = fill(imax, length(reals), length(imags))
f(u) = u^2 + c
for j = axes(reals, 1), k = axes(imags, 1)
z = reals[j] + 1im * imags[k]
for n = 1:imax
z = f(z)
if abs(z) > R
data[j, k] = n
break
end
end
end
return reverse(transpose(data), dims=1)
endjulia (generic function with 1 method)
res = LinRange(-2, 2, 10)
ims = LinRange(-1, 1, 10)
data1 = julia(-0.8 + 0.156im, 4.0, res, ims)10×10 Matrix{Int64}:
1 2 2 3 3 3 2 2 2 1
2 2 3 3 5 4 3 2 2 1
2 2 4 5 116 11 4 3 2 2
2 3 9 8 65 108 7 4 3 2
2 4 60 19 21 131 125 7 3 2
2 3 7 125 131 21 19 60 4 2
2 3 4 7 108 65 8 9 3 2
2 2 3 4 11 116 5 4 2 2
1 2 2 3 4 5 3 3 2 2
1 2 2 2 3 3 3 2 2 1res = LinRange(-2, 2, 20)
ims = LinRange(-1, 1, 10)
data1 = julia(-0.8 + 0.156im, 40.0, res, ims)10×20 Matrix{Int64}:
3 3 3 3 4 4 4 4 4 … 4 4 4 4 3 3 3 3 3
3 3 3 4 4 4 5 5 6 5 5 4 4 4 4 3 3 3
3 3 4 4 5 6 6 7 14 8 6 5 5 4 4 4 3 3
3 4 4 5 8 181 11 188 44 33 8 8 14 5 4 4 3 3
3 4 5 24 54 43 20 54 21 15 88 415 94 8 6 4 4 3
3 4 4 6 8 94 415 88 15 … 21 54 20 43 54 24 5 4 3
3 3 4 4 5 14 8 8 33 44 188 11 181 8 5 4 4 3
3 3 4 4 4 5 5 6 8 14 7 6 6 5 4 4 3 3
3 3 3 4 4 4 4 5 5 6 5 5 4 4 4 3 3 3
3 3 3 3 3 4 4 4 4 4 4 4 4 4 3 3 3 3imshow(data1, colormap=GR.COLORMAP_BLUESCALE)imshow([0 1 0; 0 0 1])res = LinRange(-1.5, 1.5, 600)
ims = LinRange(-1, 1, 400)
data2 = julia(-0.5125 + 0.5213im, 4.0, res, ims, imax=1_000);imshow(data2, colormap=GR.COLORMAP_BLUESCALE)res = LinRange(-2, 2, 600)
ims = LinRange(-1, 1, 400)
data1 = julia(-0.8 + 0.156im, 40.0, res, ims);imshow(data1, colormap=GR.COLORMAP_INFERNO)res = LinRange(-0.3, -0.1, 800)
ims = LinRange(-0.35, -0.15, 800)
data2 = julia(-0.8 + 0.156im, 4.0, res, ims);imshow(data2, colormap=GR.COLORMAP_INFERNO)Nyní obrázky generované pomocí PyPlot (viz níže).
using PyPlotres = LinRange(-2, 2, 600)
ims = LinRange(-1, 1, 400)
data2 = julia(-0.8 + 0.156im, 4.0, res, ims);
fig, ax = plt.subplots()
ax.imshow(data2, extent=[res[1], res[end], ims[1], ims[end]])res = LinRange(0, 2, 600)
ims = LinRange(0, 1, 400)
data2 = julia(-0.8 + 0.156im, 4.0, res, ims);
fig, ax = plt.subplots()
ax.imshow(data2, extent=[res[1], res[end], ims[1], ims[end]])res = LinRange(-2, 2, 1000)
ims = LinRange(-1, 1, 1000)
c = (MathConstants.golden - 2) + (MathConstants.golden - 1)*1im
data3 = julia(c, 5.0, res, ims);fig, ax = plt.subplots()
ax.imshow(data3, extent=[res[1], res[end], ims[1], ims[end]], cmap="Reds")res = LinRange(0.25, 0.75, 1000)
ims = LinRange(-0.75, -0.25, 1000)
c = (MathConstants.golden - 2) + (MathConstants.golden - 1)*1im
data4 = julia(c, 5.0, res, ims);fig, ax = plt.subplots()
ax.imshow(data4, extent=[res[1], res[end], ims[1], ims[end]], cmap="Reds")1.2 PyPlot.jl
PyPlot.jl je v podstatě Julia rozhraní k Matplotlib Pyhon knihovně, přesněji k funkcím v matplotlib.pyplot Python modulu.
Pokud znáte tuto knihovnu, pak by pro vás tato varianta měla být asi nejpříjemnější na používání. Pro ostatní mohou být užitečné tyto taháky.
- Výhody: lepší dokumentace, obrovská základna uživatelů, ozkoušený a robustní software.
- Nevýhody: pomalejší, závislost na Pythonu.
Budete potřebovat mít nainstalovánu tuto knihovnu ($ pip install matplotlib) a poté nainstalovat Julia balíček PyPlot.jl:
(@v1.11) pkg> add PyPlotPro porovnání ukažme jen základní typ grafu a pak zkusme vytvořit komplikovanější diagram v cvičení.
# Doporučuji restartovat jádro!
using PyPlotplot
Logika této metody je velmi podobná jako analogické metody v GR.jl výše.
xs = LinRange(0, 10, 200)
ys = [ sin(x) - sin(2x)/2 + sin(3x)/3 - sin(4x)/4 for x in xs ]
f = figure()
plot(xs, ys, color="red", linewidth=4.0, linestyle="--")
grid()
title("Můj úžasný graf")
xlabel("\$x\$")
ylabel("\$y\$");Výsledné obrázky lze opět snadno uložit.
f.savefig("matplotlib_fig.png")f.savefig("matplotlib_fig.pdf")K dispozici také je několik přednastavených stylů, například:
plt.style.available28-element Vector{String}:
"Solarize_Light2"
"bmh"
"classic"
"dark_background"
"fast"
"fivethirtyeight"
"ggplot"
"grayscale"
"petroff10"
"petroff6"
"petroff8"
"seaborn-v0_8"
"seaborn-v0_8-bright"
⋮
"seaborn-v0_8-darkgrid"
"seaborn-v0_8-deep"
"seaborn-v0_8-muted"
"seaborn-v0_8-notebook"
"seaborn-v0_8-paper"
"seaborn-v0_8-pastel"
"seaborn-v0_8-poster"
"seaborn-v0_8-talk"
"seaborn-v0_8-ticks"
"seaborn-v0_8-white"
"seaborn-v0_8-whitegrid"
"tableau-colorblind10"f = figure()
plt.style.use("seaborn-v0_8")
plot(xs, ys, color="red", linewidth=4.0, linestyle="--")
title("Můj úžasný graf")
xlabel(L"$x$")
ylabel(L"$y$");Cvičení: Řešení ODE
V předchozí lekci jsme si ukázali, jak vyřešit obyčejnou diferenciální rovnici , , pomocí maticové exponenciály. Řešením byla vektorová funkce .
Konkrétně jsme zvolili
Pokuste se vizualizovat tato řešení (v rovině) pro pár počátečních podmínek.
Poznámka: Viz předchozí notebook.
A = Float64[0 -1; 1 0]
function solution(matrix::Matrix{Float64}, initial_condition::Vector{Float64}, timestamps)
data = zeros(length(timestamps),2)
y = initial_condition
for j in axes(data, 1)
data[j, :] = y
y = exp(ts[j] * matrix) * initial_condition
end
return data
endsolution (generic function with 1 method)
ts = LinRange(0, 3, 100)
s1 = solution(A, [1.0, 0.0], ts)
s2 = solution(A, [-0.5, 0.0], ts)
s3 = solution(A, [1.0, 1.0], ts);f = figure()
scatter(s1[:,1], s1[:,2], color="red")
scatter(s2[:,1], s2[:,2], color="green")
scatter(s3[:,1], s3[:,2], color="blue")
grid()
title("Trajektorie")
xlabel("\$y_1\$")
ylabel("\$y_2\$");ts = LinRange(0, 7, 350)
s1 = solution(A, [1.0, 0.0], ts)
s2 = solution(A, [-0.5, 0.0], ts)
s3 = solution(A, [1.0, 1.0], ts);fig, ax = plt.subplots()
ax.set_aspect("equal")
scatter(s1[:,1], s1[:,2], color="red")
scatter(s2[:,1], s2[:,2], color="green")
scatter(s3[:,1], s3[:,2], color="blue")
grid()
title("Trajektorie")
xlabel("\$y_1\$")
ylabel("\$y_2\$");1.3 PGFPlotsX.jl
Tento balíček využívá pro generování grafů LaTeX balíček PGFPlots.
- Výhody: zřejmě nejkvalitnější výstup, vhodný i do publikací.
- Nevýhody: ideálně vyžaduje familiaritu s PGFPlots, náročnější instalace.
Musíte mít lokálně nainstalovaný LaTeX s balíčkem PGFPlots. Poté jen přidáme Julia balíček
(@v1.11) pkg> add PGFPlotsXusing PGFPlotsXTakřka nutností pro používání tohoto balíčku je prostudování si PGFPlots manuálu, který je velmi podrobný a názorný.
xs = LinRange(0, 20, 100)
ys = [ cos(x)/sqrt(x+1) for x in xs ];Makro @pgf nám umožňuje parsovat výrazy, které by nebyly validní Julia kód, například parametry grafu:
options = @pgf {
title => "Tlumená oscilace",
xlabel => "\$x\$",
ylabel => "\$y\$",
grid => "major"
}[title={Tlumená oscilace}, xlabel={$x$}, ylabel={$y$}, grid={major}] Grafické objekty pak vytvoříme pomocí konstruktorů, jejichž jména kopírují názvy LaTeX maker a prostředí.
g = Axis(options, Plot(Table(xs, ys)))Můžeme si i prohlédnout LaTeX kód, který se vygeneroval:
print_tex(g)\begin{axis}[title={Tlumená oscilace}, xlabel={$x$}, ylabel={$y$}, grid={major}]
\addplot
table[row sep={\\}]
{
\\
0.0 1.0 \\
0.20202020202020204 0.893554245654044 \\
0.4040404040404041 0.775983556965637 \\
0.6060606060606061 0.6485406037552491 \\
0.8080808080808082 0.5138048905565358 \\
1.0101010101010102 0.3750758675276676 \\
1.2121212121212122 0.23601775972659012 \\
1.4141414141414141 0.10041183197927928 \\
1.6161616161616164 -0.028037702725686314 \\
1.8181818181818183 -0.14586492596796072 \\
2.0202020202020203 -0.24997819449287356 \\
2.2222222222222223 -0.3377729061720941 \\
2.4242424242424243 -0.4072208430616047 \\
2.6262626262626263 -0.4569351605487472 \\
2.8282828282828283 -0.4862101377254743 \\
3.0303030303030303 -0.4950352538653798 \\
3.2323232323232327 -0.484083816106636 \\
3.4343434343434343 -0.45467712002295513 \\
3.6363636363636367 -0.4087259023159157 \\
3.8383838383838382 -0.348651588805861 \\
4.040404040404041 -0.2772905093754423 \\
4.242424242424242 -0.19778481180957286 \\
4.444444444444445 -0.11346423350720694 \\
4.646464646464646 -0.027723165846137755 \\
4.848484848484849 0.056102440473789546 \\
5.050505050505051 0.13485383368998885 \\
5.252525252525253 0.2056596042718416 \\
5.454545454545454 0.2660333065780028 \\
5.656565656565657 0.31395516431249626 \\
5.858585858585858 0.3479350974447313 \\
6.0606060606060606 0.3670550360768516 \\
6.262626262626263 0.37098928216349664 \\
6.464646464646465 0.3600025126700308 \\
6.666666666666666 0.334925856167946 \\
6.8686868686868685 0.2971122875082646 \\
7.070707070707071 0.2483733418065222 \\
7.272727272727273 0.19089982160318078 \\
7.474747474747475 0.1271697352276353 \\
7.6767676767676765 0.05984713990471977 \\
7.878787878787879 -0.00832414513650889 \\
8.080808080808081 -0.07462785190881611 \\
8.282828282828284 -0.13647951821882634 \\
8.484848484848484 -0.19152377168661003 \\
8.686868686868687 -0.23772105099838264 \\
8.88888888888889 -0.27342062443246246 \\
9.09090909090909 -0.29741733199031645 \\
9.292929292929292 -0.30899013494359545 \\
9.494949494949495 -0.30792127917779194 \\
9.696969696969697 -0.2944956380370906 \\
9.8989898989899 -0.2694805669827386 \\
10.101010101010102 -0.2340873468053269 \\
10.303030303030303 -0.1899159860547257 \\
10.505050505050505 -0.13888577066265204 \\
10.707070707070708 -0.08315446652729264 \\
10.909090909090908 -0.02502948025897692 \\
11.11111111111111 0.033125449750166375 \\
11.313131313131313 0.0889843341231118 \\
11.515151515151516 0.14035010633054038 \\
11.717171717171716 0.18523937201735224 \\
11.919191919191919 0.22195751208390194 \\
12.121212121212121 0.24916133517051656 \\
12.323232323232322 0.265906996654124 \\
12.525252525252526 0.27168150542183467 \\
12.727272727272727 0.26641680216167013 \\
12.92929292929293 0.25048608730278416 \\
13.131313131313131 0.22468277566227216 \\
13.333333333333332 0.1901831310210957 \\
13.535353535353536 0.1484942611195437 \\
13.737373737373737 0.10138970795629311 \\
13.939393939393941 0.050835328894516835 \\
14.141414141414142 -0.0010914861119250925 \\
14.343434343434343 -0.05228598940028595 \\
14.545454545454547 -0.10070027530470042 \\
14.747474747474747 -0.14442417523563253 \\
14.94949494949495 -0.1817596870160649 \\
15.151515151515152 -0.21128606825729157 \\
15.353535353535353 -0.23191312435899492 \\
15.555555555555555 -0.24292071556420858 \\
15.757575757575758 -0.24398307403676198 \\
15.95959595959596 -0.23517713813765204 \\
16.161616161616163 -0.2169747521993337 \\
16.363636363636363 -0.19021922062382077 \\
16.565656565656568 -0.1560873198104007 \\
16.767676767676768 -0.11603843624934314 \\
16.96969696969697 -0.07175299227959078 \\
17.17171717171717 -0.02506272370473082 \\
17.373737373737374 0.022124329366016028 \\
17.575757575757574 0.06790107619516698 \\
17.77777777777778 0.11043777281991562 \\
17.97979797979798 0.14805452738856317 \\
18.18181818181818 0.1792870624657542 \\
18.383838383838384 0.20294317957898042 \\
18.585858585858585 0.21814776617432916 \\
18.78787878787879 0.2243746621565776 \\
18.98989898989899 0.22146424265126738 \\
19.19191919191919 0.20962615358154776 \\
19.393939393939394 0.1894272337188925 \\
19.595959595959595 0.1617652471816049 \\
19.7979797979798 0.12782961052335254 \\
20.0 0.08905080657207223 \\
}
;
\end{axis}
PGFPlots nabízí bohaté možnosti změny stylu a prezentace:
@pgf Axis(options, Plot({"red", "line width" => "2pt" }, Table(xs, ys)))PGFPlots zvládá i 3D grafy (v LaTeXu!!!).
@pgf Axis({"colorbar"},
Plot3({"surf", "samples" => "15", "domain" => "0:1", "y domain" => "-1:1"}, Expression("x^2 - y^2"))
)1.4 Makie.jl
Do čtvrtice ještě jedna poměrně zajímavá možnost. Pro podrobnější prozkoumání doporučuji vaší pozornosti galerii.
- Výhody: poměrně velmi dobrá dokumentace se spoustou příkladů.
- Nevýhody: vleče se při prvním startu.
Balíček nabízí několik backendů: CairoMakie.jl (2D), GLMakie.jl a WGLMakie.jl.
Instalace je opět standardní a nebudu ji zde opakovat.
using CairoMakie[ Info: Precompiling CairoMakie [13f3f980-e62b-5c42-98c6-ff1f3baf88f0] (caches not reused: 1 for dependency source file not found) Precompiling packages... 0.9 s ✓ Animations 0.9 s ✓ FastInterpolations → FastInterpolationsColorVectorSpaceExt 1.0 s ✓ StructArrays 0.8 s ✓ StructArrays → LinearAlgebraExt 0.8 s ✓ StructArrays → AdaptExt 1.0 s ✓ Accessors → StructArraysExt 1.2 s ✓ StructArrays → SparseArraysExt 1.3 s ✓ StructArrays → StaticArraysExt 2.8 s ✓ ShaderAbstractions 3.0 s ✓ FreeTypeAbstraction 6.0 s ✓ MathTeXEngine 229.1 s ✓ Makie 6.3 s ✓ IntervalArithmetic → IntervalArithmeticMakieExt 7.3 s ✓ IntervalSets → IntervalSetsMakieExt 57.2 s ✓ CairoMakie 15 dependencies successfully precompiled in 304 seconds. 282 already precompiled.
xs = LinRange(0, 20, 200)
ys = sin.(xs) .* xs;fig, ax, plt = lines(xs, ys)
lines!(xs, cos.(xs))
ax.xlabel = "x"
ax.ylabel = "y"
ax.title = "Pokusný graf"
current_figure()Cvičení: Mandelbrotův fraktál
function mandelbrot(R::Float64, reals, imags; imax::Int64=50)
data = fill(imax, length(reals), length(imags))
f(u, c) = u^2 + c
for j = axes(reals, 1), k = axes(imags, 1)
c = reals[j] + 1im * imags[k]
z = zero(c)
for n = 1:imax
z = f(z, c)
if abs(z) > R
data[j, k] = n
break
end
end
end
return data
endmandelbrot (generic function with 1 method)
res = LinRange(-2, 1, 400)
ims = LinRange(-1, 1, 200)
data1 = mandelbrot(10.0, res, ims);heatmap(res, ims, data1, colormap = :deep)res = LinRange(-1.51, -1.49, 600)
ims = LinRange(-0.01, 0.01, 400)
data1 = mandelbrot(15.0, res, ims, imax=50);heatmap(res, ims, data1, colormap = :inferno)res = LinRange(-1.505, -1.500, 600)
ims = LinRange(-0.002, 0.002, 400)
data1 = mandelbrot(50.0, res, ims, imax=200);heatmap(res, ims, data1, colormap = :viridis)3D grafy
Makie poskytuje dva backendy schopné vykreslovat 3D grafiku, GLMakie.jl a WGLMakie.jl.
using GLMakie
xs = LinRange(0, 10, 100)
ys = LinRange(0, 15, 100)
zs = [cos(x) * sin(2*y) + x + y for x in xs, y in ys]
surface(xs, ys, zs, axis=(type=Axis3,))Cvičení: Vizualizace PRNG založeného na logistickém zobrazení
function my_prng(n, seed)
data = zeros(n)
data[1] = seed
for j = 2:n
data[j] = 4data[j-1]*(1 - data[j-1])
end
return data
enddata = my_prng(10^6, 0.7500000001);Jak tato posloupnost vypadá?
using CairoMakiefig, ax, plt = scatter(1:1000, data[1:1000])
ax.xlabel = "n"
current_figure()hist(data, bins=50, normalization = :pdf)f(x) = acos(1-2x)/pi
udata = f.(data);hist(udata, bins=50, normalization = :pdf)1.5 Interact.jl
Tento balíček umožňuje vytvářet interaktivní vizualizace. Pokyny k instalaci jsou tentokrát malinko komplikovanější, viz Getting Started.
using Interact, CairoMakiexs = LinRange(-5, 20, 200);@manipulate for a=0:0.01:1, ω=0:0.01:2
ys = [ a * sin(ω * x) for x in xs ]
vbox(lines(xs, ys))
end1.6 UnicodePlots.jl
Samostatnou kapitolou a disciplínou je vytváření grafů pomocí unicode znaků (lze i v terminálu, vyzkoušejte!).
using UnicodePlotslineplot(LinRange(0, 10, 100), sin.(LinRange(0, 10, 100)), title="Sinus") ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Sinus⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
┌────────────────────────────────────────┐
1 │⠀⠀⠀⠀⡰⠉⠉⠑⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠊⠉⠑⡄⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⡰⠁⠀⠀⠀⠱⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠁⠀⠀⠀⠘⡄⠀⠀⠀⠀⠀│
│⠀⠀⢠⠃⠀⠀⠀⠀⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠃⠀⠀⠀⠀⠀⠸⡀⠀⠀⠀⠀│
│⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⢇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡎⠀⠀⠀⠀⠀⠀⠀⢧⠀⠀⠀⠀│
│⠀⡸⠀⠀⠀⠀⠀⠀⠀⠀⠘⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠁⠀⠀⠀⠀⠀⠀⠀⠘⡄⠀⠀⠀│
│⢠⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢱⠀⠀⠀│
│⡜⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⡆⠀⠀│
│⠧⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⢵⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⢤⠧⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⢵⠤⠤│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⡆⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢱⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⡜⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢇│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡀⠀⠀⠀⠀⠀⠀⢰⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢆⠀⠀⠀⠀⡜⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
-1 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⣀⣀⠜⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
└────────────────────────────────────────┘
⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀10⠀ heatmap(randn(100, 100)) ┌──────────────────────────────┐ 4
100 │▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ ┌──┐
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
1 │▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ └──┘
└──────────────────────────────┘ -4
1 100 using Images, FileIO
img_Gauss = load("../homeworks/B211/files/gauss_portret.jpg")
img_Gauss = map(x -> Float64(x.r), img_Gauss)
heatmap(reverse(img_Gauss, dims=1))2. Images.jl, Colors.jl, ImageMagick.jl, ImageMetadata.jl...
Tyto balíčky se specializují přímo na práci s obrázky, jejich vytváření a jejich editaci.
Nespadají tedy přímo do kategorie předchozích balíčků.
Využijete je třeba při rychlém generování obrázků z matic nebo při strojovém před/zpracování obrázků (viz ImageFeatures.jl, ImageTransformation.jl nebo ImageSegmentation.jl, ImageDraw.jl).
Instalace je opět standardní (]add Images, ]add Colors).
using Images, Colors[ Info: Precompiling PolynomialsMakieExt [1531507d-725e-5582-9e59-18df98086d4b] Precompiling packages... 5.6 s ✓ Polynomials → PolynomialsMakieExt 1 dependency successfully precompiled in 9 seconds. 295 already precompiled. [ Info: Precompiling ArrayInterfaceFillArraysExt [103188a2-059f-504d-80a8-05c2106ecd92] Precompiling packages... 0.6 s ✓ ArrayInterface → ArrayInterfaceFillArraysExt 1 dependency successfully precompiled in 1 seconds. 3 already precompiled.
2.1 Vytvoření obrázku
img_data = rand(400, 600)
img_data[1:50, 1:50] .= 0
img_data400×600 Matrix{Float64}:
0.0 0.0 0.0 … 0.681026 0.920322 0.596755
0.0 0.0 0.0 0.336384 0.975388 0.0189425
0.0 0.0 0.0 0.928234 0.00987076 0.101844
0.0 0.0 0.0 0.515735 0.5151 0.281218
0.0 0.0 0.0 0.0056696 0.161269 0.231896
0.0 0.0 0.0 … 0.0410987 0.576529 0.585257
0.0 0.0 0.0 0.593428 0.99256 0.429586
0.0 0.0 0.0 0.329358 0.541753 0.564124
0.0 0.0 0.0 0.0918989 0.248027 0.61908
0.0 0.0 0.0 0.977239 0.337007 0.689221
0.0 0.0 0.0 … 0.552717 0.340214 0.426312
0.0 0.0 0.0 0.0928862 0.808408 0.341378
0.0 0.0 0.0 0.338943 0.801685 0.391441
⋮ ⋱
0.907803 0.465305 0.202659 0.376308 0.213809 0.654264
0.210653 0.0798368 0.681277 0.396067 0.474638 0.982776
0.308087 0.370473 0.0320016 … 0.665892 0.322288 0.941678
0.284839 0.222254 0.296509 0.212968 0.716135 0.612288
0.0233161 0.792131 0.932767 0.189227 0.263264 0.479845
0.816231 0.402788 0.0937667 0.549838 0.0855301 0.677286
0.987072 0.530093 0.0695206 0.474522 0.475297 0.210332
0.452932 0.481609 0.615754 … 0.524793 0.362966 0.199156
0.893552 0.489221 0.617432 0.747552 0.804627 0.360774
0.439967 0.764987 0.3217 0.224662 0.377398 0.131746
0.343369 0.704933 0.698127 0.349691 0.831072 0.288844
0.4028 0.536984 0.31806 0.644772 0.225268 0.37677Gray(0.7)typeof(Gray(0.9))Gray{Float64}img = Gray.(img_data)display(MIME("text/plain"), img)400×600 Array{Gray{Float64},2} with eltype Gray{Float64}:
Gray{Float64}(0.0) … Gray{Float64}(0.596755)
Gray{Float64}(0.0) Gray{Float64}(0.0189425)
Gray{Float64}(0.0) Gray{Float64}(0.101844)
Gray{Float64}(0.0) Gray{Float64}(0.281218)
Gray{Float64}(0.0) Gray{Float64}(0.231896)
Gray{Float64}(0.0) … Gray{Float64}(0.585257)
Gray{Float64}(0.0) Gray{Float64}(0.429586)
Gray{Float64}(0.0) Gray{Float64}(0.564124)
Gray{Float64}(0.0) Gray{Float64}(0.61908)
Gray{Float64}(0.0) Gray{Float64}(0.689221)
Gray{Float64}(0.0) … Gray{Float64}(0.426312)
Gray{Float64}(0.0) Gray{Float64}(0.341378)
Gray{Float64}(0.0) Gray{Float64}(0.391441)
⋮ ⋱
Gray{Float64}(0.907803) Gray{Float64}(0.654264)
Gray{Float64}(0.210653) Gray{Float64}(0.982776)
Gray{Float64}(0.308087) … Gray{Float64}(0.941678)
Gray{Float64}(0.284839) Gray{Float64}(0.612288)
Gray{Float64}(0.0233161) Gray{Float64}(0.479845)
Gray{Float64}(0.816231) Gray{Float64}(0.677286)
Gray{Float64}(0.987072) Gray{Float64}(0.210332)
Gray{Float64}(0.452932) … Gray{Float64}(0.199156)
Gray{Float64}(0.893552) Gray{Float64}(0.360774)
Gray{Float64}(0.439967) Gray{Float64}(0.131746)
Gray{Float64}(0.343369) Gray{Float64}(0.288844)
Gray{Float64}(0.4028) Gray{Float64}(0.37677)dump(img)Array{Gray{Float64}}((400, 600))
1: Gray{Float64}
val: Float64 0.0
2: Gray{Float64}
val: Float64 0.0
3: Gray{Float64}
val: Float64 0.0
4: Gray{Float64}
val: Float64 0.0
5: Gray{Float64}
val: Float64 0.0
...
239996: Gray{Float64}
val: Float64 0.19915637518526674
239997: Gray{Float64}
val: Float64 0.3607737992612461
239998: Gray{Float64}
val: Float64 0.13174588925607555
239999: Gray{Float64}
val: Float64 0.2888438071782746
240000: Gray{Float64}
val: Float64 0.3767696115162892
Obrázky můžeme i snadno ukládat v různých formátech.
using FileIOsave("test.jpg", img)200343
RGB(0.1, 0.2, 0.52)HSV(180,0.5,1)map(x -> HSV(360 * x, 1, 1), img_data)Nahrávání obrázků
using FileIO, ImageMagick, ImageIOimg_Gauss = load("../homeworks/B211/files/gauss_portret.jpg")typeof(img_Gauss)Matrix{RGB{N0f8}} (alias for Array{RGB{Normed{UInt8, 8}}, 2})N0f8N0f8 (alias for Normed{UInt8, 8})dump(img_Gauss)Array{RGB{N0f8}}((480, 422))
1: RGB{N0f8}
r: N0f8
i: UInt8 0xe3
g: N0f8
i: UInt8 0xeb
b: N0f8
i: UInt8 0xed
2: RGB{N0f8}
r: N0f8
i: UInt8 0x99
g: N0f8
i: UInt8 0xa1
b: N0f8
i: UInt8 0xa3
3: RGB{N0f8}
r: N0f8
i: UInt8 0x37
g: N0f8
i: UInt8 0x3f
b: N0f8
i: UInt8 0x41
4: RGB{N0f8}
r: N0f8
i: UInt8 0x57
g: N0f8
i: UInt8 0x5f
b: N0f8
i: UInt8 0x61
5: RGB{N0f8}
r: N0f8
i: UInt8 0xa1
g: N0f8
i: UInt8 0xa9
b: N0f8
i: UInt8 0xab
...
202556: RGB{N0f8}
r: N0f8
i: UInt8 0x3f
g: N0f8
i: UInt8 0x4a
b: N0f8
i: UInt8 0x4c
202557: RGB{N0f8}
r: N0f8
i: UInt8 0x3b
g: N0f8
i: UInt8 0x46
b: N0f8
i: UInt8 0x48
202558: RGB{N0f8}
r: N0f8
i: UInt8 0x35
g: N0f8
i: UInt8 0x40
b: N0f8
i: UInt8 0x42
202559: RGB{N0f8}
r: N0f8
i: UInt8 0x42
g: N0f8
i: UInt8 0x4d
b: N0f8
i: UInt8 0x4f
202560: RGB{N0f8}
r: N0f8
i: UInt8 0x2e
g: N0f8
i: UInt8 0x39
b: N0f8
i: UInt8 0x3b
Všimněte si speciálního datového typu:
?N0f8search: N0f8 N8f8 n0f8 N56f8 N0f16 N4f28 N60f4 N30f2 N0f64 N10f6 N6f58 N0f32
Normed{T <: Unsigned, f} <: FixedPoint{T, f}
Normed{T,f} maps Unsigned integers from 0 to 2^f-1 to the range [0.0, 1.0]. For example, Normed{UInt8,8} maps 0x00 to 0.0 and 0xff to 1.0.
There are the typealiases for Normed in the NXfY notation, where Y is the number of fractional bits (i.e. f), and X+Y equals the number of underlying bits used. For example, N0f8 is aliased to Normed{UInt8,8} and N4f12 is aliased to Normed{UInt16,12}.
Jeden pixel je barevně reprezentován trojicí čísel (RGB).
p = img_Gauss[1, 1]typeof(p)RGB{N0f8}p.r0.89N0f8
p.g0.922N0f8
p.b0.929N0f8
img_Gauss[10, 10]Například můžeme extrahovat červený kanál a převést ho do datového typu, v kterém se lépe počítá:
imgR = map(x -> Float64(x.r), img_Gauss)480×422 Matrix{Float64}:
0.890196 0.501961 0.682353 0.854902 … 0.635294 0.647059 0.541176
0.6 0.478431 0.639216 0.584314 0.462745 0.827451 0.788235
0.215686 0.705882 0.615686 0.431373 0.454902 0.65098 0.513725
0.341176 0.482353 0.435294 0.576471 0.356863 0.564706 0.4
0.631373 0.545098 0.596078 0.403922 0.411765 0.603922 0.356863
0.215686 0.462745 0.937255 0.65098 … 0.611765 0.584314 0.411765
0.337255 0.109804 0.627451 0.843137 0.541176 0.615686 0.576471
0.705882 0.427451 0.431373 0.67451 0.294118 0.701961 0.65098
0.337255 0.439216 0.423529 0.407843 0.368627 0.639216 0.627451
0.282353 0.278431 0.501961 0.313725 0.721569 0.478431 0.701961
0.6 0.533333 0.513725 0.447059 … 0.768627 0.611765 0.639216
0.682353 0.752941 0.619608 0.619608 0.721569 0.615686 0.470588
0.427451 0.568627 0.713725 0.419608 0.556863 0.678431 0.509804
⋮ ⋱ ⋮
0.305882 0.0588235 0.270588 0.537255 0.239216 0.34902 0.423529
0.356863 0.207843 0.184314 0.337255 0.380392 0.415686 0.423529
0.27451 0.254902 0.294118 0.235294 … 0.407843 0.360784 0.403922
0.368627 0.12549 0.356863 0.427451 0.45098 0.341176 0.4
0.52549 0.396078 0.309804 0.258824 0.576471 0.266667 0.34902
0.376471 0.337255 0.454902 0.372549 0.4 0.372549 0.368627
0.129412 0.235294 0.580392 0.509804 0.443137 0.45098 0.352941
0.329412 0.101961 0.239216 0.337255 … 0.341176 0.254902 0.247059
0.505882 0.14902 0.192157 0.372549 0.556863 0.313725 0.231373
0.376471 0.203922 0.219608 0.337255 0.462745 0.14902 0.207843
0.219608 0.509804 0.623529 0.415686 0.239216 0.113725 0.258824
0.211765 0.568627 0.607843 0.25098 0.235294 0.211765 0.180392Gray.(imgR)Gray.([imgR[1:180, :]; imgR[225:end, :]])Gray.(imgR')3. Cairo.jl a Luxor.jl
Cairo.jl představuje rozhranní k 2D grafické knihovně Cairo.
S pomocí této knihovny jsme schopni deklarativním způsobem vytvářet zcela vlastní obrázky, ovšem operuje na poměrně nízké úrovni.
Uživatelsky příjemnější je balíček Luxor.jl.
Tento balíček nám umožňuje vytvářet rasterovou (PNG) i vektorovou (SVG) grafiku.
Jeho výhodou je i poměrně podrobná dokumentace s tutoriály.
using Luxor@svg begin
text("Hello world")
end@svg begin
text("Toto je můj první obrázek!", Point(0, 0), angle = pi/4, halign = :center)
rect(-50, -50, 100, 100, :stroke)
circle(Point(0, 0), 50, :stroke)
end@svg begin
circle(Point(-50, 0), 50, action=:fill)
circle(Point(50, 0), 60, action=:fill)
rulers()
endPozor, souřadný systém je orientován v grafice obvyklým způsobem "hlavou dolů".
Vedle výše použitých primitiv rect a circ máme k dispozici spoustu dalších nástrojů.
@svg begin
background("blue")
sethue("red")
move(Point(100, 0))
arc(Point(0, 0), 100, 0, pi/4)
arc(Point(0, 0), 200, pi/4, pi/2)
strokepath()
end@svg begin
background("black")
sethue("white")
for j = 0:15
line(100 * (-1)^j, -200 + j * 20)
end
strokepath()
endmove a line pracují v souřadnicích relativních k počátku v bodě .
K dispozici máme i rmove a rline, které pracují relativně k aktuální poloze.
@svg begin
background("black")
sethue("white")
circle(Point(-100, 0), 5, action = :fill)
circle(Point(100, 0), 5, action = :fill)
move(Point(-100, 0))
for j = 0:8
rline(Point(50*cos(j*2pi/8), 50*sin(j*2pi/8)))
end
closepath()
move(Point(100, 0))
for j = 0:8
rline(Point(50*cos(j*2pi/8), 50*sin(j*2pi/8)))
end
closepath()
strokepath()
endMakra se hodí k rychlému prozkoumávání a experimentování v Notebooku nebo editoru (VS Code umí obrázky správně zobrazovat).
Co když chceme výsledný obrázek exportovat?
function on_circle(j::Integer, n::Integer, R::Real)
return Point(R*cos((j-1)*2pi/n), R*sin((j-1)*2pi/n))
end
function my_colorful_ngon(n::Integer, filename::AbstractString; R::Real = 200)
n < 3 && error("At least 3 vertices are needed!")
R <= 0 && error("R has to be positive!")
Drawing(500, 500, filename)
origin()
for j = 1:n
setcolor(rand(3)...)
poly([ Point(0,0), on_circle(j-1, n, R), on_circle(j, n, R) ], :fill)
end
finish()
preview()
endmy_colorful_ngon (generic function with 1 method)
my_colorful_ngon(3, "3.svg")my_colorful_ngon(8, "8.svg")Řešení některých příkladů
K Julia:
function julia(c::Complex{Float64}, R::Float64, reals, imags; imax::Int64=1000)
img = zeros(length(reals), length(imags))
fc(z) = z^2 + c
for j in axes(reals, 1), k in axes(imags, 1)
n = 0
z = reals[j] + 1im*imags[k]
while n <= imax && abs(z) < R
z = fc(z)
n += 1
end
img[j, k] = n
end
return img
end