Hlavní navigace

Jazyk Go a textový terminál ve funkci základního prvku uživatelského rozhraní (2.část)

22. 7. 2021
Doba čtení: 26 minut

Sdílet

 Autor: Go lang
Tvorbou aplikací pro běh v terminálu se budeme zabývat i dnes. Nejprve se zmíníme o knihovně cfmt, která rozšiřuje možnosti standardní knihovny fmt a ve druhé půlce článku si ukážeme vykreslování grafů do terminálu knihovnou asciigraph.

Obsah

1. Jazyk Go a textový terminál ve funkci základního prvku uživatelského rozhraní (2.část)

2. Od knihovny aurora ke knihovně cfmt

3. Funkce nabízené knihovnou cfmt

4. Konce řádků ve vypisovaných zprávách

5. Kombinace funkcí z knihoven fmt a cfmt

6. Vytvoření řetězce se zprávou a současně i řídicími kódy pro změnu barvy

7. Naformátování zprávy společně s jejím obarvením

8. Výstup do souboru

9. Knihovna asciigraph aneb jednoduché grafy vykreslené do textového terminálu

10. Vykreslení jednoduchého grafu z předpočítaných hodnot

11. Vykreslení průběhu funkce

12. Automatické odvození hodnot na x-ové ose

13. Automatické odvození hodnot na y-ové ose

14. Změna sklonu průběhu v nakresleném grafu

15. Záporné hodnoty v grafu

16. Nastavení dalších parametrů grafu

17. Hodnoty NaN a jejich vliv na vykreslení grafu

18. Nekonečna a jejich vliv na vykreslení grafu

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Jazyk Go a textový terminál ve funkci základního prvku uživatelského rozhraní (2.část)

V dnešním článku se, podobně jako v článku předchozím, postupně zaměříme na popis knihoven určených pro práci s textovým terminálem z programovacího jazyka Go. Tyto knihovny se od sebe budou odlišovat svým zaměřením a můžeme je zhruba rozdělit do pěti kategorií:

  1. Knihovny zlepšující logování a podporující barevné zvýraznění logovacích zpráv na terminálu. Sem spadá například balíček zerolog popsaný minule.
  2. Knihovny určené pro podporu různých barev popředí a pozadí textu, změnu stylu textu atd. Příkladem může být balíček aurora zmíněný minule, popř. cfmt popsaný dnes, knihovna nazvaná go-colortext apod.
  3. Knihovny pro zobrazení jednoduchých textových dialogů a boxů se zprávami. Tuto problematiku řeší balíček box-cli-maker.
  4. Knihovny pro tvorbu grafů, „teploměrů“ atd. na ploše terminálu. Příkladem je balíček asciigraph. I tímto balíčkem se budeme zabývat v dnešním článku.
  5. Knihovny určené pro tvorbu plnohodnotných textových uživatelských rozhraní (TUI). Příkladem mohou být balíčky termui, termbox-go, progressbar atd.
Poznámka: dnes použité demonstrační příklady byly opět spuštěny v xtermu s nastavením světlého pozadí. Použité barvy se (podle očekávání) budou lišit ve chvíli, kdy bude použito tmavé pozadí, popřípadě odlišný emulátor terminálu – to je cena, kterou je nutné zaplatit (mj.) i za zpětnou kompatibilitu.

Obrázek 1: Zobrazení logovacích informací s různou úrovní provedené přes knihovnu zerolog.

2. Od knihovny aurora ke knihovně cfmt

Ve druhé polovině předchozího článku jsme si ukázali základní možnosti použití knihovny nazvané aurora (což je pro knihovnu obarvující výstup na terminálu příhodné jméno). Tato knihovna umožňuje explicitní specifikaci barev textu, popř. jeho stylu. Pro tyto účely se používá objekt získaný konstruktorem aurora.NewAurora:

package main
 
import (
        "flag"
        "fmt"
 
        "github.com/logrusorgru/aurora"
)
 
var colorizer aurora.Aurora
 
func init() {
        var colors = flag.Bool("colors", false, "enable or disable colors")
        flag.Parse()
 
        colorizer = aurora.NewAurora(*colors)
}
 
func main() {
        fmt.Println(colorizer.Red("Test"))
        fmt.Println(colorizer.Green("Test"))
        fmt.Println(colorizer.Blue("Test"))
        fmt.Println(colorizer.Cyan("Test"))
        fmt.Println(colorizer.Magenta("Test"))
        fmt.Println(colorizer.Yellow("Test"))
 
        fmt.Println()
 
        fmt.Println(colorizer.Bold(colorizer.Red("Test")))
        fmt.Println(colorizer.Bold(colorizer.Green("Test")))
        fmt.Println(colorizer.Bold(colorizer.Blue("Test")))
        fmt.Println(colorizer.Bold(colorizer.Cyan("Test")))
        fmt.Println(colorizer.Bold(colorizer.Magenta("Test")))
        fmt.Println(colorizer.Bold(colorizer.Yellow("Test")))
}

S výsledkem:

Obrázek 2: Knihovna aurora: kombinace tučného písma se specifikací barvy.

Možnosti poskytované touto knihovnou jsou sice široké, ale vyžadují relativně velké zásahy do zdrojového kódu; navíc je obarvení prováděno na poměrně nízké úrovni („toto má být červeně“, „tento text se zeleným pozadím“). Z důvodu zjednodušení a určité standardizace proto nad samotnou aurorou vznikla knihovna nazvaná cfmt, která obsahuje několik funkcí, jejichž názvy jsou sémantické – říkají tedy, jakého typu je určitá zpráva a nikoli, jak přesně má být obarvena. Tento přístup a ostatně i jména funkcí, jsou převzaty z Bootstrapu. Podívejme se nyní na jednoduchý příklad použití knihovny cfmt:

package main
 
import (
        "github.com/mingrammer/cfmt"
)
 
func main() {
        cfmt.Success("Success message")
        cfmt.Info("Info message")
        cfmt.Warning("Warning message")
        cfmt.Error("Error message")
}

S tímto výsledkem:

Obrázek 3: Výsledek zavolání čtyř základních funkcí z knihovny cfmt.

Poznámka: povšimněte si, že se nevytváří žádný pomocný objekt, tj. použití cfmt je stejně „složité“ jako použití základní knihovny fmt.

3. Funkce nabízené knihovnou cfmt

Funkce, které jsou nabízeny knihovnou cfmt, můžeme rozdělit podle toho, jaké zprávy zobrazují (úspěšná operace, informace, varování, chyby) a jak je zobrazují – s nebo bez konců řádku, s formátováním, s výstupem do řetězce, souboru atd.:

