Rkový skript ke stažení: R
Co si zde představíme?
plot
,ggplot2
,Úvodem bych chtěl varovat, že obrázky jsou velmi silný nástroj, který
čtenáře zaujme jako první. Snahou o hezkou a názornou vizualizaci si
můžete snadno získat jeho přízeň a chuť číst dále. Ovšem buďte na
pozoru, neboť pomocí obrázků se dá snadno lhát:
plot
, její parametry a základní kreslící
funkceZákladní funkce, která umožňuje zakreslovat data do dvourozměrného
obrázku je plot()
. Její výstup se často velmi liší podle
toho, jakým způsobem jsou zadána data. V této části budeme pracovat s
numerickými hodnotami x
a y
a v další části si
ukážeme více. V tomto případě nám Rko vrátí bodový diagram:
n <- 100
x <- rnorm(n)
y <- 1 - x + rnorm(n, sd = 0.5)
plot(x, y)
Asi se shodneme, že takovýto graf zrovna vábně nevypadá. Můžeme si
polepšit upřesněním spousty argumentů, začněme s těmi přímočarými.
plot(x, y,
xlab = "Náhodná veličina X", ylab = "Náhodná veličina Y", main = "Závislost Y na X", # popisky
pch = 18, col = "skyblue", cex = 0.7 # symbol, barva a velikost bodu
)
# ?pch # pro vysvětlení čísel symbolů
par
v sobě ukrývá současné nastavení parametrů pro
vykreslování obrázků. Pokud se Vám třeba nelíbí ta spousta volného místa
okolo grafu, tak přenastavte mar
:
par(mar = c(4, 4, 2, 0.5)) # počet "linek" v pořadí bottom, left, top, right
# odteď bude platné pro všechny následující obrázky, dokud se nezmění
plot(x, y,
xlim = c(-3, 3), ylim = c(-2, 5), # dolní a horní limity pro x-ovou a y-ovou osu
xlab = "Náhodná veličina X", ylab = "Náhodná veličina Y", main = "Závislost Y na X",
pch = 23, col = "darkblue", bg = "deepskyblue", cex = 0.8 # symbol s vnitřním pozadím
)
# ?par # přehled všech nastavitelných parametrů
Prohledáním help(par)
zjistíme, že jde opravdu upravit
mnohé:
par(mar = c(5.2, 4.2, 3, 0.5))
plot(x, y,
xlim = c(-3, 3), ylim = c(-2, 5), # dolní a horní limity pro x-ovou a y-ovou osu
xlab = "Náhodná veličina X", ylab = "Náhodná veličina Y",
main = "Závislost Y na X", sub = "Bodový diagram", # hlavní a sekundární popisek grafu
pch = 7, col = "orchid", cex = 0.8,
bty = "n", # žádný obdélník okolo dat, dále "o" (the default), "l", "7", "c", "u", "]"
cex.axis = 0.5, # menší čísla u os
col.axis = "darkgreen", # barva čísel na ose
font.axis = 2, # tučné písmo na ose
cex.lab = 1.2, col.lab = "darkblue", font.lab = 3, # nastavení popisků os
cex.main = 3, col.main = "chocolate", font.main = 2, # nastavení nadpisu
cex.sub = 0.7, col.sub = "slategrey", font.sub = 4 # nastavení sekundárního popisku
)
# ?par # přehled všech nastavitelných parametrů
Nyní se věnujme osám grafu. Pokud nejsme spokojeni s defaultním výstupem, můžeme zakázat jejich vykreslení a vložit osy vlastní:
par(mar = c(4, 4, 2, 2))
plot(x, y,
xlim = c(-3, 3), ylim = c(-2, 5),
xlab = "Náhodná veličina X", ylab = "", main = "Závislost Y na X",
pch = 23, col = "darkblue", bg = "deepskyblue", cex = 0.8,
xaxt = "n", # zamezí vykreslení osy x
yaxt = "n" # zamezí vykreslení osy y
)
axis(side = 1, at = seq(-3, 3, by = 0.5)) # vytvoření x-ové osy (je třeba nejprve zrušit výše)
axis(side = 4, at = seq(-2, 5, by = 1), las = 2) # vytvoření y-ové osy vpravo + natočení
# ?axis
# ?mtext
mtext("Závislá proměnná", side = 2, line = 0.5, cex = 0.8, font = 3, col = "slategrey") # připsání textu okolo
mtext("Náhodná veličina Y", side = 2, line = 2, cex = 1.5, font = 2) # line udává vzdálenost od hrany oblasti
Pro zajímavost: Rko používá funkci
pretty()
pro určení
hezkých popisků os:
# ?pretty
pretty(x) # n = 5
## [1] -3 -2 -1 0 1 2
pretty(x, n = 10) # chtěný počet intervalů (může být lehce nedodrženo)
## [1] -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0
pretty(x, n = 6)
## [1] -3 -2 -1 0 1 2
pretty(x, n = 6, min.n = 6) # vynutí minimálně 6 intervalů
## [1] -3 -2 -1 0 1 2 3
Všimněme si, že funkce plot()
spouští vždy nové
vykreslovací plátno. Na toto plátno se pak dají pomocí různých funkcí
postupně vrstvit další obrazce:
par(mar = c(4, 4, 2, 2))
plot(x, y,
xlim = c(-3, 3), ylim = c(-2, 5),
xlab = "Náhodná veličina X", ylab = "", main = "Závislost Y na X",
pch = 23, col = "darkblue", bg = "deepskyblue", cex = 0.8,
yaxt = "n"
)
axis(side = 4, at = seq(-2, 5, by = 1), las = 2) # vytvoření y-ové osy vpravo + natočení
mtext(expression(Y == beta[0] + beta[1] * X + epsilon), # lze přidávat i řecká písmena a indexy
side = 2, line = 0.5, cex = 0.8, font = 3, col = "slategrey")
mtext("Náhodná veličina Y", side = 2, line = 2, cex = 1.3, font = 2) # line udává vzdálenost od hrany oblasti
# ?abline # přidává přímku do grafu
abline(a = 1, b = -1, col = "red", # červená přímka y = a + b * x
lty = 2, # 1=solid (default), 2=dashed, 3=dotted, 4=dotdash, 5=longdash, 6=twodash
lwd = 2) # tloušťka čáry
abline(h = 1, lty = 3, lwd = 0.7, col = "grey") # horizontální linka (skutečná střední hodnota)
abline(v = 0, lty = 3, lwd = 0.7, col = "grey") # vertikální linka (skutečná střední hodnota)
# ?points # přidání bodů
points(mean(x), mean(y), pch = 8, cex = 2, lwd = 2, col = "darkorchid") # přidání bodu (výběrový průměr)
# ?lines # přidání lineárních spojnic bodů
xbreaks <- c(-2.5, -1:1, 2.5)
xstredy <- zoo::rollmean(xbreaks, 2)
fx <- cut(x, breaks = xbreaks)
miny <- tapply(y, fx, min)
maxy <- tapply(y, fx, max)
lines(xstredy, miny, col = "goldenrod2", lwd = 3) # lokální minima y
lines(xstredy, maxy, col = "goldenrod4", lwd = 3) # lokální maxima y
# ?segment # přidání úseček (zde jen jedné)
segments(x0 = -3, x1 = 3, # výchozí a koncové x-ové souřadnice
y0 = 5, # y1 = y0, výchozí a koncové y-ové souřadnice
col = "firebrick", lwd = 1.5)
# ?rug # přidání "rohožky"
rug(x, col = "lawngreen", ticksize = 0.02)
# ?arrows # přidání šipek
arrows(x0 = -3, y0 = min(y), y1 = max(y), col = "peru", lwd = 2,
code = 3, # směr šipky: =1 (od 0 k 1), =2 (od 1 k 0), =3 (oba směry)
length = 0.1, angle = 70) # nastavení délky a úhlu šipek
arrows(x0 = -2, x1 = -1,
y0 = 0.5, y1 = -1, col = "red4", lwd = 2)
# ?text # přidání textu do obrázku
text(-2, 0.5, labels = "hustota N(0,1)", pos = 3, # pos = 3 znamená nahoru od vytyčených souřadnic
col = "red4", font = 2, cex = 0.8)
# ?rect # přidání obdélníků
fy <- cut(y, breaks = -2:5)
histy <- prop.table(table(fy))
rect(xleft = 3-histy, xright = 3,
ybottom = -2:4, ytop = -1:5,
col = paste0("grey", seq(80, 20, by = -10)), border = "gold", lwd = 1.5)
# ?polygon # mnohoúhelník, přičemž může být opravdu velmi mnoho
gridx <- seq(-3, 3, by = 0.05)
polyx <- c(-3, gridx, 3)
polyy <- 4*c(0, dnorm(gridx), 0) -2
polygon(x = polyx, y = polyy, col = "turquoise", border = "seagreen", lwd = 2)
# ?legend
legend("topleft",
c("Pozorování", "Průměr"),
ncol = 2, # počet sloupečků legendy
title = "Nadpis legendy", title.cex = 0.6,
cex = 0.8, # relativní velikost celé legendy
bty = "u", # styl rámečku okolo legendy
pch = c(23, 8),
col = c("darkblue", "darkorchid"),
pt.bg = c("deepskyblue", NA),
lwd = c(1, 2),
lty = 0
)
legend(0.1, 4, c("Podmíněná střední hodnota", "Marginální střední hodnota"),
col = c("red", "grey"), lty = c(2, 3), lwd = c(2, 1),
cex = 0.8, box.lty = 5)
Pokud máme data uložená v nějakém
data.frame
, tak můžeme
souřadnice bodů udávat také takto:
data(iris)
iris$fSpecies <- factor(iris$Species)
mycol <- c("pink", "orchid", "darkorchid")
names(mycol) <- levels(iris$fSpecies)
par(mar = c(4,4,0.5,0.5))
plot(Sepal.Width ~ Sepal.Length, data = iris, # závislá ~ vysvětlující proměnná
pch = 16, col = mycol[fSpecies]) # barva dle druhu kosatce
legend("topright", levels(iris$fSpecies),
ncol = nlevels(iris$fSpecies),
pch = 16, cex = 0.8, col = mycol)
Někdy je užitečné použít logaritmické měřítko. Buď lze vykreslit
přímo log(x)
, ale takto lze zachovat popisky os v
originálním měřítku bez námahy:
data(Animals, package = "MASS")
summary(Animals)
## body brain
## Min. : 0.023 Min. : 0.40
## 1st Qu.: 3.100 1st Qu.: 22.23
## Median : 53.830 Median : 137.00
## Mean : 4278.439 Mean : 574.52
## 3rd Qu.: 479.000 3rd Qu.: 420.00
## Max. :87000.000 Max. :5712.00
par(mfrow = c(1,2), mar = c(4,4,2,0.5)) # dva obrázky vedle sebe
plot(brain ~ body, type = "n", data = Animals, # závislá ~ vysvětlující proměnná (žádné body)
main = "Animals - originální měřítko",
xlim = c(-2e4, 1.1e5), ylim = c(-2e2, 6e3))
text(Animals$body, Animals$brain, labels = rownames(Animals))
plot(brain ~ body, type = "n", data = Animals, # závislá ~ vysvětlující proměnná (žádné body)
main = "Animals - logaritmické měřítko",
log = "xy") # logaritmické transformace os x i y (popisky originální)
text(Animals$body, Animals$brain, labels = rownames(Animals)) # souřadnice nadále udávat v původním měřítku
Podívejme se nyní na různé varianty grafů, které Rko nabízí. Začněme
s tím, jak se mění výstup klasického plot
při změně
type
. Dávejte pozor, že některé mají smysl, jen když x-ové
hodnoty jsou srovnané od nejmenšího po největší:
par(mfrow = c(3,3), mar = c(2,2,2,0.5)) # mřížka 3×3 obrázků na jednom plátně
u <- 1:20
v <- rnorm(20)
plot(u, v, type = "n", main = "n") # "none" čisté plátno bez bodů
plot(u, v, type = "p", main = "p") # "points" jen body (defaultní nastavení)
plot(u, v, type = "l", main = "l") # "lines" lineární lomenná funkce
plot(u, v, type = "b", main = "b") # "both" body s úsečkami mezi nimi
plot(u, v, type = "c", main = "c") # přerušená lomenná čára na místě bodů
plot(u, v, type = "o", main = "o") # "over" body přes úsečky
plot(u, v, type = "s", main = "s") # "step" dolní skokovitá funkce (skok až s další hodnotou)
plot(u, v, type = "S", main = "S") # "Step" horní skokovitá funkce (skok hned s hodnotou)
plot(u, v, type = "h", main = "h") # "hist" vertikální linky jako histogram
Základní grafy pro práci s numerickou proměnnou jsou
boxplot
, hist
par(mfrow = c(1,2), mar = c(4,4,2.5,0.5)) # mfrow = c(1,2) - mříž 1×2 pro obrázky (tedy dva vedle sebe)
boxplot(iris$Sepal.Length)
hist(iris$Sepal.Length)
## Hezčí verze
par(mfrow = c(1,3), mar = c(2,4,2.5,0.5))
# Boxplot
boxplot(iris$Sepal.Length, main = "Sepal length [cm]", col = "tomato")
# Violin plot (je třeba nainstalovat balíček vioplot)
vioplot::vioplot(iris$Sepal.Length, main = "Sepal length [cm]", col = "goldenrod")
# využívá jádrové odhady hustoty jako
# plot(density(iris$Sepal.Length))
# ale nejdříve by to chtělo vědět, o co přesně se jedná...
hist(iris$Sepal.Length, xlab = "", main = "Sepal length [cm]", col = "lightblue",
freq = FALSE, # y-ovou osu jako hustotu (ne frekvence)
breaks = seq(4, 8, by=1/3), # vlastní dělení na intervaly
right = FALSE, # zleva uzavřené intervaly (namísto vpravo)
density = 20, # hustota šrafování
angle = 30, # úhel šrafování
border = "royalblue", # barva ohraničení
)
rug(iris$Sepal.Length, col = "red")
Vícero numerických proměnných lze zobrazit v matici bodovými diagramy stylem každý s každým:
# ?pairs
plot(iris[, 1:4]) # stejné jako funkce pairs(iris[, 1:4])
psych::pairs.panels(iris[, 1:4]) # hezčí verze z balíčku psych (je třeba nainstalovat)
Nyní se zaměřme na kategoriální proměnné. Pro ně jsou vhodné
sloupcové (barplot
) či koláčové (piechart
)
grafy:
f <- factor(sample(1:3, 100, replace = T, prob = c(0.35, 0.45, 0.2)))
par(mfrow = c(2,2)) # mříž 2×2
plot(f) # = plot.factor --> vyprodukuje barplot
barplot(prop.table(table(f))) # očekává výšky sloupců tj. (relativní) četnosti
pie(table(f)) # očekává (relativní) četnosti
dotchart(table(f)) # srovnání kategorií bodově na liniích
Zde je návod, jak si obrázky vyladit:
par(mfrow = c(1,3)) # mříž 2×2
pt <- prop.table(table(f))
b <- barplot(pt, width = 1, space = 0, # šířka jedné kategorie
main = "Relativní četnosti kategorií",
ylim = c(0, max(pt)*1.05), # navýšení horní hranice grafu
# horiz = TRUE, # vodorovné sloupce
names.arg = paste("Hezčí", 1:3), # přepíše levely faktoru na ose x
legend.text = c("Málo", "Středně", "Hodně"), # vytvoří legendu, pokud je třeba dovysvětlit
col = c("greenyellow", "yellowgreen", "chartreuse3"),
# density = 10, angle = 70, # šrafování místo úplné výplně
border = "forestgreen"
)
lines(seq(0.5, 2.5, by = 1), prop.table(table(f)), type = "b", col = "coral", lwd = 3)
# středy sloupců jsou díky nulovým mezerám mezi sloupci přesně 0.5, 1.5, 2.5 (zkuste bez udání space)
# Ovšem funkce nejen že kreslí, také (tiše) vrací středy sloupců.
# To můžeme využít třeba pro napsání číselné hodnoty nad sloupec.
text(b[,1], pt, labels = table(f), pos = 3, font = 2)
pie(table(f), edges = 20, # aproximace výseče pomocí polygonu o tolika stěnách
main = "Koláčový diagram",
radius = 1, # poloměr kruhu (pozor, kresleno do čtverce [-1,1]×[-1,1])
clockwise = TRUE, # zda začít jako hodiny na 12 a postupovat po směru hod. ručiček
labels = paste0(c("Málo", "Středně", "Hodně"),
" (", table(f) / length(f) * 100, " %)"),
# density = 30, angle = 50, # šrafování místo úplné výplně
col = c("cornflowerblue", "steelblue", "royalblue"),
border = "navyblue", lty = 3, font = 2
)
dotchart(table(f),
main = "Počítadlový diagram",
xlim = c(0, max(table(f))+5), # protáhnutí x-ové osy
labels = c("Málo", "Středně", "Hodně"), # popisky na levé straně
color = c("salmon", "orangered", "indianred4"), # barvy symbolů i popisků
pch = 17, pt.cex = 3, font = 2, # úprava symbolů, popisků
lcolor = c("grey20", "grey50", "grey80") # barvy linek
)
Dvojice kategoriálních proměnných lze zakreslit následovně:
# Použijeme tabulku VADeaths dostupnou v Rku
# ?VADeaths
VADeaths
## Rural Male Rural Female Urban Male Urban Female
## 50-54 11.7 8.7 15.4 8.4
## 55-59 18.1 11.7 24.3 13.6
## 60-64 26.9 20.3 37.0 19.3
## 65-69 41.0 30.9 54.6 35.1
## 70-74 66.0 54.3 71.1 50.0
class(VADeaths)
## [1] "matrix" "array"
par(mfrow = c(2,2), mar = c(2.2,2.2,2,0.1))
barplot(VADeaths)
dotchart(VADeaths)
spineplot(VADeaths)
mosaicplot(VADeaths)
Opět si ukážeme, jak tyto obrázky oživit pomocí dodatečných parametrů:
library("car")
head(TitanicSurvival)
## survived sex age passengerClass
## Allen, Miss. Elisabeth Walton yes female 29.0000 1st
## Allison, Master. Hudson Trevor yes male 0.9167 1st
## Allison, Miss. Helen Loraine no female 2.0000 1st
## Allison, Mr. Hudson Joshua Crei no male 30.0000 1st
## Allison, Mrs. Hudson J C (Bessi no female 25.0000 1st
## Anderson, Mr. Harry yes male 48.0000 1st
summary(TitanicSurvival)
## survived sex age passengerClass
## no :809 female:466 Min. : 0.1667 1st:323
## yes:500 male :843 1st Qu.:21.0000 2nd:277
## Median :28.0000 3rd:709
## Mean :29.8811
## 3rd Qu.:39.0000
## Max. :80.0000
## NA's :263
TitanicSurvival$fage <- addNA(cut(TitanicSurvival$age, breaks = c(0, 18, 35, 100),
labels = c("Child", "Young adult", "Older adult")))
# ?TitanicSurvival
(TAB1 <- table(TitanicSurvival$survived, TitanicSurvival$passengerClass))
##
## 1st 2nd 3rd
## no 123 158 528
## yes 200 119 181
(TAB2 <- table(TitanicSurvival$sex, TitanicSurvival$survived))
##
## no yes
## female 127 339
## male 682 161
(TAB3 <- table(TitanicSurvival$fage, TitanicSurvival$survived))
##
## no yes
## Child 98 95
## Young adult 326 205
## Older adult 195 127
## <NA> 190 73
(TAB4 <- table(TitanicSurvival$passengerClass,
TitanicSurvival$sex,
TitanicSurvival$survived ))
## , , = no
##
##
## female male
## 1st 5 118
## 2nd 12 146
## 3rd 110 418
##
## , , = yes
##
##
## female male
## 1st 139 61
## 2nd 94 25
## 3rd 106 75
par(mfrow = c(2,2))
barplot(TAB1, main = "Passenger Class vs Survival",
col = c("darkgreen", "palegreen"),
horiz = TRUE, las = 2)
legend("bottomright", c("No", "Yes"), title = "Survived",
pt.bg = c("darkgreen", "palegreen"), pch = 22, pt.cex = 1.3)
dotchart(TAB2, main = "Survival vs Sex",
xlim = c(0, max(TAB2)),
color = c("violetred", "dodgerblue"), # barvy podskupin a symbolů (zdola nahoru)
gcolor = c("black", "green"), # barvy hlavních skupin
pch = 17, pt.cex = 3, font = 2, # úprava symbolů, popisků
labels = c("Female", "Male") # úprava popisků
)
spineplot(TAB3, main = "Survival vs Age",
col = c("lightsteelblue", "midnightblue"), # barvy v pořadí odzdola nahoru
yaxlabels = c("No", "Yes"), # odshora dolů (tedy opačně!)
xaxlabels = c("<= 18", "<= 35", "> 35", "NA") # změna popisků
)
# mosaicplot zvládá i více jak dvourozměrné tabulky
mosaicplot(TAB4, main = "Survival vs Sex and Passenger Class",
col = c("saddlebrown", "navajowhite"), # barvy zleva doprava
# shade = T, # měří vychýlení od celkového průměru
sub = paste0("Total number of passengers is ", nrow(TitanicSurvival), ".") # menší titulek dole
)
Už jsme poznali, jak zakreslit samostatně numerické či samostatně kategoriální veličiny. Zbývá se zaměřit na případ kombinace těchto dvou kategorií. I když by rozdíl v pořadí mezi proměnnými být neměl, tak se v Rku rozlišují dva grafy dle typu vysvětlované proměnné. Když je naší odezvou numerická proměnná, výsledkem je soustava boxplotů, jeden pro každou kategorii:
par(mfrow = c(1,1), mar = c(4,4,2.5,2))
plot(count ~ spray, data = InsectSprays, # pomocí formule "y ~ x"
main = "InsectSprays",
col = c("bisque", "wheat", "ivory", "cornsilk", "beige", "honeydew"))
# odezva ~ závisí na těchto proměnných (takže první se píše y-ová osa, pak až x-ová)
Můžeme tak sledovat, které kategorie mají k sobě blízko a které se od sebe liší.
Kategorizací numerické proměnné můžeme zakreslit vývoj vztahu.
data("Hosi0", package = "mffSM")
par(mfrow = c(1,2), mar = c(4,4,2.5,2))
plot(bweight ~ blength, data = Hosi0, # bez faktorizace jen bodový diagram
main = "Porodní váha a délka chlapců")
plot(bweight ~ factor(blength), data = Hosi0, # je třeba si faktor udělat
main = "Porodní váha a délka chlapců",
col = terrain.colors(9), # funkce vracející zadaný počet barev vhodný pro "výškový terén na mapě"
width = table(factor(blength))) # šířky boxplotů dle četnosti jednotlivých kategorií
Jakmile je ale naší odezvou kategoriální proměnná a vysvětlující
numerická, nelze vykreslit boxploty. Numerická proměnná se vnitřně
kategorizuje pomocí cut
s hezky ekvidistantně vzdálenými
dělícími body a vykreslí se spineplot
znázorňující vývoj
poměrů kategorií se změnou numerické proměnné. Hraniční body nejsou od
sebe ekvidistantně vzdáleny, ale úměrně dle počtu pozorování v daném
intervalu.
par(mfrow = c(1,2), mar = c(4,4,2.5,2.5))
# defaultní výstup
plot(survived ~ age, data = TitanicSurvival)
# vlastní kategorie
plot(survived ~ age, data = TitanicSurvival,
breaks = c(0, 15, 20, 25, 30, 40, 50, 100), # vlastní kategorie
col = c("seashell", "darkslategrey"))
Doposud jsme si ukazovali kreslící funkce v základní výbavě Rka. V
poslední době (a hlavně komerční sféře) jsou oblíbené moderní Rkové
knihovny jako například ggplot2
. Syntax kreslení je velmi
odlišný od toho standardního a má svou vlastní logiku:
library("ggplot2")
## Use suppressPackageStartupMessages() to eliminate package startup messages
data(diamonds, package = "ggplot2")
diamonds$fcarat <- cut(diamonds$carat, breaks = c(0,0.5,1,1.5,2,6))
gp <- ggplot(data = diamonds, # uložení obrázku do proměnné
mapping = aes(x = carat, y = price, color = clarity)) + # s jakými daty se pracuje
geom_point() # vykreslit body
gp # vykreslení současného stavu provede plot(gp)
Obrázek máme uložený v proměnné
gp
a nyní k němu můžeme
přidat další příkazy upřesňující vzhled či další obrazce k
vykreslení:
grouped_diamonds <- matrix(tapply(diamonds$price, diamonds$clarity:diamonds$fcarat, mean),
nrow = nlevels(diamonds$fcarat))
rownames(grouped_diamonds) <- levels(diamonds$fcarat)
colnames(grouped_diamonds) <- levels(diamonds$clarity)
stredy <- c(0.25, 0.75, 1.25, 1.75, 4)
colors <- heat.colors(nlevels(diamonds$clarity))
gp2 <- gp + # přeuložení do jiné proměnné
geom_line(mapping = aes(x = stredy, I1), data = grouped_diamonds, color = colors[1], linewidth = 1.5) +
geom_line(mapping = aes(x = stredy, SI2), data = grouped_diamonds, color = colors[2], linewidth = 1.5) +
geom_line(mapping = aes(x = stredy, SI1), data = grouped_diamonds, color = colors[3], linewidth = 1.5) +
geom_line(mapping = aes(x = stredy, VS2), data = grouped_diamonds, color = colors[4], linewidth = 1.5) +
geom_line(mapping = aes(x = stredy, VS1), data = grouped_diamonds, color = colors[5], linewidth = 1.5) +
geom_line(mapping = aes(x = stredy, VVS2), data = grouped_diamonds, color = colors[6], linewidth = 1.5) +
geom_line(mapping = aes(x = stredy, VVS1), data = grouped_diamonds, color = colors[7], linewidth = 1.5) +
geom_line(mapping = aes(x = stredy, IF), data = grouped_diamonds, color = colors[8], linewidth = 1.5)
gp2 + theme_minimal() + # změna stylu obrázku
scale_x_log10() + # log10 transformace x
scale_y_log10() + # log10 transformace odezvy
labs(x = "Weight of the diamond [carat]",
y = "Price [$]",
title = "Scatterplot",
subtitle = "The price of diamonds vs weight and clarity on logarithmic scale")
Jenže jak přidat legendu pro jednotlivé linky, když si legendu dělá
ggplot
sám?
S ggplot2
se lze opravdu vyřádit, ale zde na to již není
prostor. Zde je odkaz na 50 zajímavých
obrázků i se zdrojovým kódem. Zde je odkaz na tvorbu
animovaných obrázků (pro prezentace či web) s pomocí knihovny
gganimate
.
Nyní se zaměřme na ukládání obrázků. Jedna (velmi nedoporučovaná!)
volba je záložka Plots > Export, kde si lze vybrat formát,
rozměry a kam se má obrázek uložit. Jenže při každé změně jednoho
obrázku hodláte znovu nastavovat to samé? Lepší je si ukládání obrázku
zaznamenat přímo do scriptu. Rko nabízí funkce pdf
,
jpeg
, png
a další pro ukládání obrázků v
zadaném formátu.
Ukážeme si jejich použití spolu s dalšími kreslícími funkcemi, na které se zatím nedostalo.
WD <- getwd()
dir_fig <- file.path(dirname(WD), "fig") # upravte si dle vlastního adresáře
pdf(file = file.path(dir_fig, "sin_a_cos.pdf"),
width = 6, height = 4 # v palcích (inch)
# encoding = "utf8" # kódování znaků
)
{ # doporučuji všechny příkazy obalit
par(mfrow = c(1, 1), mar = c(4, 2, 2.5, 0.5)) # 1×1, okraje
curve(sin(x), from = -10, to = 10, col = "blue", lwd = 2, # vykreslí zadanou funkci v jedné proměnné
xlab = "x", ylab = "", main = "Goniometrické křivky") # klasické pdf má problém s českými znaky
# je třeba si vyhrát s encoding či fonts argumenty...
curve(cos(x), from = -10, to = 10, col = "red", lwd = 2, add = T) # add=T přidá do již existujícího obrázku
abline(h = 0, col = "grey", lty = 2)
abline(v = 0, col = "grey", lty = 3)
}
dev.off() # uzavření PDFka - NEZAPOMENOUT!!!
Všimněte si, že české symboly se v Rku neuložily správně. Pro české
účely je daleko spolehlivější pokročilá verze této funkce
cairo_pdf()
:
cairo_pdf(file = file.path(dir_fig, "dnorm_dt.pdf"), width = 6, height = 4) # v palcích (inch)
{
par(mfrow = c(1, 1), mar = c(4, 4, 2.5, 0.5))
curve(dnorm(x), from = -3, to = 3, col = "blue", lwd = 2, # hustota N(0,1)
xlab = "x", ylab = "Hustota",
main = "Příliš žluťoučký kůň úpěl ďábelské ódy") # pro ověření češtiny
curve(dt(x, df = 5), from = -3, to = 3, col = "red", lwd = 2, add = T) # hustota t(5)
abline(h = 0, col = "grey", lty = 2)
abline(v = 0, col = "grey", lty = 3)
legend("topright", c("N(0,1)", "t(5)"), col = c("blue", "red"), lty = 1, lwd = 2)
}
dev.off() # uzavření PDFka - NEZAPOMENOUT!!!
Další formát, ve kterém je možné obrázky ukládat je jpg
.
Problém je však s kvalitou a velikostí obrázku:
x <- rnorm(50)
y <- rnorm(50, sd = 2)
jpeg(file.path(dir_fig, "ecdf.jpg"),
width = 1000, height = 700, units = "px", # v pixelech (jako default, ale lze změnit)
quality = 75, pointsize = 12 # originální nastavení kvality obrazu
)
{
layout(matrix(c(1,1, # první řádek splyne v jediný obrázek
2,3), nrow = 2, byrow = TRUE)) # mříž 2×2
par(mar = c(4,4,2.5,0.5))
# ?plot.ecdf # Empirická kumulativní distribuční funkce
# ?plot.acf # Empirická autokorelační funkce
plot(ecdf(x), col = "red", main = "Empirická distribuční funkce",
xlim = range(c(x, y))) # aby šíře okna pojala oba výběry
plot(ecdf(y), col = "blue", add = T)
plot(ecdf(x), col = "red", verticals = T, col.01line = "slategrey", pch = 19, main = "N(0,1)")
plot(ecdf(y), col = "blue", verticals = T, col.01line = "slategrey", pch = 16, main = "N(0,2^2)")
}
dev.off() # uzavření jpeg - NEZAPOMENOUT!!!
Kvalita velikost obrázku se dá navýšit hraním si s dodatečnými argumenty:
jpeg(file.path(dir_fig, "ecdf_kvalitneji.jpg"),
width = 1000, height = 700, units = "px", # stejné rozměry jako předtím
quality = 100, pointsize = 20 # zlepšení kvality obrázku + zvětšení písma,
# res = ... # rozlišení, 72 je default
)
{
layout(matrix(c(2,3, # mříž 2×2
1,1), nrow = 2, byrow = TRUE)) # druhý řádek splyne v jediný obrázek - ten první!
par(mar = c(4,4,2.5,0.5))
plot(ecdf(x), col = "red", main = "Empirická distribuční funkce",
xlim = range(c(x, y))) # aby šíře okna pojala oba výběry
plot(ecdf(y), col = "blue", add = T)
plot(ecdf(x), col = "red", verticals = T, col.01line = "slategrey", pch = 19, main = "N(0,1)")
plot(ecdf(y), col = "blue", verticals = T, col.01line = "slategrey", pch = 16, main = "N(0,2^2)")
}
dev.off() # uzavření jpeg - NEZAPOMENOUT!!!
Dále lze ukládat jako png
se stejnými argumenty jako
funkce jpeg
:
y <- x <- seq(-2*pi, 2*pi, length.out = 201) # x-ové a y-ové hodnoty
z <- outer(sin(x), cos(y)) # z = sin(x) * cos(y), každý s každým
dim(z)
breaks <- seq(-1, 1, length.out = 11) # zkuste vyšší hodnoty, třeba 51
COLs <- terrain.colors(length(breaks)-1) # barev o 1 méně než
# ?terrain.colors # jaké další barevné palety Rko nabízí?
# COLs <- hcl.colors(length(breaks)-1, palette = "viridis")
# COLs <- hcl.colors(length(breaks)-1, palette = "Dark 3")
# COLs <- hcl.colors(length(breaks)-1, palette = "YlGnBu")
# COLs <- hcl.colors(length(breaks)-1, palette = "Green-Brown")
# COLs <- hcl.colors(length(breaks)-1, palette = "Blue-Red 3")
# COLs <- rainbow(length(breaks)-1)
# COLs <- heat.colors(length(breaks)-1)
# COLs <- topo.colors(length(breaks)-1)
# COLs <- cm.colors(length(breaks)-1)
png(file.path(dir_fig, paste0("image_sincos_", length(breaks)-1, "_barvicek.png")),
width = 600, height = 500, units = "px", pointsize = 15) # nastavení velikosti
{
layout(matrix(c(1,2), nrow = 1, byrow = TRUE), # dva obrázky vedle sebe
widths=c(5,1)) # šířkově v poměru 5:1 (druhý bude velmi hubený)
par(mar = c(4,4,2.5,0.5))
# barevné vykreslení hodnot funkce o dvou proměnných (heatmap)
image(x, y, z, main = c("f(x,y) = sin(x) * cos(y)"), bty = "n",
breaks = breaks, col = COLs, # kategorizace hodnot + barevné schéma
asp = 1) # zachová poměr x a y os 1:1
# legenda jako separátní obrázek
par(mar = c(4,0,2.5,3)) # horní a dolní okraje stejné, žádný vlevo, napravo delší
plot(0, 0, type ="n", # bty = "n", # NIC nekreslit, jen otevřít kreslící okno
xlim = c(0,1), ylim = c(-1,1), # rozsah y hodnot odpovídající hodnotám funkce
xaxs = "i", yaxs = "i", # žádné vnitřní rozšíření xlim a ylim hodnot
xaxt = "n", yaxt = "n", # bez os x a y
xlab = "", ylab = "") # žádné popisky os
axis(4, seq(-1, 1, length.out = 11), las = 2) # vlastní osa napravo
rect(xleft = 0, xright = 1, # obdélníky po celé šíři vykreslovací plochy
ybottom = breaks[-length(breaks)], # dolní hodnoty úzkých obdélníků
ytop = breaks[-1], # horní hodnoty úzkých obdélníků
col = COLs, border = NA) # barevné vyplnění obdélníků bez ohraničení
}
dev.off() # uzavření png - NEZAPOMENOUT!!!
y <- x <- seq(-2*pi, 2*pi, length.out = 201) # x-ové a y-ové hodnoty
z <- outer(sin(x), cos(y)) + outer(x, y)/20 # z = sin(x) * cos(y) + x * y / 20, každý s každým
dim(z)
(rz <- range(z))
barev <- 100
breaks <- seq(rz[1], rz[2], length.out = barev+1)
COLs <- hcl.colors(barev, palette = "YlGnBu")
png(file.path(dir_fig, paste0("image_sincos_plus_xy_", barev, "_barvicek.png")),
width = 600, height = 500, units = "px", pointsize = 15) # nastavení velikosti
{
layout(matrix(c(1,2), nrow = 1, byrow = TRUE), # dva obrázky vedle sebe
widths=c(5,1)) # šířkově v poměru 5:1 (druhý bude velmi hubený)
par(mar = c(4,4,2.5,0.5))
# barevné vykreslení hodnot funkce o dvou proměnných (heatmap)
image(x, y, z, main = c("f(x,y) = sin(x) * cos(y) + x*y/20"), bty = "n",
breaks = breaks, col = COLs, # kategorizace hodnot + barevné schéma
asp = 1) # zachová poměr x a y os 1:1
# legenda jako separátní obrázek
par(mar = c(4,0,2.5,3)) # horní a dolní okraje stejné, žádný vlevo, napravo delší
plot(0, 0, type ="n", # bty = "n", # NIC nekreslit, jen otevřít kreslící okno
xlim = c(0,1), ylim = rz, # rozsah y hodnot odpovídající hodnotám funkce
xaxs = "i", yaxs = "i", # žádné vnitřní rozšíření xlim a ylim hodnot
xaxt = "n", yaxt = "n", # bez os x a y
xlab = "", ylab = "") # žádné popisky os
axis(4, pretty(breaks), las = 2) # vlastní osa napravo
rect(xleft = 0, xright = 1, # obdélníky po celé šíři vykreslovací plochy
ybottom = breaks[-length(breaks)], # dolní hodnoty úzkých obdélníků
ytop = breaks[-1], # horní hodnoty úzkých obdélníků
col = COLs, border = NA) # barevné vyplnění obdélníků bez ohraničení
}
dev.off() # uzavření png - NEZAPOMENOUT!!!
Nyní si ukážeme, jak sestrojit 3D graf pomocí funkce
persp()
:
y <- x <- seq(-10, 10, length.out = 30)
f <- function(x, y){r <- sqrt(x^2+y^2); 10 * sin(r)/r}
z <- outer(x, y, f)
par(mar = c(1.5,0,0,0))
persp(x, y, z, theta = 30, phi = 30, expand = 0.5, col = "lightblue",
ltheta = 120, shade = 0.75, ticktype = "detailed",
xlab = "X", ylab = "Y", zlab = "Sinc( r )", cex.axis = 0.8)
Hustota dvourozměrného normálního rozdělení:
library("mvtnorm")
x <- seq(-3, 3, length.out = 30)
y <- seq(-4, 4, length.out = 30)
Sigma <- matrix(c(1.2,0.6,0.6,1.8), nrow = 2, byrow = TRUE)
detSigma <- det(Sigma)
mu <- c(0,0)
# f <- function(x, y){ exp(-t(cbind(x,y) - mu) %*% solve(Sigma, cbind(x,y) - mu) / 2)/(2*pi)/sqrt(detSigma)}
f <- function(x, y){dmvnorm(cbind(x, y), mean = mu, sigma = Sigma)}
z <- outer(x, y, f)
par(mar = c(1.5,0,0,0))
persp(x, y, z, theta = 40, phi = 50, expand = 0.5, col = "olivedrab1",
ltheta = 120, shade = 0.75, ticktype = "detailed",
xlab = "X", ylab = "Y", zlab = "Hustota N_2", cex.axis = 0.8)
Nyní si ukážeme, jak vykreslit mapy. V obecném balíčku
maps
nalezneme hranice států jako polygony jen pro mapu
celého světa a vybraných států světa (USA, Francie, …)
library("maps")
world <- map_data("world")
ggplot(data = world, aes(x = long, y = lat, group = group, bg = region)) +
geom_polygon() +
theme(legend.position="none")
Existuje R-kový balíček s daty pro ČR. Najdete v něm třeba hranice krajů jako polygony.
library("RCzechia")
czechia <- kraje("low")
# czechia$KOD_CZNUTS3
# Nezaměstnanost - stav k 31.8.2025 dle ČSÚ - https://csu.gov.cz/jhc/mapa-podil-kraje
nezam <- c(3.50, 3.77, 3.77, 3.68, 5.33, 6.71, 5.06,
3.82, 3.56, 3.61, 5.02, 4.74, 3.73, 6.27)
names(nezam) <- c("PRA", "STC", "JHC", "PLZ", "KLV", "UST", "LIB",
"KRH", "PAR", "VYS", "JHM", "OLO", "ZLI", "MSK")
fnezam <- cut(nezam, breaks = seq(3.5, 7, by = 0.5), include.lowest = T)
colors <- heat.colors(nlevels(fnezam), rev = TRUE)
names(colors) <- levels(nezam)
par(mfrow = c(1,1), mar = c(0,0,2.5,0))
plot(st_geometry(czechia), col = colors[fnezam], main = "Nezaměstnanost v českých regionech")
legend("topright", levels(fnezam), fill = colors, bty = "n")
Obsahuje nejen kraje, okresy a řeky, ale i užitečné oblasti či sítě v rámci našeho území:
par(mfrow = c(1,2), mar = c(0,0,2.5,0))
chko <- chr_uzemi() %>% subset(TYP == "CHKO")
plot(st_geometry(chko), col = "forestgreen", main = "Chráněné krajinné oblasti")
plot(st_geometry(zeleznice()), col = "darkslategrey", main = "Železniční tratě")
S útvary lze dělat různá prolínání a úpravy, ale to je nad naše
kapacity. Více o použití tohoto balíčku je k nalezení zde.
V tomto skriptu jsem se snažil ukázat spoustu různých barev
předdefinovaných v R. Pokud byste chtěli kompletní přehled, naleznete
jej v tomto dokumentu. Na tomto
webu lze také nalézt přehled Rkových barev spolu s konvertorem do
jiných formátů. Další palety barev jsou dostupné v balíčku
colorspace
.
Vyřešte si to sami, aniž byste se dívali do řešení (úplně dole vespod skriptu).
Nakreslete si obrázek terče, tedy soustředných kruhů o různých poloměrech s jiným podbarvením. Žádné osy, popisky ani okraje nejsou potřeba.
Vykreslete boxplot numerické proměnné, aniž byste použili funkci
boxplot
. Používejte quantile
,
rect
, segments
apod.
Vytvořge vlastní “počítadlový” diagram pro kategoriální proměnnou, kde četnost bude odpovídat počtu kuliček na počítadle (vodorovně zleva).
Podívejte se na dataset ?EuStockMarkets
, který
obsahuje 4 časové řady evropských akciových indexů, zakreslete je do
jednoho obrázku jinými barvami. Jaké jsou mezi nimi vztahy? Jak vypadají
autokorelační funkce těchto řad? Napočítejte pro každý index řadu
diferencí v ceně oproti předchozímu pracovnímu dni. Vykreslete podvojné
bodové diagramy a autokorelační funkce pro tyto diference.
Pomocí datasetu ?chickwts
ukázkově zakreslete, jaký
je rozdíl ve výsledné váze kuřat při různé stravě. Typy krmiva si
seřaďte dle mediánových hodnot váhy.
Uvažte dataset ?HairEyeColor
obsahující třírozměrnou
tabulku, kde se studenti dělí do skupin podle barvy vlasů, barvy očí a
pohlaví. Pomocí vhodných barev a obrázků zakreslete marginální četnosti,
podvojné četnosti i celou tabulku.
Věková pyramida. Stáhněte si z mých stránek data Českého statistického úřadu cr_1945_2023.xlsx, která obsahují počty mužů a žen v jednotlivých věkových kategoriích. Pro jeden zvolený rok vytvořte pomocí základních funkcí věkovou pyramidu, což jsou dva histogramy (pro muže a ženy) zády k sobě. Zde je návod, jak to vykreslit v Rku pomocí speciální knihovny:
library(readxl)
library(apyramid)
library(ggplot2) # apyramid funguje s touto knihovnou
data_dir <- file.path(dirname(getwd()), "data") # adresář s uloženými daty
veky <- 0:100
# Sloupec CC obsahuje data k 31.12. 2023
muzi <- read_excel(file.path(data_dir, "cr_1945_2023.xlsx"), range = "CC3:CC103", col_names = FALSE)
zeny <- read_excel(file.path(data_dir, "cr_1945_2023.xlsx"), range = "CC106:CC206", col_names = FALSE)
data <- data.frame(pohlavi = rep(c("Muži", "Ženy"), each = length(veky)),
vek = rep(veky, 2),
pocet = c(unlist(muzi), unlist(zeny)))
data <- transform(data,
fvek = factor(vek),
fvek2 = cut(vek, breaks = seq(0,100,by=5), right = TRUE, include.lowest = TRUE))
# Po roce
age_pyramid(data, age_group = fvek, split_by = pohlavi, count = pocet, horizontal_lines = FALSE) +
scale_fill_manual(values = c("Muži" = "royalblue", "Ženy" = "tomato")) +
theme_minimal()
# Skupiny po 5 letech
age_pyramid(data, age_group = fvek2, split_by = pohlavi, count = pocet, horizontal_lines = FALSE) +
scale_fill_manual(values = c("Muži" = "royalblue", "Ženy" = "tomato")) +
theme_minimal()