manipulation ggtitle ggplot change r ggplot2 rose-diagram

r - ggplot - ggtitle position



Rosa de los vientos con ggplot(R)? (3)

¿Alguna vez ha probado la función windRose del paquete Openair? Es muy fácil y puedes establecer intervalos, estadísticas, etc.

windRose(mydata, ws = "ws", wd = "wd", ws2 = NA, wd2 = NA, ws.int = 2, angle = 30, type = "default", bias.corr = TRUE, cols = "default", grid.line = NULL, width = 1, seg = NULL, auto.text = TRUE, breaks = 4, offset = 10, normalise = FALSE, max.freq = NULL, paddle = TRUE, key.header = NULL, key.footer = "(m/s)", key.position = "bottom", key = TRUE, dig.lab = 5, statistic = "prop.count", pollutant = NULL, annotate = TRUE, angle.scale = 315, border = NA, ...) pollutionRose(mydata, pollutant = "nox", key.footer = pollutant, key.position = "right", key = TRUE, breaks = 6, paddle = FALSE, seg = 0.9, normalise = FALSE, ...)

Estoy buscando un buen código R (o paquete) que use ggplot2 para crear rosas de viento que muestren la frecuencia, magnitud y dirección de los vientos.

Estoy particularmente interesado en ggplot2 ya que la construcción de la trama de esa manera me da la oportunidad de aprovechar el resto de la funcionalidad allí.

Datos de prueba

Descargue un año de datos meteorológicos del nivel de 80 m en la torre "M2" de National Wind Technology . Este enlace creará un archivo .csv que se descargará automáticamente. Necesita encontrar ese archivo (se llama "20130101.csv") y leerlo.

# read in a data file data.in <- read.csv(file = "A:/drive/somehwere/20130101.csv", col.names = c("date","hr","ws.80","wd.80"), stringsAsFactors = FALSE))

Esto funcionaría con cualquier archivo .csv y sobrescribirá los nombres de las columnas.

Data de muestra

Si no desea descargar esa información, aquí hay 10 puntos de datos que usaremos para mostrar el proceso:

data.in <- structure(list(date = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L,

1L, 1L), .Label = "1/1/2013", clase = "factor"), hr = 1: 9, ws.80 = c (5, 7, 7, 51.9, 11, 12, 9, 11 , 17), wd.80 = c (30, 30, 30, 180, 180, 180, 269, 270, 271)), .Names = c ("date", "hr", "ws.80", " wd.80 "), row.names = c (NA, -9L), clase =" data.frame ")


Aquí está mi versión del código. Agregué etiquetas para las instrucciones (N, NNE, NE, ENE, E ....) e hice que la etiqueta y mostrara la frecuencia en porcentaje en lugar de conteos.

Haga clic aquí para ver la figura del viento Rose con instrucciones y frecuencia (%)

# WindRose.R require(ggplot2) require(RColorBrewer) require(scales) plot.windrose <- function(data, spd, dir, spdres = 2, dirres = 22.5, spdmin = 2, spdmax = 20, spdseq = NULL, palette = "YlGnBu", countmax = NA, debug = 0){ # Look to see what data was passed in to the function if (is.numeric(spd) & is.numeric(dir)){ # assume that we''ve been given vectors of the speed and direction vectors data <- data.frame(spd = spd, dir = dir) spd = "spd" dir = "dir" } else if (exists("data")){ # Assume that we''ve been given a data frame, and the name of the speed # and direction columns. This is the format we want for later use. } # Tidy up input data ---- n.in <- NROW(data) dnu <- (is.na(data[[spd]]) | is.na(data[[dir]])) data[[spd]][dnu] <- NA data[[dir]][dnu] <- NA # figure out the wind speed bins ---- if (missing(spdseq)){ spdseq <- seq(spdmin,spdmax,spdres) } else { if (debug >0){ cat("Using custom speed bins /n") } } # get some information about the number of bins, etc. n.spd.seq <- length(spdseq) n.colors.in.range <- n.spd.seq - 1 # create the color map spd.colors <- colorRampPalette(brewer.pal(min(max(3, n.colors.in.range), min(9, n.colors.in.range)), palette))(n.colors.in.range) if (max(data[[spd]],na.rm = TRUE) > spdmax){ spd.breaks <- c(spdseq, max(data[[spd]],na.rm = TRUE)) spd.labels <- c(paste(c(spdseq[1:n.spd.seq-1]), ''-'', c(spdseq[2:n.spd.seq])), paste(spdmax, "-", max(data[[spd]],na.rm = TRUE))) spd.colors <- c(spd.colors, "grey50") } else{ spd.breaks <- spdseq spd.labels <- paste(c(spdseq[1:n.spd.seq-1]), ''-'', c(spdseq[2:n.spd.seq])) } data$spd.binned <- cut(x = data[[spd]], breaks = spd.breaks, labels = spd.labels, ordered_result = TRUE) # figure out the wind direction bins dir.breaks <- c(-dirres/2, seq(dirres/2, 360-dirres/2, by = dirres), 360+dirres/2) dir.labels <- c(paste(360-dirres/2,"-",dirres/2), paste(seq(dirres/2, 360-3*dirres/2, by = dirres), "-", seq(3*dirres/2, 360-dirres/2, by = dirres)), paste(360-dirres/2,"-",dirres/2)) # assign each wind direction to a bin dir.binned <- cut(data[[dir]], breaks = dir.breaks, ordered_result = TRUE) levels(dir.binned) <- dir.labels data$dir.binned <- dir.binned # Run debug if required ---- if (debug>0){ cat(dir.breaks,"/n") cat(dir.labels,"/n") cat(levels(dir.binned),"/n") } # create the plot ---- p.windrose <- ggplot(data = data, aes(x = dir.binned, fill = spd.binned ,y = (..count..)/sum(..count..) ))+ geom_bar() + scale_x_discrete(drop = FALSE, labels = c("N","NNE","NE","ENE", "E", "ESE", "SE","SSE", "S","SSW", "SW","WSW", "W", "WNW","NW","NNW")) + coord_polar(start = -((dirres/2)/360) * 2*pi) + scale_fill_manual(name = "Wind Speed (m/s)", values = spd.colors, drop = FALSE) + theme(axis.title.x = element_blank()) + scale_y_continuous(labels = percent) + ylab("Frequencia") # adjust axes if required if (!is.na(countmax)){ p.windrose <- p.windrose + ylim(c(0,countmax)) } # print the plot print(p.windrose) # return the handle to the wind rose return(p.windrose) }


