Custom graphical devices

Warning

This is still very experimental, and using this may result in crashing the Python interpreter.

The C-API to R allows extension writers to implement custom graphical devices (using C). This feature was used to implement drivers to SVG or Cairo, for example (Cairo support made it later to the R codebase).

Rpy2 is exposing the creation of custome graphical devies to Python programmer, without the need for C.

To demonstrate how to implement a graphical, we consider the following example: a device that counts the number of times graphical primitives are used. This is something of very limited practical use, but enough to explain the principles.

Such a device would be implemented as follows:

import rpy2.rinterface._rpy_device as rdevice
from collections import Counter

class BeancounterDevice(rdevice.GraphicalDevice):
    """ Graphical devive for R that counts the
    number of times primitives are called."""

    def __init__(self):
        super(BeancounterDevice, self).__init__()
        self._ct = Counter()

    def circle(self, x, y, radius):
        self._ct['circle'] += 1

    def clip(self, x0, x1, y0, y1):
        self._ct['clip'] += 1

    def line(self, x1, y1, x2, y2):
        self._ct['lines'] += 1

    def mode(self, mode):
        self._ct['mode'] += 1

    def rect(self, x0, x1, y0, y1):
        self._ct['rectangle'] += 1

    def strwidth(self, text):
        self._ct['strwidth'] += 1
        return float(0)

    def text(x, y, string, rot, hadj):
        self._ct['text'] += 1

The class BeancounterDevice can now be used as genuine R plotting device.

from rpy2.robjects.packages import importr

dev = BeancounterDevice()

graphics = importr("graphics")
# plot into our counting device
graphics.plot(0, 0)

# Print the counts
print(dev._ct)

To implement a new custom graphical device for R, one only has to extend the class rpy2.rinterface._rpy_device.GraphicalDevice. Error messages will be printed if that new device does not implement functionalities used by R.

The Python documentation strings for the class and its methods are:

class rpy2.rinterface._rpy_device.GraphicalDevice

Python-defined graphical device for R.

activate()

Callback to implement: activation of the graphical device.

bottom

Bottom coordinate.

canGenKeybd

Ability to generate keyboard events.

canGenMouseDown

Ability to generate mouse down events.

canGenMouseMove

Ability to generate mouse move events.

canGenMouseUp

Ability to generate mouse up events.

circle()

Callback to implement: draw a circle on the graphical device. The callback will receive the parameters x, y, radius

clip()

Callback to implement: clip the graphical device. The callback method will receive 4 arguments (Python floats) corresponding to the x0, x1, y0, y1 respectively.

close()

Callback to implement: close the device.

deactivate()

Callback to implement: deactivate the graphical device.

devnum

Device number.

displayListOn

Status of the display list.

getevent()

Callback to implement: get event on the graphical device.

hasTextUTF8

UTF8 capabilities of the device.

left

Left coordinate.

line()

Callback to implement: draw a line on the graphical device. The callback will receive the arguments x1, y1, x2, y2.

locator()

Callback to implement: locator on the graphical device.

metricinfo()

Callback to implement: MetricInfo on the graphical device.

mode()

Callback to implement: mode of the graphical device.

newpage()

Callback to implement: create a new page for the graphical device. If the device can only handle one page, the callback will have to eventually terminate clean an existing page.

polygon()

Callback to implement: draw a polygon on the graphical device.

polyline()

Callback to implement: draw a polyline on the graphical device.

rect()

Callback to implement: draw a rectangle on the graphical device. The callback will receive 4 parameters x0, x1, y0, y1.

right

Right coordinate.

size()

Callback to implement: set the size of the graphical device. The callback must return a tuple of 4 Python float (C double). These could be: left = 0 right= <WindowWidth> bottom = <WindowHeight> top=0

strwidth()

Callback to implement: strwidth(text) -> width

Width (in pixels) of a text when represented on the graphical device. The callback will return a Python float (C double).

text()

Callback to implement: display text on the device. The callback will receive the parameters: x, y (position), string, rot (angle in degrees), hadj (some horizontal spacing parameter ?)

top

Top coordinate.

wantSymbolUTF8

UTF8 capabilities of the device.