Bizonyára sokan találkoztak már azzal a problémával, hogy a készülő publikációjukhoz egy olyan speciális ábrára lett volna szükségük, aminek előállítására az Excel vagy a Word nem volt képes. Ilyen esetekre kínál megoldást az R ggplot2 csomagja.
Maga a ggplot2 alapcsomag és az arra épülő számos kiegészítő csomag egy olyan vizualizációs ökoszisztémát alkot, amely egy szabványosított interfészen keresztül programozottan, ugyanakkor a végletekig személyre szabható módon teszi lehetővé a különböző diagramok, ábrák elkészítését. Ennek komplex bemutatására nyilvánvalóan nem lehet elegendő egyetlen poszt és erre nem is törekszem. Csakúgy, mint a karácsonyfa-diagramnál, most is egy gyakorlati példán keresztül szeretném érzékeltetni a ggplot2 sokoldalúságát.
A feladat jelen esetben egy olyan oszlopdiagram-szerű ábra előállítása, amelyen az egyes oszlopok egy-egy valóságban is létező könyv gerincének megjelenését imitálják, emellett arányosak a kérdéses könyvek fizikai méretével.
Ennek a posztnak a lényege azonban nem a konkrét ábra, hanem a gyakorlási lehetőség. A ggplot2 első megközelítésre sajnos baromira bonyolultnak tűnik. A működése és annak finomságai csak úgy sajátíthatók el készségszinten, ha az ember folyamatosan kísérletezget vele. Könyvespolc-diagramot általában nem készítünk, de a megoldás összetevőit a későbbiekben más, értelmes munkák során hasznosítani lehet.
A könyvespolc tartalma
Mielőtt a technikai részletekbe belevágnánk, elsőként tekintsük tehát át, hogy konkrétan milyen könyvekről van szó! Az elkészítendő virtuális könyvespolcra olyan munkákat válogattam ki, amelyeket a nyár folyamán szeretnék majd elolvasni.
A következő nyolc könyvről van szó:
Mivel a saját kutatási területem a magyar főnemesség társadalomtörténetéhez kapcsolódik, így az első két könyv emiatt érdekes a számomra. Ebből a szempontból Szemethy Tamás: Katonabárók és hivatalnok grófok. Új arisztokraták a 18. századi Magyarországon, illetve Melkovics Tamás: A reformkori főrendi ellenzék és 1839-40-es zászlóbontása című munkájára esett a választásom.
A következő két kötet a Hajnal István Kör augusztusi konferenciájára való felkészülés miatt kell nekem, ahol az ókígyósi Wenckheim-kastély vendégkönyvéből kibontakozó hálózatokról tartok majd előadást. Emiatt érzem fontosnak Szilágyi Adrienn: Az uradalom elvesztése. Nemesi családok a 19. századi Békés megyében, valamint Sisa József: Kastélyépítészet és kastélykultúra Magyarországon. A historizmus kora című kötetét.
Ha csak úgy olvasgatok, akkor általában a 20. századi magyar történelemre esik a választásom. Ebből a korszakból két egri kollégám közelmúltban megjelent könyvét szemeltem ki magamnak: Valuch Tibor: Mindennapi történeteink. Válogatott társadalomtörténeti tanulmányok, valamint Fábián Máté: Egy fajvédő főispán a Horthy-korszakban. Borbély-Maczky Emil 1887–1945 című monográfiáját.
Végezetül két módszertani jellegű munka is helyet kapott a listán. Az információk vizuális ábrázolásának elrettentő példáiba és jó gyakorlataiba vezeti be az olvasót Alberto Cairo a How Charts Lie. Getting Smarter about Visual Information című kötete, míg a tudománymetria újszerű megközelítésével találkozhatunk Dashun Wang és Barabási Albert László A tudomány tudománya címet viselő könyvében.
Ezeket a köteteket akarom tehát elhelyezni a virtuális könyvespolcon. Itt külön is szeretnék köszönetet mondani Szemethy Tamásnak, aki nemcsak készségesen válaszolt a könyve fizikai méreteit firtató furcsa kérdéseimre, hanem pár nappal később meg is ajándékozott egy példánnyal. Így már fizikailag is felkerülhetett a könyvespolcomra. 😁 És persze ugyancsak köszönöm Fábián Máté, Szilágyi Adrienn és Valuch Tibor korábbi hasonló gesztusát is.
A diagram technikai megvalósítása
Egy ggplot2-vel készült ábra felépítését talán annak analógiájára lehet a legjobban elképzelni, mintha átlátszó fóliákra rajzolnánk vagy írnánk, majd ezeket a fóliákat egy adott sorrendben egymásra rétegeznénk. Ebben a rendszerben a fentebb lévő rétegek rajzolatai értelemszerűen kitakarhatják az alattuk lévő rétegek egyes részleteit. A diagram végső megjelenése a rétegek összességéből bontakozik ki.
A lényegét tekintve a megvalósítás abból áll majd, hogy fokozatosan újabb és újabb rétegeket adok a diagramhoz, egészen addig, amíg el nem érem a kívánt vizuális hatást.
A továbbiakban öt lépésben fogok végig menni a diagram technikai megvalósításának folyamatán.
A diagram megvalósításának lépései (kattintásra nagyítható)
Az alábbiakban R nyelven (v4.0.3) írt kódot használok a feladat végrehajtásához. A magyarázó szövegek közé ékelt fekete kódblokkok tartalmát az RStudio-ban egymás alá illesztve elvileg bárki által reprodukálható az itt bemutatott műveletsor. A kódblokkok # kezdetű sorai pusztán magyarázó funkcióval bírnak, ezekre a program futtatásakor nincs szükség.
Elsőként tekintsük át, hogy milyen csomagokra lesz szükségünk és töltsük be ezeket!
A ggplot2 teszi lehetővé a tulajdonképpeni diagram létrehozását.
Az extrafont csomaggal a számítógépünkre feltelepített betűtípusok összességéből választhatjuk ki azokat, amelyekkel feliratozni akarjuk a könyvek gerincét. (A ggplot2 alapértelmezés szerint egy minimalista sans-serif betűtípust használ.) Első használatkor a
font_import()
paranccsal kell indítani, aminek végrehajtása több percig is eltarthat. A későbbiekben viszont erre már nincsen szükség.
Megjegyzendő, hogy az általam készített ábrával pontosan megegyező kinézethez természetesen az olvasó gépén is telepítve kell legyenek a kódban említett betűtípusok. Amennyiben ez nem így lenne, akkor a megfelelő helyeken át kell írni a kódot a rendelkezésre álló fontoknak megfelelően!Végül a png és a grid csomag a PNG típusú képek beolvasását teszi lehetővé.
# A szükséges csomagok betöltése.
# A legelső használat előtt az install.packages("...") utasítással telepíteni
# kell ezeket. A ... helyére az adott csomag neve írandó.
library(ggplot2)
library(extrafont)
# font_import()
# Csak az első alkalommal futtatandó! Ekkor a # jelet ki kell venni a sor elejéről!
library(png)
library(grid)
Hozzuk létre a munkakönyvtárat is, majd töltsük le ide és csomagoljuk ki a furcsa-diagramok-2-konyvespolc.rar fájlt! Ebben 4 darab PNG kiterjesztésű képet találunk.
# Ide a saját munkakönyvtárunk elérését kell beírni!
setwd("C:/Munkakönyvtár")
1. A könyvek gerincének megrajzolása
Ahogy a fenti ábrán látható, a könyvek vizuális megjelenésének alapját színes négyszögek alkotják. Ezeket a geom_rect()
réteggel tudjuk hozzáadni a diagramunkhoz. Bemenetként egy adatkeretet vár tőlünk, amelynek mezői a réteg paramétereiként funkcionálnak majd.
Paraméter | Magyarázat |
---|---|
xmin | a négyszög bal alsó sarkának x koordinátája (numerikus érték) |
ymin | a négyszög bal alsó sarkának y koordinátája (numerikus érték) |
xmax | a négyszög jobb felső sarkának x koordinátája (numerikus érték) |
ymax | a négyszög jobb felső sarkának y koordinátája (numerikus érték) |
fill | a négyszög kitöltésének színe* (karakterlánc) |
color | a négyszög körvonalának színe* (karakterlánc) |
A könnyebb áttekinthetőség érdekében az alábbiakban minden könyvnek önálló adatkeretet hozok létre. Ezeket az rbind()
függvénnyel fűzöm össze a rect elnevezésű adatkeretté.
rect <- rbind(
szemethy = data.frame(
"xmin" = 0,
"ymin" = 0,
"xmax" = 30,
"ymax" = 243,
"fill" = c("#4f6573",NA),
"color" = c(NA,"#000000")
),
melkovics = data.frame(
"xmin" = 30,
"ymin" = c(0,16,0),
"xmax" = 55,
"ymax" = c(240,224,240),
"fill" = c("#65442a","#f1d4a7",NA),
"color" = c(NA,NA,"#000000")
),
szilagyi = data.frame(
"xmin" = 55,
"ymin" = c(0,60,0),
"xmax" = 80,
"ymax" = c(245,90,245),
"fill" = c("#828284","#ffffff",NA),
"color" = c(NA,NA,"#000000")
),
sisa = data.frame(
"xmin" = 80,
"ymin" = 0,
"xmax" = 110,
"ymax" = 250,
"fill" = c("#294072",NA),
"color" = c(NA,"#000000")
),
valuch = data.frame(
"xmin" = 110,
"ymin" = c(0,153,170,0),
"xmax" = 125,
"ymax" = c(238,170,238,238),
"fill" = c("#422f28","#9b332a","#ffffff",NA),
"color" = c(NA,NA,NA,"#000000")
),
fabian = data.frame(
"xmin" = 125,
"ymin" = 0,
"xmax" = 142,
"ymax" = c(200,70,200),
"fill" = c("#ffffff","#664d48",NA),
"color" = c(NA,NA,"#000000")
),
cairo = data.frame(
"xmin" = c(142,142,142,152,145,155,142),
"ymin" = c(0,115,115,115,110,110,0),
"xmax" = c(164,164,148,158,151,161,164),
"ymax" = c(115,243,121,127,131,117,243),
"fill" = c("#01b1ec","#02a2dc","#017eac","#017eac","#df202f","#ffd124",NA),
"color" = c(NA,NA,NA,NA,NA,NA,"#000000")
),
dashunbarabasi = data.frame(
"xmin" = 164,
"ymin" = 0,
"xmax" = 194,
"ymax" = 230,
"fill" = c("#241f23",NA),
"color" = c(NA,"#000000")
)
)
A geom_rect()
réteg első, data nevű paramétere a rect néven elmentett adatkeret. A vizualizálandó elemek megjelenítésének tulajdonságait a mapping paraméterben, az aes()
(aesthetic) függvénybe csomagolva kell megadnunk. Itt a réteg által elvárt, a fenti táblázatban bemutatott paraméterekhez hozzárendeljük az adatkeret megfelelő – történetesen azonos nevet viselő – mezőit. Magát a diagramot a konyvespolc nevű változóban raktározzuk el.
konyvespolc <- ggplot() +
geom_rect(data = rect, mapping = aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = fill, color = color), show.legend = F)
Mielőtt továbbmennénk, érdemes kitérni a színek megadásának módjára. Ez elsőre talán egy kicsit bonyolultnak fog hangozni, de ez az ára a diagramok teljes körű testreszabhatóságának. (Amit ebben a posztban éppen csak kóstolgatunk.)
A fill és a color paraméterekben látszólag direktben vannak megadva a színek, hiszen a háttérben álló adatkeret fill és color mezői így tartalmazzák ezeket, hexadecimális formátumban. Valójában azonban az aes()
függvény számára nem a konkrét színek az érdekesek. Itt egy kategóriaképzésről van szó, ahol az egymástól különböző értékek önálló kategóriákat alkotnak. A kategorizáláshoz történetesen a színek kódjait használtam fel, de egyébként bármilyen más karakterlánccal is működne a dolog. A ggplot2 az egyforma értékekhez tartozó vizuális elemeket egyformára, a különbözőeket különbözőre fogja színezni. A fill és a color mezők tartalma ennyit és nem többet jelent.
Hogy pontosan milyen színnel akarjuk látni az ábrázolandó elemeket, azt a scale_fill_manual()
és a scale_color_manual()
rétegek hozzáadásával tudjuk manuálisan szabályozni. Itt a values paraméterben egy névvel ellátott vektorban kell megadni, hogy az adatkeretünk fill és color mezőiben szereplő értékek milyen színeknek felelnek meg. Vagyis minden egyes értékhez hozzárendelünk egy-egy konkrét színt. Jelen esetben saját magát.
colors <- unique(na.omit(c(rect$fill, rect$color)))
colors <- setNames(colors, colors)
Ezt követően már összerakhatjuk a diagramunk első részét, amelyet lefuttatva a munkafolyamatot áttekintő ábra 1. részén látható eredményt kapjuk. (Kapnánk, ha lefuttatnánk.)
konyvespolc <- konyvespolc +
scale_fill_manual(values = colors) +
scale_color_manual(values = colors)
2. A vonalas díszítmények hozzáadása
Két könyv gerincén vonalas díszítmények is vannak. Ezeket alapvetően a geom_segment()
rétegben, ugyancsak egy adatkeret tartalmára támaszkodva lehetne felvarázsolni a diagramra. Nálam azonban valami miatt nem szerette ezt a megoldást a ggplot2. Ezért végül az annotate()
függvény segítségével, az adatokat ennek paramétereiként direktben megadva helyeztem fel a vonalakat a diagramra.
Az R nyelv igen rugalmas. Ugyanazt a dolgot általában többféle módon is megvalósíthatjuk.
A függvény első paramétere a “segment” karakterlánc, utalva arra, hogy a geom_segment()
réteget helyettesíti. A többi paraméter jelentése leolvasható az alábbi táblázatból.
Paraméter | Magyarázat |
---|---|
x | a vonal kezdetének x koordinátája (numerikus érték) |
y | a vonal kezdetének y koordinátája (numerikus érték) |
xend | a vonal végének x koordinátája (numerikus érték) |
yend | a vonal végének y koordinátája (numerikus érték) |
color | a vonal színe (karakterlánc) |
linetype | a vonal típusa (karakterlánc) |
size | a vonal vastagsága (numerikus érték) |
Az annotate()
függvény paraméterei egyedi értékként és vektorként is megadhatók. Utóbbival egyszerre több vonalat is definiálni tudunk egyazon függvényen belül.
Én az alábbiakban két darab függvényt használok, hogy egyértelműen elkülöníthető legyen egymástól a két érintett könyv. Az elsőben két pontvonalat, a másodikban pedig egyetlen sima vonalat adok a konyvespolc néven elmentett ábrához.
konyvespolc <- konyvespolc +
annotate("segment",
x = 30,
y = c(18,222),
xend = 55,
yend = c(18,222),
color = "#65442a",
linetype = "dotted",
size = 1.3) +
annotate("segment",
x = 130,
y = 122,
xend = 137,
yend = 122,
color = "#000000",
linetype = "solid",
size = 1
)
3. A raszteres díszítmények hozzáadása
A következő lépésben a könyvek gerincét díszítő logókat helyezem fel az ábrára. A jelenlegi feladattól elvonatkoztatva ez azt jelenti tehát, hogy PNG kiterjesztésű raszteres képeket is hozzá tudunk adni egy diagramhoz.
Elsőként olvassuk be az R-be a munkakönyvtárunkba korábban letöltött és kicsomagolt 4 darab képet a png és a grid csomag segítségével.
szemethy <- readPNG("szemethy.png")
szemethy <- rasterGrob(szemethy, interpolate = T)
sisa <- readPNG("sisa.png")
sisa <- rasterGrob(sisa, interpolate = T)
szilagyi1 <- readPNG("szilagyi1.png")
szilagyi1 <- rasterGrob(szilagyi1, interpolate = T)
szilagyi2 <- readPNG("szilagyi2.png")
szilagyi2 <- rasterGrob(szilagyi2, interpolate = T)
Ezeket az annotate_custom()
függvénnyel adjuk hozzá a konyvespolc változóban tárolt diagramhoz. Itt nem használhatunk vektorokat, minden képet külön kell megadni. A függvény első paramétere a beolvasott képet tartalmazó változó neve, a többi magyarázata pedig a táblázatban látható.
Paraméter | Magyarázat |
---|---|
xmin | a kép bal alsó sarkának x koordinátája (numerikus érték) |
ymin | a kép bal alsó sarkának y koordinátája (numerikus érték) |
xmax | a kép jobb felső sarkának x koordinátája (numerikus érték) |
ymax | a kép jobb felső sarkának y koordinátája (numerikus érték) |
konyvespolc <- konyvespolc +
annotation_custom(szemethy,
xmin = 4,
ymin = 20,
xmax = 25,
ymax = 35) +
annotation_custom(szilagyi1,
xmin = 58,
ymin = 63,
xmax = 77,
ymax = 87) +
annotation_custom(szilagyi2,
xmin = 60,
ymin = 228,
xmax = 75,
ymax = 235) +
annotation_custom(sisa,
xmin = 90,
ymin = 15,
xmax = 100,
ymax = 27)
4. A feliratok hozzáadása
A feliratok esetében sajnos ugyanaz a helyzet, mint a vonalas díszítményeknél: a geom_text()
réteggel és a hátterében lévő adatkerettel valami miatt nem volt képes megbírkózni a rendszer és folyton szétesett az ábra. Ezért most is az annotate()
függvényt fogom használni. Ennek paraméterei vektorosan is megadhatók. Ezt a tulajdonságot kihasználva, a feliratok számától függetlenül könyvenként egy darab függvényt definiálok.
A függvény első paramétere a “text” karakterlánc, a továbbiak pedig az alábbi táblában felsorolva szerepelnek.
Paraméter | Magyarázat |
---|---|
x | a szöveg elhelyezkedésének x koordinátája (numerikus érték) |
y | a szöveg elhelyezkedésének y koordinátája (numerikus érték) |
label | maga a szöveg (karakterlánc) |
hjust | a szöveg vízszintes igazítása (numerikus érték) |
vjust | a szöveg függőleges igazítása (numerikus érték) |
angle | a szöveg elforgatásának szöge (numerikus érték) |
family | a szöveg betűtípusa (karakterlánc) |
size | a szöveg mérete (numerikus érték) |
fontface | a szöveg kiemelésének módja (karakterlánc) |
color | a szöveg színe (karakterlánc) |
A szöveg igazításánál általában 0 és 1 közötti értékeket használunk, ahol a két szélsőség a bal és a jobb oldalra, illetve a fentre és a lentre való igazítást jelenti. 0.5 esetén a szöveg közepe pontosan a paraméterként megadott koordinátára esik. Ugyanakkor használhatunk az intervallumból kilógó értékeket is, amivel nagyobb mértékű eltolást lehet elérni.
A family paraméternek csak akkor van hatása, ha az extrafont csomagot betöltöttük. A fontface paraméter esetén a “plain”, “bold”, “italic” és “bold.italic” értékeket használhatjuk.
konyvespolc <- konyvespolc +
annotate("text",
x = 15,
y = c(85,160),
label = c("Szemethy Tamás","KATONABÁRÓK ÉS\nHIVATALNOK GRÓFOK"),
hjust = 0.5,
vjust = 0.5,
angle = 90,
family = c("Calibri","Cambria"),
size = 10,
fontface = c("plain","bold"),
color = "#ffffff") +
annotate("text",
x = 42.5,
y = 210,
label = "Melkovics Tamás\nA REFORMKORI FŐRENDI ELENZÉK\nÉS 1839-40-ES ZÁSZLÓBONTÁSA",
hjust = 1,
vjust = 0.5,
angle = 90,
family = "Cambria",
size = 7,
color = "#000000") +
annotate("text",
x = 67.5,
y = c(14,100),
label = c("Szilágyi Adrienn","Az uradalom elvesztése"),
hjust = 0,
vjust = 0.5,
angle = 90,
family = c("Calibri","Rockwell"),
size = c(8,10),
fontface = "bold",
color = "#ffffff") +
annotate("text",
x = 95,
y = 40,
label = "Sisa József ~::~ KASTÉLYÉPÍTÉSZET ÉS KASTÉLYKULTÚRA MAGYARORSZÁGON",
hjust = 0,
vjust = 0.5,
angle = 90,
family = "Cambria",
size = 8,
color = "#e0de97") +
annotate("text",
x = 117.5,
y = c(35,80),
label = c("Valuch Tibor","Mindennapi történeteink"),
hjust = 0,
vjust = 0.5,
angle = 90,
family = "Bahnschrift",
size = 9,
color = c("#ffffff","#9b332a")) +
annotate("text",
x = 133.5,
y = c(42,76,130),
label = c("FÁBIÁN MÁTÉ","EGY FAJVÉDŐ FŐISPÁN\nA HORTHY-KORSZAKBAN","BORBÉLY-MACZKY EMIL (1887-1945)"),
hjust = 0,
vjust = 0.5,
angle = 90,
family = "Arial Nova Light",
size = 5,
color = c("#ffffff","#000000","#000000")) +
annotate("text",
x = 153,
y = c(30,30,185,80),
label = c("Cairo","Alberto","How Charts Lie","Getting Smarter about\nVisual Information"),
hjust = 0.5,
vjust = c(1.2,-0.2,0.5,0.5),
angle = 270,
family = "Calibri",
size = c(12,12,22,7),
fontface = "bold",
color = "#ffffff") +
annotate("text",
x = 179,
y = c(75,75,185,185,15),
label = c("DASHUN WANG","BARABÁSI ALBERT-LÁSZLÓ","A TUDOMÁNY","TUDOMÁNYA","L"),
hjust = 0.5,
vjust = c(-0.2,1.2,-0.2,1.2,0.5),
angle = c(90,90,90,90,0),
family = "Arial Narrow",
size = c(10,10,17,17,13),
fontface = c("bold","bold","bold","bold","plain"),
color = c("#ffffff","#ffffff","#07b3db","#07b3db","#ffffff"))
5. A diagram feliratainak felhelyezése és formázása
Végezetül a diagramot ellátom néhány felirattal és megformázom azokat.
konyvespolc <- konyvespolc +
labs(x = "A könyvespolc szélessége (mm)",
y = "A könyvespolc magassága (mm)",
caption = "https://aprogramozotortenesz.hu/") +
theme(
axis.text = element_text(size = 12),
axis.title = element_text(size = 15),
plot.caption = element_text(size = 15, face = "bold")
)
Magát a diagramot a konyvespolc változóban tároltuk el. Ezt a konzolba beírva elővarázsolhatjuk a kész ábrát. Íme!
konyvespolc
Egy furcsa diagram (kattintásra nagyítható)
Kellemes nyarat kívánok mindenkinek! 🕶️🌞🚣