Pokazywanie wartości danych na skumulowanym wykresie słupkowym w ggplot2

112

Chciałbym pokazać wartości danych na skumulowanym wykresie słupkowym w ggplot2. Oto mój próbowany kod

Year      <- c(rep(c("2006-07", "2007-08", "2008-09", "2009-10"), each = 4))
Category  <- c(rep(c("A", "B", "C", "D"), times = 4))
Frequency <- c(168, 259, 226, 340, 216, 431, 319, 368, 423, 645, 234, 685, 166, 467, 274, 251)
Data      <- data.frame(Year, Category, Frequency)
library(ggplot2)
p <- qplot(Year, Frequency, data = Data, geom = "bar", fill = Category,     theme_set(theme_bw()))
p + geom_text(aes(label = Frequency), size = 3, hjust = 0.5, vjust = 3, position =     "stack") 

wprowadź opis obrazu tutaj

Chciałbym pokazać te wartości danych w środku każdej części. Każda pomoc w tym zakresie będzie bardzo mile widziana. Dzięki

MYaseen208
źródło
Powiązane pytanie: stackoverflow.com/questions/18994631/ ...
Tyler Rinker
Właściwie nie jest to miejsce na debatę, ale zastanawiam się, czy można być w tej kwestii zbyt nakazowym, szczególnie dla bardziej ogólnej publiczności. To fajny przykład - liczby oznaczają procenty, które można zapamiętać, co eliminuje potrzebę stosowania skali, która może być trudniejsza dla czytelników o mniejszej znajomości liczb?
geoteoria

Odpowiedzi:

193

Z ggplot 2.2.0etykiet można łatwo układać w stosy, używając position = position_stack(vjust = 0.5)w geom_text.

ggplot(Data, aes(x = Year, y = Frequency, fill = Category, label = Frequency)) +
  geom_bar(stat = "identity") +
  geom_text(size = 3, position = position_stack(vjust = 0.5))

wprowadź opis obrazu tutaj

Zauważ również, że „ position_stack()i position_fill()teraz stosuj wartości w odwrotnej kolejności grupowania, co powoduje, że domyślna kolejność stosu jest zgodna z legendą”.


Odpowiedź ważna dla starszych wersji ggplot:

Oto jedno podejście, które oblicza punkty środkowe słupków.

library(ggplot2)
library(plyr)

# calculate midpoints of bars (simplified using comment by @DWin)
Data <- ddply(Data, .(Year), 
   transform, pos = cumsum(Frequency) - (0.5 * Frequency)
)

# library(dplyr) ## If using dplyr... 
# Data <- group_by(Data,Year) %>%
#    mutate(pos = cumsum(Frequency) - (0.5 * Frequency))

# plot bars and add text
p <- ggplot(Data, aes(x = Year, y = Frequency)) +
     geom_bar(aes(fill = Category), stat="identity") +
     geom_text(aes(label = Frequency, y = pos), size = 3)

Wykres wynikowy

Ramnath
źródło
Dzięki za tę odpowiedź. Użyłem go do podobnego użycia data.tablezamiast plyr, więc coś takiego:Data.dt[,list(Category, Frequency, pos=cumsum(Frequency)-0.5*Frequency), by=Year]
atomicules
Czy w ogóle można dodać również całkowitą częstotliwość?
Pablo Olmos de Aguilera C.
26

Jak wspomniał Hadley, istnieją skuteczniejsze sposoby przekazywania wiadomości niż etykiety na skumulowanych wykresach słupkowych. W rzeczywistości wykresy skumulowane nie są zbyt skuteczne, ponieważ słupki (każda kategoria) nie mają wspólnej osi, więc porównanie jest trudne.

W takich przypadkach prawie zawsze lepiej jest użyć dwóch wykresów, które mają wspólną oś. W twoim przykładzie zakładam, że chcesz pokazać ogólną sumę, a następnie proporcje wniesione przez każdą kategorię w danym roku.

library(grid)
library(gridExtra)
library(plyr)

# create a new column with proportions
prop <- function(x) x/sum(x)
Data <- ddply(Data,"Year",transform,Share=prop(Frequency))

# create the component graphics
totals <- ggplot(Data,aes(Year,Frequency)) + geom_bar(fill="darkseagreen",stat="identity") + 
  xlab("") + labs(title = "Frequency totals in given Year")
proportion <- ggplot(Data, aes(x=Year,y=Share, group=Category, colour=Category)) 
+ geom_line() + scale_y_continuous(label=percent_format())+ theme(legend.position = "bottom") + 
  labs(title = "Proportion of total Frequency accounted by each Category in given Year")

# bring them together
grid.arrange(totals,proportion)

To da ci dwupanelowy wyświetlacz, taki jak ten:

Grafika z 2 panelami ułożona pionowo

Jeśli chcesz dodać wartości częstotliwości, najlepszym formatem jest tabela.

AndrewMinCH
źródło