2

I'm trying to build a web app which shows the user the variation of his weight over time. Therefore I'm trying to plot a line graph. I want to make use of matplotlib or a similar library inside my views file to plot the graph.
This answer explains how the graph can be plotted through Django views.

My code in views.py file looks like this:(no need to read in detail, it's working fine)

from django.shortcuts import render, HttpResponseRedirect, HttpResponse
from .forms import DiabetesForm
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib as plt
from matplotlib.dates import DateFormatter
import datetime
import random
import io


def mplimage(request):
    f = Figure()
    ax = f.add_subplot(111)
    x = []
    y = []
    now = datetime.datetime.now()
    delta = datetime.timedelta(days=1)
    for i in range(10):
        x.append(now)
        now += delta
        y.append(random.randint(0, 1000))
    ax.plot_date(x, y, '-')
    ax.xaxis.set_major_formatter(DateFormatter('%Y-%m-%d'))
    f.autofmt_xdate()

    buf = io.BytesIO()
    canvas = FigureCanvas(f)
    canvas.print_png(buf)
    response=HttpResponse(buf.getvalue(),content_type='image/png')
    # if required clear the figure for reuse
    f.clear()
    # I recommend to add Content-Length for Django
    response['Content-Length'] = str(len(response.content))
    #
    return response

And the code in urls.py is:

from django.urls import path, include
from . import views
urlpatterns = [
    path('', views.mplimage, name='home'),

]

However, this code shows only the plotted image( that was generated in views.py file ) in the HTML page.
What I want:
I want to pass the generated image and the template name together in the render function so that apart from the image I can other information/content written as well.

In other words, I want to make use of the passed image in my HTML page which can hold other content too.

Any other method through which I can do the job will also be highly appreciated.

Edit: I don't know much of javascript, so please don't give answers related to javascript unless there's no other method.

Edit2:Here the updated and working code as suggested by @Mikhail (second method):

from django.shortcuts import render, HttpResponseRedirect, HttpResponse
from .forms import DiabetesForm
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib as plt
from matplotlib.dates import DateFormatter
import datetime
import random
import io
import base64


def mplimage(request):
    f = Figure()
    ax = f.add_subplot(111)
    x = []
    y = []
    now = datetime.datetime.now()
    delta = datetime.timedelta(days=1)
    for i in range(10):
        x.append(now)
        now += delta
        y.append(random.randint(0, 1000))
    ax.plot_date(x, y, '-')
    ax.xaxis.set_major_formatter(DateFormatter('%Y-%m-%d'))
    f.autofmt_xdate()

    buf = io.BytesIO()
    canvas = FigureCanvas(f)
    canvas.print_png(buf)
    response=HttpResponse(buf.getvalue(),content_type='image/png')
    # if required clear the figure for reuse
    img_str = base64.b64encode(buf.getvalue())
    data_url = 'data:image/jpg;base64,' + base64.b64encode(buf.getvalue()).decode()
    f.clear()
    # I recommend to add Content-Length for Django
    #response['Content-Length'] = str(len(response.content))
    #
    #return response
    return render(request, "display.html", {'image': data_url })

Here's the display.html file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Display</title>
</head>
<body>
    <img src="{{ image }}" alt=""/>
    <h1>Write whatever you want</h1>
</body>
</html>
falcon lover
  • 87
  • 4
  • 12

1 Answers1

4

What you want is to embed the image in an HTML page.

I see two options here:

  1. Load the image separately:
    With this option you will create two Django views. One will render the image, and the other will render the HTML content with an <img> tag referring to the image. The user will thus open the HTML url and see the image there.

  2. Return the HTML page with the image embedded as a data: URL:
    You will need to convert your image from a bytestring (buf.getvalue() in your code) into a base64 string and construct a URL of form data:image/png;base64,YOUR_IMAGE_BASE64_CONTENT, and then add an <img> tag with src set to the constructed URL.

Mikhail Burshteyn
  • 4,762
  • 14
  • 27
  • Hey, I'm not sure how to use two views to render HTML and image separately. Does the first point mean that I will have to plot the image using the first view, store it somewhere and then use the tag to render it? Or does it mean something else? I want to avoid storing the image. I'm probably misunderstanding the first point so could you please explain it a bit more? – falcon lover Mar 04 '19 at 17:31
  • Hey, the second method worked for me ;). Thank you for the help @Mikhail. But I'm still curious about the first method. – falcon lover Mar 04 '19 at 17:49