Typ funkce Úspěšná operace Informace Varování Chyba
tisk obarvené zprávy Success Info Warning Error
přidání konce řádku Successln Infoln Warningln Errorln
výstup do řetězce Ssuccess Sinfo Swarning Serror
výstup do řetězce + konec řádku Ssuccessln Sinfoln Swarningln Serrorln
naformátování zprávy Successf Infof Warningf Errorf
výstup do souboru Fsuccess Finfo Fwarning Ferror
výstup do souboru + konec řádku Fsuccessln Finfoln Fwarningln Ferrorln
výstup do souboru s naformátováním Fsuccessf Finfof Fwarningf Ferrorf

Znak „S“ na začátku názvu tedy značí výstup do řetězce zatímco „F“ výstup do souboru. Naproti tomu koncovka „ln“ označuje funkce, které provádí odřádkování a „f“ funkce umožňující naformátování zprávy.

4. Konce řádků ve vypisovaných zprávách

Výše zmíněné funkce Success, Info, Warning a Error z knihovny cfmt odpovídají svým chováním funkci Print ze standardního balíčku fmt, pochopitelně až na ten rozdíl, že text obarvují. Pokud tedy budeme potřebovat jednotlivé zprávy vypsat na nové řádky, je jedním z možných řešení explicitní zařazení znaku „\n“ do vypisovaných zpráv (v případě logování přes zerolog je to pochopitelně zbytečné):

package main
 
import (
        "github.com/mingrammer/cfmt"
)
 
func main() {
        cfmt.Success("Success message\n")
        cfmt.Info("Info message\n")
        cfmt.Warning("Warning message\n")
        cfmt.Error("Error message\n")
}

S výsledkem:

Obrázek 4: Explicitní zařazení znaku „\n“ do vypisovaných zpráv.

Ve standardní knihovně fmt je vedle funkce Print dostupná i funkce Println, která odřádkování provede automaticky. I pro tuto funkci existují v knihovně cfmt obdobné funkce končící na „ln“, které jsou ukázány v dalším demonstračním příkladu:

package main
 
import (
        "github.com/mingrammer/cfmt"
)
 
func main() {
        cfmt.Successln("Success message")
        cfmt.Infoln("Info message")
        cfmt.Warningln("Warning message")
        cfmt.Errorln("Error message")
}

S výsledkem:

Obrázek 5: Příklad použití funkcí *ln, které automaticky odřádkují.

5. Kombinace funkcí z knihoven fmt a cfmt

Jednou z předností knihovny cfmt je záruka, že volání jejích funkcí je možné bez problémů proložit s voláním funkcí ze standardní knihovny fmt. To ve skutečnosti pro jiné knihovny nemusí platit, a to například kvůli odlišnému řešení bufferů, specifikám různých operačních systémů atd. Následující příklad, který kombinuje volání funkcí z obou výše zmíněných knihoven, je tedy nejenom plně funkční, ale i přenositelný na různé operační systémy a platformy:

package main
 
import (
        "fmt"
 
        "github.com/mingrammer/cfmt"
)
 
func main() {
        fmt.Print("1st line: ")
        cfmt.Successln("Success message")
 
        fmt.Print("2nd line: ")
        cfmt.Infoln("Info message")
 
        fmt.Print("3rd line: ")
        cfmt.Warningln("Warning message")
 
        fmt.Print("4th line: ")
        cfmt.Errorln("Error message")
 
        fmt.Println()
        fmt.Println("That's all...")
}

Nyní by měl výsledek vypadat takto:

Obrázek 6: Prokládané volání funkcí z knihoven fmt a cfmt.

6. Vytvoření řetězce se zprávou a současně i řídicími kódy pro změnu barvy

Další čtyři funkce z knihovny cfmt začínají znakem „s“, takže připomínají funkci Sprint ze standardní knihovny fmt. Podobnost názvů v tomto případě pochopitelně není náhodná, protože funkce Ssuccessln, Sinfo, Swarningln a Serror skutečně převedou zprávu i s příslušnými řídicími kódy do řetězce, který lze následně použít libovolnou další funkcí jazyka Go (resp. pochopitelně funkcí, která na svém vstupu řetězec očekává):

package main
 
import (
        "fmt"
 
        "github.com/mingrammer/cfmt"
)
 
func main() {
        var msg string
 
        msg = cfmt.Ssuccess("Success message")
        fmt.Printf("1st line: %s\n", msg)
 
        msg = cfmt.Sinfo("Info message")
        fmt.Printf("2nd line: %s\n", msg)
 
        msg = cfmt.Swarning("Warning message")
        fmt.Printf("3rd line: %s\n", msg)
 
        msg = cfmt.Serror("Error message")
        fmt.Printf("4th line: %s\n", msg)
 
        fmt.Println()
        fmt.Println("That's all...")
}

Výsledek běhu tohoto příkladu může vypadat následovně:

Obrázek 7: Výpis řetězců získaných funkcemi Ssuccess, Sinfo, Swarning a Serror.

Podle očekávání existují i varianty těchto funkcí končících na „ln“, které za zprávu automaticky přidají znak pro konec řádku:

package main
 
import (
        "fmt"
 
        "github.com/mingrammer/cfmt"
)
 
func main() {
        var msg string
 
        msg = cfmt.Ssuccessln("Success message")
        fmt.Printf("1st line: %s", msg)
 
        msg = cfmt.Sinfoln("Info message")
        fmt.Printf("2nd line: %s", msg)
 
        msg = cfmt.Swarningln("Warning message")
        fmt.Printf("3rd line: %s", msg)
 
        msg = cfmt.Serrorln("Error message")
        fmt.Printf("4th line: %s", msg)
 
        fmt.Println()
        fmt.Println("That's all...")
}

Výsledek běhu tohoto příkladu může vypadat následovně:

Obrázek 7: Výpis řetězců získaných funkcemi Ssuccessln, Sinfoln, Swarningln a Serrorln.

7. Naformátování zprávy společně s jejím obarvením

Čtveřice funkcí nazvaných Successf, Infof, Warningf a Errorf se chová podobně jako funkce Printf ze standardní knihovny fmt – funkce očekává, že prvním parametrem bude formátovací řetězec, na jehož základě se zkontrolují a zpracují případné další parametry. Výstup je následně obarven podle toho, která konkrétní funkce byla právě zavolána. Chování si můžeme odzkoušet na dalším demonstračním příkladu, který vyhodnotí, zda je vstupní číselná hodnota příliš malá, velká, nebo „právě akorát“:

package main
 
import (
        "fmt"
 
        "github.com/mingrammer/cfmt"
)
 
func main() {
        for i := 1; i <= 10; i++ {
                switch {
                case i < 5:
                        cfmt.Warningf("Value too low: %d\n", i)
                case i == 5:
                        cfmt.Successf("An ideal value: %d\n", i)
                case i == 10:
                        cfmt.Errorf("Too high!!! %d\n", i)
                case i > 5:
                        cfmt.Infof("Bit higher then necessary: %d\n", i)
                default:
                        cfmt.Errorf("Can't happen %d\n", i)
                }
        }
 
        fmt.Println()
        fmt.Println("That's all...")
}

Výsledek po spuštění příkladu:

