30【源码】数据可视化大屏:基于 Echarts + Python Flask 实现的32-9超宽大屏 - 中国&国际疫情实时追踪

我是 YYDataV数据可视化 

专注于 数据可视化大屏,工厂扫码装箱系统 

我的微信 6550523,多多交流 ~

目录

效果展示

1.动态实时更新数据效果图

2.鼠标右键切换主题 

 一. 确定需求方案 

1. 屏幕分辨率

2. 部署方式 

二. 整体架构设计

三.开发思路

1. 数据爬取 requests

2.  数据准备 pandas

四.编码实现 (基于篇幅及可读性考虑,此处展示部分关键代码)

1. 前端html代码

2. 世界疫情地图 echarts world

3. 动态加载数据代码

4. 服务器端 JSON 通信数据定义 

5. 前端JS - 数据定时更新控制

6.后端 flask 服务器

四. 启动命令

五. 运行效果

六. 源码下载 

更多可视化案例


前言:本案例爬取数据源为腾讯疫情数据, 对数据进行分析归类处理,然后制作成32:9超宽分辨率的可视化大屏。

效果展示

1.动态实时更新数据效果图

2.鼠标右键切换主题 

代码中预置了12个主题风格,实际开发中可根据实际情况二次增加。

 切换主题,我们可以看到:主题的配色变化了另一种风格。

 

 

 一. 确定需求方案 

1. 屏幕分辨率

这个案例的大屏分辨率是32:9,超炫的的宽屏比。

根据电脑分辨率屏幕自适应显示,F11全屏查看;

2. 部署方式 

B/S方式:支持Windows、Linux、Mac等各种主流操作系统;支持主流浏览器Chrome,Microsoft Edge,360等;服务器采用python语言编写,配置好python环境即可。

二. 整体架构设计

  1. 前端Echarts开源库:使用 WebStorm 编辑器;
  2. 后端 http服务器:基于 Python 实现,使用 Pycharm 或 VSCode 编辑器;
  3. 数据传输格式:JSON;
  4. 数据源类型:JSON文件。实际开发需求中,支持定制HTTP API接口方式或其它各种类型数据库,如PostgreSQL、MySQL、Oracle、Microsoft SQL Server、SQLite、Excel表格等。
  5. 数据更新方式:采用http get 轮询方式 。在实际应用中,也可以视情况选择j监测后端数据实时更新,实时推送到前端的方式;

三.开发思路

1. 数据爬取 requests

    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 /537.36'
    }
    # 国内疫情数据统计
    url = 'https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=statisGradeCityDetail,diseaseh5Shelf'
    response = requests.get(url, headers=headers)
    chinaTotal = response.json()['data']['diseaseh5Shelf']['chinaTotal']
    chinaAdd = response.json()['data']['diseaseh5Shelf']['chinaAdd']
    dom_list = {
        "china": {
            "localConfirm": chinaTotal['localConfirm'],
            "nowConfirm": chinaTotal['nowConfirm'],
            "confirm": chinaTotal['confirm'],
            "dead": chinaTotal['dead'],
            "localConfirm_": chinaAdd['localConfirmH5'],
            "nowConfirm_": chinaAdd['nowConfirm'],
            "confirm_": chinaAdd['confirm'],
            "dead_": chinaAdd['dead']
        },
    }

2.  数据准备 pandas

生成中国地图所需的json数据 - 生成 static/map_china_map/map_china_map.json 文件

    statisGradeCityDetail = response.json()['data']['statisGradeCityDetail']    
    # 生成中国地图数据
    # pandas分组求和groupby sum
    df = pd.DataFrame(statisGradeCityDetail)
    gp_df = df[["confirmAdd", "confirm", "nowConfirm"]
               ].groupby(df['province']).sum()

    # reset_index 将province变成了列,将索引设置成了自然数0 1 2 ...
    gp_df = gp_df.reset_index()
    # print(gp_df)
    # 生成新列名
    gp_df = gp_df.rename(
        columns={'province': 'name'})

    print("4. 生成 map_china_map 图表的数据", gp_df)
    gp_df.to_json(
        "static/map_china_map/map_china_map.json", orient="records")

四.编码实现 (基于篇幅及可读性考虑,此处展示部分关键代码)

1. 前端html代码

使用bootstrap container-fluid, row, col等实现。

