您好,登錄后才能下訂單哦!
本篇文章為大家展示了怎么在Django中利用Highcharts 實現數據可視化,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
開發環境
使用 Python 2.7.14,django 1.11.8,highcharts 4.0.1
直接命令行輸入以下語句,即可安裝django 1.11.8
。
pip install django==1.11.8
至于Highcharts
,可以去官網下載。我用的是之前前輩給的模板,js不是太懂,所以基本沒改,只是為了方便進行拓展,對功能模塊進行了注釋。
開發需求
手頭已有爬取的winstore不同app,不同榜單,不同地區的多天rank數據。這些rank數據存放在MySQL服務器中,庫名為winstore,表名為winstore_rank。
現在需要將這些rank數據用折線圖的方式展示出來。同時在網頁上需要可以根據選擇的日期,地區,榜單來動態產生折線圖。
問題解析
根據開發需求,可以將這次任務分為三個部分。
前端頁面
a. ajax動態獲取地區列表、榜單列表,生成對應的下拉列表,必要時需將傳統下拉列表轉換成多選下拉列表
b. 根據搜索結果,將符合條件的app的rank添加到折線圖中
服務器端
a. 接受前端的請求,與數據庫通信,返回所請求數據
MySQL數據庫
a. 根據服務器端傳輸的sql語句進行對應的查詢
根據上述的分析,前端肯定是js + jQuery + Echarts + jquery.multiselect
了,服務器端采用Django,數據庫方面Django有對應的驅動模塊,不用管。
1. 前端頁面
新建一個文件rank.html
,內容如下:
<head> {% load static %} <script type="text/javascript" src="{% static 'js/jquery.min.js' %}"></script> <script type="text/javascript" src="{% static 'js/highcharts.js' %}"></script> <script type="text/javascript" src="{% static 'js/jquery-ui.min.js' %}"></script> <script type="text/javascript" src="{% static 'js/exporting.js' %}"></script> <script type="text/javascript" src="{% static 'js/jquery.multiselect.min.js' %}"></script> <link rel="stylesheet" href="{% static 'css/jquery-ui.min.css' %}" rel="external nofollow" > <link rel="stylesheet" href="{% static 'css/jquery.multiselect.css' %}" rel="external nofollow" > <link rel="stylesheet" href="{% static 'css/screen1.css' %}" rel="external nofollow" > <style type="text/css"> #set-content ul li #chart { width: 60px; font-size: 12px; height: 22px; } </style> <script type="text/javascript"> // 設定開始日期和結束日期,默認為最近10天 $(function() { $("#beginDate").datepicker({dateFormat: "yy-mm-dd"}); $("#endDate").datepicker({dateFormat: "yy-mm-dd"}); var dateNow = new Date(); var str_dateNow = dateNow.getFullYear() + "-" + (dateNow.getMonth() + 1) + "-" + dateNow.getDate(); var dateBegin = new Date(dateNow - 10 * 1000 * 3600 * 24); var str_dateBegin = dateBegin.getFullYear() + "-" + (dateBegin.getMonth() + 1) + "-" + dateBegin.getDate(); $("#beginDate").datepicker("setDate", str_dateBegin); $("#endDate").datepicker("setDate", str_dateNow); }); // 動態獲取數據庫中region數據,填充入下拉列表 $(function() { $.get("/getWinstoreRegions", {"limit": "0"}, function(regionsDict) { for (var id in regionsDict) { regionOption = "<option value='" + id + "'>" + regionsDict[id] + "</option>"; $("#region").append(regionOption); } }, "json" ) }); // 動態獲取數據庫中chart數據,填充入下拉列表 $(function() { $.get("/getWinstoreCharts", {"limit": "0"}, function(chartsDict) { for (var id in chartsDict) { chartOption = "<option value='" + id + "'>" + chartsDict[id] + "</option>"; $("#chart").append(chartOption); } }, "json" ) }); // 動態獲取數據庫中category數據,填充入下拉列表 $(function() { $.get("/getWinstoreCategories", {"limit": "0"}, function(categoriesDict) { for (var id in categoriesDict) { categoryOption = "<option value='" + id + "'>" + categoriesDict[id] + "</option>"; $("#category").append(categoryOption); } }, "json" ) }); // 動態獲取數據庫中app名字,填充入下拉列表 $(function() { $.get( "/getWinstoreApps", {"limit":"0",}, function(dataDict) { // 循環添加下拉列表的option for (var id in dataDict) { appOption = "<option value='" + id + "'>" + dataDict[id] + "</option>"; $("#appName").append(appOption); } // 初始化多選 $("#appName").multiselect({header: false,}); // 選中所有下拉列表項 $("#appName").multiselect("checkAll"); // 動態設置多選框的寬度 var ulList = $(".ui-multiselect-checkboxes")[0]; // 必須先單擊多選下拉列表,然后才可以獲取對應元素的寬度值 $(".ui-multiselect")[0].click(); var maxWidth = 0; for (var i = 0; i < ulList.childElementCount; i++) { var currentInputWidth = $(ulList.childNodes[i]).find("input")[0].offsetWidth; var currentSpanWidth = $(ulList.childNodes[i]).find("span")[0].offsetWidth; var currentWidth = currentSpanWidth + currentInputWidth * 3; if (currentWidth > maxWidth) { maxWidth = currentWidth; } } // 設置對應標簽的寬度 $($(".ui-multiselect")[0]).width(maxWidth); $($(".ui-multiselect-menu")[0]).width(maxWidth + 6); // 二次單擊 $(".ui-multiselect")[0].click(); }, "json"); }); // 綁定query按鈕的單擊操作 $(function() { $("#query").click(function() { var region = $("#region").val(); var beginDate = $("#beginDate").val(); var endDate = $("#endDate").val(); var chart = $("#chart").val(); var appNames = $("#appName").val(); var category = $("#category").val(); // 將appNames連接成字符串 queryReport(region, beginDate, endDate, chart, category, appNames.join("@")); }); }) var lineChart; // 獲取繪圖數據 function queryReport(region, beginDate, endDate, chart, category, appNames) { // 清空原有繪圖數據 $("#container")[0].innerHTML = ""; // 初始化折線圖參數 var lineChart = new Highcharts.Chart({ chart: { renderTo: 'container', type: 'line' }, title: { text: 'Daily Ranking', style: {fontFamily: 'Helvetica', fontWeight: '200'} }, subtitle: { text: 'By Product', style: {fontFamily: 'Helvetica', fontWeight: '200'} }, xAxis: [{ // master axis type: 'datetime', gridLineWidth:1, gridLineDashStyle: 'longdash', tickInterval: 24 * 3600 * 1000, }, { // slave axis type: 'datetime', linkedTo: 0, opposite: true, tickInterval: 24 * 3600 * 1000, labels: { formatter: function () {return Highcharts.dateFormat('%a', this.value);} } }], tooltip: { headerFormat: '<span>{point.key}</span><br/>', pointFormat: '<span >\u25AC</span> {series.name}: <b>{point.y}</b><br/>', }, yAxis: [{ // Primary yAxis min:1, reversed: true, labels: { format: 'No. {value}', style: { color: '#4572A7' } }, title: { text: 'Ranking', style: { color: '#4572A7' } } }, { // Secondary yAxis min:1, reversed: true, title: { text: 'Ranking', style: { color: '#4572A7' } }, labels: { format: 'No. {value}', style: { color: '#4572A7' } }, opposite: true, }], plotOptions: { column: { dataLabels: { enabled: true }, enableMouseTracking: true }, line: { dataLabels: { enabled: true }, enableMouseTracking: true } }, series: [], }); // 構造url參數 parameters = {'region': region, 'beginDate': beginDate, 'endDate': endDate, 'chart': chart, 'category': category, 'appNames': appNames }; // 請求繪圖數據 $.get("/getWinstoreRank", parameters, function(rankDict) { var ranksOfApp = new Array(); for (var app in rankDict) { lineChart.addSeries({ name: app, data: rankDict[app] }); } }, "json" ); } </script> </head> <body> <div id="set-content"> <ul> <li> <label for="region">Country/Region: </label> <select id="region"></select> </li> <li> <label for="beginDate">Begin Date: </label> <input type="text" id="beginDate"> </li> <li> <label for="endDate">End Date: </label> <input type="text" id="endDate"> </li> <li> <label for="chart">Chart: </label> <select id="chart"></select> </li> <li> <label for="category">Category: </label> <select id="category"></select> </li> <li> <label for="appName">App:</label> <select id="appName" multiple="multiple" size="4"></select> </li> <li> <button id='query'>Query</button> </li> </ul> </div> <div id="container"></div> </body>
這里稍微解釋下,在實際使用中,使用highcharts生成折線圖,根據不同的數據,只需要修改series參數即可。而series參數是個啥,可以在上面的HTML代碼中搜索series即可。稍微觀察下,就明白了。
至于你想換個大餅圖,柱狀圖,可以 點擊這里 找現成的例子,稍作修改就可以使用了。當然也許你有更多個性化的需求,那可以 點擊這里 找到對應的配置項進行修改。
2. 服務器端
1、首先命令行進入到你想放置項目代碼的地方
django_admin startproject winstore
2、進入剛剛新建的項目文件夾
cd winstore
3、創建新的應用rank
。這里的應用可以理解成具有獨立功能的一組網頁的結合,當然在本篇博客里,只有一個網頁了。
python manage.py startapp rank
4、在rank文件夾中新建文件夾templates
和static
,將剛剛新建的rank.html
放入templates
文件夾,同時將引用的js庫文件放入static
文件夾下,注意文件夾層級。
5.、打開winstore文件夾下的settings.py
,在INSTALL_APPS
下添加rank
,添加之后如下:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rank' # 添加的部分 ]
將DATABASES
修改成你自己的MySQL數據庫的控制信息。下面是我的數據庫設置:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'winstore', # 數據庫名 'HOST': '127.0.0.1', # IP 'PORT': '3306', # 端口號 'USER': 'root', # 用戶名 'PASSWORD': '111111', # 密碼 } }
6、編輯rank
文件夾下的views.py
文件,在rank.html中加入必要的網頁動態功能的實現。由于app的排名數據是根據其所處的榜單chart
和應用類別category
,以及不同的地區region
來確定的,所以這里里的功能實現就需要包括5個部分。分別對appName
、chart
、category
、region
實現從數據庫動態獲取其取值集合以及獲取排名數據。對應的實現分別如下:
appName
def getWinstoreApps(request): """ 根據接收到的GET請求返回app的取值集合 """ # 構造SQL語句 sql = 'SELECT DISTINCT appName FROM winstore_rank' # 默認appNames的key和value相同 appNames = {} try: result = getDataFromSQL(sql) result = [r[0] for r in result] for key in result: appNames[key] = key except Exception as e: print('getWinstoreApps ERROR: ' + str(e)) appNames['QQ'] = 'QQ' return JsonResponse(appNames)
chart
def getWinstoreCharts(request): """ 根據接收到的GET請求返回chart的取值集合 """ # 構造SQL語句 sql = 'SELECT DISTINCT chart FROM winstore_rank' # 默認charts的key和value相同 charts = {} try: result = getDataFromSQL(sql) result = [r[0] for r in result] for key in result: charts[key] = key except Exception as e: print('getWinstoreCharts ERROR: ' + str(e)) charts['Free'] = 'Free' return JsonResponse(charts)
category
def getWinstoreCategories(request): """ 根據接收到的GET請求返回category的取值集合 """ # 構造SQL語句 sql = 'SELECT DISTINCT category FROM winstore_rank' # 默認categories的key和value相同 categories = {} try: result = getDataFromSQL(sql) result = [r[0] for r in result] for key in result: categories[key] = key except Exception as e: print('getWinstoreCategories ERROR: ' + str(e)) categories['Education'] = 'Education' return JsonResponse(categories)
region
def getWinstoreRegions(request): """ 根據接收到的GET請求返回region的取值集合 """ # 構造SQL語句 sql = 'SELECT DISTINCT region FROM winstore_rank' # 默認regions的key和value相同 regions = {} try: result = getDataFromSQL(sql) result = [r[0] for r in result] for key in result: regions[key] = key except Exception as e: print('getWinstoreRegions ERROR: ' + str(e)) regions['EN-US'] = 'EN-US' return JsonResponse(regions)
獲取排名數據
def getWinstoreRank(request): """ 根據接收到的GET請求返回對應app的排名數據 """ # 從GET請求中獲取參數 region = request.GET.get("region", "EN-US") chart = request.GET.get("chart", "Free") category = request.GET.get("category", "Education") beginDate = request.GET.get("beginDate", "2018-01-22") endDate = request.GET.get("endDate", "2018-02-02") appNames = request.GET.get("appNames", "QQ").split("@") # 構造SQL語句 sqlTemp = 'SELECT the_date, rank FROM winstore_rank WHERE ' \ 'region="%s" AND chart="%s" AND category="%s" AND ' \ 'the_date BETWEEN "%s" AND "%s" AND ' \ 'appName=' % (region, chart, category, beginDate, endDate) # 以每個appName作為key,對應的排名數據列表作為value appRank = {} for appName in appNames: sql = sqlTemp + '"' + appName + '"' try: result = getDataFromSQL(sql) # 根據數據庫返回的結果將缺少rank數據的日期補0 result = addZeroToRank(beginDate, endDate, result) appRank[appName] = result except Exception as e: print('getWinstoreRank ERROR: ' + str(e)) return JsonResponse(appRank) def addZeroToRank(beginDate, endDate, result): """ 以beginDate和endDate為日期的起始,將result中缺少的日期補全,同時設定排名為0 Param: beginDate: 開始日期字符串,“2018-01-23” endDate: 結束日期字符串, “2018-02-02” result: 形如[(date, 23L), (date, 12L), [date, 3L]......] Return: 按照日期順序排列的排名數據,缺省排名為0 """ # 將日期字符串轉變為date類型數據,方便日期加減 y, m, d = [int(i) for i in beginDate.split("-")] begin = datetime.date(y, m, d) y, m, d = [int(i) for i in endDate.split("-")] end = datetime.date(y, m, d) current = begin # 獲取result中的日期,方便進行判斷 resultTemp = [r[0] for r in result] while current <= end: if not (current in resultTemp): result.append((current, 0)) current += datetime.timedelta(days=1) result.sort(key=lambda x: x[0]) return [int(r[1]) for r in result]
這里主要就是構造SQL語句,然后訪問數據庫獲取對應的數據集合。其中getDataFromSQL()
是對訪問MySQL數據庫的簡單封裝,具體代碼如下:
def getDataFromSQL(sql): """ 根據sql語句獲取數據庫的返回數據 """ cursor = connection.cursor() cursor.execute(sql) return list(cursor.fetchall())
一些涉及到的引用可以參考文末給出的項目代碼。
最終綁定一下首頁
def index(request): """ 綁定網站首頁 """ return render(request, 'rank.html')
3. MySQL數據庫
實際應用時,相關的rank數據是通過爬蟲獲取的。在這里,就直接填充一些隨機的rank數據進去了,不影響最終的結果。
最終成果展示
首頁
rank數據展示
可以看到雖然前端頁面很簡陋,但是功能是實現了。不過有個問題 就是重新點擊query按鈕后,highcharts提供的右側頁面中間下載圖片的那個三道杠會出現并排的兩個。
上述內容就是怎么在Django中利用Highcharts 實現數據可視化,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。