Aprofundando as técnicas sobre gráficos

Vários outros pacotes estão disponíveis para a geração de gráficos em R. Entre eles estão os pacotes grid, lattice e ggplot2 que visam expandir as habilidades do sistema gráfico básico. grid fornece acesso de baixo nível às capacidades gráficas, geralmente usada por programadores, enquanto lattice fornece uma abordagem intuitiva para a análise de dados multivariados. Ambos são utilizadas por outros pacotes de geração gráfica e são instaladas por padrão na instalação do de R. Focaremos aqui nossa atenção sobre ggplot2.

Gráficos com ggplot2

ggplot2 é um pacote de visualização de dados criado por Hadley Wickham em 2005. Ele amplia e extende as funções gráficas básicas de R e contém vários padrões para exibição na web e para a impressão. O pacote é baseado no conceito de gramática de gráficos onde se pode construir todos os gráficos necessários à partir de alguns poucos componentes: o conjuntos de dados, informações para a elaboração estética do gráfico, elementos geométricos (marcas visuais para representar pontos plotados) e um sistema de coordenadas (cartesiano, polar, mapa, etc.). Apresentaremos aqui um resumo das funções. Para referências mais completas consulte os links no final este capítulo.

ggplot2 deve ser instalado separadamente ou dentro de um pacote de utilitários mais amplo que o inclui, o tidyverse.

As partes ou componentes de um gráfico são desenhadas em camadas. Todos os gráficos plotados são iniciados com uma chamada à função ggplot(). Em seguida, ou na mesma chamada, se fornece a fonte de dados (que deve ser um data frame) e as informações sobre a estética, especificados por aes(). Depois são acrescentadas as camadas, escalas, coordenadas e ângulo de perspectiva, usando-se +. Gráficos são gravados em disco com a função ggsave(). Observe que, diferente das outras funções gráficas vistas, ggplot() não aceita vetores como argumentos mas apenas data frames.

Hadley Wickhan, em seu livro R for Data Science, propõe uma forma forma geral ou template para se compreender a estrutura de ggplot2. Ele resume o pacote da seguinte forma:

ggplot(data = <DATA>) +
       <GEOM_FUNCTION> (
           mapping = aes(<MAPPINGS>),
           stat = <STAT>,
           position = <POSITION> ) +
       <COORDINATE_FUNCTION> +
       <FACET_FUNCTION>

O princípio subjacente é o de que qualquer gráfico pode ser construído com esses elementos (embora nem todos sejam obrigatórios). As funções facet permitem dividir o gráfico em partes que são plotadas juntas. É possível que em novas camadas se insira outra fonte de dados, diferente daquela passada na primeira camada.

ggplot() Cria um gráfico
+; %+% operador para inserção de camadas
aes() insere informações sobre eixos e estética do gráfico
ggsave() grava um objeto ggplot
qplot() quickplot() plotagem simplificada

Para ilustrar o conceito do gráfico construído por camadas considere o seguinte código:

> install.packages("tidyverse")
> library(ggplot2)
> data("mtcars")
> g <- ggplot(mtcars) # Inicializa o gráfico
> # Uma camada, contendo pontos, é inserida com geom_point.
> # Em aes() mapeamos as variáveis, definimos cores e tamanho dos pontos
> g <- g +
       geom_point(aes(x = hp, y = mpg, color = factor(am)), size = 3)

> # Para alterar as cores
> g <- g +
      scale_color_manual("Tipo",
                          values = c("darkred", "deepskyblue4"),
                          labels = c("Manuais", "Automáticos"))
> # Rótulos
> g <- g +
       labs(title = 'Consumo comparado de potência de carros automáticos e manuais',
            y = 'Consumo', x = 'Potência')
> print(g)

O gráfico é plotado:

> library(ggplot2)
> cidades <- data.frame(nome=c("SP", "Rio", "Bsb", "Salv", "BH"),
                        populacao=c(12.106, 6.520, 3.040, 2.953, 2.523))
> graf <-ggplot(cidades, aes(x=nome, y=populacao))
        + geom_bar(stat = "identity")
        + labs(title="População, em milhões")
