14

Im using python 3.4 and Django 1.8. I want to "print" a matplotlib result in a Django template. I reach this a few days ago, so I continue in other things of my Django App. Now, I dont know why, I was going to show the result to a friend, and my template with a matplotlib graph, now shows a big code! I dont know why this happen, because my view doesnt change in anything from when it was showing the right graph! Please help me!

This is my view!

from django.shortcuts import render
from matplotlib import pylab
from pylab import *
import PIL
import PIL.Image
import io
from io import *

def graphic(request):

pos = arange(10)+ 2 

barh(pos,(1,2,3,4,5,6,7,8,9,10),align = 'center')

yticks(pos,('#hcsm','#ukmedlibs','#ImmunoChat','#HCLDR','#ICTD2015','#hpmglobal','#BRCA','#BCSM','#BTSM','#OTalk'))

xlabel('Popularity')
ylabel('Hashtags')
title('Hashtags')
subplots_adjust(left=0.21)

buffer = io.BytesIO()
canvas = pylab.get_current_fig_manager().canvas
canvas.draw()
graphIMG = PIL.Image.fromstring('RGB', canvas.get_width_height(),               canvas.tostring_rgb())
graphIMG.save(buffer, "PNG")
content_type="Image/png"
buffercontent=buffer.getvalue()


graphic = (buffercontent ,content_type)
pylab.close()


return render(request, 'graphic.html',{'graphic':graphic})

Of course in my graphic.html is a variable called {{graphic}} inside a blockcontent!

This was showing the right result in my template! What happen? Now sometimes when i run my template it shows a big code, or just show me this django error:

Exception Value:
main thread is not in main loop

Exception Location: C:\Python34\lib\site-packages\matplotlib\backends\tkagg.py in blit, line 17

Help!

2
  • 2
    Try {{ graphic | safe }} Commented May 29, 2015 at 14:24
  • @lanAuld I make that change in my html template and it doesnt fix the problem! Thanks! Commented May 29, 2015 at 14:41

5 Answers 5

10
    from io import BytesIO
    import base64
    import matplotlib.pyplot as plt
    import numpy as np

    def graphic(request):

        pos = np.arange(10)+ 2 

        fig = plt.figure(figsize=(8, 3))
        ax = fig.add_subplot(111)

        ax.barh(pos, np.arange(1, 11), align='center')
        ax.set_yticks(pos)
        ax.set_yticklabels(('#hcsm',
            '#ukmedlibs',
            '#ImmunoChat',
            '#HCLDR',
            '#ICTD2015',
            '#hpmglobal',
            '#BRCA',
            '#BCSM',
            '#BTSM',
            '#OTalk',), 
            fontsize=15)
        ax.set_xticks([])
        ax.invert_yaxis()

        ax.set_xlabel('Popularity')
        ax.set_ylabel('Hashtags')
        ax.set_title('Hashtags')

        plt.tight_layout()

        buffer = BytesIO()
        plt.savefig(buffer, format='png')
        buffer.seek(0)
        image_png = buffer.getvalue()
        buffer.close()

        graphic = base64.b64encode(image_png)
        graphic = graphic.decode('utf-8')

        return render(request, 'graphic.html',{'graphic':graphic})

and in the template:

<img src="data:image/png;base64,{{ graphic|safe }}">

I have:

matplotlib==3.0.2 and Django==2.1.4

Sign up to request clarification or add additional context in comments.

Comments

6

Edit:

try with

graphic = cStringIO.StringIO()
canvas.print_png(graphic)
return render(request, 'graphic.html',{'graphic':graphic})

You have to specify that your image is a binary string:

<img src="data:image/png;base64,{{graphic|safe}}">

Or actually save it to the filesystem and provide the path.

Alternatively you could use Bokeh which can give you the html + javascript to embed the plot directly in the template, then it is dynamically generated and brings nice features.

16 Comments

I try to use: <img src="data:image/png;base64,{{graphic|safe}}"> and now i only get a broken image icon in my template! Im new in python, so i dont know i need to change in my view the render line to: return render(request, 'graphic.html',{'graphic|safe':graphic})
the |safe function is meant to be in the template :) Can you add the image html code in you answer please?
{% extends "base.html" %} {% block title %}Index{% endblock %} {% block subtitle %}<H2>blablabla</H2>{% endblock %} {% block graphic %} <img src="data:image/PNG;base64,{{graphic|safe}}"> {% endblock %}
When my code stops working, i was working in the settings of django static files, does this could be the reason of my problem?
ah ok, so you were saving it to the filesystem before. So yes you could also save it somewhere and make sure the directory is in the static files path. Or checkout my edit to display it inline.
|
3

The final solution was to create a special view that returns the matplotlib plot in an empty template, like this:

def grafico (rquest):
    pos = arange(10)+ 2 

    barh(pos,(1,2,3,4,5,6,7,8,9,10),align = 'center')

    yticks(pos,('#hcsm','#ukmedlibs','#ImmunoChat','#HCLDR','#ICTD2015','#hpmglobal','#BRCA','#BCSM','#BTSM','#OTalk'))

    xlabel('Popularidad')
    ylabel('Hashtags')
    title('Gráfico de Hashtags')
    subplots_adjust(left=0.21)

    buffer = io.BytesIO()
    canvas = pylab.get_current_fig_manager().canvas
    canvas.draw()
    graphIMG = PIL.Image.fromstring('RGB', canvas.get_width_height(), canvas.tostring_rgb())
    graphIMG.save(buffer, "PNG")
    pylab.close()

    return HttpResponse (buffer.getvalue(), content_type="Image/png")

The next step is to put in your template this:

<img src="url_of_the_graphic_view">

And thats all!

1 Comment

That way you can show only 1 plot per page... right? :(
1
def show(request):

x = np.arange(10)
y = x
fig = plt.figure()
plt.plot(x, y)
canvas = fig.canvas
buf, size = canvas.print_to_buffer()
image = Image.frombuffer('RGBA', size, buf, 'raw', 'RGBA', 0, 1)
buffer=io.BytesIO()
image.save(buffer,'PNG')
graphic = buffer.getvalue()
graphic = base64.b64encode(graphic)
buffer.close()
return render(request, 'graphic.html',{'graphic':graphic})

2 Comments

Please try to avoid just dumping code as an answer and try to explain what it does and why. Your code might not be obvious for people who do not have the relevant coding experience. Please edit your answer to include clarification, context and try to mention any limitations, assumptions or simplifications in your answer.
sorry. try with "graphic = base64.b64encode(graphic)",encode graphic in base64. then the PNG can decoded in templates.
1

I had a broken icon image as well, after using the answers above, and I fixed it by removing the b' and ' from the graphic base64 binary representation :

return render(request, 'graphic.html', {'graphic': str(graphic)[2:-1]})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.