2 Galerija grafika

U nastavku je dat seminarski rad iz Statističkog softvera 1, pod naslovom “Paketi za grafičko predstavljanje”, čiji su autori koleginice Aida Al-Raghyfi i Nataša Martinović. Zahvaljujemo im na vrlo interesantnim primerima vizuelizacija mogućih paketom ggplot, kao i na prikazu drugih paketa za interaktivne grafike.

Napomena. Radi brzine učitavanja, paketi plotly i highcharter su podeljeni u svoje stranice, koje su dostupne u sadržaju sa leve strane.

Uvod

Grafičko predstavljanje podataka je metod koji prikazuje vrednosti, izveštaje, upoređuje rezultate ili daje predviđanja o toku određenih situacija. To je vizuelni prikaz podataka kroz grafikone.

U ovom radu, bavićemo se paketima: ggplot2, plotly i highcharter.


2.1 Ggplot2

Paket ggplot2 je jedan od najkorisnijih i najzastupljenijih paketa u R-u. Ima dosta različitu sintaksu od sintakse klasičnih grafika, i samim tim zahteva malo više učenja, ali najveća prednost ovog paketa je što se sa malo koda prave estetski bogati grafici.

Paket ggplot2 se zasniva na takozvanoj “gramatici grafike”. Grafici se prave “sabiranjem”, odnosno dodajemo komponentu po komponentu na grafik. Glavni delovi koje grafik ima su:

  1. Podaci (data): Skup podataka koji se prikazuje
  2. Geometrijski objekat (geom_*): Tip geometrijskog objekta kojim se prikazuju podaci.
  3. Estetski parametri (aes()): Estetski atributi koji se mogu dodeliti geometrijskim objektima.

Sada ćemo proći kroz par jednostavnih primera

library(ggplot2)
data("midwest", package = "ggplot2")  
 midwest <- read.csv("http://goo.gl/G1K41K")  
#Za primer koristićemo skup podataka midwest iz paketa ggplot2. Ovo je skup podataka populacije svih okruga od 5 država srednjeg zapada SAD-a.

g<-ggplot(midwest, aes(x=area, y=poptotal)) +  geom_point(col="steelblue",  size=3) +   #funkcija geom_point tačakama predstavlja svaki okrug iz naše tabele 
  geom_smooth(method="lm", col="firebrick") #funkcija geom_smooth pravi određenu aproksimaciju podataka, u ovom slučaju je to linearni model, ali može biti i nelinearni model, što ćemo videti kasnije
g

g + xlim(c(0, 0.1)) + ylim(c(0, 1000000)) #Pošto se tačke većinom nalaze na donjoj polovini, funkcijom xlim/ylim možemo da posmatramo grafik u granicama koje mi odredimo, i na taj način obrišemo tačke van tih granica
## Warning: Removed 5 rows containing non-finite values (stat_smooth).
## Warning: Removed 5 rows containing missing values (geom_point).

g1<-g+coord_cartesian(xlim=c(0, 0.1), ylim=c(0, 1000000)) #Ili funkcijom coord_cartesian() da zumiramo grafik u delu koji nama odgovara
g1 + ggtitle("Area Vs Population", subtitle="From midwest dataset") + xlab("Area") + ylab("Population") #Funkcija za stavljanje naslova i podnaslova

gg <- ggplot(midwest, aes(x=area, y=poptotal)) + 
  geom_point(aes(col=state,size=popdensity)) +  #Stavljamo da svaki okrug ima svoju boju u zavisnoti od toga u kojoj državi se nalazi i veličinu u zavisnosti od gustine naseljenosti
  geom_smooth(method="loess", col="firebrick", size=2) + #ovde možemo videti nelinearni metod aproksimacije podataka
  coord_cartesian(xlim=c(0, 0.1), ylim=c(0, 1000000)) + #ograničavamo gornje i donje vrednosti koordinatnih osa
  labs(title="Area Vs Population", subtitle="From midwest dataset", y="Population", x="Area", caption="Midwest Demographics")
plot(gg)

