/ Data Visualization

Low-level bindings to the CairoGraphics library for fast 2d drawing operations

Low-level bindings to the CairoGraphics library for fast 2d drawing operations

cairocore

cairocore provides a canvas and tools for fast 2d drawing operations.

It provides a low-level wrapper around the cariographics 2D graphics library (written in C) which provides drawing operations and related functions, with consistent output on multiple platforms and output media (e.g. SVG, PDF, PNG etc).

This package is not a graphics device - you can’t plot to it. Instead it provides a canvas for directly drawing shapes and text.

Key Features

  • Very fast line and shape drawing
  • Convert canvas surface to/from R arrays - this means you can draw on
    an array from within R
  • Alpha-blending and anti-aliasing
  • Direct control of what pixels get put on a canvas i.e. not having to
    pass through an intermediate plotting step (e.g. ggplot) or graphics
    device (e.g. png())

Package Philosophy

cairocore is a one-to-one mapping from R functions to C functions in
the cariographics C library.

This package will remain very “C-like”, but other packages are welcome
to wrap this cairocore to enable more idiomatic R programming styles.

One such wrapper is
cairobasic which offers
a subset of the possible drawing operations with a friendlier interface.

Installation Pre-requisite: Cairographics C library + headers

Install CairoGraphics on Mac OSX
  • Using homebrew - brew install cairo (this
    works on my Mac)
  • Using MacPorts - sudo port install cairo
  • Using fink
Install CairoGraphics on Linux
  • Debian/Ubuntu - sudo apt-get install libcairo2-dev
  • Fedora - sudo yum install cairo-devel
  • openSUSE - zypper install cairo-devel
Install CairoGraphics on Windows

I haven’t been able to test any of the windows techniques - if you are a
windows user, please let me know what worked for you!

Installation

You can install from
GitHub with:

# install.package('remotes')
remotes::install_github('coolbutuseless/cairocore')

Documentation + Tutorials

cairocore behaves almost identically to the CairoGraphics C library
and in many cases examples from the internet (which are all in C code)
may be lightly modified and used as R code.

The documentation for cairocore is mostly a direct translation of the
CairoGraphics documentation
and has been extracted from the C source files.

View the online documentation
here

A great tutorial on using CairoGraphics in C is from
zetcode.

Vignettes

I’ve tried to highlight a few interesting features of CairoGrapihcs in
the vignettes, but the library is huge and I can’t cover all of it here.

Hopefully there are enough code examples to get you started!

Example - Using cairocore as a drawing canvas

demo-shapes

library(cairocore)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Create a surface to draw on.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
width  <- 800
height <- 400

