Come posso inserire una scala trasformata sul lato destro di un ggplot2?

Sto creando un grafico che mostra il cambiamento dei livelli del lago nel tempo. Ho allegato un semplice esempio qui sotto. Vorrei aggiungere una scala (segni di spunta e annotazione) sul lato destro del grafico che mostra l’elevazione in piedi. So che ggplot2 non permetterà due scale differenti (vedi Plot con 2 assi y, un asse y a sinistra e un altro asse y a destra ), ma poiché si tratta di una trasformazione della stessa scala, c’è un modo per Fai questo? Preferirei continuare a utilizzare ggplot2 e non dover tornare alla funzione plot ().

library(ggplot2) LakeLevels<-data.frame(Day=c(1:365),Elevation=sin(seq(0,2*pi,2*pi/364))*10+100) p <- ggplot(data=LakeLevels) + geom_line(aes(x=Day,y=Elevation)) + scale_y_continuous(name="Elevation (m)",limits=c(75,125)) p 

Dovresti dare un’occhiata a questo link http://rpubs.com/kohske/dual_axis_in_ggplot2 .

Ho adattato il codice fornito lì per il tuo esempio. Questa correzione sembra molto “hacky”, ma ti fa diventare parte del modo in cui ti trovi. L’unico pezzo rimasto è capire come aggiungere del testo all’asse destro del grafico.

  library(ggplot2) library(gtable) library(grid) LakeLevels<-data.frame(Day=c(1:365),Elevation=sin(seq(0,2*pi,2*pi/364))*10+100) p1 <- ggplot(data=LakeLevels) + geom_line(aes(x=Day,y=Elevation)) + scale_y_continuous(name="Elevation (m)",limits=c(75,125)) p2<-ggplot(data=LakeLevels)+geom_line(aes(x=Day, y=Elevation))+ scale_y_continuous(name="Elevation (ft)", limits=c(75,125), breaks=c(80,90,100,110,120), labels=c("262", "295", "328", "361", "394")) #extract gtable g1<-ggplot_gtable(ggplot_build(p1)) g2<-ggplot_gtable(ggplot_build(p2)) #overlap the panel of the 2nd plot on that of the 1st plot pp<-c(subset(g1$layout, name=="panel", se=t:r)) g<-gtable_add_grob(g1, g2$grobs[[which(g2$layout$name=="panel")]], pp$t, pp$l, pp$b, pp$l) ia <- which(g2$layout$name == "axis-l") ga <- g2$grobs[[ia]] ax <- ga$children[[2]] ax$widths <- rev(ax$widths) ax$grobs <- rev(ax$grobs) ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm") g <- gtable_add_cols(g, g2$widths[g2$layout[ia, ]$l], length(g$widths) - 1) g <- gtable_add_grob(g, ax, pp$t, length(g$widths) - 1, pp$b) # draw it grid.draw(g) 

inserisci la descrizione dell'immagine qui

Potrei aver trovato una soluzione per posizionare il titolo dell’asse, con alcune idee dalla risposta di Nate Pope che può essere trovata qui:
ggplot2: aggiunta dell’asse x trasformato secondario sopra il grafico
E una discussione sull’accesso ai grobs nel gtable qui: https://groups.google.com/forum/m/#!topic/ggplot2-dev/AVHHcYqc5uU

Alla fine, ho appena aggiunto la linea

 g <- gtable_add_grob(g, g2$grob[[7]], pp$t, length(g$widths), pp$b) 

prima di chiamare grid.draw(g) , che sembrava fare il trucco.
A quanto ho capito, prende il titolo dell'asse y g2$grob[[7]] e lo colloca sul lato esterno più a destra. Potrebbe non essere la soluzione migliore, ma ha funzionato per me.

Un'ultima cosa. Sarebbe bello trovare un modo per ruotare il titolo dell'asse.

Saluti,

Tim

A questa domanda è stata data una risposta, ma il problema generale di aggiungere un asse secondario e una scala secondaria sul lato destro di un object ggplot è uno che si presenta continuamente. Vorrei riportare qui di seguito il mio tweak sul problema, basato su diversi elementi dati da varie risposte in questo thread e in molti altri thread (vedere un elenco parziale di riferimenti sotto).

