风玫瑰与ggplot(R)?

时间:2013-06-24 01:02:13

标签: r ggplot2 rose-diagram

我正在寻找使用ggplot2来创建显示风的频率,大小和方向的wind roses的良好R代码(或包)。

我对ggplot2特别感兴趣,因为构建情节可以让我有机会利用其中的其他功能。

测试数据

National Wind Technology's "M2"塔上的80米级别下载一年的天气数据。 This link将创建一个自动下载的.csv文件。您需要找到该文件(它被称为“20130101.csv”),并将其读入。

# 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))

这适用于任何.csv文件,并会覆盖列名。

样本数据

如果您不想下载该数据,我们将使用以下10个数据点来演示该过程:

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

1L,1L),. Label =“1/1/2013”​​,class =“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)),. Name = c(“日期”,“小时”,“ws.80”,“wd.80” ),row.names = c(NA,-9L),class =“data.frame”)

4 个答案:

答案 0 :(得分:65)

为了论证,我们假设我们使用data.in数据框,它有两个数据列和某种日期/时间信息。我们最初会忽略日期和时间信息。

ggplot函数

我编写了以下功能。我对其他人的经验或建议如何改善这一点感兴趣。

# 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)
}

概念和逻辑证明

我们现在将检查代码是否符合我们的预期。为此,我们将使用简单的演示数据集。

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

这给了我们这个情节: Unit Test Results 所以:我们已经按方向和风速正确地对数据进行了分类,并按预期编码了我们的超出范围的数据。看起来不错!

使用此功能

现在我们加载真实数据。我们可以从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"))

或来自档案:

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

快捷方式

使用M2数据的简单方法是只传入spddir(速度和方向)的单独向量:

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

这给了我们这个情节:

enter image description here

如果我们想要自定义分档,我们可以将它们添加为参数:

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

enter image description here

使用数据框和列名

要使图表与ggplot()更兼容,您还可以传入数据框和速度和方向变量的名称

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

面对另一个变量

我们还可以使用ggplot的分面功能按月或年绘制数据。让我们首先从data.in中的日期和小时信息中获取时间戳,然后转换为月份和年份:

# 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)

然后,您可以应用分面来显示风的变化如何随月变化:

# 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())

enter image description here

评论

有关该功能及其使用方法的一些注意事项:

  • 输入是:
    • 速度向量(spd)和方向(dir数据框的名称以及包含速度和方向数据的列的名称。
    • 风速(spdres)和方向(dirres)的箱尺寸的可选值。
    • palettecolorbrewer顺序调色板的名称,
    • countmax设定风玫瑰的范围。
    • debug是一个开关(0,1,2),用于启用不同级别的调试。
  • 我希望能够为图表设置最大速度(spdmax)和计数(countmax),以便我可以比较来自不同数据集的windroses
  • 如果风速超过(spdmax),则会将其添加为灰色区域(请参见图)。我应该编写类似spdmin的代码,以及风速小于此值的颜色代码区域。
  • 根据请求,我实施了一种使用自定义风速箱的方法。可以使用spdseq = c(1,3,5,12)参数添加它们。
  • 您可以使用常用的ggplot命令删除度数bin标签以清除x轴:p.wr3 + theme(axis.text.x = element_blank(),axis.title.x = element_blank())
  • 最近ggplot2在某些时候更改了垃圾箱的顺序,因此这些图不起作用。我认为这是版本2.2。但是,如果您的情节看起来有点奇怪,请更改代码,以便测试“2.2”可能是“2.1”或“2.0”。

答案 1 :(得分:5)

这是我的代码版本。我添加了方向标签(N,NNE,NE,ENE,E ....),并使y标签以百分比而不是计数显示频率。

Click here to see figure of wind Rose with directions and frequency (%)

    # 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)
}

答案 2 :(得分:1)

您是否尝试过Openair包中的windRose功能?它非常简单,您可以设置间隔,统计等。

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, ...)

答案 3 :(得分:0)

enter image description here我按照您的建议,尝试使用代码复制一个方面,但是结果如下:

我找不到显示所有13个方面的方法