如何在Django网页中嵌入matplotlib图形?

19

请见谅,我对Django、Python和Web开发都非常新手。我的目标是展示使用matplotlib生成的图表。我曾经让首页自动重定向到图表的png文件(在浏览器中显示图表)。但现在我想要看到实际的首页,仅嵌入图表。换句话说,我想看到导航栏等元素以及网页主体中的图表。

目前,我已经进行了一些搜索,并大致知道如何实现这一目标。我的想法是创建一个专门返回图表的视图,然后从模板中使用img src标签访问此png图像以显示数据。

图表代码:

from django.shortcuts import render
import urllib
import json
from django.http import HttpResponse
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
import datetime as dt
import pdb

def index(request):
    stock_price_url = 'https://www.quandl.com/api/v3/datatables/WIKI/PRICES.json?ticker=GOOGL&date.gte=20151101&qopts.columns=date,close&api_key=KEY'

    date = []
    price = []

    #pdb.set_trace()
    source_code = urllib.request.urlopen(stock_price_url).read().decode()

    json_root = json.loads(source_code)
    json_datatable = json_root["datatable"]
    json_data = json_datatable["data"]

    for day in json_data:
        date.append(dt.datetime.strptime(day[0], '%Y-%m-%d'))
        price.append(day[1])

    fig=Figure()
    ax = fig.add_subplot(1,1,1)

    ax.plot(date, price, '-')

    ax.set_xlabel('Date')
    ax.set_ylabel('Price')
    ax.set_title("Google Stock")

    canvas = FigureCanvas(fig)
    response = HttpResponse(content_type='image/png')
    #canvas.print_png(response)
    return response

模板代码:

{% extends "home/header.html" %}
  {% block content %}
  <p>Search a stock to begin!</p>
  <img src="home/graph.py" />

  {% endblock %}

我现在得到的是:

当前页面


在此处找到了我的问题的答案:链接 - rigotre
请问您可以详细说明一下,在您给出的链接中我应该在哪里找到解决方案吗?谢谢 :) - sphoenix
2
@sphoenix 我已经有一段时间没有使用Django了,但我相信这是这里 - rigotre
5个回答

24

我知道这个问题标记为matplotlib,但我需要做相同的事情,我发现plotly更容易使用和视觉上更吸引人。你可以简单地绘制图形,然后在查看中获取图形的html代码:

# fig is plotly figure object and graph_div the html code for displaying the graph
graph_div = plotly.offline.plot(fig, auto_open = False, output_type="div")
# pass the div to the template

在模板中执行以下操作:

<div style="width:1000;height:100">
{{ graph_div|safe }}
</div>

9

当我在Django页面上呈现matplotlib图像时,我搜索了很久,直到找到了一个适合我的解决方案。通常情况下,只会打印出一个较长的字符串,而不是生成可视化图像。那么,最终对我有效的方法如下:

首先,导入以下内容:

import matplotlib.pyplot as plt
from io import StringIO
import numpy as np

返回一个图形的虚拟函数如下:

def return_graph():

    x = np.arange(0,np.pi*3,.1)
    y = np.sin(x)

    fig = plt.figure()
    plt.plot(x,y)

    imgdata = StringIO()
    fig.savefig(imgdata, format='svg')
    imgdata.seek(0)

    data = imgdata.getvalue()
    return data

可以通过调用 return_graph() 返回的图像,由其他函数进行呈现:

def home(request):
    context['graph'] = return_graph()
    return render(request, 'x/dashboard.html', context)

dashboard.html文件中,该图形是通过以下命令嵌入的:

{{ graph|safe }}

4

我认为您应该取消注释此行:

#canvas.print_png(response)

您可以使用Django HttpResponse轻松返回绘图,而不是使用一些额外的库。在matplotlib中,有一个FigureCanvasAgg,它为您提供了访问画布的权限,在画布上渲染绘图。最后,您可以将其简单地返回为HttpResonse。这里有一个非常基本的示例。

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_agg import FigureCanvasAgg
from django.http import HttpResponse

def plot(request):
    # Data for plotting
    t = np.arange(0.0, 2.0, 0.01)
    s = 1 + np.sin(2 * np.pi * t)

    fig, ax = plt.subplots()
    ax.plot(t, s)

    ax.set(xlabel='time (s)', ylabel='voltage (mV)',
           title='About as simple as it gets, folks')
    ax.grid()

    response = HttpResponse(content_type = 'image/png')
    canvas = FigureCanvasAgg(fig)
    canvas.print_png(response)
    return response

这是一个简单易懂的回答。我正在尝试与 OP 做同样的事情。我的视图指向一个模板,该模板执行一些操作以显示来自模型的数据,但我想知道如何将其合并到该视图中?最后我返回:"render(request, 'viewer.html', context),其中 context 是我传递给模板的对象 [context = {'modelObj': modelObj, 'displayFields': form}]。我如何在已经发送的 context 之外,也像上面那样发送图形呢?谢谢您的帮助。 - user20408
1
请注意,上面的示例可能会导致以下错误:"ValueError:fname必须是PathLike或文件句柄"。此问题解决了发生这种情况的一些原因:https://dev59.com/01UL5IYBdhLWcg3w88Ao - user535883

2

我的设置:

Django==2.2.2
windrose==1.6.8

我只是分享了一个我在网上找到的解决方案。我将其与windrose和django一起使用(感谢某些文章作者)。而且这个

import base64
import io
from matplotlib import pyplot as plt

flike = io.BytesIO()
plt.savefig(flike)
b64 = base64.b64encode(flike.getvalue()).decode()
return render(request, template_name='details_wind.html', context={'wind_rose': wind_rose_image})

在模板中,将其显示为图像:

<img src='data:image/png;base64,{{ wind_rose }}'>

0
如果您想将 matplotlib 图形嵌入到 django-admin 中,可以尝试使用 django-matplotlib 字段。该字段不会在数据库中创建列,但会呈现为常规字段。您无需自定义/子类化 admin.ModelAdmin,只需在您的模型中使用此字段并定义图形生成方式即可。

使用django-matplotlib,您可以在管理页面中呈现图形,但不能在视图中呈现-如果我错了,请纠正我。 - Domenico Spidy Tamburro

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