Tracer les points à l'extérieur de la grille sous forme de flèches pointant vers les données avec ggplot2 en R
je génère des cartes avec des données à l'échelle mondiale, puis zoomant dans certaines régions. Sur la vue agrandie, je voudrais montrer qu'il y a d'autres points de données en dehors de la zone de limitation, en mettant des pointes de flèche qui point du centre de la zone à l'endroit où le point de données est dans le monde extérieur.
Remarque: Je n'ai pas besoin que ce soit un" grand cercle", juste des vecteurs XY dans la projection Mercator, parce que j'imagine que ce sera utile pour les tracés "normaux" comme bien.
par exemple, voici la carte du monde montrant l'étendue des données:
et voici le zoom en vue, avec des flèches magenta ajoutées manuellement pour montrer ce que je voudrais générer.
ci-Dessous le code et les données j'utilise pour générer ces deux parcelles. J'ai besoin d'un moyen de générer les pointes de flèche.
require(ggplot2)
te = structure(list(lat = c(33.7399, 32.8571, 50.2214, 36.96263, 33.5835,
33.54557, 47.76147, 48, 59.40289, 35.93411, 32.87962, 38.3241,
50.03844, 37.44, 50.07774, 50.26668, 36.5944), lng = c(-118.37608,
-117.25746, -5.3865, -122.00809, -117.86159, -117.79805, -124.45055,
-126, -146.35157, -122.931472, -117.25285, -123.07331, -5.26339,
25.4, -5.709894, -3.86828, -121.96201)), .Names = c("lat", "lng"
), class = "data.frame", row.names = c(NA, -17L))
all_states = map_data("world")
# world version:
wp = ggplot() +
geom_polygon(data = all_states, aes(x = long, y = lat, group = group), colour = "gray",
fill = "gray") +
coord_cartesian(ylim = c(0, 80), xlim = c(-155, 45)) +
geom_point(data = te, aes(x = lng, y = lat), color = "blue", size = 5,alpha = 0.6)
print(wp)
#states plot
sp = ggplot() +
geom_polygon(data = all_states, aes(x = long, y = lat, group = group), colour = "gray", fill = "gray") +
coord_cartesian(ylim = c(30, 52), xlim = c(-128, -114)) +
geom_point(data = te, aes(x = lng, y = lat), color = "blue", size = 5, alpha = 0.6)
print(sp)
2 réponses
Cette solution utilise sp
et rgeos
paquets pour manipuler les données spatiales, le principal point d'intersection étant les lignes et une boîte polygone pour obtenir les points de bord pour les flèches. Alors si vous dessinez des flèches geom_segment
et de largeur zéro, la ligne est invisible et seule la tête de flèche reste.
cette fonction calcule les intersections ligne-boîte:
boxint <- function(xlim, ylim, xp, yp){
## build box as SpatialPolygons
box = cbind(xlim[c(1,2,2,1,1)],
ylim[c(1,1,2,2,1)])
box <- sp::SpatialPolygons(list(sp::Polygons(list(sp::Polygon(box)),ID=1)))
## get centre of box
x0=mean(xlim)
y0=mean(ylim)
## construct line segments to points
sl = sp::SpatialLines(
lapply(1:length(xp),
function(i){
sp::Lines(list(sp::Line(cbind(c(x0,xp[i]),c(y0,yp[i])))),ID=i)
}
)
)
## intersect lines segments with boxes to make points
pts = rgeos::gIntersection(sl, as(box, "SpatialLines"))
as.data.frame(sp::coordinates(pts), row.names=1:length(xp))
}
Et renvoie le geom
avec des flèches:
wherelse <- function(xlim, ylim, points){
## get points outside bounding box
outsides = points[!(
points$lng>=xlim[1] &
points$lng <= xlim[2] &
points$lat >= ylim[1] &
points$lat <= ylim[2]),]
npts = nrow(outsides)
## get centre point of box
x = rep(mean(xlim),npts)
y = rep(mean(ylim),npts)
## compute box-point intersections
pts = boxint(xlim, ylim, outsides$lng, outsides$lat)
pts$x0=x
pts$y0=y
## create arrow segments as invisible lines with visible arrowheads
ggplot2::geom_segment(data=pts, aes(x=x0,y=y0,xend=x,yend=y),
lwd=0, arrow=grid::arrow(length=unit(0.5,"cm"),
type="closed"),col="magenta")
}
donc votre exemple, le tracé de base est:
sp = ggplot() +
geom_polygon(
data=all_states,
aes(x=long, y=lat, group = group),colour="gray",fill="gray" ) +
coord_cartesian(ylim=c(30, 52), xlim=c(-128,-114)) +
geom_point(data=te,aes(x=lng,y=lat),color="blue",size=5,alpha=0.6)
puis ajouter les flèches avec:
sp + wherelse(c(-128,-114), c(30,52), te)
pas sûr s'il y a une option pour dessiner les flèches exactement comme vous les voulez!
Voici ma tentative. C'est le plus proche que je suis arrivé. J'ai utilisé gcIntermediate()
pour calculer la distance la plus courte entre le point central de votre carte américaine et les points de données qui restent en dehors de la bbox. Par conséquent, les positions des flèches peuvent ne pas être quelque chose que vous voulez. J'espère que quelqu'un d'autre fournira une meilleure solution basée sur cette tentative.
j'ai d'abord arrangé votre df (i.e., te) avec le point central de la carte zoomée américaine. J'ai ensuite choisi des points de données qui ne sont pas dans la bbox de la carte des états-unis. Ensuite, ajoutez deux colonnes pour indiquer le point central de la carte américaine. Renommer deux colonnes et calculer la plus courte distance avec gcIntermediate.
library(dplyr)
library(ggplot2)
library(geosphere)
filter(te, !between(lng, -128, -114) | !between(lat, 30, 52)) %>%
mutate(start_long = (-128 - 114) / 2,
start_lat = (30 + 52) / 2) %>%
rename(end_lat = lat, end_long = lng) %>%
do(fortify(as(gcIntermediate(.[,c("start_long", "start_lat")],
.[,c("end_long", "end_lat")],
100,
breakAtDateLine = FALSE,
addStartEnd = TRUE,
sp = TRUE), "SpatialLinesDataFrame"))) -> foo
foo
contient 100 points de données pour tracer la ligne respective. J'ai choisi des points de données qui restent proches de la limite de la bbox. Je cherchais spécifiquement deux points de données pour chaque ligne afin que je puisse utiliser geom_segment()
plus tard. J'admets que j'ai un peu joué avec la condition du filtre. En fin de compte, je n'ai pas de sous-ensemble de données en utilisant lat ce cas.
filter(foo, between(long, -128, -126.5) | between(long, -115.5, -114)) %>%
group_by(group) %>%
slice(c(1,n())) -> mydf
dans la prochaine étape, j'ai réarrangé la base de données basée sur ce lien
mutate(mydf, end_long = lag(long), end_lat = lag(lat)) %>%
slice(n()) -> mydf2
finalement j'ai dessiné la carte avec des flèches. J'espère que cela vous fournira une sorte de base. J'espère également que d'autres utilisateurs de SO fourniront de meilleures solutions.
ggplot() +
geom_polygon(data = all_states, aes(x = long, y = lat, group = group),
colour = "gray", fill = "gray" ) +
coord_cartesian(ylim = c(30, 52), xlim = c(-128,-114)) +
geom_point(data = te, aes(x = lng,y = lat), color = "blue", size = 5,alpha = 0.6) +
geom_segment(data = mydf2, aes(x = end_long, xend = long,
y = end_lat, yend = lat, group = group),
arrow = arrow(length = unit(0.2, "cm"), ends = "last"))