> print(graf)        # gráfico-1 é plotado

> # Usando mtcars$cyl como fator
> a <- ggplot(mtcars, aes(factor(cyl)))
> b <- a + geom_bar()
> c <- a + geom_bar(fill="red")
> d <- a + geom_bar(fill="red", colour = "black")
> e <- a + geom_bar(fill=rainbow(3), colour = "black")

> print(b)           # gráfico (b) é plotado
> print(c)           # gráfico (c) é plotado
> print(d)           # gráfico (d) é plotado
> print(e)           # gráfico (e) é plotado


> f <- ggplot(data=mtcars, aes(x=wt, y=mpg)) + geom_point() +
              labs(title="Carros", x="Peso", y="Consumo: Miles/Galão")

> g <- ggplot(data=mtcars, aes(x=wt, y=mpg)) +
              geom_point(pch=20, color="steelblue", size=2) +
              geom_smooth(method="lm", color="red", linetype=2) +
              labs(title="Automóveis", x="Peso", y="Consumo")

> mtcars$am <- factor(mtcars$am, levels=c(0,1), labels=c("Automatico", "Manual"))
> mtcars$vs <- factor(mtcars$vs, levels=c(0,1), labels=c("Motor-V", "Motor Comum"))
> mtcars$cyl <- factor(mtcars$cyl)

> h <-ggplot(data=mtcars, aes(x=hp, y=mpg, shape=cyl, color=cyl)) +
             geom_point(size=3) + facet_grid(am~vs) +
             labs(title="Carros: por tipo de motor", x="Potência", y="Consumo")

> print(f)           # gráfico (f) é plotado
> print(g)           # gráfico (g) é plotado
> print(h)           # gráfico (h) é plotado

Nos códigos acima ggplot() inicializa o gráfico, informa que mtcars será o data frame a ser usado. aes() (que fornece a estética ou aparência do plot), mapeia o wt (peso) com o eixo x e mpg (milhas por galão, consumo) com o eixo y. Os objetos geométricos (geoms) são os responsáveis pelos elementos visíveis sobre os eixos coordenados, incluindo pontos, linhas, barras, caixas e áreas sombreadas. No gráfico (f) geom_point(), por padrão, marca pontos em (x, y) desenhando um gráfico de dispersão. A função labs() insere texto para os eixos.
No gráfico (g) geom_point() torna os pontos em esferas (pch=20), e define cor e tamanho. A função geom_smooth() insere uma linha vermelha tracejada (linetype=2) com ajuste linear definido pelo método (method=”lm”). A área sombreada representa intervalos de 95 % de confiança (default). Os gráficos plotados são mostrados abaixo:

Em (h) são traçados gráficos separados para os tipos de transmissão automática versus manual e tipo de motor. A cor e símbolo usado indicam o número de cilindros do carro (cyl) que também é a variável agrupadora.

No último gráfico (h) as cores para o parâmetro cyl foram escolhidas automaticamente. Para controlar manualmente este comportamento podemos usar scale_color_manual() como exibido abaixo:

> ggplot(iris,
         aes(x = Petal.Length, y = Petal.Width, color = Species)) +
         geom_point()
> ggplot(iris,
         aes(x = Petal.Length, y = Petal.Width, color = Species)) +
         geom_point() +
         scale_color_manual(values = c("steelblue", "gold3", "darkorange"))

Os seguintes gráficos são gerados:

A função scale_color_manual() foi usada porque a variável Species é categórica. Outras funções são usadas para controlar escalas de cor usando diferentes tipos de variiáveis. Existem outras como scale_color__discrete(), scale_color_continuous(), scale_color_gradient(), etc. Igualmente se pode controlar outras propriedades usando-se scale_fill, scale_x etc.

As funções geom

Através da função ggplot() determinamos a fonte dos dados e as variáveis a serem plotadas. Já as diversas funções geom (algumas delas listadas abaixo) informa como elas devem ser representadas graficamente.

