
Register a font that draws the shapes at a common size
Source:R/shapes-font.R
register_shapes_font.RdThe shape palettes made with unicode = TRUE draw each shape by asking the
device font for a Unicode character. Fonts draw those characters at unrelated
sizes, so a circle, a triangle and a plus sign from one font can differ by
a factor of two in area, and a font may not have the character at all.
register_shapes_font() registers a font that ships with ggthemes and
contains the geometric shapes, arrows, signs and marks used by the palettes,
at the same Unicode characters, so the same palettes draw with comparable
sizes.
Value
The font family name, "ggthemes shapes", to pass as a fontfamily.
As side effects, the font is registered with systemfonts again, in
case the registry was cleared, and the palettes stop warning about shapes
the font has.
Size
Each glyph is scaled until the convex hull of its outline has the area of
one reference circle. That keeps hollow, filled and rotated shapes
comparable, and it is the convention R's own pch symbols follow (circle,
square, diamond and triangle have equal area). Stroke widths are fixed. The
exclamation mark is too narrow to reach the reference area without outgrowing
the em box, so it is drawn smaller.
Coverage
The font covers every shape the unicode = TRUE palettes draw, so they need
no other font: calc_shape_pal(), cleveland_shape_pal(),
stata_shape_pal() and tableau_shape_pal(). It also covers the Tableau
"kpi", "arrows" and "thin-arrows" palettes and the sign shapes of
"gender" (see tableau_shape_pal()). It does not cover the pictograph
shapes: the Tableau "weather" and "bug-tracking" palettes and the
restroom signs of "gender". Those characters still come from the
device font. Palettes with no unicode argument, such as
tremmel_shape_pal(), use base pch symbols and need no font.
Using the font
The simplest way is geom_point_glyph() in place of
ggplot2::geom_point(). It reads the font file itself, needs no font family
set anywhere, and works with ggsave().
With geom_point(), the font must be set on the device font family, because
geom_point() does not take a family. With a graphics device that reads
fonts through systemfonts, such as ragg or svglite, set
the family on a grid viewport around the plot:
family <- register_shapes_font()
p <- ggplot(mtcars, aes(mpg, hp, shape = factor(cyl))) +
geom_point() +
scale_shape_tableau(unicode = TRUE)
print(p, vp = grid::viewport(gp = grid::gpar(fontfamily = family)))A palette made with unicode = TRUE warns, when the plot is built, if the
device's default font lacks its shapes; it cannot see a family set on a
viewport. Once register_shapes_font() or geom_point_glyph() has been
called, it warns only about shapes this font does not have. That lasts until
ggthemes is unloaded, for example by restarting R or with
unloadNamespace("ggthemes"), since the setting lives in the package
namespace.
ggthemes registers the font with systemfonts when it loads, if
systemfonts is installed, so the family name "ggthemes shapes" works
even before register_shapes_font() is called.
ggsave() draws the plot without that viewport, so the font does not apply
through it; draw the plot to the device yourself, as above.
Devices that look fonts up themselves (pdf(), and png() with the cairo
type) do not see fonts registered this way; install
system.file("fonts", "ggthemes-shapes.ttf", package = "ggthemes") on the
system to use the font there. A copy installed on the system is used as it
is: register_shapes_font() does not register the family a second time.
The font is original work distributed under the same license as the package.
It is built by data-raw/shapes-font/build.py.
See also
tableau_shape_pal() and cleveland_shape_pal() for palettes made
with unicode = TRUE.
Other shapes:
cleveland_shape_pal(),
embed_shapes_font(),
geom_point_glyph(),
scale_shape_cleveland(),
scale_shape_tremmel(),
tremmel_shape_pal()
Examples
if (FALSE) { # rlang::is_installed(c("systemfonts", "ragg")) && interactive()
library("ggplot2")
family <- register_shapes_font()
p <- ggplot(mtcars, aes(mpg, hp, shape = factor(cyl))) +
geom_point(size = 4) +
scale_shape_tableau(unicode = TRUE)
png_file <- tempfile(fileext = ".png")
ragg::agg_png(png_file, width = 480, height = 360)
print(p, vp = grid::viewport(gp = grid::gpar(fontfamily = family)))
dev.off()
}