django使用matplotlib绘统计图
毕业设计需要用matplotlib画图,记录一下学习过程吧。之前已经记录过关于matplotlib的安装和使用。这次将要在django里的views函数中使用。完整的代码在https://github.com/PegasusWang/Physics_web.git,顺便再熟悉下git的使用吧。
###简介
挺简单的一个小项目,首先在安卓端设计登录和注册窗口,以及题目显示Activity,安卓的后台用的是django,获取题目信息用get方法,用django返回json格式的数据。登录和注册用post发送用户名和密码,然后在views函数中验证。用户提交题目答案后,在web端接收后更新数据库,之后用matplotlib绘制答案统计图。
###设计matplotlibUtil模块
我需要用到俩种图,一种是柱状图(histogram),一种是饼图(pie chart),之前写过如何参考官方demo修改成自己需要的格式。为了方便就把这两个函数写进去一个python文件里:matplotlibUtil.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Bar chart demo with pairs of bars grouped for easy comparison.
"""
import numpy as np
import matplotlib as mpl
mpl.use('Agg') # for backend without gui
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # set default font for mac
def draw_histogram(a_num, b_num, c_num, d_num, n_groups, path):
"""Draw result.
:param a_num: tuple of select A users.
eg: (12, 2, 34, 12, 78, 13).
:param n_groups: The length of tuple a_num.
:param path: The path images would save.
"""
fig, ax = plt.subplots()
index = np.arange(n_groups)
bar_width = 0.2
opacity = 0.4
error_config = {'ecolor': '0.3'}
rects1 = plt.bar(index, a_num, bar_width,
alpha=opacity,
color='b',
error_kw=error_config,
label='A')
rects2 = plt.bar(index + bar_width, b_num, bar_width,
alpha=opacity,
color='r',
error_kw=error_config,
label='B')
rects3 = plt.bar(index+bar_width*2, c_num, bar_width,
alpha=opacity,
color='b',
error_kw=error_config,
label='C')
rects4 = plt.bar(index+bar_width*3, d_num, bar_width,
alpha=opacity,
color='g',
error_kw=error_config,
label='D')
def autolabel(rects):
# attach some text labels
for rect in rects:
height = rect.get_height()
ax.text(rect.get_x()+rect.get_width()/2.0, 1.05*height,
'%d'%int(height), ha='center', va='bottom')
autolabel(rects1)
autolabel(rects2)
autolabel(rects3)
autolabel(rects4)
plt.xlabel(u'题号')
plt.ylabel(u'人数')
plt.title(u'答题结果统计')
#plt.xticks(index + bar_width, ('1', '2', '3', '4', '5', '6'))
plt.xticks(index + bar_width, tuple(map(str, range(1, n_groups+1))))
ax.set_ybound(0, 40)
plt.tight_layout()
#plt.show()
plt.savefig(path)
plt.clf() # note: remember plt.clf() to clear buffer
plt.close()
def draw_piechart(question_info, explode, path):
"""Draw pie chart of each question.
:param: question_info is a list of users. eg: [12, 23, 43, 13]
means 12 people select A, 23 select B, 43 C, 13 D.
"""
labels = 'A', 'B', 'C', 'D'
colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']
#explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs')
plt.pie(question_info, explode=explode, labels=labels, colors=colors,
autopct='%1.1f%%', shadow=True)
# Set aspect ratio to be equal so that pie is drawn as a circle.
plt.axis('equal')
#plt.show()
plt.savefig(path)
plt.clf() # note: remember plt.clf() to clear buffer
plt.close()
已经把函数封装成了需要的形式,现在开始在views里边使用。
###在views函数中绘图
现在有了绘图模块就可以在views.py中直接调用了。
def show_result(request):
"""draw result image"""
import matplotlibUtil
from mysite.settings import MEDIA_ROOT
# draw histogram
n_groups = Question.objects.all().count()
options = ('A', 'B', 'C', 'D')
nums = []
for option in options:
num = []
for tid in range(1, n_groups + 1):
cnt = Result.objects.filter(t_id=tid, my_option=option).count()
num.append(cnt)
nums.append(num)
histogram_path = MEDIA_ROOT + 'images/results/' + '0.png'
print histogram_path
try:
matplotlibUtil.draw_histogram(nums[0], nums[1], nums[2], nums[3],
n_groups, histogram_path)
except:
return render(request, 'physics/result_image.html', {'images': None})
# draw pie chart
for tid in range(1, n_groups+1):
explode = [0.0, 0.0, 0.0, 0.0]
answer_num = ord(Question.objects.get(t_id=tid).t_answer.upper()) - ord('A')
explode[answer_num] = 0.1
explode = tuple(explode)
question_info = []
for each in options:
cnt = Result.objects.filter(t_id=tid, my_option=each).count()
question_info.append(cnt)
chart_path = MEDIA_ROOT + 'images/results/' + str(tid) + '.png'
print chart_path
try:
matplotlibUtil.draw_piechart(question_info, explode, chart_path)
except:
return render(request, 'physics/result_image.html', {'images': None})
images = []
for i in range(n_groups+1):
images.append('/media/images/results/'+str(i)+'.png')
return render(request, 'physics/result_image.html',
{'images': images})
然后就是模板中使用了,直接引用就可以了。我用的是一个模板自己改了一下。
最后的效果如下: