Skip to content

Commit bf7db6e

Browse files
committed
key.pos can hold relative key position in available space
see r-spatial/stars#642
1 parent 1761ed3 commit bf7db6e

File tree

3 files changed

+43
-15
lines changed

3 files changed

+43
-15
lines changed

NEWS.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# version 1.0-15
22

3-
* `[<-.sf` fixes the `agr` attribute if it is broken; #2211
3+
* `plot.sf()`: `key.width` is sensitive to pointsize graphics parameter, `key.pos` can hold a second value in [0, 1] determining the relative position of the key in the available space
4+
5+
* `[<-.sf` fixes the `agr` attribute when it is broken; #2211
46

57
* `sf` objects get a new attribute, `.sf_namespace`, which forces loading the `sf` namespace when it has not been loaded so far, e.g. for proper printing or plotting of an `sf` object; #2212 by Mike Mahoney
68

R/plot.R

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#' @param nbreaks number of colors breaks (ignored for \code{factor} or \code{character} variables)
1212
#' @param breaks either a numeric vector with the actual breaks, or a name of a method accepted by the \code{style} argument of \link[classInt]{classIntervals}
1313
#' @param max.plot integer; lower boundary to maximum number of attributes to plot; the default value (9) can be overriden by setting the global option \code{sf_max.plot}, e.g. \code{options(sf_max.plot=2)}
14-
#' @param key.pos integer; side to plot a color key: 1 bottom, 2 left, 3 top, 4 right; set to \code{NULL} to omit key completely, 0 to only not plot the key, or -1 to select automatically. If multiple columns are plotted in a single function call by default no key is plotted and every submap is stretched individually; if a key is requested (and \code{col} is missing) all maps are colored according to a single key. Auto select depends on plot size, map aspect, and, if set, parameter \code{asp}.
14+
#' @param key.pos numeric; side to plot a color key: 1 bottom, 2 left, 3 top, 4 right; set to \code{NULL} to omit key completely, 0 to only not plot the key, or -1 to select automatically. If multiple columns are plotted in a single function call by default no key is plotted and every submap is stretched individually; if a key is requested (and \code{col} is missing) all maps are colored according to a single key. Auto select depends on plot size, map aspect, and, if set, parameter \code{asp}. If it has lenght 2, the second value, ranging from 0 to 1, determines where the key is placed in the available space (default: 0.5, center).
1515
#' @param key.width amount of space reserved for the key (incl. labels), thickness/width of the scale bar
1616
#' @param key.length amount of space reserved for the key along its axis, length of the scale bar
1717
#' @param pch plotting symbol
@@ -72,7 +72,7 @@
7272
#' @export
7373
plot.sf <- function(x, y, ..., main, pal = NULL, nbreaks = 10, breaks = "pretty",
7474
max.plot = if(is.null(n <- getOption("sf_max.plot"))) 9 else n,
75-
key.pos = get_key_pos(x, ...), key.length = .618, key.width = lcm(1.8),
75+
key.pos = get_key_pos(x, ...), key.length = .618, key.width = lcm(1.8 * par("ps")/12),
7676
reset = TRUE, logz = FALSE, extent = x, xlim = st_bbox(extent)[c(1,3)],
7777
ylim = st_bbox(extent)[c(2,4)]) {
7878

@@ -89,8 +89,9 @@ plot.sf <- function(x, y, ..., main, pal = NULL, nbreaks = 10, breaks = "pretty"
8989
opar = par()
9090
if (ncol(x) > 2 && !isTRUE(dots$add)) { # multiple maps to plot...
9191
cols = setdiff(names(x), attr(x, "sf_column"))
92-
lt = .get_layout(st_bbox(x), min(max.plot, length(cols)), par("din"), key.pos, key.width)
93-
key.pos = lt$key.pos
92+
lt = .get_layout(st_bbox(x), min(max.plot, length(cols)), par("din"), key.pos[1], key.width)
93+
if (key.pos.missing || key.pos == -1)
94+
key.pos = lt$key.pos
9495
layout(lt$m, widths = lt$widths, heights = lt$heights, respect = FALSE)
9596

9697
if (isTRUE(dots$axes))
@@ -140,7 +141,7 @@ plot.sf <- function(x, y, ..., main, pal = NULL, nbreaks = 10, breaks = "pretty"
140141
plot.new()
141142

142143
# plot key?
143-
if (!is.null(key.pos) && key.pos != 0 && col_missing) {
144+
if (!is.null(key.pos) && key.pos[1] != 0 && col_missing) {
144145
if (is.null(pal))
145146
pal = function(n) sf.colors(n, categorical = is.factor(values))
146147
colors = if (is.function(pal))
@@ -229,7 +230,7 @@ plot.sf <- function(x, y, ..., main, pal = NULL, nbreaks = 10, breaks = "pretty"
229230
(is.factor(values) || length(unique(na.omit(values))) > 1 || breaks_numeric) && # 2065
230231
length(col) > 1) { # plot key?
231232

232-
switch(key.pos,
233+
switch(key.pos[1],
233234
layout(matrix(c(2,1), nrow = 2, ncol = 1),
234235
widths = 1, heights = c(1, key.width)), # 1 bottom
235236
layout(matrix(c(1,2), nrow = 1, ncol = 2),
@@ -779,6 +780,24 @@ bb2merc = function(x, cls = "ggmap") { # return bbox in the appropriate "web mer
779780
axis(side, at = at, labels = labels, ...)
780781
}
781782

783+
# given range r = (a,b), return a value range that:
784+
# * scales such that (b-a)/(y-x)=l
785+
# * shifts linearly within [x,y] such that a==x if o==0, or b==y if o==1
786+
xy_from_r = function(r, l, o) {
787+
stopifnot(length(r) == 2, l <= 1, l > 0, o >= 0, o <= 1)
788+
a = r[1]
789+
b = r[2]
790+
if (o == 1) {
791+
y = b
792+
x = b - (b-a)/l
793+
} else {
794+
i = o / (o-1)
795+
y = (a + (b-a)/l - i * b)/(1 - i)
796+
x = i * (y - b) + a
797+
}
798+
c(x, y)
799+
}
800+
782801
#' @name stars
783802
#' @export
784803
#' @param z ignore
@@ -801,6 +820,11 @@ bb2merc = function(x, cls = "ggmap") { # return bbox in the appropriate "web mer
801820
zlim = range(z, na.rm = TRUE)
802821
if (is.null(breaks))
803822
breaks = seq(zlim[1], zlim[2], length.out = length(col) + 1)
823+
offset = 0.5
824+
if (length(key.pos) == 2) {
825+
offset = key.pos[2]
826+
key.pos = key.pos[1]
827+
}
804828
if (is.character(key.length)) {
805829
kl = as.numeric(gsub(" cm", "", key.length))
806830
sz = if (key.pos %in% c(1,3))
@@ -814,14 +838,13 @@ bb2merc = function(x, cls = "ggmap") { # return bbox in the appropriate "web mer
814838
at = pretty(br)
815839
at = at[at > br[1] & at < br[2]]
816840
}
817-
kl_lim = function(r, kl) { m = mean(r); (r - m)/kl + m }
818841
if (key.pos %in% c(1,3)) {
819842
ylim = c(0, 1)
820-
xlim = kl_lim(range(breaks), key.length)
843+
xlim = xy_from_r(range(breaks), key.length, offset)
821844
mar = c(0, ifelse(axes, 2.1, 1), 0, 1)
822845
}
823846
if (key.pos %in% c(2,4)) {
824-
ylim = kl_lim(range(breaks), key.length)
847+
ylim = xy_from_r(range(breaks), key.length, offset)
825848
xlim = c(0, 1)
826849
mar = c(ifelse(axes, 2.1, 1), 0, 1.2, 0)
827850
}
@@ -876,6 +899,11 @@ bb2merc = function(x, cls = "ggmap") { # return bbox in the appropriate "web mer
876899
# TODO:
877900
ksz = as.numeric(gsub(" cm", "", key.width)) * 2
878901
breaks = (0:n) + 0.5
902+
offset = 0.5
903+
if (length(key.pos) == 2) {
904+
offset = key.pos[2]
905+
key.pos = key.pos[1]
906+
}
879907
if (is.character(key.length)) {
880908
kl = as.numeric(gsub(" cm", "", key.length))
881909
sz = if (key.pos %in% c(1,3))
@@ -884,17 +912,15 @@ bb2merc = function(x, cls = "ggmap") { # return bbox in the appropriate "web mer
884912
dev.size("cm")[2]
885913
key.length = kl/sz
886914
}
887-
kl_lim = function(r, kl) { m = mean(r); (r - m)/kl + m }
888915
if (key.pos %in% c(1,3)) {
889916
ylim = c(0, 1)
890-
xlim = kl_lim(range(breaks), key.length)
917+
xlim = xy_from_r(range(breaks), key.length, offset)
891918
mar = c(0, ifelse(axes, 2.1, 1), 0, 1)
892919
mar[key.pos] = 2.1
893920
} else {
894-
ylim = kl_lim(range(breaks), key.length)
921+
ylim = xy_from_r(range(breaks), key.length, offset)
895922
xlim = c(0, 1)
896923
mar = c(ifelse(axes, 2.1, 1), 0, 1.2, 0)
897-
#mar[key.pos] = 2.1
898924
mar[key.pos] = max(ksz - 1.3, 0.0)
899925
}
900926
par(mar = mar)

man/plot.Rd

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)