Some New Graphical Parameter Specifications in R

Paul Murrell
Department of Statistics
The University of Auckland

This document follows on from the discussion of font specification in R by looking at the user-level interface for specifying fonts and then considering new specifications for line end/joins and alpha transparency.

General points

The graphics engine and graphics device interface has now been modified so that, instead of passing individual graphical parameters, a single "graphics context" (a pointer to an R_GE_gcontext structure) is passed from graphics systems to the graphics engine and on to graphics devices. This context contains a full set of graphical parameters and individual graphics functions only need to take notice of the relevant ones (e.g., a line-drawing function can ignore the font settings).

Adding new graphical parameters to the graphics context requires three steps: the appropriate slots must be added to the R_GE_gcontext structure (forcing a recompile of all graphics systems and graphics devices); graphics systems should then provide some interface for the user to set/get these parameters; graphics devices should attempt to honour the new parameter settings.


As described in a previous document, the current font setting is described by three parameters: font family, font face, and font size (times cex).

Graphics Engine implementation

These parameters are stored in the R_GE_gcontext structure. The graphics engine intercepts cases where the fontfamily describes a Hershey font.
    double cex;          
    double ps;           
    int fontface;        
    char fontfamily[50]; 
The following font family names are interpreted as Hershey vector fonts (and handled by the graphics engine rather than passed on to the graphics device): "HersheySerif" , "HersheySans" , "HersheyScript" , "HersheyGothicEnglish" , "HersheyGothicGerman" , "HersheyGothicItalian" , "HersheySymbol" , "HersheySansSymbol".

Graphics System implementation

grid already has fontfamily, fontface, fontsize (and cex) gpars. This allows grid to handle hershey fonts without a nasty additional vfont spec.

For base graphics, the suggestion is to allow the existing font par() to be a list specifying both family and face.

Implementation in devices

Some of the following is loosely based on the Cascading Style Sheet approach to specifying font families.
Font databases
Specifying a font family by a single "name" may be ambiguous (e.g., a system may have Type 1 and TrueType versions of a font, there may be two versions of a font from two different "foundries", ...). Furthermore, the additional information required to resolve the ambiguities will tend to be device-specific.

To allow the user to solve any ambiguity, each device should provide a dev.options() function, which includes a fontdb option. The fontdb is a list of named elements, where the name is a font family name and the element is a device-specific description of the font family to be used.

The fontdb must include the following "generic" font family specifications (even if the same font is used for all of them): "sans", "serif", "symbol", "mono". An example for ps.options might be ...

    ps.options(fontdb=list(sans="Helvetica", serif="Times", 
                           symbol="Symbol", mono="Courier"))
... and for x11.options ...
The default fontfamily will be "sans" to provide the current default behaviour.

Font family specifications which are not in the fontdb will not be modified and each device will try to satisfy the specification as well as it can. If the user decides that the device does not produce the desired behaviour for a particular font family specification, then the user can add an element to the fontdb to obtain the desired behaviour. For example, if X11 is not finding the right font for "Helvetica", the user could do something like ...

    myfontdb <- x11.options("fontdb")
    myfontdb$Helvetica <- "-adobe-helvetica-*-*-*-*-*-*-*-*-*-*-*-*"
Similarly, a windows user could enforce TrueType font selection ...
    myfontdb <- win.options("fontdb")
    myfontdb$Arial <- "Arial [TT]"
For very special cases, one-off font family names could be created ...
    myfontdb <- win.options("fontdb")
    myfontdb$ArialTT <- "Arial [TT]"
    myfontdb$Arial <- "Arial"
Changing font family on-the-fly
The following devices should in theory be able to dynamically attempt to honour font family specifications(?): X11, Windows, Quartz, Gnome, gtk, Java.

I think a different approach will be necessary for file-based devices where header information needs to include a declaration of the font resources used in the document. Here I am thinking of: PostScript, PDF, SVG.

My suggestion is that in these cases the full set of fonts to be used has to be declared when the device is opened. For example, something like:

    postscript(family=c("Courier", "Helvetica", "Times"))

I'm not sure yet what the situation is for xfig or PicTeX.

Alpha transparency

