Django matplotlib: fname must be a PathLike or file handle - django

I am trying to display a plot with matplotlib and django following this and this questions, however it seems not working, I tried both solutions and only while using IO i get an empty canvas, but when I try to plot a 'real' plot I get the error in the title.
This is my view:
import django
from matplotlib.backends.backend_agg import FigureCanvasAgg as
FigureCanvas
from matplotlib.figure import Figure
import numpy as np
import matplotlib.pyplot as plt
import io
def mplimage(request):
fig = Figure()
canvas = FigureCanvas(fig)
x = np.arange(-2, 1.5, .01)
y = np.sin(np.exp(2 * x))
plt.plot(x, y)
buf = io.BytesIO()
plt.savefig(buf, format='png')
plt.close(fig)
response = django.http.HttpResponse(content_type='image/png')
canvas.print_png(response)
return response
and here the link in urls.py:
import mpl.views
url(r'mplimage.png', mpl.views.mplimage)

This works if you save the file objects as JPEG (requires PIL) instead of PNG using print_jpg() method instead of print_png().
Change:
response = django.http.HttpResponse(content_type='image/png')
canvas.print_png(response)
To:
response = HttpResponse(content_type='image/jpg')
canvas.print_jpg(response)

from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
import numpy as np
import django
def showimage(request):
fig = Figure()
canvas = FigureCanvas(fig)
ax = fig.add_subplot(111)
x = np.arange(-2,1.5,.01)
y = np.sin(np.exp(2*x))
ax.plot(x, y)
response = HttpResponse(content_type='image/jpg')
canvas.print_jpg(response)
return response

Related

Django: embedding image in template

I need an image to be displayed within my webpage. The image is stored within a variable in views.py.
Most solutions such as the one below use HttpResponse to output images but I want the image to be embedded within my html template.
from django.http import HttpResponse
def my_image(request):
image_data = open("/path/to/my/image.png", "rb").read()
PS. I am getting the image by using matplotlib to create the image. So I cannot use a static folder. Example code given below (credit:this)
import sys
from django.http import HttpResponse
import matplotlib as mpl
mpl.use('Agg') # Required to redirect locally
import matplotlib.pyplot as plt
import numpy as np
from numpy.random import rand
try:
# Python 2
import cStringIO
except ImportError:
# Python 3
import io
def get_image(request):
"""
This is an example script from the Matplotlib website, just to show
a working sample >>>
"""
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2 # 0 to 15 point radiuses
plt.scatter(x, y, s=area, c=colors, alpha=0.5)
"""
Now the redirect into the cStringIO or BytesIO object >>>
"""
if cStringIO in sys.modules:
f = cStringIO.StringIO() # Python 2
else:
f = io.BytesIO() # Python 3
plt.savefig(f, format="png", facecolor=(0.95,0.95,0.95))
plt.clf()
"""
Add the contents of the StringIO or BytesIO object to the response, matching the
mime type with the plot format (in this case, PNG) and return >>>
"""
return HttpResponse(f.getvalue(), content_type="image/png")
return HttpResponse(image_data, content_type="image/png")
Save the image in the media directory and then use ajax to update the div
something like
def get_image(request):
"""
This is an example script from the Matplotlib website, just to show
a working sample >>>
"""
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2 # 0 to 15 point radiuses
plt.scatter(x, y, s=area, c=colors, alpha=0.5)
filepath = os.path.join(settings.MEDIA_PATH,'/name_of_the_file.png')
plt.savefig(filepath, facecolor=(0.95,0.95,0.95))
plt.clf()
return HttpResponse(filepath)
then go to the function with ajax request
$.ajax({ type: "POST",
url: 'THE URL TO THE FUNCTION',
data: {
csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val(),
},
success: function(response){
$('#your_div_id').html("<img src=\""+responce+"\"></img>")
}
});

How to make tabular legend using matplotlib and python

I am plotting a choropleth map in python from a shapefile and i want to customize the legend of the plot, i am using the code bellow:
import pandas as pd
import pysal as ps
import geopandas as gp
import numpy as np
import matplotlib.pyplot as plt
pth = 'outcom.shp'
tracts = gp.GeoDataFrame.from_file(pth)
ax = plot_dataframe(tracts, column='Density', scheme='QUANTILES', k=4, colormap=plt.cm.Blues, legend=True)
plt.show()
Besides, i am using a small patch that i found here http://nbviewer.ipython.org/gist/jorisvandenbossche/d4e6efedfa1e4e91ab65 in order to visualize the legend.
here's my result :
But, i need something similar to this :
so my question now, is how can i have a customized legend
You may use a plt.table as a legend.
import matplotlib.pyplot as plt
import numpy as np
valeur = np.array([.1,.45,.7])
text=[["Faible","Ng<1,5" ],["Moyenne","1,5<Ng<2,5"],[u"Elevée", "Ng>2,5"]]
colLabels = ["Exposition", u"Densité"]
tab=plt.table(cellText=text, colLabels=colLabels,
colWidths = [0.2,0.2], loc='lower right',
cellColours=plt.cm.hot_r(np.c_[valeur,valeur]))
plt.show()
In order to link this table to a contourf plot, you may do as follows:
from matplotlib import pyplot as plt
import numpy as np
a = np.sort(np.random.rand(100)).reshape(10,10)*4
levels = np.array([0,1.5,2.5,4])
sm = plt.contourf(a, levels = levels, cmap=plt.cm.hot_r )
text=[["Faible","Ng<1,5" ],["Moyenne","1,5<Ng<2,5"],[u"Elevée", "Ng>2,5"]]
colLabels = ["Exposition", u"Densité"]
col = levels[:-1] + np.diff(levels)/2.
cellcol = sm.cmap(sm.norm(np.c_[col,col]))
tax = plt.gcf().add_axes([0,0,1,1])
tab=tax.table(cellText=text, colLabels=colLabels,
colWidths = [0.2,0.2], loc='lower left',
cellColours=cellcol )
tax.axis("off")
plt.show()

