一:最终大屏效果展示
由于生成了html网页只能在本地上显示,这个大屏是动态的,只能显示其中的图片。如果要分享给他人使用,就需要将html源码转为网页。
生成的html源码入口:Python数据分析项目实战01_票房榜单分析和pyecharts大屏可视化 - 飞书云文档 (feishu.cn)
二:背景介绍
该项目给出了2021年前国内和进口的一些电影的票房数据,分别为票房榜.xlsx和电影票房表现概览.xlsx,具体下载或观看入口:
Python数据分析项目实战01_票房榜单分析和pyecharts大屏可视化 - 飞书云文档 (feishu.cn)
我们可以做一些可视化分析,如利用Python中的大屏可视化pyecharts库。由此我们有以下思路:
- 分别对两个表进行数据清洗和整理后再合成一个表
- 表一:电影票房-top50
- 表二:国产-进口年份和电影标签分布
- 表三:国产电影上映首周票房表现 -Top50
- 表四:进口电影上映首周票房表现 -Top50
- 大屏整合展示
三:pyecharts可视化解题步骤
Step1:整合数据
先导入我们所需的库:
import numpy as np
import pandas as pd
from collections import Counter
from pyecharts import options as opts
from pyecharts.charts import *
from pyecharts.commons.utils import JsCode
from pyecharts.globals import ThemeType
from pyecharts.components import Table
from pyecharts.options import ComponentTitleOpts
import datetime
再导入数据进行观察:
data = pd.read_excel("./票房榜.xlsx")
data
如图为数据概览,我们可以提取出我们准备分析的年份,并将票房转为票房/亿以便于数据可视化。
data["年份"] = data["上映日期"].apply(lambda x: str(x.split("-")[0]))
data["票房"] = data["票房"].apply(lambda x: round(x/100000000, 2))
data = data.rename(columns={"票房":"票房/亿"})
然后在处理完第一个数据表后,我们处理第二个数据表,然后将数据表二的数据添加到第一个数据表中,因为数据表1到根据票房排名的顺序对于数据可视化很重要。
pd.set_option('display.max_columns', None) # 可以显示出数据如果所含列名过多也不被省略显示
data_haed = pd.read_excel(r"./电影票房表现概览.xlsx")
data_haed.head(1)
对两个数据进行拼接:
data_haed_all = data.merge(data_haed, how="left", on=['EnMovieID'])
# 用电影票房表现概览.xlsx来补充票房榜.xlsx,使得电影的排名不变。
data_haed_all.head(1)
然后进行如下数据的列名清洗:
data_haed_all["首映票房"] = data_haed_all["首映票房"].apply(lambda x: round(x/100000000, 2))
data_haed_all["首周票房"] = data_haed_all["首周票房"].apply(lambda x: round(x/100000000, 2))
data_haed_all["首周末票房"] = data_haed_all["首周末票房"].apply(lambda x: round(x/100000000, 2))
data_haed_all = data_haed_all.rename(columns={"电影_x":"电影", "首映票房": "首映票房/亿", "首周票房": "首周票房/亿", "首周末票房": "首周末票房/亿"})
data_haed_all = data_haed_all.drop(labels=["EnMovieID","DBOMovieID","EFMTMovieID","电影_y","GenreMainID"],axis=1)
最终得到如下的列名:
colums = list(data_haed_all)
print(colums)
然后我们分别提取出国内和进口的数据:
data_all = data_haed_all[data_haed_all["榜单类别"] == "全部"]
data_china = data_haed_all[data_haed_all["榜单类别"] == "国产"]
data_foreign = data_haed_all[data_haed_all["榜单类别"] == "进口"]
data_cat = [data_all, data_china, data_foreign]
cat = ["全部", "国产","进口"]
Step2:表一:电影票房-top50
接下的代码较为复杂,就不逐行解释了,想具体了解的可以逐行进行阅读,其中涉及一些前端知识,比如网页渲染:
line_max = max(max(data_all['场均人次'].tolist()), max(data_all['平均票价'].tolist()))
bar_max = max(data_all['票房/亿'].tolist())
bar_all = (
Bar(init_opts=opts.InitOpts(width="1000px", height="600px",theme='light')) # 设置图表大小
.add_xaxis(xaxis_data=data_all['电影'].tolist()) # x轴
.add_yaxis(
series_name="票房/亿", # 柱形图系列名称
y_axis=data_all['票房/亿'].tolist(), # 数据
label_opts=opts.LabelOpts(is_show=False, position='top', formatter="{c}/亿"), # 显示数据标签
itemstyle_opts={
"normal": {
"color": JsCode("""new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#ee3f4d'
}, {
offset: 1,
color: '#eea2a4'
}], false)""", ),
"opacity": 0.8,
# "barBorderRadius": [20, 20, 0, 0],
'shadowBlur': 8,
'shadowColor': 'rgba(0, 0, 0, 0.4)',
'shadowOffsetX': 10,
'shadowOffsetY': 10,
'borderColor': 'rgb(220,220,220)',
'borderWidth': 1
}}
)
.extend_axis( # 设置次坐标轴
yaxis=opts.AxisOpts(
name="", # 次坐标轴名称
type_="value", # 次坐标手类型
min_=-2 * line_max, # 最小值
max_=2 * line_max, # 最大值
is_show=False, # 是否显示
axisline_opts=opts.AxisLineOpts(is_show=False, # y轴线不显示
linestyle_opts=opts.LineStyleOpts(color='#2486b9')), # 设置线颜色, 字体颜色也变
axistick_opts=opts.AxisTickOpts(is_show=False), # 刻度线不显示
axislabel_opts=opts.LabelOpts(formatter="{value}"), # 次坐标轴数据显示格式
)
)
.set_global_opts(title_opts=opts.TitleOpts(title="电影票房 - top50", # 标题
title_textstyle_opts=opts.TextStyleOpts(font_size=20), # 主标题字体大小
subtitle="国产/进口", # 次坐标轴
pos_left='center',
pos_top='0.8%'), # 标题位置
legend_opts=opts.LegendOpts(is_show=True,
pos_top=50,
orient="horizontal",
), # 不显示图例
tooltip_opts=opts.TooltipOpts(
trigger="axis",
axis_pointer_type="shadow"
), # 提示框
xaxis_opts=opts.AxisOpts(name='',
type_='category',
axislabel_opts=opts.LabelOpts(rotate=360),
),
yaxis_opts=opts.AxisOpts(type_="value", # y轴类型
max_=bar_max,
name='票房/亿', # y轴名称
name_location='middle', # y轴名称位置
name_gap=70, # y轴名称距离轴线距离
axistick_opts=opts.AxisTickOpts(is_show=False), # 刻度线
axisline_opts=opts.AxisLineOpts(is_show=False), # y轴线
splitline_opts=opts.SplitLineOpts(is_show=True), # y轴网格线
axislabel_opts=opts.LabelOpts(formatter="{value}"),
), # 轴标签显示方式
datazoom_opts=opts.DataZoomOpts(is_zoom_lock=False)
)
)
line_all = (
Line()
.add_xaxis(xaxis_data=data_all['电影'].tolist()) # x轴
.add_yaxis(
series_name="场均人次", # 名称
yaxis_index=1, # 次坐标
is_smooth=True, # 线条样式 , 是否设置成圆滑曲线
y_axis=data_all['场均人次'].tolist(),
itemstyle_opts={
"normal": {
"color": JsCode(
"""new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#2486b9'
}, {
offset: 1,
color: '#FF00FF'
}], false)""", ),
"opacity": 0.7,
"barBorderRadius": [45, 45, 45, 45],
"shadowColor": 'rgb(0, 160, 221)',
}},
linestyle_opts={
'normal': {
'width': 3,
'shadowColor': 'rgba(0, 0, 0, 0.5)',
'shadowBlur': 5,
'shadowOffsetY': 10,
'shadowOffsetX': 10,
'curve': 0.5,
'color': '#2486b9'
}
},
label_opts=opts.LabelOpts(is_show=False), # 显示数据标签
)
.add_yaxis(
series_name="平均票价", # 名称
yaxis_index=1, # 次坐标
is_smooth=True, # 线条样式 , 是否设置成圆滑曲线
y_axis=data_all['平均票价'].tolist(),
itemstyle_opts={
"normal": {
"color": JsCode(
"""new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#1a6840'
}, {
offset: 1,
color: '#66c18c'
}], false)""", ),
"opacity": 0.7,
"barBorderRadius": [45, 45, 45, 45],
"shadowColor": 'rgb(0, 160, 221)',
}},
linestyle_opts={
'normal': {
'width': 3,
'shadowColor': 'rgba(0, 0, 0, 0.5)',
'shadowBlur': 5,
'shadowOffsetY': 10,
'shadowOffsetX': 10,
'curve': 0.5,
'color': '#66c18c'
}
},
label_opts=opts.LabelOpts(is_show=False), # 显示数据标签
)
)
bar_all.overlap(line_all) # 图表组合
bar_all.render_notebook()
Step3:表二:国产-进口年份和电影标签分布
先计算计算上榜电影年份汇总:
data_china_year = data_china["年份"].value_counts()
data_foreigna_year = data_foreign["年份"].value_counts()
可以统计不同年份的数量分布。
然后分别计算国内和进口的上榜电影标签汇总:
tags_china = []
tag_china = data_china['作品类型'].tolist()
for t in tag_china:
try:
for i in t.split('/'):
tags_china.append(i)
except:
continue
tags_china_pair = []
for key, value in Counter(tags_china).items():
tags_china_pair.append([key, value])
print(tags_china_pair)
tags_foreign = []
tag_foreign = data_foreign['作品类型'].tolist()
for t in tag_foreign:
try:
for i in t.split('/'):
tags_foreign.append(i)
except:
continue
tags_foreign_pair = []
for key, value in Counter(tags_foreign).items():
tags_foreign_pair.append([key, value])
得到如下的类似结果:
然后利用类似于Step2得到表一的方法得到表二:
pie = (
Pie(init_opts=opts.InitOpts(width="1000px", height="900px", theme='light'))
.add('国产年份', [list(z) for z in zip(data_china_year.index.tolist(),
data_china_year.values.tolist())],
radius=['55', '100'],
center=['33%', '30%']
)
.add('进口', [list(z) for z in zip(data_foreigna_year.index.tolist(),
data_foreigna_year.values.tolist())],
radius=['55', '100'],
center=['75%', '30%'])
.add('国产电影标签', tags_china_pair,
radius=['55', '100'],
center=['33%', '80%']
)
.add('进口电影标签', tags_foreign_pair,
radius=['55', '100'],
center=['75%', '80%']
)
.set_series_opts(
label_opts=opts.LabelOpts(formatter="{b}: {c}", font_size=14),
tooltip_opts=opts.TooltipOpts(trigger="item", formatter="{a} <br/>{b}: {c} ({d}%)"),
itemstyle_opts={"normal": {
'shadowBlur': 2,
"borderColor": '#87CEFA',
"borderWidth": 3,
'shadowColor': '#87CEFA',
'opacity': 1
}
})
.set_global_opts(
legend_opts=opts.LegendOpts(is_show=False, pos_top='5%'),
title_opts=[
dict(
text=f'国产-进口上榜 - TOP50 - 详情分布',
left='center',
top='1%',
textStyle=dict(
color='#000',
fontSize=24)),
dict(
text=f'国产分布',
left='28%',
top='10%',
textStyle=dict(
color='#999999',
fontSize=18)),
dict(
text=f'进口分布',
left='70%',
top='10%',
textStyle=dict(
color='#999999',
fontSize=18)),
dict(
text=f'国产电影标签',
left='28%',
top='55%',
textStyle=dict(
color='#999999',
fontSize=18)),
dict(
text=f'进口电影标签',
left='70%',
top='55%',
textStyle=dict(
color='#999999',
fontSize=18)),
],
)
)
pie.render_notebook()
Step4:表三:国产电影上映首周票房表现 -Top50
再利用我们整合得到的数据与之前类似的方法得到表三:
bar_china = (
Bar(init_opts=opts.InitOpts(width="1200px", height="600px", theme='light')) # 设置图表大小
.add_xaxis(xaxis_data=data_china['电影'].tolist()) # x轴
.add_yaxis(
series_name="首映票房/亿", #柱形图系列名称
stack='stack1',
y_axis=data_china['首映票房/亿'].tolist(), # 数据
label_opts=opts.LabelOpts(is_show=False,position='top',formatter="{c} 亿"), # 显示数据标签
itemstyle_opts={
"normal": {
"color": JsCode("""new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#126bae'
}, {
offset: 1,
color: '#619ac3'
}], false)""", ),
"opacity": 0.8,
# "barBorderRadius": [20, 20, 0, 0],
'shadowBlur': 4,
'shadowColor': 'rgba(0, 0, 0, 0.3)',
'shadowOffsetX': 5,
'shadowOffsetY': 5,
'borderColor': 'rgb(220,220,220)',
'borderWidth': 1
}}
)
.add_yaxis(
series_name="首周票房/亿", #柱形图系列名称
stack='stack1',
y_axis=data_china['首周票房/亿'].tolist(), # 数据
label_opts=opts.LabelOpts(is_show=False,position='top',formatter="{c} 亿"), # 显示数据标签
itemstyle_opts={
"normal": {
"color": JsCode("""new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#ea7293'
}, {
offset: 1,
color: '#ec8aa4'
}], false)""", ),
"opacity": 0.8,
# "barBorderRadius": [20, 20, 0, 0],
'shadowBlur': 4,
'shadowColor': 'rgba(0, 0, 0, 0.3)',
'shadowOffsetX': 5,
'shadowOffsetY': 5,
'borderColor': 'rgb(220,220,220)',
'borderWidth': 1
}}
)
.add_yaxis(
series_name="首周末票房/亿", #柱形图系列名称
stack='stack1',
y_axis=data_china['首周末票房/亿'].tolist(), # 数据
label_opts=opts.LabelOpts(is_show=False,position='top',formatter="{c} 亿"), # 显示数据标签
itemstyle_opts={
"normal": {
"color": JsCode("""new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#9eccab'
}, {
offset: 1,
color: '#a4cab6'
}], false)""", ),
"opacity": 0.8,
# "barBorderRadius": [20, 20, 0, 0],
'shadowBlur': 4,
'shadowColor': 'rgba(0, 0, 0, 0.3)',
'shadowOffsetX': 5,
'shadowOffsetY': 5,
'borderColor': 'rgb(220,220,220)',
'borderWidth': 1
}}
)
.reversal_axis()
# .set_series_opts(label_opts=opts.LabelOpts(position="right"))
.set_global_opts(title_opts=opts.TitleOpts(title="国产电影上映首周票房表现 -Top50",# 标题
title_textstyle_opts=opts.TextStyleOpts(font_size=20), #主标题字体大小
subtitle="", # 次坐标轴
pos_left='center'),# 标题位置
legend_opts=opts.LegendOpts(
is_show=True,
pos_top=30,
orient="horizontal"
), # 不显示图例
tooltip_opts=opts.TooltipOpts(
trigger="axis",
axis_pointer_type="shadow"
),# 提示框
yaxis_opts=opts.AxisOpts(name='',
type_='category',
# axislabel_opts=opts.LabelOpts(rotate=30),
),
xaxis_opts=opts.AxisOpts(type_="value", # y轴类型
# max_=5000000,
name='', # y轴名称
name_location='middle', # y轴名称位置
name_gap=70, # y轴名称距离轴线距离
axistick_opts=opts.AxisTickOpts(is_show=False), # 刻度线
axisline_opts=opts.AxisLineOpts(is_show=False), # y轴线
splitline_opts=opts.SplitLineOpts(is_show=True), # y轴网格线
axislabel_opts=opts.LabelOpts(formatter="{value}")), # 轴标签显示方式
datazoom_opts=opts.DataZoomOpts(is_zoom_lock=False,
orient="vertical")
)
)
bar_china.render_notebook()
Step5:表四:进口电影上映首周票房表现 -Top50
与Step4类似得到表四:
bar_foreign = (
Bar(init_opts=opts.InitOpts(width="1200px", height="600px", theme='light')) # 设置图表大小
.add_xaxis(xaxis_data=data_foreign['电影'].tolist()) # x轴
.add_yaxis(
series_name="首映票房/亿", #柱形图系列名称
stack='stack1',
y_axis=data_foreign['首映票房/亿'].tolist(), # 数据
label_opts=opts.LabelOpts(is_show=False,position='top',formatter="{c} 亿"), # 显示数据标签
itemstyle_opts={
"normal": {
"color": JsCode("""new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#126bae'
}, {
offset: 1,
color: '#619ac3'
}], false)""", ),
"opacity": 0.8,
# "barBorderRadius": [20, 20, 0, 0],
'shadowBlur': 4,
'shadowColor': 'rgba(0, 0, 0, 0.3)',
'shadowOffsetX': 5,
'shadowOffsetY': 5,
'borderColor': 'rgb(220,220,220)',
'borderWidth': 1
}}
)
.add_yaxis(
series_name="首周票房/亿", #柱形图系列名称
stack='stack1',
y_axis=data_foreign['首周票房/亿'].tolist(), # 数据
label_opts=opts.LabelOpts(is_show=False,position='top',formatter="{c} 亿"), # 显示数据标签
itemstyle_opts={
"normal": {
"color": JsCode("""new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#ea7293'
}, {
offset: 1,
color: '#ec8aa4'
}], false)""", ),
"opacity": 0.8,
# "barBorderRadius": [20, 20, 0, 0],
'shadowBlur': 4,
'shadowColor': 'rgba(0, 0, 0, 0.3)',
'shadowOffsetX': 5,
'shadowOffsetY': 5,
'borderColor': 'rgb(220,220,220)',
'borderWidth': 1
}}
)
.add_yaxis(
series_name="首周末票房/亿", #柱形图系列名称
stack='stack1',
y_axis=data_foreign['首周末票房/亿'].tolist(), # 数据
label_opts=opts.LabelOpts(is_show=False,position='top',formatter="{c} 亿"), # 显示数据标签
itemstyle_opts={
"normal": {
"color": JsCode("""new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#9eccab'
}, {
offset: 1,
color: '#a4cab6'
}], false)""", ),
"opacity": 0.8,
# "barBorderRadius": [20, 20, 0, 0],
'shadowBlur': 4,
'shadowColor': 'rgba(0, 0, 0, 0.3)',
'shadowOffsetX': 5,
'shadowOffsetY': 5,
'borderColor': 'rgb(220,220,220)',
'borderWidth': 1
}}
)
.reversal_axis()
# .set_series_opts(label_opts=opts.LabelOpts(position="right"))
.set_global_opts(title_opts=opts.TitleOpts(title="进口电影上映首周票房表现 -Top50",# 标题
title_textstyle_opts=opts.TextStyleOpts(font_size=20), #主标题字体大小
subtitle="", # 次坐标轴
pos_left='center'),# 标题位置
legend_opts=opts.LegendOpts(
is_show=True,
pos_top=30,
orient="horizontal"
), # 不显示图例
tooltip_opts=opts.TooltipOpts(
trigger="axis",
axis_pointer_type="shadow"
),# 提示框
yaxis_opts=opts.AxisOpts(name='',
type_='category',
# axislabel_opts=opts.LabelOpts(rotate=30),
),
xaxis_opts=opts.AxisOpts(type_="value", # y轴类型
# max_=5000000,
name='', # y轴名称
name_location='middle', # y轴名称位置
name_gap=70, # y轴名称距离轴线距离
axistick_opts=opts.AxisTickOpts(is_show=False), # 刻度线
axisline_opts=opts.AxisLineOpts(is_show=False), # y轴线
splitline_opts=opts.SplitLineOpts(is_show=True), # y轴网格线
axislabel_opts=opts.LabelOpts(formatter="{value}")), # 轴标签显示方式
datazoom_opts=opts.DataZoomOpts(is_zoom_lock=False,
orient="vertical")
)
)
bar_foreign.render_notebook()
Step6:大屏整合展示
最后到了整合四个表进行大屏可视化的最后步骤:
from pyecharts.charts import Page
page = Page(layout=Page.DraggablePageLayout, page_title="大屏展示")
page.add(bar_all,pie,bar_china,bar_foreign)
# 先保存到test.html 然后打开,拖拽图片自定义布局, 之后记得点击左上角“save config”对布局文件进行保存。
# 会生成一个chart_config.json的文件,这其中包含了每个图表ID对应的布局位置
page.render('test0.html')
bar_all,pie,bar_china,bar_foreign分别为我们得到的表一,表二,表三,表四。
# 然后运行下面这行代码。保存布局好的的仪表盘文件。
page.save_resize_html('test0.html', cfg_file='chart_config.json', dest='大屏可视化.html')
然后最终可以得到文章开头的大屏可视化网页。可以在本地直接查看html的渲染效果,也可以得到Html代码。
这些步骤展示了如何用Python中的pyecharts库来得到数据的大屏可视化分析。
点下关注,分享更多AI,数据分析和量化金融实用教程和实战项目。