利用Python开发七普数据在线可视化看板

简介: 利用Python开发七普数据在线可视化看板

1 简介

这是我的系列教程「Python+Dash快速web应用开发」的第十八期,通过前面十七期的内容,如果你有用心学习的话,那么恭喜你已经具备使用Dash编写常规web应用的能力了。

而在使用Dash开发web应用时,页面内容和功能逻辑简单倒还好,一旦你的功能内容开始复杂化系统化起来,那么像过往文章示例中简单一个app.py存放所有功能代码就不适用了。

而在今天的教程中,我就将为大家介绍我在日常使用过程中总结出的一套针对Dash项目的前后端分离的项目结构基础范式,并以搭建「全国七普部分数据可视化看板」为例,供大家参考借鉴,从而更有条理的编写和管理Dash应用项目。

图1

2 Dash项目结构基础范式

2.1 总体结构一览

开门见山,我们直接先来一览今天要介绍的Dash基础项目结构:

+ dash_demo_project/
   + assets/
      + css/
      + img/
      + js/
       • favicon.ico
   + callbacks/
   + models/
   + views/
    • app.py
    • server.py

在不考虑「外部参数导入」「用户登陆验证」「应用部署」等额外配置文件及功能内容的前提下,上面的结构就可以满足常规Dash应用的需求了。

下面我们基于和鲸上获取到的「第七次全国人口普查」公开数据集,以搭建下面这个简单的数据可视化看板为例,介绍上述各部分的实际功能意义(完整项目源码见文章开头链接或公众号后台回复七普可视化)。

图2

2.2 各部分结构介绍

2.2.1 再谈assets

「页面布局篇」中我们提到过assets目录,它是官方推荐的用于存放我们的Dash应用所依赖静态资源文件的目录,如依赖的cssjsfavicon.ico、各种图片及字体等静态资源,在本文的可视化看板案例中,assets目录资源放置情况如下:

+ assets/
  + css/
      • bootstrap.min.css
      • custom.css
  + img/
      • wxgzh.png
      • zsxq.png
  + js/
   • favicon.ico

其中img目录下存放的是首页的两张二维码图片,在Dash中可以配合Img()get_asset_url()来获取assets目录下指定文件路径并渲染:

html.Img(src=app.get_asset_url('img/zsxq.png'), style={'width': '100%'})

css目录下则放置了dash_bootstrap-components所依赖的css文件,而custom.css则是我自己编写的一些用于样式美化的css代码:

.nav-link.active {
    background-color: #4fc3f7!important;
}
#index-desc > * {
    font-size: 26px;
}
.table td, .table th {
    text-align: center;
}

直接放置于assets根目录下的favicon.ico则用来替换Dash默认的网页图标:

图3

你可以根据自己Dash项目的实际需求灵活变通,譬如需要用到echarts就可以在js目录下放置echarts.min.js文件。

2.2.2 在server.py中实例化配置Dash对象

跟以往的例子不同,在严谨的Dash工程下,推荐构建单独的server.py文件来完成对Dash对象的实例化配置等工作,在今天的可视化看板案例中server.py比较简单,内容如下:

import dash
app = dash.Dash(
    __name__,
    suppress_callback_exceptions=True
)
# 设置网页title
app.title = '七普部分数据看板'
server = app.server

2.2.3 在app.py中编写前端骨架与路由

如果你的Dash项目非常简单,那么from server import app之后,就可以像往常一样在app.py中组织你的前端与回调部分内容。

但如果你的Dash项目功能较为复杂,亦或是url联结的页面较多时,就可以只在app.py中编写前端layout「骨架」,包含了必要的Location()部件、保持不变的前端部分以及由url变化所触发的页面内容容器,譬如今天的可视化看板中左侧边栏部分以及Location()监听部件:

app.layout = html.Div(
    [
        # 监听url变化
        dcc.Location(id='url'),
        html.Div(
            [
                # 标题区域
                html.Div(
                    html.H3(
                        '七普部分数据看板',
                        style={
                            'marginTop': '20px',
                            'fontFamily': 'SimSun',
                            'fontWeight': 'bold'
                        }
                    ),
                    style={
                        'textAlign': 'center',
                        'margin': '0 10px 0 10px',
                        'borderBottom': '2px solid black'
                    }
                ),
                # 子页面区域
                html.Hr(),
                dbc.Nav(
                    [
                        dbc.NavLink('首页', href='/', active="exact"),
                        dbc.NavLink('年龄结构', href='/age', active="exact"),
                        dbc.NavLink('性别结构', href='/sex', active="exact"),
                        dbc.NavLink('六普vs七普', href='/statistics', active="exact"),
                    ],
                    vertical=True,
                    pills=True
                )
            ],
            style={
                'flex': 'none',
                'width': '300px',
                'backgroundColor': '#fafafa'
            }
        ),
        html.Div(
            id='page-content',
            style={
                'flex': 'auto'
            }
        )
    ],
    style={
        'width': '100vw',
        'height': '100vh',
        'display': 'flex'
    }
)