Python 2.7 Value Error : need more than 2 values to unpack

I have Python 2.7 Win 32 and have installed Matplotlib, Numpy, PyParsing, Dateutil. In IDLE I place in the code:
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import matplotlib.dates as mdates
import numpy as np
def graphRawFX () :
date,bid,ask = np.loadtxt,unpack=True,('GPBUSD1d.txt')
delimiter=',',
converters={0:mdates.strpdate2num('%Y%m%d%H%M%S') }
fig = plt.figure(figsize=(10,7))
ax1 = plt.subplot2grid((40,40), (0,0), rowspan=40, colspan=40)
ax1.plot(date,bid)
ax1.plot(date,ask)
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d %H:%M:%S'))
plt.grid(True)
plt.show()
there are three variable but only two values given
date,bid,ask = np.loadtxt,unpack=True,('GPBUSD1d.txt')
you probably need to change that line to :
date=mdates.strpdate2num('%Y%m%d%H%M%S')
bid,ask = np.loadtxt,unpack=True,('GPBUSD1d.txt')

Python 2.7 NameError: name 'ax1' is not defined

I have Python 2.7 Win 32 and have installed Matplotlib, Numpy, PyParsing, Dateutil. In IDLE I place in the following code:
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import matplotlib.dates as mdates
import numpy as np
def graphRawFX () :
date=mdates.strpdate2num('%Y%m%d%H%M%S')
bid, ask = np.loadtxt('GPBUSD1d.txt', unpack=True)
delimiter=',',
converters={0:mdates.strpdate2num('%Y%m%d%H%M%S') }
fig = plt.figure(figsize=(10,7))
ax1 = plt.subplot2grid((40,40), (0,0), rowspan=40, colspan=40)
ax1.plot(date,bid)
ax1.plot(date,ask)
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d %H:%M:%S'))
plt.grid(True)
plt.show()
Running the code results in to the following:
Traceback (most recent call last):
File "C:/Users/Emanuel/Desktop/test.py", line 18, in <module>
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d %H:%M:%S'))
NameError: name 'ax1' is not defined
Any suggestion to editing the code would be helpful.
This is because you are calling ax1 outside the method in which it has been defined it. Perhaps you should include that line in the method as well.
or else:
You can create the ax1 object outside the method and then change some of its attributes as necessary in your function by using global ax1
EDIT: It should look something like this:
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import matplotlib.dates as mdates
import numpy as np
ax1 = plt.subplot2grid((40,40), (0,0), rowspan=40, colspan=40)
def graphRawFX (axes1) :
date=mdates.strpdate2num('%Y%m%d%H%M%S')
bid, ask = np.loadtxt('GPBUSD1d.txt', unpack=True)
delimiter=',',
converters={0:mdates.strpdate2num('%Y%m%d%H%M%S') }
fig = plt.figure(figsize=(10,7))
axes1.plot(date,bid)
axes1.plot(date,ask)
graphRawFX(ax1)
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d %H:%M:%S'))
plt.grid(True)
plt.show()

how to output horizontal barchart to django site page

I tried an examle in a django views.py:
import numpy as np
import matplotlib.pyplot as plt
N=3
Data = (1,2,9)
ind = np.arrange(N)
width = 0.35
p1 = plt.bar(ind, Data, width, color='r')
what i dont know - how to direc this to the page in django site.
Shall i use plt.show() or try to create buffer for png object?
sorry for this ...
This is what you are looking for :
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
import matplotlib.pyplot as plt
import django
def plot(request):
plt.plot()
canvas = FigureCanvas(plt.figure(1))
response=django.http.HttpResponse(content_type='image/png')
canvas.print_png(response)
return response
I have no tested that, but could work. You have to use the backend_agg for printing a canvas as png format, to be handle as a mimetype image/png file.
The better approach seems to be write a view to output the chars.
The view would be this:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
from django.http import HttpResponse
def bar_chart(request):
if request.GET.get('data', False):
data = (1,2,9)
else:
if type(request.GET['data']) == list():
data = request.GET['data']
chart = plt.bar(np.arange(3), data, 0.35, color='r')
canvas = FigureCanvas(chart)
response = HttpResponse(content_type='image/png')
canvas.print_png(response)
return response
# inside urls.py
#
# url(r'^charts/bar_chart.png$', 'myapp.views.charts.simple', name="bar_chart"),
And in your templates you can use this way:
<h1>My Bar Char</h1>
<img src="{% url bar_chart %}?data=[10,20,40,50,30,50]" />
This will render:
<h1>My Bar Char</h1>
<img src="/charts/bar_chart.png?data=[10,20,40,50,30,50]" />
I hope you can test it and complete this answer.