#Sada ćemo da izdvojimo i zaokružimo okruge koji imaju između 350000 i 500000 stanovnika i sa površinom izmedju 0.01 i 0.1
library(ggalt)
## Registered S3 methods overwritten by 'ggalt':
##   method                  from   
##   grid.draw.absoluteGrob  ggplot2
##   grobHeight.absoluteGrob ggplot2
##   grobWidth.absoluteGrob  ggplot2
##   grobX.absoluteGrob      ggplot2
##   grobY.absoluteGrob      ggplot2
midwest_select <- midwest[midwest$poptotal > 350000 & 
                            midwest$poptotal <= 500000 & 
                            midwest$area > 0.01 & 
                            midwest$area < 0.1, ]

ggplot(midwest, aes(x=area, y=poptotal)) + 
  geom_point(aes(col=state, size=popdensity)) +   
  geom_smooth(method="loess", se=F) + 
  xlim(c(0, 0.1)) + 
  ylim(c(0, 500000)) +   
  geom_encircle(aes(x=area, y=poptotal), 
                data=midwest_select, 
                color="red", 
                size=2, 
                expand=0.08) +
  labs(subtitle="Area Vs Population", 
       y="Population", 
       x="Area", 
       title="Scatterplot + Encircle", 
       caption="Source: midwest")
## Warning: Removed 15 rows containing non-finite values (stat_smooth).
## Warning: Removed 15 rows containing missing values (geom_point).

#Sada posmatramo skup podataka mpg iz paketa ggplot2, odnosno uzeti su podaci iz Motor Trend US magazina, iz 1974. godine, koji obuhvataju potrošnju goriva i 10 aspekata dizajna automobila i performanse za 32 automobila.

data(mpg, package="ggplot2") 
mpg <- read.csv("http://goo.gl/uEeRGu")
g <- ggplot(mpg, aes(x=displ, y=hwy)) + 
  geom_point() + 
  geom_smooth(method="lm", se=FALSE) + 
  theme_bw()  

mpg1<-g + facet_wrap( ~ class, nrow=3) + labs(title="hwy vs displ", caption = "Source: mpg", subtitle="Ggplot2 - Faceting - Multiple plots in one figure")  
#Funkcija facet_wrap() omogućava predstavljanje jednog grafika pomoću više manjih grafika za kategorije koje mi želimo
#Koristeći nrow biramo broj vrsta u kojima će se nalaziti manji grafici
mpg1

mpg2<-g + facet_wrap( ~ class, scales = "free") + labs(title="hwy vs displ", caption = "Source: mpg", subtitle="Ggplot2 - Faceting - Multiple plots in one figure with free scales") 
#Dok sa scales="free" program sam odabere
mpg2

#U ovom konkretnom primeru, upoređujući dobijene manje grafike zaključujemo da sportski automobili koji imaju velike motore, a malu masu troše manje nego pickup i minivan
#Sada prikazujemo estetske promene, kao što su: menjanje boje pozadine, menjanje debljine i boje svih unutrašnjih linija, kao i ivica i x/y-osa
g <- ggplot(mpg, aes(x=displ, y=hwy)) + 
  geom_point() + 
  geom_smooth(method="lm", se=FALSE) + 
  theme_bw()

g + theme(panel.background = element_rect(fill = 'khaki'),
          panel.grid.major = element_line(colour = "burlywood", size=1.5),
          panel.grid.minor = element_line(colour = "tomato", 
                                          size=.25, 
                                          linetype = "dashed"),
          panel.border = element_blank(),
          axis.line.x = element_line(colour = "darkorange", 
                                     size=1.5, 
                                     lineend = "butt"),
          axis.line.y = element_line(colour = "darkorange", 
                                     size=1.5)) +
  labs(title="Modified Background", 
       subtitle="How to Change Major and Minor grid, Axis Lines, No Border")

#Po želji se mogu menjati i margine grafika
g + theme(plot.background=element_rect(fill="salmon"), 
          plot.margin = unit(c(2, 2, 1, 1), "cm")) +  # gore,desno,dole,levo
  labs(title="Modified Background", subtitle="How to Change Plot Margin") 

Sada ćemo prikazati još neke tipove geometrijskih objekata kojim se prikazuju podaci.


2.1.1 Linijski grafici

Za crtanje vremenski uređenih podataka, poput vremenskih serija, standardni grafici su linijski. To je prosto linija koja prikazuje kretanje neke promenljive kroz vreme.

#Za primer koristićemo skup podataka economics iz paketa ggplot2.
data("economics", package = "ggplot2")