Obrázek 8: Naformátované a obarvené zprávy.

Pro zajímavost se ještě můžeme podívat, jak vlastně vypadají řetězce produkované knihovnou cfmt, a to na úrovni jednotlivých bajtů. Pomůžeme si následujícím příkladem, který vypíše obsah jednotlivých řetězců převedených na pole bajtů s využitím standardní knihovny encoding/hex:

package main
 
import (
        "encoding/hex"
        "fmt"
 
        "github.com/mingrammer/cfmt"
)
 
func printEncoded(s string) {
        bytes := []byte(s)
        fmt.Printf("Encoded:\n%s\n", hex.Dump(bytes))
}
 
func main() {
        var msg string
 
        msg = cfmt.Ssuccessln("Success message")
        fmt.Printf("1st line: %s", msg)
        printEncoded(msg)
 
        msg = cfmt.Sinfoln("Info message")
        fmt.Printf("2nd line: %s", msg)
        printEncoded(msg)
 
        msg = cfmt.Swarningln("Warning message")
        fmt.Printf("3rd line: %s", msg)
        printEncoded(msg)
 
        msg = cfmt.Serrorln("Error message")
        fmt.Printf("4th line: %s", msg)
        printEncoded(msg)
 
        fmt.Println()
        fmt.Println("That's all...")
}

Výsledek po spuštění příkladu:

Obrázek 9: Naformátované a obarvené zprávy společně s jejich binárním obsahem vypsaným ve formě „hex dumpu“.

8. Výstup do souboru

Knihovna cfmt podporuje i výpis obarvených zpráv přímo do souboru. Pro tuto činnost se používají funkce začínající na „F“, přesněji řečeno v praxi především funkce Fsuccessln, Finfoln, Fwarningln a Ferrorln, popř. jejich varianty bez „ln“. Podívejme se na způsob použití těchto funkcí:

package main
 
import (
        "log"
        "os"
 
        "github.com/mingrammer/cfmt"
)
 
func main() {
        file, err := os.Create("./temp.txt")
        if err != nil {
                log.Fatal(err)
        }
 
        defer file.Close()
 
        cfmt.Fsuccessln(file, "Success message")
        cfmt.Finfoln(file, "Info message")
        cfmt.Fwarningln(file, "Warning message")
        cfmt.Ferrorln(file, "Error message")
}

K dispozici jsou i funkce zajišťující výstup naformátované zprávy do souboru. Tyto funkce začínají znakem „F“ a končí znakem „f“. Příklad z předchozí kapitoly tedy můžeme snadno upravit:

package main
 
import (
        "fmt"
        "log"
        "os"
 
        "github.com/mingrammer/cfmt"
)
 
func main() {
        file, err := os.Create("./temp.txt")
        if err != nil {
                log.Fatal(err)
        }
 
        defer file.Close()
 
        for i := 1; i <= 10; i++ {
                switch {
                case i < 5:
                        cfmt.Fwarningf(file, "Value too low: %d\n", i)
                case i == 5:
                        cfmt.Fsuccessf(file, "An ideal value: %d\n", i)
                case i == 10:
                        cfmt.Ferrorf(file, "Too high!!! %d\n", i)
                case i > 5:
                        cfmt.Finfof(file, "Bit higher then necessary: %d\n", i)
                default:
                        cfmt.Ferrorf(file, "Can't happen %d\n", i)
                }
        }
 
        fmt.Println()
        fmt.Println("That's all...")
}
Poznámka: vytvořené soubory lze vypsat například nástrojem cat, a to včetně obarvení.

9. Knihovna asciigraph aneb jednoduché grafy vykreslené do textového terminálu

Druhá knihovna pro jazyk Go, se kterou se dnes seznámíme, se jmenuje asciigraph. Je to přiléhavé a současně i zavádějící jméno, protože tato knihovna sice umožňuje vykreslení grafů (průběhů funkcí či naměřených hodnot) na textovém terminálu, ovšem pro tento účel využívá znaky z Unicode a nikoli z jeho (maličké) podmnožiny ASCII. Praktické použití této knihovny je triviální, protože postačuje funkci nazvané Plot předat data, která se mají vykreslit (konkrétně se jedná o řez polem typu float64) a výsledkem je řetězec s požadovaným grafem. V případě potřeby je pochopitelně možné předat funkci Plot i další parametry grafu. Výsledný řetězec je možné zobrazit na terminálu, uložit do souboru, poslat přes HTTP uživateli atd.

10. Vykreslení jednoduchého grafu z předpočítaných hodnot

První demonstrační příklad založený na knihovně asciigraph je převzat přímo ze stránek tohoto projektu a byl pouze nepatrně upraven. Je v něm ukázáno, jak lze vykreslit graf hodnot typu float64, což je v jazyce Go obdoba céčkovského datového typu double. Pro samotné vykreslení stačí zavolat funkci Plot a výsledný řetězec vypsat standardní funkcí fmt.Println:

package main
 
import (
        "fmt"
        "github.com/guptarohit/asciigraph"
)
 
func main() {
        data := []float64{3, 4, 5, 6, 9, 8, 5, 8, 6, 10, 2, 7, 2, 5, 6}
        graph := asciigraph.Plot(data)
 
        fmt.Println(graph)
}

Výsledek vypadá následovně:

 10.00 ┤        ╭╮
  9.00 ┤   ╭╮   ││
  8.00 ┤   │╰╮╭╮││
  7.00 ┤   │ │││││╭╮
  6.00 ┤  ╭╯ ││╰╯│││ ╭
  5.00 ┤ ╭╯  ╰╯  │││╭╯
  4.00 ┤╭╯       ││││
  3.00 ┼╯        ││││
  2.00 ┤         ╰╯╰╯
Poznámka: povšimněte si, že na rozdíl od některých dalších knihoven není výstupem sloupcový graf (či jeho textová obdoba), ale spojitý graf, i když pochopitelně v mezích daných možnostmi textového terminálu a znaků z Unicode.

11. Vykreslení průběhu funkce

Pokusme se nyní o vykreslení průběhu funkce, přičemž jednotlivé hodnoty vypočteme v programové smyčce a uložíme do pole s prvky typu float64:

package main
 
import (
        "fmt"
 
        "github.com/guptarohit/asciigraph"
)
 
const SAMPLES = 40
 
func main() {
        var values [SAMPLES]float64
 
        for i := 0; i < SAMPLES; i++ {
                values[i] = float64(i % 10)
        }
        graph := asciigraph.Plot(values)
 
        fmt.Println(graph)
}

Zdrojový kód tohoto příkladu sice vypadá bezchybně, ale nepůjde přeložit. Je tomu tak z toho důvodu, že se do funkce Plot snažíme předat pole (array) prvků typu float64 a nikoli řez (slice)

./02-computed-values.go:17:26: cannot use values (type [40]float64) as type []float64 in argument to asciigraph.Plot

