fill_scribble() builds a grid::pattern() fill value from several
randomly wandering lines, each a random finite sum of sine harmonics
(see the internal scribble_lines() helper) rather than a smooth noise
field or a scattered discrete motif – giving a loose, hand-drawn
scribble texture built from genuinely continuous strokes.
Usage
fill_scribble(
color = "black",
angle = 0,
n_lines = 5L,
n_harmonics = 3L,
amplitude = 0.35,
resolution = 200L,
linewidth = 1,
spacing = 0.25,
aspect = NULL,
seed = 1L,
extend = "repeat"
)Arguments
- color
One or more line colours. A vector shorter than
n_linesis recycled (in order, not randomly) across the wandering lines – a single colour (the default) colours every line the same, matching the original behaviour. Default"black".- angle
Line angle in degrees, measured counterclockwise from horizontal (matching
fill_hatch()'s ownangleconvention).0/90/180/270(the olddirection = "horizontal"/"vertical") tile exactly seamlessly; any other angle rotates the tile content as an approximation only – see "Known limitation" below. Default0.- n_lines
Number of wandering lines per tile. Must be a positive integer. Default
5L.- n_harmonics
Number of sine harmonics summed per line. Must be a positive integer. Default
3L.- amplitude
Maximum total wiggle amplitude, as a
"npc"fraction of the tile, split acrossn_harmonics(so more harmonics each contribute proportionally less). Must be a non-negative number. Default0.35.- resolution
Number of points sampled along each line. Must be a positive integer of at least
2L. Default200L.- linewidth
Line width. Must be a positive number. Default
1.- spacing
Baseline tile size, as a fraction of the target's bounding box. Must be a positive number. Default
0.25.- aspect
Width-to-height ratio of the target polygon's bounding box. Must be a positive number, or
NULL(the default) to resolve it automatically from the real target's own bounding-box aspect ratio atdraw()time – see the fill class. Passing a fixed number instead computes the pattern once, immediately, against that value only.- seed
Integer seed for the random harmonics. Default
1L.- extend
Passed to
grid::pattern(). Default"repeat".
Value
A pattern object as returned by grid::pattern(), suitable for
use as the fill argument to grid::gpar().
Details
A wandering open line poses a tiling problem none of the other
fill_*() helpers have: fill_hatch()'s diagonal and fill_noise()'s
raster both tile by construction (a straight corner-to-corner line, or
an already-periodic field), and fill_stipple()/fill_scatter()/
fill_halftone() sidestep the problem entirely by keeping their
scattered content margined well clear of the tile edge. A wandering
line that's meant to look continuous can't stay clear of the edge –
it has to run all the way to it, and pick up again at exactly the right
place, in both position and slope, on the opposite edge, or the seam
shows as a visible kink. fill_scribble() gets this for free by
building each line as a random sum of sine harmonics at integer
frequencies only: over one full period, such a sum always returns
exactly to its starting value and slope (to floating-point precision),
so consecutive tile copies join with no visible seam – confirmed
visually with extend = "repeat" at small spacing, including
repeated copies (unlike the polygon-in-a-genuinely-repeated-tile issue
documented at fill_scatter(), open-line content showed no clipping or
distortion in testing).
Known limitation – arbitrary angle is only approximate
Every other angled helper (fill_hatch()/fill_crosshatch()/
fill_stripe()) achieves an arbitrary angle by reshaping the tile
itself (via hatch_tile_dims()) around content that's a plain
corner-to-corner diagonal. That trick doesn't generalize here:
reshaping the tile around a wandering line just anisotropically
stretches its wiggle rather than rotating it, since the line's content
isn't a bare diagonal the tile shape can reinterpret. A genuinely
rotated wandering line would need the tile built as a rotated/sheared
parallelogram with edge-matching worked out for a curve rather than a
segment – no such technique exists in this package. At angle a
multiple of 90 degrees, fill_scribble() instead swaps/reflects the
along/across axes directly (no trigonometry involved), so tiling
stays exactly seamless – this is what angle = 0/90 (the old
direction = "horizontal"/"vertical") already relied on, now
extended to 180/270 for free. Any other angle instead rotates
the whole tile's content about its own centre, which is only an
approximation: the underlying wandering line is periodic along its own
local axis, not around an arbitrary rotated one, so a non-right-angle
rotation can leave a visible seam where adjacent tile copies meet, and
may leave small gaps near the tile corners that no line's wiggle
reaches. Revisit if a real sketch needs a genuinely seamless arbitrary
angle.
Examples
draw(shape_circle(fill = fill_scribble(n_lines = 4L, seed = 6602L)))
# angle = 90 runs the wandering lines top-to-bottom instead, tiling
# exactly as seamlessly as angle = 0
draw(shape_circle(
fill = fill_scribble(n_lines = 4L, angle = 90, seed = 6602L)
))
# any other angle rotates the tile content -- an approximation only,
# so a seam can be visible at the tile edges
draw(shape_circle(
fill = fill_scribble(n_lines = 4L, angle = 30, seed = 6602L)
))
# more harmonics and higher amplitude give a more agitated scribble
draw(shape_circle(
fill = fill_scribble(
n_lines = 6L,
n_harmonics = 6L,
amplitude = 0.6,
seed = 6602L
)
))
# a colour vector is recycled across the wandering lines
draw(shape_circle(
fill = fill_scribble(
color = c("steelblue", "tomato"),
n_lines = 4L,
seed = 6602L
)
))