<body id="container_body">
     <div class="container-fluid">
          <!-- 外框 1 -->
          <div class="row" id="container_1">
               <h3 style="color:#f5efef; text-align: center;">30【源码】数据可视化大屏:基于 Echarts +
                    Python
                    Flask 实现的32-9超宽大屏 - 中国&国际疫情实时追踪 </h3>
          </div>

          <!-- 外框 2 -->
          <div class="row" id="container_2">
               <!-- 左侧 -->
               <div class="col-3">
                    <!-- 左侧第1行 -->
                    <div class="row" style="height: 20%">
                         <div id="container_l1" class="col-3">
                         </div>

                         <div id="container_l2" class="col-3">
                         </div>

                         <div id="container_l3" class="col-3">
                         </div>

                         <div id="container_l4" class="col-3">
                         </div>
                    </div>
                    <!-- 左侧第2行 -->
                    <div class="row" style="height: 44%">
                         <div id="container_l5" class="col">
                         </div>
                    </div>

                    <!-- 左侧第3行 -->
                    <div class="row" style="height: 35%">
                         <div id="container_l6" class="col">
                              <dv-scroll-board id="vue_app" :config="config" />
                         </div>
                    </div>
               </div>

               <!-- 中间 -->
               <div class="col-3">
                    <div class="row" style="height: 100%">
                         <div id="container_m1_root" class="col">
                              <div class="div-section">
                                   <button type="button" class="btn btn-info" style="width: fit-content;"
                                        onclick="async_echart_china('container_m1', 'map_china_map/map_china_map.json', 'confirmAdd')">新增确诊</button>
                                   <button type="button" class="btn btn-info" style="width: fit-content;"
                                        onclick="async_echart_china('container_m1', 'map_china_map/map_china_map.json', 'confirm')">累计确诊</button>
                                   <button type="button" class="btn btn-info" style="width: fit-content;"
                                        onclick="async_echart_china('container_m1', 'map_china_map/map_china_map.json', 'nowConfirm')">现有确诊</button>
                              </div>
                              <div id="container_m1"></div>
                         </div>
                    </div>
               </div>
               <!-- 中间 -->
               <div class="col-3">
                    <div class="row" style="height: 100%">
                         <div class="col" id="container_m2_root">
                              <div class="div-section">
                                   <button type="button" class="btn btn-info" style="width: fit-content;"
                                        onclick="async_echart_map_geo_map_world('container_m2', 'map_geo_map_world/map_geo_map_world.json', 'confirmAdd')">新增确诊</button>
                                   <button type="button" class="btn btn-info" style="width: fit-content;"
                                        onclick="async_echart_map_geo_map_world('container_m2', 'map_geo_map_world/map_geo_map_world.json', 'confirm')">累计确诊</button>
                                   <button type="button" class="btn btn-info" style="width: fit-content;"
                                        onclick="async_echart_map_geo_map_world('container_m2', 'map_geo_map_world/map_geo_map_world.json', 'nowConfirm')">现有确诊</button>
                              </div>
                              <div id="container_m2"></div>
                         </div>
                    </div>

               </div>

               <!-- 右侧 -->
               <div class="col-3">
                    <!-- 第1行 -->
                    <div class="row" style="height: 20%">
                         <div id="container_r1" class="col">
                         </div>

                         <div id="container_r2" class="col">
                         </div>

                         <div id="container_r3" class="col">
                         </div>

                         <div id="container_r4" class="col">
                         </div>
                    </div>
                    <!-- 第2行 -->
                    <div class="row" style="height: 44%">
                         <div id="container_r5" class="col">
                         </div>
                    </div>

                    <!-- 第3行 -->
                    <div class="row" style="height: 35%">
                         <div id="container_r6" class="col">
                              <dv-scroll-board id="vue_app_2" :config="config" />
                         </div>
                    </div>
               </div>
          </div>
     </div>


     <!-- 鼠标右键切换主题 theme [1/2] -->
     <!-- style="width: 200px;" 必须写在html,不能写在css文件中 -->
     <ul id="right_menu" style="width: 200px;">
          <li><img src="img/drop-down.png"> 主题列表</li>
          <li>infographic</li>
          <li>macarons</li>
          <li>roma</li>
          <li>shine</li>
          <li>walden</li>
          <li>westeros</li>
          <li>wonderland</li>
          <li>vintage</li>
          <li>purple-passion</li>
          <li>chalk</li>
          <li>dark</li>
          <li>essos</li>
     </ul>
</body>

2. 世界疫情地图 echarts world

