简体   繁体   中英

How do you use R in Python to return an R graph through Django?

I'm trying to run the following R code through my Django application with the end result being a printed R graph in a Python Django webpage. Here is the code for R.

t=read.table(file=file("request.FILES['fileUpload']"))
colnames(t) <- c('x', 'y')
t = data.frame(t)
fit1 = lm(y ~ x, data = t)
par(mfrow=c(1,1))
plot(x=t$x, y=t$y, xlab="x", ylab="y", main="Simple Linear Regression", xlim=c(0,100), ylim=c(0,6), par=20)
abline(fit1, col="red")

Here is something like what I am trying to achieve in the Django function.

from django.shortcuts import render, HttpResponse
import pandas as pd

def upload_files(request):
    if request.method == 'POST':
        upload = pd.read_table(request.FILES['fileUpload'])
        << Run R Code Here and return the graph >>
        response = RGraph
        return response
             OR
        return render(request, 'Regression/index.html', {'graph':response})
    return render(request, 'Regression/index.html')

HTML code is as follows.

<html>
    <title>Import File</title>
        <body>
            <h1>Import File</h1>
                <hr>
            {% if graph %}
                <img alt="my base64 graph" src="data:image/png;base64,{{graph}}" />
            {% endif %}
            <form enctype="multipart/form-data" method="post">
                {% csrf_token %}
                <input type="file" name="fileUpload" />
                <input type="submit" value="Submit" />
            </form>
        </body>
</html>

As always, thanks for the help.

Apparently rpy2 does not provide a direct function which can return a file object to python. So what i recommend is:

1) Set a path to save your R image files

  • On your settings.py define a variable where your R scripts/images should be saved

    STATIC_R = 'r_plots'

2) Build a model/form to handle the file management based on your settings

  • Model

    from django.conf import settings class RScript(models.Model): script = FileField(upload_to=settings.STATIC_R) @property def script_path(self): return os.path.basename(self.script.name)
  • Remember (from docs): FielField.upload_to : A local filesystem path that will be appended to your MEDIA_ROOT setting to determine the value of the url attribute.

  • Form

    class RScriptForm(forms.ModelForm): class Metal: model = RScript fields = ('script',)

3) Running you code from upload

  • Receive your R script and save it

    my_plot_script = ''' t=read.table(file=file("{path}")) colnames(t) <- c('x', 'y') t = data.frame(t) fit1 = lm(y ~ x, data = t) par(mfrow=c(1,1)) png(filename="{path}.png") plot = plot(x=t$x, y=t$y, xlab="x", ylab="y", main="Simple Linear Regression", xlim=c(0,100), ylim=c(0,6), par=20) abline(fit1, col="red") dev.off() ''' def my_view(request): if request.method == 'POST': form = RScriptForm(request.POST) if form.is_valid(): form.save() (...)
  • Now that we have script saved let's try to running it with rpy2

    my_plot_script = ''' t=read.table(file=file("{path}")) colnames(t) <- c('x', 'y') t = data.frame(t) fit1 = lm(y ~ x, data = t) par(mfrow=c(1,1)) png(filename="{path}.png") plot = plot(x=t$x, y=t$y, xlab="x", ylab="y", main="Simple Linear Regression", xlim=c(0,100), ylim=c(0,6), par=20) abline(fit1, col="red") dev.off() ''' def my_view(request): context = {} if request.method == 'POST': form = RScriptForm(request.POST) if form.is_valid(): form.save() import rpy2.robjects as robjects robjects.r(my_plot_script.format(form.instance.script_path)) context['graph'] = form.instance.script_path + '.png' return render(request, 'Regression/graph.html', context)
  • on your template

    <html> <title>Import File</title> <body> <h1>Import File</h1> <hr> {% if graph %} <img alt="my base64 graph" src="{{graph}}" /> {% endif %} <form enctype="multipart/form-data" method="post"> {% csrf_token %} <input type="file" name="fileUpload" /> <input type="submit" value="Submit" /> </form> </body> </html>
  1. For this you can use the interface between R and Python given in the RPy2` python package . This allows you to run a R session alongside a python session, and being able to run R commands from within python and getting back the result.

  2. Alternatively, you can run R as a commandline script on the server, have a look at Rscript to get this working. This script could produce a png based on a number of input arguments. Python could then pick up the png and send it back to the user.

  3. As a third alternative, you could run R via Rserve , and create a connection to it to get the plotting done. For example see here .

Solution 3 is a bit overkill, but allows you to use R on a different server than your Django instance. Solution 1. is quite flexible, but more complex. Finally, solution 2. is the simplest solution, but sometimes lacks flexibility, especially if lot's of interaction between R and Python is needed.

If you install.package('magick') in your R instance then you can use rpy2 to get the image data back to Python as follows (I've used a simplier plot function):

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_data = ro.globalenv['image']

    image = Image.open(BytesIO(bytes(image_data)))

    return image


if __name__ == '__main__':
    image = main()
    image.show()

You can then use the method here to render the image within a Django template.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM