(数据科学学习手札121)Python+Dash快速web应用开发——项目结构篇
本文示例代码已上传至我的
Github仓库https://github.com/CNFeffery/DataScienceStudyNotes
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应用所依赖静态资源文件的目录,如依赖的css、js、favicon.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_page、age_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相关知识,分别定义了数据模型对应了七普中的年龄结构、性别结构以及六普七普对比数据表,并在views、callbacks等涉及的子模块中导入并调用,以年龄结构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())
而本文案例中涉及到的数据可视化内容均由plotly及plotly.express实现,关于这部分内容我会在之后的进阶教程中加以概括。
本文完整项目案例源码+附件你可以在文章开头链接页面查看和下载。
下期我将带大家学习如何在Linux、Windows等系统中正式部署Dash应用,敬请期待。
以上就是本文的全部内容,欢迎在评论区发表你的意见和想法。
(数据科学学习手札121)Python+Dash快速web应用开发——项目结构篇的更多相关文章
- (数据科学学习手札102)Python+Dash快速web应用开发——基础概念篇
本文示例代码与数据已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的新系列教程Python+Dash快 ...
- (数据科学学习手札108)Python+Dash快速web应用开发——静态部件篇(上)
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
- (数据科学学习手札109)Python+Dash快速web应用开发——静态部件篇(中)
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
- (数据科学学习手札112)Python+Dash快速web应用开发——表单控件篇(上)
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
- (数据科学学习手札115)Python+Dash快速web应用开发——交互表格篇(上)
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
- (数据科学学习手札116)Python+Dash快速web应用开发——交互表格篇(中)
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
- (数据科学学习手札117)Python+Dash快速web应用开发——交互表格篇(下)
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
- (数据科学学习手札118)Python+Dash快速web应用开发——特殊部件篇
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
- (数据科学学习手札120)Python+Dash快速web应用开发——整合数据库
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
随机推荐
- Edge 浏览器开发工具新增了 3D 视图,你尝试了吗?
在使用开发者工具的时候,无意间发现了一个3D面板,如下: 仔细想想,这应该是之前 Firefox 的特性啊,不过后来去掉了,说是太难维护,没想到 Edge 也添加了这个特性. 使用该特性,你可以完成如 ...
- 【DB宝45】MySQL高可用之MGR+Consul架构部署
目录 一.MGR+Consul架构简介 二.搭建MGR 2.1.申请3台MGR机器 2.2.3台主机安装MySQL环境 2.3.修改MySQL参数 2.4.重启MySQL环境 2.5.安装MGR插件( ...
- 走进springboot
SpringBoot基础 核心思想---自动装配---约定大于配置 开发环境:jdk1.8.maven.springboot.idea 一.快速构建一个springboot项目 1.1.进入sprin ...
- (数据科学学习手札115)Python+Dash快速web应用开发——交互表格篇(上)
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
- 痞子衡嵌入式:关于恩智浦入驻B站的一些思考
故事起源于这周五的一封公司邮件,标题是"恩智浦B站首支原创视频播放量破万",公司Marcom部门特地群发了这个邮件给全体员工,并鼓励大家积极DIY工作相关的有趣视频,为公司这个萌新 ...
- [Fundamental of Power Electronics]-PART I-3.稳态等效电路建模,损耗和效率-3.3 等效电路模型的构建
3.3 等效电路模型的构建 接下来,让我们完善直流变压器模型来解决变换器的损耗问题.这将使用众所周知的电路分析技术来确定变换器的电压,电流和效率. 在前面的章节,我们利用电感伏秒平衡和电容电荷平衡得到 ...
- Redis解读(2):Redis的Java客户端
Redis的Java客户端 Redis不仅使用命令客户端来操作,而且可以使用程序客户端操作,其实配置和实现起来也非常容易. 现在基本上主流的语言都有客户端支持,比如Java.C.C#.C++.php. ...
- C#修改AD账号及密码
在使用AD域环境搭建的账号系统修改密码的时候比较麻烦一般需要管理员在域环境去进行对用户的密码进行修改. 以下就是用来查询和修改AD域密码的方法. 1 /// <summary> 2 /// ...
- Flowable与springBoot项目整合及出现的问题
Flowable与springBoot项目整合及出现的问题 单纯地将Flowable和springBoot整合,使用mysql作为数据库,整合中踩了两个坑,见文末. 在pom中添加依赖 <?xm ...
- C程序数组算法 — 冒泡法排序【前冒 || 后冒】
第一种写法(前冒泡): /* C程序数组算法 - 冒泡法排序 * 此例子按照 大 -> 小 排序 * 原理:两两相比较,然后进行大小对调 * 比较次数: n^2 次 * 说明:冒泡排序是相对稳定 ...