Skip to content

Commit

Permalink
option 4 implemented #848
Browse files Browse the repository at this point in the history
  • Loading branch information
mtennekes committed Mar 22, 2024
1 parent 275c9dd commit d5b9589
Show file tree
Hide file tree
Showing 21 changed files with 698 additions and 275 deletions.
7 changes: 7 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,14 @@ S3method(tmapSubsetShp,stars)
export(get_fact_levels_na)
export(make_by_vars)
export(marker_icon)
export(opt_tm_bubbles)
export(opt_tm_dots)
export(opt_tm_labels)
export(opt_tm_lines)
export(opt_tm_polygons)
export(opt_tm_raster)
export(opt_tm_sqaures)
export(opt_tm_symbols)
export(opt_tm_text)
export(providers)
export(qtm)
Expand Down
222 changes: 222 additions & 0 deletions R/misc_pointLabel.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
test_rect = function(x, y, width, height, bbx) {
library(grid)
grid.newpage()

asp = tmaptools::get_asp_ratio(bbx)

if (asp > 1) {
pushViewport(viewport(width = unit(1, "snpc"), height = unit(1/asp, "snpc")))
} else {
pushViewport(viewport(width = unit(asp, "snpc"), height = unit(1, "snpc")))
}


pushViewport(viewport(xscale = bbx[c(1,3)], yscale = bbx[c(2,4)]))
grid.rect()

mapply(function(xi,yi,wi,hi) {
grid.rect(x = unit(xi, "native"), y = unit(yi, "native"), width = unit(wi, "native"), height = unit(hi, "native"), gp = gpar(fill = "orange", col = "black"))
}, x, y, width, height)
upViewport(2)
}

test_poly = function(xs, ys, bbx) {
library(grid)
grid.newpage()

asp = tmaptools::get_asp_ratio(bbx)

if (asp > 1) {
pushViewport(viewport(width = unit(1, "snpc"), height = unit(1/asp, "snpc")))
} else {
pushViewport(viewport(width = unit(asp, "snpc"), height = unit(1, "snpc")))
}

pushViewport(viewport(xscale = bbx[c(1,3)], yscale = bbx[c(2,4)]))

grid.rect()

grid.path(x = unit(xs, "native"), y = unit(ys, "native"), gp = gpar(fill = "orange", col = "black"))

upViewport(2)
}