surface <- cairo_image_surface_create(
  format = cairo_format_t$CAIRO_FORMAT_ARGB32, 
  width  = width,
  height = height
)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Every surface must have a context in order to operate on it.
# For faster operation, antialiasing can be switched off
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cr <- cairo_create(surface)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Clear the surface to a light grey
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cairo_set_source_rgb(cr, 0.98, 0.98, 0.98)
cairo_paint(cr)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Draw some red lines
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cairo_set_source_rgba(cr, 1, 0, 0, 0.02)
for (i in seq(width)) {
  cairo_move_to(cr, 0, 0)
  cairo_line_to(cr, i, height)
  cairo_stroke(cr)
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Draw some rectangles
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cairo_set_line_width(cr, 0.5)
cairo_set_source_rgba(cr, 0, 0, 1, 0.2)

for (j in seq(1, height, 22)) {
  for (i in seq(width/2, width, 22)) {
    cairo_rectangle(cr, i, j, 20, 20)
    cairo_fill(cr)
  }
}


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Draw green circles
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for (x in seq(1, width/3, 50)) {
  for (y in seq(height/2, height, 50)) {
    cairo_set_source_rgba(cr, 0, 0.5, 0, 0.1)
    cairo_arc(cr, x, y, radius = 20, 0, 2*pi)
    cairo_fill(cr)
  }
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Get the image surface as a raster
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
raster_out <- cairo_image_surface_get_raster(surface, nchannel = 3)
plot(raster_out, interpolate = FALSE)

README-unnamed-chunk-2-1


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Save the surface as a PNG
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cairo_surface_write_to_png(surface, tempfile(fileext = ".png"))
#> [1] 0

Example - drawing 10,000 alpha blended lines

demo-swirl

library(cairocore)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Calculate the end coordinates of a lot of line segments
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
width  <- 1000
height <- 500
N      <- 10000
t      <- seq(0, 2*pi, length.out = N)
x1     <- width  * sin(t)
x2     <- width  * sin(2 * t + pi/2)
y1     <- height * cos(t)
y2     <- height * cos(4*t + pi/2)


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Create a surface to draw on.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
surface <- cairo_image_surface_create(
  format = cairo_format_t$CAIRO_FORMAT_ARGB32, 
  width  = width,
  height = height
)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Every surface must have a context in order to operate on it.
# For faster operation, antialiasing can be switched off
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cr <- cairo_create(surface)
# cairo_set_antialias(cr, cairo_antialias_t$CAIRO_ANTIALIAS_NONE)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Clear the surface to a light grey
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cairo_set_source_rgb(cr, 0.98, 0.98, 0.98)
cairo_paint(cr)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Set the drawing colour for subsequent operations
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cairo_set_source_rgba(cr, 0.2, 0.3, 1, 0.01)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Draw each line - 
#   this seems laborious but it is idiomatic C/cairo programming style
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for (i in seq(N)) {
  cairo_move_to(cr, x1[i], y1[i])
  cairo_line_to(cr, x2[i], y2[i])
  cairo_stroke(cr)
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Write some text on the cairo surface
# `cairo_font_slant_t` and `cairo_font_weight_t` are enums in C which have 
# been encoded as lists in R.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cairo_select_font_face (
  cr, 
  family = "sans", 
  slant  = cairo_font_slant_t$CAIRO_FONT_SLANT_NORMAL, 
  weight = cairo_font_weight_t$CAIRO_FONT_WEIGHT_BOLD
)

cairo_set_font_size(cr, 57.0)
cairo_set_source_rgba(cr, 0, 0, 0, 0.3) 
cairo_move_to (cr, 5.0, 60.0)
cairo_show_text (cr, "{cairocore}")

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Get the image surface as a raster
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
raster_out <- cairo_image_surface_get_raster(surface, nchannel = 3)
plot(raster_out, interpolate = FALSE)

README-unnamed-chunk-3-1

Example - taking an array in R, drawing on it, returning it to R

demo-volcano

library(cairocore)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Let's grab the volcano
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
arr <- (t(volcano) - min(volcano))/(max(volcano) - min(volcano))
plot(as.raster(arr), interpolate = FALSE)

README-unnamed-chunk-4-1

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Initialise a surface from the array
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
surface <- cairo_image_surface_create_from_array(arr)
cr      <- cairo_create(surface)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Draw a circle on the cairo surface
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cairo_arc(cr, 70, 15, 10, 0, 2*pi)
cairo_set_line_width(cr, 3);
cairo_set_source_rgba(cr, 255/255, 99/255, 71/255, 0.8)
cairo_stroke(cr)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Write some text on the cairo surface
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cairo_select_font_face (cr, "serif", cairo_font_slant_t$CAIRO_FONT_SLANT_NORMAL, cairo_font_weight_t$CAIRO_FONT_WEIGHT_BOLD)
cairo_set_font_size (cr, 17.0)
cairo_set_source_rgb (cr, 0.2, 0.6, 1.0) 
cairo_move_to (cr, 2.0, 56.0)
cairo_show_text (cr, "{cairocore}")

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Fetch the drawing surface as an array
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
array_out <- cairo_image_surface_get_array(surface=surface)
plot(as.raster(array_out), interpolate = FALSE)

README-unnamed-chunk-5-1

Related Software

  • The R Cairo package uses
    the CairoGraphics library internally to provide graphics output
    devices for plotting.
  • The R cairoDevice
    package appears to be almost identical to the {Cairo} package in
    that it provides graphics output devices for plotting.

Acknowledgements

  • R Core for developing and maintaining R
  • CRAN maintainers, for patiently shepherding packages onto CRAN and
    maintaining the repository

GitHub

Comments