ggplot(economics, aes(x = date, y = psavert)) +
  geom_line(color = "darkgreen") +
  geom_smooth() + 
  scale_x_date(date_breaks = "5 years", date_labels = "%b %Y") +
  labs(x = "Mesec", y = "Stopa stednje") #Funkcijom scale_x_date možemo da odaberemo na koliko godina ćemo da pratimo promene, u ovom konkretnom slučaju smo stavili 5 (“%b” u formatu označava mesec a “%Y” godinu, pa možemo da menjamo i redosled)
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'


2.1.2 Stacked area chart

Sličan linijskom grafiku, s tim da je oblast ispod linija obojen. Koristimo ga kada želimo da vidimo kako se kvantitet promenio kroz vreme, kada prikazujemo udeo individualnih komponenata. Treba primetiti jednu bitnu stvar, po default-u svaka geom_area() počinje od y-ose(što je obično 0), ali ako želimo da prikažemo udeo individualnih komponenata, potrebno je da svaka geom_area() bude naslagana jedna na drugu. S toga ćemo u sledećem primeru staviti y=stopastednje+srednjetrajanjenezaposlenosti

library(lubridate)
## 
## Attaching package: 'lubridate'
## The following object is masked from 'package:base':
## 
##     date
theme_set(theme_bw())

df <- economics[, c("date", "psavert", "uempmed")] #pravimo kolonu sa potrebnim vrednostima
df <- df[lubridate::year(df$date) %in% c(1967:1981), ]

brks <- df$date[seq(1, length(df$date), 12)]  #podele za x-osu, na svakih 12 meseci
lbls <- lubridate::year(brks) #oznake koje će biti na x-osi


ggplot(df, aes(x=date)) + 
  geom_area(aes(y=psavert+uempmed, fill="psavert")) + 
  geom_area(aes(y=uempmed, fill="uempmed")) + 
  labs(title="Area Chart of Returns Percentage", 
       subtitle="From Wide Data format", 
       caption="Source: Economics", 
       y="Returns %") +  
  scale_x_date(labels = lbls, breaks = brks) +
  scale_fill_manual(name="", 
                    values = c("psavert"="#00ba38", "uempmed"="#f8766d")) # boja linija


2.1.3 Sezonski grafik

Ako radimo sa vremenskim serijama klase ts ili xts, možemo da vidimo sezonske fluktuacije pomoću sezonskih grafika koristeći forecast::ggseasonplot.

#install.packages("forecast")
library(ggplot2)
library(forecast)
## Registered S3 method overwritten by 'xts':
##   method     from
##   as.zoo.xts zoo
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
## Registered S3 methods overwritten by 'forecast':
##   method             from    
##   fitted.fracdiff    fracdiff
##   residuals.fracdiff fracdiff
theme_set(theme_classic())
#Uzimamo podatke o sezonskim promenenama broja putnika na međunarodnim letovima, kao i o sezonskim promenama vazdušne temperature u Nottingham Castle-u

nottem_small <- window(nottem, start=c(1920, 1), end=c(1925, 12))  # uzimamo manji vremenski period


#Sezonske promene broja putnika na međunarodnim letovima
ggseasonplot(AirPassengers) + labs(title="Seasonal plot: International Airline Passengers")

#Sezonske promene vazdušne temperature u Nottingham Castle-u
ggseasonplot(nottem_small) + labs(title="Seasonal plot: Air temperatures at Nottingham Castle")


2.1.4 Bar plotovi

Bar plotovi nam služe za grafički prikaz kategoričkih promenljivih. Na njima se prikazuje koliko postoji podataka u bazi iz odgovarajuće kategorije.

#Prebrojimo iz baze mpg broj automobila po klasi
ggplot(mpg, aes(x = class)) +
  geom_bar(fill = "forestgreen", color = "black")

#Bar plotovi mogu biti i naslagani, da prikazuju više vrednosti za istu kategoriju odjednom. 
#Nacrtaćemo bar plot gde se vidi populacija za 1997., 2002. i 2007. godinu izabranih zemalja.
#position = "dodge" nam pomaže da lakše čitamo vrednosti sa grafika, tako što ih stavlja jednu do druge
library(gapminder)

# napravimo kratak spisak država koje ćemo gledati i upoređivati populacije tokom određenih godina
countries <- c( "Turkey", "Argentina", "Australia", "Belgium")

