flask+mysql+ECharts+ajax+百度地图实现数据可视化

2023-10-26

思路

1:后台连接数据库创建session对象
2:创建表关系映射
3:查询数据
4:将数据封装成特定格式(json)
5:前台通过ajax请求指定路由异步加载数据并在地图上展示
先来看一下效果
在这里插入图片描述
地图参考:https://gallery.echartsjs.com/editor.html?c=map-china-dataRange

准备:导入相应的库

连接数据库:sqlalchemy

from flask import Flask, render_template, jsonify
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker
from config import *

config 中保存的是数据库的url

CONN = 'mysql://root:root@127.0.0.1:3306/csv_change_mysql?charset=utf8'
注意:更换成自己的用户名、密码、数据库名称

1:连接数据库并创建session对象

Base = declarative_base()
engine = create_engine(CONN)
Session = sessionmaker(bind=engine)
session = Session()

2:创建表关系映射
我的数据库结构为:
在这里插入图片描述
表名为test,id字段没什么用主要是因为在使用使用sqlalchemy创建映时必须指定一个主键否则会报错
详情请看我的另一篇博客:

txt文件导入数据库

创建映射代码:

class Test(Base):
    __tablename__ = 'test'
    id = Column(Integer,primary_key=True,autoincrement=True)
    job = Column(String(16))
    low_salary = Column(Integer)
    high_salary = Column(Integer)
    location = Column(String(5))

3:查询数据
我需要的是地点与薪资之间的关系所以只需要这两列即可
sql:select avg(high_salary),max(high_salary),min(high_salary),count(id),location from test group by location;
查询出最高薪资、最低薪资、平均薪资、地点、以及职位数
执行sql语句

recruits = session.execute(sql)

4:封装数据:
我需要的数据格式
在这里插入图片描述
因此需要将查询结果封装成指定格式数据

def query_data():
    returnData = {}
    sql = 'select avg(high_salary),max(high_salary),min(high_salary),count(id),location from test group by location;'
    recruits = session.execute(sql)
    x = []
    for recruit in recruits:
        x.append(recruit)
    two_tuple = tuple(x)#二维数组
    print(two_tuple)
    avg_salary = []
    max_salary = []
    min_salary = []
    count_job = []
    for item in two_tuple:
        location = item[4]
        avg_salary.append({'name': location, 'value': round(item[0], 0)})
        max_salary.append({'name': location, 'value': round(item[1], 0)})
        min_salary.append({'name': location, 'value': round(item[2], 0)})
        count_job.append({'name': location, 'value': round(item[3], 0)})
    #加一个状态码让前台可以判断是否得到了数据
    if two_tuple:
        returnData['status'] = 1
    else:
        returnData['status'] = 0
    returnData['avg_salary'] = avg_salary
    returnData['max_salary'] = max_salary
    returnData['min_salary'] = min_salary
    returnData['count_job'] = count_job
    return jsonify(returnData)

到了这后台代码基本完成了

还有一点需要注意的是在数据库中查询到的数据存在中文的问题

使用json.dumps()可以使用ensure_ascii=False指定
使用jsonify可以通过设置app.config[‘JSON_AS_ASCII’] = False来显示中文

5:前台请求数据
①:导入所需的库
jquery
echarts
百度地图扩展
百度开发者中心申请的apikey
echarts地图都是基于百度地图显示的如果你没有一个百度地图的ak的话地图是无法显示的
如果你没有百度地图的ak请先申请一个步骤也很简单请参考:

百度开发者中心javascript api 文档

引入代码:

     <!--echarts-->
    <script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts/echarts.min.js"></script>
    <!--jquery-->
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <!--map-->
    <script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts/map/js/china.js"></script>
    <!--ak-->
    <scripttype="text/javascript"src="https://api.map.baidu.com/apiv=2.0&ak=你申请的ak"></script>