Řešením je (podle očekávání) získání řezu z pole, což je operace, která nevyžaduje kopii dat a je tedy velmi rychlá a paměťově efektivní:

package main
 
import (
        "fmt"
 
        "github.com/guptarohit/asciigraph"
)
 
const SAMPLES = 40
 
func main() {
        var values [SAMPLES]float64
 
        for i := 0; i < SAMPLES; i++ {
                values[i] = float64(i % 10)
        }
        graph := asciigraph.Plot(values[:])
 
        fmt.Println(graph)
}

Nyní již bude vše plně funkční:

 9.00 ┼        ╭╮        ╭╮        ╭╮        ╭
 8.00 ┤       ╭╯│       ╭╯│       ╭╯│       ╭╯
 7.00 ┤      ╭╯ │      ╭╯ │      ╭╯ │      ╭╯
 6.00 ┤     ╭╯  │     ╭╯  │     ╭╯  │     ╭╯
 5.00 ┤    ╭╯   │    ╭╯   │    ╭╯   │    ╭╯
 4.00 ┤   ╭╯    │   ╭╯    │   ╭╯    │   ╭╯
 3.00 ┤  ╭╯     │  ╭╯     │  ╭╯     │  ╭╯
 2.00 ┤ ╭╯      │ ╭╯      │ ╭╯      │ ╭╯
 1.00 ┤╭╯       │╭╯       │╭╯       │╭╯
 0.00 ┼╯        ╰╯        ╰╯        ╰╯

12. Automatické odvození hodnot na x-ové ose

V případě, že se při tvorbě grafu nespecifikují jeho parametry, je jeho šířka (měřená ve znacích) přímo odvozena od počtu hodnot, které jsou funkci Plot předány. Mnohdy to znamená, že graf je širší než okno terminálu a jeho řádky jsou zalomeny, což je pochopitelně situace, které je nutné se v praxi vyhnout:

package main
 
import (
        "fmt"
 
        "github.com/guptarohit/asciigraph"
)
 
const SAMPLES = 200
 
func main() {
        var values [SAMPLES]float64
 
        for i := 0; i < SAMPLES; i++ {
                values[i] = float64(i / 2 % 16)
        }
        graph := asciigraph.Plot(values[:])
 
        fmt.Println(graph)
}

Graf bude nyní na šířku měřit 207 znaků, což u většiny uživatelů přesáhne nastavenou (i maximální možnou) šířku okna terminálu:

 15.00 ┼                             ╭─╮                             ╭─╮                             ╭─╮                             ╭─╮                             ╭─╮                             ╭─╮
 14.00 ┤                           ╭─╯ │                           ╭─╯ │                           ╭─╯ │                           ╭─╯ │                           ╭─╯ │                           ╭─╯ │
 13.00 ┤                         ╭─╯   │                         ╭─╯   │                         ╭─╯   │                         ╭─╯   │                         ╭─╯   │                         ╭─╯   │
 12.00 ┤                       ╭─╯     │                       ╭─╯     │                       ╭─╯     │                       ╭─╯     │                       ╭─╯     │                       ╭─╯     │
 11.00 ┤                     ╭─╯       │                     ╭─╯       │                     ╭─╯       │                     ╭─╯       │                     ╭─╯       │                     ╭─╯       │
 10.00 ┤                   ╭─╯         │                   ╭─╯         │                   ╭─╯         │                   ╭─╯         │                   ╭─╯         │                   ╭─╯         │
  9.00 ┤                 ╭─╯           │                 ╭─╯           │                 ╭─╯           │                 ╭─╯           │                 ╭─╯           │                 ╭─╯           │
  8.00 ┤               ╭─╯             │               ╭─╯             │               ╭─╯             │               ╭─╯             │               ╭─╯             │               ╭─╯             │
  7.00 ┤             ╭─╯               │             ╭─╯               │             ╭─╯               │             ╭─╯               │             ╭─╯               │             ╭─╯               │
  6.00 ┤           ╭─╯                 │           ╭─╯                 │           ╭─╯                 │           ╭─╯                 │           ╭─╯                 │           ╭─╯                 │
  5.00 ┤         ╭─╯                   │         ╭─╯                   │         ╭─╯                   │         ╭─╯                   │         ╭─╯                   │         ╭─╯                   │
  4.00 ┤       ╭─╯                     │       ╭─╯                     │       ╭─╯                     │       ╭─╯                     │       ╭─╯                     │       ╭─╯                     │
  3.00 ┤     ╭─╯                       │     ╭─╯                       │     ╭─╯                       │     ╭─╯                       │     ╭─╯                       │     ╭─╯                       │     ╭─
  2.00 ┤   ╭─╯                         │   ╭─╯                         │   ╭─╯                         │   ╭─╯                         │   ╭─╯                         │   ╭─╯                         │   ╭─╯
  1.00 ┤ ╭─╯                           │ ╭─╯                           │ ╭─╯                           │ ╭─╯                           │ ╭─╯                           │ ╭─╯                           │ ╭─╯
  0.00 ┼─╯                             ╰─╯                             ╰─╯                             ╰─╯                             ╰─╯                             ╰─╯                             ╰─╯

13. Automatické odvození hodnot na y-ové ose

I rozsah hodnot na y-ové ose a tedy i výška grafu je při implicitním nastavení odvozena od vstupních hodnot předávaných do funkce Plot. Toto chování knihovny asciigraph si můžeme demonstrovat na příkladu, ve kterém se postupně zvětšuje rozsah hodnot (obor hodnot) vykreslované funkce. I příslušné grafy se budou postupně zvyšovat:

package main
 
import (
        "fmt"
 
        "github.com/guptarohit/asciigraph"
)
 
const SAMPLES = 64
 
func displayGraph(modulus int) {
        var values [SAMPLES]float64
 
        for i := 0; i < SAMPLES; i++ {
                values[i] = float64(i % modulus)
        }
        graph := asciigraph.Plot(values[:])
 
        fmt.Println(graph)
}
 
func main() {
        for modulus := 2; modulus <= 64; modulus *= 2 {
                displayGraph(modulus)
                fmt.Println("\n")
        }
}

