2016-03-21 6 views
2

Ich möchte ein Balkendiagramm erstellen, in dem die Antwortvariable (Gewichtsänderung) über unterschiedlich lange Zeiträume gemessen wird, definiert durch ein Start- und ein Enddatum. Die Breite der Balken sollte der Länge des Zeitraums entsprechen. Ein kleines Beispiel meiner Daten:Balkendiagramm mit variablen Balkenbreiten als Datumsbereiche auf der X-Achse

wtchange.data <- structure(list(start.date = structure(1:3, .Label = c("2015-04-01", 
    "2015-04-15", "2015-04-30"), class = "factor"), end.date = structure(1:3, .Label = c("2015-04-15", 
    "2015-04-30", "2015-05-30"), class = "factor"), wtchange = c(5L, 
    10L, 15L), se = c(1.2, 2.5, 0.8)), .Names = c("start.date", "end.date", 
    "wtchange", "se"), class = "data.frame", row.names = c(NA, -3L 
    )) 

wtchange.data 
# start.date end.date wtchange se 
# 1 2015-04-01 2015-04-15  5 1.2 
# 2 2015-04-15 2015-04-30  10 2.5 
# 3 2015-04-30 2015-05-30  15 0.8 

wtchange.data$start.date <- as.Date(wtchange.data$start.date) 
wtchange.data$end.date <- as.Date(wtchange.data$end.date) 

Versuch geom_bar zu verwenden:

library(ggplot2) 
ggplot(wtchange.data, aes(x = start.date, y = wtchange)) + 
    geom_bar(stat = "identity", color = "black") + 
    geom_errorbar(aes(ymin = wtchange-se, ymax = wtchange+se), width = 1) 

(nicht erlaubt> 2 Links mit < 10 Ruf, so kann leider nicht die erste Handlung zeigen)

Das Hauptproblem ist, dass wenn die Ästhetik des Diagrammbereichs definiert ist (x = start.date, y = wtchange), kann ich nur eine Variable (start.date in diesem Beispiel) für die x-Achse verwenden, aber ich brauche wirklich um sowohl start.date als auch end.date irgendwie zu verwenden, um Strichbreiten zu begrenzen, die jeder Periode entsprechen. Das Diagramm sollte wie folgt aussehen (in der Farbe gezeichnet): enter image description here

Ein zweites Problem besteht darin, dass die Stäbe lückenlos berühren sollten, aber ich bin nicht sicher, ob es überhaupt möglich ist, da die Stäbe sein müssen verschiedene Breiten, so dass Sie keine Balkenbreite für alle Balken festlegen können. Wäre es möglich, die Breite für jeden Balken manuell festzulegen?


Edit: Danke Henrik für die Links. Ich habe einige Fortschritte gemacht. I berechnete Datum Mittelpunkte für die Zentrierung der Stäbe an:

wtchange.data$date.midpoint <- wtchange.data$start.date + 
(wtchange.data$end.date - wtchange.data$start.date)/2 

Und dann berechnet Periodenlängen für die Verwendung als Strichbreiten:

wtchange.data$period.length <- wtchange.data$end.date - wtchange.data$start.date 

Die aktualisierte Graph-Code ist jetzt:

ggplot(wtchange.data, aes(x = date.midpoint, y = wtchange)) + 
    geom_bar(stat = "identity", color = "black", width = wtchange.data$period.length) + 
    geom_errorbar(aes(ymin = wtchange-se, ymax = wtchange+se), width = 1) 

enter image description here

Das einzige verbleibende Problem i s, dass es immer noch eine kleine Lücke zwischen den Bars an einem Ort gibt. Ich schätze, das liegt an der Art und Weise, wie R die Datumsdifferenzberechnung auf die nächste Anzahl von Tagen rundet.

Antwort

1

Sie haben recht: Es ist die Berechnung der Differenz zwischen Ende und Beginn Daten, die der Grund für die Lücke ist. Wir müssen numeric Perioden anstelle von difftime verwenden (siehe Erläuterung unten), wenn Sie die Breite und den Mittelpunkt berechnen.

# length of periods, width of bars as numeric 
df$width <- as.numeric(df$end.date - df$start.date) 

# mid-points 
df$mid <- df$start.date + df$width/2 

# dates for breaks 
dates <- unique(c(df$start.date, df$end.date)) 

ggplot(df, aes(x = mid, y = wtchange)) + 
    geom_bar(stat = "identity", color = "black", width = df$width) + 
    geom_errorbar(aes(ymin = wtchange - se, ymax = wtchange + se), width = 1) + 
    scale_x_date(breaks = dates) 

enter image description here


Entsprechende geom_rect Code:

# mid-points 
df$mid <- df$start.date + as.numeric(df$end.date - df$start.date)/2 

# dates for breaks 
dates <- unique(c(df$start.date, df$end.date)) 

ggplot(df, aes(x = mid, y = wtchange)) + 
    geom_rect(aes(xmin = start.date, xmax = end.date, ymin = 0, ymax = wtchange), color = "black") + 
    geom_errorbar(aes(ymin = wtchange - se, ymax = wtchange + se), width = 1) + 
    scale_x_date(breaks = dates) 

Und etwas weniger Tinte mit geom_step anspruchsvoll:

# need to add an end date to the last period 
df2 <- tail(df, 1) 
df2$start.date <- df2$end.date 
df2 <- rbind(df, df2) 

# mid-points 
df$mid <- df$start.date + as.numeric(df$end.date - df$start.date)/2 

ggplot() + 
    geom_step(data = df2, aes(x = start.date, y = wtchange)) + 
    geom_errorbar(data = df, aes(x = mid, ymin = wtchange - se, ymax = wtchange + se), width = 1) + 
    scale_x_date(breaks = dates) + 
    ylim(0, 16) + 
    theme_bw() 

enter image description here


Auf der "difftime Ausgabe":

Werte der Klasse Date kann intern als fraktionierte Tage dargestellt werden (siehe ?Date und ?Ops.Date; versuchen: Sys.Date(); Sys.Date() + 0.5; Sys.Date() + 0.5 + 0.5). Wenn jedoch ein Objekt difftime zu einem Date Objekt hinzugefügt wird, ist das Objekt difftimeam nächsten ganzen Tag gerundet (siehe x Argument in ?Ops.Date). 2015-04-30 mit Ihrem Startdatum 2015-04-15 und Enddatum

Lasst uns die Berechnungen überprüfen:

mid <- (as.Date("2015-04-30") - as.Date("2015-04-15"))/2 
mid 
# Time difference of 7.5 days 

str(mid) 
# Class 'difftime' atomic [1:1] 7.5 
# ..- attr(*, "units")= chr "days" 

# calculate the midpoint using the difftime object 
as.Date("2015-04-15") + mid 
# [1] "2015-04-23" 

# calculating midpoint using numeric object yields another date... 
as.Date("2015-04-15") + as.numeric(mid) 
# [1] "2015-04-22" 

# But is "2015-04-15" above in fact fractional, i.e. "2015-04-22 point 5"? 
# Let's try and add 0.5 
as.Date("2015-04-15") + as.numeric(mid) + 0.5 
# [1] "2015-04-23" 
# Yes. 

So verwenden wir die numeric Zeit, statt der difftime Zeit.

Verwandte Themen