②:ajax异步加载数据

 $(function () {
        $.ajax({
            type:'post',
            url:'/query',
            dataType:'json',
            success:function (returnData) {
                console.log(returnData);
                if (returnData.status == 1){
                //option中是地图的相关配置
                    option = {}
                }
                    var dom = document.getElementById("container");
                    var myChart = echarts.init(dom);
                    myChart.setOption(option);
                                }
                            })
                        });

在这里插入图片描述

注意请求方式为post

后台要允许post请求否则会报404

@app.route('/query',methods=['POST'])
def query_data():

还有一个细节就是地图的tooltip显示问题需要在option中配置代码为

 tooltip: {
                            trigger: 'item',
                            formatter: function(params) {
                                            var res = params.name+'<br/>';
                                            var myseries = option.series;
                                            for (var i = 0; i < myseries.length; i++) {
                                                for(var j=0;j<myseries[i].data.length;j++){
                                                    if(myseries[i].data[j].name==params.name){
                                                        res+=myseries[i].name +' : '+myseries[i].data[j].value+'</br>';
                                                    }
                                                }
                                            }
                                            return res;
                                        }
                        }

最后放上完整代码请大家酌情参考
后台:

from flask import Flask, render_template, jsonify
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker
from config import *
import json
Base = declarative_base()
engine = create_engine(CONN)
Session = sessionmaker(bind=engine)
session = Session()

class Test(Base):
    __tablename__ = 'test'
    id = Column(Integer,primary_key=True,autoincrement=True)
    job = Column(String(16))
    low_salary = Column(Integer)
    high_salary = Column(Integer)
    location = Column(String(5))

app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False
@app.route('/query',methods=['POST'])
def query_data():
    returnData = {}
    sql = 'select avg(high_salary),max(high_salary),min(high_salary),count(id),location from test group by location;'
    recruits = session.execute(sql)
    x = []
    for recruit in recruits:
        x.append(recruit)
    two_tuple = tuple(x)#二维数组
    avg_salary = []
    max_salary = []
    min_salary = []
    count_job = []
    for item in two_tuple:
        location = item[4]
        avg_salary.append({'name': location, 'value': round(item[0], 0)})
        max_salary.append({'name': location, 'value': round(item[1], 0)})
        min_salary.append({'name': location, 'value': round(item[2], 0)})
        count_job.append({'name': location, 'value': round(item[3], 0)})
    #加一个状态码让前台可以判断是否得到了数据
    if two_tuple:
        returnData['status'] = 1
    else:
        returnData['status'] = 0
    returnData['avg_salary'] = avg_salary
    returnData['max_salary'] = max_salary
    returnData['min_salary'] = min_salary
    returnData['count_job'] = count_job
    return jsonify(returnData)
@app.route('/')
def hello_world():
    return render_template('testView.html')


if __name__ == '__main__':
    app.run()

