Hlavní navigace

Tvorba grafů v jazyce Go

Pavel Tišnovský

Dnes navážeme na předchozí dva články, v nichž jsme si popsali některé možnosti nabízené projektem Gonum v oblasti numerické matematiky. Dnes si popíšeme dvě knihovny určené pro tvorbu grafů.

Doba čtení: 46 minut

Sdílet

11. Nastavení hodnot zobrazovaných na osách

12. Sloupcové grafy

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

20. Odkazy na Internetu

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.

Poznámka: dnes popisovaná dvojice knihoven je sice použitelná v poměrně velkém množství případů, ovšem programovací jazyk Go se většinou používá pro tvorbu odlišných typů aplikací, typicky aplikací s REST API rozhraním apod. Pokud vám tedy možnosti popisovaných knihoven nebudou vyhovovat, může být užitečnější se zaměřit na použití odlišných knihoven, které „pouze“ poskytují data ve vhodném formátu, která jsou následně zpracována a vykreslena do plochy HTML stránky s využitím možností poskytovaných canvasem a programovacím jazykem JavaScript. Jednu z takto koncipovaných knihoven si ve stručnosti popíšeme příště. Navíc uvidíme, že kvůli silnému typovému systému jazyka Go a některým omezením volání funkcí (neexistence keywords parametrů) nemusí být tvorba grafů v tomto jazyce tak elegantní, jako v případě použití jazyka R, Matlabu či populární kombinace Python+NumPy+Matplotlib.

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
Poznámka: kvůli závislosti na dalších balíčcích tedy není instalace glotu tak přímočará, jak jsme jinak ve světě Go zvyklí.

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)
}
Poznámka: po ukončení práce s grafem by se mělo provést i jeho uzavření (deinicializace). Jedná se o typický případ, kdy v programovacím jazyce Go použijeme konstrukci defer:
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)
Poznámka: zajímavé je, že rozsahy jsou určeny celými čísly a ne hodnotami s plovoucí řádovou čárkou. Pravděpodobně se jedná o nedomyšlenost v návrhu knihovny, protože podobné omezení v původním Gnuplotu nenajdeme (autor článku posílá patch s opravou).

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")
Poznámka: metody Cmd a CheckedCmd se od sebe odlišují – první z těchto metod vrací hodnotu typu error (nebo nil pokud k chybě nedošlo), zatímco druhá metoda při detekci chyby přímo zavolá funkci panic().

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ů:

  1. Jméno průběhu (label)
  2. Styl vykreslování („lines“, „points“ atd.)
  3. Řez s x-ovými hodnotami
  4. 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)
Poznámka: ve skutečnosti lze předat přímo math.Sin.

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)
Poznámka: v současnosti je možné nastavit pouze celočíselné rozsahy.

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)
Poznámka: povšimněte si, jakým způsobem se zapisuje symbol π tak, aby s ním korektně pracoval i nástroj Gnuplot.

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
}
Poznámka: povšimněte si, že se v tomto případě jedná o uzávěr (closure).

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/...
Poznámka: dnes se seznámíme pouze se základními vlastnostmi knihovny plot. Další možnosti, které tato knihovna uživatelům nabízí, budou vysvětleny a na demonstračních příkladech ukázány příště.

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:

# Příklad Stručný popis Cesta
1 glot01.go graf s naměřenými hodnotami vykreslený knihovnou glot https://github.com/tisnik/go-root/blob/master/article50/glot01.go
2 glot02.go změna stylu vykreslování https://github.com/tisnik/go-root/blob/master/article50/glot02.go
3 glot03.go specifikace rozsahů hodnot na osách x a y https://github.com/tisnik/go-root/blob/master/article50/glot03.go
4 glot04.go vykreslení několika průběhů do jediného grafu https://github.com/tisnik/go-root/blob/master/article50/glot04.go
5 glot05.go nastavení vyšší kvality zobrazení – použití antialiasingu https://github.com/tisnik/go-root/blob/master/article50/glot05.go
6 glot06.go vylepšení a refaktoring předchozího příkladu https://github.com/tisnik/go-root/blob/master/article50/glot06.go
7 glot07.go specifikace titulku grafu a popisů obou jeho os https://github.com/tisnik/go-root/blob/master/article50/glot07.go
8 glot08.go vykreslení průběhu funkce https://github.com/tisnik/go-root/blob/master/article50/glot08.go
9 glot09.go automatický výpočet hodnot funkce při použití metody AddFunc2d https://github.com/tisnik/go-root/blob/master/article50/glot09.go
10 glot10.go specifikace rozsahů hodnot na osách x a y https://github.com/tisnik/go-root/blob/master/article50/glot10.go
11 glot11.go vykreslení průběhů několika funkcí do jediného grafu https://github.com/tisnik/go-root/blob/master/article50/glot11.go
12 glot12.go nastavení hodnot zobrazovaných na osách https://github.com/tisnik/go-root/blob/master/article50/glot12.go
13 glot13.go vykreslení sloupcového grafu https://github.com/tisnik/go-root/blob/master/article50/glot13.go
14 glot14.go vykreslení vyplněného sloupcového grafu, určení šířky sloupců https://github.com/tisnik/go-root/blob/master/article50/glot14.go
15 glot15.go zobrazení průběhu funkce se dvěma nezávislými proměnnými https://github.com/tisnik/go-root/blob/master/article50/glot15.go
16 glot16.go zobrazení průběhu funkce se dvěma nezávislými proměnnými https://github.com/tisnik/go-root/blob/master/article50/glot16.go
       
