Matplotlib into a Django Template - python

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!

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

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.

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!

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

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]})

Related

How to display image in django using HttpResponse

I am trying to display the image of python script output using below lines but instead of displaying in browser, code downloading the file instead of displaying
this is the function i have created in views.py:
def adc(request):
file = "C:\Users\TheBoss\Downloads\New_test.xlsx"
df = pd.read_excel(file, sheet_name='Graph')
plt.plot(df['Date'], df['Video Device - Not Responding'], label = 'Video Device - Not Responding')
#plt.plot(df['Date'], df['30th Apr'], 'b', label = '30-Apr')
plt.xticks(rotation=45)
plt.tick_params(axis='x', which='major', labelsize=6)
# naming the y axis
plt.ylabel('Condition Count')
# giving a title to my graph
plt.title('Condition')
# function to show the plot
plt.legend()
#plt.show()
plt.savefig('C:\\Users\\TheBoss\\Downloads\\test.png')
image_data = open("C:\\Users\\TheBoss\\Downloads\\test.png", "rb").read()
return HttpResponse(image_data, content_type="test/png")
Generally, this should be enough to display image inline.
def adc(request):
file = "C:\Users\TheBoss\Downloads\New_test.xlsx"
df = pd.read_excel(file, sheet_name='Graph')
plt.plot(df['Date'], df['Video Device - Not Responding'], label = 'Video Device - Not Responding')
plt.xticks(rotation=45)
plt.tick_params(axis='x', which='major', labelsize=6)
plt.ylabel('Condition Count')
plt.title('Condition')
plt.legend()
buffer = io.BytesIO()
plt.savefig(buffer, format='png')
return HttpResponse(buffer.getvalue(), content_type="test/png")
It should display as an image in most browsers and if you want to insert the image in HTML, you'd use a simple
<img src="{% url 'my_image' %}">
I know from experience that this works in Edge, Firefox and Opera. Sometimes browsers need additional convincing to display image inline and in those cases setting the header Content-Disposition to inline usually works.

give a bytes to reportlab.lib.utils.ImageReader