Postupná změna výšky grafu je jasně patrná:

 1.00 ┼╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭╮╭
 0.00 ┼╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯╰╯
 
 
 3.00 ┼  ╭╮  ╭╮  ╭╮  ╭╮  ╭╮  ╭╮  ╭╮  ╭╮  ╭╮  ╭╮  ╭╮  ╭╮  ╭╮  ╭╮  ╭╮  ╭
 2.00 ┤ ╭╯│ ╭╯│ ╭╯│ ╭╯│ ╭╯│ ╭╯│ ╭╯│ ╭╯│ ╭╯│ ╭╯│ ╭╯│ ╭╯│ ╭╯│ ╭╯│ ╭╯│ ╭╯
 1.00 ┤╭╯ │╭╯ │╭╯ │╭╯ │╭╯ │╭╯ │╭╯ │╭╯ │╭╯ │╭╯ │╭╯ │╭╯ │╭╯ │╭╯ │╭╯ │╭╯
 0.00 ┼╯  ╰╯  ╰╯  ╰╯  ╰╯  ╰╯  ╰╯  ╰╯  ╰╯  ╰╯  ╰╯  ╰╯  ╰╯  ╰╯  ╰╯  ╰╯
 
 
 7.00 ┼      ╭╮      ╭╮      ╭╮      ╭╮      ╭╮      ╭╮      ╭╮      ╭
 6.00 ┤     ╭╯│     ╭╯│     ╭╯│     ╭╯│     ╭╯│     ╭╯│     ╭╯│     ╭╯
 5.00 ┤    ╭╯ │    ╭╯ │    ╭╯ │    ╭╯ │    ╭╯ │    ╭╯ │    ╭╯ │    ╭╯
 4.00 ┤   ╭╯  │   ╭╯  │   ╭╯  │   ╭╯  │   ╭╯  │   ╭╯  │   ╭╯  │   ╭╯
 3.00 ┤  ╭╯   │  ╭╯   │  ╭╯   │  ╭╯   │  ╭╯   │  ╭╯   │  ╭╯   │  ╭╯
 2.00 ┤ ╭╯    │ ╭╯    │ ╭╯    │ ╭╯    │ ╭╯    │ ╭╯    │ ╭╯    │ ╭╯
 1.00 ┤╭╯     │╭╯     │╭╯     │╭╯     │╭╯     │╭╯     │╭╯     │╭╯
 0.00 ┼╯      ╰╯      ╰╯      ╰╯      ╰╯      ╰╯      ╰╯      ╰╯
 
 
 15.00 ┼              ╭╮              ╭╮              ╭╮              ╭
 14.00 ┤             ╭╯│             ╭╯│             ╭╯│             ╭╯
 13.00 ┤            ╭╯ │            ╭╯ │            ╭╯ │            ╭╯
 12.00 ┤           ╭╯  │           ╭╯  │           ╭╯  │           ╭╯
 11.00 ┤          ╭╯   │          ╭╯   │          ╭╯   │          ╭╯
 10.00 ┤         ╭╯    │         ╭╯    │         ╭╯    │         ╭╯
  9.00 ┤        ╭╯     │        ╭╯     │        ╭╯     │        ╭╯
  8.00 ┤       ╭╯      │       ╭╯      │       ╭╯      │       ╭╯
  7.00 ┤      ╭╯       │      ╭╯       │      ╭╯       │      ╭╯
  6.00 ┤     ╭╯        │     ╭╯        │     ╭╯        │     ╭╯
  5.00 ┤    ╭╯         │    ╭╯         │    ╭╯         │    ╭╯
  4.00 ┤   ╭╯          │   ╭╯          │   ╭╯          │   ╭╯
  3.00 ┤  ╭╯           │  ╭╯           │  ╭╯           │  ╭╯
  2.00 ┤ ╭╯            │ ╭╯            │ ╭╯            │ ╭╯
  1.00 ┤╭╯             │╭╯             │╭╯             │╭╯
  0.00 ┼╯              ╰╯              ╰╯              ╰╯
 
 
 31.00 ┼                              ╭╮                              ╭
 30.00 ┤                             ╭╯│                             ╭╯
 29.00 ┤                            ╭╯ │                            ╭╯
 28.00 ┤                           ╭╯  │                           ╭╯
 27.00 ┤                          ╭╯   │                          ╭╯
 26.00 ┤                         ╭╯    │                         ╭╯
 25.00 ┤                        ╭╯     │                        ╭╯
 24.00 ┤                       ╭╯      │                       ╭╯
 23.00 ┤                      ╭╯       │                      ╭╯
 22.00 ┤                     ╭╯        │                     ╭╯
 21.00 ┤                    ╭╯         │                    ╭╯
 20.00 ┤                   ╭╯          │                   ╭╯
 19.00 ┤                  ╭╯           │                  ╭╯
 18.00 ┤                 ╭╯            │                 ╭╯
 17.00 ┤                ╭╯             │                ╭╯
 16.00 ┤               ╭╯              │               ╭╯
 15.00 ┤              ╭╯               │              ╭╯
 14.00 ┤             ╭╯                │             ╭╯
 13.00 ┤            ╭╯                 │            ╭╯
 12.00 ┤           ╭╯                  │           ╭╯
 11.00 ┤          ╭╯                   │          ╭╯
 10.00 ┤         ╭╯                    │         ╭╯
  9.00 ┤        ╭╯                     │        ╭╯
  8.00 ┤       ╭╯                      │       ╭╯
  7.00 ┤      ╭╯                       │      ╭╯
  6.00 ┤     ╭╯                        │     ╭╯
  5.00 ┤    ╭╯                         │    ╭╯
  4.00 ┤   ╭╯                          │   ╭╯
  3.00 ┤  ╭╯                           │  ╭╯
  2.00 ┤ ╭╯                            │ ╭╯
  1.00 ┤╭╯                             │╭╯
  0.00 ┼╯                              ╰╯

14. Změna sklonu průběhu v nakresleném grafu

Ještě si vyzkoušejme, jakým způsobem se knihovna asciigraph vyrovná se změnou sklonu nakresleného průběhu funkce. V případě grafického výstupu (ovšem s dostatečným rozlišením) to je pochopitelně snadná úloha, ovšem v textovém terminálu je situace složitější:

package main
 
import (
        "fmt"
 
        "github.com/guptarohit/asciigraph"
)
 
const SAMPLES = 64
 
func displayGraph(modulus int, slope int) {
        var values [SAMPLES]float64
 
        for i := 0; i < SAMPLES; i++ {
                values[i] = float64(i / slope % modulus)
        }
        graph := asciigraph.Plot(values[:])
 
        fmt.Println(graph)
}
 
func main() {
        const modulus = 16
        for slope := 1; slope <= 5; slope++ {
                displayGraph(modulus, slope)
                fmt.Println("\n")
        }
}

