问:
unknown NAs in ggplot
I'm making a wind rose plot for wind speed/direction data, and found a very cool custom function.

[https://stackoverflow.com/questions/17266780/wind-rose-with-ggplot-r/17266781#17266781]

Everything runs smoothly, but when the plot comes up, there is a chunk of NA data that shows up. There are no NAs in the dataframe, and I can't think of why there is an NA label with so much data in it...

Thank you!

Code below:

```<code>plot.windrose <- function(data,
                          spd,
                          dir,
                          spdres = 2,
                          dirres = 22.5,
                          spdmin = 0,
                          spdmax = 18,
                          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()) + #I can put in my own theme settings
    scale_y_continuous(labels = percent) + # these are lined up with North bar, showing percent of time in a bin
    ylab("Frequency")

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

plot.windrose(data = SR_plaster_wind_inst1,
              spd = SR_plaster_wind_inst1$wind_speed,
              dir = SR_plaster_wind_inst1$wind_direction,
              spdmin = 0,
              spdmax = 18,
              spdres = 2,
              dirres = 22.5,
              palette = "YlGnBu")
</code>```

enter image description here
enter link description here

答:
Edit

Thanks for adding the link to your data, it makes it a lot easier to troubleshoot when you can replicate the issue. The problem appears to be caused when 'wind_speed = 0'. If you change the line spd.breaks <- spdseq to spd.breaks <- spdseq - 0.001 any wind_speed values that equal zero are included on the figure, instead of being labelled "NA", i.e.

library(tidyverse)
library(scales)
#>
#> Attaching package: 'scales'
#> The following object is masked from 'package:purrr':
#>
#>     discard
#> The following object is masked from 'package:readr':
#>
#>     col_factor
library(RColorBrewer)

df <- read_csv("https://raw.githubusercontent.com/c4hendrickson/SFSU_Thesis/main/Data/SR_plaster_wind_inst1.csv")
#> Rows: 1158 Columns: 2
#> ── Column specification ────────────────────────────────────────────────────────
#> Delimiter: ","
#> dbl (2): wind_speed, wind_direction
#>
#> ℹ Use `spec()` to retrieve the full column specification for this data.
#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

plot.windrose <- function(data,
                          spd,
                          dir,
                          spdres = 2,
                          dirres = 22.5,
                          spdmin = 0,
                          spdmax = 18,
                          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()) + #I can put in my own theme settings
    scale_y_continuous(labels = percent) + # these are lined up with North bar, showing percent of time in a bin
    ylab("Frequency")

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

plot.windrose(data = df,
              spd = "wind_speed",
              dir = "wind_direction",
              spdmin = 0,
              spdmax = 20,
              spdres = 2,
              dirres = 22.5,
              palette = "YlGnBu")
```
<p><img src="https://i.imgur.com/WnAArHp.png" alt="" /></p>
<pre class="lang-r prettyprint-override"><code>
plot.windrose <- function(data,
                          spd,
                          dir,
                          spdres = 2,
                          dirres = 22.5,
                          spdmin = 0,
                          spdmax = 18,
                          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 - 0.001
    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()) + #I can put in my own theme settings
    scale_y_continuous(labels = percent) + # these are lined up with North bar, showing percent of time in a bin
    ylab("Frequency")

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

plot.windrose(data = df,
              spd = "wind_speed",
              dir = "wind_direction",
              spdmin = 0,
              spdmax = 20,
              spdres = 2,
              dirres = 22.5,
              palette = "YlGnBu")
</code>```

Created on 2022-02-11 by the reprex package (v2.0.1)

Original answer

I suspect this is due to the number of colors in the "YlGnBu" RColorBrewer pallete (n=9). If you increase the size of the bins (i.e. spdres = 3) or use a different pallete with more colors (i.e. palette = "RdYlBl") do you see fewer NA's?

Do you have any speeds over 18m/s? I.e. if you specify spdmax = 30 and spdres = 4 do you see fewer NA's?

Title: unknown NAs in ggplot

Body:
I'm making a wind rose plot for wind speed/direction data, and found a very cool custom function.

[https://stackoverflow.com/questions/17266780/wind-rose-with-ggplot-r/17266781#17266781]

Everything runs smoothly, but when the plot comes up, there is a chunk of NA data that shows up. There are no NAs in the dataframe, and I can't think of why there is an NA label with so much data in it...

Thank you!

Code below:

plot.windrose <- function(data,
                          spd,
                          dir,
                          spdres = 2,
                          dirres = 22.5,
                          spdmin = 0,
                          spdmax = 18,
                          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()) + #I can put in my own theme settings
    scale_y_continuous(labels = percent) + # these are lined up with North bar, showing percent of time in a bin
    ylab("Frequency")

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

plot.windrose(data = SR_plaster_wind_inst1,
              spd = SR_plaster_wind_inst1$wind_speed,
              dir = SR_plaster_wind_inst1$wind_direction,
              spdmin = 0,
              spdmax = 18,
              spdres = 2,
              dirres = 22.5,
              palette = "YlGnBu")

enter image description here
enter link description here

Body:
Edit

Thanks for adding the link to your data, it makes it a lot easier to troubleshoot when you can replicate the issue. The problem appears to be caused when 'wind_speed = 0'. If you change the line spd.breaks <- spdseq to spd.breaks <- spdseq - 0.001 any wind_speed values that equal zero are included on the figure, instead of being labelled "NA", i.e.

library(tidyverse)
library(scales)
#>
#> Attaching package: 'scales'
#> The following object is masked from 'package:purrr':
#>
#>     discard
#> The following object is masked from 'package:readr':
#>
#>     col_factor
library(RColorBrewer)

df <- read_csv("https://raw.githubusercontent.com/c4hendrickson/SFSU_Thesis/main/Data/SR_plaster_wind_inst1.csv")
#> Rows: 1158 Columns: 2
#> ── Column specification ────────────────────────────────────────────────────────
#> Delimiter: ","
#> dbl (2): wind_speed, wind_direction
#>
#> ℹ Use `spec()` to retrieve the full column specification for this data.
#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

plot.windrose <- function(data,
                          spd,
                          dir,
                          spdres = 2,
                          dirres = 22.5,
                          spdmin = 0,
                          spdmax = 18,
                          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()) + #I can put in my own theme settings
    scale_y_continuous(labels = percent) + # these are lined up with North bar, showing percent of time in a bin
    ylab("Frequency")

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

plot.windrose(data = df,
              spd = "wind_speed",
              dir = "wind_direction",
              spdmin = 0,
              spdmax = 20,
              spdres = 2,
              dirres = 22.5,
              palette = "YlGnBu")

plot.windrose <- function(data,
                          spd,
                          dir,
                          spdres = 2,
                          dirres = 22.5,
                          spdmin = 0,
                          spdmax = 18,
                          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 - 0.001
    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()) + #I can put in my own theme settings
    scale_y_continuous(labels = percent) + # these are lined up with North bar, showing percent of time in a bin
    ylab("Frequency")

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

plot.windrose(data = df,
              spd = "wind_speed",
              dir = "wind_direction",
              spdmin = 0,
              spdmax = 20,
              spdres = 2,
              dirres = 22.5,
              palette = "YlGnBu")

Created on 2022-02-11 by the reprex package (v2.0.1)

Original answer

I suspect this is due to the number of colors in the "YlGnBu" RColorBrewer pallete (n=9). If you increase the size of the bins (i.e. spdres = 3) or use a different pallete with more colors (i.e. palette = "RdYlBl") do you see fewer NA's?

Do you have any speeds over 18m/s? I.e. if you specify spdmax = 30 and spdres = 4 do you see fewer NA's?


来源: stackexchange

问:
How to read Custom Attributes using reflection set by Fluent API in EF 4.1
I've managed to read custom attributes when I use data annotation.
like following code.

```<code>Object[] test = propertyInfo.GetCustomAttributes(typeof(KeyAttribute), true);
</code>```

But when I changed to use Fluent API. I couldn't read that attribute anymore.
Any idea?

答:
Fluent API does not set attributes. Fluent API and Attributes tell EF how to build the model.

These are two different ways to achieve the same thing. That is to build the Model.

Edit

If you need to retrieve the metadata such as primary keys you need to access the MetadataWorkspace.

This article has the details.

ContentLicense: CC BY-SA 3.0

Body:
I've managed to read custom attributes when I use data annotation.
like following code.

Object[] test = propertyInfo.GetCustomAttributes(typeof(KeyAttribute), true);

But when I changed to use Fluent API. I couldn't read that attribute anymore.
Any idea?


问:
Can a polymorphic constant be mapped over a list of *types*?
Haskell hobbyist here - is it possible to map a polymorphic constant over a list of types in a generic way?

More precisely, consider this snippet:

```<code>{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}

module Main where

import Data.Kind( Type )

class HasName a where name :: String

instance HasName Int where name = "Int"

instance HasName Double where name = "Double"

class AllNames (ts :: [Type]) where
  allNames :: [String]

instance AllNames '[] where
  allNames = []

instance (HasName t, AllNames rest) => AllNames (t ': rest) where
  allNames = name @t : allNames @rest

main :: IO ()
main = print $ allNames @'[Int, Double]
</code>```

Unsurprisingly, this works as expected, i.e., it prints ["Int","Double"]. However, if I try to generalize the pattern above so that the code can be used with any name-like polymorphic constant, then I run into problems.

Here's my attempt at generalization:

```<code>{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}

module Main where

import Data.Kind( Constraint, Type )

--
-- Intended to be the generalized version of 'name'
--
type PolymorphicConstant (c :: Type -> Constraint) (a :: Type) = forall t . c t => a

--
-- Intended to be the generalized version of 'AllNames'
--
class AllPolymorphicConstants (c :: Type -> Constraint) (ts :: [Type]) (a :: Type) where
  allPolymorphicConstants :: PolymorphicConstant c a -> [ a ]

instance AllPolymorphicConstants c '[] a where
  allPolymorphicConstants _ = []

instance (c t, AllPolymorphicConstants c rest a) => AllPolymorphicConstants c (t ': rest) a where
  allPolymorphicConstants f = f @t : allPolymorphicConstants @c @rest @a f

</code>```

Alas, this doesn't compile (btw, I'm using GHC 8.10.7):

```<code>Main.hs:31:74: error:
    • Could not deduce: c t0 arising from a use of ‘f’
      from the context: (c t, AllPolymorphicConstants c rest a)
        bound by the instance declaration at Main.hs:30:10-91
      or from: c t1
        bound by a type expected by the context:
                  PolymorphicConstant c a
        at Main.hs:31:74
    • In the fourth argument of ‘allPolymorphicConstants’, namely ‘f’
      In the second argument of ‘(:)’, namely
        ‘allPolymorphicConstants @c @rest @a f’
      In the expression: f @t : allPolymorphicConstants @c @rest @a f
    • Relevant bindings include
        f :: PolymorphicConstant c a (bound at Main.hs:31:27)
        allPolymorphicConstants :: PolymorphicConstant c a -> [a]
          (bound at Main.hs:31:3)
   |
31 |   allPolymorphicConstants f = f @t : allPolymorphicConstants @c @rest @a f
   |                                                                          ^
</code>```

I'm probably missing something basic that makes this sort of generalization impossible - but what is it exactly?

答:
I wish someone can prove me wrong, but this is one of the few corner cases where we meet a limitation of current GHC and we can not get away from using Proxy, Tagged or similar "relics" of the past.

A minimal example

Let's consider a simpler example:

```<code>class C a where

-- Ambiguous type
type T a = forall t. C t => a
</code>```

Note that, if we have a value x :: T a, there is no unambiguous way to use it except with an explicit type argument x @t. That's the price to pay for using ambiguous types, but that's fine.

The following code type-checks as expected.

```<code>foo :: forall t a. (C t) => T a -> a
foo f = f @t
</code>```

Instead, this does not.

```<code>-- Error: Could not deduce (C t0) arising from a use of `foo'
foo2 :: forall t a. (C t) => T a -> a
foo2 = foo
</code>```

This might be surprising at first. Indeed, foo2 has exactly the same type of foo, so foo2=foo is obviously OK! Yet, it fails. The reason is, once again, ambiguous types, and the thumb rule still is: if something has an ambiguous type, we can not use it if we don't pass additional @t @a arguments.

Doing that makes everything work.

```<code>foo3 :: forall t a. (C t) => T a -> a
foo3 = foo @t @a
</code>```

The above is a little strange since we can't write (and have not to write) foo3 @t @a = foo @t @a. I guess that if GHC forced us to do that, then it could also allow us to "eta-contract the type arguments" everything and write foo3 = foo.

Now, what if we eta-expand the value argument (not the type!). We get an error:

```<code>-- Error: Could not deduce (C t0) arising from a use of `x'
foo4 :: forall t a. (C t) => T a -> a
foo4 x = foo @t @a x
</code>```

Groan. This is simply foo3 = foo @t @a eta-expanded. What's going wrong here? Well, the issue is the same: now we introduced x :: T a, and that's an ambiguous type, so we can not use x without @... arguments. Even if foo expects a polymorphic value!

Here we find ourselves unable to escape. GHC sees the polymorphic arguments and adds an implicit type argument abstraction over x, adding (\@t0 -> ... in front. But that's a kind of syntax we are not allowed to use, and there is no way to capture the fresh type variable t0. In other words, we would like to write

```<code>foo4 :: forall t a. (C t) => T a -> a
foo4 x = foo @t @a (\@t0 -> x @t0)
</code>```

but we can only write

```<code>foo4 :: forall t a. (C t) => T a -> a
foo4 x = foo @t @a (x @something)
</code>```

and there is no way to mention t0 there. Sigh.

Using proxies

The only "solution" I can see it to use Proxy (or similar relics), and avoid ambiguous types.

```<code>-- No longer ambiguous
type T a = forall t. C t => Proxy t -> a

foo :: forall t a. (C t) => T a -> a
foo f = f (Proxy @t)

foo4 :: forall t a. (C t) => T a -> a
foo4 x = foo @t @a x
</code>```

Now we can use x as-is since it has no longer an ambiguous type.

Using Tagged or wrapping the polymorphic value inside a newtype or data would also work, since it makes the type no longer ambiguous.

The original code, proxy-fied

```<code>type PolymorphicConstant (c :: Type -> Constraint) (a :: Type)
   = forall t . c t => Proxy t -> a

--
-- Intended to be the generalized version of 'AllNames'
--
class AllPolymorphicConstants (c :: Type -> Constraint) (ts :: [Type]) (a :: Type) where
  allPolymorphicConstants :: PolymorphicConstant c a -> [ a ]

instance AllPolymorphicConstants c '[] a where
  allPolymorphicConstants _ = []

instance (c t, AllPolymorphicConstants c rest a)
    => AllPolymorphicConstants c (t ': rest) a where
  allPolymorphicConstants f = f (Proxy @t) : allPolymorphicConstants @c @rest @a f
</code>```

ContentLicense: CC BY-SA 4.0

Body:
Haskell hobbyist here - is it possible to map a polymorphic constant over a list of types in a generic way?

More precisely, consider this snippet:

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}

module Main where

import Data.Kind( Type )

class HasName a where name :: String

instance HasName Int where name = "Int"

instance HasName Double where name = "Double"

class AllNames (ts :: [Type]) where
  allNames :: [String]

instance AllNames '[] where
  allNames = []

instance (HasName t, AllNames rest) => AllNames (t ': rest) where
  allNames = name @t : allNames @rest

main :: IO ()
main = print $ allNames @'[Int, Double]

Unsurprisingly, this works as expected, i.e., it prints ["Int","Double"]. However, if I try to generalize the pattern above so that the code can be used with any name-like polymorphic constant, then I run into problems.

Here's my attempt at generalization:

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}

module Main where

import Data.Kind( Constraint, Type )

--
-- Intended to be the generalized version of 'name'
--
type PolymorphicConstant (c :: Type -> Constraint) (a :: Type) = forall t . c t => a

--
-- Intended to be the generalized version of 'AllNames'
--
class AllPolymorphicConstants (c :: Type -> Constraint) (ts :: [Type]) (a :: Type) where
  allPolymorphicConstants :: PolymorphicConstant c a -> [ a ]

instance AllPolymorphicConstants c '[] a where
  allPolymorphicConstants _ = []

instance (c t, AllPolymorphicConstants c rest a) => AllPolymorphicConstants c (t ': rest) a where
  allPolymorphicConstants f = f @t : allPolymorphicConstants @c @rest @a f

Alas, this doesn't compile (btw, I'm using GHC 8.10.7):

Main.hs:31:74: error:
    • Could not deduce: c t0 arising from a use of ‘f’
      from the context: (c t, AllPolymorphicConstants c rest a)
        bound by the instance declaration at Main.hs:30:10-91
      or from: c t1
        bound by a type expected by the context:
                  PolymorphicConstant c a
        at Main.hs:31:74
    • In the fourth argument of ‘allPolymorphicConstants’, namely ‘f’
      In the second argument of ‘(:)’, namely
        ‘allPolymorphicConstants @c @rest @a f’
      In the expression: f @t : allPolymorphicConstants @c @rest @a f
    • Relevant bindings include
        f :: PolymorphicConstant c a (bound at Main.hs:31:27)
        allPolymorphicConstants :: PolymorphicConstant c a -> [a]
          (bound at Main.hs:31:3)
   |
31 |   allPolymorphicConstants f = f @t : allPolymorphicConstants @c @rest @a f
   |                                                                          ^

I'm probably missing something basic that makes this sort of generalization impossible - but what is it exactly?

Body:
I wish someone can prove me wrong, but this is one of the few corner cases where we meet a limitation of current GHC and we can not get away from using Proxy, Tagged or similar "relics" of the past.

A minimal example

Let's consider a simpler example:

class C a where

-- Ambiguous type
type T a = forall t. C t => a

Note that, if we have a value x :: T a, there is no unambiguous way to use it except with an explicit type argument x @t. That's the price to pay for using ambiguous types, but that's fine.

The following code type-checks as expected.

foo :: forall t a. (C t) => T a -> a
foo f = f @t

Instead, this does not.

-- Error: Could not deduce (C t0) arising from a use of `foo'
foo2 :: forall t a. (C t) => T a -> a
foo2 = foo

This might be surprising at first. Indeed, foo2 has exactly the same type of foo, so foo2=foo is obviously OK! Yet, it fails. The reason is, once again, ambiguous types, and the thumb rule still is: if something has an ambiguous type, we can not use it if we don't pass additional @t @a arguments.

Doing that makes everything work.

foo3 :: forall t a. (C t) => T a -> a
foo3 = foo @t @a

The above is a little strange since we can't write (and have not to write) foo3 @t @a = foo @t @a. I guess that if GHC forced us to do that, then it could also allow us to "eta-contract the type arguments" everything and write foo3 = foo.

Now, what if we eta-expand the value argument (not the type!). We get an error:

-- Error: Could not deduce (C t0) arising from a use of `x'
foo4 :: forall t a. (C t) => T a -> a
foo4 x = foo @t @a x

Groan. This is simply foo3 = foo @t @a eta-expanded. What's going wrong here? Well, the issue is the same: now we introduced x :: T a, and that's an ambiguous type, so we can not use x without @... arguments. Even if foo expects a polymorphic value!

Here we find ourselves unable to escape. GHC sees the polymorphic arguments and adds an implicit type argument abstraction over x, adding (\@t0 -> ... in front. But that's a kind of syntax we are not allowed to use, and there is no way to capture the fresh type variable t0. In other words, we would like to write

foo4 :: forall t a. (C t) => T a -> a
foo4 x = foo @t @a (\@t0 -> x @t0)

but we can only write

foo4 :: forall t a. (C t) => T a -> a
foo4 x = foo @t @a (x @something)

and there is no way to mention t0 there. Sigh.

Using proxies

The only "solution" I can see it to use Proxy (or similar relics), and avoid ambiguous types.

-- No longer ambiguous
type T a = forall t. C t => Proxy t -> a

foo :: forall t a. (C t) => T a -> a
foo f = f (Proxy @t)

foo4 :: forall t a. (C t) => T a -> a
foo4 x = foo @t @a x

Now we can use x as-is since it has no longer an ambiguous type.

Using Tagged or wrapping the polymorphic value inside a newtype or data would also work, since it makes the type no longer ambiguous.

The original code, proxy-fied

type PolymorphicConstant (c :: Type -> Constraint) (a :: Type)
   = forall t . c t => Proxy t -> a

--
-- Intended to be the generalized version of 'AllNames'
--
class AllPolymorphicConstants (c :: Type -> Constraint) (ts :: [Type]) (a :: Type) where
  allPolymorphicConstants :: PolymorphicConstant c a -> [ a ]

instance AllPolymorphicConstants c '[] a where
  allPolymorphicConstants _ = []

instance (c t, AllPolymorphicConstants c rest a)
    => AllPolymorphicConstants c (t ': rest) a where
  allPolymorphicConstants f = f (Proxy @t) : allPolymorphicConstants @c @rest @a f


问:
How to resolve "Parcel build failed. @parcel/optimizer-terser: "_" is redeclared" error
Good day everyone!

When I tried to build my parcel-based app, I encountered the following error:

```<code>Build failed.

@parcel/optimizer-terser: "_" is redeclared

3724 |
  > 3725 | let _ = (t1)=>t1
  >      |    ^ "\_" is redeclared
    3726 | , t;
    3727 | // src/components/visually-hidden/visually-hidden.styles.ts

  ℹ It's likely that Terser doesn't support this syntax yet.
</code>```

Normally, I would have tried to comb through the console logs to try and debug the issues at hand, but I haven't been able to figure out where to start with this one.

Could someone help guide me in that direction please? Thanks mate!

答:
For me the issue was a wrong import of styled() method when extending a material ui component:

Was importing:

```<code>import { styled } from '@mui/material/styles';
</code>```

instead of:

```<code>import styled from 'styled-components';
</code>```

and was obviously using the styled-components syntax:

```<code>const StyledAutocomplete = styled(Autocomplete) <IStyledAutocompleteP>`
// some css here
`;
</code>```

Body:
Good day everyone!

When I tried to build my parcel-based app, I encountered the following error:

Build failed.

@parcel/optimizer-terser: "_" is redeclared

3724 |
  > 3725 | let _ = (t1)=>t1
  >      |    ^ "\_" is redeclared
    3726 | , t;
    3727 | // src/components/visually-hidden/visually-hidden.styles.ts

  ℹ It's likely that Terser doesn't support this syntax yet.

Normally, I would have tried to comb through the console logs to try and debug the issues at hand, but I haven't been able to figure out where to start with this one.

Could someone help guide me in that direction please? Thanks mate!

Body:
For me the issue was a wrong import of styled() method when extending a material ui component:

Was importing:

import { styled } from '@mui/material/styles';

instead of:

import styled from 'styled-components';

and was obviously using the styled-components syntax:

const StyledAutocomplete = styled(Autocomplete) <IStyledAutocompleteP>`
// some css here
`;


问:
Terraform Azure fails to create Database
Im using terraform 2.33.0 (I tested 2.90.0 too ) to create a sql server and then create a database

Today Ive started getting the following error:

Error waiting on create/update future for SQL Database "x" (Resource
Group "y", Server "z"): Code="45157" Message="Server 'z' is busy with
another operation. Please try your operation later.

I can create the sql database in the portal fine after this failure.

Has anybody seen this issue or anything like it?

The SQL Server is created like this:

```<code>resource "azurerm_sql_server" "tenant_sql" {
  name                         = "fakename"
  resource_group_name          = azurerm_resource_group.tenant_rg.name
  location                     = var.location
  version                      = "12.0"
  administrator_login          = var.sql_server_admin_login
  administrator_login_password = random_password.sql_server_admin_password.result

   tags = {
        Application = "blah"
      Tenant = var.tenant
      CustomerId = var.customer_id
      Environment = var.environment
    }
}
</code>```

The db is created like this

```<code>resource "azurerm_sql_database" "tenant_sqldb" {
  name                             = "x"
  resource_group_name              = azurerm_resource_group.tenant_rg.name
  location                         =  var.location
  server_name                      = "fakename"
  create_mode                      = "Default"
  edition                          = var.database_is_premium == true ? "Premium" : "Standard"
  requested_service_objective_name = var.database_is_premium == true ? "P4" : "S1"
  max_size_bytes = 268435456000
   tags = {
      Application = "bah"
      Tenant      = var.tenant
      CustomerId  = var.customer_id
      Environment = var.environment
    }
}
</code>```

This all executes as one script!

Its worth noting that azurem_sql_database is deprecated so perhaps the RM API behaviour has changed and azurem_sql_database isnt accounting for this.

答: Solved by moving away from the deprecated azurerm_sql_server to azurerm_mssql_server and azurerm_sql_database to azurerm_mssql_database</p>

Body:
Im using terraform 2.33.0 (I tested 2.90.0 too ) to create a sql server and then create a database

Today Ive started getting the following error:

Error waiting on create/update future for SQL Database "x" (Resource
Group "y", Server "z"): Code="45157" Message="Server 'z' is busy with
another operation. Please try your operation later.

I can create the sql database in the portal fine after this failure.

Has anybody seen this issue or anything like it?

The SQL Server is created like this:

resource "azurerm_sql_server" "tenant_sql" {
  name                         = "fakename"
  resource_group_name          = azurerm_resource_group.tenant_rg.name
  location                     = var.location
  version                      = "12.0"
  administrator_login          = var.sql_server_admin_login
  administrator_login_password = random_password.sql_server_admin_password.result

   tags = {
        Application = "blah"
      Tenant = var.tenant
      CustomerId = var.customer_id
      Environment = var.environment
    }
}

The db is created like this

resource "azurerm_sql_database" "tenant_sqldb" {
  name                             = "x"
  resource_group_name              = azurerm_resource_group.tenant_rg.name
  location                         =  var.location
  server_name                      = "fakename"
  create_mode                      = "Default"
  edition                          = var.database_is_premium == true ? "Premium" : "Standard"
  requested_service_objective_name = var.database_is_premium == true ? "P4" : "S1"
  max_size_bytes = 268435456000
   tags = {
      Application = "bah"
      Tenant      = var.tenant
      CustomerId  = var.customer_id
      Environment = var.environment
    }
}

This all executes as one script!

Its worth noting that azurem_sql_database is deprecated so perhaps the RM API behaviour has changed and azurem_sql_database isnt accounting for this.


问:
Formatting Emails from Sheets in Google App Script
I'm trying to format emails from a Google Sheet into a string that I can use as email recipients. I've gotten the emails, and I'm using a for loop to try to remove empty values, but it's not catching ("true" never triggers). Can someone tell me what I'm doing wrong?

Here's my sample sheet: https://docs.google.com/spreadsheets/d/1RPw_sNHF3JTlMYBD_Mk1BTOHDLaXya8IaeuU3YkxHUQ/edit?usp=sharing

Here's my code:

```<code>function affiliateReportReminder() {

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('Sheet1');
  var lastRow = sheet.getRange("A1:A").getLastRow();
  var emails = sheet.getRange("A1:A" + lastRow).getValues();
  for (i = 0; i > lastRow; i++) {
    if (emails[i]='') {
      console.log(true)
      emails.splice(i,1);
    }
  }
  console.log(emails);
};
</code>```

答:
By the way, if you want to remove empty elements from array you can do it with array.filter(String) method. In this case it could be:

```<code>var emails = sheet.getRange("A1:A" + lastRow).getValues().flat().filter(String);
</code>```

array.flat() makes 1D array from 2D array: [[a],[''],[b]] --> [a,'',b]

array.filter(String) removes empty elements: [a,'',c] --> [a,b]

Body:
I'm trying to format emails from a Google Sheet into a string that I can use as email recipients. I've gotten the emails, and I'm using a for loop to try to remove empty values, but it's not catching ("true" never triggers). Can someone tell me what I'm doing wrong?

Here's my sample sheet: https://docs.google.com/spreadsheets/d/1RPw_sNHF3JTlMYBD_Mk1BTOHDLaXya8IaeuU3YkxHUQ/edit?usp=sharing

Here's my code:

function affiliateReportReminder() {

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('Sheet1');
  var lastRow = sheet.getRange("A1:A").getLastRow();
  var emails = sheet.getRange("A1:A" + lastRow).getValues();
  for (i = 0; i > lastRow; i++) {
    if (emails[i]='') {
      console.log(true)
      emails.splice(i,1);
    }
  }
  console.log(emails);
};

Body:
By the way, if you want to remove empty elements from array you can do it with array.filter(String) method. In this case it could be:

var emails = sheet.getRange("A1:A" + lastRow).getValues().flat().filter(String);

array.flat() makes 1D array from 2D array: [[a],[''],[b]] --> [a,'',b]

array.filter(String) removes empty elements: [a,'',c] --> [a,b]


答:
this solution might help https://gis.stackexchange.com/a/368547</p>
```<code>var heatPane = map.getPanes('heatPane').overlayPane; // access the canvas
// now, use mousemove on pane; the leaflet map.on("mousemove", function (e){}) won't help
heatPane.onmousemove = function (e) {
var display_val = lyrHEAT._heatmap.getValueAt({
    x: e.layerX,
    y: e.layerY
});
 // display wherever you like the 'display_val' parameter, either as tooltip or in a div
};
</code>```

Title: Hover over data point on leaflet-heatmap.js heatmap to get value

Body:
I'm following this tutorial and have modified it to meet my needs (mapping Air Quality Index by zip-code). Now I want to hover over a data point to get its value.

Here is the code from the tutorial, which is fairly close to what I ended up with:

var testData = {
  max: 8,
  data: [{lat: 24.6408, lng:46.7728, count: 3},{lat: 50.75, lng:-1.55, count: 1},{lat: 52.6333, lng:1.75, count: 1},{lat: 48.15, lng:9.4667, count: 1},{lat: 52.35, lng:4.9167, count: 2},{lat: 60.8, lng:11.1, count: 1},{lat: 43.561, lng:-116.214, count: 1},{lat: 47.5036, lng:-94.685, count: 1},{lat: 42.1818, lng:-71.1962, count: 1},{lat: 42.0477, lng:-74.1227, count: 1},{lat: 40.0326, lng:-75.719, count: 1},{lat: 40.7128, lng:-73.2962, count: 2},{lat: 27.9003, lng:-82.3024, count: 1},{lat: 38.2085, lng:-85.6918, count: 1},{lat: 46.8159, lng:-100.706, count: 1},{lat: 30.5449, lng:-90.8083, count: 1},{lat: 44.735, lng:-89.61, count: 1},{lat: 41.4201, lng:-75.6485, count: 2},{lat: 39.4209, lng:-74.4977, count: 1},{lat: 39.7437, lng:-104.979, count: 1},{lat: 39.5593, lng:-105.006, count: 1},{lat: 45.2673, lng:-93.0196, count: 1},{lat: 41.1215, lng:-89.4635, count: 1},{lat: 43.4314, lng:-83.9784, count: 1},{lat: 43.7279, lng:-86.284, count: 1},{lat: 40.7168, lng:-73.9861, count: 1},{lat: 47.7294, lng:-116.757, count: 1},{lat: 47.7294, lng:-116.757, count: 2},{lat: 35.5498, lng:-118.917, count: 1},{lat: 34.1568, lng:-118.523, count: 1},{lat: 39.501, lng:-87.3919, count: 3},{lat: 33.5586, lng:-112.095, count: 1},{lat: 38.757, lng:-77.1487, count: 1},{lat: 33.223, lng:-117.107, count: 1},{lat: 30.2316, lng:-85.502, count: 1},{lat: 39.1703, lng:-75.5456, count: 8},{lat: 30.0041, lng:-95.2984, count: 2},{lat: 29.7755, lng:-95.4152, count: 1},{lat: 41.8014, lng:-87.6005, count: 1},{lat: 37.8754, lng:-121.687, count: 7},{lat: 38.4493, lng:-122.709, count: 1},{lat: 40.5494, lng:-89.6252, count: 1},{lat: 42.6105, lng:-71.2306, count: 1},{lat: 40.0973, lng:-85.671, count: 1},{lat: 40.3987, lng:-86.8642, count: 1},{lat: 40.4224, lng:-86.8031, count: 4},{lat: 47.2166, lng:-122.451, count: 1},{lat: 32.2369, lng:-110.956, count: 1},{lat: 41.3969, lng:-87.3274, count: 2},{lat: 41.7364, lng:-89.7043, count: 2},{lat: 42.3425, lng:-71.0677, count: 1},{lat: 33.8042, lng:-83.8893, count: 1},{lat: 36.6859, lng:-121.629, count: 2},{lat: 41.0957, lng:-80.5052, count: 1},{lat: 46.8841, lng:-123.995, count: 1},{lat: 40.2851, lng:-75.9523, count: 2},{lat: 42.4235, lng:-85.3992, count: 1},{lat: 39.7437, lng:-104.979, count: 2},{lat: 25.6586, lng:-80.3568, count: 7},{lat: 33.0975, lng:-80.1753, count: 1},{lat: 25.7615, lng:-80.2939, count: 1},{lat: 26.3739, lng:-80.1468, count: 1},{lat: 37.6454, lng:-84.8171, count: 1},{lat: 34.2321, lng:-77.8835, count: 1},{lat: 34.6774, lng:-82.928, count: 1},{lat: 39.9744, lng:-86.0779, count: 1},{lat: 35.6784, lng:-97.4944, count: 2},{lat: 33.5547, lng:-84.1872, count: 1},{lat: 27.2498, lng:-80.3797, count: 1},{lat: 41.4789, lng:-81.6473, count: 1},{lat: 41.813, lng:-87.7134, count: 1},{lat: 41.8917, lng:-87.9359, count: 1},{lat: 35.0911, lng:-89.651, count: 1},{lat: 32.6102, lng:-117.03, count: 1},{lat: 41.758, lng:-72.7444, count: 1},{lat: 39.8062, lng:-86.1407, count: 1},{lat: 41.872, lng:-88.1662, count: 1},{lat: 34.1404, lng:-81.3369, count: 1},{lat: 46.15, lng:-60.1667, count: 1},{lat: 36.0679, lng:-86.7194, count: 1},{lat: 43.45, lng:-80.5, count: 1},{lat: 44.3833, lng:-79.7, count: 1},{lat: 45.4167, lng:-75.7, count: 2},{lat: 43.75, lng:-79.2, count: 2},{lat: 45.2667, lng:-66.0667, count: 3},{lat: 42.9833, lng:-81.25, count: 2},{lat: 44.25, lng:-79.4667, count: 3},{lat: 45.2667, lng:-66.0667, count: 2},{lat: 34.3667, lng:-118.478, count: 3},{lat: 42.734, lng:-87.8211, count: 1},{lat: 39.9738, lng:-86.1765, count: 1},{lat: 33.7438, lng:-117.866, count: 1},{lat: 37.5741, lng:-122.321, count: 1},{lat: 42.2843, lng:-85.2293, count: 1},{lat: 34.6574, lng:-92.5295, count: 1},{lat: 41.4881, lng:-87.4424, count: 1},{lat: 25.72, lng:-80.2707, count: 1},{lat: 34.5873, lng:-118.245, count: 1},{lat: 35.8278, lng:-78.6421, count: 1}]
};

var baseLayer = L.tileLayer(
  'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
    attribution: '...',
    maxZoom: 18
  }
);

var cfg = {
  // radius should be small ONLY if scaleRadius is true (or small radius is intended)
  // if scaleRadius is false it will be the constant radius used in pixels
  "radius": 2,
  "maxOpacity": .8,
  // scales the radius based on map zoom
  "scaleRadius": true,
  // if set to false the heatmap uses the global maximum for colorization
  // if activated: uses the data maximum within the current map boundaries
  //   (there will always be a red spot with useLocalExtremas true)
  "useLocalExtrema": true,
  // which field name in your data represents the latitude - default "lat"
  latField: 'lat',
  // which field name in your data represents the longitude - default "lng"
  lngField: 'lng',
  // which field name in your data represents the data value - default "value"
  valueField: 'count'
};

var heatmapLayer = new HeatmapOverlay(cfg);

var map = new L.Map('map-canvas', {
  center: new L.LatLng(25.6586, -80.3568),
  zoom: 4,
  layers: [baseLayer, heatmapLayer]
});

heatmapLayer.setData(testData);

Should I get the value by using Leaflet's bindPopup method or is there a better way of doing it? I'm using the latest version of Leaflet.

Any help is greatly appreciated.

EDIT

I never really found the answer but I came up with a close alternative. Forgive me for the hackiness; it wasn't a huge project and I haven't had time to put more effort into it.

What I did was layer the map that I already had with Leaflet's bindPopup method, that way the user can click on the point to retrieve the data.

Here's my code for attaching the data to the click event:

for ( var i=0; i < airdata.length; ++i )
          {
             if (airdata[i].AQI < 40) {
                 var circle = L.circle([airdata[i].LAT, airdata[i].LON], 1000, {
                      color: 'transparent',
                      fillColor: 'transparent',
                      fillOpacity: airdata[i].AQI
                  })
                  .bindPopup(airdata[i].CITY + ', ' + airdata[i].STATE + '
' + airdata[i].ZIPCODE + '
' + 'AQI: ' + airdata[i].AQI.toString())
                  .addTo(map);
              } else if (airdata[i].AQI > 40 & airdata[i].AQI < 60) {
                  var circle = L.circle([airdata[i].LAT, airdata[i].LON], 1000, {
                      color: 'transparent',
                      fillColor: 'transparent',
                      fillOpacity: airdata[i].AQI
                  })
                  .bindPopup(airdata[i].CITY + ', ' + airdata[i].STATE + '
' + airdata[i].ZIPCODE + '
' + 'AQI: ' + airdata[i].AQI.toString())
                  .addTo(map);
              } else {
                  var circle = L.circle([airdata[i].LAT, airdata[i].LON], 1000, {
                      color: 'transparent',
                      fillColor: 'transparent',
                      fillOpacity: airdata[i].AQI
                  })
                  .bindPopup(airdata[i].CITY + ', ' + airdata[i].STATE + '
' + airdata[i].ZIPCODE + '
' + 'AQI: ' + airdata[i].AQI.toString())
                  .addTo(map);
              }
          }
          };

Not ideal, but if I had more time for this I would figure it out. Good luck!

Also, here's a helpful answer: https://gis.stackexchange.com/questions/131944/leaflet-marker-mouseover-popup

Basically says to attach the data to leaflet's mouseover event.

Body:
this solution might help https://gis.stackexchange.com/a/368547

var heatPane = map.getPanes('heatPane').overlayPane; // access the canvas
// now, use mousemove on pane; the leaflet map.on("mousemove", function (e){}) won't help
heatPane.onmousemove = function (e) {
var display_val = lyrHEAT._heatmap.getValueAt({
    x: e.layerX,
    y: e.layerY
});
 // display wherever you like the 'display_val' parameter, either as tooltip or in a div
};


问:
"The return type 'String?' isn't a 'void', as required by the closure's context."
The error I am receiving states "The return type 'String?' isn't a 'void', as required by the closure's context."    the variable "_desc" is a string.

```<code>                    decoration: InputDecoration(labelText: 'Caption'),
                    validator: (value) {
                      return value!.isEmpty ? 'Description is required' : null;
                    },
                    onSaved: (value) {
                      return _desc = value;
                    },
</code>```

Any help would be highly appreciated!

答: Ditch the return. Just assign _desc.

Body:
The error I am receiving states "The return type 'String?' isn't a 'void', as required by the closure's context."    the variable "_desc" is a string.

                    decoration: InputDecoration(labelText: 'Caption'),
                    validator: (value) {
                      return value!.isEmpty ? 'Description is required' : null;
                    },
                    onSaved: (value) {
                      return _desc = value;
                    },

Any help would be highly appreciated!

Body: Ditch the return. Just assign _desc.


问:
Sencha Touch FormPanel submit listener not working
I'm trying to add a listener to a Ext.form.Formpanel subelement Ext.form.BasicForm for the submit event and then reset the form via its .reset() method. In the doc at http://dev.sencha.com/deploy/touch/docs/?class=Ext.form.FormPanel it clearly states that:

```<code>submit : ( Ext.FormPanel this, Object result )
Fires upon successful (Ajax-based) form submission
</code>```

But it somehow it won't really work for me.
This is my code:

```<code>    var messInput = new Ext.form.FormPanel
({
    fullscreen : true,
    url : '/mess/',
    standardSubmit : false,
    listeners : {
        el: {
            submit: function(form, result) {
                form.reset();
            }
        }
            },
    items: [
            new Ext.form.Text ({
                name : 'mess',
                placeHolder: 'Text and #Tags',
                listeners : {
                keyup :function(field, event) {
                    var keyCode = event.browserEvent.keyCode;
                    if(keyCode == 51) {
                        console.log(event.browserEvent.keyCode);
                    }

                }
            }
        })]
});
</code>```

if i try it this way i get a

Uncaught TypeError: Object [object Object] has no method 'reset'

Can somebody explain what the problem is excatly here? do i need to call the parent Formpanel because i add the listener to the underlying el?

答:
You are listening to basic js-event "submit" for the dom-element. You can't get (easily) sencha objects inside it. That's why Ext.form.FormPanel has beforeSubmit-event. The data is already collected so you can reset the form and process to ajax submit with return true;

```<code>form = new Ext.form.FormPanel({
    fullscreen : true,
    url : '/mess/',
    listeners: {
        beforesubmit: function(e, a) {
           this.reset();
           return true;
        }
    },

    standardSubmit : false,
    items: [
            new Ext.form.Text ({
                name : 'mess',
                placeHolder: 'Text and #Tags',
                listeners : {
                keyup :function(field, event) {
                    var keyCode = event.browserEvent.keyCode;
                    if(keyCode == 51) {
                        console.log(event.browserEvent.keyCode);
                    }

                }
            }
        })]
});
</code>```

EDIT: This is the correct way, sorry about the last answer.

Body:
I'm trying to add a listener to a Ext.form.Formpanel subelement Ext.form.BasicForm for the submit event and then reset the form via its .reset() method. In the doc at http://dev.sencha.com/deploy/touch/docs/?class=Ext.form.FormPanel it clearly states that:

submit : ( Ext.FormPanel this, Object result )
Fires upon successful (Ajax-based) form submission

But it somehow it won't really work for me.
This is my code:

    var messInput = new Ext.form.FormPanel
({
    fullscreen : true,
    url : '/mess/',
    standardSubmit : false,
    listeners : {
        el: {
            submit: function(form, result) {
                form.reset();
            }
        }
            },
    items: [
            new Ext.form.Text ({
                name : 'mess',
                placeHolder: 'Text and #Tags',
                listeners : {
                keyup :function(field, event) {
                    var keyCode = event.browserEvent.keyCode;
                    if(keyCode == 51) {
                        console.log(event.browserEvent.keyCode);
                    }

                }
            }
        })]
});

if i try it this way i get a

Uncaught TypeError: Object [object Object] has no method 'reset'

Can somebody explain what the problem is excatly here? do i need to call the parent Formpanel because i add the listener to the underlying el?

Body:
You are listening to basic js-event "submit" for the dom-element. You can't get (easily) sencha objects inside it. That's why Ext.form.FormPanel has beforeSubmit-event. The data is already collected so you can reset the form and process to ajax submit with return true;

form = new Ext.form.FormPanel({
    fullscreen : true,
    url : '/mess/',
    listeners: {
        beforesubmit: function(e, a) {
           this.reset();
           return true;
        }
    },

    standardSubmit : false,
    items: [
            new Ext.form.Text ({
                name : 'mess',
                placeHolder: 'Text and #Tags',
                listeners : {
                keyup :function(field, event) {
                    var keyCode = event.browserEvent.keyCode;
                    if(keyCode == 51) {
                        console.log(event.browserEvent.keyCode);
                    }

                }
            }
        })]
});

EDIT: This is the correct way, sorry about the last answer.


问:
nodejs reachable from internet via react application
I have a react app running on https and a nodejs running localhost:3001. my nodejs app does not capture data from react application.
What have I missed?

server.js (Nodejs)

```<code>const express = require('express');
const bodyParser = require('body-parser');
const nodemailer = require('nodemailer');
const cors = require('cors');
const app = express();
const Excel = require('exceljs');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.use(cors());

app.get('/', ()=>{
 console.log('welcome to test')
})
app.post('/api/xcl', (req, res) =>{

const workbook = new Excel.Workbook();
workbook.xlsx.readFile('test.xlsx')
.then(() =>{
const workSheet = workbook.getWorksheet('test');
workSheet.addRow([req.body.fNamn, req.body.eNamn, req.body.oNamn, req.body.ePost,
req.body.dVal, req.body.kNamn]);
workbook.xlsx.writeFile('test.xlsx');
})
.catch(error => {
console.log(error.message);
});

const PORT = process.env.PORT || 3001
app.listen(PORT, () => console.info(`server has started on ${PORT}`))
</code>```

app.js (Reactjs)

```<code> axios.post('http://localhost/:3001/api/xcl', data)
        .then(res =>{
            setSent(true)
            console.log(res.data)
        })
        .catch(() => {
            console.log(err=>console.log(err.response.data));
        })
</code>```

I have declared the proxy   "proxy": "http://localhost:3001/" in package.json

React app runs on an iis site https://test.me:443

答:
There is another way.
You can create your axios instance, and give it baseURL, then for
http calls use that instance of axios.</p>
```<code>import axios from "axios";
const api = axios.create({
 baseURL: "http://localhost:3001",
});

api.post('/api/xcl', data)
        .then(res =>{
            setSent(true)
            console.log(res.data)
        })
        .catch(() => {
            console.log(err=>console.log(err.response.data));
        })
</code>```

Body:
I have a react app running on https and a nodejs running localhost:3001. my nodejs app does not capture data from react application.
What have I missed?

server.js (Nodejs)

const express = require('express');
const bodyParser = require('body-parser');
const nodemailer = require('nodemailer');
const cors = require('cors');
const app = express();
const Excel = require('exceljs');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.use(cors());

app.get('/', ()=>{
 console.log('welcome to test')
})
app.post('/api/xcl', (req, res) =>{

const workbook = new Excel.Workbook();
workbook.xlsx.readFile('test.xlsx')
.then(() =>{
const workSheet = workbook.getWorksheet('test');
workSheet.addRow([req.body.fNamn, req.body.eNamn, req.body.oNamn, req.body.ePost,
req.body.dVal, req.body.kNamn]);
workbook.xlsx.writeFile('test.xlsx');
})
.catch(error => {
console.log(error.message);
});

const PORT = process.env.PORT || 3001
app.listen(PORT, () => console.info(`server has started on ${PORT}`))

app.js (Reactjs)

 axios.post('http://localhost/:3001/api/xcl', data)
        .then(res =>{
            setSent(true)
            console.log(res.data)
        })
        .catch(() => {
            console.log(err=>console.log(err.response.data));
        })

I have declared the proxy   "proxy": "http://localhost:3001/" in package.json

React app runs on an iis site https://test.me:443

Body:
There is another way.
You can create your axios instance, and give it baseURL, then for
http calls use that instance of axios.

import axios from "axios";
const api = axios.create({
 baseURL: "http://localhost:3001",
});

api.post('/api/xcl', data)
        .then(res =>{
            setSent(true)
            console.log(res.data)
        })
        .catch(() => {
            console.log(err=>console.log(err.response.data));
        })


问:
Making a input range that perfectly aligns with numbers above it
I have a slider that goes from 1 to 12. I would like the thumb to perfectly align with all the numbers above it when I move it up and down.

This is what I have so far, but as you can see, it is still slightly off.

Is there a way to achieve this?

body {
  height: 100vh;
  display: flex;
}

.container {
  margin: auto;
  width: 400px;
}

span {
  display: block;
  width: 1ch;
}

.numbers {
  display: flex;
  justify-content: space-between;
  padding-left: .4em;
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div class="container">
  <div class="numbers">
    <span>1</span><span>2</span><span>3</span><span>4</span><span>5</span><span>6</span><span>7</span><span>8</span><span>9</span><span>10</span><span>11</span><span>12</span>
  </div>
  <input style="width: 100%;" type="range" min="1" max="12" name="" id="" />
</div></code>```

答:
We can configure the number spans so they all have the same width and center text alignment. By setting their initial width to zero we negate the effect of their contents, which vary in size (1 vs 10, for example).

We can use flexbox on the slider as well, giving it the same flex-grow value as twice our 12 numbered spans. This lets us use half-widths for spacing. We add a span on each side of it with a value of half that of the numbered spans, shifting things over properly.

Finally, some margin tweaks get things pixel-perfect (in Chrome, at least).

Note that I've changed the primary width to a relative value so you can see that this works at any size. Have a look at the full screen demo.

The primary drawback here is that we have quantities hard-coded in the CSS. If the slider range changes, so must the CSS. Ideally we'd find a fully flexible solution.

If I'm not making sense, have a look at https://css-tricks.com/snippets/css/a-guide-to-flexbox.

body {
  height: 100vh;
  display: flex;
}

.container {
  margin: auto;
  width: 75vw;
}

.numbers,
.slider {
  display: flex;
  justify-content: space-between;
}

.numbers span,
.slider span {
  width: 0;
  flex-grow: 1;
  text-align: center;
}

.slider span {
  flex-grow: 1;
}

.slider input {
  flex-grow: 24;
  margin-left: -2px; /* account for UI sizing */
  margin-right: -2px; /* account for UI sizing */
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div class="container">
  <div class="numbers">
    <span>1</span><span>2</span><span>3</span><span>4</span><span>5</span><span>6</span><span>7</span><span>8</span><span>9</span><span>10</span><span>11</span><span>12</span>
  </div>

  <div class="slider">
    <span><!-- half --></span>
    <input type="range" min="1" max="12" name="" value="1" id="" />
    <span><!-- half --></span>
  </div>
</div></code>```

Body:
I have a slider that goes from 1 to 12. I would like the thumb to perfectly align with all the numbers above it when I move it up and down.

This is what I have so far, but as you can see, it is still slightly off.

Is there a way to achieve this?

body {
  height: 100vh;
  display: flex;
}

.container {
  margin: auto;
  width: 400px;
}

span {
  display: block;
  width: 1ch;
}

.numbers {
  display: flex;
  justify-content: space-between;
  padding-left: .4em;
}

    123456789101112

  <input style="width: 100%;" type="range" min="1" max="12" name="" id="" />

Body:
We can configure the number spans so they all have the same width and center text alignment. By setting their initial width to zero we negate the effect of their contents, which vary in size (1 vs 10, for example).

We can use flexbox on the slider as well, giving it the same flex-grow value as twice our 12 numbered spans. This lets us use half-widths for spacing. We add a span on each side of it with a value of half that of the numbered spans, shifting things over properly.

Finally, some margin tweaks get things pixel-perfect (in Chrome, at least).

Note that I've changed the primary width to a relative value so you can see that this works at any size. Have a look at the full screen demo.

The primary drawback here is that we have quantities hard-coded in the CSS. If the slider range changes, so must the CSS. Ideally we'd find a fully flexible solution.

If I'm not making sense, have a look at https://css-tricks.com/snippets/css/a-guide-to-flexbox.

body {
  height: 100vh;
  display: flex;
}

.container {
  margin: auto;
  width: 75vw;
}

.numbers,
.slider {
  display: flex;
  justify-content: space-between;
}

.numbers span,
.slider span {
  width: 0;
  flex-grow: 1;
  text-align: center;
}

.slider span {
  flex-grow: 1;
}

.slider input {
  flex-grow: 24;
  margin-left: -2px; /* account for UI sizing */
  margin-right: -2px; /* account for UI sizing */
}

<div class="container">
  <div class="numbers">
    <span>1</span><span>2</span><span>3</span><span>4</span><span>5</span><span>6</span><span>7</span><span>8</span><span>9</span><span>10</span><span>11</span><span>12</span>
  </div>

  <div class="slider">
    <span><!-- half --></span>
    <input type="range" min="1" max="12" name="" value="1" id="" />
    <span><!-- half --></span>
  </div>
</div>


问:
Making a Legend/Key in GraphViz
I’d like to include a legend or key in my GraphViz diagram. I’m having trouble figuring out what code to use, though. I also want to put it in a corner, but the only coord I know for sure is the bottom-left: pos="10,10!".

Does anyone know how I can get this to work?

答:
This works well for simpler legends (from: https://forum.graphviz.org/t/adding-key-or-legend/351)

```<code>digraph l {
  subgraph clusterMain {
      graph [labelloc="b" labeljust="r" label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD>left 1</TD><TD>right 1</TD></TR>
<TR><TD>left 2</TD><TD>right 2</TD></TR>
</TABLE>>];
      "x" "y"
      a -> b -> c
  }
}
</code>```

Title: Making a Legend/Key in GraphViz

Body:
This works well for simpler legends (from: https://forum.graphviz.org/t/adding-key-or-legend/351)

digraph l {
  subgraph clusterMain {
      graph [labelloc="b" labeljust="r" label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD>left 1</TD><TD>right 1</TD></TR>
<TR><TD>left 2</TD><TD>right 2</TD></TR>
</TABLE>>];
      "x" "y"
      a -> b -> c
  }
}


问:
Why is INDEX+MATCH returning more than 1 value when used in a query while the same statement outside of the query returns only 1 value?
Example file:
https://docs.google.com/spreadsheets/d/1M-o8Mu3vBrBgs1wC1WL5kqK61m6Vu1K5ylGByKDCZTo/edit?usp=sharing

On the sheet "To be coached" I have a query in cell A2. The query might not be optimal and maybe it's convoluted, but it works, aside from one small detail that I just can't get to work. This is the current query.

```<code>=QUERY({
IFERROR(QUERY(FILTER(ARRAYFORMULA({MATCH('Quiz results'!F9:F,Team!G2:G,0),'Quiz results'!A9:A,'Quiz results'!C9:C,'Quiz results'!D9:D,IFERROR('Quiz results'!A9:A/0),"Question:"&CHAR(10)&'Quiz results'!G8&CHAR(10)&CHAR(10)&"Provided answer:"&CHAR(10)&'Quiz results'!G9:G&CHAR(10)&CHAR(10)&"Correct answer:"&CHAR(10)&'Quiz results'!G7}),'Quiz results'!G9:G<>'Quiz results'!G$7),"SELECT Col1,Col2,Col3,Col4,'Quiz',Col5,'"&'Quiz results'!B6&"','"&'Quiz results'!G6&"',Col6 WHERE Col2 IS NOT NULL LABEL 'Quiz' '','"&'Quiz results'!B6&"' '','"&'Quiz results'!G6&"' ''"),{"","","","","","","",""})
},"SELECT * WHERE Col1 IS NOT NULL ORDER BY Col2,Col1")
</code>```

Column B shows names, which for the sake of the example I have obfuscated into "Person 1" and so on. The result I'm trying to achieve is that column A shows whether the person mentioned in column B has an active status or not. That information is present on the sheet "Team" in column A.

So far, I've been able to get the query to present the row number of an array based on information from the sheet "Team" which contains the status of the relevant person. To do this I used a MATCH statement.

```<code>MATCH('Quiz results'!F9:F,Team!G2:G,0)
</code>```

The problem occurs when I try to get the actual "Yes" and "No" values from the "Team" sheet by combining the MATCH statement with an INDEX statement.

```<code>INDEX(Team!A2:A,MATCH('Quiz results'!F9:F,Team!G2:G,0),1)
</code>```

When I do this, the entire query fails with the message "Query completed with an empty output". This is probably due to the IFERROR statement. When I remove that, the error is as follows.

Function ARRAY_ROW parameter 2 has mismatched row size. Expected: 1.
Actual: 998.

From what I can gather, this means that the INDEX+MATCH statement is providing 998 rows while the expected input for the query is only 1 row. But I don't understand why it is returning so many rows. When I use the same INDEX+MATCH statement on the sheet "Test" in cell A2, it returns only one cell as a result, giving "Yes". (That should actually give a "No" for the particular person on that row, but that is a different problem which might just be occurring due to using the statement in a different context.) Even when I encapsulate the formula in an ARRAYFORMULA, I still only get 1 cell as a result. So why is the same formula giving 998 rows when it's used in the query?

I am open to any and all ideas on how to get column A on sheet "To be coached" to show the correct "Yes" and "No" values for each person based on their status in sheet "Team" by using a single formula in cell A2. The reason for this is that in the end I want to use those values to filter the query result so that it doesn't show data for inactive people. (...WHERE Col1<>"No"...)

答:
try removing that 1 in INDEX which will solve your ARRAY_ROW error:

```<code>=INDEX(Team!A2:A, MATCH('Quiz results'!F9:F, Team!G2:G, 0))
</code>```

fyi, there is VLOOKUP:

```<code>=INDEX(IFNA(VLOOKUP('Quiz results'!F9:F, {Team!G2:G, Team!A2:A}, 2, 0)))
</code>```

Body:
Example file:
https://docs.google.com/spreadsheets/d/1M-o8Mu3vBrBgs1wC1WL5kqK61m6Vu1K5ylGByKDCZTo/edit?usp=sharing

On the sheet "To be coached" I have a query in cell A2. The query might not be optimal and maybe it's convoluted, but it works, aside from one small detail that I just can't get to work. This is the current query.

=QUERY({
IFERROR(QUERY(FILTER(ARRAYFORMULA({MATCH('Quiz results'!F9:F,Team!G2:G,0),'Quiz results'!A9:A,'Quiz results'!C9:C,'Quiz results'!D9:D,IFERROR('Quiz results'!A9:A/0),"Question:"&CHAR(10)&'Quiz results'!G8&CHAR(10)&CHAR(10)&"Provided answer:"&CHAR(10)&'Quiz results'!G9:G&CHAR(10)&CHAR(10)&"Correct answer:"&CHAR(10)&'Quiz results'!G7}),'Quiz results'!G9:G<>'Quiz results'!G$7),"SELECT Col1,Col2,Col3,Col4,'Quiz',Col5,'"&'Quiz results'!B6&"','"&'Quiz results'!G6&"',Col6 WHERE Col2 IS NOT NULL LABEL 'Quiz' '','"&'Quiz results'!B6&"' '','"&'Quiz results'!G6&"' ''"),{"","","","","","","",""})
},"SELECT * WHERE Col1 IS NOT NULL ORDER BY Col2,Col1")

Column B shows names, which for the sake of the example I have obfuscated into "Person 1" and so on. The result I'm trying to achieve is that column A shows whether the person mentioned in column B has an active status or not. That information is present on the sheet "Team" in column A.

So far, I've been able to get the query to present the row number of an array based on information from the sheet "Team" which contains the status of the relevant person. To do this I used a MATCH statement.

MATCH('Quiz results'!F9:F,Team!G2:G,0)

The problem occurs when I try to get the actual "Yes" and "No" values from the "Team" sheet by combining the MATCH statement with an INDEX statement.

INDEX(Team!A2:A,MATCH('Quiz results'!F9:F,Team!G2:G,0),1)

When I do this, the entire query fails with the message "Query completed with an empty output". This is probably due to the IFERROR statement. When I remove that, the error is as follows.

Function ARRAY_ROW parameter 2 has mismatched row size. Expected: 1.
Actual: 998.

From what I can gather, this means that the INDEX+MATCH statement is providing 998 rows while the expected input for the query is only 1 row. But I don't understand why it is returning so many rows. When I use the same INDEX+MATCH statement on the sheet "Test" in cell A2, it returns only one cell as a result, giving "Yes". (That should actually give a "No" for the particular person on that row, but that is a different problem which might just be occurring due to using the statement in a different context.) Even when I encapsulate the formula in an ARRAYFORMULA, I still only get 1 cell as a result. So why is the same formula giving 998 rows when it's used in the query?

I am open to any and all ideas on how to get column A on sheet "To be coached" to show the correct "Yes" and "No" values for each person based on their status in sheet "Team" by using a single formula in cell A2. The reason for this is that in the end I want to use those values to filter the query result so that it doesn't show data for inactive people. (...WHERE Col1<>"No"...)

Body:
try removing that 1 in INDEX which will solve your ARRAY_ROW error:

=INDEX(Team!A2:A, MATCH('Quiz results'!F9:F, Team!G2:G, 0))

fyi, there is VLOOKUP:

=INDEX(IFNA(VLOOKUP('Quiz results'!F9:F, {Team!G2:G, Team!A2:A}, 2, 0)))


问:
Convert string to date in google big query
I have a string column which has date value in the below format

6/1/2020 12:00:00 AM

I want only the date part and convert the column to date
so when i use date_trunc and parse date like below it is giving error

select CAST(DATE_TRUNC(PARSE_DATE('%m/%d/%Y', datecolumn), AS DATE)) from table name

PLease let me know what is the best way to achieve this

答:
Use below</p>
```<code>select date(parse_datetime('%m/%d/%Y %I:%M:%S %p', datecolumn))
from your_table
</code>```

Body:
Use below

select date(parse_datetime('%m/%d/%Y %I:%M:%S %p', datecolumn))
from your_table


问:
SQL merge result set from two select queries and transpose counting
I'm trying to extract data from database with a particular template.

In my database I have the following data:

```<code> System | Type | Number
   A      TypeA   1
   A      TypeB   1
   A      TypeA   1
   B      TypeA   1
</code>```

I'd like to get something like this:

```<code>System | #TypeA | #TypeB
   A       2       1
   B       1       0
</code>```

Is it possible with only one query?

I tried to do full outer join between two queries without success. I'm curious to know the best solution in terms of performance.

Thank you in advance!

答:
You can do this with aggregation using a conditional case expression

```<code>select system,
  Sum(case when type='TypeA' then 1 else 0 end) "#TypeA",
  Sum(case when type='Typeb' then 1 else 0 end) "#TypeB"
from t
group by system;
</code>```

Body:
I'm trying to extract data from database with a particular template.

In my database I have the following data:

 System | Type | Number
   A      TypeA   1
   A      TypeB   1
   A      TypeA   1
   B      TypeA   1

I'd like to get something like this:

System | #TypeA | #TypeB
   A       2       1
   B       1       0

Is it possible with only one query?

I tried to do full outer join between two queries without success. I'm curious to know the best solution in terms of performance.

Thank you in advance!

Body:
You can do this with aggregation using a conditional case expression

select system,
  Sum(case when type='TypeA' then 1 else 0 end) "#TypeA",
  Sum(case when type='Typeb' then 1 else 0 end) "#TypeB"
from t
group by system;


问:
How can I tell if a date is before a certain time in Java?
For example given a java.util.Date how could I test if the time was before 12.30 PM that day?</p>

答:
Create a Date startDate and endDate with the desired dates and then you can do something similar as this: </p>

```<code>if (startDate.before(endDate))
{
  System.out.println("Date is before your given date");
}
</code>```

Body:
Create a Date startDate and endDate with the desired dates and then you can do something similar as this:

if (startDate.before(endDate))
{
  System.out.println("Date is before your given date");
}


问:
Decoding binary version of pdf from REST api call response using Powershell
I have a powershell script where I send a call to REST Api:

```<code>$DownloadReportResponse = Invoke-RestMethod -Method Post -Uri $DownloadReportUrl -ContentType "application/json" -Body $DownloadReportRequestBody | Out-File -FilePath ("C:\Practice\Report-01_29_14-28.pdf")  -Force
</code>```

The response I get is a binary representation of the pdf, so it is bunch of texts:

```<code>>>
endobj
5 0 obj
<<
  /N 3
  /Length 11 0 R
  /Filter /FlateDecode
>>
stream
xwXSçÇßsNö`$!l{¥@ ¦Ù¢  $÷@T°¢¨ÈR)X°ZÔ(âÞ
RZ¬âÂÑD§õööÞÛÛïç|ßûû½çý÷y ¤L®0V@(#ü½±qñì `= nn¶WXX0+ÐÍÈ;Ñ« R¼¯1{ÿOªÜl± (LÎ³xü\®ä/ÉVØ'åLKÎP0R°X~@9k(8u?ûÌ°§yBOÎrÎæ  y
îó<)_Î"â<?_Î×ål)
äüF+äsä9 H
</code>```

The Out-File -FilePath ("C:\Neoload\Report-01_29_14-28.pdf") command will save it as a pdf but when I open it I have no luck seeing the content.

Question: What commands are used to decoding the api response which sends pdf in binary representation and how do I go about saving it in my machine?

答:
This should work:

```<code>$DownloadReportResponse = Invoke-RestMethod -Method Post -Uri $DownloadReportUrl -ContentType "application/json" -Body $DownloadReportRequestBody -OutFile "C:\Users\demo\download.pdf"
</code>```

Documentation Example

Body:
I have a powershell script where I send a call to REST Api:

$DownloadReportResponse = Invoke-RestMethod -Method Post -Uri $DownloadReportUrl -ContentType "application/json" -Body $DownloadReportRequestBody | Out-File -FilePath ("C:\Practice\Report-01_29_14-28.pdf")  -Force

The response I get is a binary representation of the pdf, so it is bunch of texts:

>>
endobj
5 0 obj
<<
  /N 3
  /Length 11 0 R
  /Filter /FlateDecode
>>
stream
xwXSçÇßsNö`$!l{¥@ ¦Ù¢  $÷@T°¢¨ÈR)X°ZÔ(âÞ
RZ¬âÂÑD§õööÞÛÛïç|ßûû½çý÷y ¤L®0V@(#ü½±qñì `= nn¶WXX0+ÐÍÈ;Ñ« R¼¯1{ÿOªÜl± (LÎ³xü\®ä/ÉVØ'åLKÎP0R°X~@9k(8u?ûÌ°§yBOÎrÎæ  y
îó<)_Î"â<?_Î×ål)
äüF+äsä9 H

The Out-File -FilePath ("C:\Neoload\Report-01_29_14-28.pdf") command will save it as a pdf but when I open it I have no luck seeing the content.

Question: What commands are used to decoding the api response which sends pdf in binary representation and how do I go about saving it in my machine?

Body:
This should work:

$DownloadReportResponse = Invoke-RestMethod -Method Post -Uri $DownloadReportUrl -ContentType "application/json" -Body $DownloadReportRequestBody -OutFile "C:\Users\demo\download.pdf"

Documentation Example


问:
Laravel Unable to Queue Job
I repeatedly receive the following error when I try to push a job onto my Laravel Queue:

```<code>Argument 1 passed to Illuminate\Queue\Jobs\Job::resolveAndFire() must be of the type array, null given, called in /home/vagrant/Code/project/vendor/laravel/framework/src/Illuminate/Queue/Jobs/BeanstalkdJob.php on line 53 and defined
</code>```

I have no clue what is going wrong but I'm guessing it's something to do with the fact I haven't used the SerializesModel Trait? When I try to use Serializes model, I just get an undefined property $directory error.

The job class is:

```<code>/**
 * Class StoreFile
 * @package App\Jobs
 */
class StoreFile extends Job implements SelfHandling, ShouldQueue
{
    use InteractsWithQueue;

    /**
     * @param string $directory
     * @param string $filename
     * @param UploadedFile $file
     */
    public function __construct($directory, $filename, $file)
    {
        $this->directory = $directory;
        $this->filename = $filename;
        $this->file = $file;
    }

    /**
     * @param FileSystem $storage
     * @return boolean
     */
    public function handle(FileSystem $storage)
    {
        $path = $this->directory . $this->filename;
        $storage->disk('s3')->put($path, $this->file);

        return true;
    }
}
</code>```

UPDATE
I queue the job from another class using this:

```<code>$this->dispatch(new StoreFile($directory, rawurlencode($filename), file_get_contents($evidence)));
</code>```

Where $evidence is an UploadedFile. I'm certain that all the variables are set as if I remove the ShouldQueue/InteractsWithQueue the job executes fine

答: In my case, it was because the jobs tables was having a payload "0" instead of JSON for executing the job.</p>

Title: Laravel Unable to Queue Job

Body:
I repeatedly receive the following error when I try to push a job onto my Laravel Queue:

Argument 1 passed to Illuminate\Queue\Jobs\Job::resolveAndFire() must be of the type array, null given, called in /home/vagrant/Code/project/vendor/laravel/framework/src/Illuminate/Queue/Jobs/BeanstalkdJob.php on line 53 and defined

I have no clue what is going wrong but I'm guessing it's something to do with the fact I haven't used the SerializesModel Trait? When I try to use Serializes model, I just get an undefined property $directory error.

The job class is:

/**
 * Class StoreFile
 * @package App\Jobs
 */
class StoreFile extends Job implements SelfHandling, ShouldQueue
{
    use InteractsWithQueue;

    /**
     * @param string $directory
     * @param string $filename
     * @param UploadedFile $file
     */
    public function __construct($directory, $filename, $file)
    {
        $this->directory = $directory;
        $this->filename = $filename;
        $this->file = $file;
    }

    /**
     * @param FileSystem $storage
     * @return boolean
     */
    public function handle(FileSystem $storage)
    {
        $path = $this->directory . $this->filename;
        $storage->disk('s3')->put($path, $this->file);

        return true;
    }
}

UPDATE
I queue the job from another class using this:

$this->dispatch(new StoreFile($directory, rawurlencode($filename), file_get_contents($evidence)));

Where $evidence is an UploadedFile. I'm certain that all the variables are set as if I remove the ShouldQueue/InteractsWithQueue the job executes fine


问:
Is there a way to convert time logged as Minutes:Seconds into numeric form?
I am working with a dataset that has time tracked as minutes:seconds (34:15 would be 34 minutes and 15 seconds) and its stored as a character currently. Is there a way to convert this to just minutes so that 34:15 would show up as 35.25?</p>

答:
One way would be split on the colon, convert to numeric, then divide the minutes by 60 to get the decimal.</p>
```<code>time <- c("4:30","2:20","34:15")

sapply(strsplit(time,":"),
       function(x) {
         x <- as.numeric(x)
         x[1]+x[2]/60
       }
)

[1]  4.500000  2.333333 34.250000
</code>```

Body:
One way would be split on the colon, convert to numeric, then divide the minutes by 60 to get the decimal.

time <- c("4:30","2:20","34:15")

sapply(strsplit(time,":"),
       function(x) {
         x <- as.numeric(x)
         x[1]+x[2]/60
       }
)

[1]  4.500000  2.333333 34.250000