En aras de la argumentación, supondremos que estamos utilizando el marco de datos data.in , que tiene dos columnas de datos y algún tipo de información de fecha / hora. Ignoraremos la información de fecha y hora inicialmente.

La función ggplot

He codificado la función a continuación. Estoy interesado en la experiencia o sugerencias de otras personas sobre cómo mejorar esto.

# WindRose.R require(ggplot2) require(RColorBrewer) plot.windrose <- function(data, spd, dir, spdres = 2, dirres = 30, spdmin = 2, spdmax = 20, spdseq = NULL, palette = "YlGnBu", countmax = NA, debug = 0){ # Look to see what data was passed in to the function if (is.numeric(spd) & is.numeric(dir)){ # assume that we''ve been given vectors of the speed and direction vectors data <- data.frame(spd = spd, dir = dir) spd = "spd" dir = "dir" } else if (exists("data")){ # Assume that we''ve been given a data frame, and the name of the speed # and direction columns. This is the format we want for later use. } # Tidy up input data ---- n.in <- NROW(data) dnu <- (is.na(data[[spd]]) | is.na(data[[dir]])) data[[spd]][dnu] <- NA data[[dir]][dnu] <- NA # figure out the wind speed bins ---- if (missing(spdseq)){ spdseq <- seq(spdmin,spdmax,spdres) } else { if (debug >0){ cat("Using custom speed bins /n") } } # get some information about the number of bins, etc. n.spd.seq <- length(spdseq) n.colors.in.range <- n.spd.seq - 1 # create the color map spd.colors <- colorRampPalette(brewer.pal(min(max(3, n.colors.in.range), min(9, n.colors.in.range)), palette))(n.colors.in.range) if (max(data[[spd]],na.rm = TRUE) > spdmax){ spd.breaks <- c(spdseq, max(data[[spd]],na.rm = TRUE)) spd.labels <- c(paste(c(spdseq[1:n.spd.seq-1]), ''-'', c(spdseq[2:n.spd.seq])), paste(spdmax, "-", max(data[[spd]],na.rm = TRUE))) spd.colors <- c(spd.colors, "grey50") } else{ spd.breaks <- spdseq spd.labels <- paste(c(spdseq[1:n.spd.seq-1]), ''-'', c(spdseq[2:n.spd.seq])) } data$spd.binned <- cut(x = data[[spd]], breaks = spd.breaks, labels = spd.labels, ordered_result = TRUE) # clean up the data data. <- na.omit(data) # figure out the wind direction bins dir.breaks <- c(-dirres/2, seq(dirres/2, 360-dirres/2, by = dirres), 360+dirres/2) dir.labels <- c(paste(360-dirres/2,"-",dirres/2), paste(seq(dirres/2, 360-3*dirres/2, by = dirres), "-", seq(3*dirres/2, 360-dirres/2, by = dirres)), paste(360-dirres/2,"-",dirres/2)) # assign each wind direction to a bin dir.binned <- cut(data[[dir]], breaks = dir.breaks, ordered_result = TRUE) levels(dir.binned) <- dir.labels data$dir.binned <- dir.binned # Run debug if required ---- if (debug>0){ cat(dir.breaks,"/n") cat(dir.labels,"/n") cat(levels(dir.binned),"/n") } # deal with change in ordering introduced somewhere around version 2.2 if(packageVersion("ggplot2") > "2.2"){ cat("Hadley broke my code/n") data$spd.binned = with(data, factor(spd.binned, levels = rev(levels(spd.binned)))) spd.colors = rev(spd.colors) } # create the plot ---- p.windrose <- ggplot(data = data, aes(x = dir.binned, fill = spd.binned)) + geom_bar() + scale_x_discrete(drop = FALSE, labels = waiver()) + coord_polar(start = -((dirres/2)/360) * 2*pi) + scale_fill_manual(name = "Wind Speed (m/s)", values = spd.colors, drop = FALSE) + theme(axis.title.x = element_blank()) # adjust axes if required if (!is.na(countmax)){ p.windrose <- p.windrose + ylim(c(0,countmax)) } # print the plot print(p.windrose) # return the handle to the wind rose return(p.windrose) }