17 plot01.go prázdný graf obsahující pouze legendu a osy https://github.com/tisnik/go-root/blob/master/article50/plot01.go
18 plot02.go graf s naměřenými hodnotami vykreslený knihovnou plot https://github.com/tisnik/go-root/blob/master/article50/plot02.go
19 plot03.go změna popisků na osách https://github.com/tisnik/go-root/blob/master/article50/plot03.go
20 plot04.go zobrazení průběhů dvou funkcí v jediném grafu https://github.com/tisnik/go-root/blob/master/article50/plot04.go

20. Odkazy na Internetu

  1. package glot
    https://godoc.org/github.com/A­rafatk/glot
  2. Gnuplotting: Output terminals
    http://www.gnuplotting.org/output-terminals/
  3. Introducing Glot the plotting library for Golang
    https://medium.com/@Arafat­./introducing-glot-the-plotting-library-for-golang-3133399948a1
  4. Introducing Glot the plotting library for Golang
    https://blog.gopheracademy.com/advent-2018/introducing-glot/
  5. Glot is a plotting library for Golang built on top of gnuplot
    https://github.com/Arafatk/glot
  6. Example plots (gonum/plot)
    https://github.com/gonum/plot/wi­ki/Example-plots
  7. A repository for plotting and visualizing data (gonum/plot)
    https://github.com/gonum/plot
  8. golang library to make https://chartjs.org/ plots
    https://github.com/brentp/go-chartjs
  9. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  10. The Gonum Numerical Computing Package
    https://www.gonum.org/pos­t/introtogonum/
  11. Gomacro na GitHubu
    https://github.com/cosmos72/gomacro
  12. gophernotes – Use Go in Jupyter notebooks and nteract
    https://github.com/gopher­data/gophernotes
  13. gonum
    https://github.com/gonum
  14. go-gota/gota – DataFrames and data wrangling in Go (Golang)
    https://porter.io/github.com/go-gota/gota
  15. A repository for plotting and visualizing data
    https://github.com/gonum/plot
  16. Gonum Numerical Packages
    https://www.gonum.org/
  17. Stránky projektu MinIO
    https://min.io/
  18. MinIO Quickstart Guide
    https://docs.min.io/docs/minio-quickstart-guide.html
  19. MinIO Go Client API Reference
    https://docs.min.io/docs/golang-client-api-reference
  20. MinIO Python Client API Reference
    https://docs.min.io/docs/python-client-api-reference.html
  21. 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/
  22. Benchmarking MinIO vs. AWS S3 for Apache Spark
    https://blog.min.io/benchmarking-apache-spark-vs-aws-s3/
  23. MinIO Client Quickstart Guide
    https://docs.min.io/docs/minio-client-quickstart-guide.html
  24. Analýza kvality zdrojových kódů Minia
    https://goreportcard.com/re­port/github.com/minio/minio
  25. This is MinIO
    https://www.youtube.com/wat­ch?v=vF0lQh0XOCs
  26. Running MinIO Standalone
    https://www.youtube.com/wat­ch?v=dIQsPCHvHoM
  27. „Amazon S3 Compatible Storage in Kubernetes“ – Rob Girard, Principal Tech Marketing Engineer, Minio
    https://www.youtube.com/wat­ch?v=wlpn8K0jJ4U
  28. Ginkgo
    http://onsi.github.io/ginkgo/
  29. Gomega
    https://onsi.github.io/gomega/
  30. Ginkgo's Preferred Matcher Library na GitHubu
    https://github.com/onsi/gomega/
  31. Provided Matchers
    http://onsi.github.io/gomega/#provided-matchers
  32. Dokumentace k balíčku goexpect
    https://godoc.org/github.com/go­ogle/goexpect
  33. Balíček goexpect
    https://github.com/google/goexpect
  34. Balíček go-expect
    https://github.com/Netflix/go-expect
  35. Balíček gexpect
    https://github.com/Thomas­Rooney/gexpect
  36. Expect (originál naprogramovaný v TCL)
    https://core.tcl-lang.org/expect/index
  37. Expect (Wikipedia)
    https://en.wikipedia.org/wiki/Expect
  38. Pexpect
    https://pexpect.readthedoc­s.io/en/stable/
  39. Golang SSH Client: Multiple Commands, Crypto & Goexpect Examples
    http://networkbit.ch/golang-ssh-client/
  40. goblin na GitHubu
    https://github.com/franela/goblin
  41. Mocha framework
    https://mochajs.org/
  42. frisby na GitHubu
    https://github.com/verdverm/frisby
  43. package frisby
    https://godoc.org/github.com/ver­dverm/frisby
  44. Frisby alternatives and similar packages (generováno)
    https://go.libhunt.com/frisby-alternatives
  45. Cucumber for golang
    https://github.com/DATA-DOG/godog
  46. How to Use Godog for Behavior-driven Development in Go
    https://semaphoreci.com/com­munity/tutorials/how-to-use-godog-for-behavior-driven-development-in-go
  47. Comparative Analysis Of GoLang Testing Frameworks
    https://www.slideshare.net/Dushy­antBhalgami/comparative-analysis-of-golang-testing-frameworks
  48. A Quick Guide to Testing in Golang
    https://caitiem.com/2016/08/18/a-quick-guide-to-testing-in-golang/
  49. Tom's Obvious, Minimal Language.
    https://github.com/toml-lang/toml
  50. xml.org
    http://www.xml.org/
  51. Soubory .properties
    https://en.wikipedia.org/wi­ki/.properties
  52. Soubory INI
    https://en.wikipedia.org/wi­ki/INI_file
  53. JSON to YAML
    https://www.json2yaml.com/
  54. Data Format Converter
    https://toolkit.site/format.html
  55. Viper na GitHubu
    https://github.com/spf13/viper
  56. GoDotEnv na GitHubu
    https://github.com/joho/godotenv
  57. The fantastic ORM library for Golang
    http://gorm.io/
  58. Dokumentace k balíčku gorilla/mux
    https://godoc.org/github.com/go­rilla/mux
  59. Gorilla web toolkitk
    http://www.gorillatoolkit.org/
  60. Metric types
    https://prometheus.io/doc­s/concepts/metric_types/
  61. Histograms with Prometheus: A Tale of Woe
    http://linuxczar.net/blog/2017/06/15/pro­metheus-histogram-2/
  62. Why are Prometheus histograms cumulative?
    https://www.robustperception.io/why-are-prometheus-histograms-cumulative
  63. Histograms and summaries
    https://prometheus.io/doc­s/practices/histograms/
  64. Instrumenting Golang server in 5 min
    https://medium.com/@gsisi­mogang/instrumenting-golang-server-in-5-min-c1c32489add3
  65. Semantic Import Versioning in Go
    https://www.aaronzhuo.com/semantic-import-versioning-in-go/
  66. Sémantické verzování
    https://semver.org/
  67. Getting started with Go modules
    https://medium.com/@fonse­ka.live/getting-started-with-go-modules-b3dac652066d
  68. Create projects independent of $GOPATH using Go Modules
    https://medium.com/mindorks/create-projects-independent-of-gopath-using-go-modules-802260cdfb51o
  69. Anatomy of Modules in Go
    https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16
  70. Modules
    https://github.com/golang/go/wi­ki/Modules
  71. Go Modules Tutorial
    https://tutorialedge.net/golang/go-modules-tutorial/
  72. Module support
    https://golang.org/cmd/go/#hdr-Module_support
  73. Go Lang: Memory Management and Garbage Collection
    https://vikash1976.wordpres­s.com/2017/03/26/go-lang-memory-management-and-garbage-collection/
  74. Golang Internals, Part 4: Object Files and Function Metadata
    https://blog.altoros.com/golang-part-4-object-files-and-function-metadata.html
  75. What is REPL?
    https://pythonprogramminglan­guage.com/repl/
  76. What is a REPL?
    https://codewith.mu/en/tu­torials/1.0/repl
  77. Programming at the REPL: Introduction
    https://clojure.org/guides/re­pl/introduction
  78. What is REPL? (Quora)
    https://www.quora.com/What-is-REPL
  79. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  80. Read-eval-print loop (Wikipedia)
    https://en.wikipedia.org/wi­ki/Read%E2%80%93eval%E2%80%93prin­t_loop
  81. Vim as a Go (Golang) IDE using LSP and vim-go
    https://octetz.com/posts/vim-as-go-ide
  82. gopls
    https://github.com/golang/go/wi­ki/gopls
  83. IDE Integration Guide
    https://github.com/stamble­rre/gocode/blob/master/doc­s/IDE_integration.md
  84. How to instrument Go code with custom expvar metrics
    https://sysdig.com/blog/golang-expvar-custom-metrics/
  85. Golang expvar metricset (Metricbeat Reference)
    https://www.elastic.co/gu­ide/en/beats/metricbeat/7­.x/metricbeat-metricset-golang-expvar.html
  86. Package expvar
    https://golang.org/pkg/expvar/#NewInt
  87. Java Platform Debugger Architecture: Overview
    https://docs.oracle.com/en/ja­va/javase/11/docs/specs/jpda/jpda­.html
  88. The JVM Tool Interface (JVM TI): How VM Agents Work
    https://www.oracle.com/technet­work/articles/javase/index-140680.html
  89. JVM Tool Interface Version 11.0
    https://docs.oracle.com/en/ja­va/javase/11/docs/specs/jvmti­.html
  90. Creating a Debugging and Profiling Agent with JVMTI
    http://www.oracle.com/technet­work/articles/javase/jvmti-136367.html
  91. JVM TI (Wikipedia)
    http://en.wikipedia.org/wiki/JVM_TI
  92. IBM JVMTI extensions
    http://publib.boulder.ibm­.com/infocenter/realtime/v2r0/in­dex.jsp?topic=%2Fcom.ibm.sof­trt.doc%2Fdiag%2Ftools%2Fjvmti_ex­tensions.html
  93. Go & cgo: integrating existing C code with Go
    http://akrennmair.github.io/golang-cgo-slides/#1
  94. Using cgo to call C code from within Go code
    https://wenzr.wordpress.com/2018/06/07/u­sing-cgo-to-call-c-code-from-within-go-code/
  95. Package trace
    https://golang.org/pkg/runtime/trace/
  96. Introducing HTTP Tracing
    https://blog.golang.org/http-tracing
  97. Command trace
    https://golang.org/cmd/trace/
  98. A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
    https://github.com/wesovilabs/koazee
  99. Funkce vyššího řádu v knihovně Underscore
    https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/
  100. Delve: a debugger for the Go programming language.
    https://github.com/go-delve/delve
  101. Příkazy debuggeru Delve
    https://github.com/go-delve/delve/tree/master/Do­cumentation/cli
  102. Debuggery a jejich nadstavby v Linuxu
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/
  103. Debuggery a jejich nadstavby v Linuxu (2. část)
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/
  104. Debuggery a jejich nadstavby v Linuxu (3): Nemiver
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/
  105. Debuggery a jejich nadstavby v Linuxu (4): KDbg
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/
  106. 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/
  107. Debugging Go Code with GDB
    https://golang.org/doc/gdb
  108. Debugging Go (golang) programs with gdb
    https://thornydev.blogspot­.com/2014/01/debugging-go-golang-programs-with-gdb.html
  109. GDB – Dokumentace
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/
  110. GDB – Supported Languages
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/Suppor­ted-Languages.html#Supported-Languages
  111. GNU Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Debugger
  112. The LLDB Debugger
    http://lldb.llvm.org/
  113. Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/Debugger
  114. 13 Linux Debuggers for C++ Reviewed
    http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817
  115. 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
  116. Go Proverbs: Simple, Poetic, Pithy
    https://go-proverbs.github.io/
  117. Handling Sparse Files on Linux
    https://www.systutorials.com/136652/han­dling-sparse-files-on-linux/
  118. Gzip (Wikipedia)
    https://en.wikipedia.org/wiki/Gzip
  119. Deflate
    https://en.wikipedia.org/wiki/DEFLATE
  120. 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/
  121. Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
    https://www.root.cz/clanky/he­xadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/
  122. Hex dump
    https://en.wikipedia.org/wi­ki/Hex_dump
  123. Rozhraní io.ByteReader
    https://golang.org/pkg/io/#ByteReader
  124. Rozhraní io.RuneReader
    https://golang.org/pkg/io/#RuneReader
  125. Rozhraní io.ByteScanner
    https://golang.org/pkg/io/#By­teScanner
  126. Rozhraní io.RuneScanner
    https://golang.org/pkg/io/#Ru­neScanner
  127. Rozhraní io.Closer
    https://golang.org/pkg/io/#Closer
  128. Rozhraní io.Reader
    https://golang.org/pkg/io/#Reader
  129. Rozhraní io.Writer
    https://golang.org/pkg/io/#Writer
  130. Typ Strings.Reader
    https://golang.org/pkg/strin­gs/#Reader
  131. VACUUM (SQL)
    https://www.sqlite.org/lan­g_vacuum.html
  132. VACUUM (Postgres)
    https://www.postgresql.or­g/docs/8.4/sql-vacuum.html
  133. go-cron
    https://github.com/rk/go-cron
  134. gocron
    https://github.com/jasonlvhit/gocron
  135. clockwork
    https://github.com/whiteShtef/cloc­kwork
  136. clockwerk
    https://github.com/onatm/clockwerk
  137. JobRunner
    https://github.com/bamzi/jobrunner
  138. Rethinking Cron
    https://adam.herokuapp.com/pas­t/2010/4/13/rethinking_cron/
  139. In the Beginning was the Command Line
    https://web.archive.org/web/20180218045352/htt­p://www.cryptonomicon.com/be­ginning.html
  140. repl.it (REPL pro různé jazyky)
    https://repl.it/languages
  141. GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
    https://github.com/jroimartin/gocui
  142. Read–eval–print loop
    https://en.wikipedia.org/wi­ki/Read%E2%80%93eval%E2%80%93prin­t_loop
  143. go-prompt
    https://github.com/c-bata/go-prompt
  144. readline
    https://github.com/chzyer/readline
  145. A pure golang implementation for GNU-Readline kind library
    https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/
  146. go-readline
    https://github.com/fiorix/go-readline
  147. 4 Python libraries for building great command-line user interfaces
    https://opensource.com/article/17/5/4-practical-python-libraries
  148. prompt_toolkit 2.0.3 na PyPi
    https://pypi.org/project/prom­pt_toolkit/
  149. python-prompt-toolkit na GitHubu
    https://github.com/jonathan­slenders/python-prompt-toolkit
  150. The GNU Readline Library
    https://tiswww.case.edu/php/chet/re­adline/rltop.html
  151. GNU Readline (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Readline
  152. readline — GNU readline interface (Python 3.x)
    https://docs.python.org/3/li­brary/readline.html
  153. readline — GNU readline interface (Python 2.x)
    https://docs.python.org/2/li­brary/readline.html
  154. GNU Readline Library – command line editing
    https://tiswww.cwru.edu/php/chet/re­adline/readline.html
  155. gnureadline 6.3.8 na PyPi
    https://pypi.org/project/gnureadline/
  156. Editline Library (libedit)
    http://thrysoee.dk/editline/
  157. Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
    https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/
  158. libedit or editline
    http://www.cs.utah.edu/~bi­gler/code/libedit.html
  159. WinEditLine
    http://mingweditline.sourceforge.net/
  160. rlcompleter — Completion function for GNU readline
    https://docs.python.org/3/li­brary/rlcompleter.html
  161. rlwrap na GitHubu
    https://github.com/hanslub42/rlwrap
  162. rlwrap(1) – Linux man page
    https://linux.die.net/man/1/rlwrap
  163. readline(3) – Linux man page
    https://linux.die.net/man/3/readline
  164. history(3) – Linux man page
    https://linux.die.net/man/3/history
  165. Dokumentace k balíčku oglematchers
    https://godoc.org/github.com/ja­cobsa/oglematchers
  166. Balíček oglematchers
    https://github.com/jacobsa/o­glematchers
  167. Dokumentace k balíčku ogletest
    https://godoc.org/github.com/ja­cobsa/ogletest
  168. Balíček ogletest
    https://github.com/jacobsa/ogletest
  169. Dokumentace k balíčku assert
    https://godoc.org/github.com/stret­chr/testify/assert
  170. Testify – Thou Shalt Write Tests
    https://github.com/stretchr/testify/
  171. package testing
    https://golang.org/pkg/testing/
  172. Golang basics – writing unit tests
    https://blog.alexellis.io/golang-writing-unit-tests/
  173. An Introduction to Programming in Go / Testing
    https://www.golang-book.com/books/intro/12
  174. An Introduction to Testing in Go
    https://tutorialedge.net/golang/intro-testing-in-go/
  175. Advanced Go Testing Tutorial
    https://tutorialedge.net/go­lang/advanced-go-testing-tutorial/
  176. GoConvey
    http://goconvey.co/
  177. Testing Techniques
    https://talks.golang.org/2014/tes­ting.slide
  178. 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
  179. Afinní transformace
    https://cs.wikibooks.org/wi­ki/Geometrie/Afinn%C3%AD_tran­sformace_sou%C5%99adnic
  180. package gg
    https://godoc.org/github.com/fo­gleman/gg
  181. Generate an animated GIF with Golang
    http://tech.nitoyon.com/en/blog/2016/01/07/­go-animated-gif-gen/
  182. Generate an image programmatically with Golang
    http://tech.nitoyon.com/en/blog/2015/12/31/­go-image-gen/
  183. The Go image package
    https://blog.golang.org/go-image-package
  184. Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
    https://github.com/llgcode/draw2d
  185. Draw a rectangle in Golang?
    https://stackoverflow.com/qu­estions/28992396/draw-a-rectangle-in-golang
  186. YAML
    https://yaml.org/
  187. edn
    https://github.com/edn-format/edn
  188. Smile
    https://github.com/FasterXML/smile-format-specification
  189. Protocol-Buffers
    https://developers.google.com/protocol-buffers/
  190. Marshalling (computer science)
    https://en.wikipedia.org/wi­ki/Marshalling_(computer_sci­ence)
  191. Unmarshalling
    https://en.wikipedia.org/wi­ki/Unmarshalling
  192. Introducing JSON
    http://json.org/
  193. Package json
    https://golang.org/pkg/encoding/json/
  194. The Go Blog: JSON and Go
    https://blog.golang.org/json-and-go
  195. Go by Example: JSON
    https://gobyexample.com/json
  196. Writing Web Applications
    https://golang.org/doc/articles/wiki/
  197. Golang Web Apps
    https://www.reinbach.com/blog/golang-webapps-1/
  198. Build web application with Golang
    https://legacy.gitbook.com/bo­ok/astaxie/build-web-application-with-golang/details
  199. Golang Templates – Golang Web Pages
    https://www.youtube.com/wat­ch?v=TkNIETmF-RU
  200. Simple Golang HTTPS/TLS Examples
    https://github.com/denji/golang-tls
  201. Playing with images in HTTP response in golang
    https://www.sanarias.com/blog/1214Pla­yingwithimagesinHTTPrespon­seingolang
  202. MIME Types List
    https://www.freeformatter.com/mime-types-list.html
  203. Go Mutex Tutorial
    https://tutorialedge.net/golang/go-mutex-tutorial/
  204. Creating A Simple Web Server With Golang
    https://tutorialedge.net/go­lang/creating-simple-web-server-with-golang/
  205. Building a Web Server in Go
    https://thenewstack.io/building-a-web-server-in-go/
  206. How big is the pipe buffer?
    https://unix.stackexchange­.com/questions/11946/how-big-is-the-pipe-buffer
  207. How to turn off buffering of stdout in C
    https://stackoverflow.com/qu­estions/7876660/how-to-turn-off-buffering-of-stdout-in-c
  208. setbuf(3) – Linux man page
    https://linux.die.net/man/3/setbuf
  209. setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
    https://linux.die.net/man/3/setvbuf
  210. Select waits on a group of channels
    https://yourbasic.org/golang/select-explained/
  211. Rob Pike: Simplicity is Complicated (video)
    http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893
  212. Algorithms to Go
    https://yourbasic.org/
  213. Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
    https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/
  214. 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/
  215. Go Defer Simplified with Practical Visuals
    https://blog.learngoprogram­ming.com/golang-defer-simplified-77d3b2b817ff
  216. 5 More Gotchas of Defer in Go — Part II
    https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa
  217. The Go Blog: Defer, Panic, and Recover
    https://blog.golang.org/defer-panic-and-recover
  218. The defer keyword in Swift 2: try/finally done right
    https://www.hackingwithswift.com/new-syntax-swift-2-defer
  219. Swift Defer Statement
    https://andybargh.com/swift-defer-statement/
  220. Modulo operation (Wikipedia)
    https://en.wikipedia.org/wi­ki/Modulo_operation
  221. Node.js vs Golang: Battle of the Next-Gen Languages
    https://www.hostingadvice­.com/blog/nodejs-vs-golang/
  222. The Go Programming Language (home page)
    https://golang.org/
  223. GoDoc
    https://godoc.org/
  224. Go (programming language), Wikipedia
    https://en.wikipedia.org/wi­ki/Go_(programming_langua­ge)
  225. Go Books (kniha o jazyku Go)
    https://github.com/dariubs/GoBooks
  226. The Go Programming Language Specification
    https://golang.org/ref/spec
  227. Go: the Good, the Bad and the Ugly
    https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/
  228. Package builtin
    https://golang.org/pkg/builtin/
  229. Package fmt
    https://golang.org/pkg/fmt/
  230. The Little Go Book (další kniha)
    https://github.com/dariubs/GoBooks
  231. The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
    https://www.safaribookson­line.com/library/view/the-go-programming/9780134190570/e­book_split010.html
  232. Learning Go
    https://www.miek.nl/go/
  233. Go Bootcamp
    http://www.golangbootcamp.com/
  234. Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
    http://www.informit.com/sto­re/programming-in-go-creating-applications-for-the-21st-9780321774637
  235. Introducing Go (Build Reliable, Scalable Programs)
    http://shop.oreilly.com/pro­duct/0636920046516.do
  236. Learning Go Programming
    https://www.packtpub.com/application-development/learning-go-programming
  237. The Go Blog
    https://blog.golang.org/
  238. Getting to Go: The Journey of Go's Garbage Collector
    https://blog.golang.org/ismmkeynote
  239. Go (programovací jazyk, Wikipedia)
    https://cs.wikipedia.org/wi­ki/Go_(programovac%C3%AD_ja­zyk)
  240. Rychle, rychleji až úplně nejrychleji s jazykem Go
    https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/
  241. Installing Go on the Raspberry Pi
    https://dave.cheney.net/2012/09/25/in­stalling-go-on-the-raspberry-pi
  242. 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
  243. Niečo málo o Go – Golang (slovensky)
    http://golangsk.logdown.com/
  244. How Many Go Developers Are There?
    https://research.swtch.com/gop­hercount
  245. Most Popular Technologies (Stack Overflow Survery 2018)
    https://insights.stackover­flow.com/survey/2018/#most-popular-technologies
  246. Most Popular Technologies (Stack Overflow Survery 2017)
    https://insights.stackover­flow.com/survey/2017#techno­logy
  247. JavaScript vs. Golang for IoT: Is Gopher Winning?
    https://www.iotforall.com/javascript-vs-golang-iot/
  248. The Go Programming Language: Release History
    https://golang.org/doc/de­vel/release.html
  249. Go 1.11 Release Notes
    https://golang.org/doc/go1.11
  250. Go 1.10 Release Notes
    https://golang.org/doc/go1.10
  251. Go 1.9 Release Notes (tato verze je stále používána)
    https://golang.org/doc/go1.9
  252. Go 1.8 Release Notes (i tato verze je stále používána)
    https://golang.org/doc/go1.8
  253. Go on Fedora
    https://developer.fedorapro­ject.org/tech/languages/go/go-installation.html
  254. Writing Go programs
    https://developer.fedorapro­ject.org/tech/languages/go/go-programs.html
  255. The GOPATH environment variable
    https://tip.golang.org/doc/co­de.html#GOPATH
  256. Command gofmt
    https://tip.golang.org/cmd/gofmt/
  257. The Go Blog: go fmt your code
    https://blog.golang.org/go-fmt-your-code
  258. C? Go? Cgo!
    https://blog.golang.org/c-go-cgo
  259. 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/
  260. 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
  261. Gofmt No Longer Allows Spaces. Tabs Only
    https://news.ycombinator.com/i­tem?id=7914523
  262. Why does Go „go fmt“ uses tabs instead of whitespaces?
    https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces
  263. Interactive: The Top Programming Languages 2018
    https://spectrum.ieee.org/sta­tic/interactive-the-top-programming-languages-2018
  264. Go vs. Python
    https://www.peterbe.com/plog/govspy
  265. PackageManagementTools
    https://github.com/golang/go/wi­ki/PackageManagementTools
  266. A Tour of Go: Type inference
    https://tour.golang.org/basics/14
  267. Go Slices: usage and internals
    https://blog.golang.org/go-slices-usage-and-internals
  268. Go by Example: Slices
    https://gobyexample.com/slices
  269. What is the point of slice type in Go?
    https://stackoverflow.com/qu­estions/2098874/what-is-the-point-of-slice-type-in-go
  270. The curious case of Golang array and slices
    https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335
  271. Introduction to Slices in Golang
    https://www.callicoder.com/golang-slices/
  272. Golang: Understanding ‚null‘ and nil
    https://newfivefour.com/golang-null-nil.html
  273. What does nil mean in golang?
    https://stackoverflow.com/qu­estions/35983118/what-does-nil-mean-in-golang
  274. nils In Go
    https://go101.org/article/nil.html
  275. Go slices are not dynamic arrays
    https://appliedgo.net/slices/
  276. Go-is-no-good (nelze brát doslova)
    https://github.com/ksimka/go-is-not-good
  277. Rust vs. Go
    https://news.ycombinator.com/i­tem?id=13430108
  278. Seriál Programovací jazyk Rust
    https://www.root.cz/seria­ly/programovaci-jazyk-rust/
  279. Modern garbage collection: A look at the Go GC strategy
    https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e
  280. Go GC: Prioritizing low latency and simplicity
    https://blog.golang.org/go15gc
  281. Is Golang a good language for embedded systems?
    https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems
  282. Running GoLang on an STM32 MCU. A quick tutorial.
    https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial
  283. Go, Robot, Go! Golang Powered Robotics
    https://gobot.io/
  284. Emgo: Bare metal Go (language for programming embedded systems)
    https://github.com/ziutek/emgo
  285. UTF-8 history
    https://www.cl.cam.ac.uk/~mgk25/uc­s/utf-8-history.txt
  286. Less is exponentially more
    https://commandcenter.blog­spot.com/2012/06/less-is-exponentially-more.html
  287. Should I Rust, or Should I Go
    https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9
  288. Setting up and using gccgo
    https://golang.org/doc/install/gccgo
  289. Elastic Tabstops
    http://nickgravgaard.com/elastic-tabstops/
  290. Strings, bytes, runes and characters in Go
    https://blog.golang.org/strings
  291. Datový typ
    https://cs.wikipedia.org/wi­ki/Datov%C3%BD_typ
  292. Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
    https://www.root.cz/clanky/pro­gramovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09
  293. 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
  294. Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
    https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05
  295. Printf Format Strings
    https://www.cprogramming.com/tu­torial/printf-format-strings.html
  296. Java: String.format
    https://docs.oracle.com/ja­vase/8/docs/api/java/lang/Strin­g.html#format-java.lang.String-java.lang.Object…-
  297. Java: format string syntax
    https://docs.oracle.com/ja­vase/8/docs/api/java/util/For­matter.html#syntax
  298. Selectors
    https://golang.org/ref/spec#Selectors
  299. Calling Go code from Python code
    http://savorywatt.com/2015/09/18/ca­lling-go-code-from-python-code/
  300. Go Data Structures: Interfaces
    https://research.swtch.com/interfaces
  301. How to use interfaces in Go
    http://jordanorelli.com/pos­t/32665860244/how-to-use-interfaces-in-go
  302. Interfaces in Go (part I)
    https://medium.com/golangspec/in­terfaces-in-go-part-i-4ae53a97479c
  303. Part 21: Goroutines
    https://golangbot.com/goroutines/
  304. Part 22: Channels
    https://golangbot.com/channels/
  305. [Go] Lightweight eventbus with async compatibility for Go
    https://github.com/asaske­vich/EventBus
  306. What about Trait support in Golang?
    https://www.reddit.com/r/go­lang/comments/8mfykl/what_a­bout_trait_support_in_golan­g/
  307. 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/
  308. Control Flow
    https://en.wikipedia.org/wi­ki/Control_flow
  309. Structured programming
    https://en.wikipedia.org/wi­ki/Structured_programming
  310. Control Structures
    https://www.golang-book.com/books/intro/5
  311. Control structures – Go if else statement
    http://golangtutorials.blog­spot.com/2011/06/control-structures-if-else-statement.html
  312. Control structures – Go switch case statement
    http://golangtutorials.blog­spot.com/2011/06/control-structures-go-switch-case.html
  313. Control structures – Go for loop, break, continue, range
    http://golangtutorials.blog­spot.com/2011/06/control-structures-go-for-loop-break.html
  314. Goroutine IDs
    https://blog.sgmansfield.com/2015/12/go­routine-ids/
  315. Different ways to pass channels as arguments in function in go (golang)
    https://stackoverflow.com/qu­estions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang
  316. justforfunc #22: using the Go execution tracer
    https://www.youtube.com/wat­ch?v=ySy3sR1LFCQ
  317. Single Function Exit Point
    http://wiki.c2.com/?Single­FunctionExitPoint
  318. Entry point
    https://en.wikipedia.org/wi­ki/Entry_point
  319. Why does Go have a GOTO statement?!
    https://www.reddit.com/r/go­lang/comments/kag5q/why_do­es_go_have_a_goto_statemen­t/
  320. Effective Go
    https://golang.org/doc/ef­fective_go.html
  321. GoClipse: an Eclipse IDE for the Go programming language
    http://goclipse.github.io/
  322. GoClipse Installation
    https://github.com/GoClip­se/goclipse/blob/latest/do­cumentation/Installation.md#in­stallation
  323. The zero value of a slice is not nil
    https://stackoverflow.com/qu­estions/30806931/the-zero-value-of-a-slice-is-not-nil
  324. Go-tcha: When nil != nil
    https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic
  325. Nils in Go
    https://www.doxsey.net/blog/nils-in-go