gm <- gapminder[(gapminder$year %in% c(1997, 2002, 2007)) &
                            (gapminder$country %in% countries), ]
ggplot(gm, aes(x = country, y = pop)) +
  geom_col(color = "black", mapping = aes(fill = factor(year)), position = "dodge")


2.1.5 Lollipop grafik

U suštini sadrži iste informacije kao bar plot, s tim što ih redukuje u tanke linije, pa samim tim izgledaju lepše i modernije.

library(ggplot2)
theme_set(theme_bw())

ggplot(gm, aes(x = country, y = pop,label=year)) + 
  geom_point(size=3) + 
  geom_segment(aes(x=country, 
                   xend=country, 
                   y=0, 
                   yend=pop)) + 
  labs(title="Lollipop Chart" 
      ) + 
  theme(axis.text.x = element_text(angle=65, vjust=0.6)) + #udaljenost naziva država od linije x-ose
  geom_text(nudge_x = 0.2 ) #udaljenost godina od tačkica


2.1.6 Dumbbell plot

Koristimo ga ako želimo da predstavimo rast i opadanje između dve tačke u vremenu i poredimo udaljenost između dve kategorije

#Posmatramo bazu podataka health koja nam daje procente iz 2013. i 2014. za 26 gradova u SAD-u.

##devtools::install_github("hrbrmstr/ggalt")
library(ggplot2)
library(ggalt)
theme_set(theme_classic())

health <- read.csv("https://raw.githubusercontent.com/selva86/datasets/master/health.csv")
health$Area <- factor(health$Area, levels=as.character(health$Area))  #za pravilno uređenje ovih tegića

 ggplot(health, aes(x=pct_2013, xend=pct_2014, y=Area, group=Area)) + 
  geom_dumbbell( 
    color="blue", 
    size=0.75, 
    ) + 
  
  labs(x=NULL, 
       y=NULL, 
       title="Dumbbell Chart", 
       subtitle="Pct Change: 2013 vs 2014", 
       caption="Source: https://github.com/hrbrmstr/ggalt") +
  theme(plot.title = element_text(hjust=0.5, face="bold"),
        plot.background=element_rect(fill="#f7f7f7"),
        panel.background=element_rect(fill="#f7f7f7"),
        panel.grid.minor=element_blank(),
        panel.grid.major.y=element_blank(),
        panel.grid.major.x=element_line(),
        axis.ticks=element_blank(),
        legend.position="top",
        panel.border=element_blank())


2.1.7 Histogram

Gruba ocena raspodele uzorka se može vizuelizovati histogramima, gde brojimo koliko elemenata uzorka upada u odgovarajuće kategorije. Koristeći histogram, možemo da kontrolišemo broj pravougaonika, takođe možemo odabrati koliki interval pokriva svaki pravougaonik.

library(ggplot2)
 theme_set(theme_classic())

 ##Ponovo posmatramo automobile, i posmatramo broj vozila određene klase po zapremini motora
 g <- ggplot(mpg, aes(displ)) + scale_fill_brewer(palette = "Spectral")
 
 g + geom_histogram(aes(fill=class), 
                    binwidth = .1, 
                    col="black", 
                    size=.1) + 
   labs(title="Histogram sa automatskim brojem pravougaonika", 
        subtitle="Engine Displacement across Vehicle Classes")  

 g + geom_histogram(aes(fill=class), 
                    bins=5, 
                    col="black", 
                    size=.1) +   
   labs(title="Histogram sa fiksiranim brojem pravougaonika", 
        subtitle="Engine Displacement across Vehicle Classes") 


2.1.8 Grafik gustine

Grafik gustine predstavlja raspodelu podataka u kontinuiranom intervalu ili vremenskom periodu. To je zapravo verzija histograma koja glatko iscrtava vrednosti kako bi se izbegli grubi prelazi.

library(ggplot2)
 theme_set(theme_classic())
#I dalje posmatramo mpg bazu podataka i pravimo grafik gustine gradske kilometraže u odnosu na broj cilindara
 
#Podešavamo alfa transparentnost i bojimo gustine u odnosu na broj cilindara 
 g <- ggplot(mpg, aes(cty))
 g + geom_density(aes(fill=factor(cyl)), alpha=0.8) + 
   labs(title="Density plot", 
        subtitle="City Mileage Grouped by Number of cylinders",
        caption="Source: mpg",
        x="City Mileage",
        fill="# Cylinders")