Z výsledků je zřetelné, že se stále používá stejná skupina Unicode znaků, nezávisle na tom, jaký je sklon:

 15.00 ┼              ╭╮              ╭╮              ╭╮              ╭
 14.00 ┤             ╭╯│             ╭╯│             ╭╯│             ╭╯
 13.00 ┤            ╭╯ │            ╭╯ │            ╭╯ │            ╭╯
 12.00 ┤           ╭╯  │           ╭╯  │           ╭╯  │           ╭╯
 11.00 ┤          ╭╯   │          ╭╯   │          ╭╯   │          ╭╯
 10.00 ┤         ╭╯    │         ╭╯    │         ╭╯    │         ╭╯
  9.00 ┤        ╭╯     │        ╭╯     │        ╭╯     │        ╭╯
  8.00 ┤       ╭╯      │       ╭╯      │       ╭╯      │       ╭╯
  7.00 ┤      ╭╯       │      ╭╯       │      ╭╯       │      ╭╯
  6.00 ┤     ╭╯        │     ╭╯        │     ╭╯        │     ╭╯
  5.00 ┤    ╭╯         │    ╭╯         │    ╭╯         │    ╭╯
  4.00 ┤   ╭╯          │   ╭╯          │   ╭╯          │   ╭╯
  3.00 ┤  ╭╯           │  ╭╯           │  ╭╯           │  ╭╯
  2.00 ┤ ╭╯            │ ╭╯            │ ╭╯            │ ╭╯
  1.00 ┤╭╯             │╭╯             │╭╯             │╭╯
  0.00 ┼╯              ╰╯              ╰╯              ╰╯
 
 
 15.00 ┼                             ╭─╮                             ╭─
 14.00 ┤                           ╭─╯ │                           ╭─╯
 13.00 ┤                         ╭─╯   │                         ╭─╯
 12.00 ┤                       ╭─╯     │                       ╭─╯
 11.00 ┤                     ╭─╯       │                     ╭─╯
 10.00 ┤                   ╭─╯         │                   ╭─╯
  9.00 ┤                 ╭─╯           │                 ╭─╯
  8.00 ┤               ╭─╯             │               ╭─╯
  7.00 ┤             ╭─╯               │             ╭─╯
  6.00 ┤           ╭─╯                 │           ╭─╯
  5.00 ┤         ╭─╯                   │         ╭─╯
  4.00 ┤       ╭─╯                     │       ╭─╯
  3.00 ┤     ╭─╯                       │     ╭─╯
  2.00 ┤   ╭─╯                         │   ╭─╯
  1.00 ┤ ╭─╯                           │ ╭─╯
  0.00 ┼─╯                             ╰─╯
 
 
 15.00 ┼                                            ╭──╮
 14.00 ┤                                         ╭──╯  │
 13.00 ┤                                      ╭──╯     │
 12.00 ┤                                   ╭──╯        │
 11.00 ┤                                ╭──╯           │
 10.00 ┤                             ╭──╯              │
  9.00 ┤                          ╭──╯                 │
  8.00 ┤                       ╭──╯                    │
  7.00 ┤                    ╭──╯                       │
  6.00 ┤                 ╭──╯                          │
  5.00 ┤              ╭──╯                             │              ╭
  4.00 ┤           ╭──╯                                │           ╭──╯
  3.00 ┤        ╭──╯                                   │        ╭──╯
  2.00 ┤     ╭──╯                                      │     ╭──╯
  1.00 ┤  ╭──╯                                         │  ╭──╯
  0.00 ┼──╯                                            ╰──╯
 
 
 15.00 ┼                                                           ╭───
 14.00 ┤                                                       ╭───╯
 13.00 ┤                                                   ╭───╯
 12.00 ┤                                               ╭───╯
 11.00 ┤                                           ╭───╯
 10.00 ┤                                       ╭───╯
  9.00 ┤                                   ╭───╯
  8.00 ┤                               ╭───╯
  7.00 ┤                           ╭───╯
  6.00 ┤                       ╭───╯
  5.00 ┤                   ╭───╯
  4.00 ┤               ╭───╯
  3.00 ┤           ╭───╯
  2.00 ┤       ╭───╯
  1.00 ┤   ╭───╯
  0.00 ┼───╯
 
 
 12.00 ┼                                                           ╭───
 11.00 ┤                                                      ╭────╯
 10.00 ┤                                                 ╭────╯
  9.00 ┤                                            ╭────╯
  8.00 ┤                                       ╭────╯
  7.00 ┤                                  ╭────╯
  6.00 ┤                             ╭────╯
  5.00 ┤                        ╭────╯
  4.00 ┤                   ╭────╯
  3.00 ┤              ╭────╯
  2.00 ┤         ╭────╯
  1.00 ┤    ╭────╯
  0.00 ┼────╯
Poznámka: průběh se sklonem větším než 45° není vykreslen, protože v takovém případě se změní měřítko na y-ové ose; pokud ovšem parametry explicitně nezměníme.

15. Záporné hodnoty v grafu

Prozatím jsme v grafu používali funkce (resp. jejich navzorkované hodnoty), které byly kladné. Ovšem knihovna asciigraph pochopitelně podporuje i záporné hodnoty, o čemž se můžeme velmi snadno přesvědčit po spuštění následujícího demonstračního příkladu:

package main
 
import (
        "fmt"
 
        "github.com/guptarohit/asciigraph"
)
 
const SAMPLES = 64
 
func displayGraph(modulus int, slope int) {
        var values [SAMPLES]float64
 
        for i := 0; i < SAMPLES; i++ {
                values[i] = float64((i - SAMPLES/2) / slope % modulus)
        }
        graph := asciigraph.Plot(values[:])
 
        fmt.Println(graph)
}
 
func main() {
        const modulus = 16
        for slope := 1; slope <= 5; slope++ {
                displayGraph(modulus, slope)
                fmt.Println("\n")
        }
}

S výsledky:

  15.00 ┤                                              ╭╮              ╭
  14.00 ┤                                             ╭╯│             ╭╯
  13.00 ┤                                            ╭╯ │            ╭╯
  12.00 ┤                                           ╭╯  │           ╭╯
  11.00 ┤                                          ╭╯   │          ╭╯
  10.00 ┤                                         ╭╯    │         ╭╯
   9.00 ┤                                        ╭╯     │        ╭╯
   8.00 ┤                                       ╭╯      │       ╭╯
   7.00 ┤                                      ╭╯       │      ╭╯
   6.00 ┤                                     ╭╯        │     ╭╯
   5.00 ┤                                    ╭╯         │    ╭╯
   4.00 ┤                                   ╭╯          │   ╭╯
   3.00 ┤                                  ╭╯           │  ╭╯
   2.00 ┤                                 ╭╯            │ ╭╯
   1.00 ┤                                ╭╯             │╭╯
   0.00 ┼╮              ╭╮              ╭╯              ╰╯
  -1.00 ┤│             ╭╯│             ╭╯
  -2.00 ┤│            ╭╯ │            ╭╯
  -3.00 ┤│           ╭╯  │           ╭╯
  -4.00 ┤│          ╭╯   │          ╭╯
  -5.00 ┤│         ╭╯    │         ╭╯
  -6.00 ┤│        ╭╯     │        ╭╯
  -7.00 ┤│       ╭╯      │       ╭╯
  -8.00 ┤│      ╭╯       │      ╭╯
  -9.00 ┤│     ╭╯        │     ╭╯
 -10.00 ┤│    ╭╯         │    ╭╯
 -11.00 ┤│   ╭╯          │   ╭╯
 -12.00 ┤│  ╭╯           │  ╭╯
 -13.00 ┤│ ╭╯            │ ╭╯
 -14.00 ┤│╭╯             │╭╯
 -15.00 ┤╰╯              ╰╯
