|
| 1 | +#' @title Plot a legend for a choropleth map |
| 2 | +#' @description This function plots a legend for a choropleth map. |
| 3 | +#' |
| 4 | +#' @param pal a set of colors |
| 5 | +#' @param alpha if \code{pal} is a \link{hcl.colors} palette name, the |
| 6 | +#' alpha-transparency level in the range \[0,1\] |
| 7 | +#' @param col_na color for missing values |
| 8 | +#' @param pos position of the legend, one of "topleft", "top", |
| 9 | +#' "topright", "right", "bottomright", "bottom", "bottomleft", |
| 10 | +#' "left", "interactive" or a vector of two coordinates in map units |
| 11 | +#' (c(x, y)) |
| 12 | +#' @param val break labels |
| 13 | +#' @param title title of the legend |
| 14 | +#' @param title_cex size of the legend title |
| 15 | +#' @param val_cex size of the values in the legend |
| 16 | +#' @param val_rnd number of decimal places of the values in |
| 17 | +#' the legend. |
| 18 | +#' @param val_dec decimal separator |
| 19 | +#' @param val_big thousands separator |
| 20 | +#' @param no_data if TRUE a "missing value" box is plotted |
| 21 | +#' @param no_data_txt label for missing values |
| 22 | +#' @param frame whether to add a frame to the legend (TRUE) or not (FALSE) |
| 23 | +#' @param border color of the boxes' borders |
| 24 | +#' @param size size of the legend; 2 means two times bigger |
| 25 | +#' @param bg background of the legend |
| 26 | +#' @param fg foreground of the legend |
| 27 | +#' @param cex width and height cex of boxes |
| 28 | +#' @param return_bbox return only bounding box of the legend. |
| 29 | +#' No legend is plotted. |
| 30 | +#' @param adj adj |
| 31 | +#' @param frame_border border color of the frame |
| 32 | +#' @keywords internal |
| 33 | +#' @noRd |
| 34 | +#' @import graphics |
| 35 | +#' @return No return value, a legend is displayed. |
| 36 | +#' @examples |
| 37 | +#' plot.new() |
| 38 | +#' plot.window(xlim = c(0, 1), ylim = c(0, 1), asp = 1) |
| 39 | +#' leg_choro(val = c(1, 2, 3, 4), pal = c("red1", "red3", "red4")) |
| 40 | +leg_choro_point <- function(pos = "left", |
| 41 | + val, |
| 42 | + pal = "Inferno", |
| 43 | + alpha = NULL, |
| 44 | + symbol = "circle", |
| 45 | + title = "Legend Title", |
| 46 | + title_cex = .8 * size, |
| 47 | + val_cex = .6 * size, |
| 48 | + val_rnd = 0, |
| 49 | + val_dec = ".", |
| 50 | + val_big = "", |
| 51 | + col_na = "white", |
| 52 | + no_data = FALSE, |
| 53 | + no_data_txt = "No Data", |
| 54 | + frame = FALSE, |
| 55 | + frame_border = fg, |
| 56 | + border = "#333333", |
| 57 | + bg = "#f7f7f7", |
| 58 | + fg = "#333333", |
| 59 | + size = 1, |
| 60 | + cex = 1, |
| 61 | + return_bbox = FALSE, |
| 62 | + adj = c(0, 0)) { |
| 63 | + # spacings |
| 64 | + x_spacing <- xinch(par("csi")) / 4 |
| 65 | + y_spacing <- yinch(par("csi")) / 4 |
| 66 | + |
| 67 | + # boxes sizes |
| 68 | + w_box <- cex * size * x_spacing * 5 * 2 / 3 |
| 69 | + h_box <- cex * size * y_spacing * 5 * 2 / 3 |
| 70 | + |
| 71 | + |
| 72 | + # Nb. boxes and values |
| 73 | + n_val <- length(val) |
| 74 | + n_box <- n_val - 1 |
| 75 | + if (n_val < 2) { |
| 76 | + stop("You need to provide at least two values for 'val'", call. = FALSE) |
| 77 | + } |
| 78 | + |
| 79 | + # rounded and ordered values for the legend |
| 80 | + val <- rev(get_val_rnd( |
| 81 | + val = val, val_rnd = val_rnd, val_dec = val_dec, |
| 82 | + val_big = val_big |
| 83 | + )) |
| 84 | + |
| 85 | + # box colors |
| 86 | + pal <- rev(get_pal(pal, n_box, alpha = alpha)) |
| 87 | + |
| 88 | + # title dimensions |
| 89 | + title_dim <- get_title_dim(title, title_cex) |
| 90 | + |
| 91 | + # boxes dimensions |
| 92 | + boxes_dim <- list(w = w_box, h = n_box * h_box) |
| 93 | + |
| 94 | + # label dimension |
| 95 | + labels_dim <- list( |
| 96 | + w = max(strwidth(val, units = "user", cex = val_cex, font = 1)), |
| 97 | + h = strheight(val[1], units = "user", cex = val_cex, font = 1) / 2 + |
| 98 | + strheight(val[n_val], units = "user", cex = val_cex, font = 1) / 2 + |
| 99 | + n_box * h_box |
| 100 | + ) |
| 101 | + |
| 102 | + # NA box and label dimensions |
| 103 | + if (isTRUE(no_data)) { |
| 104 | + na_box_dim <- list(w = w_box, h = h_box) |
| 105 | + na_label_dim <- list( |
| 106 | + w = strwidth(no_data_txt, units = "user", cex = val_cex, font = 1), |
| 107 | + h = max( |
| 108 | + strheight(no_data_txt, units = "user", cex = val_cex, font = 1), |
| 109 | + h_box |
| 110 | + ) |
| 111 | + ) |
| 112 | + } else { |
| 113 | + na_box_dim <- list(w = 0, h = 0) |
| 114 | + na_label_dim <- list(w = 0, h = 0) |
| 115 | + no_data_txt <- "" |
| 116 | + } |
| 117 | + |
| 118 | + # legend dimension |
| 119 | + legend_dim <- list( |
| 120 | + w = x_spacing + |
| 121 | + max( |
| 122 | + title_dim$w, |
| 123 | + boxes_dim$w + labels_dim$w + x_spacing, |
| 124 | + na_box_dim$w + na_label_dim$w + x_spacing |
| 125 | + ) + |
| 126 | + x_spacing, |
| 127 | + h = y_spacing + |
| 128 | + ifelse(title_dim$h != 0, title_dim$h + 2 * y_spacing * size, 0) + |
| 129 | + labels_dim$h + |
| 130 | + ifelse(na_label_dim$h != 0, na_label_dim$h + y_spacing * size, 0) + |
| 131 | + y_spacing |
| 132 | + ) |
| 133 | + |
| 134 | + # get legend coordinates |
| 135 | + legend_coords <- get_legend_coords( |
| 136 | + pos = pos, legend_dim = legend_dim, |
| 137 | + adj = adj, frame = frame, |
| 138 | + x_spacing = x_spacing, |
| 139 | + y_spacing = y_spacing |
| 140 | + ) |
| 141 | + |
| 142 | + # return legend coordinates only |
| 143 | + if (return_bbox) { |
| 144 | + return(invisible(legend_coords)) |
| 145 | + } |
| 146 | + |
| 147 | + |
| 148 | + # display frame |
| 149 | + plot_frame( |
| 150 | + frame = frame, legend_coords = legend_coords, |
| 151 | + bg = bg, frame_border = frame_border, |
| 152 | + x_spacing = x_spacing, y_spacing = y_spacing |
| 153 | + ) |
| 154 | + |
| 155 | + # display title |
| 156 | + plot_title( |
| 157 | + title = title, title_cex = title_cex, title_dim = title_dim, |
| 158 | + fg = fg, legend_coords = legend_coords, |
| 159 | + x_spacing = x_spacing, y_spacing = y_spacing |
| 160 | + ) |
| 161 | + |
| 162 | + # display boxes |
| 163 | + left <- rep(legend_coords$left + x_spacing, n_box) |
| 164 | + right <- left + w_box |
| 165 | + y <- legend_coords$top - y_spacing - |
| 166 | + ifelse(title_dim$h != 0, title_dim$h + 2 * y_spacing * size, 0) - |
| 167 | + strheight(val[1], units = "user", cex = val_cex, font = 1) / 2 |
| 168 | + top <- rep(NA, n_box) |
| 169 | + for (i in 1:n_box) { |
| 170 | + top[i] <- y - (i - 1) * h_box |
| 171 | + } |
| 172 | + bottom <- top - h_box |
| 173 | + |
| 174 | + if (symbol == "square") { |
| 175 | + rect( |
| 176 | + xleft = left, ybottom = bottom, xright = right, ytop = top, |
| 177 | + col = pal, border = border, lwd = .7 |
| 178 | + ) |
| 179 | + } |
| 180 | + |
| 181 | + if (symbol == "circle") { |
| 182 | + symbols( |
| 183 | + x = left + (right - left) / 2, y = bottom + (top - bottom) / 2, |
| 184 | + circles = (right - left) / 2, inches = F, add = T, |
| 185 | + bg = pal, fg = border, lwd = .7 |
| 186 | + ) |
| 187 | + } |
| 188 | + |
| 189 | + # display labels |
| 190 | + x <- rep(legend_coords$left + x_spacing + w_box + x_spacing, n_val) |
| 191 | + y <- rep(NA, n_val) |
| 192 | + top <- top[1] |
| 193 | + for (i in 1:n_val) { |
| 194 | + y[i] <- top - (i - 1) * h_box |
| 195 | + } |
| 196 | + text(x = x, y = y, labels = val, cex = val_cex, adj = c(0, 0.5), col = fg) |
| 197 | + |
| 198 | + if (isTRUE(no_data)) { |
| 199 | + # display na box |
| 200 | + left <- legend_coords$left + x_spacing |
| 201 | + right <- left + w_box |
| 202 | + bottom <- legend_coords$bottom + y_spacing + |
| 203 | + (na_label_dim$h - na_box_dim$h) / 2 |
| 204 | + top <- bottom + h_box |
| 205 | + if (symbol == "square") { |
| 206 | + rect( |
| 207 | + xleft = left, ybottom = bottom, xright = right, ytop = top, |
| 208 | + col = col_na, border = border, lwd = .7 |
| 209 | + ) |
| 210 | + } |
| 211 | + if (symbol == "circle") { |
| 212 | + symbols( |
| 213 | + x = left + (right - left) / 2, y = bottom + (top - bottom) / 2, |
| 214 | + circles = (right - left) / 2, inches = F, add = T, |
| 215 | + bg = col_na, fg = border, lwd = .7 |
| 216 | + ) |
| 217 | + } |
| 218 | + # display na label |
| 219 | + x <- legend_coords$left + x_spacing + w_box + x_spacing |
| 220 | + y <- bottom + (top - bottom) / 2 |
| 221 | + text( |
| 222 | + x = x, y = y, labels = no_data_txt, cex = val_cex, adj = c(0, 0.5), |
| 223 | + col = fg |
| 224 | + ) |
| 225 | + } |
| 226 | + return(invisible(NULL)) |
| 227 | +} |
0 commit comments