Prueba de concepto y lógica

Ahora comprobaremos que el código haga lo que esperamos. Para esto, usaremos el conjunto simple de datos de demostración.

# try the default settings p0 <- plot.windrose(spd = data.in$ws.80, dir = data.in$wd.80)

Esto nos da esta trama: Entonces: hemos ordenado correctamente los datos por dirección y velocidad del viento, y hemos codificado nuestros datos fuera de rango como se esperaba. ¡Se ve bien!

Usando esta función

Ahora cargamos los datos reales. Podemos cargar esto desde la URL:

data.in <- read.csv(file = "http://midcdmz.nrel.gov/apps/plot.pl?site=NWTC&start=20010824&edy=26&emo=3&eyr=2062&year=2013&month=1&day=1&endyear=2013&endmonth=12&endday=31&time=0&inst=21&inst=39&type=data&wrlevel=2&preset=0&first=3&math=0&second=-1&value=0.0&user=0&axis=1", col.names = c("date","hr","ws.80","wd.80"))

o del archivo:

data.in <- read.csv(file = "A:/blah/20130101.csv", col.names = c("date","hr","ws.80","wd.80"))

La manera rápida

La manera simple de usar esto con los datos M2 es simplemente pasar en vectores separados para spd y dir (velocidad y dirección):

# try the default settings p1 <- plot.windrose(spd = data.in$ws.80, dir = data.in$wd.80)

Lo que nos da esta trama:

Y si queremos contenedores personalizados, podemos agregarlos como argumentos:

p2 <- plot.windrose(spd = data.in$ws.80, dir = data.in$wd.80, spdseq = c(0,3,6,12,20))

Usar un marco de datos y los nombres de las columnas

Para que las tramas sean más compatibles con ggplot() , también puede pasar un marco de datos y el nombre de las variables de velocidad y dirección:

p.wr2 <- plot.windrose(data = data.in, spd = "ws.80", dir = "wd.80")

Faceting por otra variable

También podemos trazar los datos por mes o año usando la capacidad de facetado de ggplot. Comencemos por obtener la marca de tiempo de la información de fecha y hora en data.in , y la conversión a mes y año:

# first create a true POSIXCT timestamp from the date and hour columns data.in$timestamp <- as.POSIXct(paste0(data.in$date, " ", data.in$hr), tz = "GMT", format = "%m/%d/%Y %H:%M") # Convert the time stamp to years and months data.in$Year <- as.numeric(format(data.in$timestamp, "%Y")) data.in$month <- factor(format(data.in$timestamp, "%B"), levels = month.name)

A continuación, puede aplicar facetas para mostrar cómo la rosa de los vientos varía por mes:

# recreate p.wr2, so that includes the new data p.wr2 <- plot.windrose(data = data.in, spd = "ws.80", dir = "wd.80") # now generate the faceting p.wr3 <- p.wr2 + facet_wrap(~month, ncol = 3) # and remove labels for clarity p.wr3 <- p.wr3 + theme(axis.text.x = element_blank(), axis.title.x = element_blank())

Comentarios

Algunas cosas que debe tener en cuenta sobre la función y cómo se puede usar:

  • Las entradas son:
    • vectores de velocidad ( spd ) y dirección ( dir ) o el nombre del marco de datos y los nombres de las columnas que contienen los datos de velocidad y dirección.
    • valores opcionales del tamaño del contenedor para velocidad del viento ( spdres ) y dirección ( dirres ).
    • palette es el nombre de una paleta secuencial colorbrewer ,
    • countmax establece el rango de la rosa de los vientos.
    • debug es un modificador (0,1,2) para habilitar diferentes niveles de depuración.
  • Quería poder establecer la velocidad máxima ( spdmax ) y el recuento ( countmax ) para las tramas para que pueda comparar las mareas de viento de diferentes conjuntos de datos
  • Si hay velocidades de viento que exceden ( spdmax ), esas se agregan como una región gris (ver la figura). Probablemente debería codificar algo como spdmin también, y regiones de código de color donde las velocidades del viento son menores que eso.
  • A raíz de una solicitud, implementé un método para usar contenedores de velocidad de viento personalizados. Se pueden agregar utilizando el spdseq = c(1,3,5,12) .
  • Puede eliminar las etiquetas de bin de grado utilizando los comandos ggplot habituales para borrar el eje x: p.wr3 + theme(axis.text.x = element_blank(),axis.title.x = element_blank()) .
  • En algún momento recientemente ggplot2 cambió el orden de los contenedores, de modo que las tramas no funcionaron. Creo que esta era la versión 2.2. Pero, si sus tramas se ven un poco raras, cambie el código para que la prueba para "2.2" sea tal vez "2.1" o "2.0".