Poznámka: kvůli úspoře místa je ukázán pouze první graf vykreslený demonstračním příkladem.

16. Nastavení dalších parametrů grafu

Prozatím jsme ve všech předchozích demonstračních příkladech používali implicitní parametry grafu, které byly odvozeny od hodnot předaných funkci Plot. Na základě počtu hodnot se stanovila šířka grafu a podle rozsahu hodnot pak jeho výška. Ovšem tyto dva parametry lze specifikovat explicitně (ve znacích):

width := asciigraph.Width(40)
height := asciigraph.Height(20)

Dále je možné specifikovat popisek grafu:

caption := asciigraph.Caption(fmt.Sprintf("Modulus: %d, slope: %d", modulus, slope))

Všechna tato nastavení realizují rozhraní Interface je možné je před funkci Plot, a to v libovolném pořadí:

graph := asciigraph.Plot(values[:], width, height, caption)

Následuje ukázka využití těchto explicitně zadaných parametrů při vykreslení grafů:

package main
 
import (
        "fmt"
 
        "github.com/guptarohit/asciigraph"
)
 
const SAMPLES = 64
 
func displayGraph(modulus int, slope int) {
        var values [SAMPLES]float64
 
        for i := 0; i < SAMPLES; i++ {
                values[i] = float64((i - SAMPLES/2) / slope % modulus)
        }
 
        width := asciigraph.Width(40)
        height := asciigraph.Height(20)
        caption := asciigraph.Caption(fmt.Sprintf("Modulus: %d, slope: %d", modulus, slope))
 
        graph := asciigraph.Plot(values[:], width, height, caption)
 
        fmt.Println(graph)
}
 
func main() {
        const modulus = 16
        for slope := 1; slope <= 5; slope++ {
                displayGraph(modulus, slope)
                fmt.Println("\n")
        }
}

S výsledky:

  15.00 ┤                            ╭╮        ╭
  13.53 ┤                           ╭╯│       ╭╯
  12.06 ┤                          ╭╯ │      ╭╯
  10.59 ┤                         ╭╯  │     ╭╯
   9.12 ┤                        ╭╯   │    ╭╯
   7.65 ┤                       ╭╯    │   ╭╯
   6.18 ┤                      ╭╯     │  ╭╯
   4.72 ┤                      │      │ ╭╯
   3.25 ┤                     ╭╯      │ │
   1.78 ┤                    ╭╯       │╭╯
   0.31 ┼╮                  ╭╯        ╰╯
  -1.16 ┤│       ╭╮        ╭╯
  -2.63 ┤│      ╭╯╰╮      ╭╯
  -4.10 ┤│     ╭╯  │     ╭╯
  -5.57 ┤│    ╭╯   │    ╭╯
  -7.04 ┤│   ╭╯    │   ╭╯
  -8.51 ┤│  ╭╯     │  ╭╯
  -9.98 ┤│  │      │ ╭╯
 -11.45 ┤│ ╭╯      │ │
 -12.92 ┤│╭╯       │╭╯
 -14.38 ┤╰╯        ╰╯
                  Modulus: 16, slope: 1
 
 
  6.00 ┤                                      ╭
  5.40 ┤                                     ╭╯
  4.80 ┤                                  ╭──╯
  4.20 ┤                                ╭─╯
  3.60 ┤                               ╭╯
  3.00 ┤                            ╭──╯
  2.40 ┤                            │
  1.80 ┤                         ╭──╯
  1.20 ┤                      ╭──╯
  0.60 ┤                      │
  0.00 ┼                 ╭────╯
 -0.60 ┤                ╭╯
 -1.20 ┤             ╭──╯
 -1.80 ┤           ╭─╯
 -2.40 ┤          ╭╯
 -3.00 ┤       ╭──╯
 -3.60 ┤       │
 -4.20 ┤    ╭──╯
 -4.80 ┤ ╭──╯
 -5.40 ┤ │
 -6.00 ┼─╯
                 Modulus: 16, slope: 5

17. Hodnoty NaN a jejich vliv na vykreslení grafu

Mezi hodnoty reprezentovatelné datovým typem float64 patří i NaN neboli „Not a Number“. Ty se mohou objevit jak ve vstupních datech, tak i při výpočtech (přesně dle normy IEEE 754). Bude tedy vhodné zjistit, jak se existence těchto hodnot projeví na vykresleném grafu:

package main
 
import (
        "fmt"
        "math"
 
        "github.com/guptarohit/asciigraph"
)
 
func main() {
        data := []float64{3, 4, 5, 6, 9, 8, 5, math.NaN(), 6, 10, 2, 7, 2, 5, 6}
        graph := asciigraph.Plot(data)
 
        fmt.Println(graph)
}

Graf vykreslený knihovnou asciigraph vypadá takto:

 10.00 ┤        ╭╮
  9.00 ┤   ╭╮   ││
  8.00 ┤   │╰╮  ││
  7.00 ┤   │ │  ││╭╮
  6.00 ┤  ╭╯ │ ╶╯│││ ╭
  5.00 ┤ ╭╯  ╰╴  │││╭╯
  4.00 ┤╭╯       ││││
  3.00 ┼╯        ││││
  2.00 ┤         ╰╯╰╯
Poznámka: z grafu je patrné, že hodnota NaN byla z výsledného obrázku vynechána, což je vlastně rozumné řešení.

18. Nekonečna a jejich vliv na vykreslení grafu

Datový typ float64 ovšem podporuje i kladné a záporné nekonečno. To v jazyku Go získáme zavoláním funkce math.Inf(), přičemž znaménko vstupní hodnoty určuje, zda se bude jednat o nekonečno kladné nebo záporné. Opět se pokusíme vytvořit graf s těmito hodnotami:

bitcoin_skoleni

package main
 
import (
        "fmt"
        "math"
 
        "github.com/guptarohit/asciigraph"
)
 
func main() {
        data := []float64{3, 4, 5, 6, 9, 8, 5, math.Inf(1), 6, 10, 2, math.Inf(-1), 2, 5, 6}
        graph := asciigraph.Plot(data)
 
        fmt.Println(graph)
}

Tentokrát ovšem nebude vykreslení úspěšné, což znamená, že je nutné tyto vstupní hodnoty filtrovat ještě před pokusem o vykreslení grafu:

panic: runtime error: index out of range [-9223372036854775808]
 
goroutine 1 [running]:
github.com/guptarohit/asciigraph.Plot(0xc000055ec8, 0xf, 0xf, 0x0, 0x0, 0x0, 0xc000010260, 0xc000076ef0)
        /home/ptisnovs/go/src/github.com/guptarohit/asciigraph/asciigraph.go:109 +0x16fd
main.main()
        /home/ptisnovs/src/go-root/article_77/asciigraph/10-infinity.go:12 +0xac
exit status 2

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 nového 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ě stovku kilobajtů), můžete namísto toho použít odkazy na jednotlivé demonstrační příklady, které naleznete v následující tabulce:

