riatelab/mapsf

FR: Calculate max cex for mf_label that shows all text

rlh1994 opened this issue · 2 comments

I was hoping to request a feature or possibly just a solution to this problem:

I produce a large number of maps via a loop and they have varying numbers of polygons on them (but are as a whole image the same size and resolution). Because of this it means that the text size is very difficult to set right; maps with few polygons end up with tiny text but if I increase it then maps with many polygons become a mess or unreadable (I have to use overlap = TRUE as I need all the labels). Currently I attempt some convoluted calculation based on the ratio between the largest and smallest polygon areas and base it on that, but it isn't ideal.

I was hoping for a solution that would allow mf_label to calculate the ideal text size to avoid overlapping at all, or in an ideal world it would set the cex of each text to the maximum size where it remains within the polygon.

I think this might be possible by looking at the below section and instead of adjusting the locations adjusting the cex, but I haven't really looked through the code enough to be sure of that.

while (isOverlaped) {
if (!is_overlap(x1 - .5 * wid, y1 - .5 * ht, wid, ht, boxes) &&
x1 - .5 * wid > xlim[1] && y1 - .5 * ht > ylim[1] &&
x1 + .5 * wid < xlim[2] && y1 + .5 * ht < ylim[2]) {
boxes[[length(boxes) + 1]] <- c(x1 - .5 * wid, y1 - .5 * ht, wid, ht)
isOverlaped <- FALSE
} else {
theta <- theta + tstep
r <- r + rstep * tstep / (2 * pi)
x1 <- xo + sdx * r * cos(theta)
y1 <- yo + sdy * r * sin(theta)
}
}
}

Any help with this problem would be great!

Hello,
I've managed to find a solution using wordcloud pkg. This solution could be refined using something more subtle than polygon areas (like inscribed rectangle areas or bbox areas...)
I'm not sure I want to add this feature to the package.

library(mapsf)
library(sf)
#> Linking to GEOS 3.9.0, GDAL 3.2.2, PROJ 7.2.1; sf_use_s2() is TRUE
library(wordcloud)
#> Le chargement a nécessité le package : RColorBrewer
# import basemap
mtq <- mf_get_mtq()
# compute area
mtq$surf <- st_area(mtq)
# centroid coordinates
loc <- st_coordinates(st_centroid(mtq))
#> Warning in st_centroid.sf(mtq): st_centroid assumes attributes are constant over
#> geometries of x
# compute output cex (max cex = 1.7)
cexx = 1.7 * mtq$surf / max(mtq$surf)
# plot map 
mf_export(mtq, width = 800)
mf_map(mtq)
# get text layout
nc <- wordlayout(x = loc[,1], y = loc[,2], words = mtq$LIBGEO, cex = cexx)
# plot labels
text(x = nc[,1] + .5 * nc[,3], y = nc[,2] + .5 * nc[,4], 
     labels = mtq$LIBGEO, cex = cexx)
dev.off()
#> png 
#>   2

Created on 2022-07-18 by the reprex package (v2.0.1)
map

That's a clever approach thanks, I'll hopefully have time to give it a try in a few weeks! Understandable about not wanting to add it, I'm quite an edge case compared to the way most people would make maps!