I have read that you can use a bytes like object to reportlab.lib.utils.ImageReader(). If I read in a file path it works fine, but I want to use a byte like object instead that way I can save the plot I want in memory, and not have to constantly be saving updated plots on the drive.
This is where I found the code to convert the image into a string
https://www.programcreek.com/2013/09/convert-image-to-string-in-python/
This is an example of how to use BytesIO as input for ImageReader()
How to draw image from raw bytes using ReportLab?
This class is used to make a plot and pass in a save it to memory with BytesIO(). string is the value I'm going to pass later
#imports
import PyPDF2
from io import BytesIO
from reportlab.lib import utils
from reportlab.lib.pagesizes import landscape, letter
from reportlab.platypus import (Image, SimpleDocTemplate,
Paragraph, Spacer)
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch, mm
import datetime
import os
import csv
import io
import base64
import urllib
from django.contrib import admin
from django.forms import model_to_dict
from django.http import HttpResponse
from django.urls import path
from django.views.decorators.csrf import csrf_protect
from django.utils.decorators import method_decorator
from reporting import models, functions, functions2
import matplotlib
matplotlib.use('agg')
from matplotlib import pyplot as plt
import numpy as np
def make_plot(data):
items = [tuple(item) for item in data.items()]
keys = [item[0] for item in items]
vals = [item[1] for item in items]
fig, ax = plt.subplots()
ind = np.arange(len(keys)) # the x locations for the groups
width = 0.35 # the width of the bars
rects1 = ax.bar(ind - width/2, vals, width)
ax.set_ylabel('Count')
ax.set_xticks(ind)
ax.set_xticklabels(keys)
buf = io.BytesIO()
fig.savefig(buf, format='png')
buf.seek(0)
string = base64.b64encode(buf.read())
return 'data:image/png;base64,' + urllib.parse.quote(string), string
This is the minimum code to show how the information is moved to where the error occurs.
class ProgressReportAdmin(ReadOnlyAdmin):
current_extra_context = None
#csrf_protect_m
def changelist_view(self, request, extra_context=None):
plot = make_plot(data)
self.current_extra_context = plot[1]
def export(self, request):
image = self.current_extra_context
pdf = functions.LandscapeMaker(image, fname, rotate=True)
pdf.save()
This is where the error occurs, in the scaleImage function
class LandscapeMaker(object):
def __init__(self, image_path, filename, rotate=False):
self.pdf_file = os.path.join('.', 'media', filename)
self.logo_path = image_path
self.story = [Spacer(0, 1*inch)]
def save(self):
fileObj = BytesIO()
self.doc = SimpleDocTemplate(fileObj, pagesize=letter,
leftMargin=1*inch)
self.doc.build(self.story,
onFirstPage=self.create_pdf)
def create_pdf(self, canvas, doc):
logo = self.scaleImage(self.logo_path)
def scaleImage(self, img_path, maxSize=None):
#Error1 occurs on
img = utils.ImageReader(img_path)
img.fp.close()
#Error2
#image = BytesIO(img_path)
#img = utils.ImageReader(image)
#img.fp.close()
For Error1 I receive:
raise IOError('Cannot open resource "%s"' % name)
img = utils.ImageReader(img_path)
"OSError: Cannot open resource "b'iVBORw0KGgoAAA' etc.,
For Error2 I receive
OSError: cannot identify image file <_io.BytesIO object at 0x7f8e4057bc50>
cannot identify image file <_io.BytesIO object at 0x7f8e4057bc50>
fileName=<_io.BytesIO object at 0x7f8e4057bc50> identity=[ImageReader#0x7f8e43fd15c0]
I think you have to pass buff to ImageReader somehow.
I'm using this function to save and draw the figures I generate with matplotlib and it works perfectly for me.
seek(offset, whence=SEEK_SET) Change the stream position to the given offset. Behaviour depends on the whence parameter. The default value for whence is SEEK_SET.
getvalue() doesn't work except the seek(0)
def save_and_draw(fig, x_img, y_img, width_img=width_img, height_img=height_img):
imgdata = BytesIO()
fig.savefig(imgdata, format='png')
imgdata.seek(0)
imgdata = ImageReader(imgdata)
self.c.drawImage(imgdata, x_img, y_img, width_img, height_img)
plt.close(fig)

How to access graph which is present in views.py file into html templates in django

I have a views.py file as follows
def showimage(request):
# Construct the graph
t = arange(0.0, 2.0, 0.01)
s = sin(2*pi*t)
plot(t, s, linewidth=1.0)
xlabel('time (s)')
ylabel('voltage (mV)')
title('About as simple as it gets, folks')
grid(True)
buffer = StringIO.StringIO()
canvas = pylab.get_current_fig_manager().canvas
canvas.draw()
pilImage = PIL.Image.frombytes("RGB", canvas.get_width_height(), canvas.tostring_rgb())
pilImage.save(buffer, "PNG")
pylab.close()
Could you please help me to pass that graph into the html page?
It looks like you copied your code directly from https://www.eriksmistad.no/making-charts-and-outputing-them-as-images-to-the-browser-in-django/ but without the imports and definition.
You also left off the ending:
# Send buffer in a http response the the browser with the mime type image/png set
return HttpResponse(buffer.getvalue(), content_type="image/png")
But I wouldn't put this directly in my views.

from flask, how to send the matplotlib plot image to html?

In flask, how can I make the image saved from plt in matplotlib show up on a webpage? The below python code creates a plot and saves it as a .png image. The HTML file also follows. When I ran it I ended up with the error saying:
TypeError: expected str, bytes or os.PathLike object, not NoneType.
Anyone who can help me please show me what to do.
#app.route('/images/<air_quality>')
def images(air_quality):
return render_template("displaygraph.html", title=air_quality)
#app.route('/fig/<air_quality>')
def fig(air_quality):
import matplotlib.pyplot as plt
import numpy as np
from io import BytesIO
img = BytesIO()
pm10 = np.array(['23', '45', '56', '12'])
pm25 = np.array(['34', '56', '59', '34'])
dates = np.array(['2017-12-20', '2017-12-21', '2017-12-22', '2017-12-23'])
plt.figure(figsize=(12, 8), dpi=100, facecolor='1.0')
plt.title("GangNam", fontsize=20)
plt.plot_date(dates, pm10, 'rs--', label='pm10')
plt.plot_date(dates, pm25, 'gs--', label='pm25')
plt.legend()
img = plt.savefig('img.png')
return send_file(img, mimetype='image/png')
I do not how to display HTML file here. But the file has this inside the img tag:
src="{{url_for('fig', air_quality = title)}}
You can save pylab figure into in-memory file like BytesIO(py3), StringIO(py2).
plt.savefig(img, format='png')
img.seek(0)
response=make_response(img.getvalue())
response.headers['Content-Type'] = 'image/png'
img.close()
return response

Create a graph from a CSV file and render to browser with Django and the Pandas Python library

I'm learning how to use the Django framework for a work project that will allow users to load files in various formats (at the moment I am only dealing with CSV files), graph that data using Pandas, and display that data back to the user via a Django template. I haven't had any problems creating the graph in iPython, but have been struggling with getting it to an HTML Django template.
I've followed the following example from matplotlib:
# graph input file
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.dates import DateFormatter
def graph(request):
fig = Figure()
ax = fig.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'))
fig.autofmt_xdate()
canvas = FigureCanvas(fig)
response = HttpResponse( content_type = 'image/png')
canvas.print_png(response)
return response
The above example works great and I can see it in a template, but that's just a graph with hard-coded values.
I've attempted to use Pandas because of its seemingly simplistic syntax and my attempts in Django are as follows:
# graph input file
import pandas as pd
from pandas import DataFrame
def graph(request):
data_df = pd.read_csv("C:/Users/vut46744/Desktop/graphite_project/sampleCSV.csv")
data_df = pd.DataFrame(dataArray)
data_df.plot()
response = HttpResponse( content_type = 'image/png')
return response
In Django calling the .plot() displays the graph fine, but displays a blank page to the HTML template. I've also tried using Numpy's genfromtxt() and loadtxt(), but to no avail. Also, my Google searches have not been fruitful either.
Any help or suggestion would be great. If you know of a better alternative to Pandas then I am willing to try other options.
Haven't tried this yet, but I would attack it something like:
def graph(request):
fig = Figure()
ax = fig.add_subplot(111)
data_df = pd.read_csv("C:/Users/vut46744/Desktop/graphite_project/sampleCSV.csv")
data_df = pd.DataFrame(data_df)
data_df.plot(ax=ax)
canvas = FigureCanvas(fig)
response = HttpResponse(content_type='image/png')
canvas.print_png(response)
return response

Categories

Resources