1

I am using ggplot2 to plot a picture in my server, now I want to transfer the picture to front-end. In fact, the front-end can send some plot commands to the server, so after generating the png, the server need to transfer it to front-end. My current method is to save the png as tempory png, and delete it as soon as it has been transfered. Like this:

def r_function(x,y,filename):
  r_code = f"""
  library(ggplot2)
  p <- ggplot(data.frame(x={x}, y={y}), aes(x=x, y=y)) +
     geom_point() +
     labs(title="R Plot")
  ggsave(p, filename="{filename}", width=4, height=3, dpi=300)
  """
  robjects.r(r_code)


def test(request):
    x = request.GET.get("x", "c(1,2,3,4,5)")
    y = request.GET.get("y", "c(2,4,6,8,10)")
    filename = f"{uuid.uuid4()}_plot.png"
    with conversion.localconverter(default_converter):
        r_function(x, y, filename)
        with open(f"{filename}", "rb") as f:
            response = HttpResponse(f.read(), content_type="image/png")
            response["Content-Disposition"] = f"inline; filename={filename}"
        # delete the temporay file
        os.remove(filename)
    return response

But I think this soultion is not efficent, I don't hope generate the tempory file and i just want to transfer the png file once it has been generated. So is there any better way to solve the problem?

Fei
  • 51
  • 4
  • 1
    Have you seen the `ggplot2` section of the `r2py` [docs](https://rpy2.github.io/doc/latest/html/graphics.html)? Rather than sending the Python data to the R function it imports the `ggplot2` library into Python and then draws the plot directly to Python's graphics device. Slightly unclear on the setup you're describing with the server - could you replicate this? – SamR Jul 21 '23 at 15:33
  • @SamR Thank you for reminding me of the docs. I am building a website using django as back-end framework and djang-restframwork for api. The code snippets is also in DRF views.py, my idea is to run r code in python and plot different png according to the user's request, then transfer the png via DRF. – Fei Jul 21 '23 at 16:23

1 Answers1

2

I initially though you could write the png as base64 directly into a variable instead of a file, but @MrGumble in How to convert simple R plot image to base64 encoding without reading/writing image file to disk first? points out points out png requires a file (source: .External(C_devga, paste0("png:", filename), ...)

I think the best you can do is use tempfile. But, you can put it all in the same function (keep the tempfile create/del in one place, don't have to manage across requests), returning the base64 encoded image as a string to use with python.

We can wrap the saving function with tryCatch to make sure the temp file is removed.

function str_plt(x,y) {
  p <-  ggplot(data.frame(x=x,y=y)) +
        aes(x,y) + geom_points()
  fn <- tempfile(fileext='.png')
  img <- tryCatch({
            ggsave(p, file=fn)
            base64enc::base64encode(fn)},
         finally=unlink(fn))
  return(img)
}
Will
  • 1,206
  • 9
  • 22