Função Plota Opções
geom_bar() gráfico de barras color, fill, alpha
geom_boxplot() gráfico de caixas color, fill, alpha, notch, width
geom_density() gráfico de densidades color, fill, alpha, linetype
geom_histogram() histograma color, fill, alpha, linetype, binwidth
geom_hline() linhas horizontais color, alpha, linetype, size
geom_jitter() pontos espalhados color, size, alpha, shape
geom_line() gráfico de linhas colorvalpha, linetype, size
geom_point() gráfico de dispersão color, alpha, shape, size
geom_rug() gráfico “rug” color, side
geom_smooth() ajuste de linhas method, formula, color, fill, linetype, size
geom_text() anotações em texto Many; see the help for this function
geom_violin() gráfico violino color, fill, alpha, linetype
geom_vline() linhas verticiais color, alpha, linetype, size

As opções mais comuns são:

Opção Controla
color Cor de pontos, linhas e bordas
fill Cor de áreas preenchidas
alpha transparência de cores, de 0 (transparent) até 1 (opaco)
linetype padrão de linhas (1 = sólido, 2 = tracejado, 3 = pontos, 4 = ponto-traço, 5 = traço longo, 6 = duplo traço)
size tamanho de pontos e largura de linhas
shape símbolo do ponto (igual pch: 0 = quadrado vazio, 1 = círculo vazio, 2 = triângulo, …)
position posição de objetos plotados (barras e pontos)
binwidth largura da caixa de histograma
notch booleano, se caixas devem ser recortados
sides colocação de “rugs” (“b” = abaixo, “l” = esquerda, “t” = acima, “r” = direita, “bl” = abaixo à esquerda, etc
width largura de gráficos de caixas

Para os exemplos seguintes usaremos o data frame singer (incluído no pacote lattice) que contém alturas (em polegadas) e faixa vocal para cada cantor e cantora do “New York Choral Society”. As faixas são: Bass 2, Bass 1, Tenor 2, Tenor 1, Alto 2, Alto 1, Soprano 2 e Soprano 1.

> data(singer, package="lattice")
> ggplot(singer, aes(x=height))
        + geom_histogram(fill="red", colour = "black")
        + labs(title="Coral de New York", x="Altura", y="Contagem")
> # O gráfico (i) é plotado
> ggplot(singer, aes(x=voice.part, y=height))
        + geom_boxplot(fill="steelblue", colour = "black")
        + labs(title="Coral de New York", x="Faixa vocal", y="Altura")
> # O gráfico (j) é plotado

Note que no gráfico de histograma apenas a coordenada x foi especificada pois, nesse caso, o valor default de y é a contagem de observações incluídas dentro de cada retângulo. Como aes() está inserido dentro de ggplot() todos os parâmetros definidos ali serão globais, valendo para todas as camadas (se não for novamente informado dentro de outra função de camada).

Para o exemplo que se segue usaremos o data frame Salaries que contém salários de algumas categorias de professores do ensino superior dos EUA no período de 2008-2009 (apenas 9 meses). Ele contém observações sobre algumas variáveis, incluindo sex e salary.

> library(car)
> # Para listar o sexo em português inserimos um novo campo
> Salaries$sexo <- ifelse(Salaries$sex=="Male", "Homem", "Mulher")

> ggplot(Salaries, aes(x=sexo, y=salary)) +
    geom_boxplot(fill="skyblue3", color="black", notch=TRUE) +
    geom_point(color="yellow", alpha=.5) +
    geom_rug(sides="r", color="darkgrey") +
    geom_jitter(position = position_jitter(width = .1),
                alpha = 0.5, color="darkred") +
    labs(title="Salário de professores (EUA)", x="Sexo", y = "Salário")

O seguinte gráfico é plotado:

O gráfico inclui caixas chanfradas (notch) azuis com bordas pretas. Os pontos, correspondentes às observações, são plotados em amarelo, com transparência .5. Observe que todos os pontos amarelos se acumulam sobre a linha vertical correspondentes aos dois sexos, uma vez que todos possuem uma das duas coordenadas no eixo x. Uma nova camada foi inserida através de um espalhamento aleatório (jitter) sobre estes pontos, usando-se geom_jitter() que são plotados em vermelho escuro. Este espalhamento não tem significado estatístico e serve apenas para facilitar a visualização dos pontos. Os dois conjuntos foram mantidos aqui apenas para efeito didático. Poderíamos ter inserido o efeito usando geom_point(position="jitter") junto que os demais parâmetros e omitindo geom_jitter(). Nesse caso os pontos amarelos ficariam dispersos. geom_rug() insere marcas em cinza na lateral direita, correspondentes às posições (y) dos pontos. Os lados podem ser sides = "rltd", alguma das letras ou combinações delas: right, left, top, down.

Agrupamentos

Muitas vezes é útil observar no mesmo gráfico grupos de observações diferentes. Já vimos que podemos agrupar dados em R usando fatores (ou variáveis de categorias). No pacote ggplot2 os agrupamentos ficam definidos pela associação de variáveis com características visuais como forma, cor, preenchimento, tamanhos e tipo de linha, em geral definidas dentro da função aes().

> ggplot(Salaries, aes(x=rank, fill=sexo)) +
       geom_bar(position="stack") +
       labs(title='position="stack"')

> ggplot(Salaries, aes(x=rank, fill=sexo)) +
       geom_bar(position="dodge") +
       labs(title='position="dodge"')

> ggplot(Salaries, aes(x=rank, fill=sexo)) +
       geom_bar(position="fill") +
       labs(title='position="fill"')

O código resulta, respectivamente nos seguintes gráficos, onde o agrupamento se deu por meio do parâmetro fill:

Mais de uma propriedade podem ser usadas para um agrupamento, como se vê no gráfico plotado pelo código abaixo.

> ggplot(data=Salaries, aes(x=salary, fill=rank)) +
       geom_density(alpha=.3) +
       labs(title="Salários de Professores",
             x="Salário", y="Número de Professores")
ggplot(data=Salaries, aes(x=salary, fill=rank, color=sexo)) +
       geom_density(alpha=.3) +
       labs(title="Salários Masc x Fem", x="Salário",
       y="Número de Professores")

No segundo gráfico o agrupamento foi feito através dos parâmetros fill e color:

Apesar de estar pouco nítido e não muito útil para uma análise, o gráfico representa 6 distribuições diferentes para as combinações de sexo =”Masculino” e “Feminino” e rank = “Prof”, “AssistProf” e “AssocProf”. O rank está representado pelo preenchimento (fill) e o sexo pela cor da borda (color) em cada distrinuição.

Gráficos em subplos (facet)

O último gráfico plotado apreenta 6 distribuições sobrepostas, pouco úties para uma visualização dos dados. Pode ser mais interessante analisar grupos diferentes olhando gráficos separados, apresentados lado a lado. No ggplot2 estes gráficos são chamados de facetados (faceted graphs) e são criados com as funções facet_wrap() e facet_grid():

Função

Resultado
facet_wrap(~var, ncol=n) gráficos separados para cada nível de var, dispostos em colunas
facet_wrap(~var, nrow=n) gráficos separados para cada nível de var, disposto em linhas
facet_grid(rowvar~colvar) gráficos separados para cada nível de rowvar e colvar
facet_grid(rowvar~.) gráficos separados para cada nível de rowvar, dispostos em uma coluna
facet_grid(.~colvar) gráficos separados para cada nível de colvar, dispostos em uma linha

Na tabela var, rowvar, colvar são fatores, rowvar representa linhas colvar representa colunas.

Nos exemplos abaixo usamos o mesmo gráfico congestionado do caso anterior, onde 6 distribuições estavam representadas. No primeiro caso desdobramos as plotagens em 2 linhas, separadas por sexo. No segundo 3 gráficos são dispostos em uma coluna, 3 linhas, separados por rank.

> ggplot(data=Salaries, aes(x=salary, fill=rank, color=sexo)) +
          geom_density(alpha=.3) +
         labs(title="Salários Masc x Fem",
               x="Salário", y="Número de Professores") +
         facet_wrap(~sexo, nrow=2)

> ggplot(data=Salaries, aes(x=salary, fill=rank, color=sexo)) +
         geom_density(alpha=.3) +
         labs(title="Salários Masc x Fem",
              x="Salário", y="Número de Professores") +
         facet_wrap(~rank, nrow=3)

Em uma ordenação de facetas dividida por um fator com 8 elementos, distribuídos em 4 linhas, ficam dois plots lada a lado em cada linha:

> ggplot(data=singer, aes(x=height)) + geom_histogram() +
         labs(title="Cantores", x="Altura", y="Número de cantores") +
         facet_wrap(~voice.part, nrow=4)

Adicionando curvas e ajustes estatísticos

Além da construção de gráficos customizados, ggplot2 permite incluir nesses gráficos informações processadas por meio de funções estatísticas de análise. Estas funções permitem o agrupamento de dados, o cálculo de densidades, contornos e quantis. Usando a função geom_smooth() podemos adicionar aos gráficos de dispersão linhas suavizadas (linear, não linear e não paramétricas) e sombreamentos para intervalos de confiança.

Parâmetro Descrição
method= método de suavização: lm, glm, smooth, rlm, e gam (linear, linear generalizado, loess, linear robusto ou aditivo generalizado). smooth é o default.
formula= fórmula para a função de suavização. Exemplos: y~x (default), y~log(x), y~poly(x,n) para ajuste a polinômio de n-ésimo grau e y~ns(x,n) para um ajuste de spline com n graus de liberdade.
se booleano, default=TRUE. Plota intervalos de confiança.
level nível para intervalos de confiança (default de 95%).
fullrange booleano, default=FALSE. Se o ajuste deve incluir toda a faixa do plot (TRUE) ou apenas os dados.

LOESS suavização de dispersão estimada localmente (locally estimated scatterplot smoothing).

> library(dplyr)
> carros <- mtcars %>% mutate(carro=rownames(mtcars))

> carro1 <- ggplot(carros, aes(x=disp, y=mpg)) + geom_point() + geom_smooth()

> carro2 <- ggplot(data=carros, aes(x=disp, y=mpg, color=carb)) +
            geom_smooth(method=lm, formula=y~x, size=1) +
            geom_point(size=2)

> carro3 <- ggplot(data=carros, aes(x=disp, y=mpg, color=carb)) +
            geom_smooth(method=lm, formula=y~poly(x,2), size=1) +
            geom_point(size=2)

> carro4 <- ggplot(data=carros, aes(x=disp, y=mpg, color=carb)) +
          geom_smooth(method=lm, formula=y~poly(x,2), size=1, se=FALSE) +
          geom_point(size=2)
          
> print(carro1)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
> print(carro2)
> print(carro3)
> print(carro4)
> # os gráficos carro1, carro2, carro3 e carro4 são plotados.

Para o gráfico carro1 nenhum parâmetro foi fornecido. geom_smooth() adotados os defaults method = 'loess', formula 'y ~ x', como é informado no console. Em carro2 uma reta de melhor ajuste é plotada. Em carro3 uma curva de segundo grau de melhor ajuste é plotada.
A mesma curva é repetida em carro4 sem a representação dos intervalos de confiança.

Observe que o data frame carros foi criado à partir de mtcars com a função mutate() da biblioteca dplyr. Ela permite a criação de uma nova variável para o data frame existente. Além usamos o pipe:

> mtcars %>% mutate(carro=rownames(mtcars))
> # que é o mesmo que:
> mutate(mtcars, carro=rownames(mtcars))	

A biblioteca ggplot2 incluiu um grande número de funções estatísticas para facilitar a visualização de dados. Estas funções podem ser chamadas implicitamente, sem chamadas do usuário. geom_smooth(), por exemplo, faz uso de stat_smooth() para encontrar a curva de melhor ajuste aos dados e os intervalos de confiança. É sempre útil consultar as páginas de ajuda para estas funções, por exemplo através de ?stat_smooth().

Temas

ggplot2 traz em sua instalação alguns temas prontos que modificam a aparência de um gráfico e a possibilidade da modificação ou criação personalizada destes temas. As opções da função theme() permitem o ajuste de fonts, planos de fundo, cores, linhas de grade, tamanho da fonte do eixo x, posição da legenda, etc. Para cada elemento do tema existe um tipo de objeto que realiza as alterações. Por exemplo, o estilo do título do eixo x (axis.title.x) é alterado com a função element_text() que possui diversos parâmetros (família da fonte, tipo da fonte, cor, tamanho, alinhamento etc.). As principais funções para se alterar elementos de um tema são element_text(), element_line(), element_rect() e element_blank(). O útilmo é usado para que nada seja desenhado no elemento que recebe esta função.

Um exemplo simples de uso de temas é mostrado, através da aplicação do tema theme_dark():

> library(lattice)   # Para usar o data frame singer
> ggplot(data=singer, aes(x=height, fill=voice.part)) +
         geom_density() +
         facet_grid(voice.part~.)
> ggplot(data=singer, aes(x=height, fill=voice.part)) +
         geom_density() +
         facet_grid(voice.part~.) + theme_dark()

Para quem usa o RStudio existe um add-in que permite a customização gráfico do ggplot2 através de uma interface com o usuário que usa atalhos de teclado e interação com o mouse chamada ggThemeAssist. Com ela o usuário pode alterar temas do forma WYSIWYG, usando tentativa e erro. O pacote deve ser instalado com install.packages("ggThemeAssist").

Para usar este add-in é necessário criar um objeto gráfico do ggplot2 e depois usá-lo como parâmetro em ggThemeAssistGadget. Uma janela é aberta com acesso à vários elementos da geometria do gráfico. Quando a janela é fechada a função retorna uma linha de comando contendo os parâmetros para que seja plotado o gráfico escolhido. O procedimento e resultado aparecem no código abaixo.

> library(ggThemeAssist)
> pp <- ggplot(data=singer, aes(x=height, fill=voice.part)) +
               geom_density() + facet_grid(voice.part~.)
> ggThemeAssistGadget(pp)
> # Uma janela é aberta onde os parâmetros podem ser alterados interativamente.
> # A linha abaixo é retornada:
> pp + theme(plot.subtitle = element_text(colour = "bisque4",
             vjust = 1), plot.caption = element_text(vjust = 1),
             axis.title = element_text(family = "Bookman",
             size = 14), plot.title = element_text(family = "Bookman"),
             legend.title = element_text(family = "Bookman"),
             panel.background = element_rect(fill = "cornsilk2"),
             legend.key = element_rect(colour = "antiquewhite4"),
             legend.background = element_rect(fill = "lavenderblush1")) +
             labs(title = "Número de cantores x Altura", x = "Altura",
             y = "Número de cantores",
             subtitle = "Exemplo de Uso do ggThemeAssistGadget",
             caption = "Gráfico demonstrativo")
> # O gráfico plotado aparece na imagem abaixo.

Múltiplos gráficos por página e salvando gráficos

Para os gráficos plotados pelo sistema base de R é possível combinar vários gráficos em um único com o uso da função layout() e o parâmetro mfrow. Com o pacote ggplot2 gráficos podem ser combinados em uma figura única com a função grid.arrange().
O código ilustra este procedimento.

> install.packages("gridExtra")
> library(gridExtra)
> data(Salaries, package="car")
> library(ggplot2)
> p1 <- ggplot(data=cars, aes(x=speed)) + geom_bar(fill=rainbow(19))
> p2 <- ggplot(data=cars, aes(x=dist)) + geom_bar() 
> p3 <- ggplot(data=cars, aes(x=speed, y=dist)) + geom_point(color="red")
> grid.arrange(p1, p2, p3, ncol=3)

> ggsave(file="grafico-3.png", plot=p3, width=5, height=4)
> print(p1)
> ggsave(file="grafico-1.pdf")

Observe que neste caso estamos plotando gráficos independentes em uma simples figura, o que é diferente do que foi feito com a função facet onde se representava gráficos construídos sobre um mesmo data frame mas separados por variáveis categóricas.

A função ggsave() é usada para gravar os gráficos. A primeira chamada acima grava, na pasta ativa, uma imagem grafico-3.png com 5×4 polegadas. A segunda, onde se omitiu o parâmetro plot, grava um arquivo pdf com o último gráfico plotado, no caso o gráfico p1.

 


Aquisição de Dados