R currently supports the colour specification "transparent" for making a PNG background transparent. All other colours are fully opaque. There is a growing interest in having more general transparency support.

Graphics Engine implementation

R's internal colour specification has already been extended to include an "alpha channel". A colour is stored as a 32-bit integer with 8 bits each for Red, Green, and Blue and 8 bits for alpha transparency. There are some possible problems with this approach.

The first issue is with the specification of transparent colours. It would be possible (though a reasonable amount of work) to modify the colour-generating functions (e.g., rgb, hsv, ...) to accept an extra "alpha" argument. However, it is not simple to extend the specification of colours by name (e.g., col="red") to include a flexible description of transparency.

A similar problem arises in converting an internal R colour back into a user-level colour name (e.g., rgb(0, 0, 1) produces "#0000FF").

An alternative imlpementation would add a separate alpha slot in the R_GE_gcontext -- essentially make the specification of the colour and the specification of the alpha level independent. This would imply a common alpha setting for both col and fill within a single R_EG_gcontext, which is a little more restrictive (for example to get a rectangle whose border and fill have different alpha transparencies you would need to draw two separate rectangles), but would avoid some of the problems with the alpha channel approach. For example, semi-transparent red becomes something like:

    (col="red", alpha=0.3)
A third alternative would be to have separate "colalpha" and "fillalpha" slots in the R_GE_gcontext to allow separate border and fill transparencies in a single specification.

Specifications in other systems

SVG specifies the alpha transparency level separately from the colour, either as a property of an entire object or as separate stroke and fill properties.

PDF also specifies transparency as a separate property.

In Java (Graphics2D), transparency is part of a color description.

Graphics System implementation

grid already has an "alpha" gpar. This is not passed to the graphics engine yet (it's only used with the gridSVG package). This is obviously designed along the lines of having an alpha slot in the R_GE_gcontext.

As discussed above, the simplest thing to implement for base would be a new "alpha" par().

Implementation in devices

There is little difference between having a separate R_GE_gcontext slot and using the current alpha channel for devices. An R_ALPHA macro already exists to extract the alpha channel from a colour spec.

I think the following devices should be capable of honouring an alpha transparency: SVG (for sure), Quartz (though I'm guessing), gtk (also guessing), gnome (guess), Java, PDF (although the device would need updating to support version 1.4).

I have no idea for Windows.

I'm pretty sure the following cannot support transparency: PostScript, xfig, X11. But there are X11 extensions which do support transparency (need to determine whether the appropriate extensions [Render?] can be assumed to be available).

I totally assume that PicTeX cannot support transparency.

Line end/joins

Currently R always uses "round" caps for line endings and "round" joins for line joins. The latter is typically fairly reasonable, but it is not hard to make the former look silly. For example, ...
    plot(1:10, type="h", lwd=30)
The proposal is to add line end and line join specifications to R.

Specifications in other systems

The W3C SVG specification, the Java 1.4 spec, and the X11 spec all pretty much agree:
  1. Line endings are either rounded ("round cap"), flat at the line end ("butt cap"), or flat and extended slightly beyond the line end ("square cap").
  2. Line joins are either rounded ("round join"), pointy ("mitre join"), or squared-off ("bevel join").
  3. SVG and Java also allow a "mitre limit" to convert to bevel joins if a mitre join would look too spiky. X11 has a fixed limit. I think the limit is expressed as the angle between the two line segments at the join. The default setting seems to be 10 usually and SVG sets a lower bound for the limit at 1.

Graphics Engine implementation

Just add three new elements to the R_GE_gcontext structure:
    int linecap;
    int linejoin;
    double mitrelimit;

Graphics System implementation

For base graphics, add three new par()s (naming following the tradition of as much abbreviation as possible): Similarly for grid graphics, add three new gpars:

Implementation in devices

I have evidence to suggest the following devices should be able to honour the line end/join specifications (* indicates no user-settable mitre limit; I don't think this is likely to be a HUGE problem): X11*, PostScript, PDF, xfig*, SVG, Java.

I haven't looked yet, but I'd be mightily surprised if these ones couldn't do it: Windows, Quartz, Gnome, gtk.

I have no idea yet whether PicTeX will support it.