前台页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>
    <div id="container" style="width: 600px; height:400px; margin: 0 auto;top: 100px"></div>
	<script src="{{ url_for('static',filename='js/jquery-1.2.6.pack.js') }}"></script>
    <script src="{{ url_for('static',filename='js/echarts.js') }}"></script>
    <script src="{{ url_for('static',filename='js/China.js') }}"></script>
    <script type="text/javascript">
    $(function () {
        $.ajax({
            type:'post',
            url:'/query',
            dataType:'json',
            success:function (returnData) {
                console.log(returnData);
                if (returnData.status == 1){
                    option = {
                        title: {
                            text: '大数据行业地点与薪资关系',
                            subtext: 'Test数据',
                            left: 'center'
                        },
                        tooltip: {
                            trigger: 'item',
                            formatter: function(params) {
                                            var res = params.name+'<br/>';
                                            var myseries = option.series;
                                            for (var i = 0; i < myseries.length; i++) {
                                                for(var j=0;j<myseries[i].data.length;j++){
                                                    if(myseries[i].data[j].name==params.name){
                                                        res+=myseries[i].name +' : '+myseries[i].data[j].value+'</br>';
                                                    }
                                                }
                                            }
                                            return res;
                                        }
                        },
                        legend: {
                            orient: 'vertical',
                            left: 'left',
                            data:['最大薪资(k)','最低薪资(k)','平均薪资(k)','总职位数(个)']
                        },
                        visualMap: {
                            min: 0,
                            max: 200,
                            left: 'left',
                            top: 'bottom',
                            text: ['高','低'],           // 文本,默认为数值文本
                            calculable: true
                        },
                        toolbox: {
                            show: true,
                            orient: 'vertical',
                            left: 'right',
                            top: 'center',
                            feature: {
                                dataView: {readOnly: false},
                                restore: {},
                                saveAsImage: {}
                            }
                        },
                        series: [
                            {
                                name: '最大薪资(k)',
                                type: 'map',
                                mapType: 'china',
                                roam: false,
                                tooltip:{
                                    show:true
                                },
                                label: {
                                    normal: {
                                        show: true
                                    },
                                    emphasis: {
                                        show: true
                                    }
                                },
                                data:returnData.max_salary
                            },
                            {
                                name: '最低薪资(k)',
                                type: 'map',
                                mapType: 'china',
                                 tooltip:{
                                    show:true
                                },
                                label: {
                                    normal: {
                                        show: true
                                    },
                                    emphasis: {
                                        show: true
                                    }
                                },
                                data:returnData.min_salary

                            },
                            {
                                name: '平均薪资(k)',
                                type: 'map',
                                mapType: 'china',
                                 tooltip:{
                                    show:true
                                },
                                label: {
                                    normal: {
                                        show: true
                                    },
                                    emphasis: {
                                        show: true
                                    }
                                },
                                data:returnData.avg_salary
                            },   {
                                name: '总职位数(个)',
                                type: 'map',
                                mapType: 'china',
                                 tooltip:{
                                    show:true
                                },
                                label: {
                                    normal: {
                                        show: true
                                    },
                                    emphasis: {
                                        show: true
                                    }
                                },
                                data:returnData.count_job
                            }
                        ]
                    };
                }
                    var dom = document.getElementById("container");
                    var myChart = echarts.init(dom);
                    myChart.setOption(option);
                                }
                            })
                        });
    </script>

</body>

</html>

注:地图加载不出来,可能是js文件顺序问题,china.js要放大echarts.js后面。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

flask+mysql+ECharts+ajax+百度地图实现数据可视化 的相关文章

