Search code examples
pythonpython-3.xggplot2rpy2

Save ggplot2 figure via rpy2 into a Python buffer


I'm trying to save the output of a ggplot2 R object created using rpy2 into a buffer controlled by Python.

I'm able to do this using matplotlib but I cannot seems to do it with ggplot2 via rpy2.


In matplotlib.pyplot, this can be accomplished with:

import matplotlib.pyplot as plt
import io
import numpy

def test_save():
    x = numpy.linspace(-5, 5)
    y = 3*x + 2
    fig = plt.figure()
    plt.plot(x, f)
    buf = io.BytesIO()
    plt.savefig(buf, format = 'png')
    return buf

ggplot2 attempt:

import io
import numpy   
import rpy2.robjects as robjects
from pandas import DataFrame
import rpy2.robjects.lib.ggplot2 as ggplot2


def test_ggplot2_save():

    x = numpy.linspace(-5, 5)
    y = 3*x + 2
    df = DataFrame({'x': x, 'y': y})

    gp = ggplot2.ggplot(df)
    pp = (gp 
      + ggplot2.aes_string(x='x', y='y')
      + ggplot2.geom_point()
      + ggplot2.labs(title="MY DATA", x='x', y='y'))
    # pp.plot()

    buf = io.BytesIO()

    robjects.r.ggsave(filename=buf, plot=pp, width=200, height=120, unit='mm')

Error:

NotImplementedError: Conversion 'py2ri' not defined for objects of type ''

I was trying to use the rpy2.robjects.lib.ggplot2.GGPlot.save feature.


Solution

  • R's ggplot2::ggsave is expecting a string specifying a path (relative or absolute) as an argument for the parameter filename. For example "/this/is/my/figure.png".

    A Python BytesIO object is quite different. It is an in-memory binary stream (roughly Python object that behaves like a (binary) file).

    If using ggsave is not an absolute requirement, consider using rpy2.robjects.lib.grdevices.render_to_bytesio(). This is the function that makes the following display inline figures in the Jupyter notebook:

    from rpy2.ipython.ggplot import image_png
    # pp is your ggplot2 figure
    display(image_png(pp))