ggtitle - ¿Cómo puedo poner una escala transformada en el lado derecho de un ggplot2?
ggplot title size (4)
Estoy creando un gráfico que muestra el cambio en los niveles del lago a lo largo del tiempo. He adjuntado un ejemplo simple a continuación. Me gustaría agregar una escala (marcas y anotaciones) en el lado derecho de la gráfica que muestra la elevación en pies. Sé que ggplot2 no permitirá dos escalas diferentes (ver Ploteo con 2 ejes y, un eje y a la izquierda y otro eje y a la derecha ), pero debido a que esta es una transformación de la misma escala, ¿hay alguna manera de ¿hacer esto? Preferiría seguir usando ggplot2 y no tener que volver a la función 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
Deberías echar un vistazo a este enlace http://rpubs.com/kohske/dual_axis_in_ggplot2 .
He adaptado el código provisto allí para tu ejemplo. Esta solución parece muy "hacky", pero te lleva a una parte del camino allí. La única pieza que queda es descubrir cómo agregar texto al eje derecho del gráfico.
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)
Esta pregunta ha sido respondida, pero el problema general de agregar un eje secundario y una escala secundaria al lado derecho de un objeto ggplot es uno que aparece todo el tiempo. Me gustaría informar debajo mi propio ajuste sobre el problema, basado en varios elementos dados por varias respuestas en este hilo, así como en varios otros hilos (ver una lista parcial de referencias a continuación).
Tengo una necesidad de producción masiva de gráficos de eje y dual, así que construí una función ggplot_dual_axis()
. Estas son las características de posible interés:
El código muestra las líneas de la cuadrícula para los ejes y-izquierda e y-derecha (esta es mi contribución principal aunque es trivial)
El código imprime un símbolo del euro y lo inserta en el pdf (algo que vi allí: trazar el símbolo del euro € en ggplot2? )
El código intenta evitar la impresión de ciertos elementos dos veces ("intentos" sugieren que dudo que tenga éxito)
Preguntas sin respuesta:
¿Hay alguna manera de modificar la función
ggplot_dual_axis()
para eliminar uno de losgeom_line()
ogeom_point()
o lo que sea, sin lanzar errores si tales elementos geom no están presentes? En pseudo-código algo así comoif has(geom_line) ...
¿Cómo puedo llamar a
g2$grobs[[7]]
por palabra clave en lugar de índice? Esto es lo que devuelve:text[axis.title.y.text.232]
Mi interés en la pregunta proviene de mis intentos fallidos de agarrar las líneas de la grilla mediante la aplicación de un truco similar. Creo que las líneas de la cuadrícula están ocultas en algún lugar dentro deg2$grobs[[4]]
, pero no estoy seguro de cómo acceder a ellas.
Editar . Pregunta: Pude responderme a mí mismo: ¿Cómo puedo aumentar el margen de la trama en el lado derecho, donde está la etiqueta ''Euro''? Respuesta: el theme(plot.margin = unit(c(1,3,0.5,0.8), "lines"))
hará el truco, por ejemplo.
Por favor señale cualquier problema obvio o sugiera mejoras.
Ahora el código: con suerte será útil para alguien. Como dije, no reclamo originalidad, es una combinación de cosas que otros ya han demostrado.
##'' 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))
}
Y debajo de algunos datos falsos y dos gráficos que están destinados a unidades en dólares y euros. ¿No sería genial tener un paquete que te permitiera hacer un diagrama y envolverlo con una llamada a un diagrama de eje dual como ggplot_dual_axis_er(ggplot_object, currency = c("dollar", "euro"))
y automáticamente obtendría los tipos de cambio para usted! :-)
# 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, e.g. .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")
Lista parcial de referencias:
- Mostrar dos ejes paralelos en un ggplot (R)
- Eje y dual en ggplot2 para figura de panel múltiple
- ¿Cómo puedo poner una escala transformada en el lado derecho de un ggplot2?
- Conservar la proporción de gráficos usando grid.arrange
- Los peligros de alinear las parcelas en ggplot
- https://github.com/kohske/ggplot2
Para rotar el título del eje, agregue lo siguiente al gráfico p2:
p2 <- p2 + theme(axis.title.y=element_text(angle=270))
Pude haber encontrado una solución para colocar el título del eje, con algunas ideas de la respuesta de Nate Pope que se puede encontrar aquí:
ggplot2: Adición de un eje x transformado secundario en la parte superior de la trama
Y una discusión sobre el acceso a grobs en gtable aquí: https://groups.google.com/forum/m/#!topic/ggplot2-dev/AVHHcYqc5uU
Al final, acabo de agregar la línea
g <- gtable_add_grob(g, g2$grob[[7]], pp$t, length(g$widths), pp$b)
antes de llamar a grid.draw(g)
, lo que parecía hacer el truco.
Según lo entiendo, toma el título del eje y g2$grob[[7]]
y lo coloca en el lado exterior derecho. Puede que no sea la solución perfecta, pero funcionó para mí.
Una última cosa. Sería bueno encontrar una forma de rotar el título del eje.
Saludos,
Tim