2012-04-09 13 views
5

Sto tracciando grafici a linee che mostrano la variazione del prezzo nel tempo per più strumenti, utilizzando ggplot2. Sono riuscito a ottenere più linee sulla trama e ad aggiungere valori che mostrano il più recente cambiamento di prezzo. Quello che voglio fare (e non ho ancora ottenuto) è di riordinare il tasto della legenda in modo che la serie di prezzi che è aumentata di più sia in cima alla legenda, seguita dalla chiave della serie di prezzi che è aumentata al secondo posto e presto.R: come riordinare la chiave della legenda nel tracciato di ggplot2 in modo che corrisponda ai valori finali di ogni serie?

Nella trama seguente, la legenda mostra la chiave in ordine alfabetico. Quello che mi piacerebbe fare è mostrare le voci chiave della legenda nell'ordine DDD, AAA, CCC e BBB, che è l'ordine delle prestazioni a partire dalla data più recente. Come posso fare questo?

codice

ggplo2 chart showing legend order

Minimal-ish segue.

require(ggplot2) 
require(scales) 
require(gridExtra) 
require(lubridate) 
require(reshape) 

# create fake price data 
set.seed(123) 
monthsback <- 15 
date <- as.Date(paste(year(now()), month(now()),"1", sep="-")) - months(monthsback) 
mydf <- data.frame(mydate = seq(as.Date(date), by = "month", length.out = monthsback), 
         aaa = runif(monthsback, min = 600, max = 800), 
         bbb = runif(monthsback, min = 100, max = 200), 
         ccc = runif(monthsback, min = 1400, max = 2000), 
         ddd = runif(monthsback, min = 50, max = 120)) 

# function to calculate change 
change_from_start <- function(x) { 
    (x - x[1])/x[1] 
} 

# for appropriate columns (i.e. not date), replace fake price data with change in price 
mydf[, 2:5] <- lapply(mydf[, 2:5], function(myparam){change_from_start(myparam)}) 

# get most recent values and reshape 
myvals <- mydf[mydf$mydate == mydf$mydate[nrow(mydf)],] 
myvals <- melt(myvals, id = c('mydate')) 

# plot multiple lines 
p <- ggplot(data = mydf) + 
    geom_line(aes(x = mydate, y = aaa, colour = "AAA"), size = 1) + 
    geom_line(aes(x = mydate, y = bbb, colour = "BBB"), size = 1) + 
    geom_line(aes(x = mydate, y = ccc, colour = "CCC"), size = 1) + 
    geom_line(aes(x = mydate, y = ddd, colour = "DDD"), size = 1) + 
    scale_colour_manual("", values = c("AAA" = "red", "BBB" = "black", "CCC" = "blue", "DDD" = "green")) + 
    scale_y_continuous(label = percent_format()) + 
    geom_text(data = myvals, aes(x = mydate + 30, y = value, label = sprintf("%+1.1f%%", myvals$value * 100)), size = 4, colour = "grey50") + 
    opts(axis.title.y = theme_blank()) + 
    opts() 

# and output 
print(p) 

risposta

9

Prova questo:

mydf <- melt(mydf,id.var = 1) 
mydf$variable <- factor(mydf$variable,levels = rev(myvals$variable[order(myvals$value)]),ordered = TRUE) 

# plot multiple lines 
p <- ggplot(data = mydf) + 
    geom_line(aes(x = mydate,y = value,colour = variable,group = variable),size = 1) + 
    scale_colour_manual("", values = c("aaa" = "red", "bbb" = "black", "ccc" = "blue", "ddd" = "green")) + 
    scale_y_continuous(label = percent_format()) + 
    geom_text(data = myvals, aes(x = mydate + 30, y = value, label = sprintf("%+1.1f%%", myvals$value * 100)), 
       size = 4, colour = "grey50") + 
    opts(axis.title.y = theme_blank()) + 
    opts() 

# and output 
print(p) 