Ho bisogno di una produzione in serie di grafici a doppio asse y, quindi ho creato una funzione ggplot_dual_axis() . Ecco le caratteristiche di potenziale interesse:

  1. Il codice mostra la griglia per entrambi gli assi y-left e y-right (questo è il mio contributo principale anche se è banale)

  2. Il codice stampa un simbolo dell’euro e lo incorpora nel pdf (qualcosa che ho visto lì: Tracciare Euro Symbol € in ggplot2? )

  3. Il codice tenta di evitare di stampare alcuni elementi due volte (“tentativi” suggerisce che ne dubito pienamente)

Domande senza risposta:

  • Esiste un modo per modificare la funzione ggplot_dual_axis() per rimuovere uno di geom_line() o geom_point() o qualunque cosa possa essere senza geom_point() errori se tali elementi geom non sono presenti. In pseudo-codice qualcosa come if has(geom_line) ...

  • Come posso chiamare il g2$grobs[[7]] per parola chiave piuttosto che indice? Questo è ciò che restituisce: text[axis.title.y.text.232] mio interesse per la domanda deriva dai miei tentativi falliti di afferrare le linee della griglia applicando un trucco simile. Penso che le linee della griglia siano nascoste da qualche parte all’interno di g2$grobs[[4]] , ma non sono sicuro di come accedervi.

Modifica Domanda Sono stato in grado di rispondere a me stesso: come posso aumentare il margine di trama sul lato destro, dove si trova l’etichetta “Euro”? Risposta: theme(plot.margin = unit(c(1,3,0.5,0.8), "lines")) farà il trucco, per esempio.

Si prega di segnalare eventuali problemi evidenti o suggerire miglioramenti.

Ora il codice: speriamo che possa essere utile a qualcuno. Come ho detto, non rivendico l’originalità, è una combinazione di cose che altri hanno già mostrato.

 ##' function named ggplot_dual_axis() ##' Takes 2 ggplot plots and makes a dual y-axis plot ##' function takes 2 compulsory arguments and 1 optional argument ##' arg lhs is the ggplot whose y-axis is to be displayed on the left ##' arg rhs is the ggplot whose y-axis is to be displayed on the right ##' arg 'axis.title.y.rhs' takes value "rotate" to rotate right y-axis label ##' The function does as little as possible, namely: ##' # display the lhs plot without minor grid lines and with a ##' transparent background to allow grid lines to show ##' # display the rhs plot without minor grid lines and with a ##' secondary y axis, a rotated axis label, without minor grid lines ##' # justify the y-axis label by setting 'hjust = 0' in 'axis.text.y' ##' # rotate the right plot 'axis.title.y' by 270 degrees, for symmetry ##' # rotation can be turned off with 'axis.title.y.rhs' option ##' ggplot_dual_axis <- function(lhs, rhs, axis.title.y.rhs = "rotate") { # 1. Fix the right y-axis label justification rhs <- rhs + theme(axis.text.y = element_text(hjust = 0)) # 2. Rotate the right y-axis label by 270 degrees by default if (missing(axis.title.y.rhs) | axis.title.y.rhs %in% c("rotate", "rotated")) { rhs <- rhs + theme(axis.title.y = element_text(angle = 270)) } # 3a. Use only major grid lines for the left axis lhs <- lhs + theme(panel.grid.minor = element_blank()) # 3b. Use only major grid lines for the right axis # force transparency of the backgrounds to allow grid lines to show rhs <- rhs + theme(panel.grid.minor = element_blank(), panel.background = element_rect(fill = "transparent", colour = NA), plot.background = element_rect(fill = "transparent", colour = NA)) # Process gtable objects # 4. Extract gtable library("gtable") # loads the grid package g1 <- ggplot_gtable(ggplot_build(lhs)) g2 <- ggplot_gtable(ggplot_build(rhs)) # 5. Overlap the panel of the rhs plot on that of the lhs plot pp <- c(subset(g1$layout, name == "panel", se = t:r)) g <- gtable_add_grob(g1, g2$grobs[[which(g2$layout$name == "panel")]], pp$t, pp$l, pp$b, pp$l) # Tweak axis position and labels ia <- which(g2$layout$name == "axis-l") ga <- g2$grobs[[ia]] ax <- ga$children[["axis"]] # ga$children[[2]] ax$widths <- rev(ax$widths) ax$grobs <- rev(ax$grobs) ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm") g <- gtable_add_cols(g, g2$widths[g2$layout[ia, ]$l], length(g$widths) - 1) g <- gtable_add_grob(g, ax, pp$t, length(g$widths) - 1, pp$b) g <- gtable_add_grob(g, g2$grobs[[7]], pp$t, length(g$widths), pp$b) # Display plot with arrangeGrob wrapper arrangeGrob(g) library("gridExtra") grid.newpage() return(arrangeGrob(g)) } 