同样地,也推荐将监听url变化从而渲染不同页面的「路由回调」一并写在app.py中,方便后续的管理与升级:

# 路由总控
@app.callback(
    Output('page-content', 'children'),
    Input('url', 'pathname')
)
def render_page_content(pathname):
    if pathname == '/':
        return index_page
    elif pathname == '/age':
        return age_page
    elif pathname == '/sex':
        return sex_page
    elif pathname == '/statistics':
        return statistics_page
    return html.H1('您访问的页面不存在!')

2.2.4 在views子模块中构建多页面前端内容

在上一小节的路由回调中你可能会好奇不同url下的返回值index_pageage_page等都是什么,这些都构建在「子模块」views下:

+ views/
   • age.py
   • index.py
   • sex.py
   • statistics.py
   • __init__.py

譬如其中之一的age.py内容如下:

import dash_html_components as html
import dash_core_components as dcc
import dash_bootstrap_components as dbc
import pandas as pd
import plotly.express as px
from models.age import Age
age_data = (
    pd.DataFrame(Age.fetch_all()).rename(columns={
        'region': '地区',
        'prop_0_to_14': '0到14岁人口占比',
        'prop_15_59': '15到59岁人口占比',
        'prop_60_above': '60岁以上人口占比',
        'prop_65_above': '65岁以上人口占比'
    })
)
fig = px.bar(age_data.melt(id_vars=['地区'],
                           value_vars=['0到14岁人口占比', '15到59岁人口占比', '60岁以上人口占比'],
                           var_name='年龄段',
                           value_name='占比(%)'),
             y="地区", x="占比(%)", color="年龄段", title="七普各地区人口年龄结构",
             color_discrete_map={
                 '0到14岁人口占比': '#0868ac',
                 '15到59岁人口占比': '#43a2ca',
                 '60岁以上人口占比': '#a8ddb5'
             },
             orientation='h')
fig.update_layout(
    font=dict(
        family="Times New Roman, SimSun"
    )
)
fig.update_layout(xaxis_range=[0, 100])
fig.update_layout(
    margin=dict(t=50, b=10)
)
age_page = html.Div(
    [
        html.Div(
            dbc.Table.from_dataframe(age_data, striped=True),
            style={
                'overflowY': 'auto',
                'flex': '1'
            }
        ),
        html.Div(
            dcc.Graph(figure=fig, style={'height': '100%'}),
            style={
                'flex': '1',
                'height': '100%'
            }
        )
    ],
    style={
        'display': 'flex',
        'height': '100%'
    }
)

通过这种方式针对不同页面构建相应的前端对象,从而在app.py中按照下列方式导入就可以使用了:

from views.index import index_page
from views.age import age_page
from views.sex import sex_page
from views.statistics import statistics_page

2.2.5 在callbacks子模块中构建多页面后端逻辑

当你在views下构建的页面内容中涉及到回调交互的功能时,我推荐将对应的后端回调逻辑拆分到callbacks子模块下同名文件中,这样非常便于编写与维护。

同时「一定要」记住在views下对应的前端子模块中,一定要导入callbacks中对应的回调子模块内部的「至少」一个对象,否则Dash在打包应用时是扫描不到相应的回调函数内容进行编译的,进而会导致应用启动时回调无效,譬如在views/statistics.py中我们就执行了from callbacks.statistics import statistics_data

2.2.6 在models子模块下定义数据模型

前面说的很多内容都关乎Dash应用的构建,而当你的Dash应用依赖外部数据时,推荐的方式是类似flask项目那样构建子模块models来定义数据模型,实现与数据库的关联。

而我们今天的可视化看板案例中就配合「整合数据库篇」介绍的peewee相关知识,分别定义了数据模型对应了七普中的年龄结构性别结构以及六普七普对比数据表,并在viewscallbacks等涉及的子模块中导入并调用,以年龄结构models/age.py为例:

from peewee import SqliteDatabase, Model
from peewee import CharField, FloatField
db = SqliteDatabase('models/age.db')
class Age(Model):
    # 地区,唯一
    region = CharField(unique=True)
    # 0-14岁占比
    prop_0_to_14 = FloatField()
    # 15-59岁占比
    prop_15_59 = FloatField()
    # 60岁及以上占比
    prop_60_above = FloatField()
    # 65岁及以上占比
    prop_65_above = FloatField()
    class Meta:
        database = db
        primary_key = False  # 禁止自动生成唯一id列
    @classmethod
    def fetch_all(cls):
        return list(cls.select().dicts())
目录
相关文章
|
1月前
|
人工智能 Python
【02】做一个精美的打飞机小游戏,python开发小游戏-鹰击长空—优雅草央千澈-持续更新-分享源代码和游戏包供游玩-记录完整开发过程-用做好的素材来完善鹰击长空1.0.1版本
【02】做一个精美的打飞机小游戏,python开发小游戏-鹰击长空—优雅草央千澈-持续更新-分享源代码和游戏包供游玩-记录完整开发过程-用做好的素材来完善鹰击长空1.0.1版本
54 7
|
2天前
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
21 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
|
4天前
|
数据采集 数据安全/隐私保护 Python
从零开始:用Python爬取网站的汽车品牌和价格数据
在现代化办公室中,工程师小李和产品经理小张讨论如何获取懂车帝网站的汽车品牌和价格数据。小李提出使用Python编写爬虫,并通过亿牛云爬虫代理避免被封禁。代码实现包括设置代理、请求头、解析网页内容、多线程爬取等步骤,确保高效且稳定地抓取数据。小张表示理解并准备按照指导操作。
从零开始:用Python爬取网站的汽车品牌和价格数据
|
2天前
|
人工智能 测试技术 数据处理
通义灵码 2.0 体验报告:Deepseek 加持下的 Python 开发之旅
通义灵码 2.0 体验报告:Deepseek 加持下的 Python 开发之旅
34 11
|
1月前
|
前端开发 搜索推荐 编译器
【01】python开发之实例开发讲解-如何获取影视网站中经过保护后的视频-用python如何下载无法下载的视频资源含m3u8-python插件之dlp-举例几种-详解优雅草央千澈
【01】python开发之实例开发讲解-如何获取影视网站中经过保护后的视频-用python如何下载无法下载的视频资源含m3u8-python插件之dlp-举例几种-详解优雅草央千澈
109 34
【01】python开发之实例开发讲解-如何获取影视网站中经过保护后的视频-用python如何下载无法下载的视频资源含m3u8-python插件之dlp-举例几种-详解优雅草央千澈
|
6天前
|
API Python
python泛微e9接口开发
通过POST请求向指定IP的API注册设备以获取`secrit`和`spk`。请求需包含`appid`、`loginid`、`pwd`等头信息。响应中包含状态码、消息及`secrit`(注意拼写)、`secret`和`spk`字段。示例代码使用`curl`命令发送请求,成功后返回相关信息。
29 5
|
1月前
|
数据采集 Web App开发 数据可视化
Python用代理IP获取抖音电商达人主播数据
在当今数字化时代,电商直播成为重要的销售模式,抖音电商汇聚了众多达人主播。了解这些主播的数据对于品牌和商家至关重要。然而,直接从平台获取数据并非易事。本文介绍如何使用Python和代理IP高效抓取抖音电商达人主播的关键数据,包括主播昵称、ID、直播间链接、观看人数、点赞数和商品列表等。通过环境准备、代码实战及数据处理与可视化,最终实现定时任务自动化抓取,为企业决策提供有力支持。
|
1月前
|
人工智能 编译器 Python
python已经安装有其他用途如何用hbuilerx配置环境-附带实例demo-python开发入门之hbuilderx编译器如何配置python环境—hbuilderx配置python环境优雅草央千澈
python已经安装有其他用途如何用hbuilerx配置环境-附带实例demo-python开发入门之hbuilderx编译器如何配置python环境—hbuilderx配置python环境优雅草央千澈
41 0
python已经安装有其他用途如何用hbuilerx配置环境-附带实例demo-python开发入门之hbuilderx编译器如何配置python环境—hbuilderx配置python环境优雅草央千澈
|
IDE 开发工具 Android开发
Python开发神器PyCharm,体验下吧
Python开发神器PyCharm,体验下吧
198 0
Python开发神器PyCharm,体验下吧
|
存储 监控 IDE
猪行天下之Python基础——1.3 Python开发IDE之PyCharm(下)
内容简述: 1、为什么要使用IDE? 2、PyCharm的下载安装 3、PyCharm的基本使用 4、PyCharm程序调试 5、共用全局的Python解释器
288 0

热门文章

最新文章