enter image description here

ho sciolto i vostri set di dati completo per risparmiare diverse linee per il tracciato codice. La chiave, come al solito, è assicurarsi che la variabile sia un fattore ordinato.

Per affrontare il problema che è sorto nei commenti, è possibile passare qualunque cosa le etichette che ti piace di apparire nella legenda in sé, fino a quando si ottiene l'ordine corretto:

ggplot(data = mydf) + 
    geom_line(aes(x = mydate,y = value,colour = variable,group = variable),size = 1) + 
    scale_colour_manual("", values = c("aaa" = "red", "bbb" = "black", "ccc" = "blue", "ddd" = "green"),labels = c('Company D','Company A','Company C','Company B')) + 
    scale_y_continuous(label = percent_format()) + 
    geom_text(data = myvals, aes(x = mydate + 30, y = value, label = sprintf("%+1.1f%%", myvals$value * 100)), 
       size = 4, colour = "grey50") + 
    opts(axis.title.y = theme_blank()) + 
    opts() 

enter image description here

Nota: A partire dalla versione 0.9.2 è stato optsreplaced da theme, ad esempio:

+ theme(axis.title.y = element_blank()) 
+3

Perfetto! Si noti che 'factor ordered' non è necessario. L'ordine del livello è importante ma a ggplot2 non importa se il fattore è ordinato o meno. – kohske

+0

Buono a sapersi, @kohske, grazie! Immagino di essere troppo paranoico sul codice di altre persone che decide sul proprio ordine se il fattore non è ordinato. – joran

+0

Grazie a joran per questo - stavo evitando una fusione per il data frame principale, ma non è una vera conseguenza e, come lei segnala, consente di risparmiare un sacco di informazioni. Suppongo che sarebbe possibile definire la parte 'values ​​= c (" aaa "=" red ")' separatamente usando una lista in modo che non debba approfondire la parte ggplot del codice ogni volta che voglio fare cambia gli articoli che voglio tracciare ...? Grazie anche a kohske per l'input. – SlowLearner

0

Penso che ci sia un modo più semplice. Una volta che si scioglie il dataframe, ordinarlo per valore di data e utilizzare i valori per l'ultima data per creare la legenda. Dato che hai ordinato per valore, la legenda mostrerà le righe nell'ordine corrispondente al modo in cui hai ordinato il valore (da max a min o min a max). Codice sotto.

require(ggplot2) 
require(scales) 
require(gridExtra) 
require(lubridate) 
require(reshape) 

# create fake price data 
set.seed(123) 
monthsback <- 15 
date <- as.Date(paste(year(now()), month(now()),"1", sep="-")) - months(monthsback) 
mydf <- data.frame(mydate = seq(as.Date(date), by = "month", length.out = monthsback), 
         aaa = runif(monthsback, min = 600, max = 800), 
         bbb = runif(monthsback, min = 100, max = 200), 
         ccc = runif(monthsback, min = 1400, max = 2000), 
         ddd = runif(monthsback, min = 50, max = 120)) 

# function to calculate change 
change_from_start <- function(x) { 
    (x - x[1])/x[1] 
} 

# for appropriate columns (i.e. not date), replace fake price data with change in price 
mydf[, 2:5] <- lapply(mydf[, 2:5], function(myparam){change_from_start(myparam)}) 

mydf <- melt(mydf, id.var=1) 

#Order by date and value. Decreasing since want to order greatest to least 
mydf <- mydf[order(mydf$mydate, mydf$value, decreasing = TRUE),] 

#Create legend breaks and labels 
legend_length <- length(unique(mydf$variable)) 
legend_breaks <- mydf$variable[1:legend_length] 

#Pass order through scale_colour_discrete 
ggplot(data=mydf) + geom_line(aes(x = mydate,y = value,colour = variable,group = variable),size = 1) + scale_colour_discrete(breaks=legend_breaks) 
Problemi correlati