# Příklad/soubor Stručný popis Cesta
1 01-basic-usage.go základní způsob použití balíčku cfmt https://github.com/tisnik/go-root/blob/master/article77/cfmt-mindgrammer/01-basic-usage.go
2 02-explicit-endlines.go explicitní tisk konců řádků https://github.com/tisnik/go-root/blob/master/article77/cfmt-mindgrammer/02-explicit-endlines.go
3 03-implicit-endlines.go implicitní tisk konců řádků https://github.com/tisnik/go-root/blob/master/article77/cfmt-mindgrammer/03-implicit-endlines.go
4 04-mixing-with-fmt.go použití obarveného řetězce se standardním balíčkem fmt https://github.com/tisnik/go-root/blob/master/article77/cfmt-mindgrammer/04-mixing-with-fmt.go
5 05-string-generation.go obarvený výstup přesměrovaný do řetězce https://github.com/tisnik/go-root/blob/master/article77/cfmt-mindgrammer/05-string-generation.go
6 06-string-generation-newlines.go obarvený výstup přesměrovaný do řetězce https://github.com/tisnik/go-root/blob/master/article77/cfmt-mindgrammer/06-string-generation-newlines.go
7 07-string-formatting.go formátování s obarvením https://github.com/tisnik/go-root/blob/master/article77/cfmt-mindgrammer/07-string-formatting.go
8 08-string-content.go výpis obsahu obarveného řetězce https://github.com/tisnik/go-root/blob/master/article77/cfmt-mindgrammer/08-string-content.go
9 09-output-to-file.go obarvený výstup přesměrovaný do souboru https://github.com/tisnik/go-root/blob/master/article77/cfmt-mindgrammer/09-output-to-file.go
10 10-output-to-file.go obarvený výstup přesměrovaný do souboru https://github.com/tisnik/go-root/blob/master/article77/cfmt-mindgrammer/10-output-to-file.go
       
11 01-basic-usage.go základní způsob použití balíčku asciigraph https://github.com/tisnik/go-root/blob/master/article77/as­ciigraph/01-basic-usage.go
12 02-computed-values.go předpočet hodnot pro zobrazení (nefunkční příklad) https://github.com/tisnik/go-root/blob/master/article77/as­ciigraph/02-computed-values.go
13 03-to-slice.go předpočet hodnot pro zobrazení (funkční příklad) https://github.com/tisnik/go-root/blob/master/article77/as­ciigraph/03-to-slice.go
14 04-x-range.go implicitní určení rozsahu na x-ové ose https://github.com/tisnik/go-root/blob/master/article77/as­ciigraph/04-x-range.go
15 05-y-range.go implicitní určení rozsahu na y-ové ose https://github.com/tisnik/go-root/blob/master/article77/as­ciigraph/05-y-range.go
16 06-slope.go sklon grafu https://github.com/tisnik/go-root/blob/master/article77/as­ciigraph/06-slope.go
17 07-negative-values.go vliv negativních hodnot na tvar grafu https://github.com/tisnik/go-root/blob/master/article77/as­ciigraph/07-negative-values.go
18 08-settings.go nastavení vlastností zobrazovaného grafu https://github.com/tisnik/go-root/blob/master/article77/as­ciigraph/08-settings.go
19 09-nans.go hodnoty NaN v grafu https://github.com/tisnik/go-root/blob/master/article77/as­ciigraph/09-nans.go
20 10-infinity.go kladné a záporné nekonečno v grafu https://github.com/tisnik/go-root/blob/master/article77/as­ciigraph/10-infinity.go

20. Odkazy na Internetu

  1. Jazyk Go a textový terminál ve funkci základního prvku uživatelského rozhraní
    https://www.root.cz/clanky/jazyk-go-a-textovy-terminal-ve-funkci-zakladniho-prvku-uzivatelskeho-rozhrani/
  2. Tvorba aplikací a her s textovým uživatelským rozhraním s využitím knihovny Blessed
    https://www.root.cz/clanky/tvorba-aplikaci-a-her-s-textovym-uzivatelskym-rozhranim-s-vyuzitim-knihovny-blessed/
  3. Tvorba aplikací a her s textovým rozhraním s knihovnou Blessed (dokončení)
    https://www.root.cz/clanky/tvorba-aplikaci-a-her-s-textovym-rozhranim-s-knihovnou-blessed-dokonceni/
  4. ANSI Escape Code – Colors
    https://en.wikipedia.org/wi­ki/ANSI_escape_code#Colors
  5. A curated list of awesome Go frameworks, libraries and software
    https://awesome-go.com/
  6. Aurora
    https://github.com/logrusorgru/aurora
  7. colourize
    https://github.com/TreyBas­tian/colourize
  8. go-colortext
    https://github.com/daviddengcn/go-colortext
  9. blessed na PyPi
    https://pypi.org/project/blessed/
  10. blessed na GitHubu
    https://github.com/jquast/blessed
  11. Blessed documentation!
    https://blessed.readthedoc­s.io/en/latest/
  12. termbox-go na GitHubu
    https://github.com/nsf/termbox-go
  13. termui na GitHubu
    https://github.com/gizak/termui
  14. blessed na GitHubu
    https://github.com/chjj/blessed
  15. blessed-contrib na GitHubu
    https://github.com/yaronn/blessed-contrib
  16. tui-rs na GitHubu
    https://github.com/fdehau/tui-rs
  17. asciigraph
    https://github.com/guptaro­hit/asciigraph
  18. Standardní balíček text/tabwriter
    https://golang.org/pkg/tex­t/tabwriter/
  19. Elastic tabstops: A better way to indent and align code
    https://nickgravgaard.com/elastic-tabstops/
  20. ASCII Table Writer
    https://github.com/olekukon­ko/tablewriter
  21. TablePrinter
    https://github.com/lensesi­o/tableprinter
  22. go-pretty
    https://github.com/jedib0t/go-pretty
  23. What are the drawbacks of elastic tabstops?
    https://softwareengineerin­g.stackexchange.com/questi­ons/137290/what-are-the-drawbacks-of-elastic-tabstops
  24. Elastic tabstop editors and plugins
    https://stackoverflow.com/qu­estions/28652/elastic-tabstop-editors-and-plugins
  25. Příkaz gofmt
    https://golang.org/cmd/gofmt/
  26. 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/
  27. zerolog
    https://github.com/rs/zerolog
  28. Zero Allocation JSON Logger na Go.doc
    https://pkg.go.dev/github­.com/rs/zerolog?utm_source=go­doc
  29. cfmt
    https://github.com/mingrammer/cfmt
  30. box-cli-maker
    https://github.com/Delta456/box-cli-maker
  31. Who uses zerolog
    https://github.com/rs/zerolog/wiki/Who-uses-zerolog
  32. Go Progress Bar
    https://github.com/ermani­mer/progress_bar

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.