Использование rpy2 для возврата данных изображения из R в Python

#python #r #imagemagick #rpy2

#python #r #imagemagick #rpy2

Вопрос:

Я создаю график в R, но затем пытаюсь вернуть результирующие данные изображения в Python, чтобы Python мог отобразить изображение.

В R я использовал magick библиотеку для хранения изображения в памяти (вместо вывода на экран).

«Мы используем image_write для экспорта изображения в любом формате в файл на диске или в памяти, если path = NULL «

Я не уверен, как обрабатывать SexpExtPtr ByteVector типы or, которые возвращаются rpy2 в 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))
  

Приведенный выше код выдает ошибку:

 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'

  

В Python:

  • figure имеет тип <class 'rpy2.rinterface.SexpExtPtr'>
  • image имеет тип <class 'rpy2.robjects.vectors.ByteVector'>

Ответ №1:

Итак … оказывается, что <class 'rpy2.robjects.vectors.ByteVector'> это итеративно, и я могу использовать bytes() для построения массива байтов.

Кроме того, поместив код в функцию, которая использует return для возврата изображения PIL, я могу получить изображение для отображения в записной книжке Jupyter (в качестве альтернативы мы могли бы просто сделать 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()
  

Комментарии:

1. rpy2 делает все списки R, векторы, массивы итеративными из Python. В дополнение к этому несколько типов массивов совместимы между R и Python, и для них существуют более эффективные решения. Например, ваш объект image будет реализовывать интерфейс массива numpy ( numpy.org/doc/stable/reference/arrays.interface.html ). Это позволит вам использовать ускорение C с совместимым пакетом (например, numpy.array , или numpy.asarray ).