前言
党的十八大以来,国产电影产业与事业快速发展,创作水平不断提高,题材类型丰富多元,受众口碑不断提升,在市场竞争中表现愈发突出,已成为广大人民群众首选的文化消费形式。国产电影的高质量发展,有着多重的表现。
首先是主旋律电影的复苏。既往,主旋律似乎和院线电影难以相容,取得商业成功的主旋律电影少之又少,而一些商业电影的价值取向也似乎与主旋律貌合神离。近年来,随着国内电影工业水平不断提升,电影作品对主旋律的表达方式也更为细腻深入,观众对主旋律影片的认可度逐渐提高。诸如2016年的《湄公河行动》、2018年的《红海行动》、2019年的《我和我的祖国》、2020年的《八佰》《我和我的家乡》、2021年的《长津湖》《中国医生》等影片,充分吸纳了类型片的叙事手段,凭借其精良的制作与深厚的情怀,在票房、口碑上实现了双丰收,《长津湖》更是打破了影史票房纪录,创造了中国电影的奇迹。
其次是商业电影的繁盛。过去的十年是中国电影扩展市场,开疆拓土的十年。2012年以来,电影市场保持着高速增长的态势,2012年全国银幕数有13118块,到2021年达到了82248块,基本覆盖了全国的城市与城镇;2019年全国总票房达到了642亿元,其后由于疫情影响票房总量有一定程度下降,但也超越北美成为世界第一。从2012年《人再囧途之泰囧》拿下12亿票房成为首部超十亿票房国产电影并获得当年票房冠军之后,国产电影开始频频打破票房纪录,在好莱坞电影的冲击下茁壮成长,让引进片称霸票房榜的时代成为了过去式。2015年,《捉妖记》取得24亿票房;2016年,《美人鱼》取得33亿票房;2017年,《战狼2》取得56亿票房;再到《长津湖》的57亿票房,国产电影票房冠军几经易手,人们对国产电影的信心也与日俱增。在此期间,也出现了《心花路放》《夏洛特烦恼》《流浪地球》《你好,李焕英》《唐人街探案》系列等商业表现优秀的电影作品,国产电影的市场一路向好。
为了进一步将国产电影和进口电影的票房进行一个更好地对比,此次选题用大数据可视化的方式直观的将数据展示出来,可视化主要使用 pyecharts >= 1.9。
数据分析
数据集概况
数据集分为四个文件,分别是电影票房表现概览、票房榜、电影票房三十日时段趋势数据和电影票房三十日时段详情。
数据维度:
电影票房表现概览维度31,数据量100:
票房榜维度8,数据量150
电影票房三十日时段趋势数据维度16,数据量4620
电影票房三十日时段详情数据维度15,数据量3392
数据可视化过程
引包
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(r"/home/mw/input/movie7110/票房榜.xlsx") data.head(1)
票房榜数据字段处理
data["年份"] = data["上映日期"].apply(lambda x: str(x.split("-")[0])) data["票房"] = data["票房"].apply(lambda x: round(x/100000000, 2)) data = data.rename(columns={"票房":"票房/亿"}) data.head(1)
电影票房表现数据概览
data_haed = pd.read_excel(r"/home/mw/input/movie7110/电影票房表现概览.xlsx") data_haed.head(1)
电影票房数据字段处理
data_haed_all = data.merge(data_haed, how="left", on=['EnMovieID']) 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.info() 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 = ["全部", "国产","进口"]
榜单类别 - 国产/进口 - TOP50
tab = Tab() headers = colums rows_china = data_china[colums].apply(lambda x: list(x), axis=1).values.tolist() rows_foreign = data_foreign[colums].apply(lambda x: list(x), axis=1).values.tolist() attributes = {"class": "fl-table", "style": "margin: 0 auto"} # 居中显示 table_china = Table() attributes = {"class": "fl-table", "style": "margin: 0 auto"} # 居中显示 table_china.add(headers, rows_china, attributes) table_china.set_global_opts( title_opts=ComponentTitleOpts(title=f"榜单类别 - 国产 - TOP50", subtitle="") ) table_foreign = Table() attributes = {"class": "fl-table", "style": "margin: 0 auto"} # 居中显示 table_foreign.add(headers, rows_foreign, attributes) table_foreign.set_global_opts( title_opts=ComponentTitleOpts(title=f"榜单类别 - 进口 - TOP50", subtitle="") ) table = Table() table.add([], [], attributes) table.set_global_opts( title_opts=ComponentTitleOpts(title="键盘左右键移动视图查看", subtitle="") ) tab.add(table_china, "国产") tab.add(table_foreign, "进口") tab.add(table, "点击预览") tab.render_notebook()
电影票房榜单 - 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()
电影票房榜单 - 国产/进口 - TOP50
tab_rank = Tab() for i in range(1,3): line_max = max(max(data_cat[i]['场均人次'].tolist()), max(data_cat[i]['平均票价'].tolist())) bar_max = max(data_cat[i]['票房/亿'].tolist()) bar1 = ( Bar(init_opts=opts.InitOpts(width="1000px", height="600px",theme='light')) # 设置图表大小 .add_xaxis(xaxis_data=data_cat[i]['电影'].tolist()) # x轴 .add_yaxis( series_name="票房/亿", # 柱形图系列名称 y_axis=data_cat[i]['票房/亿'].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], "shadowColor": 'rgb(0, 160, 221)', }} ) .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=f"{cat[i]}电影票房 - 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=35, 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) ) ) line1 = ( Line() .add_xaxis(xaxis_data=data_cat[i]['电影'].tolist()) # x轴 .add_yaxis( series_name="场均人次", # 名称 yaxis_index=1, # 次坐标 is_smooth=True, # 线条样式 , 是否设置成圆滑曲线 y_axis=data_cat[i]['场均人次'].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_cat[i]['平均票价'].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), # 显示数据标签 ) ) bar1.overlap(line1) # 图表组合 tab_rank.add(bar1, cat[i]) tab_rank.add(table, "点击预览") tab_rank.render_notebook()
计算上榜电影标签汇总
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])
国产-进口上榜 - TOP50 - 详情分布
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()