Obsah
3. Graf s naměřenými hodnotami vykreslený knihovnou glot
4. Změna stylu vykreslování, specifikace rozsahů hodnot na osách x a y
5. Vykreslení několika průběhů do jediného grafu
6. Nastavení vyšší kvality zobrazení – použití antialiasingu
7. Specifikace titulku grafu a popisů obou jeho os
9. Automatický výpočet hodnot funkce při použití metody AddFunc2d
10. Vykreslení průběhů několika funkcí do jediného grafu
11. Nastavení hodnot zobrazovaných na osách
13. Zobrazení průběhu funkce se dvěma nezávislými proměnnými
14. Knihovna plot z projektu Gonum
15. Prázdný graf obsahující pouze legendu a osy
16. Graf s naměřenými hodnotami vykreslený knihovnou plot
17. Změna popisků na osách grafu
18. Zobrazení průběhů dvou funkcí v jediném grafu
19. Repositář s demonstračními příklady
1. Tvorba grafů v jazyce Go
V předchozích dvou částech [1] [2] seriálu o programovacím jazyce Go jsme se zabývali popisem některých možností poskytovaných sadou knihoven dodávaných v rámci projektu Gonum. Připomeňme si, že tento projekt programátorům poskytuje sadu funkcí, metod a datových typů z oblasti numerické matematiky, lineární algebry, grafových algoritmů atd. Většina výsledků je tištěna v textové podobě, ovšem mnohdy budeme potřebovat i grafický výstup, zejména zobrazení dat, popř. funkcí ve formě grafů. Pro jazyk Go existuje hned několik takových knihoven, které se od sebe odlišují jak poskytovanými možnostmi (jaké grafy lze vytvářet, do jaké míry je jejich styl modifikovatelný atd.), tak i použitým back endem, tedy knihovnou či nástrojem sloužím pro vlastní vykreslení grafu. Dnes se seznámíme především s knihovnou nazvanou glot, ovšem ukážeme si i základní grafy poskytované knihovnou plot, která pochází přímo z projektu Gonum.
Obrázek 1: V oblasti tvorby grafů nalezneme poměrně velké množství různých nástrojů. Některé z těchto nástrojů jsou určeny pro jeden konkrétní programovací jazyk (typicky pro R či pro jazyk Julia), další mohou být obecnější. V oblasti open source patří mezi tyto nástroje například populární knihovna Matplotlib pro programovací jazyk Python.
Obrázek 2: Ukázka dalších možností poskytovaných knihovnou Matplotlib.
2. Knihovna glot
První knihovnou, která umožňuje v programovacím jazyce Go vykreslovat některé typy grafů, je knihovna, která se jmenuje glot. Tento název je odvozen od známého nástroje Gnuplot, který již byl na stránkách Rootu popsán. Knihovna glot je totiž ve skutečnosti rozhraním mezi programovacím jazykem Go a právě nástrojem Gnuplot, z čehož vyplývají některé vlastnosti této knihovny, například závislost podporovaných výstupních formátů na tom, jak byl Gnuplot přeložen. Knihovna glot sice v aktuální verzi podporuje jen omezené množství grafů (v porovnání s možnostmi Gnuplotu, ale například i Matplotlibu), ovšem její vývoj není zdaleka ukončen, takže se pravděpodobně dočkáme dalších (dnes chybějících) funkcí, popř. rozšíření možností již implementovaných funkcí.
Obrázek 3: Ještě jeden typ grafu vykreslený s využitím knihovny Matplotlib.
Knihovna glot se nainstaluje stejným způsobem, jako jakákoli jiná knihovna určená pro ekosystém programovacího jazyka Go, konkrétně příkazem go get:
$ go get github.com/Arafatk/glot
Kromě toho je však nutné nainstalovat i vlastní Gnuplot:
$ sudo dnf install gnuplot-x11
popř.:
$ sudo apt-get install gnuplot-x11
Obrázek 4: Knihovna Matplotlib umožňuje i tvorbu trojrozměrných grafů, projekcí 3D funkcí atd.
3. Graf s naměřenými hodnotami vykreslený knihovnou glot
Ukažme si nyní některé základní možnosti, které nám současná verze knihovny glot nabízí. Nejprve vykreslíme jednoduchý graf, v němž budou vyneseny „naměřené“ hodnoty, které budou vyobrazeny jako jednotlivé body. Naměřené hodnoty pro jednoduchost budeme reprezentovat sekvencí pevně zadaných hodnot, a to i v několika dalších demonstračních příkladech (samozřejmě je však možné příslušné hodnoty získat libovolným jiným způsobem):
[]int32{1, 2, 4, 8, 9, 8, 4, 2, 1}
Před samotným vykreslením je nutné vytvořit objekt (datovou strukturu) představující graf. K tomu slouží konstruktor nazvaný NewPlot, kterému je nutné mj. předat informaci o tom, zda se bude vykreslovat 2D či 3D graf:
plot, err := glot.NewPlot(2, false, false) if err != nil { panic(err) }
defer plot.Close()
Dále je nutné do grafu přidat měřené body se specifikací jména vykreslené řady/funkce i způsobu jejich vykreslení (zde formou jednotlivých bodů – „points“):
plot.AddPointGroup("Measured data", "points", []int32{1, 2, 4, 8, 9, 8, 4, 2, 1})
Nakonec se výsledek uloží buď do rastrového souboru (PNG, GIF, JPEG) nebo do formátu s vektorovým výstupem (PDF atd.):
plot.SavePlot("glot01.png")
Úplný zdrojový kód dnešního prvního demonstračního příkladu vypadá takto:
package main import ( "github.com/Arafatk/glot" ) func main() { plot, err := glot.NewPlot(2, false, false) if err != nil { panic(err) } plot.AddPointGroup("Measured data", "points", []int32{1, 2, 4, 8, 9, 8, 4, 2, 1}) plot.SavePlot("glot01.png") }
Obrázek 5: Graf s vynesenými naměřenými body vytvořený prvním demonstračním příkladem.
4. Změna stylu vykreslování, specifikace rozsahů hodnot na osách x a y
Ve druhém parametru metody AddPointGroup je nutné specifikovat styl vykreslování hodnot. V prvním příkladu byly použity jednotlivé body, ovšem hodnoty je možné spojit úsečkami:
plot.AddPointGroup("Measured data", "lines", []int32{1, 2, 4, 8, 9, 8, 4, 2, 1})
S následujícím výsledkem:
Obrázek 6: Změna stylu vykreslování grafu – body jsou spojeny úsečkami.
K dispozici jsou následující styly vykreslování:
# | Styl |
---|---|
1 | lines |
2 | points |
3 | linepoints |
4 | impulses |
5 | dots |
6 | bar |
7 | steps |
8 | fill |
9 | id |
10 | histogram |
11 | circle |
12 | errorbars |
13 | boxerrorbars |
14 | boxes |
15 | lp |
Úplný zdrojový kód takto upraveného demonstračního příkladu vypadá následovně:
package main import ( "github.com/Arafatk/glot" ) func main() { plot, err := glot.NewPlot(2, false, false) if err != nil { panic(err) } plot.AddPointGroup("Measured data", "lines", []int32{1, 2, 4, 8, 9, 8, 4, 2, 1}) plot.SavePlot("glot02.png") }
Graf je možné upravovat i dalšími způsoby. Typickým požadavkem je specifikace rozsahu hodnot na x-ové a y-ové ose. To lze provést metodami nazvanými SetXrange a SetYrange:
plot.SetXrange(-2, 10) plot.SetYrange(0, 10)
Obrázek 7: Graf, v němž byly změněny rozsahy na x-ové i y-ové ose.
Opět se samozřejmě podíváme na úplný zdrojový kód tohoto demonstračního příkladu:
package main import ( "github.com/Arafatk/glot" ) func main() { plot, err := glot.NewPlot(2, false, false) if err != nil { panic(err) } plot.AddPointGroup("Measured data", "lines", []int32{1, 2, 4, 8, 9, 8, 4, 2, 1}) plot.SetXrange(-2, 10) plot.SetYrange(0, 10) plot.SavePlot("glot03.png") }
5. Vykreslení několika průběhů do jediného grafu
Do jediného grafu je možné v případě potřeby (a ta je poměrně častá) vykreslit i větší množství průběhů, přičemž je možné nezávisle nastavovat i styly vykreslování jednotlivých částí grafu. Každý průběh je označen legendou, která se předává jako první parametr metody AddPointGroup, popř. dalších dále zmíněných metod určených pro přidání nějakého objektu do grafu:
plot.AddPointGroup("Measured data", "lines", []float32{1.2, 1.9, 3.9, 8.2, 9.5, 8.1, 4.1, 1.8, 1.5}) plot.AddPointGroup("Expected data", "lines", []float32{1, 2, 4, 8, 9, 8, 4, 2, 1})
Samozřejmě lze zvolit odlišné styly vykreslování:
plot.AddPointGroup("Measured data", "points", []float32{1.2, 1.9, 3.9, 8.2, 9.5, 8.1, 4.1, 1.8, 1.5}) plot.AddPointGroup("Expected data", "lines", []float32{1, 2, 4, 8, 9, 8, 4, 2, 1})
Zdrojový kód programu, který vytvoří graf se dvěma průběhy, může v tom nejjednodušším případě vypadat následovně:
package main import ( "github.com/Arafatk/glot" ) func main() { plot, err := glot.NewPlot(2, false, false) if err != nil { panic(err) } plot.AddPointGroup("Measured data", "lines", []float32{1.2, 1.9, 3.9, 8.2, 9.5, 8.1, 4.1, 1.8, 1.5}) plot.AddPointGroup("Expected data", "lines", []float32{1, 2, 4, 8, 9, 8, 4, 2, 1}) plot.SetXrange(-2, 10) plot.SetYrange(0, 10) plot.SavePlot("glot04.png") }
Obrázek 8: Graf, do něhož byly zakresleny dva průběhy.
6. Nastavení vyšší kvality zobrazení – použití antialiasingu
Všechny předchozí grafy nevypadají na obrazovce monitoru a v použitém standardním rozlišení 640×480 pixelů příliš pěkně, a to mj. i z toho důvodu, že jsou patrné „schody“ na všech úsečkách, které nejsou vodorovné nebo naopak svislé. Tento typický vzorek, který je výsledkem aplikace klasického slavného Bresenhamova algoritmu, je však možné odstranit aplikací některého z algoritmů, který úsečky vykreslí s využitím antialiasingu (což vyžaduje použití více barvových odstínů). I Gnuplot a tím pádem i na něm postavená knihovna glot tuto možnost nabízí, a to konkrétně při použití back endu představovaného knihovnou Cairo. Potíž ovšem nastává při použití metody SavePlot, protože v této metodě se mění nastavení parametru terminal, jehož parametry jsou omezeny na „png“ a „pdf“ (opět se jedná o nedostatek současné verze). Namísto metody SavePlot by bylo vhodné zavolat tyto příkazy nástroje Gnuplot:
set terminal pngcairo set output jméno_souboru.png replot
Tyto příkazy sice nemají přímou obdobu v knihovně glot, což ovšem nevadí, protože je možné namísto nich použít „univerzální“ metodu nazvanou Cmd nebo CheckedCmd:
plot.Cmd("set terminal pngcairo") plot.Cmd("set output 'glot05.png'") plot.Cmd("replot")
resp.:
plot.Checked("set terminal pngcairo") plot.Checked("set output 'glot05.png'") plot.Checked("replot")
Demonstrační příklad, který vytiskne graf ve vyšší kvalitě, by tedy mohl vypadat následovně:
package main import ( "github.com/Arafatk/glot" ) func main() { plot, err := glot.NewPlot(2, false, false) if err != nil { panic(err) } defer plot.Close() plot.AddPointGroup("Measured data", "lines", []float32{1.2, 1.9, 3.9, 8.2, 9.5, 8.1, 4.1, 1.8, 1.5}) plot.AddPointGroup("Expected data", "lines", []float32{1, 2, 4, 8, 9, 8, 4, 2, 1}) plot.SetXrange(-2, 10) plot.SetYrange(0, 10) plot.Cmd("set terminal pngcairo") plot.Cmd("set output 'glot05.png'") plot.Cmd("replot") }
Obrázek 9: Antialiasing použitý při vykreslování.
Vzhledem k tomu, že požadavek na uložení grafu do rastrového obrázku ve vyšší kvalitě bude pravděpodobně velmi častý, vytvoříme pro tento účel novou metodu. Ovšem rozšíření datového typu z jiného balíčku o novou metodu není přímo možné – musíme namísto toho zabalit původní datový typ do nového uživatelsky definovaného typu:
type Plot struct { *glot.Plot }
Pro tento nový typ (v aktuálním balíčku) je již vytvoření nové metody triviální:
func (plot *Plot) Save(filename string) { plot.Cmd("set terminal pngcairo") plot.Cmd("set output '" + filename + "'") plot.Cmd("replot") }
Nesmíme samozřejmě zapomenout na konstruktor pro nový datový typ, který nahradí konstruktor výchozí:
func NewPlot(dimensions int) *Plot { plot, err := glot.NewPlot(dimensions, false, false) if err != nil { panic(err) } return &Plot{plot} }
Upravený kód příkladu tedy může vypadat například takto:
package main import ( "github.com/Arafatk/glot" ) type Plot struct { *glot.Plot } func (plot *Plot) Save(filename string) { plot.Cmd("set terminal pngcairo") plot.Cmd("set output '" + filename + "'") plot.Cmd("replot") } func NewPlot(dimensions int) *Plot { plot, err := glot.NewPlot(dimensions, false, false) if err != nil { panic(err) } return &Plot{plot} } func main() { plot := NewPlot(2) defer plot.Close() plot.AddPointGroup("Measured data", "lines", []float32{1.2, 1.9, 3.9, 8.2, 9.5, 8.1, 4.1, 1.8, 1.5}) plot.AddPointGroup("Expected data", "lines", []float32{1, 2, 4, 8, 9, 8, 4, 2, 1}) plot.SetXrange(-2, 10) plot.SetYrange(0, 10) plot.Save("glot06.png") }
Obrázek 10: Výsledek běhu šestého demonstračního příkladu (aplikace antialiasingu).
7. Specifikace titulku grafu a popisů obou jeho os
Knihovna glot umožňuje i další manipulace s vytvářeným grafem. Například je možné specifikovat titulek grafu (typicky zobrazený nahoře, což je však možné v případě potřeby změnit) i popisky obou os. Pro tento účel se používá trojice metod se jmény SetTitle, SetXLabel a SetYLabel:
plot.SetTitle("Plot #7") plot.SetXLabel("t") plot.SetYLabel("m/s")
Samozřejmě nezapomeneme ani na úplný zdrojový kód takto upraveného příkladu:
package main import ( "github.com/Arafatk/glot" ) type Plot struct { *glot.Plot } func (plot *Plot) Save(filename string) { plot.Cmd("set terminal pngcairo") plot.Cmd("set output '" + filename + "'") plot.Cmd("replot") } func NewPlot(dimensions int) *Plot { plot, err := glot.NewPlot(dimensions, false, false) if err != nil { panic(err) } return &Plot{plot} } func main() { plot := NewPlot(2) defer plot.Close() plot.AddPointGroup("Measured data", "lines", []float32{1.2, 1.9, 3.9, 8.2, 9.5, 8.1, 4.1, 1.8, 1.5}) plot.AddPointGroup("Expected data", "lines", []float32{1, 2, 4, 8, 9, 8, 4, 2, 1}) plot.SetTitle("Plot #7") plot.SetXLabel("t") plot.SetYLabel("m/s") plot.SetXrange(-2, 10) plot.SetYrange(0, 10) plot.Save("glot07.png") }
Obrázek 11: Graf, u něhož byl nastavený titulek i popisky obou os.
8. Vykreslení průběhu funkce
V mnoha případech je nutné do grafu vynést průběh nějaké funkce na určeném intervalu. V tomto případě můžeme při tvorbě grafu postupovat několika různými způsoby. Můžeme například vypočítat všechny hodnoty funkce na zadaném intervalu pro předem nastavený počet bodů, řekněme 100 bodů (což odpovídá počtu lomených čar, které aproximují průběh funkce):
const points = 100
Dále musíme vytvořit řez obsahující dvojici řezů typu float64. První z těchto řezů bude sloužit pro uložení x-ových souřadnic bodů, druhý pro uložený y-ových souřadnic. V následujícím úryvku kódu je ukázáno, jak se tento „řez řezů“ v programovacím jazyce Go zkonstruuje:
pts := make([][]float64, 2) for i := 0; i < 2; i++ { pts[i] = make([]float64, points) } for i := 0; i < points; i++ { x := float64(i) * 2.0 * math.Pi / points pts[0][i] = x pts[1][i] = math.Sin(x) }
Tento řez je následně předán nám již známé metodě AddPointGroup:
plot.AddPointGroup("sin t", "lines", pts)
S výsledkem:
Obrázek 12: Vykreslení průběhu funkce. Ve skutečnosti je hladká křivka nahrazena 99 úsečkami.
Úplný zdrojový kód tohoto demonstračního příkladu vypadá takto:
package main import ( "fmt" "github.com/Arafatk/glot" "math" ) type Plot struct { *glot.Plot } func (plot *Plot) Save(filename string) { plot.Cmd("set terminal pngcairo") plot.Cmd("set output '" + filename + "'") plot.Cmd("replot") } func NewPlot(dimensions int) *Plot { plot, err := glot.NewPlot(dimensions, false, false) if err != nil { panic(err) } return &Plot{plot} } const points = 100 func main() { plot := NewPlot(2) defer plot.Close() pts := make([][]float64, 2) for i := 0; i < 2; i++ { pts[i] = make([]float64, points) } for i := 0; i < points; i++ { x := float64(i) * 2.0 * math.Pi / points pts[0][i] = x pts[1][i] = math.Sin(x) } plot.AddPointGroup("sin t", "lines", pts) plot.SetTitle("Plot #8") plot.SetXLabel("t") plot.SetYLabel("sin t") plot.Save("glot08.png") }
9. Automatický výpočet hodnot funkce při použití metody AddFunc2d
Existuje však ještě jeden způsob vykreslení funkce, který je ve většině případů lepší a poněkud obecnější. Tento způsob spočívá v použití metody nazvané AddFunc2d. Této metodě se předává čtveřice parametrů:
- Jméno průběhu (label)
- Styl vykreslování („lines“, „points“ atd.)
- Řez s x-ovými hodnotami
- Funkce, která se má vykreslit (připomeňme si, že v Go jsou funkce plnohodnotným datovým typem)
Příklad použití pro funkci math.Sin:
function := func(t float64) float64 { return math.Sin(t) } plot.AddFunc2d("sin t", "lines", pointsX[:], function)
Obrázek 13: Vykreslení průběhu funkce.
Opět si ukažme, jak vypadá celý zdrojový kód příkladu:
package main import ( "github.com/Arafatk/glot" "math" ) type Plot struct { *glot.Plot } func (plot *Plot) Save(filename string) { plot.Cmd("set terminal pngcairo") plot.Cmd("set output '" + filename + "'") plot.Cmd("replot") } func NewPlot(dimensions int) *Plot { plot, err := glot.NewPlot(dimensions, false, false) if err != nil { panic(err) } return &Plot{plot} } const points = 100 func main() { plot := NewPlot(2) defer plot.Close() var pointsX [points]float64 for i := 0; i < points; i++ { pointsX[i] = float64(i) * 2.0 * math.Pi / points } function := func(t float64) float64 { return math.Sin(t) } plot.AddFunc2d("sin t", "lines", pointsX[:], function) plot.SetTitle("Plot #9") plot.SetXLabel("t") plot.SetYLabel("sin t") plot.Save("glot09.png") }
V dalším příkladu změníme rozsah hodnot na x-ové i y-ové ose:
plot.SetXrange(0, int(math.Round(2.0*math.Pi))) plot.SetYrange(-1, 1)
Obrázek 14: Vykreslení průběhu funkce v odlišném rozsahu.
package main import ( "github.com/Arafatk/glot" "math" ) type Plot struct { *glot.Plot } func (plot *Plot) Save(filename string) { plot.Cmd("set terminal pngcairo") plot.Cmd("set output '" + filename + "'") plot.Cmd("replot") } func NewPlot(dimensions int) *Plot { plot, err := glot.NewPlot(dimensions, false, false) if err != nil { panic(err) } return &Plot{plot} } const points = 100 func main() { plot := NewPlot(2) defer plot.Close() var pointsX [points]float64 for i := 0; i < points; i++ { pointsX[i] = float64(i) * 2.0 * math.Pi / points } function := func(t float64) float64 { return math.Sin(t) } plot.AddFunc2d("sin t", "lines", pointsX[:], function) plot.SetTitle("Plot #10") plot.SetXLabel("t") plot.SetYLabel("sin t") plot.SetXrange(0, int(math.Round(2.0*math.Pi))) plot.SetYrange(-1, 1) plot.Save("glot10.png") }
10. Vykreslení průběhů několika funkcí do jediného grafu
Nyní se můžeme pokusit vykreslit několik funkcí do jediného grafu. Pro ilustraci možností knihovny glot (a tím pádem i nástroje Gnuplot) použijeme trojici anonymních funkcí, z nichž každá slouží pro vyčíslení hodnoty sinu s určitým posunutím (nulový posun, posun o 2π/3 a posun o –2π3):
function1 := func(t float64) float64 { return math.Sin(t) } function2 := func(t float64) float64 { return math.Sin(t + 2.0*math.Pi/3) } function3 := func(t float64) float64 { return math.Sin(t - 2.0*math.Pi/3) }
Všechny tři funkce lze přidat do grafu s využitím nám již známé metody AddFunc2d:
plot.AddFunc2d("sin t", "lines", pointsX[:], function1) plot.AddFunc2d("sin t+2{/Symbol p}/3", "lines", pointsX[:], function2) plot.AddFunc2d("sin t-2{/Symbol p}/3", "lines", pointsX[:], function3)
Výsledkem by měl být následující graf:
Obrázek 11: Průběh tří funkcí vykreslený do jediného grafu.
Opět si pochopitelně ukážeme úplný zdrojový kód tohoto upraveného demonstračního příkladu:
package main import ( "github.com/Arafatk/glot" "math" ) type Plot struct { *glot.Plot } func (plot *Plot) Save(filename string) { plot.Cmd("set terminal pngcairo") plot.Cmd("set output '" + filename + "'") plot.Cmd("replot") } func NewPlot(dimensions int) *Plot { plot, err := glot.NewPlot(dimensions, false, false) if err != nil { panic(err) } return &Plot{plot} } const points = 100 func main() { plot := NewPlot(2) defer plot.Close() var pointsX [points]float64 for i := 0; i < points; i++ { pointsX[i] = float64(i) * 2.0 * math.Pi / points } function1 := func(t float64) float64 { return math.Sin(t) } function2 := func(t float64) float64 { return math.Sin(t + 2.0*math.Pi/3) } function3 := func(t float64) float64 { return math.Sin(t - 2.0*math.Pi/3) } plot.AddFunc2d("sin t", "lines", pointsX[:], function1) plot.AddFunc2d("sin t+2{/Symbol p}/3", "lines", pointsX[:], function2) plot.AddFunc2d("sin t-2{/Symbol p}/3", "lines", pointsX[:], function3) plot.SetTitle("Plot #11") plot.SetXLabel("t") plot.SetYLabel("y") plot.SetXrange(0, int(math.Round(2.0*math.Pi))) plot.SetYrange(-1, 1) plot.Save("glot11.png") }
11. Nastavení hodnot zobrazovaných na osách
U goniometrických funkcí jsou popisky x-ové osy odvozené od nastaveného rozsahu (0 až 6 resp. 0 až 7) spíše matoucí. Lepší by bylo, aby se na tuto osu zobrazily hodnoty odvozené od čísla π, protože pracujeme s jeho násobky a zlomky. K tomuto účelu sice prozatím neexistuje přímý příkaz v knihovně glot, ovšem můžeme použít metodu CheckedCmd pro předání libovolného příkazu nástroji Gnuplot. Toto řešení může vypadat následovně:
plot.CheckedCmd(`set xtics ('0' 0, '{/Symbol p}' pi, '2{/Symbol p}' 2*pi)`)
Výsledek může vypadat takto:
Obrázek 12: Graf, u nějž jsou specifikovány hodnoty zobrazené na x-ové ose.
Úplný výpis takto rozšířeného demonstračního příkladu vypadá následovně:
package main import ( "github.com/Arafatk/glot" "math" ) type Plot struct { *glot.Plot } func (plot *Plot) Save(filename string) { plot.Cmd("set terminal pngcairo") plot.Cmd("set output '" + filename + "'") plot.Cmd("replot") } func NewPlot(dimensions int) *Plot { plot, err := glot.NewPlot(dimensions, false, false) if err != nil { panic(err) } return &Plot{plot} } const points = 100 func main() { plot := NewPlot(2) defer plot.Close() var pointsX [points]float64 for i := 0; i < points; i++ { pointsX[i] = float64(i) * 2.0 * math.Pi / points } function1 := func(t float64) float64 { return math.Sin(t) } function2 := func(t float64) float64 { return math.Sin(t + 2.0*math.Pi/3) } function3 := func(t float64) float64 { return math.Sin(t - 2.0*math.Pi/3) } plot.AddFunc2d("sin t", "lines", pointsX[:], function1) plot.AddFunc2d("sin t+2{/Symbol p}/3", "lines", pointsX[:], function2) plot.AddFunc2d("sin t-2{/Symbol p}/3", "lines", pointsX[:], function3) plot.SetTitle("Plot #12") plot.SetXLabel("t") plot.SetYLabel("y") plot.SetXrange(0, 1+int(math.Round(2.0*math.Pi))) plot.SetYrange(-1, 1) plot.CheckedCmd(`set xtics ('0' 0, '{/Symbol p}' pi, '2{/Symbol p}' 2*pi)`) plot.Save("glot12.png") }
12. Sloupcové grafy
Dalším typem grafu, s nímž se velmi často setkáme, jsou sloupcové grafy. Jejich použití si poněkud netradičně ukážeme na průběhu funkce sinc:
function1 := func(t float64) float64 { // limita if t == 0.0 { return 1.0 } return math.Sin(t) / t }
Vykreslení běžného průběhu funkce s využitím lomené čáry:
plot.AddFunc2d("sinc t", "lines", pointsX[:], function1)
Vykreslení sloupcového grafu:
plot.AddFunc2d("sinc t", "boxes", pointsX[:], function1)
Povšimněte si, že takto nakonfigurovaný sloupcový graf má relativní šířky sloupců rovné 1.0 (sloupce se dotýkají hranami) a navíc nejsou jednotlivé sloupce vyplněné:
Obrázek 13: Sloupcový graf, relativní šířka sloupců je rovna 1.0, sloupce jsou nevyplněné.
Celý kód příkladu je následující:
package main import ( "github.com/Arafatk/glot" "math" ) type Plot struct { *glot.Plot } func (plot *Plot) Save(filename string) { plot.Cmd("set terminal pngcairo") plot.Cmd("set output '" + filename + "'") plot.Cmd("replot") } func NewPlot(dimensions int) *Plot { plot, err := glot.NewPlot(dimensions, false, false) if err != nil { panic(err) } return &Plot{plot} } const points = 50 func main() { plot := NewPlot(2) defer plot.Close() var pointsX [points]float64 for i := 0; i < points; i++ { pointsX[i] = float64(i) * 2.0 * math.Pi / points } function1 := func(t float64) float64 { // limita if t == 0.0 { return 1.0 } return math.Sin(t) / t } plot.AddFunc2d("sinc t", "boxes", pointsX[:], function1) plot.SetTitle("Plot #13") plot.SetXLabel("t") plot.SetYLabel("y") plot.SetXrange(0, 1+int(math.Round(2.0*math.Pi))) plot.SetYrange(-1, 1) plot.CheckedCmd(`set xtics ('0' 0, '{/Symbol p}' pi, '2{/Symbol p}' 2*pi)`) plot.Save("glot13.png") }
Nastavit je možné i výplň sloupců (zde prozatím bez uvedení barvy výplně) a jejich relativní šířky. Šířka 0.5 znamená, že sloupce budou stejně široké jako mezery mezi nimi:
plot.CheckedCmd("set style fill solid") plot.CheckedCmd("set boxwidth 0.5 relative")
Obrázek 14: Sloupcový graf, relativní šířka sloupců je rovna 1/2, sloupce jsou vyplněné.
Opět si ukážeme příslušný příklad:
package main import ( "github.com/Arafatk/glot" "math" ) type Plot struct { *glot.Plot } func (plot *Plot) Save(filename string) { plot.Cmd("set terminal pngcairo") plot.Cmd("set output '" + filename + "'") plot.Cmd("replot") } func NewPlot(dimensions int) *Plot { plot, err := glot.NewPlot(dimensions, false, false) if err != nil { panic(err) } return &Plot{plot} } const points = 50 func main() { plot := NewPlot(2) defer plot.Close() var pointsX [points]float64 for i := 0; i < points; i++ { pointsX[i] = float64(i) * 2.0 * math.Pi / points } function1 := func(t float64) float64 { // limita if t == 0.0 { return 1.0 } return math.Sin(t) / t } plot.AddFunc2d("sinc t", "boxes", pointsX[:], function1) plot.CheckedCmd("set style fill solid") plot.CheckedCmd("set boxwidth 0.5 relative") plot.SetTitle("Plot #14") plot.SetXLabel("t") plot.SetYLabel("y") plot.SetXrange(0, 1+int(math.Round(2.0*math.Pi))) plot.SetYrange(-1, 1) plot.CheckedCmd(`set xtics ('0' 0, '{/Symbol p}' pi, '2{/Symbol p}' 2*pi)`) plot.Save("glot14.png") }
13. Zobrazení průběhu funkce se dvěma nezávislými proměnnými
Další typ grafu, s nímž se dnes seznámíme, je trojrozměrný graf, ve kterém se zobrazuje funkce typu [z]=f(x, y) pro vybrané vstupní hodnoty x a y (jedná se tedy o odlišný typ grafu, než je tomu u grafů ze třetího a čtvrtého obrázku). Před zobrazením této funkce je nejprve nutné připravit dva řezy. První řez bude obsahovat x-ové souřadnice bodů, druhý řez y-ové souřadnice. Pokud například budeme chtít vykreslit spirálu, budou x-ové a y-ové souřadnice nezávislých hodnot opisovat kružnici:
var pointsX [points]float64 var pointsY [points]float64 for i := 0; i < points; i++ { t := float64(i) * 8.0 * math.Pi / points pointsX[i] = math.Sin(t) pointsY[i] = math.Cos(t) }
Hodnotu funkce odpovídající z-ovým souřadnicím získáme pomocí malého triku – nezávisle na předaných parametrech budeme vracet rostoucí posloupnost hodnot typu float64:
z := 0.0 function1 := func(u, v float64) float64 { z = z + 1.0 return z }
Obrázek 15: Spirála vykreslená do 3D grafu.
Pro vykreslení funkce v 3D prostoru se používá metoda AddFunc3d:
plot.AddFunc3d("spiral", "points", pointsX[:], pointsY[:], function1)
Opět si ukažme úplný zdrojový kód tohoto příkladu:
package main import ( "github.com/Arafatk/glot" "math" ) type Plot struct { *glot.Plot } func (plot *Plot) Save(filename string) { plot.Cmd("set terminal pngcairo") plot.Cmd("set output '" + filename + "'") plot.Cmd("replot") } func NewPlot(dimensions int) *Plot { plot, err := glot.NewPlot(dimensions, false, false) if err != nil { panic(err) } return &Plot{plot} } const points = 400 func main() { plot := NewPlot(3) defer plot.Close() var pointsX [points]float64 var pointsY [points]float64 for i := 0; i < points; i++ { t := float64(i) * 8.0 * math.Pi / points pointsX[i] = math.Sin(t) pointsY[i] = math.Cos(t) } z := 0.0 function1 := func(u, v float64) float64 { z = z + 1.0 return z } plot.AddFunc3d("spiral", "points", pointsX[:], pointsY[:], function1) plot.SetTitle("Plot #15") plot.SetXLabel("t") plot.SetYLabel("y") plot.Save("glot15.png") }
Nepatrnou úpravou dosáhneme vykreslení funkce v 3D pomocí lomené čáry:
plot.AddFunc3d("spiral", "lines", pointsX[:], pointsY[:], function1)
S výsledky:
Obrázek 16: Spirála vykreslená do 3D grafu.
14. Knihovna plot z projektu Gonum
Druhou knihovnou určenou pro tvorbu grafů, o níž se dnes alespoň ve stručnosti zmíníme, je knihovna nazvaná jednoduše plot, jejíž repositář se nachází na adrese https://github.com/gonum/plot. Jedná se o součást projektu Gonum, ovšem v případě potřeby lze knihovnu plot použít nezávisle na ostatních balíčcích, které v Gonum nalezneme. Na rozdíl od výše popsané knihovny glot, která závisí na nástroji Gnuplot (a nejedná se tedy o „čistý“ Go projekt, se všemi z toho plynoucími důsledky), je plot vytvořena pouze v jazyku Go, což mj. znamená její snadnější instalaci popř. bezproblémové použití v dalších aplikacích.
Samotná instalace této knihovny (tedy její stažení a překlad) je pro programátory používající jazyk Go triviální:
$ go get gonum.org/v1/plot/...
15. Prázdný graf obsahující pouze legendu a osy
Nejprve si ukážeme, jak se v knihovně plot vykresluje prázdný graf, který obsahuje pouze legendu a osy. Strukturu popisující graf vytvoříme konstruktorem plot.New():
p, err := plot.New() if err != nil { panic(err) }
Při vykreslování grafu je nutné zadat rozlišení výsledného obrázku. To se však nespecifikuje v pixelech, ale v absolutních délkových jednotkách (milimetry, typografické body atd.). Vzhledem k tomu, že se pro přepočet rozlišení na pixely používá metoda převzatá z PostScriptu, můžeme rozlišení 640×480 pixelů specifikovat v palcích takto:
const resX = 20.0 / 3.0 * vg.Inch const resY = 5.0 * vg.Inch
Posledním krokem je vykreslení do zvoleného výstupního souboru, samozřejmě s kontrolou chyby:
err = p.Save(resX, resY, "plot01.png") if err != nil { panic(err) }
Obrázek 17: Prázdný graf vykreslený knihovnou plot.
Celý příklad bude vypadat následovně:
package main import ( "gonum.org/v1/plot" "gonum.org/v1/plot/vg" ) const resX = 20.0 / 3.0 * vg.Inch const resY = 5.0 * vg.Inch func main() { p, err := plot.New() if err != nil { panic(err) } err = p.Save(resX, resY, "plot01.png") if err != nil { panic(err) } }
16. Graf s naměřenými hodnotami vykreslený knihovnou plot
Do grafu nyní přidáme několik naměřených hodnot. Ty budeme specifikovat polem popř. řezem:
input := [...]int32{1, 2, 4, 8, 9, 8, 4, 2, 1}
Z těchto hodnot se vytvoří pole hodnot typu plotter.XYs, tedy pole obsahující struktury nesoucí x-ové a y-ové souřadnice bodů. V jazyce Go je nutné použít explicitní zápis:
points := make(plotter.XYs, len(input)) for i := range points { points[i].X = float64(i) points[i].Y = float64(input[i]) }
A nakonec příslušný průběh přidáme do grafu pomocí metody AddLinePoints, což se vlastně příliš neliší od postupu použitého v knihovně glot:
err = plotutil.AddLinePoints(p, "Measured data", points) if err != nil { panic(err) }
Výsledek:
Obrázek 18: Graf s naměřenými hodnotami vykreslený knihovnou plot.
Zdrojový kód druhého demonstračního příkladu používajícího knihovnu plot:
package main import ( "gonum.org/v1/plot" "gonum.org/v1/plot/plotter" "gonum.org/v1/plot/plotutil" "gonum.org/v1/plot/vg" ) const resX = 20.0 / 3.0 * vg.Inch const resY = 5.0 * vg.Inch func main() { p, err := plot.New() if err != nil { panic(err) } input := [...]int32{1, 2, 4, 8, 9, 8, 4, 2, 1} points := make(plotter.XYs, len(input)) for i := range points { points[i].X = float64(i) points[i].Y = float64(input[i]) } err = plotutil.AddLinePoints(p, "Measured data", points) if err != nil { panic(err) } err = p.Save(resX, resY, "plot02.png") if err != nil { panic(err) } }
17. Změna popisků na osách grafu
V sedmé kapitole jsme si ukázali, jakým způsobem se mění titulek grafu popř. popisky obou os v knihovně glot. Při použití alternativní knihovny plot je ve skutečnosti tato změna ještě jednodušší, protože pouze postačuje nastavit několik atributů:
p.Title.Text = "Plot #3" p.X.Label.Text = "X" p.Y.Label.Text = "Y"
S výsledkem zobrazeným na devatenáctém obrázku:
Obrázek 19: Graf se změněným titulkem i popiskami obou os.
Třetí varianta příkladu založeného na knihovně plot bude vypadat takto:
package main import ( "gonum.org/v1/plot" "gonum.org/v1/plot/plotter" "gonum.org/v1/plot/plotutil" "gonum.org/v1/plot/vg" ) const resX = 20.0 / 3.0 * vg.Inch const resY = 5.0 * vg.Inch func main() { p, err := plot.New() if err != nil { panic(err) } input := [...]int32{1, 2, 4, 8, 9, 8, 4, 2, 1} points := make(plotter.XYs, len(input)) for i := range points { points[i].X = float64(i) points[i].Y = float64(input[i]) } p.Title.Text = "Plot #3" p.X.Label.Text = "X" p.Y.Label.Text = "Y" err = plotutil.AddLinePoints(p, "Measured data", points) if err != nil { panic(err) } err = p.Save(resX, resY, "plot03.png") if err != nil { panic(err) } }
18. Zobrazení průběhů dvou funkcí v jediném grafu
Graf s několika průběhy, s jehož tvorbou v glotu jsme se seznámili v desáté kapitole, je možné při použití knihovny plot vytvořit předáním dalších parametrů do funkce AddLinePoints. Povšimněte si, že se (kromě prvního parametru, což je struktura typu graf) vždy předává dvojice parametrů jméno průběhu+příslušné body (x,y):
err = plotutil.AddLinePoints(p, "Expected data", points1, "Measured data", points2) if err != nil { panic(err) }
Výsledek může vypadat následovně:
Obrázek 20: Výsledek běhu čtvrtého příkladu používajícího knihovnu plot.
Nakonec si uveďme zdrojový kód dnešního posledního demonstračního příkladu:
package main import ( "gonum.org/v1/plot" "gonum.org/v1/plot/plotter" "gonum.org/v1/plot/plotutil" "gonum.org/v1/plot/vg" "math/rand" ) const resX = 20.0 / 3.0 * vg.Inch const resY = 5.0 * vg.Inch func main() { p, err := plot.New() if err != nil { panic(err) } input := [...]int32{1, 2, 4, 8, 9, 8, 4, 2, 1} points1 := make(plotter.XYs, len(input)) points2 := make(plotter.XYs, len(input)) for i := range input { points1[i].X = float64(i) points2[i].X = float64(i) points1[i].Y = float64(input[i]) points2[i].Y = float64(input[i]) + rand.Float64()/2.0 - 0.5 } p.Title.Text = "Plot #3" p.X.Label.Text = "X" p.Y.Label.Text = "Y" err = plotutil.AddLinePoints(p, "Expected data", points1, "Measured data", points2) if err != nil { panic(err) } err = p.Save(resX, resY, "plot04.png") if err != nil { panic(err) } }
19. Repositář s demonstračními příklady
Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/go-root (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má přibližně pět až šest megabajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:
20. Odkazy na Internetu
- package glot
https://godoc.org/github.com/Arafatk/glot - Gnuplotting: Output terminals
http://www.gnuplotting.org/output-terminals/ - Introducing Glot the plotting library for Golang
https://medium.com/@Arafat./introducing-glot-the-plotting-library-for-golang-3133399948a1 - Introducing Glot the plotting library for Golang
https://blog.gopheracademy.com/advent-2018/introducing-glot/ - Glot is a plotting library for Golang built on top of gnuplot
https://github.com/Arafatk/glot - Example plots (gonum/plot)
https://github.com/gonum/plot/wiki/Example-plots - A repository for plotting and visualizing data (gonum/plot)
https://github.com/gonum/plot - golang library to make https://chartjs.org/ plots
https://github.com/brentp/go-chartjs - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - The Gonum Numerical Computing Package
https://www.gonum.org/post/introtogonum/ - Gomacro na GitHubu
https://github.com/cosmos72/gomacro - gophernotes – Use Go in Jupyter notebooks and nteract
https://github.com/gopherdata/gophernotes - gonum
https://github.com/gonum - go-gota/gota – DataFrames and data wrangling in Go (Golang)
https://porter.io/github.com/go-gota/gota - A repository for plotting and visualizing data
https://github.com/gonum/plot - Gonum Numerical Packages
https://www.gonum.org/ - Stránky projektu MinIO
https://min.io/ - MinIO Quickstart Guide
https://docs.min.io/docs/minio-quickstart-guide.html - MinIO Go Client API Reference
https://docs.min.io/docs/golang-client-api-reference - MinIO Python Client API Reference
https://docs.min.io/docs/python-client-api-reference.html - Performance at Scale: MinIO Pushes Past 1.4 terabits per second with 256 NVMe Drives
https://blog.min.io/performance-at-scale-minio-pushes-past-1–3-terabits-per-second-with-256-nvme-drives/ - Benchmarking MinIO vs. AWS S3 for Apache Spark
https://blog.min.io/benchmarking-apache-spark-vs-aws-s3/ - MinIO Client Quickstart Guide
https://docs.min.io/docs/minio-client-quickstart-guide.html - Analýza kvality zdrojových kódů Minia
https://goreportcard.com/report/github.com/minio/minio - This is MinIO
https://www.youtube.com/watch?v=vF0lQh0XOCs - Running MinIO Standalone
https://www.youtube.com/watch?v=dIQsPCHvHoM - „Amazon S3 Compatible Storage in Kubernetes“ – Rob Girard, Principal Tech Marketing Engineer, Minio
https://www.youtube.com/watch?v=wlpn8K0jJ4U - Ginkgo
http://onsi.github.io/ginkgo/ - Gomega
https://onsi.github.io/gomega/ - Ginkgo's Preferred Matcher Library na GitHubu
https://github.com/onsi/gomega/ - Provided Matchers
http://onsi.github.io/gomega/#provided-matchers - Dokumentace k balíčku goexpect
https://godoc.org/github.com/google/goexpect - Balíček goexpect
https://github.com/google/goexpect - Balíček go-expect
https://github.com/Netflix/go-expect - Balíček gexpect
https://github.com/ThomasRooney/gexpect - Expect (originál naprogramovaný v TCL)
https://core.tcl-lang.org/expect/index - Expect (Wikipedia)
https://en.wikipedia.org/wiki/Expect - Pexpect
https://pexpect.readthedocs.io/en/stable/ - Golang SSH Client: Multiple Commands, Crypto & Goexpect Examples
http://networkbit.ch/golang-ssh-client/ - goblin na GitHubu
https://github.com/franela/goblin - Mocha framework
https://mochajs.org/ - frisby na GitHubu
https://github.com/verdverm/frisby - package frisby
https://godoc.org/github.com/verdverm/frisby - Frisby alternatives and similar packages (generováno)
https://go.libhunt.com/frisby-alternatives - Cucumber for golang
https://github.com/DATA-DOG/godog - How to Use Godog for Behavior-driven Development in Go
https://semaphoreci.com/community/tutorials/how-to-use-godog-for-behavior-driven-development-in-go - Comparative Analysis Of GoLang Testing Frameworks
https://www.slideshare.net/DushyantBhalgami/comparative-analysis-of-golang-testing-frameworks - A Quick Guide to Testing in Golang
https://caitiem.com/2016/08/18/a-quick-guide-to-testing-in-golang/ - Tom's Obvious, Minimal Language.
https://github.com/toml-lang/toml - xml.org
http://www.xml.org/ - Soubory .properties
https://en.wikipedia.org/wiki/.properties - Soubory INI
https://en.wikipedia.org/wiki/INI_file - JSON to YAML
https://www.json2yaml.com/ - Data Format Converter
https://toolkit.site/format.html - Viper na GitHubu
https://github.com/spf13/viper - GoDotEnv na GitHubu
https://github.com/joho/godotenv - The fantastic ORM library for Golang
http://gorm.io/ - Dokumentace k balíčku gorilla/mux
https://godoc.org/github.com/gorilla/mux - Gorilla web toolkitk
http://www.gorillatoolkit.org/ - Metric types
https://prometheus.io/docs/concepts/metric_types/ - Histograms with Prometheus: A Tale of Woe
http://linuxczar.net/blog/2017/06/15/prometheus-histogram-2/ - Why are Prometheus histograms cumulative?
https://www.robustperception.io/why-are-prometheus-histograms-cumulative - Histograms and summaries
https://prometheus.io/docs/practices/histograms/ - Instrumenting Golang server in 5 min
https://medium.com/@gsisimogang/instrumenting-golang-server-in-5-min-c1c32489add3 - Semantic Import Versioning in Go
https://www.aaronzhuo.com/semantic-import-versioning-in-go/ - Sémantické verzování
https://semver.org/ - Getting started with Go modules
https://medium.com/@fonseka.live/getting-started-with-go-modules-b3dac652066d - Create projects independent of $GOPATH using Go Modules
https://medium.com/mindorks/create-projects-independent-of-gopath-using-go-modules-802260cdfb51o - Anatomy of Modules in Go
https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 - Modules
https://github.com/golang/go/wiki/Modules - Go Modules Tutorial
https://tutorialedge.net/golang/go-modules-tutorial/ - Module support
https://golang.org/cmd/go/#hdr-Module_support - Go Lang: Memory Management and Garbage Collection
https://vikash1976.wordpress.com/2017/03/26/go-lang-memory-management-and-garbage-collection/ - Golang Internals, Part 4: Object Files and Function Metadata
https://blog.altoros.com/golang-part-4-object-files-and-function-metadata.html - What is REPL?
https://pythonprogramminglanguage.com/repl/ - What is a REPL?
https://codewith.mu/en/tutorials/1.0/repl - Programming at the REPL: Introduction
https://clojure.org/guides/repl/introduction - What is REPL? (Quora)
https://www.quora.com/What-is-REPL - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Read-eval-print loop (Wikipedia)
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - Vim as a Go (Golang) IDE using LSP and vim-go
https://octetz.com/posts/vim-as-go-ide - gopls
https://github.com/golang/go/wiki/gopls - IDE Integration Guide
https://github.com/stamblerre/gocode/blob/master/docs/IDE_integration.md - How to instrument Go code with custom expvar metrics
https://sysdig.com/blog/golang-expvar-custom-metrics/ - Golang expvar metricset (Metricbeat Reference)
https://www.elastic.co/guide/en/beats/metricbeat/7.x/metricbeat-metricset-golang-expvar.html - Package expvar
https://golang.org/pkg/expvar/#NewInt - Java Platform Debugger Architecture: Overview
https://docs.oracle.com/en/java/javase/11/docs/specs/jpda/jpda.html - The JVM Tool Interface (JVM TI): How VM Agents Work
https://www.oracle.com/technetwork/articles/javase/index-140680.html - JVM Tool Interface Version 11.0
https://docs.oracle.com/en/java/javase/11/docs/specs/jvmti.html - Creating a Debugging and Profiling Agent with JVMTI
http://www.oracle.com/technetwork/articles/javase/jvmti-136367.html - JVM TI (Wikipedia)
http://en.wikipedia.org/wiki/JVM_TI - IBM JVMTI extensions
http://publib.boulder.ibm.com/infocenter/realtime/v2r0/index.jsp?topic=%2Fcom.ibm.softrt.doc%2Fdiag%2Ftools%2Fjvmti_extensions.html - Go & cgo: integrating existing C code with Go
http://akrennmair.github.io/golang-cgo-slides/#1 - Using cgo to call C code from within Go code
https://wenzr.wordpress.com/2018/06/07/using-cgo-to-call-c-code-from-within-go-code/ - Package trace
https://golang.org/pkg/runtime/trace/ - Introducing HTTP Tracing
https://blog.golang.org/http-tracing - Command trace
https://golang.org/cmd/trace/ - A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
https://github.com/wesovilabs/koazee - Funkce vyššího řádu v knihovně Underscore
https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/ - Delve: a debugger for the Go programming language.
https://github.com/go-delve/delve - Příkazy debuggeru Delve
https://github.com/go-delve/delve/tree/master/Documentation/cli - Debuggery a jejich nadstavby v Linuxu
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/ - Debuggery a jejich nadstavby v Linuxu (2. část)
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/ - Debuggery a jejich nadstavby v Linuxu (3): Nemiver
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/ - Debuggery a jejich nadstavby v Linuxu (4): KDbg
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/ - Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/ - Debugging Go Code with GDB
https://golang.org/doc/gdb - Debugging Go (golang) programs with gdb
https://thornydev.blogspot.com/2014/01/debugging-go-golang-programs-with-gdb.html - GDB – Dokumentace
http://sourceware.org/gdb/current/onlinedocs/gdb/ - GDB – Supported Languages
http://sourceware.org/gdb/current/onlinedocs/gdb/Supported-Languages.html#Supported-Languages - GNU Debugger (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Debugger - The LLDB Debugger
http://lldb.llvm.org/ - Debugger (Wikipedia)
https://en.wikipedia.org/wiki/Debugger - 13 Linux Debuggers for C++ Reviewed
http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817 - Go is on a Trajectory to Become the Next Enterprise Programming Language
https://hackernoon.com/go-is-on-a-trajectory-to-become-the-next-enterprise-programming-language-3b75d70544e - Go Proverbs: Simple, Poetic, Pithy
https://go-proverbs.github.io/ - Handling Sparse Files on Linux
https://www.systutorials.com/136652/handling-sparse-files-on-linux/ - Gzip (Wikipedia)
https://en.wikipedia.org/wiki/Gzip - Deflate
https://en.wikipedia.org/wiki/DEFLATE - 10 tools written in Go that every developer needs to know
https://gustavohenrique.net/en/2019/01/10-tools-written-in-go-that-every-dev-needs-to-know/ - Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
https://www.root.cz/clanky/hexadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/ - Hex dump
https://en.wikipedia.org/wiki/Hex_dump - Rozhraní io.ByteReader
https://golang.org/pkg/io/#ByteReader - Rozhraní io.RuneReader
https://golang.org/pkg/io/#RuneReader - Rozhraní io.ByteScanner
https://golang.org/pkg/io/#ByteScanner - Rozhraní io.RuneScanner
https://golang.org/pkg/io/#RuneScanner - Rozhraní io.Closer
https://golang.org/pkg/io/#Closer - Rozhraní io.Reader
https://golang.org/pkg/io/#Reader - Rozhraní io.Writer
https://golang.org/pkg/io/#Writer - Typ Strings.Reader
https://golang.org/pkg/strings/#Reader - VACUUM (SQL)
https://www.sqlite.org/lang_vacuum.html - VACUUM (Postgres)
https://www.postgresql.org/docs/8.4/sql-vacuum.html - go-cron
https://github.com/rk/go-cron - gocron
https://github.com/jasonlvhit/gocron - clockwork
https://github.com/whiteShtef/clockwork - clockwerk
https://github.com/onatm/clockwerk - JobRunner
https://github.com/bamzi/jobrunner - Rethinking Cron
https://adam.herokuapp.com/past/2010/4/13/rethinking_cron/ - In the Beginning was the Command Line
https://web.archive.org/web/20180218045352/http://www.cryptonomicon.com/beginning.html - repl.it (REPL pro různé jazyky)
https://repl.it/languages - GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
https://github.com/jroimartin/gocui - Read–eval–print loop
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - go-prompt
https://github.com/c-bata/go-prompt - readline
https://github.com/chzyer/readline - A pure golang implementation for GNU-Readline kind library
https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/ - go-readline
https://github.com/fiorix/go-readline - 4 Python libraries for building great command-line user interfaces
https://opensource.com/article/17/5/4-practical-python-libraries - prompt_toolkit 2.0.3 na PyPi
https://pypi.org/project/prompt_toolkit/ - python-prompt-toolkit na GitHubu
https://github.com/jonathanslenders/python-prompt-toolkit - The GNU Readline Library
https://tiswww.case.edu/php/chet/readline/rltop.html - GNU Readline (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Readline - readline — GNU readline interface (Python 3.x)
https://docs.python.org/3/library/readline.html - readline — GNU readline interface (Python 2.x)
https://docs.python.org/2/library/readline.html - GNU Readline Library – command line editing
https://tiswww.cwru.edu/php/chet/readline/readline.html - gnureadline 6.3.8 na PyPi
https://pypi.org/project/gnureadline/ - Editline Library (libedit)
http://thrysoee.dk/editline/ - Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/ - libedit or editline
http://www.cs.utah.edu/~bigler/code/libedit.html - WinEditLine
http://mingweditline.sourceforge.net/ - rlcompleter — Completion function for GNU readline
https://docs.python.org/3/library/rlcompleter.html - rlwrap na GitHubu
https://github.com/hanslub42/rlwrap - rlwrap(1) – Linux man page
https://linux.die.net/man/1/rlwrap - readline(3) – Linux man page
https://linux.die.net/man/3/readline - history(3) – Linux man page
https://linux.die.net/man/3/history - Dokumentace k balíčku oglematchers
https://godoc.org/github.com/jacobsa/oglematchers - Balíček oglematchers
https://github.com/jacobsa/oglematchers - Dokumentace k balíčku ogletest
https://godoc.org/github.com/jacobsa/ogletest - Balíček ogletest
https://github.com/jacobsa/ogletest - Dokumentace k balíčku assert
https://godoc.org/github.com/stretchr/testify/assert - Testify – Thou Shalt Write Tests
https://github.com/stretchr/testify/ - package testing
https://golang.org/pkg/testing/ - Golang basics – writing unit tests
https://blog.alexellis.io/golang-writing-unit-tests/ - An Introduction to Programming in Go / Testing
https://www.golang-book.com/books/intro/12 - An Introduction to Testing in Go
https://tutorialedge.net/golang/intro-testing-in-go/ - Advanced Go Testing Tutorial
https://tutorialedge.net/golang/advanced-go-testing-tutorial/ - GoConvey
http://goconvey.co/ - Testing Techniques
https://talks.golang.org/2014/testing.slide - 5 simple tips and tricks for writing unit tests in #golang
https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742 - Afinní transformace
https://cs.wikibooks.org/wiki/Geometrie/Afinn%C3%AD_transformace_sou%C5%99adnic - package gg
https://godoc.org/github.com/fogleman/gg - Generate an animated GIF with Golang
http://tech.nitoyon.com/en/blog/2016/01/07/go-animated-gif-gen/ - Generate an image programmatically with Golang
http://tech.nitoyon.com/en/blog/2015/12/31/go-image-gen/ - The Go image package
https://blog.golang.org/go-image-package - Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
https://github.com/llgcode/draw2d - Draw a rectangle in Golang?
https://stackoverflow.com/questions/28992396/draw-a-rectangle-in-golang - YAML
https://yaml.org/ - edn
https://github.com/edn-format/edn - Smile
https://github.com/FasterXML/smile-format-specification - Protocol-Buffers
https://developers.google.com/protocol-buffers/ - Marshalling (computer science)
https://en.wikipedia.org/wiki/Marshalling_(computer_science) - Unmarshalling
https://en.wikipedia.org/wiki/Unmarshalling - Introducing JSON
http://json.org/ - Package json
https://golang.org/pkg/encoding/json/ - The Go Blog: JSON and Go
https://blog.golang.org/json-and-go - Go by Example: JSON
https://gobyexample.com/json - Writing Web Applications
https://golang.org/doc/articles/wiki/ - Golang Web Apps
https://www.reinbach.com/blog/golang-webapps-1/ - Build web application with Golang
https://legacy.gitbook.com/book/astaxie/build-web-application-with-golang/details - Golang Templates – Golang Web Pages
https://www.youtube.com/watch?v=TkNIETmF-RU - Simple Golang HTTPS/TLS Examples
https://github.com/denji/golang-tls - Playing with images in HTTP response in golang
https://www.sanarias.com/blog/1214PlayingwithimagesinHTTPresponseingolang - MIME Types List
https://www.freeformatter.com/mime-types-list.html - Go Mutex Tutorial
https://tutorialedge.net/golang/go-mutex-tutorial/ - Creating A Simple Web Server With Golang
https://tutorialedge.net/golang/creating-simple-web-server-with-golang/ - Building a Web Server in Go
https://thenewstack.io/building-a-web-server-in-go/ - How big is the pipe buffer?
https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer - How to turn off buffering of stdout in C
https://stackoverflow.com/questions/7876660/how-to-turn-off-buffering-of-stdout-in-c - setbuf(3) – Linux man page
https://linux.die.net/man/3/setbuf - setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
https://linux.die.net/man/3/setvbuf - Select waits on a group of channels
https://yourbasic.org/golang/select-explained/ - Rob Pike: Simplicity is Complicated (video)
http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893 - Algorithms to Go
https://yourbasic.org/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů: vlastní filtry a lexery
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu-vlastni-filtry-a-lexery/ - Go Defer Simplified with Practical Visuals
https://blog.learngoprogramming.com/golang-defer-simplified-77d3b2b817ff - 5 More Gotchas of Defer in Go — Part II
https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa - The Go Blog: Defer, Panic, and Recover
https://blog.golang.org/defer-panic-and-recover - The defer keyword in Swift 2: try/finally done right
https://www.hackingwithswift.com/new-syntax-swift-2-defer - Swift Defer Statement
https://andybargh.com/swift-defer-statement/ - Modulo operation (Wikipedia)
https://en.wikipedia.org/wiki/Modulo_operation - Node.js vs Golang: Battle of the Next-Gen Languages
https://www.hostingadvice.com/blog/nodejs-vs-golang/ - The Go Programming Language (home page)
https://golang.org/ - GoDoc
https://godoc.org/ - Go (programming language), Wikipedia
https://en.wikipedia.org/wiki/Go_(programming_language) - Go Books (kniha o jazyku Go)
https://github.com/dariubs/GoBooks - The Go Programming Language Specification
https://golang.org/ref/spec - Go: the Good, the Bad and the Ugly
https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/ - Package builtin
https://golang.org/pkg/builtin/ - Package fmt
https://golang.org/pkg/fmt/ - The Little Go Book (další kniha)
https://github.com/dariubs/GoBooks - The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
https://www.safaribooksonline.com/library/view/the-go-programming/9780134190570/ebook_split010.html - Learning Go
https://www.miek.nl/go/ - Go Bootcamp
http://www.golangbootcamp.com/ - Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
http://www.informit.com/store/programming-in-go-creating-applications-for-the-21st-9780321774637 - Introducing Go (Build Reliable, Scalable Programs)
http://shop.oreilly.com/product/0636920046516.do - Learning Go Programming
https://www.packtpub.com/application-development/learning-go-programming - The Go Blog
https://blog.golang.org/ - Getting to Go: The Journey of Go's Garbage Collector
https://blog.golang.org/ismmkeynote - Go (programovací jazyk, Wikipedia)
https://cs.wikipedia.org/wiki/Go_(programovac%C3%AD_jazyk) - Rychle, rychleji až úplně nejrychleji s jazykem Go
https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/ - Installing Go on the Raspberry Pi
https://dave.cheney.net/2012/09/25/installing-go-on-the-raspberry-pi - How the Go runtime implements maps efficiently (without generics)
https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics - Niečo málo o Go – Golang (slovensky)
http://golangsk.logdown.com/ - How Many Go Developers Are There?
https://research.swtch.com/gophercount - Most Popular Technologies (Stack Overflow Survery 2018)
https://insights.stackoverflow.com/survey/2018/#most-popular-technologies - Most Popular Technologies (Stack Overflow Survery 2017)
https://insights.stackoverflow.com/survey/2017#technology - JavaScript vs. Golang for IoT: Is Gopher Winning?
https://www.iotforall.com/javascript-vs-golang-iot/ - The Go Programming Language: Release History
https://golang.org/doc/devel/release.html - Go 1.11 Release Notes
https://golang.org/doc/go1.11 - Go 1.10 Release Notes
https://golang.org/doc/go1.10 - Go 1.9 Release Notes (tato verze je stále používána)
https://golang.org/doc/go1.9 - Go 1.8 Release Notes (i tato verze je stále používána)
https://golang.org/doc/go1.8 - Go on Fedora
https://developer.fedoraproject.org/tech/languages/go/go-installation.html - Writing Go programs
https://developer.fedoraproject.org/tech/languages/go/go-programs.html - The GOPATH environment variable
https://tip.golang.org/doc/code.html#GOPATH - Command gofmt
https://tip.golang.org/cmd/gofmt/ - The Go Blog: go fmt your code
https://blog.golang.org/go-fmt-your-code - C? Go? Cgo!
https://blog.golang.org/c-go-cgo - Spaces vs. Tabs: A 20-Year Debate Reignited by Google’s Golang
https://thenewstack.io/spaces-vs-tabs-a-20-year-debate-and-now-this-what-the-hell-is-wrong-with-go/ - 400,000 GitHub repositories, 1 billion files, 14 terabytes of code: Spaces or Tabs?
https://medium.com/@hoffa/400–000-github-repositories-1-billion-files-14-terabytes-of-code-spaces-or-tabs-7cfe0b5dd7fd - Gofmt No Longer Allows Spaces. Tabs Only
https://news.ycombinator.com/item?id=7914523 - Why does Go „go fmt“ uses tabs instead of whitespaces?
https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces - Interactive: The Top Programming Languages 2018
https://spectrum.ieee.org/static/interactive-the-top-programming-languages-2018 - Go vs. Python
https://www.peterbe.com/plog/govspy - PackageManagementTools
https://github.com/golang/go/wiki/PackageManagementTools - A Tour of Go: Type inference
https://tour.golang.org/basics/14 - Go Slices: usage and internals
https://blog.golang.org/go-slices-usage-and-internals - Go by Example: Slices
https://gobyexample.com/slices - What is the point of slice type in Go?
https://stackoverflow.com/questions/2098874/what-is-the-point-of-slice-type-in-go - The curious case of Golang array and slices
https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335 - Introduction to Slices in Golang
https://www.callicoder.com/golang-slices/ - Golang: Understanding ‚null‘ and nil
https://newfivefour.com/golang-null-nil.html - What does nil mean in golang?
https://stackoverflow.com/questions/35983118/what-does-nil-mean-in-golang - nils In Go
https://go101.org/article/nil.html - Go slices are not dynamic arrays
https://appliedgo.net/slices/ - Go-is-no-good (nelze brát doslova)
https://github.com/ksimka/go-is-not-good - Rust vs. Go
https://news.ycombinator.com/item?id=13430108 - Seriál Programovací jazyk Rust
https://www.root.cz/serialy/programovaci-jazyk-rust/ - Modern garbage collection: A look at the Go GC strategy
https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e - Go GC: Prioritizing low latency and simplicity
https://blog.golang.org/go15gc - Is Golang a good language for embedded systems?
https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems - Running GoLang on an STM32 MCU. A quick tutorial.
https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial - Go, Robot, Go! Golang Powered Robotics
https://gobot.io/ - Emgo: Bare metal Go (language for programming embedded systems)
https://github.com/ziutek/emgo - UTF-8 history
https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt - Less is exponentially more
https://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html - Should I Rust, or Should I Go
https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9 - Setting up and using gccgo
https://golang.org/doc/install/gccgo - Elastic Tabstops
http://nickgravgaard.com/elastic-tabstops/ - Strings, bytes, runes and characters in Go
https://blog.golang.org/strings - Datový typ
https://cs.wikipedia.org/wiki/Datov%C3%BD_typ - Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
https://www.root.cz/clanky/programovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09 - Seriál o programovacím jazyku Rust: Vytvoření „řezu“ z pole
https://www.root.cz/clanky/prace-s-poli-v-programovacim-jazyku-rust/#k06 - Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05 - Printf Format Strings
https://www.cprogramming.com/tutorial/printf-format-strings.html - Java: String.format
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#format-java.lang.String-java.lang.Object…- - Java: format string syntax
https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html#syntax - Selectors
https://golang.org/ref/spec#Selectors - Calling Go code from Python code
http://savorywatt.com/2015/09/18/calling-go-code-from-python-code/ - Go Data Structures: Interfaces
https://research.swtch.com/interfaces - How to use interfaces in Go
http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go - Interfaces in Go (part I)
https://medium.com/golangspec/interfaces-in-go-part-i-4ae53a97479c - Part 21: Goroutines
https://golangbot.com/goroutines/ - Part 22: Channels
https://golangbot.com/channels/ - [Go] Lightweight eventbus with async compatibility for Go
https://github.com/asaskevich/EventBus - What about Trait support in Golang?
https://www.reddit.com/r/golang/comments/8mfykl/what_about_trait_support_in_golang/ - Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang
https://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in-golang/ - Control Flow
https://en.wikipedia.org/wiki/Control_flow - Structured programming
https://en.wikipedia.org/wiki/Structured_programming - Control Structures
https://www.golang-book.com/books/intro/5 - Control structures – Go if else statement
http://golangtutorials.blogspot.com/2011/06/control-structures-if-else-statement.html - Control structures – Go switch case statement
http://golangtutorials.blogspot.com/2011/06/control-structures-go-switch-case.html - Control structures – Go for loop, break, continue, range
http://golangtutorials.blogspot.com/2011/06/control-structures-go-for-loop-break.html - Goroutine IDs
https://blog.sgmansfield.com/2015/12/goroutine-ids/ - Different ways to pass channels as arguments in function in go (golang)
https://stackoverflow.com/questions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang - justforfunc #22: using the Go execution tracer
https://www.youtube.com/watch?v=ySy3sR1LFCQ - Single Function Exit Point
http://wiki.c2.com/?SingleFunctionExitPoint - Entry point
https://en.wikipedia.org/wiki/Entry_point - Why does Go have a GOTO statement?!
https://www.reddit.com/r/golang/comments/kag5q/why_does_go_have_a_goto_statement/ - Effective Go
https://golang.org/doc/effective_go.html - GoClipse: an Eclipse IDE for the Go programming language
http://goclipse.github.io/ - GoClipse Installation
https://github.com/GoClipse/goclipse/blob/latest/documentation/Installation.md#installation - The zero value of a slice is not nil
https://stackoverflow.com/questions/30806931/the-zero-value-of-a-slice-is-not-nil - Go-tcha: When nil != nil
https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic - Nils in Go
https://www.doxsey.net/blog/nils-in-go