tutorial - superponer graficas en r ggplot
Comprender las fechas y trazar un histograma con ggplot2 en R (3)
Creo que la clave es que necesitas hacer el cálculo de frecuencia fuera de ggplot. Use aggregate () con geom_bar (stat = "identity") para obtener un histograma sin los factores reordenados. Aquí hay un código de ejemplo:
require(ggplot2)
# scales goes with ggplot and adds the needed scale* functions
require(scales)
# need the month() function for the extra plot
require(lubridate)
# original data
#df<-read.csv("http://pastebin.com/download.php?i=sDzXKFxJ", header=TRUE)
# simulated data
years=sample(seq(2008,2012),681,replace=TRUE,prob=c(0.0176211453744493,0.302496328928047,0.323054331864905,0.237885462555066,0.118942731277533))
months=sample(seq(1,12),681,replace=TRUE)
my.dates=as.Date(paste(years,months,01,sep="-"))
df=data.frame(YM=strftime(my.dates, format="%Y-%b"),Date=my.dates,Year=years,Month=months)
# end simulated data creation
# sort the list just to make it pretty. It makes no difference in the final results
df=df[do.call(order, df[c("Date")]), ]
# add a dummy column for clarity in processing
df$Count=1
# compute the frequencies ourselves
freqs=aggregate(Count ~ Year + Month, data=df, FUN=length)
# rebuild the Date column so that ggplot works
freqs$Date=as.Date(paste(freqs$Year,freqs$Month,"01",sep="-"))
# I set the breaks for 2 months to reduce clutter
g<-ggplot(data=freqs,aes(x=Date,y=Count))+ geom_bar(stat="identity") + scale_x_date(labels=date_format("%Y-%b"),breaks="2 months") + theme_bw() + opts(axis.text.x = theme_text(angle=90))
print(g)
# don''t overwrite the previous graph
dev.new()
# just for grins, here is a faceted view by year
# Add the Month.name factor to have things work. month() keeps the factor levels in order
freqs$Month.name=month(freqs$Date,label=TRUE, abbr=TRUE)
g2<-ggplot(data=freqs,aes(x=Month.name,y=Count))+ geom_bar(stat="identity") + facet_grid(Year~.) + theme_bw()
print(g2)
Pregunta principal
Tengo problemas para comprender por qué el manejo de fechas, etiquetas y pausas no funciona como esperaba en R cuando intento hacer un histograma con ggplot2.
Estoy buscando:
- Un histograma de la frecuencia de mis fechas
- Marcas marcadas bajo las barras correspondientes
- Etiquetas de fecha en formato
%Yb
- Límites apropiados; espacio mínimo minimizado entre el borde del espacio de la grilla y las barras más externas
He subido mis datos a pastebin para hacer esto reproducible. Creé varias columnas porque no estaba seguro de la mejor manera de hacerlo:
> dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
> head(dates)
YM Date Year Month
1 2008-Apr 2008-04-01 2008 4
2 2009-Apr 2009-04-01 2009 4
3 2009-Apr 2009-04-01 2009 4
4 2009-Apr 2009-04-01 2009 4
5 2009-Apr 2009-04-01 2009 4
6 2009-Apr 2009-04-01 2009 4
Esto es lo que intenté:
library(ggplot2)
library(scales)
dates$converted <- as.Date(dates$Date, format="%Y-%m-%d")
ggplot(dates, aes(x=converted)) + geom_histogram()
+ opts(axis.text.x = theme_text(angle=90))
Que produce este gráfico . Yo quería el formato %Y-%b
, así que busqué e intenté lo siguiente, basado en este SO :
ggplot(dates, aes(x=converted)) + geom_histogram()
+ scale_x_date(labels=date_format("%Y-%b"),
+ breaks = "1 month")
+ opts(axis.text.x = theme_text(angle=90))
stat_bin: binwidth defaulted to range/30. Use ''binwidth = x'' to adjust this.
Eso me da este gráfico
- Corregir el formato de etiqueta del eje x
- La distribución de frecuencia ha cambiado de forma (¿problema de ancho de banda?)
- Las marcas no aparecen centradas debajo de las barras
- Los xlims también han cambiado
Trabajé a través del ejemplo en la documentación ggplot2 en la sección scale_x_date
y geom_line()
parece romper, etiquetar y centrar tics correctamente cuando lo uso con mis mismos datos del eje x. No entiendo por qué el histograma es diferente.
Actualizaciones basadas en respuestas de edgester y gauden
Inicialmente pensé que la respuesta de Gauden me ayudó a resolver mi problema, pero ahora estoy desconcertado después de mirar más de cerca. Tenga en cuenta las diferencias entre los gráficos resultantes de las dos respuestas después del código.
Asume para ambos:
library(ggplot2)
library(scales)
dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
Basado en la respuesta de @deraster a continuación, pude hacer lo siguiente:
freqs <- aggregate(dates$Date, by=list(dates$Date), FUN=length)
freqs$names <- as.Date(freqs$Group.1, format="%Y-%m-%d")
ggplot(freqs, aes(x=names, y=x)) + geom_bar(stat="identity") +
scale_x_date(breaks="1 month", labels=date_format("%Y-%b"),
limits=c(as.Date("2008-04-30"),as.Date("2012-04-01"))) +
ylab("Frequency") + xlab("Year and Month") +
theme_bw() + opts(axis.text.x = theme_text(angle=90))
Aquí está mi intento basado en la respuesta de Gauden:
dates$Date <- as.Date(dates$Date)
ggplot(dates, aes(x=Date)) + geom_histogram(binwidth=30, colour="white") +
scale_x_date(labels = date_format("%Y-%b"),
breaks = seq(min(dates$Date)-5, max(dates$Date)+5, 30),
limits = c(as.Date("2008-05-01"), as.Date("2012-04-01"))) +
ylab("Frequency") + xlab("Year and Month") +
theme_bw() + opts(axis.text.x = theme_text(angle=90))
Parcela basada en el enfoque de edgeter:
Parcela basada en el enfoque de Gauden:
Tenga en cuenta lo siguiente:
- lagunas en la trama de Gauden para 2009-Dic y 2010-Mar;
table(dates$Date)
revela que hay 19 instancias de2009-12-01
y 26 instancias de2010-03-01
en los datos - La trama de edgeter comienza en 2008-abr y termina en 2012-mayo. Esto es correcto en base a un valor mínimo en los datos de 2008-04-01 y una fecha máxima de 2012-05-01. Por alguna razón, la trama de Gauden comienza en 2008-Mar y aún de alguna manera se las arregla para finalizar en 2012-mayo. Después de contar los contenedores y leer a lo largo de las etiquetas de los meses, durante mi vida no puedo entender qué trama tiene un extra o si falta un contenedor del histograma.
¿Alguna idea sobre las diferencias aquí? El método de edgeter para crear un conteo separado
Referencias relacionadas
Como un aparte, aquí hay otras ubicaciones que tienen información sobre las fechas y ggplot2 para los transeúntes en busca de ayuda:
- Empezó aquí en learnr.wordpress, un popular blog de R. Decía que necesitaba obtener mis datos en formato POSIXct, que ahora creo que es falso y que desperdicia mi tiempo.
- Otra publicación de aprendizaje recrea una serie temporal en ggplot2, pero no era realmente aplicable a mi situación.
- r-bloggers tiene una publicación sobre esto , pero parece desactualizada. La sencilla
format=
opción no funcionó para mí. - Esta pregunta SO está jugando con breaks y etiquetas. Intenté tratar mi vector
Date
como continuo y no creo que funcionó tan bien. Parecía que estaba superponiendo el mismo texto de etiqueta una y otra vez, por lo que las letras parecían algo extrañas. La distribución es más o menos correcta, pero hay pausas extrañas. Mi intento basado en la respuesta aceptada fue así ( resultado aquí ).
El gráfico de error con el título "Gráfico basado en el enfoque de Gauden" se debe al parámetro binwidth: ... + Geom_histogram (binwidth = 30, color = "white") + ... Si cambiamos el valor de 30 a a valor inferior a 20, como 10, obtendrá todas las frecuencias.
En estadística los valores son más importantes que la presentación; es más importante un gráfico insulso a una imagen muy bonita pero con errores.
ACTUALIZAR
Versión 2: Uso de la clase Date
Actualizo el ejemplo para demostrar la alineación de las etiquetas y el establecimiento de límites en la trama. También demuestro que, como as.Date
, de hecho funciona cuando se usa de manera consistente (de hecho, es probable que sea una mejor opción para sus datos que mi ejemplo anterior).
The Target Plot v2
El código v2
Y aquí está (algo excesivamente) código comentado:
library("ggplot2")
library("scales")
dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
dates$Date <- as.Date(dates$Date)
# convert the Date to its numeric equivalent
# Note that Dates are stored as number of days internally,
# hence it is easy to convert back and forth mentally
dates$num <- as.numeric(dates$Date)
bin <- 60 # used for aggregating the data and aligning the labels
p <- ggplot(dates, aes(num, ..count..))
p <- p + geom_histogram(binwidth = bin, colour="white")
# The numeric data is treated as a date,
# breaks are set to an interval equal to the binwidth,
# and a set of labels is generated and adjusted in order to align with bars
p <- p + scale_x_date(breaks = seq(min(dates$num)-20, # change -20 term to taste
max(dates$num),
bin),
labels = date_format("%Y-%b"),
limits = c(as.Date("2009-01-01"),
as.Date("2011-12-01")))
# from here, format at ease
p <- p + theme_bw() + xlab(NULL) + opts(axis.text.x = theme_text(angle=45,
hjust = 1,
vjust = 1))
p
Versión 1: Usando POSIXct
Intento una solución que haga todo en ggplot2
, dibujar sin la agregación y establecer los límites en el eje x entre principios de 2009 y finales de 2011.
The Target Plot v1
El código v1
library("ggplot2")
library("scales")
dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
dates$Date <- as.POSIXct(dates$Date)
p <- ggplot(dates, aes(Date, ..count..)) +
geom_histogram() +
theme_bw() + xlab(NULL) +
scale_x_datetime(breaks = date_breaks("3 months"),
labels = date_format("%Y-%b"),
limits = c(as.POSIXct("2009-01-01"),
as.POSIXct("2011-12-01")) )
p
Por supuesto, podría hacerlo jugando con las opciones de etiqueta en el eje, pero esto es para redondear el trazado con una rutina breve y clara en el paquete de trazado.