世界自杀率数据看板
- 1 项目效果图
- 2 项目架构
- 3 文件介绍和功能完善
- 3.1 assets文件夹介绍
- 3.2 app.py和index.py文件完善
- 3.3 header.py文件完善
- 3.4 api.py/api.ipynb文件完善
- 3.4.1 获取Dropdown组件中的下拉标签信息
- 3.4.2 获取Rangeslider组件中的时间区间
- 3.4.3 获取Checklist组件中的年龄划分
- 3.5 layoutleft.py文件完善
- 3.5.1 设置Dropdown组件
- 3.5.2 设置Rangeslider组件
- 3.5.3 设置Checklist组件
- 3.6 layoutright.py文件完善
- 4 样式修改
- 4.1 整体样式修改
- 4.2 header.py文件中样式修改
- 4.3 layoutleft.py文件中样式修改
- 4.4 layoutright.py文件中样式修改
- 5 小bug
手动反爬虫:原博地址 https://blog.csdn.net/lys_828/article/details/128624945
知识梳理不易,请尊重劳动成果,文章仅发布在CSDN网站上,在其他网站看到该博文均属于未经作者授权的恶意爬取信息
1 项目效果图
整个项目的页面包含三部分,由上左右三栏构成。项目已上传至 个人Github仓库 。 项目头部是整个面板的标题,左侧是筛选条件,右侧是依据筛选条件绘制出的散点图。
2 项目架构
项目中各文件名称与对应功能见下表
3 文件介绍和功能完善
3.1 assets文件夹介绍
assets文件夹中就是加载的样式和图片,样式这里可以使用之前已经下载好的bootstrap.min.css样式(也可以按照 项目6.2bootstrap组件 中的介绍下载其它的样式模板),本次项目中不需要加载本地图片。
3.2 app.py和index.py文件完善
主框架就是app.py项目初始化文件和index.py主程序运行文件,其中app.py文件中的信息较为简单,就是创建一个dash的应用,代码如下
index.py文件中引入初始化后的应用,然后进行布局及运行初始化设置。布局的主体是上下两个部分,上面是项目的头部信息,下方是分为一行两列。
头部只有一个信息,使用HeaderInfo()填充内容,该函数分配在header.py文件中;而下部中左侧是有三个筛选组件,分别用三个函数填充,此三个函数分配在layoutleft.py文件中;右侧只有一个图形展示,使用Scatterchart()填充内容,该函数分配在layoutright.py文件中,该文件的全部代码如下。
from dash import html
from app import app
import dash_bootstrap_components as dbc
from header import HeaderInfo
from layoutleft import DropdownInfo,RangeSliderInfo,ChecklistInfo
from layoutright import Scatterchart
app.layout = html.Div(
[
html.Div([HeaderInfo()]),
html.Div([
dbc.Row(
[
dbc.Col([DropdownInfo(),RangeSliderInfo(),ChecklistInfo()],width=4),
dbc.Col([Scatterchart()])
]
)
])
]
)
if __name__ == '__main__':
app.run_server(debug=True)
对应的剩余文件中的信息如下:(api.py和api.ipynb文件暂时没有内容)
3.3 header.py文件完善
该文件的功能就是显示项目标题,并居中,设置相对简答,全部代码如下。
from dash import html
def HeaderInfo():
return html.Div(
[
html.H1('World Suicides Data')
]
)
保存文件后,运行index.py,提示点击网址:http://127.0.0.1:8050/,刷线页面后,输出结果如下。
3.4 api.py/api.ipynb文件完善
其中api.py文件是为提供数据接口,api.iypnb文件方便进行数据处理和调式工作。下方左侧筛选的依据有国家、年份和年龄范围,所以针对此条件先在api.ipynb文件中进行数据处理,数据文件已放置在该项目下的data文件夹中。首先切换程序的执行路径,利用os.chdir()
函数,输入当前项目所在的文件路径,然后在读入数据文件,代码及输出结果如下。
3.4.1 获取Dropdown组件中的下拉标签信息
获取国家/地区的唯一值,并去除缺失值None
,代码如下。
#获取国家信息的唯一值
country_ls = df['country'].unique().tolist()
#检验列表中是否存在缺失值None
country_ls.count(None)
输出结果如下。
3.4.2 获取Rangeslider组件中的时间区间
数据时间跨度的获取,只需要求解出year
字段中的最小值和最大值即可
3.4.3 获取Checklist组件中的年龄划分
年龄分组获取即是对age
字段进行唯一值的获取。在输出的结果中如果使用列表的sort()
排序功能,发现年龄分组字段是按照字符串的规则进行排序,先比对第一个字符的大小,如果第一个字符相同, 再比较第二个字符,以此类推。但是排序的结果不满足需要,因此可借助python中自带的sorted()
函数,自定义排序规则,代码如下。
#获取年龄分组情况
age = df['age'].unique().tolist()
#使用列表的排序功能
age.sort()
#借助sorted()函数进行自定义排序规则设置
age_ordered = sorted(age,key=lambda x: int(x.split('-')[0]) if '-' in x else int(x[:2]))
输出结果如下。
数据成功获取后,把此部分代码转移到api.py文件中,此时该文件中的全部代码如下。
#切换程序的执行路径
import os
os.chdir('d:/Data Science/plotly学习/个人/【11. World suicide rate】Dropdown-Rangedlider-checklist-scatter')
#将文件数据读入到python中
import pandas as pd
df = pd.read_csv('data/suicide rates.csv')
#获取国家信息的唯一值,需要核实是否存在缺失值None
country_ls = df['country'].unique().tolist()
#获取数据的时间跨度
year_min,year_max = df['year'].min(),df['year'].max()
#获取年龄分组情况
age = df['age'].unique().tolist()
#借助sorted()函数进行自定义排序规则设置
age_ordered = sorted(age,key=lambda x: int(x.split('-')[0]) if '-' in x else int(x[:2]))
3.5 layoutleft.py文件完善
3.5.1 设置Dropdown组件
该文件的功能就是设置三个筛选的组件,首先完善第一个Dropdown组件,导入api.py中的全部数据变量,然后设置文字提醒,组件标签信息和id,代码如下。
from dash import html,dcc
from api import country_ls,year_min,year_max,age_ordered
def DropdownInfo():
return html.Div(
[
html.H3('Select Country:'),
dcc.Dropdown(
country_ls,
'Japan',
id='dpd'
)
]
)
保存文件后,刷新页面,输出的内容如下。
3.5.2 设置Rangeslider组件
可以直接把项目9中的Rangeslider组件设置的代码直接复制粘贴过来,然后修改里面的起始值和id即可,代码如下。
def RangeSliderInfo():
return html.Div(
[
html.H3('Select Year:'),
dcc.RangeSlider(
year_min,year_max,1,
marks=None,
value=[1995,2005],
tooltip={"placement": "bottom", "always_visible": True},
id='rangeslider',
)
]
)
保存文件后,刷新网址,此时页面输出结果如下。
3.5.3 设置Checklist组件
第一次使用Checklist组件,可以参考官网示例,如下。其中第一个列表里面包含了所有的内容,第二个列表是默认选择的值。
应用到项目中,丰富代码,如下。
def ChecklistInfo():
return html.Div(
[
html.H3('Select Platform:'),
dcc.Checklist(
age_ordered,
['35-54 years','55-74 years'],
id = 'checklist'
)
]
)
保存文件后,刷新网址,此时页面输出结果如下。
3.6 layoutright.py文件完善
该文件的功能是根据左侧的筛选条件进行散点图绘制,plotly绘制散点图官网示例,如下。
首先获取图表展示的数据,即按照国家、时间、年龄分组汇总求和的数据,形成一个新的数据集,方便在绘制图形时直接调用,代码及输出结果如下。
然后把此部分代码转移到api.py文件中并导入到layoutright.py文件中,再按照官网示例完善scatter图形绘制。
from dash import Input,Output,dcc
from app import app
import plotly.graph_objects as go
from api import suicide_df
def Scatterchart():
return dcc.Graph(id='scatter',config={'displayModeBar': False})
@app.callback(
Output('scatter','figure'),
[Input('dpd','value'),Input('rangeslider','value'),Input('checklist','value')]
)
def update(select_country, slider_year, radio_items):
#print(select_country, slider_year, radio_items)
df = suicide_df[(suicide_df['country'] == select_country) &
(suicide_df['year'] >= slider_year[0]) &
(suicide_df['year'] <= slider_year[1]) &
(suicide_df['age'].isin(radio_items))]
fig = go.Figure(
go.Scatter(
x=df['year'],
y=df['suicides_no'],
text = df['sex'],
textposition = 'top center',
mode = 'markers + text',
marker = dict(
size = df['suicides_no'] / 250,
color = df['suicides_no'],
colorscale = 'HSV',
showscale = False,
line = dict(
color = 'MediumPurple',
width = 2
)),
hoverinfo='text',
hovertext=
'<b>Country</b>: ' + df['country'].astype(str) + '<br>' +
'<b>Age</b>: ' + df['age'].astype(str) + '<br>' +
'<b>Sex</b>: ' + df['sex'].astype(str) + '<br>' +
'<b>Year</b>: ' + df['year'].astype(str) + '<br>' +
'<b>Population</b>: ' + [f'{x:,.0f}' for x in df['population']] + '<br>' +
'<b>Suicides/100k pop</b>: ' + [f'{x:,.0f}' for x in df['suicides/100k pop']] + '<br>' +
'<b>Suicides</b>: ' + [f'{x:,.0f}' for x in df['suicides_no']] + '<br>'
)
)
fig.update_layout(
margin=dict(
l=0,
r=0,
t=0,
b=0
)
)
return fig
保存文件后,刷新网址,此时页面输出结果如下。
4 样式修改
4.1 整体样式修改
在assets文件夹下新建一个setting.css文件,设置整体风格。主要是背景、边缘和字体颜色的设置。
此时页面样式输出如下。
4.2 header.py文件中样式修改
只有一个主题文字,需要做的就是进行居中处理即可。根据实际显示,又调整了一下文字和下方内容的边距。
4.3 layoutleft.py文件中样式修改
首先把项目10中的卡片容器应用到这里的左右两部分。由于项目的主题背景是偏黑,所以颜色上修改一下,指定为黑色调颜色。
然后应用到左侧栏中,需要注意该属性添加的位置是在index.py文件中,如下。
保存文件后,刷新网址,此时页面输出结果如下。
接着修改组件颜、间距等属性。先调整Dropdown组件的属性,直接把项目10中此属性全部复制过来,然后改一下背景颜色和字体颜色即可,代码如下。
/* width */
::-webkit-scrollbar {
width: 10px !important;
display: block !important;
}
/* Track */
::-webkit-scrollbar-track {
background: #232c37 !important;
border-radius: 10px !important;
display: block !important;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: #363535 !important;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: white !important;
}
#dpd * {
background-color: #191a1a !important;
color: #f7f8f9 !important;
font-size: 10px !important;
}
.Select-control{
border: 3px solid #323844 !important;
}
.Select-menu-outer{
overflow: hidden !important;
border-color: #373838 !important;
}
保存文件后,刷新网址,此时页面输出结果如下。
然后调整三个组件直接的间距,代码修改如下。
对于Rangeslider组件中的滑块中间的区域颜色以及按钮的边缘颜色也可以进行设置,这里按照自己的想法进行修改,代码如下。
.rc-slider-track{
background-color: rgb(234, 13, 112) !important;
}
.rc-slider-handle{
border-color: rgb(234, 13, 112) !important;
}
最后是关于Checklist组件的设置,当前版本中默认就是横向排布,尝试了很多参数后都没有办法实现垂直排列,如下。
那就只能自己自定义属性,设置一个columns属性,设置组件的宽度为三分之一,然后左对齐,设置适当的边距,完成目标样式,代码及文件修改内容如下。此处显示为全部添加指定参数时的使用方法,也可以采用最初的简写方式。
保存文件后,刷新网址,此时页面输出结果如下。
4.4 layoutright.py文件中样式修改
在项目10中已经处理过plotly绘制图形背景与项目主题背景融合的问题,添加两行代码即可解决,但是要注意设置一下字体颜色,不然文字标注就看不清楚了,全部代码如下。
from dash import Input,Output,dcc,html
from app import app
import plotly.graph_objects as go
from api import suicide_df
def Scatterchart():
return html.Div(id = 'content')
@app.callback(
Output('content','children'),
[Input('dpd','value'),Input('rangeslider','value'),Input('checklist','value')]
)
def update(select_country, slider_year, radio_items):
print(select_country, slider_year, radio_items)
df = suicide_df[(suicide_df['country'] == select_country) &
(suicide_df['year'] >= slider_year[0]) &
(suicide_df['year'] <= slider_year[1]) &
(suicide_df['age'].isin(radio_items))]
fig = go.Figure(
go.Scatter(
x=df['year'],
y=df['suicides_no'],
text = df['sex'],
textposition = 'top center',
mode = 'markers + text',
marker = dict(
size = df['suicides_no'] / 250,
color = df['suicides_no'],
colorscale = 'HSV',
showscale = False,
line = dict(
color = 'MediumPurple',
width = 2
)),
hoverinfo='text',
hovertext=
'<b>Country</b>: ' + df['country'].astype(str) + '<br>' +
'<b>Age</b>: ' + df['age'].astype(str) + '<br>' +
'<b>Sex</b>: ' + df['sex'].astype(str) + '<br>' +
'<b>Year</b>: ' + df['year'].astype(str) + '<br>' +
'<b>Population</b>: ' + [f'{x:,.0f}' for x in df['population']] + '<br>' +
'<b>Suicides/100k pop</b>: ' + [f'{x:,.0f}' for x in df['suicides/100k pop']] + '<br>' +
'<b>Suicides</b>: ' + [f'{x:,.0f}' for x in df['suicides_no']] + '<br>'
)
)
fig.update_layout(
paper_bgcolor='#202020',
plot_bgcolor='#202020',
font=dict(
# family="Lato",
size=14,
color="white"),
margin=dict(
l=0,
r=0,
t=0,
b=0
),
xaxis=dict(title='<b>Year</b>',
color='white',
showline=True,
showgrid=False,
linecolor='white',
zeroline=False
),
yaxis=dict(
title= '<b>Suicides</b>',
color= 'white',
showline= False,
showgrid= True,
gridcolor='#5a5a5a',
tickfont={
'family': 'Aerial',
'color': 'white',
'size': 12
},
zeroline=False
)
)
return [
html.H3(f'Suicide Datas: {select_country}',style={'textAlign':'center'}),
dcc.Graph(figure=fig,config={'displayModeBar': False})
]
保存文件后,刷新网址,此时页面输出结果如下。
5 小bug
一不小心发现Checklist组件中的标签顺序不对,仔细检查一下发现在指定时又进行了sorted()
一下,于是干脆就直接使用最初简单的样式(或者直接删除sorted函数也可),修改及输出对比如下。