# function adapted from car::pointLabel
# also used in tmap3
# changes are documented
# input: x, y, width and height of rectangles, bounding box (in 'sf' format')
pointLabel2 <- function (x, y, width, height, bbx,
method = c("SANN", "GA"),
gap = 0,
trace = FALSE, ...) {

asp = tmaptools::get_asp_ratio(bbx)

toUnityCoords <- function(xy) {
if (asp > 1) {
list(x = (xy$x - bbx[1])/(bbx[3] - bbx[1]) * asp,
y = (xy$y - bbx[2])/(bbx[4] - bbx[2]))
} else {
list(x = (xy$x - bbx[1])/(bbx[3] - bbx[1]),
y = (xy$y - bbx[2])/(bbx[4] - bbx[2])/asp)
}


}
toUserCoords <- function(xy) {
if (asp > 1) {
list(x = bbx[1] + xy$x/asp * (bbx[3] - bbx[1]),
y = bbx[2] + xy$y * (bbx[4] - bbx[2]))
} else {
list(x = bbx[1] + xy$x * (bbx[3] - bbx[1]),
y = bbx[2] + xy$y * asp * (bbx[4] - bbx[2]))
}

}

z <- xy.coords(x, y, recycle = TRUE)
z <- toUnityCoords(z)
x <- z$x
y <- z$y

# CHANGED: width and height are specified by user
width <- ((width + gap) / (bbx[3] - bbx[1])) * asp
height <- ((height + gap) / (bbx[4] - bbx[2])) / asp


method <- match.arg(method)
n_labels <- length(x)

gen_offset <- function(code) c(-1, -1, -1, 0, 0, 1, 1, 1)[code] *
(width/2) + (0+1i) * c(-1, 0, 1, -1, 1, -1, 0, 1)[code] *
(height/2)
rect_intersect <- function(xy1, offset1, xy2, offset2) {
w <- pmin(Re(xy1 + offset1/2), Re(xy2 + offset2/2)) -
pmax(Re(xy1 - offset1/2), Re(xy2 - offset2/2))
h <- pmin(Im(xy1 + offset1/2), Im(xy2 + offset2/2)) -
pmax(Im(xy1 - offset1/2), Im(xy2 - offset2/2))
w[w <= 0] <- 0
h[h <= 0] <- 0
w * h
}

objective <- function(gene) {
offset <- gen_offset(gene)
if (!is.null(rectidx1))
area <- sum(rect_intersect(xy[rectidx1] + offset[rectidx1],
rectv[rectidx1], xy[rectidx2] + offset[rectidx2],
rectv[rectidx2]))
else area <- 0
n_outside <- sum(Re(xy + offset - rectv/2) < 0 | Re(xy +
offset + rectv/2) > asp | Im(xy + offset - rectv/2) <
0 | Im(xy + offset + rectv/2) > 1/asp)
res <- 1000 * area + n_outside
res
}
xy <- x + (0+1i) * y
rectv <- width + (0+1i) * height
rectidx1 <- rectidx2 <- array(0, (length(x)^2 - length(x))/2)
k <- 0
for (i in 1:length(x)) for (j in seq(len = (i - 1))) {
k <- k + 1
rectidx1[k] <- i
rectidx2[k] <- j
}
canIntersect <- rect_intersect(xy[rectidx1], 2 * rectv[rectidx1],
xy[rectidx2], 2 * rectv[rectidx2]) > 0
rectidx1 <- rectidx1[canIntersect]
rectidx2 <- rectidx2[canIntersect]
if (trace)
cat("possible intersects =", length(rectidx1), "\n")
if (trace)
cat("portion covered =", sum(rect_intersect(xy, rectv,
xy, rectv)), "\n")
GA <- function() {
n_startgenes <- 1000
n_bestgenes <- 30
prob <- 0.2
mutate <- function(gene) {
offset <- gen_offset(gene)
doesIntersect <- rect_intersect(xy[rectidx1] + offset[rectidx1],
rectv[rectidx1], xy[rectidx2] + offset[rectidx2],
rectv[rectidx2]) > 0
for (i in which(doesIntersect)) {
gene[rectidx1[i]] <- sample(1:8, 1)
}
for (i in seq(along = gene)) if (runif(1) <= prob)
gene[i] <- sample(1:8, 1)
gene
}
crossbreed <- function(g1, g2) ifelse(sample(c(0, 1),
length(g1), replace = TRUE) > 0.5, g1, g2)
genes <- matrix(sample(1:8, n_labels * n_startgenes,
replace = TRUE), n_startgenes, n_labels)
for (i in 1:10) {
scores <- array(0, NROW(genes))
for (j in 1:NROW(genes)) scores[j] <- objective(genes[j,
])
rankings <- order(scores)
genes <- genes[rankings, ]
bestgenes <- genes[1:n_bestgenes, ]
bestscore <- scores[rankings][1]
if (bestscore == 0) {
if (trace)
cat("overlap area =", bestscore, "\n")
break
}
genes <- matrix(0, n_bestgenes^2, n_labels)
for (j in 1:n_bestgenes) for (k in 1:n_bestgenes) genes[n_bestgenes *
(j - 1) + k, ] <- mutate(crossbreed(bestgenes[j,
], bestgenes[k, ]))
genes <- rbind(bestgenes, genes)
if (trace)
cat("overlap area =", bestscore, "\n")
}
nx <- Re(xy + gen_offset(bestgenes[1, ]))
ny <- Im(xy + gen_offset(bestgenes[1, ]))
list(x = nx, y = ny)
}
SANN <- function() {
gene <- rep(8, n_labels)
score <- objective(gene)
bestgene <- gene
bestscore <- score
T <- 2.5
for (i in 1:50) {
k <- 1
for (j in 1:50) {
newgene <- gene
newgene[sample(1:n_labels, 1)] <- sample(1:8,
1)
newscore <- objective(newgene)
if (newscore <= score || runif(1) < exp((score -
newscore)/T)) {
k <- k + 1
score <- newscore
gene <- newgene
}
if (score <= bestscore) {
bestscore <- score
bestgene <- gene
}
if (bestscore == 0 || k == 10)
break
}
if (bestscore == 0)
break
if (trace)
cat("overlap area =", bestscore, "\n")
T <- 0.9 * T
}
if (trace)
cat("overlap area =", bestscore, "\n")
nx <- Re(xy + gen_offset(bestgene))
ny <- Im(xy + gen_offset(bestgene))
list(x = nx, y = ny)
}
if (method == "SANN")
xy <- SANN()
else xy <- GA()
xy <- toUserCoords(xy)
invisible(xy)
}
18 changes: 12 additions & 6 deletions R/tm_layers_lines.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
#' @rdname tm_lines
#' @name opt_tm_lines
#' @export
opt_tm_lines = function(lines.only = "ifany") {
list(trans.args = list(lines.only = lines.only),
mapping.args = list())
}