2.1.9 Boks plot

Boks plot predstavlja grafički prikaz 5 sumarnih statistika - minimum, 1. kvartil, medijanu, 3. kvartil i maksimum.

 library(ggplot2)
 theme_set(theme_classic())

#Stavljanjem varwidth=T podešavamo da debljina boksova bude proporcionalna broju vrednosti koje sadrži
#Posmatramo gradsku kilometražu grupisanu po klasi vozila
 g <- ggplot(mpg, aes(class, cty))
 g + geom_boxplot(varwidth=T, fill="plum") + 
   labs(title="Box plot", 
        subtitle="City Mileage grouped by Class of vehicle",
        caption="Source: mpg",
        x="Class of Vehicle",
        y="City Mileage") 


2.1.10 Violinski grafik

Sličan je box plotu, ali pokazuje gustinu unutar grupa. Ne prikazuje toliko informacija kao box plot.

 library(ggplot2)
 theme_set(theme_bw())

 g <- ggplot(mpg, aes(class, cty))
 g + geom_violin() + 
   labs(title="Violin plot", 
        subtitle="City Mileage vs Class of vehicle",
        caption="Source: mpg",
        x="Class of Vehicle",
        y="City Mileage")


2.1.11 Populaciona piramida

Predstavlja unikatan način predstavljanja koliki procenat populacije spada u određenu kategoriju. Piramida ispod je odličan primer toga koliko korisnika se zadrži na svakoj fazi e-mail marketinške kampanje.

 #install.packages("ggthemes")
 library(ggplot2)
 library(ggthemes)
 
#baza podataka koju posmatramo
 email_campaign_funnel <- read.csv("https://raw.githubusercontent.com/selva86/datasets/master/email_campaign_funnel.csv")
 
 #podele koje će se nalaziti na x-osi i oznake
 brks <- seq(-15000000, 15000000, 5000000)
 lbls = paste0(as.character(c(seq(15, 0, -5), seq(5, 15, 5))), "m")
 
 
 ggplot(email_campaign_funnel, aes(x = Stage, y = Users, fill = Gender)) +   #x-osa sadrži faze, dok y-osa sadrži broj korisnika, i bojimo naše pravougaonike u odnosu na pol korisnika 
   geom_bar(stat = "identity", width = .6) +   # crtanje pravougaonika
   scale_y_continuous(breaks = brks,   # podele
                      labels = lbls) + # oznake
   coord_flip() +  # zamena osa
   labs(title="Email Campaign Funnel") +
   theme_tufte()  + # Tufte theme iz ggfortify
   theme(plot.title = element_text(hjust = .5)) + #podešavanje i centriranje naslova
    scale_fill_brewer(palette = "Dark2") #biramo paletu boja za naše pravougaonike


2.1.12 Pitica

Pitica (ili kružni dijagram) je kružni statistički grafik koji je podeljen na parčiće. Površina svakog parčića je proporcionalna količini koju predstavlja.

#Sada ćemo piticom da predstavimo odnos broja vozila svih ponudjenih klasa
 pie <- ggplot(mpg, aes(x = "", fill = factor(class))) + 
   geom_bar(width = 1) +
   theme(axis.line = element_blank(), #izbacujemo x-osu i y-osu 
         plot.title = element_text(hjust=0.5)) + #podešavamo i centriramo naslov
   labs(fill="class", 
        x=NULL, 
        y=NULL, 
        title="Pie Chart of class", 
        caption="Source: mpg")
 
 pie + coord_polar(theta = "y")


2.1.13 Hijerarhijski dendrogram

Pomoću njih grupišemo objekte, koji su slični u nekom smislu, u grupe koje se zovu klasteri i zatim pravimo hijerarhijsku vezu.

#U narednom primeru ćemo hijerarhijski predstaviti broj uhapšenih kriminalaca na 100000 ljudi u svim državama SAD-a.

 #install.packages("ggdendro")
 library(ggplot2)
 library(ggdendro)
 theme_set(theme_bw())
 
 hc <- hclust(dist(USArrests), "ave") #hijerarhijski klastering, metoda "average"
 
 ggdendrogram(hc, rotate = T, size = 2)