Flask+MySQL+Echarts: 实现数据可视化

一、软件及对应版本

  • Python 3.6.1 |Anaconda custom
  • Flask 0.12.2
  • Echarts 4.0

二、项目目录

Project directory.jpg

三、代码展示

  • server.py
from flask import Flask,render_template, url_for
import pymysql
import pandas as pd


app = Flask(__name__)
app.jinja_env.filters['zip'] = zip

def conn_db():
    conn = pymysql.connect(host="your_host", user="your_username", password="your_password", db="your_database", charset="utf8")
    return conn

def get_data(conn=conn_db(), n=10):
    # Get the top10 products
    sql = "select ProductMName, date_format(FeedbackDate, '%Y-%m') Month, count(FeedBack) Count from Feedbacks group by ProductMName, Month order by Count desc, Month asc"
    df = pd.read_sql(sql, conn)
    conn.close()
    product_count = []
    for index, value in enumerate(df["ProductMName"].unique()):
        product_count.append([value, index+1])
    product_count = dict(product_count)
    df["Rank"] = df["ProductMName"].map(lambda x: product_count[x])
    df = df[df["Rank"]<=n][["ProductMName", "Month", "Count"]]
    df.sort_values(by="Month", inplace=True)
    df_TotleCount = df.groupby(["ProductMName"])["Count"].sum()
    df_TotleCount.sort_values(ascending=False, inplace=True)
    df_pivot = pd.pivot_table(df, index="ProductMName", columns="Month", values="Count", fill_value=0)
    return df_TotleCount, df_pivot

@app.route('/')
def display_FeedbackCountByProject():
    df_TotleCount, df_pivot = get_data(n=10)
    TotleCount = df_TotleCount.values
    ProductMName = df_pivot.index.tolist()
    Month = df_pivot.columns.tolist()
    Count = df_pivot.values.tolist()
    return render_template('FeedbackCountByProject.html', ProductMName=ProductMName, Month=Month, Count=Count, TotleCount=TotleCount)

if __name__ == "__main__":
    app.run(debug = True)
  • FeedbackCountByProject.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script src="{{ url_for('static', filename='echarts.min.js') }}"></script>
    <title></title>
    <style>
        *{
            margin: 0; padding: 0;
        }
    </style>
</head>
<body>
    <div id="top" style="width: 1200px; height: 400px; padding: 20px;"></div>
    <div id="bottom" style="width: 1200px; height: 400px; padding: 20px;"></div>
    <script type="text/javascript">
        var myTop = echarts.init(document.getElementById('top'));
        var myBottom = echarts.init(document.getElementById('bottom'));

        optionTop = {
            title: {
                text: 'Top 10 Project By Date',
                left: 0,
                top: -5,
                subtextStyle: {
                    fontWeight: 'bolder'
                },
            },
            toolbox: {
                show: true,
                right: 80,
                feature: {
                    saveAsImage: {}
                }
            },
            legend: {
                show: true,
                data: ['', '', {% for p in ProductMName %}'{{ p }}', {% endfor %}],
                right: 0
            },
            tooltip: {
                trigger: 'axis'
            },
            grid: {
                bottom: 90
            },
            xAxis: {
                type: 'category',
                boundaryGap: false,
                name: 'Month of FeedbackDate',
                nameLocation: 'center',
                nameGap: 22,
                data: [{% for m in Month %}'{{ m }}', {% endfor %}],
                silent: false,
                splitLine: {
                    show: false
                },
                splitArea: {
                    show: false
                },
                nameTextStyle: {
                    fontWeight: 'bolder'
                }
            },
            yAxis: {
                type: 'value',
                name: 'FeedbackCnt',
                nameLocation: 'center',
                nameGap: 42,
                splitArea: {
                    show: false
                },
                nameTextStyle: {
                    fontWeight: 'bolder'
                }
            },
            series: [
                {% for pr, cnt in ProductMName|zip(Count) %}{
                name: '{{ pr }}',
                type: 'line',
                data: {{ cnt }},
                symbol: 'circle',
                symbolSize: 1
                }, {% endfor %}
            ]
        };

        optionBottom = {
            title: {
                text: 'Top 10 Project By Feedback Count',
                left: 0,
                top: -5,
                subtextStyle: {
                    fontWeight: 'bolder'
                },
            },
            toolbox: {
                show: true,
                feature: {
                    saveAsImage: {}
                }
            },
            legend: {
                show: false
            },
            tooltip: {
                trigger: 'axis'
            },
            grid: {
                bottom: 90
            },
            xAxis: {
                type: 'category',
                data: [{% for p in ProductMName %}'{{ p }}', {% endfor %}],
                name: 'Products',
                nameLocation: 'center',
                nameGap: 22,
                silent: false,
                splitLine: {
                    show: false
                },
                splitArea: {
                    show: false
                },
                nameTextStyle: {
                    fontWeight: 'bolder'
                },
                axisLabel: {
                    interval: 0,
                    formatter:function(value){  
                        var ret = "";
                        var maxLength = 18;
                        var valLength = value.length;
                        var rowN = Math.ceil(valLength / maxLength);
                        if (rowN > 1)
                        {
                            for (var i=0; i<rowN; i++){
                            var temp = "";
                            var start = i * maxLength;
                            var end = start + maxLength;
                            temp = value.substring(start, end) + "\n";
                            ret += temp;
                            }
                                return ret;
                        }else{
                            return value;
                        }
                    }
                }
            },
            yAxis: {
                type: 'value',
                name: 'FeedbackCnt',
                nameLocation: 'center',
                nameGap: 42,
                splitArea: {
                    show: false
                },
                nameTextStyle: {
                    fontWeight: 'bolder'
                }
            },
            series: [
                {
                type: 'bar',
                data: [{% for tcnt in TotleCount %}{{ tcnt }}, {% endfor %}]
                }
            ]
        };

        myTop.setOption(optionTop);
        myBottom.setOption(optionBottom);

    </script>
</body>
</html>

四、图表展示

Top 10 Project By Date.png

Top 10 Project By Feedback Count.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容