#' Map layer: lines
#'
#' Map layer that draws symbols Supported visual variables are: `col` (the color), `lwd` (line width), `lty` (line type), and `col_alpha` (color alpha transparency).
Expand Down Expand Up @@ -37,6 +45,7 @@
#' @param zindex Map layers are drawn on top of each other. The `zindex` numbers (one for each map layer) determines the stacking order. By default the map layers are drawn in the order they are called.
#' @param group Name of the group to which this layer belongs. This is only relevant in view mode, where layer groups can be switched (see `group.control`)
#' @param group.control In view mode, the group control determines how layer groups can be switched on and off. Options: `"radio"` for radio buttons (meaning only one group can be shown), `"check"` for check boxes (so multiple groups can be shown), and `"none"` for no control (the group cannot be (de)selected).
#' @param options options passed on to the corresponding `opt_<layer_function>` function
#' @param popup.vars names of data variables that are shown in the popups in `"view"` mode. Set popup.vars to `TRUE` to show all variables in the shape object. Set popup.vars to `FALSE` to disable popups. Set popup.vars to a character vector of variable names to those those variables in the popups. The default (`NA`) depends on whether visual variables (e.g.`col`) are used. If so, only those are shown. If not all variables in the shape object are shown.
#' @param popup.format list of formatting options for the popup values. See the argument `legend.format` for options. Only applicable for numeric data variables. If one list of formatting options is provided, it is applied to all numeric variables of `popup.vars`. Also, a (named) list of lists can be provided. In that case, each list of formatting options is applied to the named variable.
#' @param hover name of the data variable that specifies the hover labels
Expand Down Expand Up @@ -76,15 +85,12 @@ tm_lines = function(col = tm_const(),
popup.format = list(),
hover = "",
id = "",
lines.only = "ifany",
options = opt_tm_lines(),
...) {

args = list(...)
args_called = as.list(match.call()[-1]) #lapply(as.list(match.call()[-1]), eval, envir = parent.frame())

trans.args = list(lines.only = lines.only)
mapping.args = list()

v3 = c("alpha", "scale", "lwd.legend.labels", "lwd.legend.col", "n",
"style", "style.args", "as.count", "breaks", "interval.closure",
"palette", "labels", "drop.levels", "midpoint", "stretch.palette",
Expand Down Expand Up @@ -190,7 +196,7 @@ tm_lines = function(col = tm_const(),
layer = "lines",
trans.fun = tmapTransLines,
trans.aes = list(),
trans.args = trans.args,
trans.args = options$trans.args,
trans.isglobal = FALSE,
mapping.aes = list(col = tmapScale(aes = "col",
value = col,
Expand Down Expand Up @@ -231,7 +237,7 @@ tm_lines = function(col = tm_const(),
tpar = tmapTpar(),
plot.order = plot.order,
mapping.fun = "Lines",
mapping.args = mapping.args,
mapping.args = options$mapping.args,
zindex = zindex,
group = group,
group.control = group.control,
Expand Down
19 changes: 13 additions & 6 deletions R/tm_layers_polygons.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
#' @rdname tm_polygons
#' @name opt_tm_polygons
#' @export
opt_tm_polygons = function(polygons.only = "ifany") {
list(trans.args = list(polygons.only = polygons.only),
mapping.args = list())
}


#' Map layer: polygons
#'
#' Map layer that draws polygons. Supported visual variables are: `fill` (the fill color),
Expand Down Expand Up @@ -51,6 +60,7 @@
#' (meaning only one group can be shown), `"check"` for check boxes
#' (so multiple groups can be shown), and `"none"` for no control
#' (the group cannot be (de)selected).
#' @param options options passed on to the corresponding `opt_<layer_function>` function
#' @param popup.vars names of data variables that are shown in the popups
#' in `"view"` mode. Set popup.vars to `TRUE` to show all variables in the
#' shape object. Set popup.vars to `FALSE` to disable popups. Set `popup.vars`
Expand Down Expand Up @@ -112,14 +122,11 @@ tm_polygons = function(fill = tm_const(),
popup.format = list(),
hover = "",
id = "",
polygons.only = "ifany",
options = opt_tm_polygons(),
...) {
args = list(...)
args_called = as.list(match.call()[-1]) #lapply(as.list(match.call()[-1]), eval, envir = parent.frame())

trans.args = list(polygons.only = polygons.only)
mapping.args = list()

v3 = c("alpha", "palette", "convert2density", "area", "n",
"style", "style.args", "as.count", "breaks", "interval.closure",
"labels", "drop.levels", "midpoint", "stretch.palette", "contrast",
Expand Down Expand Up @@ -215,7 +222,7 @@ tm_polygons = function(fill = tm_const(),
tm_element_list(tm_element(
layer = "polygons",
trans.fun = tmapTransPolygons,
trans.args = trans.args,
trans.args = options$trans.args,
trans.aes = list(),
trans.isglobal = FALSE,
mapping.aes = list(fill = tmapScale(aes = "fill",
Expand Down Expand Up @@ -269,7 +276,7 @@ tm_polygons = function(fill = tm_const(),
tpar = tmapTpar(area = "AREA"),
plot.order = plot.order,
mapping.fun = "Polygons",
mapping.args = mapping.args,
mapping.args = options$mapping.args,
zindex = zindex,
group = group,
group.control = group.control,
Expand Down
Loading

0 comments on commit d5b9589

Please sign in to comment.