sobota 27. ledna 2018

Hezké grafy v Pythonu

Hrál jsem si s programem sox, který generuje zvukové soubory. Sox umí vygenerovat ke zvuku hezký grafický histogram, ale neumí zobrazit průběh zvuku. Sox má naštěstí výstupní textový formát .dat, tedy spoustou čísel s průběhem zvuku. Přemýšlel jsem, pomocí kterého programu bych z těchto čísel namaloval graf, zvažoval jsem gnuplot a další a nakonec jsem usoudil, že nejjednodušší bude to uděat v Pythonu za pomoci jeho skvělé knihovny matplotlib.

Pro seznámení s touto knihovnou si nakresleme jednu periodu průběhu matematické funkce Sinus. Začněme od konce, výsledkem. Je to trochu máznuté, ale lze to kliknutím zvětšit:

Graf funkce Sinus

Tento poměrně hezký graf vytvoří následující krátký kód:

 1 # PRIPRAVA DAT
 2 
 3 import numpy
 4 
 5 def make_times_data(frm, to, step):
 6     return numpy.arange(frm, to + step, step)
 7 
 8 def make_sinus_data(times, hertz = 1):
 9     return numpy.sin(hertz * 2 * numpy.pi * times)
10 
11 npTimes = make_times_data(0.0, 1.0, 0.01)
12 npSinus = make_sinus_data(npTimes)
13 
14 # VYTVORENI GRAFU
15 
16 import matplotlib
17 
18 matplotlib.use('Agg') # musi byt pred importem pyplot
19 matplotlib.use('PDF') # musi byt pred importem pyplot
20 
21 import matplotlib.pyplot as graph
22 
23 graph.figure(figsize=(1920/120, 1080/120), dpi=120)
24 graph.grid(True)
25 graph.plot(npTimes, npSinus, 'k')
26 graph.savefig('example0.png', dpi=120)

Graf vytvoří volání funkce graph.plot(), které předáváme data jako dva seznamy, jeden seznam dat pro osu x, a druhý pro osu y. Z toho plyne, že program má dvě hlavní části. V první části se vytvoří data pro graf a v druhé části se graf namaluje.

Příprava dat


Před přípravou dat je potřeba si říct, jaký graf vlastně chceme vytvořit. Já se rozhodl vytvořit graf se sinusovou křivkou v závislosti na čase. Na ose X bude čas, na ose Y bude bude sinus. Protože chci zobrazit jen jednu periodu, rozhodl jsem se mít časouvou osu v rozsahu 1 sec a křivku sinus s frekvencí 1 Hz, což znamená jeden kmit za 1 sekundu.

Pro časovou osu X tedy potřebuji vytvořit seznam čísel od 0 do 1. Kolik těch čísel (počet vzorků) potřebuji? Nemá smysl mít větší počet vzorků než je počet pixelů na šířku obrázku, protože přebytečné vzorky by stejně nebylo kam nakreslit. To jest, maximum záleží na šířce obrázku. Běžná obrazovka má čířku 1920 pixelů. Ale není potřeba mít vzorek pro každý pixel. Matplotlib vypočítané body proloží křivkou a tak jich stačí mnohem méně. Můžete si vyzkoušet různé hodnoty a zjistit, kdy křivka začne být hrbolatá z důvodu příliš malého počtu vzorků. Já si zvolil počet 100 vzorků, což odpovídá časovému krok 0,01 sec. Vytvoření těchto časových dat (npTimes) je na řádku 11 a 6. Protože range() neumí počítat s desetinnými čísly, použil jsem funkci arange() z knihovny numpy.

Pro tyto časové data je potřeba vypočítat sinus hodnotu pro osu Y. Použil jsem funkci sin() z knihovny numpy, ktera umi počítat s celým polem npTimes  a vrací pole vypočítaných hodnot sinus. (npSinus). Výpočet je na řádku 12 a 9.

Nakreslení grafu


Pro nakresleni grafu používám knihovnu matplotlib. To je velmi silná knihovna pro tvorbu grafů, která umí vytvářet i interaktivní grafy. Vytvoření grafu jako obrázku je jen jedna z mnoha věcí, které umí. Graf se nakreslí jedním příkazem na řádku 25 a uloží do souboru (formát png) dalším příkazem na řádku 26. Na řádku 23 a 24 je nastavení grafu. Na řádku 23 se nastavuje velikost a rozlišení obrázku, na řádku 24 se zapíná mřížka.

Řádek 18 je potřeba pro kreslení grafu do obrázku. Řádek 19 je potřeba na některých systémech, kde nefunguje defaultní backend pro kreslení, třeba na Androidu.

Zvolený formát PNG patří mezi bitmapové formáty. S bitmapovým obrázkem se snadno pracuje, protože jsou široce podporovány. Alternativou je formát vektorový, třeba SVG. Jeho výhodou je, že lze libovolně měnit jeho velikost a pořád vypadá ostře. Vektorový SVG obrázek se dá vložit přímo do kódu webové stránky a může být její součástí. Při zvětšování a zmenšování stránky se SVG přizpůsobuje a pořád je ostrý. U čárových obrázků, jako jsou grafy, je také výhodou menší velikost (png obrázek nahoře má 63 kB, svg obrázek dole má 14 kB). Nevýhodou je, že SVG nepodporují starší prohlížeče, ale to dnes přestává být významné. Jak je na tom váš prohlížeč s podporou SVG poznáte podle toho, jestli pod tímto textem vidíte obrázek s grafem nebo nikoliv:

Žádné komentáře:

Okomentovat