I'm creating a plot in R, but then trying to return the resulting image data to Python so that Python can display the image.
Within R, I've used the magick
library to hold the image in memory (instead of plotting to the screen).
"We use
image_write
to export an image in any format to a file on disk, or in memory ifpath = NULL
"
I'm unsure how to process either the SexpExtPtr
or ByteVector
types that are returned by rpy2
to Python.
import rpy2.robjects as ro
r = ro.r
r('''
library("magick")
figure <- image_graph(width = 400, height = 400, res = 96)
plot(c(1,2,3))
image <- image_write(figure, path = NULL, format = "png")
# image_write(figure, path = 'example.png', format = 'png')
''')
figure = ro.globalenv['figure']
image = ro.globalenv['image']
im = Image.open(BytesIO(image))
The code above gives me the error:
Traceback (most recent call last):
File "stackoverflow.py", line 23, in <module>
im = Image.open(BytesIO(image))
TypeError: a bytes-like object is required, not 'ByteVector'
In Python:
figure
has type <class 'rpy2.rinterface.SexpExtPtr'>
image
has type <class 'rpy2.robjects.vectors.ByteVector'>
So... it turns out that <class 'rpy2.robjects.vectors.ByteVector'>
is an iterable and I can use bytes()
to construct an array of bytes.
Also, by putting the code inside a function that uses return
to return the PIL image I can get the image to display within a Jupyter notebook (alternatively we could just do image.show()
)
from io import BytesIO
import PIL.Image as Image
import rpy2.robjects as ro
def main():
r = ro.r
r('''
library("magick")
figure <- image_graph(width = 400, height = 400, res = 96)
plot(c(1,2,3))
image <- image_write(figure, path = NULL, format = "png")
image_write(figure, path = 'example.png', format = 'png')
''')
image_data = ro.globalenv['image']
image = Image.open(BytesIO(bytes(image_data)))
return image
if __name__ == '__main__':
image = main()
image.show()