E sotto alcuni dati falsi e due grafici che sono destinati a essere in unità dollaro ed euro. Non sarebbe bello avere un pacchetto che ti permetta di creare una trama e avvolgerla attorno ad una trama a due assi come ggplot_dual_axis_er(ggplot_object, currency = c("dollar", "euro")) e automaticamente recupererebbe i tassi di cambio per te! 🙂

 # Set directory: if(.Platform$OS.type == "windows"){ setwd("c:/R/plots") } else { setwd("~/R/plots") } # Load libraries library("ggplot2") library("scales") # Create euro currency symbol in plot labels, simple version # avoids loading multiple libraries # avoids problems with rounding of small numbers, eg .0001 labels_euro <- function(x) {# no rounding paste0("€", format(x, big.mark = ",", decimal.mark = ".", trim = TRUE, scientific = FALSE)) } labels_dollar <- function(x) {# no rounding: overwrites dollar() of library scales paste0("$", format(x, big.mark = ",", decimal.mark = ".", trim = TRUE, scientific = FALSE)) } # Create data df <- data.frame( Year = as.Date(c("2001", "2002", "2003", "2004", "2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012", "2013", "2014", "2015", "2016", "2017", "2018"), "%Y"), Dollar = c(0, 9000000, 1000000, 8000000, 2000000, 7000000, 3000000, 6000000, 4000000, 5000000, 5000000, 6000000, 4000000, 7000000, 300000, 8000000, 2000000, 9000000)) # set Euro/Dollar exchange rate at 0.8 euros = 1 dollar df <- cbind(df, Euro = 0.8 * df$Dollar) # Left y-axis p1 <- ggplot(data = df, aes(x = Year, y = Dollar)) + geom_line(linestyle = "blank") + # manually remove the line theme_bw(20) + # make sure font sizes match in both plots scale_x_date(labels = date_format("%Y"), breaks = date_breaks("2 years")) + scale_y_continuous(labels = labels_dollar, breaks = seq(from = 0, to = 8000000, by = 2000000)) # Right y-axis p2 <- ggplot(data = df, aes(x = Year, y = Euro)) + geom_line(color = "blue", linestyle = "dotted", size = 1) + xlab(NULL) + # manually remove the label theme_bw(20) + # make sure font sizes match in both plots scale_x_date(labels = date_format("%Y"), breaks = date_breaks("2 years")) + scale_y_continuous(labels = labels_euro, breaks = seq(from = 0, to = 7000000, by = 2000000)) # Combine left y-axis with right y-axis p <- ggplot_dual_axis(lhs = p1, rhs = p2) p # Save to PDF pdf("ggplot-dual-axis-function-test.pdf", encoding = "ISOLatin9.enc", width = 12, height = 8) p dev.off() embedFonts(file = "ggplot-dual-axis-function-test.pdf", outfile = "ggplot-dual-axis-function-test-embedded.pdf") 

inserisci la descrizione dell'immagine qui

Elenco parziale di riferimenti:

  1. Mostra due assi paralleli su un ggplot (R)
  2. Doppio asse y in ggplot2 per più figure del pannello
  3. Come posso inserire una scala trasformata sul lato destro di un ggplot2?
  4. Mantieni proporzioni di grafici usando grid.arrange
  5. I pericoli di allineare i grafici in ggplot
  6. https://github.com/kohske/ggplot2

Per ruotare il titolo dell’asse, aggiungere quanto segue al grafico p2:

 p2 <- p2 + theme(axis.title.y=element_text(angle=270))