devoutsvg
devoutsvg
provides a bespoke SVG graphics device written in plain R.
The key feature of this SVG graphics device is that it allowd for the use of patterns for filled regions in plots!
Installation
You can install from GitHub with:
# install.packages("devtools")
devtools::install_github("coolbutuseless/lofi") # Colour encoding
devtools::install_github("coolbutuseless/minisvg") # SVG creation
devtools::install_github("coolbutuseless/devout") # Device interface
devtools::install_github("coolbutuseless/devoutsvg") # This package
Basic usage of the svgout
device
Use this device in the same way you would use pdf()
, png()
any of the other
graphics output devices in R.
This results is thankfully uninteresting! That is, if the svgout
device works
properly then the output should like the standard ggplot output you’ve seen
hundreds of times before.
devoutsvg::svgout(filename = "img/devoutsvg/example-basic.svg")
ggplot(mtcars) +
geom_point(aes(mpg, wt, colour = as.factor(cyl))) +
labs(title = basename("Example - Basic"))
invisible(dev.off())
Warning in file(con, "w"): cannot open file 'img/devoutsvg/example-basic.svg':
No such file or directory
Warning in dev.off(): rdevice_close: svg_callback() Evaluation error: cannot
open the connection.
Filling with patterns
Because we now have control over the graphics device at quite a low level, we get to misbehave!
The svgout
device can be instructed to use patterns instead of the actual RGB
colour - this is achieved by
- instructing the device to use a particular pattern package (
pattern_pkg
), and - encoding particular patterns from that package as their RGB representations using
{pattern_pkg}::encode_pattern_params_as_hex_colour()
When svgout
is asked to render a colour, it instead asks pattern_pkg
to **decode**hex_colour_as_pattern_params
and returns the desired SVG pattern snippet.
Some examples of pattern packages are:
library(svgpatternsimple)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Encode the parameters for 3 different patterns into 3 different colours
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gear4_colour <- svgpatternsimple::encode_pattern_params_as_hex_colour(
pattern_name = 'null',
colour = '#123456'
)
gear6_colour <- svgpatternsimple::encode_pattern_params_as_hex_colour(
pattern_name = 'stipple',
colour = '#ff4455',
spacing = 10
)
gear8_colour <- svgpatternsimple::encode_pattern_params_as_hex_colour(
pattern_name = 'hex',
angle = 0,
spacing = 20,
fill_fraction = 0.1,
colour = '#125634'
)
c(gear4_colour, gear6_colour, gear8_colour)
svgout(filename = "img/devoutsvg/example-manual.svg", pattern_pkg = 'svgpatternsimple')
ggplot(mtcars) +
geom_bar(aes(as.factor(cyl), fill = as.factor(cyl)), colour = 'black') +
labs(title = basename("Example - manual pattern specification")) +
theme_bw() +
theme(legend.key.size = unit(1.5, "cm")) +
scale_fill_manual(
values = c(
'4' = gear4_colour,
'6' = gear6_colour,
'8' = gear8_colour
)
)
invisible(dev.off())
Using scale_fill_pattern_simple()
Rather than specifying individual patterns to map to colours, you can use a scale_fill
.
Since RGB colours don’t intuitively map to patterns, if you let ggplot choose the patterns
using the default scale_fill_discrete()
you will get a pretty ugly combination of
patterns in your plot.
scale_fill_pattern_simple()
allows the user to specify the envelope of desired outputs
and ggplot will map values-to-patterns automatically within this envelope.
By default this will give an OK spread of pattern styles, but it probably won’t be great.
See the next section for how to specify the desired envelope of possible patterns.
svgout(pattern_pkg = 'svgpatternsimple', filename = "img/devoutsvg/example-scale-fill-2.svg")
ggplot(mtcars) +
geom_bar(aes(as.factor(cyl), fill = as.factor(cyl)), colour = 'black') +
labs(title = "scale_fill_pattern_simple() - defaults") +
theme_bw() +
theme(legend.key.size = unit(1.5, "cm")) +
svgpatternsimple::scale_fill_pattern_simple()
invisible(dev.off())
Using scale_fill_pattern_simple()
with a defined pattern set.
By default scale_fill_pattern_simple()
will give an OK spread of pattern styles, but it probably won’t be great.
The call to scale_fill_pattern_simple()
can be customised to limit the possible
choices of pattern which will appear in the plot. The default options are as follows:
pattern_name = c('stripe', 'dot', 'hatch', 'check', 'stipple', 'hex')
angle = c(22., 45, 67.5)
spacing = seq(5, 50, length.out = 7)
fill_fraction = seq(0.1, 0.9, length.out = 3)
In this following example, the choice of possible patterns is limited to ‘stripe’ and ‘hatch’,
all at 45 degrees, with a range of fill_fraction
and spacing
svgout(pattern_pkg = 'svgpatternsimple', filename = "img/devoutsvg/example-patternsimple-scale-fill.svg",
width = 8, height = 6)
ggplot(mtcars) +
geom_density(aes(mpg, fill = interaction(cyl, am)), alpha = 1) +
theme_bw() +
theme(legend.key.size = unit(1.2, "cm")) +
labs(title = "scale_fill_pattern_simple() - custom") +
svgpatternsimple::scale_fill_pattern_simple(
pattern_name = c('stripe', 'hatch'),
fill_fraction = seq(0.1, 0.4, length.out = 5),
angle = c(45),
spacing = c(10, 20))
invisible(dev.off())
Pattern fills with base plots
colours <- c(
svgpatternsimple::encode_pattern_params_as_hex_colour(
pattern_name = 'null',
colour = '#123456'
),
svgpatternsimple::encode_pattern_params_as_hex_colour(
pattern_name = 'stipple',
colour = '#ff4455',
spacing = 10
),
svgpatternsimple::encode_pattern_params_as_hex_colour(
pattern_name = 'hex',
colour = '#ddff55',
spacing = 8
),
svgpatternsimple::encode_pattern_params_as_hex_colour(
pattern_name = 'check',
colour = '#ee55ff',
spacing = 10
)
)
devoutsvg::svgout(pattern_pkg = 'svgpatternsimple', filename = "img/devoutsvg/example-pie.svg")
pie(c(cool = 4, but = 2, use = 1, less = 8), col = colours)
invisible(dev.off())
U.S. Geological Survey patterns on geom_sf()
plots
The following plot uses the SVG pattern library made available in svgpatternusgs
.
The 6 areas are manually assigned a colour which corresponds to a set of pattern params.
The parameters are encoded to a colour by the encode_pattern_params_as_hex_colour()
function
in the svgpatternusgs
package.
library(sf)
library(svgpatternusgs)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Select some data
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
nc$mid <- sf::st_centroid(nc$geometry)
nc <- nc[nc$NAME %in% c('Surry', 'Stokes', 'Rockingham', 'Yadkin', 'Forsyth', 'Guilford'), ]
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Encode specific USGS pattern numbers into colours
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
colours <- c(
Surry = svgpatternusgs::encode_pattern_params_as_hex_colour(usgs_code = 601, spacing = 100, fill='#77ff99'),
Stokes = svgpatternusgs::encode_pattern_params_as_hex_colour(usgs_code = 606, spacing = 100),
Rockingham = svgpatternusgs::encode_pattern_params_as_hex_colour(usgs_code = 629, spacing = 100),
Yadkin = svgpatternusgs::encode_pattern_params_as_hex_colour(usgs_code = 632, spacing = 100),
Forsyth = svgpatternusgs::encode_pattern_params_as_hex_colour(usgs_code = 706, spacing = 100),
Guilford = svgpatternusgs::encode_pattern_params_as_hex_colour(usgs_code = 717, spacing = 100)
)
devoutsvg::svgout(filename = "img/devoutsvg/example-usgs.svg", pattern_pkg = 'svgpatternusgs')
ggplot(nc) +
geom_sf(aes(fill = NAME)) +
scale_fill_manual(values = colours) +
theme(legend.key.size = unit(0.6, "cm")) +
labs(title = "U.S. Geological Survey Patterns with `geom_sf()`") +
theme_bw()
invisible(dev.off())
SVG to PDF
If you need a PDF version of an SVG file, there are a number of options.
- Inkscape
rsvg
on the command linersvg-convert -f pdf -o t.pdf t.svg
CairoSVG
on the command line (python based)cairosvg in.svg -o out.pdf
Imagemagick
(not 100% sure)convert file.svg file.pdf
Chrome
headless (maybe?)chrome --headless --disable-gpu --print-to-pdf="output.pdf" "input.svg"
- Web-based. There are lots of these e.g.