Learn R Programming

ggimage (version 0.3.6)

geom_image_repel: geom_image_repel

Description

geom layer for visualizing image files with basic overlap avoidance

Usage

geom_image_repel(
  mapping = NULL,
  data = NULL,
  stat = "identity",
  position = "identity",
  inherit.aes = TRUE,
  na.rm = FALSE,
  by = "width",
  nudge_x = 0,
  nudge_y = 0,
  use_cache = TRUE,
  width = NULL,
  height = NULL,
  max.iter = 100,
  force = 0.1,
  box.padding = 0,
  direction = "both",
  ...
)

Value

geom layer

Arguments

mapping

aes mapping

data

data

stat

stat

position

position

inherit.aes

logical, whether inherit aes from ggplot()

na.rm

logical, whether remove NA values

by

one of 'width' or 'height'

nudge_x

horizontal adjustment to nudge image

nudge_y

vertical adjustment to nudge image

use_cache

logical, whether to use image caching for better performance

width, height

Image width and height in native panel units, see geom_image(). Only one of them keeps the aspect ratio of the image.

max.iter

non-negative whole number of displacement iterations. max.iter = 0 keeps the original coordinates (and force = 0 does the same).

force

non-negative number, the fraction of the current overlap that is resolved in one iteration (each image of an overlapping pair moves by force * overlap / 2). Larger values converge faster but produce bigger jumps.

box.padding

non-negative number, extra space added around every image box, in the same units as width/height. Repelled images are kept at least box.padding apart.

direction

one of 'both', 'x' or 'y', the axis (or axes) along which images are allowed to move. Overlap is always detected on both axes; direction only restricts the displacement, so direction = "x" slides overlapping images horizontally until they no longer overlap.

...

additional parameters

Author

Guangchuang Yu

Details

geom_image_repel() draws images like geom_image(), but moves images that overlap each other apart before drawing them. The displacement is computed offline (no network, no rendering, no ggrepel dependency) from the bounding boxes of the images, so the result is deterministic: the same plot always produces the same layout.

The algorithm works on the centres of the images, after they have been nudged (nudge_x/nudge_y) and transformed by the coordinate system (this is the space in which width/height are expressed, i.e. fractions of the panel):

  1. each image gets an axis aligned box of size width + box.padding by height + box.padding;

  2. for every pair of boxes that overlap on both axes, the two images are pushed apart along the allowed direction, by force * overlap / 2 each, away from each other;

  3. step 2 is repeated at most max.iter times, stopping early once no pair overlaps. The residual overlap after max.iter iterations is about (1 - force)^max.iter of the initial one, so the default (force = 0.1, max.iter = 100) leaves essentially no overlap.

which keeps the result reproducible. For large inputs, an adaptive uniform-grid broad phase estimates candidate density before each sweep: sparse layouts use one immutable grid, while dense layouts use the full scan when grid lookup and candidate handling would cost more than checking every pair. If a sparse-grid sweep moves any image, its candidate set is no longer current; the remainder of that sweep conservatively falls back to the full scan. The grid costs O(n + k) per sweep for k candidate checks (with O(n^2) worst-case dense behaviour), while small inputs retain the full pair scan. The cleanup is hard-capped at 256 sweeps so dense inputs cannot make cleanup grow with n beyond that fixed number of sweeps.

Images are pushed away from each other only, they are not kept inside the panel, and images are never re-ordered or removed. Images with size = Inf (e.g. the background image added by geom_bgimage()) and images that cannot be loaded are ignored by the repulsion: they keep their original position and do not push the other images around.

The width of an image that is sized through size/by (instead of an explicit width) is derived by grid from its height and from the physical aspect of the panel. geom_image_repel() uses the aspect reported by the coordinate system (coord_fixed(), exact) and assumes a square panel otherwise, which over-estimates the width of a panel that is wider than it is high. Pass explicit width/height when the exact box matters.

Examples

Run this code
library("ggplot2")
library("ggimage")
d <- data.frame(x = c(0.5, 0.52, 0.51),
                y = c(0.5, 0.51, 0.49),
                image = system.file("extdata/Rlogo.png", package = "ggimage"))
## overlapping images are pushed apart
ggplot(d, aes(x, y, image = image)) +
    geom_image_repel(width = 0.1, box.padding = 0.01)
## max.iter = 0 keeps the original coordinates
ggplot(d, aes(x, y, image = image)) +
    geom_image_repel(width = 0.1, max.iter = 0)
## only move them apart horizontally
ggplot(d, aes(x, y, image = image)) +
    geom_image_repel(width = 0.1, direction = "x")

Run the code above in your browser using DataLab