Jak změnit barvy v grafu? Jedna z nejčastějších otázek kohokoliv, kdo začíná s některým z analytických nástrojů - od Excelu, přes Power BI až po matplotlib v Pythonu a ggplot v R. V případě ggplotu vede první pokus často k nečekanému výsledku, který se na první pohled může zdát nesmyslný. Tento článek by měl vysvětlit, proč tomu tak je a jak barvy změnit správně (plus malý bonus na závěr).
Zde je příklad s daty o kosatcích (datová sada iris
je součástí základní instalace R).
Předpokládejme, že již máme graf, který vykresluje délku okvětního listu (Petal.Length
) na ose x a
jeho šířku (Petal.Width
) na ose y. Obě tyto proměnné jsme nastavili uvnitř funkce aes()
. V
dokumentaci této funkce jsme také zjistili, že jeden z dalších argumentů je color
(lze použít i
americké colour
). Co se stane, pokud tímto argumentem nastavíme barvu bodů v grafu na modrou?
ggplot(iris) +
geom_point(aes(Petal.Length, Petal.Width, color = "blue"))
Je zřejmé, že body v grafu nejsou modré. Ale i v legendě vedle grafu je napsáno, že body jsou ve skutečnosti modré. Co je tedy špatně? Jedná se o chybu v ggplot2 knihovně nebo dokonce v R? Pokud ano, někdo by si jí už dávno všiml a opravil ji. Tím to tedy pravděpodobně nebude.
Ve skutečnosti se jedná o velmi častou chybu začínajících programátorů v R (alespoň na mých kurzech). To je také důvod, proč jsem se rozhodl tento článek napsat. Najít a odstranit chybu z kódu je často náročnější než samotný kód napsat. Ve většině případů R vypíše do konzole chybu kvůli které program selhal. Takové chyby je relativně snadné odstranit (s pomocí Google a Stack Overflow). Chyby, které nepřeruší běh programu, ale dávají špatný výstup jsou často mnohem složitější na opravu, jelikož nemáme žádnou chybovou hlášku v konzoli. Na první pohled tak není zřejmé, kde problém nastal. A to je i náš příklad s barvami.
Problém je v tom, že jsme nastavili barvu ve funkci aes()
, která očekává proměnné z dat (numerické
nebo kategoriální). Funkce nezpracovává hodnoty doslovně, ale mapuje jednotlivé hodnoty z dat na
barvy z přednastavené palety barev. V případě kategorické proměnné (což je i náš příklad) se
jednotlivé kategorie seřadí abecedně a v tomto pořadí se přiřadí barvy ze zvolené palety.
Pokud bychom funkci použili správně a dosadili například druh kosatce (sloupec Species
), barvy se
přiřadí jednotlivým druhům dle abecedy. Jako první je druh "setosa", kteý tak dostane první barvu,
což je stejná červená jako v grafu výše. Zbylé dva druhy pak dostanou zelenou a modrou barvu, které
jsou hned další v paletě barev.
ggplot(iris) +
geom_point(aes(Petal.Length, Petal.Width, color = Species))
Když jsme původně nastavili barvu na modrou, ggplot to vyhodnotil jako kategoriální proměnnou s jednou kategorií "blue", které tak automaticky přiřadil první barvu z palety. Na názvu této kategorie vůbec nezáleží. Pokud bychom dosadili libovolný jiný text do tohoto argumentu, výsledek by byl pokaždé stejný (až na text v legendě).
Abychom tak nastavili barvu všem bodům v grafu bez ohledu na jakékoliv kategorii, je potřeba to
udělat uvnitř funkce geom_point
. V našem případě je to hned za pravou závorkou volání
funkce aes()
. Všimněte si také, že legenda se v tomto případě nezobrazí, portože jsme barvu
nastavili globálně a ne zavisle na datech.
ggplot(iris) +
geom_point(aes(Petal.Length, Petal.Width), color = "blue")
To samé platí o dalších atributech grafu (například velikost bodu nebo šířka čáry) i pro jiné typy
grafů (spojnicový, sloupcový, ...). Jejich nastavení uvnitř aes()
předpokládá proměnnou z dat (
číselnou, nebo kategoriální) a volba barev tak probíhá automaticky. Hodnoty z dat nejsou
interpretovány doslovně, ale relativně k dalším hodnotám. Abychom nastavili atribut na konkrétní
hodnotu, je potřeba toto udělat ve funkci pro konkrétní vrstvu (
například geom_point
, geom_line
).
V některých případech chceme použít barvy podle proměnné z dat, ale nechceme se spolehnout na výchozí nastavení palety barev. Jednou z možností je vyměnit paletu za jinou. Alternativně můžeme nastavit barvy "ručně" pro jednotlivé kategorie.
ggplot(iris) +
geom_point(aes(Petal.Length, Petal.Width, color = Species)) +
scale_color_manual(
values=c(setosa = "purple", versicolor = "red", virginica = "green")
)