随机推荐

  • 制作minist格式的图像数据集

    模仿mnist数据集制作自己的数据集 YF Li123的博客 CSDN博客 mnist数据集制作 深度学习的开放数据集及制作方法 1 MNIST 知乎 DL with python 7 TensorFlow实现自制mnist数据集 DL w
  • vue3之provide的使用

    需求 vue3爷孙组件传值 场景 点击编辑按钮 将表格行的id传递给弹框子组件中包含的孙子组件 技术栈 vue3 vite ant design vue3 2 0 ts yeye组件 sun组件
  • 【基础知识】一网络不通问题处理记录

    哈喽 大家好 我是雷工 在项目现场数据采集过程中 经常会遇到网络问题 最近又遇到一个网络问题 下面记录处理过程 方便遇到类似问题时能快速处理 一 问题描述 现场有5个西门子S71200 1500PLC系统 均在同一网段 网段1 局域网内 在
  • FPGA与ASIC的区别

    先来看张图 本图体现出了集成电路产业链 设计业 制造业 封测业 关于制造 封装测试我们看两张图稍作了解即可 数字IC ASIC设计流程及EDA工具 1 了解数字IC设计 在VLSI时代 数字IC设计是VLSI设计的根本所在 更大的规模 更好
  • Redhat下arm-linux-gcc安装

    方法 一 复制以下RPM包到 root install目录下 glibc kernheaders 2 4 8 10 i386 rpm glibc devel 2 3 2 11 9 i386 rpm cpp 3 2 2 5 i386 rpm
  • Python读取pdf表格写入excel

    背景 今天突然想到之前被要求做同性质银行的数据分析 妈耶 十几个银行 每个银行近5年的财务数据 而且财务报表一般都是 pdf 的 我们将 pdf 中表的数据一个个的拷贝到 excel 中 再借助 excel 去进行求和求平均等聚合函数操作
  • windows下redis配置密码

    转载 https www cnblogs com GuoJunwen p 9238624 html redis安装后目录如下 最简单的启动方式是直接双击redis server exe 如果要设置密码 首先打开配置文件 要注意的是这两个都是
  • 数据库设计中常见表结构的设计技巧

    一 树型关系的数据表 不少程序员在进行数据库设计的时候都遇到过树型关系的数据 例如常见的类别表 即一个大类 下面有若干个子类 某些子类又有子类这样的情况 当类别不确定 用户希望可以在任意类别下添加新的子类 或者删除某个类别和其下的所有子类
  • 使用MQTT.fx向ThingsBoard发布遥测数据

    一 在ThingsBoard平台新建设备 复制访问令牌 二 打开MQTT fx进行连接 填写服务地址及端口以及设备访问令牌 特别注意 这里踩了个深坑 这个端口一定要对应thingsboard服务thingsboard yml中的配置 这个端
  • c语言回文数

    回文数 include
  • 微信小程序:云开发·初探

    Good days give you happiness and bad days give you experience 顺境带来快乐 逆境带来成长 云开发 quickstart 这是云开发的快速启动指引 其中演示了如何上手使用云开发的三
  • VSCode集成PlantUML

    VSCode集成PlantUML 哈喽大海豚 前端 2018 01 23 前端 UML PlantUML VSCode PlantUML介绍 PlantUML是一个允许快速编写以下图类的组件 序列图 Sequence diagram 用例图
  • 常见Windows硬件故障

    电脑主机滴滴滴响是什么原因 不同的响声代表不同的硬件问题 一下是几种主板设置的提示声音代表的具体问题 1 AWARD的BIOS设定为 长声不断响 内存条未插紧 2短 系统正常启动 2短 CMOS设置错误 需重新设置 1长1短 内存或主板错误
  • CollAFL: Path Sensitive Fuzzing 模糊测试论文阅读

    CollAFL Path Sensitive Fuzzing 会议 S P2018 这是一篇内容十分饱满的Fuzz文章 受益匪浅 1 Abstract and Introduction 对于覆盖率引导的模糊测试来说 跟踪覆盖率是至关重要的
  • IT风投案例分析——facebook

    Facebook 虽然Facebook对于中国人来说是一个不存在的网站 但这并不能妨碍它成为世界前列的互联网公司 Facebook是很特殊的 它的创始人扎克伯格1984年出生 在2004年就开始创建Facebook 当时他只有仅仅二十岁 那
  • Vivado软件的一些报错总结

    1 Synth 8 2543 port connections cannot be mixed ordered and named E FPGA project Xilinx ZYNQ three days sobel 032 face o
  • 渗透测试概述与流程

    渗透测试概述 渗透测试是一种通过模拟攻击的技术与方法 挫败目标系统的安全控制措施并获得控制访问权的安全测试方法 网络渗透测试主要依据CVE已经发现的安全漏洞 模拟入侵者的攻击方法对网站应用 服务器系统和网络设备进行非破坏性质的攻击性测试 C
  • 华为od 安全测试岗 简谈机试面试【更新完】

    PS 准备慢慢更新下最近我在od的机试题以及一二轮面试题和hr面 主管面 最后成功拿到offer 但不打算去了 然后成功让对接人破防 od懂得都懂 流程是 机试 gt 一面 gt 中间穿插了性格测试考试 gt 二面 gt HR面 gt 综面
  • 关于微信小程序的生命周期

    关于微信小程序的生命周期 onLaunch 官网App vue App uvue uni app官网 问题描述 我现在有个小程序 取名为a 有个用户b 从来没有打开过小程序 那么他第一次打开小程序的时候会触发onLaunch 然后用户b退出
  • flask+mysql+ECharts+ajax+百度地图实现数据可视化

    思路 1 后台连接数据库创建session对象 2 创建表关系映射 3 查询数据 4 将数据封装成特定格式 json 5 前台通过ajax请求指定路由异步加载数据并在地图上展示 先来看一下效果 地图参考 https gallery echa