如何在Python中使用R,通过Django返回一个R图形?

5

我正在尝试通过我的Django应用程序运行以下R代码,最终结果是在Python Django网页上打印出R图形。以下是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")

这是我在Django函数中尝试实现的类似内容。

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代码。

<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>

一如既往,感谢您的帮助。


抱歉,这里的问题是什么? - ρss
我编辑了标题以使问题更清晰。 - Ravaal
只需在模板中创建一个<img src="">,其中src指向由R生成的图表即可。 - Shang Wang
但是我如何通过Python创建图表呢?我现在正在研究rpy2,但是在导入importr和lm函数时出现错误。 - Ravaal
3个回答

7

显然,rpy2没有直接提供一个可以返回Python文件对象的函数。所以我建议:

1)设置保存R图像文件的路径

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

    STATIC_R = 'r_plots'
    

2) 根据您的配置构建一个模型/表单来处理文件管理

  • 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) 从上传中运行你的代码

  • 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>
    

好的,请给我一些时间 :) - Ramon Moraes
谢谢您抽出时间来解决这个问题。我在原始帖中添加了index.html的HTML代码。 - Ravaal
@Poppins586,你能否告诉我R脚本/函数中哪一行是生成要绘制的图像的代码?我对R不太熟悉。 - Ramon Moraes
一个生成了图形,另一个在图形上进行线性回归。这两行代码是我发布的代码中的最后两行。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") - Ravaal
好的。现在我明白了。@Shang Wang 这个人是对的。你需要将绘图保存为一个图像,放在静态配置覆盖的文件夹中,然后只需将文件的字符串/名称传递给模板上的 static 标签。 - Ramon Moraes
显示剩余3条评论

3
  1. 你可以使用RPy2 Python包提供的R和Python之间的接口。这允许您在Python会话旁边运行一个R会话,并能够从Python中运行R命令并返回结果。

  2. 另一种方法是在服务器上将R作为命令行脚本运行,查看Rscript以使其正常工作。该脚本可以基于若干个输入参数生成png图像。然后,Python可以获取该png图像并将其发送回给用户。

  3. 第三种选择是通过Rserve运行R,并创建连接以完成绘图。例如,请参见此处

解决方案3有点过度,但允许您在Django实例不同的服务器上使用R。解决方案1非常灵活,但更加复杂。最后,解决方案2是最简单的解决方案,但有时缺乏灵活性,特别是如果需要大量的R和Python交互。


你能演示一下我该如何用代码实现吗?这个答案对我帮助不大。 - Ravaal

1
如果您在R实例中安装了magick包,则可以使用以下方式将图像数据传回Python(我使用了更简单的绘图函数):rpy2
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()


你可以使用方法 here 在Django模板中呈现图像。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接