-
Notifications
You must be signed in to change notification settings - Fork 3
/
plot_and_get.R
145 lines (128 loc) · 4.17 KB
/
plot_and_get.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#' Interactively select a polygon (grid graphics) and highlight points
#'
#' Click the points that should be connected as polygon. Input ends with right click (see
#' [grid::grid.locator()]). Polygon will be drawn closed.
#'
#' `map.sel.poly` is a convenience wrapper for [plot_map()], `sel.poly`,
#' and [sp::point.in.polygon()]. For customized plotting, the plot can be produced by
#' [plot_map()], [plot_voronoi()] or [levelplot()], and the result of
#' that plot command handed over to `map.sel.poly`, see the example below.
#'
#' If even more customized plotting is required,`sel.poly` should be used (see example).
#'
#' @param data hyperSpec object for plotting map or list returned by [plot_map()]
#' @param pch symbol to display the points of the polygon for [sel.poly()]
#' @param size size for polygon point symbol for [sel.poly()]
#' @param ... further arguments for [grid::grid.points()] and
#' [grid::grid.lines()]
#' @return `map.sel.poly`: array of indices for points within the selected polygon
#' @author Claudia Beleites, Sebastian Mellor
#' @seealso [grid::grid.locator()], [map.identify()]
#' @export
#' @rdname map-sel-poly
#'
#' @keywords iplot
#' @concept plotting
#' @concept plotting tools
#'
#' @examples
#' \dontrun{\donttest{
#' ## convenience wrapper
#' map.sel.poly(faux_cell)
#'
#' ## customized version
#' data <- sample(faux_cell[, , 1004 - 2i ~ 1004 + 2i], 300)
#'
#' plotdata <- plot_voronoi(data, region ~ y * x, col.regions = palette_alois())
#' print(plotdata)
#' map.sel.poly(plotdata)
#'
#' ## even more customization:
#' plot_voronoi(data)
#'
#' ## interactively retrieve polygon
#' polygon <- sel.poly()
#'
#' ## find data points within polygon
#' require("sp")
#' i.sel <- which(point.in.polygon(data$x, data$y, polygon[, 1], polygon[, 2]) > 0)
#'
#' ## work with selected points
#' grid.points(unit(data$x[i.sel], "native"), unit(data$y[i.sel], "native"))
#' }}
map.sel.poly <- function(data, pch = 19, size = 0.3, ...) {
if (!interactive()) {
stop("map.sel.poly works only on interactive graphics devices.")
}
## sp is only in Suggests, not a strict Dependency.
if (!requireNamespace("sp")) {
stop("package sp required for point.in.polygon ()")
}
if (is(data, "hyperSpec")) {
## plot hyperSpec object
print(plot_map(data))
x <- data$x
y <- data$y
} else if (is(data, "trellis")) {
## data is list with plotting data of hyperSpec object
x <- data$panel.args.common$x
y <- data$panel.args.common$y
} else {
stop("data must either be a hyperSpec object or a trellis object as returned by plot_map, plot_voronoi, or levelplot")
}
poly <- sel.poly(pch = pch, size = size, ...)
pts <- sp::point.in.polygon(x, y, poly[, 1], poly[, 2])
ind <- pts > 0
if (!any(ind)) {
warning("Empty selection: no point in polygon.")
}
ind
}
#' @return `sel.poly`: n x 2 matrix with the corner points of the polygon
#' @author Claudia Beleites
#' @seealso [grid::grid.locator()]
#' @export
#'
#' @keywords iplot
#' @concept plotting
#' @concept plotting tools
#'
#' @rdname map-sel-poly
#' @importFrom grid grid.lines grid.points
#' @importFrom utils tail
sel.poly <- function(pch = 19, size = 0.3, ...) {
if (!interactive()) {
stop("sel.poly works only on interactive graphics devices.")
}
trellis.focus()
pts <- matrix(NA, nrow = 0, ncol = 2)
repeat {
pt <- grid.locator(unit = "native")
if (!is.null(pt)) {
pts <- rbind(pts, as.numeric(pt)) # comparably few executions: low performance doesn't matter
## display the clicked point
grid.points(unit(tail(pts[, 1], 1), "native"),
unit(tail(pts[, 2], 1), "native"),
pch = pch,
size = unit(size, "char"), gp = gpar(...)
)
## connect last 2 points by line
if (nrow(pts) > 1L) {
grid.lines(unit(tail(pts[, 1L], 2L), "native"),
unit(tail(pts[, 2L], 2L), "native"),
gp = gpar(...)
)
}
} else {
## visually close polygon (if at least 3 pts)
if (nrow(pts) > 2L) {
grid.lines(unit(c(tail(pts[, 1L], 1L), pts[1L, 1L]), "native"),
unit(c(tail(pts[, 2L], 1L), pts[1L, 2L]), "native"),
gp = gpar(...)
)
}
break
}
}
pts
}