Arrange one or more text labels to fit inside a polygon.

label_fill_JamPolygon(
  jp,
  labels,
  buffer = -0.15,
  width_buffer = 0.1,
  relative = TRUE,
  color = "black",
  border = NA,
  ref_jp = NULL,
  xyratio = 1.1,
  fontsize = 10,
  cex = 1,
  degrees = 0,
  dither_cex = 0.04,
  dither_color = 0.07,
  dither_degrees = 0,
  apply_n_scale = TRUE,
  label_method = c("hexagonal"),
  draw_labels = TRUE,
  seed = 1,
  plot_style = c("none", "JamPolygon"),
  verbose = FALSE,
  ...
)

Arguments

jp

JamPolygon where only the first row is processed.

labels

character vector of labels

buffer

numeric value (default -0.15) buffer to resize the polygon, where negative values shrink the polygon size relative to the size of the polygon. For example -0.9 will reduce the polygon 90% of the way toward a completely empty polygon, where that range is defined by the width inside the polygon border.

width_buffer

numeric passed to sample_JamPolygon() to apply a "width buffer", using values relative to the maximum buffer size. This mechanism is experimental, to try to improve label placement in unusually-shaped polygons.

  • width_buffer=0 will add no additional buffer

  • width_buffer=0.5 will apply width buffer equal to half the buffer size required to create an empty polygon. The polygon is shifted left and right by half this amount each direction, then the intersection is used. This method has the intention of requiring a certain available width, for example for wide text labels.

relative

logical passed to buffer_JamPolygon() (default TRUE) to define buffer with relative coordinates.

color

character string to define the color of resulting labels.

border

character string used to define an optional item border, which is only useful when gridtext is used to visualize labels.

ref_jp

JamPolygon (optional) used only when apply_n_scale=TRUE, used to define the overall plot range before determining whether the internal area of jp should be reduced before arraying item label coordinates. The general idea is that polygons which are a smaller percentage of the total area should not be reduced as much by apply_n_scale because they have limited area, but larger polygons should receive closer to the full apply_n_scale adjustment.

xyratio

numeric value indicating the relative ratio of x (width) to y (height) when arraying coordinates inside the polygons. Values larger than 1 will place points wider from each other than they are tall, which can help with longer text labels.

fontsize

numeric font size in points, default 10.

cex

numeric multiplied by fontsize as an alternative convenient way to adjust text label sizes.

degrees

numeric value used to rotate labels, default 0, in degrees between 0 and 359.

apply_n_scale

logical indicating whether to adjust the buffer based upon the number of items, where more items uses less buffer, and fewer items imposes a larger buffer. The intent is for a single label or small number of labels to appear near the center.

label_method

character string (default "hexagonal") to define the label layout. Currently only "hexagonal" is implemented. After testing some approaches in sf::st_sample() and spatstat.random::rThomas(), the other options were interesting but ultimately not more effective specifically for character labels. Both packages have heavy R dependencies and were avoided.

draw_labels

logical (default TRUE) indicating whether to draw labels, however it is only used when plot_style="JamPolygon". Note also, when drawing labels, it assumes the plot is already created using ref_jp, and it determines the coordinate adjustments relative to ref_jp.

seed

numeric value (default 1) used to define the random seed with set.seed(seed) for reproducible output. When seed is NULL there is no call to set.seed().

plot_style

character string, default "none".

  • "none": No plot output.

  • "JamPolygon": assume ref_jp has already been plotted, and labels should be drawn in that coordinate context. For example call plot(ref_jp) then label_fill_JamPolygon(jp, ref_jp, plot_output="JamPolygon"). See examples.

verbose

logical indicating whether to print verbose output.

...

additional arguments are passed to internal functions: buffer_JamPolygon(), and sample_JamPolygon().

`dither_cex, dither_color, dither_degrees`

values used to provide some variability to the repeated pattern of text labels.

  • dither_cex provides a range to adjust cex and fontsize slightly for each label, making some slightly larger or smaller to help distinguish adjacent labels from one another.

  • dither_color provides a range for adjusting the font color, which is applied with darkFactor in jamba::makeColorDarker().

  • dither_degrees provides a range for adjusting font degrees, the default 0 means the values are not adjusted. The text() function does not permit multiple vectorized rotations, however gridtext does permit multiple angles. Best to use dither_degrees only when displaying labels with gridtext.

Value

list when there are valid coordinates, NULL otherwise. The list contains these elements:

  • "items_df": a data.frame with columns x,y,text,rot,color,fontsize,border

  • "g_labels": a grid grob graphical object only when plot_style="base", otherwise NULL

  • "scale_width": a numeric value indicating the buffer used

  • "jp_buffer": a JamPolygon object after adjusting with buffer

Details

This function is intended to define points inside a polygon area so that text labels can be roughly evenly spaced, with relatively good default positioning to minimize overlapping labels. This function does not prevent overlapping labels, nor does it fully prevent labels overlapping the polygon border.

There are options to help minimize overlapping labels, such as xyratio which defines the default width-to-height ratio of resulting points. For wider text labels, a higher value for xyratio may be helpful. To minimize adjacent (side-by-side) label overlaps, it can be helpful to use degrees to rotate labels slightly, for example degrees=5 may be enough to prevent wide labels from overlapping the next label beside it.

Strategy

  • Determine bounding box with rectangular area that encompases the polygon.

  • Define evenly spaced points across the rectangular area sufficient to produce at least n total points.

  • Retain only the subset of points which are inside the polygon.

  • If there are fewer than n remaining points, repeat the process using a higher target value for n.

Todo

Examples

df3 <- data.frame(name=c("polygon1", "polygon2"),
   label=c("polygon1", "polygon2"),
   x=I(list(
      list(c(1, 6, 6, 1),
         c(2, 5, 5, 2),
         c(3, 4, 4, 3)),
      list(#c(11, 16, 16, 11),
         c(12, 15, 15, 12),
         c(13, 14, 14, 13))
      )),
   y=I(list(
      list(c(1, 1, 6, 6),
         c(2, 2, 5, 5),
         c(3, 3, 4, 4)),
      list(#c(1, 1, 6, 6),
         c(2, 2, 5, 5),
         c(3, 3, 4, 4))
      )),
   fill=c("gold", "firebrick"))
jp3 <- new("JamPolygon", polygons=df3);

jp3p <- plot(jp3);

lfj1 <- label_fill_JamPolygon(jp3[1,], labels=rep("O", 100),
   ref_jp=jp3, plot_style="JamPolygon")
lfj2 <- label_fill_JamPolygon(jp3[2,], labels=rep("X", 40),
   buffer=-0.5,
   ref_jp=jp3, plot_style="JamPolygon")


jp3p <- plot(jp3);
lfj1 <- label_fill_JamPolygon(jp3[1,], labels=rep("O", 1), apply_n_scale=FALSE,
   ref_jp=jp3, plot_style="JamPolygon")