17.3 Mapování a nastavování estetik
V předchozím textu byl vysvětlen pojem estetika a mapování. Nyní se tomuto tématu budeme věnovat podrobněji. Každý geom
má několik estetik – dimenzí, jejichž podobu lze řídit podle určité proměnné. V případě bodového grafu (point
) jde o: x
, y
, shape
, size
, color
/colour
, fill
, stroke
a alpha
. Například geom
line
(spojnicový graf) má estetiky jiné – nerozumí stroke
, shape
a fill
. Namísto toho umí pracovat s linetype
.
Výše uvedený příklad demonstruje mechanismus mapování. S pomocí funkce aes()
je estetikám přiřazena proměnná. Některé estetiky je v závislosti na geomu nutné přiřadit. V případě geom_point()
je to například x
a y
:
%>%
diamonds ggplot(
aes(x = carat)
+
) geom_point()
## Error: geom_point requires the following missing aesthetics: y
Pomocí aes()
je možné mapovat i další estetiky:
%>%
diamonds ggplot(
aes(x = carat, y = price, size = x, color = cut)
+
) geom_point()
Pro každou namapovanou estetiku ggplot2
vytvoří vodítko, které čtenáři umožní překlad z vizualizace do dat. V případě x
a y
vykreslí osy grafu. U zbývajících estetik vykreslil legendu.
Jednu proměnnou jde mapovat i na více estetik:
%>%
diamonds ggplot(
aes(x = carat, y = price, size = cut, color = cut)
+
) geom_point()
ggplot2
takovou kombinaci zohlední i v legendě. Tento příklad ukazuje i další vlastnost ggplot2
. Pokud uživatel požaduje provedení něčeho, co Tvůrce (H. Wickham) nepovažuje za dobrý nápad, vrátí ggplot2
upozornění (via message()
).
ggplot2
poskytuje obrovské množství možností a částečně uživateli radí. Nicméně je na uživateli, aby vše nastavil tak, aby výsledné obrázky splňovaly svůj účel – jasně čtenáři předávaly určitou informaci. Obrázek použitý v příkladu například trpí zásadní vadou, která se říká “overplotting.” Pozorování se vzájemně překrývají a ve výsledný obrázek čtenáři mnoho neřekne. Nemůže vědět, zda se v některém místě vzájemně překrývá málo, nebo mnoho pozorování. Jednoduchou a často dostačující cestou jak bojovat s tímto problémem je nastavení průhlednosti (estetiky alpha
). Tuto estetiku lze samozřejmě mapovat na proměnnou, ale v tomto případě ji použijeme pro ilustraci nastavení estetiky:
%>%
diamonds ggplot(
aes(x = carat, y = price)
+
) geom_point(alpha = 0.1)
Pokud chce uživatel estetiku nastavit, je potřeba ji deklarovat v příslušné geom_*()
funkci a mimo funkci aes()
. Příklad ukazuje, že nastavení průhlednosti problém s overplottingem minimálně zmírnilo.
17.3.1 Kontrola mapování
Ve všech příkladech jsme dosud pouze mapovali estetiku na určité proměnné. Mapování předává ggplot2
informaci typu: “barvu puntíků urči podle proměnné cut
.” Jak konkrétně to ggplot2
provede (t.j. bude mít špatný řez červenou, modrou, zelenou nebo jinou barvu) jsme zatím nijak neovlivňovali.
V této kapitole si ukážeme, jak lze s pomocí funkcí scale_*_*()
měnit škálování a prvky, které pomáhají čtenáři převést vizualizaci zpět do dat.
Pro tyto účely budeme používat jednoduchou datovou tabulku se 3 pozorováními a 4 sloupci x
, y
, z
a w
…
<- data_frame(
xtable x = c(1,2,3),
y = c(1,1,1),
z = c("A","B","C"),
w = c(-1,0,1)
)
…a jednoduchý bodový graf:
%>%
xtable ggplot(
aes(x = x, y = y)
+
) geom_point()
ggplot2
namapoval data na estetiky (pozice) a vykreslil osy, které čtenáři umožňují číst data. Obrázek je takový, jaký asi všichni očekávají. Nicméně to nemusí být to, co uživatel chce. Co může chtít změnit? Například:
- jméno škály (
name
) - popisky na ose (
labels
) - pozice “hlavních” popisků na ose (
breaks
) - pozice “pomocných” popisků/čar na ose (
minor_breaks
) - interval zobrazený na obrázku – “jak dlouhá” má být osa (
limits
) - pozici osy (
position
) - transformaci hodnot na ose – například zobrazení logaritmu pozorovaných hodnot (
trans
) - zobrazení sekundární osy (
sec.axis
)
Úplný výčet možností se samozřejmě liší podle estetiky.
Mapování se řídí pomocí funkcí scale_*_*()
, která se podobně jako geom_()
připojují k volání ggplot()
pomocí funkce +
. Jména funkcí scale_*_*()
se mohou zdá komplikovaná, ale opak je pravdou. Ve jejích jménech je totiž systém. Jméno funkce se sestává ze tří částí, spojených znakem "_":
- Všechna jména začínají
scale
- Druhá část jména je jméno estetiky, kterou chceme kontrolovat
- Poslední část jména je jméno konkrétní škály (to je potřeba si občas pamatovat nebo najít)
Pokud bychom například chtěli změnit jméno osy x (estetika x
) na našem obrázku, potom budeme chtít použít funkci:
scale_x_continuous()
První část jména je daná, druhá je jasná a třetí odkazuje na povahu proměnná x
v tabulce xtable
, která je spojitá. (Takto pěkně ale jména škály nefungují vždy. Občas je třeba hledat.)
Pokud známe jméno, je z poloviny vyhráno:
%>%
xtable ggplot(
aes(x = x, y = y)
+
) geom_point() +
scale_x_continuous(name = "Tohle je osa x")
Jak bylo zmíněno výše, pomocí škál je možné nastavit velké množství parametrů:
%>%
xtable ggplot(
aes(x = x, y = y)
+
) geom_point() +
scale_x_continuous(
name = "Tohle je osa x",
breaks = c(1,2,3),
labels = c("málo","víc","málo"),
limits = c(0,4),
position = "top"
)
Poněkud specifické je nastavení transformace. V praxi se často používá logaritmická transformace:
%>%
xtable ggplot(
aes(x = x, y = y)
+
) geom_point() +
scale_x_continuous(trans = "log10")
Řada transformací je pro uživatele připravená (viz ?scale_x_continuous()
). Uživatel má navíc možnost vytvořit vlastní transformace. Pro nejčastější transformace má ggplot2
předpřipravené škály – například log10
nebo reverse
:
%>%
xtable ggplot(
aes(x = x, y = y)
+
) geom_point() +
scale_x_log10()
V předchozích příkladech jsme volali funkci scale_x_*()
pro nastavení mapování estetiky x
. Nicméně ani jednou jsme neupravovali estetiku y
a taky to fungovalo. Jak je to možné? Pokud není funkce scale_*_*()
explicitně volána uživatelem, ggplot2
odhadne, která funkce je nejvhodnější a zavolá ji interně sám. Volání:
%>%
xtable ggplot(
aes(x = x, y = y)
+
) geom_point()
Je tak ve výsledku ekvivalentní k:
%>%
xtable ggplot(
aes(x = x, y = y)
+
) geom_point() +
scale_x_continuous() +
scale_y_continuous()
Pokud se změní povaha podkladových dat, potom se i ggplot2
rozhodne volat jinou funkci scale_*_*()
. V případě volání:
%>%
xtable ggplot(
aes(x = factor(x), y = y)
+
) geom_point()
kde proměnná x
je konvertována na faktor. Vrátí ggplot2
obrázek ekvivalentní volání:
%>%
xtable ggplot(
aes(x = factor(x), y = y)
+
) geom_point() +
scale_x_discrete() +
scale_y_continuous()
ggplot2
v tomto případě volá škálu vytvořenou pro mapování diskrétních proměnných.
17.3.1.1 Mapování barev (estetiky colour
a fill
)
Pomocí funkcí scale_*_*()
lze měnit mapování všech estetik. Mezi nejčastější upravované škály patří bezesporu barvy, které se mapují v estetikách color
/colour
a fill
.
Poznámka: ggplot2
neumí a podle jeho tvůrců nikdy nebude umět vybarvovat texturou (“šrafováním”).
Pro ilustraci těchto estetik použijeme následující podobu bodového grafu:
%>%
xtable ggplot(
aes(x = x, y = y, color = z, fill = w)
+
) geom_point(
shape = 21,
stroke = 3,
size = 10
+
) scale_x_continuous(
limits = c(0.5,3.5)
+
) theme(
legend.direction = "horizontal"
-> p
)
p
Výsledná podoba obrázku je ovlivněna funkcí theme()
. Její fungování je popsáno níže. Celá struktura je přiřazená do proměnné p
. S tou budeme nadále pracovat.
Tento graf mapuje proměnné z
a w
na estetiky color
a fill
. Ostatní estetiky jsou nastaveny a jsou pro všechny body v grafu shodné.
Proměnná z
a w
se liší ve své povaze. w
je spojitá proměnná a z
je kategoriální. Práce s barvami by se obecně měla řídit podle povahy zobrazovaných dat:
- Spojité proměnné se typicky zobrazují barevným přechodem – jak vidíte na obrázku, základní volbou
ggplot2
je přechod z tmavě do světle modré. - Kategoriální proměnné, jejichž hodnoty jsou “na stejné úrovni.” Příkladem takové proměnné mohou být například značky automobilů. V takovém případě je zvolit barvy, které jsou pro vnímání člověka “stejně daleko” od sebe. Příkladem takového výběru barev může být proměnná
z
v ukázkovém obrázku. - Posledním typem jsou kategoriální proměnné, které vyjadřují sekvenci (např.: malá, střední, velká). V takovém případě je vhodné volit barevný přechod, který je také rozdělen do kroků, které musí být tak velké, aby byly pro člověka jasně odlišitelné.
Při volbě barev je také užitečné myslet na barvoslepé a na tisk na černobílé tiskárně. Jiné barvy jsou také vhodné pro plochy a jiné pro body. Ve výsledku je výběr barev nesmírně složitý. Najít sekvenci barev pro 10 úrovní je těžké, pro 20 úrovní je to nemožné. Moudrým postupem je proto používat uměřený počet barev (úrovní) a v jejich volbě vycházet z doporučení odborníků.
17.3.1.1.1 Spojité proměnné
Typickým postupem zobrazování spojité proměnné v barvě je použití barevného přechodu (gradientu) mezi dvěma nebo více barvami. ggplot2
nabízí hned 4 škály založené na gradientech:
scale_*_gradient()
(identické se scale_*_continuous()
) je základní volbou, po které u spojitých proměnných ggplot2
sáhne, pokud uživatel neporoučí jinak. Vykresluje přechod mezi dvěma barvami, které jsou nastavené parametry low
a high
:
+ scale_fill_gradient(low = "hotpink", high = "#56B1F7") p
V příkladu je nastaven přechod z tmavě poníkové do modré. Barva je vždy definována jako řetězec (nebo funkcí, která řetězec nebo jejich vektor vytvoří) – a to buď svým jménem ("hotpink"
) nebo RGB kódem ("#56B1F7"
).
scale_*_gradient2()
je derivátem scale_*_gradient()
umožňuje vytvořit přechod přes tři barvy (low
, mid
, high
) a specifikovat pozici středního bodu parametrem midpoint
. (Parametr midpoint
je defaultně nastaven na hodnotu 0.)
+ scale_fill_gradient2(midpoint = 0.5) p
scale_*_gradientn()
umožňuje použít přechod přes tolik barev, kolik si jen srdce uživatele přeje. Z tohoto důvodu neobsahuje žádné základní nastavení:
+ scale_fill_gradientn() p
## Error in scale_fill_gradientn(): argument "colors" is missing, with no default
Uživatel musí prostřednictvím parametru colours
zadat vektor barev, které se mají použít. Domnívám se, že pro uživatele – neodborníka – se jedná o nemožný úkol. Je však možné použít předpřipravené palety, které jsou součástí mnoha balíků. Následující příklad využívá paletu inferno
z balíku viridis:
+ scale_fill_gradientn(colours = viridis::inferno(3)) p
Využití scale_*_gradientn()
je vhodné spíše v plochách. Nicméně i tam je dobré spolehnout na rady odborníků. Příklad “plošného” obrázku:
Na radach odborniku je zcela postaven scale_*_distiller()
. Pracuje s rucne vybranymi diskretnimi paletami, ktere jsou dostupne na http://colorbrewer2.org/. scale_*_distiller()
tyto diskrétní palety adaptuje i pro spojité proměnné. Rozumný způsob práce je na webu zvolit vhodnou barevnou škálu a její jméno specifikovat v parametru palette
. Ten um pracovat s číslem palety i s jejím jménem:
+ scale_fill_distiller(palette = "YlGnBu") p
Parametrem direction
, který nabývá hodnot 1
nebo -1
, lze pořadí barev obrátit:
+ scale_fill_distiller(palette = "YlGnBu", direction = 1) p
Pouzivani http://colorbrewer2.org/ lze doporučit v maximální rozumné míře.
17.3.1.1.2 Diskrétní proměnné
Pro diskrétní proměnné je výchozí volbou scale_*_hue()
. Tato škála vybírá od sebe stejně vzdálené barvy na “HCL wheel” (viz např. Wikipedie). Teoreticky je tak schopna vytvořit barevné schéma pro prakticky neomezený počet kategorií. V praxi od sebe budou barvy při vyšším počtu kategorií nerozpoznatelné.
+ scale_color_hue() p
scale_*_hue()
umožňuje vybrat výchozí bod na HCL wheel a parametrem direction
směr, jakým se na něm výběr pohybuje:
+ scale_color_hue(direction = -1) p
Zejména při finalizaci grafických výstupů je vhodné poohlédnout se po předpřipravených paletách. V samotném ggplot2
jde o scale_*_brewer()
– bratra scale_*_distiller()
pro diskrétní veličiny.
+ scale_color_brewer(palette = "Set1") p
Speciální škálou je scale_*_grey()
. Ta, jak název napovídá, mapuje do odstínů šedé:
+ scale_color_grey() p
Speciálními případy škál jsou scale_*_manual()
a scale_*_identity()
. scale_*_manual()
umožňuje uživateli vytvořit si vlastní škálu. U barev bude tato možnost využívána asi jen zřídka. Za určitých okolností se však může hodit u jiných estetik – například u shape
.
scale_*_identity()
dokáže vzít proměnnou z datové tabulky a použít ji “tak jak je” pro vykreslení barev, tvarů a podobně.
17.3.1.2 Co jsme zamlčeli…
Všechny krásné škálovací funkce scale_*_*()
v posledku využívají služeb konstruktorových funkcí discrete_scale()
a continuous_scale()
. S těmito funkcemi komunikujete ze scale_*_*()
přes argument ...
. Pokud tedy budete chtít provádět něco složitějšího, tak se vyplatí projít si nápovědu právě k těmto konstruktorovým funkcím.