function init_echart_map_geo_map_world(container) {
  var chartDom = document.getElementById(container);
  var myChart = echarts.init(chartDom, window.gTheme);

  option = {
    title: {
      text: "世界疫情实时数据",
      top: "2%",
      left: "center",
      textStyle: {
        // color: "hsl(200, 86%, 48%)",
        fontSize: "20",
      },
    },

    tooltip: {
      trigger: "item",
      formatter: function (params) {
        console.log(params);
        value = 0;
        if (params.value) value = params.value;
        return params.seriesName + "<br>" + params.name + " : " + value + "人";
      },
    },

    visualMap: {
      type: "piecewise",
      splitNumber: 5,
      pieces: [
        { gt: 10000 },
        { gt: 1000, lte: 9999 },
        { gt: 500, lte: 999 },
        { gt: 100, lte: 499 },
        { gt: 10, lte: 99 },
        { gt: 1, lte: 9 },
        { lte: 0 },
      ],

      textStyle: {
        color: "#fff",
      },
      top: "bottom",
    },
    geo: [
      {
        map: "world",
        layoutCenter: ["50%", "50%"],
        zoom: 1.2,
        roam: true,
        // 地图放大或缩小的尺寸
        layoutSize: "100%",
        selectedMode: "single",
        label: {
          emphasis: {
            show: false,
          },
        },
        // 地图区域的多边形 图形样式。
        itemStyle: {
          // 图形阴影颜色。支持的格式同color。
          shadowColor: "black",
          // 图形阴影的模糊大小。
          shadowBlur: 10,
          // 阴影水平方向上的偏移距离。
          shadowOffsetX: 2,
          // 阴影垂直方向上的偏移距离。
          shadowOffsetY: 2,
        },
        // 高亮状态下的多边形和标签样式。
        emphasis: {
          itemStyle: {
            borderWidth: 3,
            borderColor: "purple",
            // areaColor: "#ffdead",
          },
        },
      },
    ],
    series: {
      name: "累计确诊",
      type: "map",
      coordinateSystem: "geo",
      geoIndex: 0,
      zoom: 1.2,
      roam: true,
    },
  };
  // 使用刚指定的配置项和数据显示图表。
  myChart.setOption(option);
  window.addEventListener("resize", function () {
    myChart.resize();
  });
}

3. 动态加载数据代码


function async_echart_map_geo_map_world(container, filename, section) {
  $.getJSON(filename).done(function (data) {
    var myChart = echarts.init(
      document.getElementById(container),
      window.gTheme
    );
    series = "";
    data_section = [];
    if (section == "confirmAdd") {
      series = "新增确诊";
      data_section = data.map((item) => {
        return { name: item.name, value: item.confirmAdd };
      });
    }
    if (section == "confirm") {
      series = "累计确诊";
      data_section = data.map((item) => {
        return { name: item.name, value: item.confirm };
      });
    }
    if (section == "nowConfirm") {
      series = "现有确诊";
      data_section = data.map((item) => {
        return { name: item.name, value: item.nowConfirm };
      });
    }
    myChart.setOption({
      series: { name: series, data: data_section },
    });
  }); //end $.getJSON
}

4. 服务器端 JSON 通信数据定义 

世界疫情地图数据

[
    {
        "name": "Afghanistan",
        "nameChinese": "\u963f\u5bcc\u6c57",
        "confirmAdd": 0,
        "confirm": 145,
        "nowConfirm": 139
    },
    {
        "name": "Albania",
        "nameChinese": "\u963f\u5c14\u5df4\u5c3c\u4e9a",
        "confirmAdd": 0,
        "confirm": 212,
        "nowConfirm": 169
    },
    {
        "name": "Algeria",
        "nameChinese": "\u963f\u5c14\u53ca\u5229\u4e9a",
        "confirmAdd": 0,
        "confirm": 511,
        "nowConfirm": 448
    },
... ... 
]

5. 前端JS - 数据定时更新控制

支持在每个echarts图表中独立控制定时更新的间隔。

 // 定时1s执行数据更新函数
  setInterval(function () {
    async_echart_bar_horizontal(
      container,
      path_bar_horizontal + "bar_horizontal.json"
    );
  }, 1000);

6.后端 flask 服务器

from flask import Flask
app = Flask(__name__, static_folder="static", template_folder="template")


# 主程序在这里
if __name__ == "__main__":

    # 开启线程,触发动态数据
    a = threading.Thread(target=asyncJson.loop)
    a.start()

    # 开启 flask 服务
    app.run(host='0.0.0.0', port=88, debug=True)

四. 启动命令

<!-- 启动server命令 -->
python main.py 

<!-- 浏览器中输入网址查看大屏(端口为 main.py 中的 port 参数定义) -->
http://localhost:88/static/index.html

<!-- 更多资料参考我的博客主页  -->
https://yydatav.blog.csdn.net/

<!-- 更多案例参考 -->
https://blog.csdn.net/lildkdkdkjf/article/details/120705616

我的微信号:6550523  欢迎多多交流

五. 运行效果

六. 源码下载 

30【源码】数据可视化:基于Echarts+PythonFlask实现的32-9超宽大屏-中国&国际疫情实时追踪-企业管理文档类资源-CSDN下载

更多可视化案例

YYDatav的数据可视化《精彩案例汇总》_YYDataV的博客-CSDN博客

猜你喜欢

转载自blog.csdn.net/lildkdkdkjf/article/details/124429648