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 2024/2025 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()Julia Version 1.12.0 Commit b907bd0600f (2025-10-07 15:42 UTC) Build Info: Official https://julialang.org release Platform Info: OS: Linux (x86_64-linux-gnu) CPU: 8 × Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz WORD_SIZE: 64 LLVM: libLLVM-18.1.7 (ORCJIT, skylake) GC: Built with stock GC Threads: 1 default, 1 interactive, 1 GC (on 8 virtual cores)
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).
legend("\$\\sin\$", "\$\\cos\$")
figure()
plot(xs, ys, title="\$y=\\sin(x)\$", xlabel="\$x\$", ylabel="\$y\$", ylim=(-1.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_TRIPLE_DOT)
plot(LinRange(-1, 1, 50), exp, linewidth=5)figure()
setlinetype(GR.LINETYPE_TRIPLE_DOT)
plot(LinRange(-1, 1, 3), exp, linewidth=5)Zde jsem se vzdal a proto:
Cvičení: ???
- Pokuste
*se změnit barvu čáry například na červenou.
* tj. úspěch není nutný.
figure()
@which plot(LinRange(-1, 1, 50), exp)scatter
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])?legendsearch: legend seekend Signed begin prepend! signed setenv Regex end
Set the legend of the plot.
The plot legend is drawn using the extended text function GR.textext. You can use a subset of LaTeX math syntax, but will need to escape certain characters, e.g. parentheses. For more information see the documentation of GR.textext.
:param args: The legend strings
Usage examples:
.. code-block:: julia
julia> # Set the legends to "a" and "b"
julia> legend("a", "b")
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]
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 = 2*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}:
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0c10-element Vector{Int64}:
110
119
18
234
21
4
196
246
222
134figure()
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_SPRING)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 = 10_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)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.413286heatmap (od B231 i B241 funguje divně!)
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()
xs = LinRange(-10, 10, 200)
ys = LinRange(-10, 10, 200)
zs = [ sin(x)*cos(y/3) for x in xs, y in ys ]
heatmap(xs, ys, 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... :-/
?heatmapimshow
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, 4.0, res, ims)10×20 Matrix{Int64}:
1 2 2 2 2 2 3 3 3 … 3 3 2 2 2 2 2 2 1
2 2 2 2 3 3 3 4 4 4 3 3 3 2 2 2 2 1
2 2 2 3 4 4 5 6 12 6 4 4 3 3 2 2 2 2
2 2 3 4 7 179 9 187 42 32 6 7 12 4 3 3 2 2
2 2 4 23 52 42 18 52 20 14 87 414 92 6 5 3 2 2
2 2 3 5 6 92 414 87 14 … 20 52 18 42 52 23 4 2 2
2 2 3 3 4 12 7 6 32 42 187 9 179 7 4 3 2 2
2 2 2 2 3 3 4 4 6 12 6 5 4 4 3 2 2 2
1 2 2 2 2 3 3 3 4 4 4 3 3 3 2 2 2 2
1 2 2 2 2 2 2 3 3 3 3 3 2 2 2 2 2 1imshow(data1, colormap=GR.COLORMAP_BLUESCALE)UndefVarError: `GR` not defined in `Main` Suggestion: check for spelling errors or missing imports. Stacktrace: [1] top-level scope @ In[10]:1 [2] eval(m::Module, e::Any) @ Core ./boot.jl:489
imshow([0 1 0; 0 0 1])PyObject <matplotlib.image.AxesImage object at 0x7f8b799756d0>
res = LinRange(-2, 2, 600)
ims = LinRange(-1, 1, 400)
data2 = julia(-0.8 + 0.156im, 4.0, res, ims, imax=1000);imshow(data2, colormap=GR.COLORMAP_BLUESCALE)UndefVarError: `GR` not defined in `Main` Suggestion: check for spelling errors or missing imports. Stacktrace: [1] top-level scope @ In[13]:1 [2] eval(m::Module, e::Any) @ Core ./boot.jl:489
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]])PyObject <matplotlib.image.AxesImage object at 0x7f8b799c3610>
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]])PyObject <matplotlib.image.AxesImage object at 0x7f8b7985e350>
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")PyObject <matplotlib.image.AxesImage object at 0x7f8b798af890>
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")PyObject <matplotlib.image.AxesImage object at 0x7f8b7805e710>
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.available29-element Vector{String}:
"Solarize_Light2"
"_classic_test_patch"
"_mpl-gallery"
"_mpl-gallery-nogrid"
"bmh"
"classic"
"dark_background"
"fast"
"fivethirtyeight"
"ggplot"
"grayscale"
"petroff10"
"seaborn-v0_8"
⋮
"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 3 methods)
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 PGFPlotsX[ Info: Precompiling StructUtilsTablesExt [06a1ca1f-7bc7-53d2-8cfe-f45bf2a4bdd3] (cache misses: wrong dep version loaded (2)) ┌ Warning: Module StructUtils with build ID fafbfcfd-3f39-4f5b-fc0f-f447682647b8 is missing from the cache. │ This may mean StructUtils [ec057cc2-7a8d-4b58-b3b3-92acb9f63b42] does not support precompilation but is imported by a module that does. └ @ Base loading.jl:2613 SYSTEM: caught exception of type :MethodError while trying to print a failed Task notice; giving up ┌ Info: Skipping precompilation due to precompilable error. Importing StructUtilsTablesExt [06a1ca1f-7bc7-53d2-8cfe-f45bf2a4bdd3]. └ exception = Error when precompiling module, potentially caused by a __precompile__(false) declaration in the module.
Takř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 CairoMakiexs = 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 │▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ └──┘
└──────────────────────────────┘ -3
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)) ┌──────────────────────────┐ 1
480 │▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ ┌──┐
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
│▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ │▄▄│
1 │▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄│ └──┘
└──────────────────────────┘ 0
1 422 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, Colors2.1 Vytvoření obrázku
img_data = rand(400, 600)
img_data[1:50, 1:50] .= 1
img_data400×600 Matrix{Float64}:
1.0 1.0 1.0 … 0.121643 0.113807 0.0668084
1.0 1.0 1.0 0.948274 0.619606 0.502734
1.0 1.0 1.0 0.503101 0.670143 0.151584
1.0 1.0 1.0 0.0239172 0.277538 0.604295
1.0 1.0 1.0 0.490541 0.393127 0.667793
1.0 1.0 1.0 … 0.472548 0.812393 0.655114
1.0 1.0 1.0 0.956671 0.398792 0.233052
1.0 1.0 1.0 0.83457 0.0990415 0.444197
1.0 1.0 1.0 0.112091 0.00794115 0.844425
1.0 1.0 1.0 0.829232 0.0768055 0.427351
1.0 1.0 1.0 … 0.750726 0.658181 0.0316363
1.0 1.0 1.0 0.38384 0.672689 0.671094
1.0 1.0 1.0 0.425385 0.320389 0.593037
⋮ ⋱
0.439972 0.219535 0.409426 0.197511 0.862967 0.141982
0.771146 0.802731 0.700258 0.908076 0.185539 0.1993
0.636862 0.137429 0.0485984 … 0.436429 0.39579 0.990276
0.431764 0.903658 0.998625 0.21813 0.0300592 0.672166
0.884402 0.216983 0.0844578 0.445998 0.89231 0.606835
0.593039 0.854489 0.16887 0.480693 0.567922 0.14455
0.961033 0.15405 0.916742 0.956848 0.563512 0.0277343
0.761781 0.353725 0.502362 … 0.475769 0.84306 0.718264
0.56985 0.141446 0.330206 0.735418 0.913564 0.123032
0.594534 0.418833 0.820879 0.900206 0.301198 0.863166
0.659226 0.714832 0.701179 0.54729 0.915038 0.866396
0.0252055 0.7622 0.917001 0.157949 0.0172959 0.499759Gray(0.9)typeof(Gray(0.9))Gray{Float64}img = Gray.(img_data)display(MIME("text/plain"), img)400×600 Matrix{Gray{Float64}}:
1.0 1.0 1.0 … 0.121643 0.113807 0.0668084
1.0 1.0 1.0 0.948274 0.619606 0.502734
1.0 1.0 1.0 0.503101 0.670143 0.151584
1.0 1.0 1.0 0.0239172 0.277538 0.604295
1.0 1.0 1.0 0.490541 0.393127 0.667793
1.0 1.0 1.0 … 0.472548 0.812393 0.655114
1.0 1.0 1.0 0.956671 0.398792 0.233052
1.0 1.0 1.0 0.83457 0.0990415 0.444197
1.0 1.0 1.0 0.112091 0.00794115 0.844425
1.0 1.0 1.0 0.829232 0.0768055 0.427351
1.0 1.0 1.0 … 0.750726 0.658181 0.0316363
1.0 1.0 1.0 0.38384 0.672689 0.671094
1.0 1.0 1.0 0.425385 0.320389 0.593037
⋮ ⋱
0.439972 0.219535 0.409426 0.197511 0.862967 0.141982
0.771146 0.802731 0.700258 0.908076 0.185539 0.1993
0.636862 0.137429 0.0485984 … 0.436429 0.39579 0.990276
0.431764 0.903658 0.998625 0.21813 0.0300592 0.672166
0.884402 0.216983 0.0844578 0.445998 0.89231 0.606835
0.593039 0.854489 0.16887 0.480693 0.567922 0.14455
0.961033 0.15405 0.916742 0.956848 0.563512 0.0277343
0.761781 0.353725 0.502362 … 0.475769 0.84306 0.718264
0.56985 0.141446 0.330206 0.735418 0.913564 0.123032
0.594534 0.418833 0.820879 0.900206 0.301198 0.863166
0.659226 0.714832 0.701179 0.54729 0.915038 0.866396
0.0252055 0.7622 0.917001 0.157949 0.0172959 0.499759dump(img)Array{Gray{Float64}}((400, 600))
1: Gray{Float64}
val: Float64 1.0
2: Gray{Float64}
val: Float64 1.0
3: Gray{Float64}
val: Float64 1.0
4: Gray{Float64}
val: Float64 1.0
5: Gray{Float64}
val: Float64 1.0
...
239996: Gray{Float64}
val: Float64 0.7182644089563988
239997: Gray{Float64}
val: Float64 0.12303167272208015
239998: Gray{Float64}
val: Float64 0.8631657055536427
239999: Gray{Float64}
val: Float64 0.8663963088439961
240000: Gray{Float64}
val: Float64 0.4997585018792784
Obrázky můžeme i snadno ukládat v různých formátech.
using FileIOArgumentError: Package FileIO not found in current path.
- Run `import Pkg; Pkg.add("FileIO")` to install the FileIO package.
Stacktrace:
[1] macro expansion
@ ./loading.jl:2375 [inlined]
[2] macro expansion
@ ./lock.jl:376 [inlined]
[3] __require(into::Module, mod::Symbol)
@ Base ./loading.jl:2358
[4] require(into::Module, mod::Symbol)
@ Base ./loading.jl:2334
[5] eval(m::Module, e::Any)
@ Core ./boot.jl:489save("test.jpg", img)200464
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})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 n0f8 N8f8 N0f64 N4f28 N30f2 N6f58 N10f6 N24f8 N0f32 N60f4 N56f8
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, :]])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