├── .gitignore ├── 00数据可视化流程和思路 ├── example0_1 │ ├── example0_1.py │ ├── resources │ │ └── sankey.xlsx │ └── result │ │ └── result_ex0_1_sankey.html └── example0_2 │ ├── example0_2.py │ ├── resources │ └── travel_routes.xlsx │ └── result │ └── result_ex0_2_geo.html ├── 01比较之柱状图 ├── example1_1 │ ├── description.md │ ├── example1_1.py │ └── result │ │ └── fans_likes.html ├── example1_2 │ ├── description.md │ ├── example1_2.py │ └── result │ │ └── company_size.html ├── example1_3 │ ├── description.md │ ├── example1_3.py │ └── result │ │ └── fans_likes_2.html └── example1_4 │ ├── description.md │ ├── example1_4.py │ └── result │ └── bmi.html ├── 02趋势之折线图 ├── example2_1 │ └── example2_1.py ├── example2_2 │ ├── example2_2.py │ └── result │ │ └── live_deal.html ├── example2_3 │ ├── example2_3.py │ └── result │ │ └── marketing_clicking_area.html └── example2_4 │ ├── example2_4.py │ └── result │ └── weather_tab.html ├── 03柱线叠加图 ├── 03-1比较与趋势对照分析 │ └── example3_1 │ │ ├── example3_1.py │ │ └── result │ │ └── salary_bar_line.html └── 03-2主因分析之帕累托图 │ ├── example3_2 │ ├── description.md │ ├── example3_2.py │ └── result │ │ └── math_analysis_pareto.html │ ├── example3_3 │ ├── description.md │ ├── example3_3.py │ └── result │ │ └── restaurant_pareto.html │ ├── example3_4 │ ├── description.md │ ├── example3_4.py │ └── result │ │ └── credit_company_pareto.html │ └── whatisParetoChart.md ├── 04构成和差异之堆叠柱状图 ├── 04-1构成和差异结合分析 │ ├── example4_1 │ │ ├── example4_1.py │ │ └── result │ │ │ └── sales_stacked_bar.html │ ├── example4_2 │ │ ├── example4_2.py │ │ └── result │ │ │ └── GDP_stacked_bar.html │ └── example4_3 │ │ └── example4_3.py └── 04-2变化量分析之瀑布图 │ ├── example4_4 │ ├── example4_4.py │ └── result │ │ └── in_out_waterfall_stacked_bar.html │ └── whatisWaterfallPlot.md ├── 05构成和差异之饼状图 ├── 05-1普通饼状图 │ └── example5_1 │ │ └── example5_1.py ├── 05-2环状图、南丁格尔玫瑰图 │ ├── example5_2 │ │ ├── example5_2.py │ │ └── result │ │ │ └── web_visit_rose_pie.html │ ├── example5_3 │ │ ├── example5_3.py │ │ └── result │ │ │ └── vip_rose_pie.html │ └── example5_4 │ │ ├── example5_4.py │ │ └── result │ │ └── live_commerce_rose_pie.html └── whatisPieChart.md ├── 06别把数据直接放程序里之使用openpyxl ├── 06-1openpyxl读取excel数据演示 │ └── example6_1 │ │ ├── example6_1.py │ │ └── resources │ │ └── table.xlsx └── 06-2openpyxl结合可视化演示 │ ├── example6_2 │ ├── example6_2.py │ ├── resources │ │ └── table.xlsx │ └── result │ │ └── sales_line.html │ └── example6_3 │ ├── example6_3.py │ ├── resources │ └── 核桃销量.xlsx │ └── result │ └── nut_sales_line.html ├── 07转化跟踪之漏斗图 ├── example7_1 │ ├── example7_1.py │ └── result │ │ └── sales_section_funnel.html ├── example7_2 │ ├── example7_2.py │ └── result │ │ └── user_conversion_rate_funnel.html ├── example7_3 │ ├── example7_3.py │ ├── resources │ │ └── 销售漏斗.xlsx │ └── result │ │ ├── teamA_sales_funnel.html │ │ ├── teamB_sales_funnel.html │ │ └── teamC_sales_funnel.html ├── example7_4 │ ├── example7_4.py │ ├── resources │ │ └── 销售.xlsx │ └── result │ │ └── year_funnel_tab.html └── whatisFunnelChart.md ├── 08多维展示之轮播图 ├── example8_1 │ ├── example8_1.py │ ├── resources │ │ └── 历年前十大经济体.xlsx │ └── result │ │ └── GDP_bar_timeline.html ├── example8_2 │ ├── example8_2.py │ ├── resources │ │ └── timeline.xlsx │ └── result │ │ └── monthly_sales_timeline.html ├── example8_3 │ ├── example8_3.py │ ├── resources │ │ └── 每月销售额.xlsx │ └── result │ │ └── sales_rose_pie_timeline.html └── whatisTimeline.md ├── 09位置之地图 ├── example9_1 │ ├── example9_1.py │ └── result │ │ └── top10property_world_map.html ├── example9_2 │ ├── example9_2.py │ ├── resources │ │ └── 全国降雨量.xlsx │ └── result │ │ └── rainfall_china_map.html └── example9_3 │ ├── example9_3.py │ ├── resources │ └── 2010-2017年各省份历年GDP.xlsx │ └── result │ └── gdp_map_timeline.html ├── 10局部密度之热力图 ├── example10_1 │ ├── example10_1.py │ ├── resources │ │ └── 便利店.xlsx │ └── result │ │ └── week_order_heatmap.html └── example10_2 │ ├── example10_2.py │ ├── resources │ └── 票价表.xlsx │ └── result │ └── ticket_price_heatmap.html ├── 11单页多图之页面组合图 ├── example11_1 │ ├── example11_1.py │ └── result │ │ └── weiboPhoneCompete_bar_page.html ├── example11_2 │ ├── example11_2.py │ └── result │ │ └── sales_rose_funnel_page.html └── example11_3 │ ├── example11_3.py │ ├── resources │ └── hiking1.xlsx │ └── result │ └── hikingfan_multigraph_page.html ├── 12数据分布之箱线图 ├── example12_1 │ ├── example12_1.py │ └── result │ │ └── experiment_gp_boxplot.html ├── example12_2 │ ├── example12_2.py │ └── result │ │ └── scores_boxplot.html └── example12_3 │ ├── example12_3.py │ └── resources │ └── titanic.xlsx ├── 13数据流向之桑基图 ├── example13_1 │ ├── example13_1.py │ └── result │ │ └── purchase_sankey.html ├── example13_2 │ ├── example13_2.py │ └── result │ │ └── product_category_sankey.html ├── example13_3 │ ├── example13_3.py │ └── result │ │ └── product_sales_sankey.html ├── example13_4 │ ├── example13_4.py │ └── result │ │ └── stayup_reason_sankey.html ├── example13_5 │ └── example13_5.py └── example13_6 │ ├── example13_6.py │ ├── resources │ └── song.xlsx │ └── result │ └── songList_sankey.html ├── 14相关与分布之散点图 ├── example14_1 │ ├── example14_1.py │ ├── resources │ │ └── wj.xlsx │ └── result │ │ └── attack_income_scatter.html ├── example14_2 │ ├── example14_2.py │ ├── resources │ │ └── 日均销量对比.xlsx │ └── result │ │ └── product_competitor_scatter.html └── example14_3 │ ├── example14_3.py │ ├── resources │ └── dino1.xlsx │ └── result │ └── acplot_scatter.html ├── 15综合评估之雷达图 ├── example15_1 │ ├── example15_1.py │ └── result │ │ └── air_quality_radar.html ├── example15_2 │ ├── example15_2.py │ └── result │ │ └── player_radar.html └── example15_3 │ ├── example15_3.py │ ├── resources │ └── test.xlsx │ └── result │ └── phone_display_radar.html ├── 16地理描述之地理坐标图 ├── example16_1 │ ├── example16_1.py │ └── result │ │ └── travel_geo.html ├── example16_2 │ ├── example16_2.py │ ├── resources │ │ └── 全国十年年平均温度.xlsx │ └── result │ │ └── TEMP_geo_timeline.html ├── example16_3 │ ├── example16_3.py │ ├── resources │ │ └── 全国运输.xlsx │ └── result │ │ └── postage_geo.html ├── example16_4 │ ├── example16_4.py │ └── result │ │ └── on_business_geo.html └── example16_5 │ ├── example16_5.py │ └── resources │ └── 用户分布.xlsx ├── 17多对多映射联系之关系图 └── example17_1 │ ├── example17_1.py │ ├── resources │ └── 知识点.xlsx │ └── result │ └── pythonKG_graph.html ├── LICENSE ├── README.md └── 综合应用:制作可视化大屏 └── 可视化大屏demo ├── result ├── GuangZhou.html ├── config │ └── page_screen_config.json └── test │ └── pagetest.html └── visual_screen.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | /.idea/modules.xml 131 | /.idea/misc.xml 132 | /.idea/python数据可视化.iml 133 | /.idea/vcs.xml 134 | /.idea/.gitignore 135 | /.idea/inspectionProfiles/profiles_settings.xml 136 | /venv_hbsh/ 137 | /.idea/jsLibraryMappings.xml 138 | /.idea/workspace-Michael-Du.xml 139 | /.idea/workspace-Michael-Du-2.xml 140 | -------------------------------------------------------------------------------- /00数据可视化流程和思路/example0_1/example0_1.py: -------------------------------------------------------------------------------- 1 | # 使用import导入openpyxl模块 2 | import openpyxl 3 | # 使用from...import从pyecharts.charts导入Sankey 4 | from pyecharts.charts import Sankey 5 | # 使用from...import从pyecharts导入options,简写为opts 6 | from pyecharts import options as opts 7 | # 使用from...import从pyecharts.charts导入Page 8 | from pyecharts.charts import Page 9 | 10 | # 使用openpyxl.load_workbook(path)读取文件,赋值给wb 11 | wb = openpyxl.load_workbook("./resources/sankey.xlsx") 12 | # 使用中括号读取工作表对照组和实验组,赋值给sheet_A,sheet_B 13 | sheet_A = wb["对照组"] 14 | sheet_B = wb["实验组"] 15 | 16 | 17 | # 定义函数gen_nodesandlinks传入参数sheet 18 | def gen_nodesandlinks(sheet): 19 | # 定义标签数据列表,赋值给变量list_labels 20 | list_labels = [] 21 | # 使用max_row函数,计算sheet的行数 22 | sheet_rows = sheet.max_row 23 | # 通过for循环,读取A列2-sheet_rows行数据 24 | for cell in sheet["A"][2:sheet_rows]: 25 | # .value属性获取单元格值,并用append()函数添加进list_labels 26 | list_labels.append(cell.value) 27 | # 通过for循环,读取B列2-sheet_rows行数据 28 | for cell in sheet["B"][2:sheet_rows]: 29 | # .value属性获取单元格值,并用append()函数添加进list_labels 30 | list_labels.append(cell.value) 31 | 32 | # 使用set()函数对list_labels去重 33 | # 使用list()函数对去重后的结果转化为列表 34 | # 赋值给变量list_nodes 35 | list_nodes = list(set(list_labels)) 36 | 37 | # 定义节点列表,赋值给变量nodes 38 | nodes = [] 39 | # 通过for循环遍历list_labels 40 | for i in list_nodes: 41 | # 定义字典,赋值给变量dic 42 | dic = {} 43 | # 为dic创建("name":"标签名")键:值对 44 | dic["name"] = i 45 | # 使用append()函数将dic添加进nodes 46 | nodes.append(dic) 47 | 48 | # 定义信息流列表,赋值给变量links 49 | links = [] 50 | # 通过for循环,读取sheet的2-sheet_rows行数据 51 | for cell in sheet[2:sheet_rows]: 52 | # 定义字典,赋值给变量dic 53 | dic = {} 54 | # .value属性获取元组索引为0的单元格值,为dic创建("source":"标签名1")键:值对 55 | dic["source"] = cell[0].value 56 | # .value属性获取元组索引为1的单元格值,为dic创建("target":"标签名")键:值对 57 | dic["target"] = cell[1].value 58 | # .value属性获取元组索引为2的单元格值,为dic创建("value":"值")键:值对 59 | dic["value"] = cell[2].value 60 | # 使用append()函数将dic添加进links 61 | links.append(dic) 62 | # 使用return返回(nodes,links) 63 | return (nodes, links) 64 | 65 | 66 | # 定义函数page_Sankey传入参数nodes_links,title_name 67 | def page_Sankey(nodes_links, title_name): 68 | # 使用Sankey()函数创建对象赋值给sankey 69 | # 使用InitOpts(),传入参数theme="dark",bg_color="#253441",赋值给init_opts 70 | sankey = Sankey(init_opts=opts.InitOpts(theme="dark", bg_color="#253441")) 71 | 72 | # 为创建的实例增加名字(sankey)、传入实验组节点和信息流列表 73 | sankey.add("sankey", 74 | nodes=nodes_links[0], 75 | links=nodes_links[1], 76 | # 使用LineStyleOpts(),传入参数opacity=0.3, curve=0.5, color="source",赋值给linestyle_opt 77 | linestyle_opt=opts.LineStyleOpts(opacity=0.3, curve=0.5, color="source"), 78 | # 使用LabelOpts(),传入参数position="right",color="white",font_size=10,赋值给label_opts 79 | label_opts=opts.LabelOpts(position="right", color="white", font_size=10), 80 | # 使用SankeyLevelsOpts(),传入参数depth为0-5、itemstyle_opts,赋值给列表levels 81 | levels=[ 82 | opts.SankeyLevelsOpts(depth=0, 83 | # 使用ItemStyleOpts(),传入参数color="#FF8947",border_color="#FF8947" 84 | itemstyle_opts=opts.ItemStyleOpts(color="#FF8947", border_color="#FF8947")) 85 | , opts.SankeyLevelsOpts(depth=1, 86 | # 使用ItemStyleOpts(),传入参数color="#96D15C",border_color="#96D15C" 87 | itemstyle_opts=opts.ItemStyleOpts(color="#96D15C", border_color="#96D15C")) 88 | , opts.SankeyLevelsOpts(depth=2, 89 | # 使用ItemStyleOpts(),传入参数color="#479BED",border_color="#479BED" 90 | itemstyle_opts=opts.ItemStyleOpts(color="#479BED", border_color="#479BED")) 91 | , opts.SankeyLevelsOpts(depth=3, 92 | # 使用ItemStyleOpts(),传入参数color="#55C4CA",border_color="#55C4CA" 93 | itemstyle_opts=opts.ItemStyleOpts(color="#55C4CA", border_color="#55C4CA")) 94 | , opts.SankeyLevelsOpts(depth=4, 95 | # 使用ItemStyleOpts(),传入参数color="#E7BF4F",border_color="#E7BF4F" 96 | itemstyle_opts=opts.ItemStyleOpts(color="#E7BF4F", border_color="#E7BF4F")) 97 | ] 98 | ) 99 | # 使用TitleOpts(),传入参数title,赋值给title_opts 100 | # 使用LegendOpts(),传入参数is_show=False,赋值给legend_opts 101 | # 调用set_global_opts() 102 | sankey.set_global_opts(title_opts=opts.TitleOpts(title=title_name), legend_opts=opts.LegendOpts(is_show=False)) 103 | # 使用return返回sankey 104 | return sankey 105 | 106 | 107 | # 创建Page对象,并赋值给page 108 | page = Page(layout=Page.DraggablePageLayout) 109 | 110 | # 在add()函数中,分别调用对照组和实验组page_Sankey()函数,图例名分别为"用户路径流转图对照组"和"用户路径流转图实验组" 111 | page.add(page_Sankey(gen_nodesandlinks(sheet_A), "用户路径流转图对照组"), page_Sankey(gen_nodesandlinks(sheet_B), "用户路径流转图实验组")) 112 | 113 | # 使用render()生成桑基图页面组合保存到./result/sankey.html 114 | page.render("./result/result_ex0_1_sankey.html") 115 | -------------------------------------------------------------------------------- /00数据可视化流程和思路/example0_1/resources/sankey.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/00数据可视化流程和思路/example0_1/resources/sankey.xlsx -------------------------------------------------------------------------------- /00数据可视化流程和思路/example0_2/example0_2.py: -------------------------------------------------------------------------------- 1 | import openpyxl 2 | from pyecharts.charts import Geo 3 | from pyecharts import options as opts 4 | from pyecharts.commons.utils import JsCode 5 | 6 | wb = openpyxl.load_workbook("./resources/travel_routes.xlsx", data_only=True) 7 | sheet = wb["travel_route"] 8 | routeList = [] 9 | 10 | for row in range(2, sheet.max_row + 1): 11 | routeInfo = sheet[row] 12 | data = (routeInfo[0].value, routeInfo[1].value) 13 | routeList.append(data) 14 | 15 | line_color_js = """ 16 | new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ 17 | offset: 0, 18 | color: '#42AECC' 19 | }, { 20 | offset: 1, 21 | color: '#F5602C' 22 | }], false) 23 | """ 24 | 25 | geo = Geo( 26 | init_opts=opts.InitOpts( 27 | theme="dark", 28 | bg_color="#475262") 29 | ) 30 | 31 | geo.add_schema(maptype="china", 32 | itemstyle_opts=opts.ItemStyleOpts( 33 | color="#2D3948", border_color="#58667A"), 34 | emphasis_itemstyle_opts=opts.ItemStyleOpts(color="#2a333d")) 35 | 36 | geo.add( 37 | "", 38 | routeList, 39 | type_="lines", 40 | symbol="circle", 41 | symbol_size=10, 42 | effect_opts=opts.EffectOpts( 43 | symbol="circle", symbol_size=4, trail_length=0), 44 | linestyle_opts=opts.LineStyleOpts( 45 | width=2, opacity=0.5, curve=0.1, color=JsCode(line_color_js)), 46 | label_opts=opts.LabelOpts(is_show=False) 47 | ) 48 | 49 | geo.render(path="./result/result_ex0_2_geo.html") 50 | -------------------------------------------------------------------------------- /00数据可视化流程和思路/example0_2/resources/travel_routes.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/00数据可视化流程和思路/example0_2/resources/travel_routes.xlsx -------------------------------------------------------------------------------- /01比较之柱状图/example1_1/description.md: -------------------------------------------------------------------------------- 1 | # example1_1 2 | 3 | 用途:分析并比较部分网红博主频道的粉丝互动情况。 4 | 5 | > 分析:可视化的目的是``比较``,且考虑到可视化的数据较少,故采用柱状图进行绘制。 6 | 7 | ## Step 1: 准备数据——网红博主的数据表 8 | 9 | **字段名:频道名称 | 粉丝数(单位:万) | 点赞数(单位:万)** 10 | 11 | note: 12 | 13 | 网红博主的数据可能是从网上爬取下来,经过清洗后存放在了excel表格或者csv表格中,最后才读进列表的 14 | 15 | 不过这里,前面的读取和清洗工作就暂时省略了,数据假如就是已经读进来且清洗了,因为我们关键是看数据可视化的思路. 16 | 17 | *** 18 | 19 | ## Step 2: 将上述表格中的数据分列提取出来 20 | 21 | **这一步的作用是准备绘图所需要的数据。** 22 | 23 | 每一个字段对应的值提取出来存储在各自的列表中。 24 | 25 | ## Step 3: 计算点赞收藏量与粉丝量的比值(赞粉比) 26 | 27 | **这一步的作用也是准备绘图需要的数据。** 28 | 29 | **赞粉比**的值在分析中具有较大的参考价值,它可以在一定程度上避免这样的博主: 30 | 31 | 1、低活跃度或低质量的博主 32 | 33 | 2、买僵尸粉的博主 34 | 35 | 3、从其它知名平台刚入驻,老粉多但新平台尚未充分运营的博主 36 | 37 | *** 38 | 39 | ## Step 4: 使用上述数据,绘制柱状图并保存 40 | 41 | **指定x轴数据列表 -> 指定y轴数据列表及其图例 -> 指定保存路径和文件名(.html格式) -> 执行保存** 42 | 43 | 注意: 44 | 45 | x轴和y轴的数据长度应该一致,从而一一对应生成图像 46 | 47 | 添加y轴的同时,一定要指定该数据的图例(series_name),否则运行会不予通过 48 | 49 | ## 附:解决图像显示时x轴部分label(标签)丢失的问题 50 | 51 | 您可以尝试将``example1_1.py``中的下述代码注释掉再运行。 52 | 53 | ```python 54 | # 优化:横坐标文字比较长时候,部分文字被遮挡不进行显示,所以让横坐标文字稍微倾斜45度一点,同时添加一个标题 55 | bar.set_global_opts( 56 | xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)), 57 | title_opts=opts.TitleOpts(title="部分博主粉丝与点赞的对比") 58 | ) 59 | ``` 60 | 61 | 然后你会发现: 62 | 63 | * 嗯?x轴为啥有些标签没有显示出来?不见了!!! 64 | 65 | * 嗯?标题去哪里了?!! 66 | 67 | 在程序中,一开始这句导入``from pyecharts import options as opts``,这里导入的其实就是对图表配置的选项,上述代码通过设置options中的一些内容,实现了向柱状图添加标题,倾斜横坐标label的功能。 68 | 69 | options模块是一个非常实用的模块,后面经常需要它辅助配置图标的一些细节呈现。 -------------------------------------------------------------------------------- /01比较之柱状图/example1_1/example1_1.py: -------------------------------------------------------------------------------- 1 | # 导入os库,方便后续路径的处理 2 | import os 3 | # 导入options 模块并简写为opts 4 | import pyecharts.options as opts 5 | # 从pyecharts.charts中 导入 Bar模块 6 | from pyecharts.charts import Bar 7 | 8 | """Step 0: 预备工作——必要的参数配置 9 | 10 | 提前指定好生成可视化图形的 数据来源路径 和 图形最终的保存路径 11 | """ 12 | # resourcesPath这次暂时没有 13 | # 目标存储的路径(相对路径的默认工作区起点为.../examplex_x这个文件夹) 14 | resultPath = "./result" 15 | 16 | 17 | """Step 1: 准备数据——网红博主的数据表 18 | 19 | 字段名:频道名称 | 粉丝数(单位:万) | 点赞数(单位:万) 20 | note: 21 | 网红博主的数据可能是从网上爬取下来,经过清洗后存放在了excel表格或者csv表格中,最后才读进列表的 22 | 不过这里,前面的读取和清洗工作就暂时省略了,数据假如就是已经读进来且清洗了,因为我们关键是看数据可视化的思路 23 | """ 24 | channel_infos = [ 25 | ("一起画笔记", 12.5, 18.2), 26 | ("我是课代表", 23.1, 15.2), 27 | ("菠萝冰和夏天", 38.5, 222.7), 28 | ("Jeannie花", 15.8, 71.5), 29 | ("Esther天", 14.1, 8.6), 30 | ("爱草莓的小挺", 11.4, 70.5), 31 | ("栀缘", 18.2, 107.7), 32 | ("钢琴上的音乐", 16.5, 128.3), 33 | ("Mu123", 22.6, 109), 34 | ("师008号", 32, 31.7) 35 | ] 36 | 37 | 38 | """Step 2: 将上述表格中的数据分列提取出来 39 | """ 40 | # 将10位博主的频道名称存入变量名为'name'的列表中 41 | # name = ["一起画笔记", "我是课代表", "菠萝冰和夏天", "Jeannie花", "Esther天", 42 | # "爱草莓的小挺", "栀缘", "钢琴上的音乐", "Mu123", "师008号"] 43 | name = [channel_info[0] for channel_info in channel_infos] 44 | # 按照博主姓名的顺序,依次将博主的粉丝数量存入变量名为'fans'的列表中 45 | # fans = [12.5, 23.1, 38.5, 15.8, 14.1, 11.4, 18.2, 16.5, 22.6, 32] 46 | fans = [channel_info[1] for channel_info in channel_infos] 47 | # 按照博主姓名的顺序,依次将博主的点赞收藏量存入变量名为‘likes’的列表中 48 | # likes = [18.2, 15.2, 222.7, 71.5, 8.6, 70.5, 107.7, 128.3, 109, 31.7] 49 | likes = [channel_info[2] for channel_info in channel_infos] 50 | 51 | 52 | """Step 3: 计算点赞收藏量与粉丝量的比值(赞粉比) 53 | 54 | 赞粉比数值具有较大的参考价值,它可以在一定程度上避免这样的博主: 55 | 1、低活跃度或低质量博主 56 | 2、买僵尸粉博主 57 | 3、从其它知名平台刚入驻,老粉多但新平台尚未充分运营的博主 58 | """ 59 | # 定义一个空列表ratioList,存储点赞收藏量与粉丝量的比值 60 | ratioList = [] 61 | # 统计点赞收藏量列表长度,并赋值给length 62 | length = len(channel_infos) 63 | # 将点赞收藏量列表中的值除以对应粉丝量列表中的值,并使用round()函数取近似值并保留2位小数,存储到ratioList列表中 64 | for i in range(length): 65 | ratio = round(likes[i] / fans[i], 2) 66 | ratioList.append(ratio) 67 | 68 | 69 | """Step 4: 使用上述数据,绘制柱状图并保存 70 | 71 | 指定x轴数据列表 -> 指定y轴数据列表及其图例 -> 指定保存路径和文件名(.html格式)执行保存 72 | 注意: 73 | x轴和y轴的数据长度应该一致,从而一一对应生成图像 74 | 添加y轴的同时,一定要指定该数据的图例(series_name),否则运行会不予通过 75 | """ 76 | # 创建一个柱状图Bar对象并赋值给变量bar 77 | bar = Bar() 78 | # 给柱状图添加x轴数据,数据内容是博主姓名列表:name 79 | bar.add_xaxis(xaxis_data=name) 80 | # 给柱状图添加y轴数据,数据内容是赞粉比列表:ratioList,指定该数据的图例为”赞粉比“ 81 | bar.add_yaxis(y_axis=ratioList, series_name="赞粉比") 82 | # 优化:横坐标文字比较长时候,部分文字被遮挡不进行显示,所以让横坐标文字稍微倾斜45度一点,同时添加一个标题 83 | bar.set_global_opts( 84 | xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)), 85 | title_opts=opts.TitleOpts(title="部分博主粉丝与点赞的对比") 86 | ) 87 | # 绘制出这条柱状图,并保存到路径"./result/fans_likes.html" 88 | resultFileName = "fans_likes.html" 89 | bar.render(path=os.path.join(resultPath, resultFileName)) 90 | -------------------------------------------------------------------------------- /01比较之柱状图/example1_2/description.md: -------------------------------------------------------------------------------- 1 | # example1_2 2 | 3 | 用途:分析并比较一些公司的员工人数情况。 4 | 5 | > 分析:可视化的目的是``比较``,且考虑到可视化的数据较少,故采用柱状图进行绘制。 6 | 7 | ## Step 1: 准备所需的绘图数据——公司及员工人数信息表 8 | 9 | **字段名:公司名 | 公司员工人数** 10 | 11 | 这里略去从表格中提取数据的情形,直接假设已经把相应字段读进了所需的列表中 12 | 13 | 且所获得的数据已经是我们所要的坐标轴数据,不需要再做计算处理了,直接对应放上坐标系即可 14 | 15 | > 其实这一步相当于已经把example1_1的前3步合并到一起了哈哈哈。不过不管怎么变,它的意图都是读取数据、预备坐标轴上的数据,这点总是不变的。 16 | 17 | *** 18 | 19 | ## Step 2: 使用上述数据,绘制柱状图并保存 20 | 21 | **创建柱状图并指定图表标题 -> 指定x轴数据列表 -> 指定y轴数据列表及其图例 -> 指定保存路径和文件名(.html格式) -> 执行保存** 22 | -------------------------------------------------------------------------------- /01比较之柱状图/example1_2/example1_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | # 使用from...import从pyecharts.charts中导入Bar模块 3 | from pyecharts.charts import Bar 4 | # 使用from...import从pyecharts中导入options模块并简写为opts 5 | from pyecharts import options as opts 6 | 7 | # 目标存储的路径 8 | resultPath = "./result" 9 | 10 | """数据来源(简化到已经清洗完毕并读取至列表的情形)""" 11 | # 将公司的名字存入变量名为"name"的列表中 12 | name = ["ibm", "microsoft", "pwc", "citi", "amazon", "apple", "ey", "walmart", "siemens", "google"] 13 | # 按照公司名字的顺序,依次将公司的人数存入变量名为"employee"的列表中 14 | employee = [274047, 116196, 111372, 101482, 93247, 90095, 158363, 120753, 87381, 75109] 15 | 16 | """绘图""" 17 | # 创建Bar对象,并赋值给bar 18 | bar = Bar() 19 | # 设置图表的标题为“公司人数对比” 20 | bar.set_global_opts(title_opts=opts.TitleOpts(title="公司人数对比")) 21 | # 传入参数xaxis_data=name使用add_xaxis()设置x轴为公司名称 22 | bar.add_xaxis(xaxis_data=name) 23 | # 传入参数y_axis=employee,使用add_yaxis()设置y轴图例为“公司人数” 24 | bar.add_yaxis(y_axis=employee, series_name="公司人数") 25 | # 使用render()绘制柱状图保存 26 | resultFileName = "company_size.html" 27 | bar.render(path=os.path.join(resultPath, resultFileName)) 28 | -------------------------------------------------------------------------------- /01比较之柱状图/example1_2/result/company_size.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Awesome-pyecharts 6 | 7 | 8 | 9 | 10 |
11 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /01比较之柱状图/example1_3/description.md: -------------------------------------------------------------------------------- 1 | # example1_3 2 | 3 | 该示例是``example1_1``的变式。这个问题中我们不再用赞粉比作为y轴数据,而是**直接拿粉丝数和点赞数同时作为y轴直观呈现**。 4 | 5 | 用途:分析并比较部分网红博主频道的粉丝互动情况。 6 | 7 | > 分析:可视化的目的是``比较``,且考虑到可视化的数据较少,故采用柱状图进行绘制,且这个柱状图是``多y轴``的柱状图 8 | 9 | ## Step 1: 准备数据——网红博主的数据表 10 | 11 | 省略,与``example1_1``完全相同。 12 | 13 | *** 14 | 15 | ## Step 2: 将上述表格中的数据分列提取出来 16 | 17 | 省略,与``example1_1``完全相同。 18 | 19 | *** 20 | 21 | ## Step 3: 使用上述数据,绘制柱状图并保存 22 | 23 | **指定x轴数据列表 -> 指定y轴数据列表及其图例 -> 指定保存路径和文件名(.html格式) -> 执行保存** 24 | 25 | > 注意,这一次y轴有两个量,一个是粉丝数,一个是点赞量,分别添加 26 | 27 | 其中上述步骤中还要设置图表配置项,添加标题并且避免横坐标显示不完全(旋转一下横坐标label) 28 | 29 | ## 附1:做图——想一次到位还是分步组装? 30 | 31 | 本例子在绘图的时候有一段很长的构造和设置多y轴柱状图的代码。 32 | 33 | ```python 34 | bar = (Bar() 35 | .set_global_opts(title_opts=opts.TitleOpts(title="博主粉丝数和点赞数"), 36 | xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45))) 37 | .add_xaxis(xaxis_data=name) 38 | .add_yaxis(y_axis=fans, series_name="粉丝数") 39 | .add_yaxis(y_axis=likes, series_name="点赞数") 40 | ) 41 | ``` 42 | 43 | 其实这跟一步一步创建柱状图呈现的效果是一样的,即**上述代码与下述效果等同**。 44 | 45 | ```python 46 | bar = Bar() 47 | bar.set_global_opts(title_opts=opts.TitleOpts(title="博主粉丝数和点赞数"), 48 | xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45))) 49 | bar.add_xaxis(xaxis_data=name) 50 | bar.add_yaxis(y_axis=fans, series_name="粉丝数") 51 | bar.add_yaxis(y_axis=likes, series_name="点赞数") 52 | ``` 53 | 54 | > 第一种写法是``pyecharts``官方文档给出demo(传送门:https://gallery.pyecharts.org/ )中惯用的代码写,其实就是把很多步设置一步到位了。 55 | > 我个人觉得第一种写法更好,一句话创建一个图表,显得更聚集一些,省得创建个图表都要写好几行。 56 | > 不过真正地到底哪种写法更好,仁者见仁智者见智的事情而已。 57 | 58 | ## 附2:全局选项设置——必须一步到位的地方! 59 | 60 | 本问题对柱状图进行调整的时候,做了**添加标题**和**倾斜横坐标文字**两件事,用到了**配置图表的全局选项设置**,即 61 | 62 | ```python 63 | bar.set_global_opts(title_opts=opts.TitleOpts(title="博主粉丝数和点赞数"), 64 | xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45) 65 | ) 66 | ``` 67 | 68 | > 不同于``附1``可以一步到位或者一步步慢慢来,这里若要同时让两个设置同时起效,必须在一个``set_global_opt``函数里同时配置相应参数,必须一步到位。 69 | 70 | 如果按照下述方式配置柱状图属性: 71 | 72 | ```python 73 | bar.set_global_opts(title_opts=opts.TitleOpts(title="博主粉丝数和点赞数")) 74 | bar.set_global_opts(xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)) 75 | ``` 76 | 77 | 可以试试,发现**原来标题的设置消失了,被横坐标label旋转的设置覆盖了**。 78 | 79 | ## 附3:图表属性选项(options)配置中的等效写法 80 | 81 | 以横坐标旋转45度为例,下面两种设置写法**效果等价**,均能正常绘图。 82 | 83 | * 写法1 84 | 85 | ```python 86 | bar.set_global_opts(xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)) 87 | ``` 88 | 89 | * 写法2 90 | 91 | ```python 92 | bar.set_global_opts(xaxis_opts=opts.AxisOpts(axislabel_opts={"rotate":45})) 93 | ``` 94 | 95 | > 喜欢哪种?还是一样这里仁者见仁智者见智。 96 | > 目前我个人比较习惯写法1,虽然写起来稍微绕一点,但不管怎么说Pycharm中有代码提示引导,也还是挺香的。 97 | > 98 | > ``pyecharts``官方对此也有相应说明,传送门:https://pyecharts.org/#/zh-cn/parameters 99 | -------------------------------------------------------------------------------- /01比较之柱状图/example1_3/example1_3.py: -------------------------------------------------------------------------------- 1 | # 导入os库,方便后续路径的处理 2 | import os 3 | # 导入options 模块并简写为opts 4 | import pyecharts.options as opts 5 | # 从pyecharts.charts中 导入 Bar模块 6 | from pyecharts.charts import Bar 7 | 8 | """Step 0: 预备工作——必要的参数配置 9 | """ 10 | # 目标存储的路径 11 | resultPath = "./result" 12 | 13 | 14 | """Step 1: 准备数据——网红博主的数据表 15 | 字段名:频道名称 | 粉丝数(单位:万) | 点赞数(单位:万) 16 | """ 17 | channel_infos = [ 18 | ("一起画笔记", 12.5, 18.2), 19 | ("我是课代表", 23.1, 15.2), 20 | ("菠萝冰和夏天", 38.5, 222.7), 21 | ("Jeannie花", 15.8, 71.5), 22 | ("Esther天", 14.1, 8.6), 23 | ("爱草莓的小挺", 11.4, 70.5), 24 | ("栀缘", 18.2, 107.7), 25 | ("钢琴上的音乐", 16.5, 128.3), 26 | ("Mu123", 22.6, 109), 27 | ("师008号", 32, 31.7) 28 | ] 29 | 30 | 31 | """Step 2: 将上述表格中的数据分列提取出来 32 | """ 33 | # 将10位博主的频道名称存入变量名为'name'的列表中 34 | # name = ["一起画笔记", "我是课代表", "菠萝冰和夏天", "Jeannie花", "Esther天", 35 | # "爱草莓的小挺", "栀缘", "钢琴上的音乐", "Mu123", "师008号"] 36 | name = [channel_info[0] for channel_info in channel_infos] 37 | # 按照博主姓名的顺序,依次将博主的粉丝数量存入变量名为'fans'的列表中 38 | # fans = [12.5, 23.1, 38.5, 15.8, 14.1, 11.4, 18.2, 16.5, 22.6, 32] 39 | fans = [channel_info[1] for channel_info in channel_infos] 40 | # 按照博主姓名的顺序,依次将博主的点赞收藏量存入变量名为‘likes’的列表中 41 | # likes = [18.2, 15.2, 222.7, 71.5, 8.6, 70.5, 107.7, 128.3, 109, 31.7] 42 | likes = [channel_info[2] for channel_info in channel_infos] 43 | 44 | 45 | """Step 3: 使用上述数据,绘制柱状图并保存 46 | 47 | 注意: 48 | 1、这一次记得设置全局配置,设置标题并调整x轴显示不完全的问题 49 | 2、这次绘制的是多y轴柱状图(y轴有点赞量和粉丝数2项合到一张图) 50 | 3、本案例中采用pyecharts官方文档中常用的一句话到底的写法 51 | """ 52 | # # 创建一个柱状图Bar对象并赋值给变量bar 53 | # bar = Bar() 54 | # # 给柱状图添加x轴数据,数据内容是博主姓名列表:name 55 | # bar.add_xaxis(xaxis_data=name) 56 | # # 给柱状图添加y轴数据,y轴数据有粉丝数和点赞量两个 57 | # bar.add_yaxis(y_axis=fans, series_name="粉丝数") 58 | # bar.add_yaxis(y_axis=likes, series_name="点赞数") 59 | # # 优化:横坐标文字比较长时候,部分文字被遮挡不进行显示,所以让横坐标文字稍微倾斜45度一点,同时添加一个标题 60 | # bar.set_global_opts( 61 | # xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)), 62 | # title_opts=opts.TitleOpts(title="博主粉丝数和点赞数") 63 | # ) 64 | """下述代码与上述注释代码等价""" 65 | bar = (Bar() 66 | .set_global_opts(title_opts=opts.TitleOpts(title="博主粉丝数和点赞数"), 67 | xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45))) 68 | .add_xaxis(xaxis_data=name) 69 | .add_yaxis(y_axis=fans, series_name="粉丝数") 70 | .add_yaxis(y_axis=likes, series_name="点赞数") 71 | ) 72 | 73 | # 绘制出这条柱状图,并保存到路径"./result/fans_likes.html" 74 | resultFileName = "fans_likes_2.html" 75 | bar.render(path=os.path.join(resultPath, resultFileName)) 76 | -------------------------------------------------------------------------------- /01比较之柱状图/example1_4/description.md: -------------------------------------------------------------------------------- 1 | # example1_4 2 | 3 | 用途:比较统计5名学生的BMI指数。公式:``bmi = weight/(height*height)`` 4 | 5 | > 分析:可视化的目的是``比较``,且考虑到可视化的数据较少,故采用柱状图进行绘制。 6 | 7 | 看完前3个example了以后,这个不是简单的一批吗? 8 | 9 | ## Step 1: 读表,取各列数据 10 | 11 | 学生姓名可作为柱状图x轴,在这一步取出。 12 | 13 | ## Step 2: 利用身高、体重数据算出BMI指数 14 | 15 | 作为y轴的BMI数据在这一步得出 16 | 17 | ## Step 3: 制图 18 | 19 | > Note: 制图时对图像的设置,最好是留下注释,不然时间久了全忘了。 20 | 21 | 以本例为例,简要交代一些图表设置信息即可。 22 | 23 | ```python 24 | """作图 25 | 26 | 标题:BMI数据统计 27 | x轴:学生姓名 28 | y轴:bmi值计算结果,图例无 29 | 存储位置:./result/bmi.html 30 | """ 31 | resultFileName = "bmi.html" 32 | bar = (Bar().set_global_opts(title_opts=opts.TitleOpts(title="BMI数据统计")) 33 | .add_xaxis(xaxis_data=name) 34 | .add_yaxis(y_axis=bmiList, series_name="") 35 | .render(path=os.path.join(resultPath, resultFileName)) 36 | ) 37 | ``` -------------------------------------------------------------------------------- /01比较之柱状图/example1_4/example1_4.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pyecharts.options as opts 3 | from pyecharts.charts import Bar 4 | 5 | """指定存储目录 6 | """ 7 | resultPath = "./result" 8 | 9 | """原始数据表(省略获取、清晰、从文件读取等逻辑) 10 | 11 | 字段:姓名 | 身高(单位:米) | 体重(单位:千克) 12 | """ 13 | student_infos = [ 14 | ('yoyo', 1.55, 45), 15 | ('coco', 1.6, 50), 16 | ('jojo', 1.58, 48), 17 | ('momo', 1.68, 55), 18 | ('bobo', 1.65, 49) 19 | ] 20 | 21 | """提取表格各列数据,准备包括后续充当x轴的name等字段 22 | """ 23 | # 将5位同学的姓名存入变量名为'name'的列表中 24 | name = [student_info[0] for student_info in student_infos] 25 | # 按照同学姓名的顺序,依次将同学的身高存入变量名为'height'的列表中 26 | height = [student_info[1] for student_info in student_infos] 27 | # 按照同学姓名的顺序,依次将同学的体重存入变量名为‘weight’的列表中 28 | weight = [student_info[2] for student_info in student_infos] 29 | 30 | """计算BMI,准备x轴字段对应y轴数据 31 | """ 32 | bmiList = [] 33 | for one_name, one_height, one_weight in student_infos: 34 | # 保留整数 35 | bmiList.append( 36 | # round(one_weight/(one_height**2), 0) 37 | round(one_weight / (one_height ** 2)) 38 | ) 39 | 40 | """作图 41 | 42 | 标题:BMI数据统计 43 | x轴:学生姓名 44 | y轴:bmi值计算结果,图例无 45 | 存储位置:./result/bmi.html 46 | """ 47 | resultFileName = "bmi.html" 48 | bar = (Bar().set_global_opts(title_opts=opts.TitleOpts(title="BMI数据统计")) 49 | .add_xaxis(xaxis_data=name) 50 | .add_yaxis(y_axis=bmiList, series_name="") 51 | .render(path=os.path.join(resultPath, resultFileName)) 52 | ) -------------------------------------------------------------------------------- /01比较之柱状图/example1_4/result/bmi.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Awesome-pyecharts 6 | 7 | 8 | 9 | 10 |
11 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /02趋势之折线图/example2_1/example2_1.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/02趋势之折线图/example2_1/example2_1.py -------------------------------------------------------------------------------- /02趋势之折线图/example2_2/example2_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Line 3 | import pyecharts.options as opts 4 | 5 | """读取数据(读表过程略去,这里聚焦加载文件数据过后的情景) 6 | 7 | 原始数据是这样的二维表,或者每个姓名作为一个单独的Worksheet(工作表) 8 | 9 | | 1月 | 2月 | 3月 | ... | 11月 | 12月 10 | huanhuan| 11 | shushu | (中间放主播的带货成交额数据) 12 | binbin | 13 | """ 14 | # 三位主播的带货成交额数据存入下列列表中 15 | huanhuan = [2.3, 2.3, 1.3, 1.2, 2.4, 3.6, 3.5, 3.4, 2.2, 5.5, 10.1, 9.2] 16 | shushu = [5.2, 4.9, 4.6, 4.7, 4.4, 5.6, 5.5, 5.5, 4.1, 6.5, 5.0, 5.2] 17 | binbin = [3.2, 3.3, 5.6, 5.4, 3.6, 4.2, 4.5, 2.5, 8.1, 8.6, 8.8, 6.3] 18 | # 将12各月份并赋值给变量month 19 | month = ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"] 20 | 21 | """制图(属性可以查阅pyecharts官方文档) 22 | 23 | 1、横坐标为月份,纵坐标是各主播带货的月成交额情况 24 | 2、曲线是平滑的 25 | 3、多曲线(添加多个y轴) 26 | 4、曲线上点的形状(标记)设置: 27 | huanhuan的折线,标记(symbol)设为"circle"。 28 | shushu的折线,标记设为"rect"。 29 | binbin的折线,标记设为"triangle"。 30 | (symbol取值是什么是从官方文档找出来的,并不是自己瞎写的) 31 | 5、标记的大小均为10 32 | 6、保存 33 | """ 34 | line = (Line() 35 | .add_xaxis(xaxis_data=month) 36 | .add_yaxis(series_name="huanhuan", y_axis=huanhuan, 37 | symbol="circle", symbol_size=10, 38 | is_smooth=True) 39 | .add_yaxis(series_name="shushu", y_axis=shushu, 40 | symbol="rect", symbol_size=10, 41 | is_smooth=True) 42 | .add_yaxis(series_name="binbin", y_axis=binbin, 43 | symbol="triangle", symbol_size=10, 44 | is_smooth=True) 45 | ) 46 | # 存储目录 47 | resultPath = "./result" 48 | # 文件名 49 | resultFileName = "live_deal.html" 50 | # 执行保存 51 | line.render(path=os.path.join(resultPath, resultFileName)) 52 | -------------------------------------------------------------------------------- /02趋势之折线图/example2_3/example2_3.py: -------------------------------------------------------------------------------- 1 | import pyecharts.options as opts 2 | from pyecharts.charts import Line 3 | import os 4 | 5 | """准备数据""" 6 | # 将周一至周日并赋值给变量data 7 | data = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] 8 | # 将不同营销渠道的点击量数据存入下列列表中 9 | # 邮件营销点击量 10 | email = [120, 132, 101, 134, 90, 230, 210] 11 | # 视频推广点击量 12 | video = [150, 232, 201, 154, 190, 330, 410] 13 | 14 | """执行绘图 15 | 16 | 1、折线图的标题为“营销渠道点击对比” 17 | 2、x轴是data 18 | 3、y轴数据有两项:一个是email,图例设为“邮件营销”;另一个是video,图例设为“视频推广” 19 | 4、y轴设定后的曲线都是光滑的 20 | 5、y轴下方要有阴影,设置透明度为50%(areastyle_opts,这个用法可以查看pyecharts官方文档) 21 | """ 22 | line = (Line() 23 | .set_global_opts(title_opts=opts.TitleOpts(title="营销渠道点击对比")) 24 | .add_xaxis(xaxis_data=data) 25 | .add_yaxis(series_name="邮件营销", y_axis=email, 26 | is_smooth=True, 27 | areastyle_opts=opts.AreaStyleOpts(opacity=0.5)) 28 | .add_yaxis(series_name="视频推广", y_axis=video, 29 | is_smooth=True, 30 | areastyle_opts=opts.AreaStyleOpts(opacity=0.5)) 31 | ) 32 | 33 | # 保存路径 34 | resultPath = "./result" 35 | if not os.path.exists(resultPath): 36 | os.mkdir(path=resultPath) 37 | # 保存文件名 38 | resultFileName = "marketing_clicking_area.html" 39 | # 执行保存 40 | line.render(path=os.path.join(resultPath, resultFileName)) 41 | -------------------------------------------------------------------------------- /02趋势之折线图/example2_4/example2_4.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Line, Tab 3 | import pyecharts.options as opts 4 | 5 | """数据来源(可能来自一个多sheet的excel表格,这里简化读表过程)""" 6 | # 具体的气候数据存入下列列表中 7 | # 最高平局气温数据 8 | weather_dict = { 9 | # 平均最高气温 10 | "Average_highest": [8.1, 8.4, 11.3, 14.2, 17.9, 21.2, 23.5, 23.2, 20.2, 15.5, 11.1, 8.3], 11 | # 日均气温数据 12 | "Daily_mean": [5.2, 5.3, 7.6, 9.9, 13.3, 16.5, 18.7, 18.5, 15.7, 12.0, 8.0, 5.5], 13 | # 平均最低气温 14 | "Average_lowest": [2.3, 2.1, 3.9, 5.5, 8.7, 11.7, 13.9, 13.7, 11.4, 8.4, 4.9, 2.7], 15 | # 平均降水量 16 | "Average_precipitation": [55.2, 40.9, 41.6, 43.7, 49.4, 45.1, 44.5, 49.5, 49.1, 68.5, 59.0, 55.2], 17 | # 平均紫外线强度 18 | "Average_ultraviolet_index": [1, 1, 2, 4, 5, 6, 6, 5, 4, 2, 1, 0], 19 | # 平均日照时间 20 | "Mean_monthly_sunshine_hours": [61.5, 77.9, 114.6, 168.7, 198.5, 204.3, 212.0, 204.7, 149.3, 116.5, 72.6, 52.0] 21 | } 22 | # 气候数据的指标名称存入列表weather_key_list中(每个Tab维度的名称) 23 | weather_key_list = list(weather_dict.keys()) 24 | # 将气候数据存入列表weather_value_list中(每个Tab维度下的y轴数据) 25 | weather_value_list = list(weather_dict.values()) 26 | # 将12各月份并赋值给变量month(x轴信息) 27 | month = ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"] 28 | 29 | 30 | def create_line(x_axis_data, y_axis_data, legend_name) -> Line: 31 | """绘制曲线 32 | 33 | 1、x轴是月份 34 | 2、y轴是不同的气候数据系列的取值 35 | 3、y轴图例是数据系列名,其中的下划线要全部换成空格 36 | 4、每个系列的y轴取值的最大值和最小值要格外强调标注出来 37 | (markpoint_opts,这个标定有点套娃,我是看pyecharts官方文档干出来的) 38 | 5、符合上述方法的图形要批量创建,用函数封装 39 | 40 | @:param x_axis_data x轴信息 41 | @:param y_axis_data y轴数据 42 | @:param legend_name y轴数据对应的图例 43 | 44 | @:return 创建好的曲线图Line对象 45 | """ 46 | line = (Line() 47 | .add_xaxis(xaxis_data=x_axis_data) 48 | .add_yaxis(series_name=legend_name, y_axis=y_axis_data, 49 | markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max"), 50 | opts.MarkPointItem(type_="min")]) 51 | ) 52 | ) 53 | return line 54 | 55 | 56 | """建立看板,可切换不同的折线图进行观察,因为后面要添加多张折线图 57 | """ 58 | tab = Tab() 59 | # 逐个创建新的曲线并添加至tab看板下 60 | for weather_key, weather_value in weather_dict.items(): 61 | # 把weather_key中的下划线换成空格呈现在最终的折线图中 62 | weather_key_modified = weather_key.replace("_", " ") 63 | tab.add( 64 | chart=create_line(x_axis_data=month, y_axis_data=weather_value, legend_name=weather_key_modified), 65 | tab_name=weather_key_modified 66 | ) 67 | 68 | # 保存路径 69 | resultPath = "./result" 70 | if not os.path.exists(path=resultPath): 71 | os.mkdir(path=resultPath) 72 | # 保存文件名 73 | resultFileName = "weather_tab.html" 74 | # 执行多折线图看板的保存 75 | tab.render(path=os.path.join(resultPath, resultFileName)) 76 | -------------------------------------------------------------------------------- /03柱线叠加图/03-1比较与趋势对照分析/example3_1/example3_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Line, Bar 3 | import pyecharts.options as opts 4 | 5 | """原始数据:日本男女收入情况调查 6 | 7 | 很巧,这次原始数据就是柱状图所需的x轴和y轴数据。 8 | 9 | 字段:年龄段 | 男性收入 | 女性收入 10 | """ 11 | # 定义存储年龄区间,男性收入、女性收入和平均收入数据列表 12 | # x轴(公共) 13 | ageList = ['<20', '20-24', '25-29', '30-34', '35-39', '40-44', '45-49', '50-54', '55-59', '60-64', '65-69', '>=70'] 14 | # y轴(两组数据) 15 | male_salaryList = [145, 262, 367, 434, 498, 570, 623, 641, 616, 457, 379, 374] 16 | female_salaryList = [106, 231, 295, 296, 292, 284, 286, 276, 261, 214, 205, 215] 17 | 18 | # 准备折线图的数据(男女平均值) 19 | average_salaryList = [(male_salary + female_salary) / 2 20 | for male_index, male_salary in enumerate(male_salaryList) 21 | for female_index, female_salary in enumerate(female_salaryList) 22 | if male_index == female_index] 23 | # 二元变量条件筛选有没有用笛卡尔积组合?可以输出验证一下。使用if做下标限制就不会出现笛卡尔积提取数据问题了 24 | # print(average_salaryList) 25 | 26 | 27 | """绘制柱线叠加图 28 | 29 | 1. 将年龄段作为x轴; 30 | 2. 将日本男性和女性收入数据作为y轴绘制柱状图;图例分别为“男性收入”“女性收入” 31 | 3. 将男女收入的平均值,作为y轴绘制折线图;y轴这里可以共享同一个坐标系 32 | 4. 将折线图叠加在柱状图上;叠加后注意折线图在更高图层,防止被柱子遮挡!!! 33 | 5. 将整个图表的标题设置为:日本男女收入情况调查; 34 | 6. 将图表保存 35 | """ 36 | # 保存路径 37 | resultPath = "./result" 38 | if not os.path.exists(path=resultPath): 39 | os.mkdir(path=resultPath) 40 | # 保存文件名 41 | resultFileName = "salary_bar_line.html" 42 | 43 | bar_line = ( 44 | Bar() 45 | .set_global_opts(title_opts=opts.TitleOpts(title="日本男女收入情况调查")) 46 | .add_xaxis(xaxis_data=ageList) 47 | .add_yaxis(series_name="男性收入", y_axis=male_salaryList) 48 | .add_yaxis(series_name="女性收入", y_axis=female_salaryList) 49 | .overlap(chart=( 50 | Line() 51 | .add_xaxis(xaxis_data=ageList) 52 | .add_yaxis(series_name="平均收入", y_axis=average_salaryList, z_level=1) # 提升图层 53 | )) 54 | .render(path=os.path.join(resultPath, resultFileName)) 55 | ) -------------------------------------------------------------------------------- /03柱线叠加图/03-2主因分析之帕累托图/example3_2/description.md: -------------------------------------------------------------------------------- 1 | # example3_2 2 | 3 | ## 1 案例背景 4 | 5 | 高三备考期间,某个年级最近一次数学考试整体考得稀烂。 6 | 7 | 备课组组长老师快要气秃了,于是决定: 8 | 9 | * 调查一下各种题型的扣分情况 10 | 11 | * 决定下周就哪些扣分严重的项目展开专题习题课 12 | 13 | > One fact: 如果所有题型都能在下周开专题习题课那当然是最好, 14 | > 但是老师们精力有限,还要考虑到学生的消化能力。 15 | 16 | 因此**不能在下周一次性覆盖到所有题型的专题**,所以要想**哪些扣分知识点最主要**应当**优先**上专题课, 17 | 从而在接下来一周**时间、精力有限的条件下**,尽**最大程度**地解决问题。 18 | 19 | ## 2 图像选择:帕累托图(Pareto Chart) 20 | 21 | ### 2.1 什么是帕累托图 22 | 23 | 帕累托图的本质是一个柱状图和一个折线图的叠加,二者共x轴,分别使用不同的y轴。 24 | 25 | * 柱状图部分的y轴:x轴字段对应的直接数据。且帕累托图绘制时要求从左到右**y轴必须自大到小排列下来** 26 | (当然y轴讲顺序x轴也会对应上的......) 27 | 28 | * 折线图部分的y轴:x轴当前字段,**加上当前字段之前所有字段**,的柱状图的**面积占比**, 29 | 所以由此可以发现,折线图在帕累托图中**始终是向上趋势,且上升到最后一个x轴字段的时候值一定是100%** 30 | 31 | ### 2.2 帕累托图的意义和作用 32 | 33 | 意义: 34 | 35 | * 柱状图的意义:y轴从大到小排开,能够表现出x轴字段的**优先情况(重要性)** 36 | 37 | * 折线图的意义:反映出x轴字段代表的事件在依照优先次序处理的情况下**完成的进度** 38 | 39 | 作用: 40 | 41 | 结合**80-20原则**,折线图80%处经过的x轴字段,重要性往往较高(柱状图直接取值很大), 42 | 在条件有限的情况下,先处理掉前80%的内容,可以在**控制成本的条件下尽快抓住问题主要矛盾着手应对**,提升效率。 43 | 44 | > 以本例为说明:备课组老师利用帕累托图可以这样决策备课 45 | 46 | * 柱状图:把知识点按扣分情况排序 47 | 48 | * 折线图:找到80%取值的位置,选出之前所有的知识点 49 | 50 | * 决策:先组织年级备课前80%的知识点专题课,其它知识点不是造成扣分的主要原因,专题讲了也没啥用,多半是粗心搞的 51 | 52 | ## 3 绘图过程 53 | 54 | 老师怎么备课就轮不到我们操心了,我们只要画出图来就行。 55 | 56 | > 注意:绘图有时不会一次性绘制得很漂亮,所以应当在指定好坐标轴的前提下,一点点去试着绘图,逐渐完善图片的细节。 57 | > 下面的绘图执行细节步骤就是针对本例一点点试出来的。 58 | 59 | ### 3.1 读取原始数据 60 | 61 | 来源:可能是年级数学校验组统计考试扣分情况的表格中提取出来的字典 62 | 63 | 字段:**知识点名称 | 平均扣分值** ,以字典存储 64 | 65 | ### 3.2 绘图数据的准备 66 | 67 | x轴:知识点名称(柱线公共) 68 | 69 | y轴: 70 | 71 | * 柱状图:平均扣分的取值,由左至右必须从大到小排列 72 | 73 | * 折线图:知识点出现的累计占比(当前知识点及其左边知识点柱状图的面积和占柱状图总面积比),纵坐标取值必须是百分数(不含%号) 74 | 75 | ### 3.3 帕累托图的柱状图部分绘制 76 | 77 | 1. x轴是知识点名称xaxis_data,适当倾斜以防止横坐标之间相互遮挡显示不全 78 | 79 | 2. y轴是平均失分的直接数值yaxis_data,图例“扣分” 80 | 81 | 3. 柱状图标题设置为“数学模块最薄弱的失分点” 82 | 83 | 4. 另起空y轴(extend_axis向yaxis依赖注入),用于后续累加的折线图纵轴取值 84 | 85 | ### 3.4 帕累托图的折线图部分绘制 86 | 87 | 1. x轴是知识点名称xaxis_data 88 | 89 | 2. y轴是知识点出现的累计占比(当前知识点及其左边知识点柱状图的面积和占柱状图总面积比,percentList),图例“扣分占比” 90 | 91 | 3. x轴确保和帕累托图的柱状图部分一致 92 | 93 | 4. y轴用帕累托图的柱状图部分之前创建的空y轴(后创建的y轴,yaxis_index为1) 94 | 95 | 5. 线容易被柱子挡住,确保折线图放在比柱状图更高图层的位置(z_level大) 96 | 97 | ### 3.5 合成帕累托图 98 | 99 | 说白了,就是往柱状图上**叠加**(overlap)折线图 100 | 101 | ### 3.6 执行保存 102 | 103 | 由于上一步合成帕累托图的时候,折线图加在了柱状图上,所以保存应该保存柱状图。 104 | -------------------------------------------------------------------------------- /03柱线叠加图/03-2主因分析之帕累托图/example3_2/example3_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Line, Bar 3 | import pyecharts.options as opts 4 | 5 | 6 | """数据来源:可能是年级数学校验组统计考试扣分情况的表格中提取出来的字典 7 | 8 | 字段:知识点名称 | 平均扣分值 ,以字典存储 9 | """ 10 | knowledge = { 11 | "圆锥曲线": 7.5, 12 | "直线与圆": 5.0, 13 | "立体几何": 10.1, 14 | "空间向量": 3.2, 15 | "数列": 14.5, 16 | "解三角": 1.9, 17 | "导数": 28.5, 18 | "函数模型": 3.3, 19 | "二项式定理": 3.0, 20 | "线性规划": 4.0, 21 | "平面向量": 3.5, 22 | "复数": 1.3, 23 | "集合": 1.9 24 | } 25 | 26 | 27 | """坐标数据准备1: 28 | 29 | 准备帕累托图的柱状图【数据】部分: 30 | 1、横坐标:知识点名称 31 | 2、纵坐标:平均扣分的取值 32 | 3、帕累托图下的约束:纵坐标由左至右必须从大到小排列 33 | """ 34 | # 取出knowledge中的键值对,以值为依据将键值对进行排序(从大到小)后,将键值对以元组的形式存在knowledge_sorted中 35 | knowledge_sorted = sorted(knowledge.items(), key=lambda knowledge_item: knowledge_item[1], reverse=True) 36 | 37 | # 取出x轴数据 38 | xaxis_data = [kn_item[0] for kn_item in knowledge_sorted] 39 | # 取出柱状图的y轴数据 40 | yaxis_data = [kn_item[1] for kn_item in knowledge_sorted] 41 | 42 | 43 | """坐标数据准备2: 44 | 45 | 准备帕累托图的折线图【数据】部分: 46 | 1、横坐标:知识点名称 47 | 2、纵坐标:知识点出现的累计占比(当前知识点及其左边知识点柱状图的面积和占柱状图总面积比) 48 | 3、帕累托图下的约束:纵坐标取值必须是百分数(不含%号) 49 | """ 50 | # 定义一个累计频率的空列表percentlist,用yaxis_data的元素初始化 51 | y_line_percentList = [data for data in yaxis_data] 52 | # 计算折线图的y轴数据总和 53 | total_y_data = sum(yaxis_data) 54 | # 添加相应的频率 55 | for index, y_data in enumerate(y_line_percentList[1:], start=1): 56 | # 当前元素 = 当前元素 + 前一个元素 57 | # 与前一个不断累加 58 | y_line_percentList[index] = y_data + y_line_percentList[index - 1] 59 | # 化作百分数形式(保留两位小数) 60 | y_line_percentList = [round(data * 100 / total_y_data, 2) for data in y_line_percentList] 61 | # 解开注释可以控制台验证取值正确性: 62 | # print(percentList) 63 | # print(yaxis_data) 64 | 65 | 66 | """帕累托图的柱状图部分绘制 67 | 68 | 1、x轴是知识点名称xaxis_data,适当倾斜以防止横坐标之间相互遮挡显示不全 69 | 2、y轴是平均失分的直接数值yaxis_data,图例“扣分” 70 | 3、柱状图标题设置为“数学模块最薄弱的失分点” 71 | 4、另起空y轴(extend_axis向yaxis依赖注入),用于后续累加的折线图纵轴取值 72 | """ 73 | bar = ( 74 | Bar() 75 | .set_global_opts(title_opts=opts.TitleOpts(title="数学模块最薄弱的失分点"), 76 | xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)) 77 | ) 78 | .add_xaxis(xaxis_data=xaxis_data) 79 | .add_yaxis(series_name="扣分", y_axis=yaxis_data) 80 | .extend_axis(yaxis=opts.AxisOpts()) 81 | ) 82 | 83 | 84 | """帕累托图的折线图部分绘制 85 | 86 | 1、x轴是知识点名称xaxis_data 87 | 2、y轴是知识点出现的累计占比(当前知识点及其左边知识点柱状图的面积和占柱状图总面积比,percentList),图例“扣分占比” 88 | 3、x轴确保和帕累托图的柱状图部分一致 89 | 4、y轴用帕累托图的柱状图部分之前创建的空y轴(后创建的y轴,yaxis_index为1) 90 | 5、线容易被柱子挡住,确保折线图放在比柱状图更高图层的位置(z_level大) 91 | """ 92 | line = ( 93 | Line() 94 | .add_xaxis(xaxis_data=xaxis_data) 95 | .add_yaxis(series_name="扣分占比", y_axis=y_line_percentList, 96 | yaxis_index=1, 97 | z_level=1) 98 | ) 99 | 100 | 101 | """万事俱备,合成帕累托图 102 | 103 | 往柱状图上叠加(overlap)折线图 104 | """ 105 | pareto = bar.overlap(line) 106 | 107 | # 保存帕累托图 108 | resultPath = "./result" 109 | if not os.path.exists(path=resultPath): 110 | os.mkdir(path=resultPath) 111 | resultFileName = "math_analysis_pareto.html" 112 | 113 | pareto.render(path=os.path.join(resultPath, resultFileName)) 114 | # 等价,但是同一张图不能重复render 115 | # bar.render(path=os.path.join(resultPath, resultFileName)) 116 | # 叠加后,折线图和柱状图的变化是相同的 117 | # line.render(path=os.path.join(resultPath, "temp_line.html")) 118 | -------------------------------------------------------------------------------- /03柱线叠加图/03-2主因分析之帕累托图/example3_3/description.md: -------------------------------------------------------------------------------- 1 | # example3_3 2 | 3 | 用途:仅利用菜品营业额,分析哪些菜品易于盈利 4 | 5 | > 分析:可视化的目的是``在原因结果、投入产出关系不够全面了解的情况下,描述和识别最有影响的因子类别``,故采用帕累托图进行绘制。 6 | > 7 | > 说人话意思就是:帕累托图的柱状图部分,可以由高向低排出营业额高的菜品(得出营业额较高的原因主次); 8 | > 而它的折线图部分,则可依据“8-2定律”在较大程度指明, 9 | > 营业额较高的菜品(共占营业额80%)有哪些,这些菜品更应该重视, 10 | > 从而指导餐厅抓主要矛盾,力保人气菜品(前80%),争取冷门菜品(后20%)热度上升或放弃低销售菜品。 -------------------------------------------------------------------------------- /03柱线叠加图/03-2主因分析之帕累托图/example3_3/example3_3.py: -------------------------------------------------------------------------------- 1 | from pyecharts.charts import Bar, Line 2 | import pyecharts.options as opts 3 | import os 4 | 5 | """原始数据 6 | 7 | 字段:菜品名 | 年营业额(单位:元) 8 | """ 9 | dish_profit = {"番茄鸡蛋": 9900, "避风塘茄夹": 6660, "广东菜心": 5210, "红烧肉": 8880, "土豆烧排骨": 2300, 10 | "木耳炒肉": 1600, "虾仁蒸蛋": 4280, "胡萝卜牛腩": 3460, "水果沙拉": 1800, "狮子头": 3200} 11 | 12 | """准备公共x轴和柱状图、折线图分别的y轴 13 | """ 14 | # 键值对按值排序 15 | dish_profit_sorted = sorted(dish_profit.items(), key=lambda x: x[1], reverse=True) 16 | 17 | # 公共x轴数据 18 | xaxisData = [data for (data, _) in dish_profit_sorted] 19 | # 柱状图y轴数据 20 | yaxisBar = [data for (_, data) in dish_profit_sorted] 21 | 22 | # 计算折线图y轴所需数据(用yaxisBar初始化) 23 | yaxisLine = [data for data in yaxisBar] 24 | # y轴项目总和 25 | sumYData = sum(yaxisBar) 26 | # 求出折线图y轴下的值(百分数,无百分号形式,保留两位小数) 27 | for index, y_data in enumerate(yaxisLine[1:], start=1): 28 | yaxisLine[index] = y_data + yaxisLine[index - 1] 29 | yaxisLine = [round(y_data / sumYData * 100, 2) for y_data in yaxisLine] 30 | # print(yaxisLine) 31 | 32 | 33 | """执行绘图 34 | 35 | 1. 将菜品名字作为x轴; 36 | 2. 菜品盈利额作为y轴,绘制柱状图,图例设置为”盈利额“; 37 | 3. 计算各个菜品的盈利占总盈利额的比例,作为y轴绘制折线图,图例设置为"盈利占比(%)"; 38 | 4. x轴的标签旋转45度,防遮挡; 39 | 5. 整个表的标题设置为“各菜品盈利额”; 40 | 6. 将折线图叠加(overlap)在柱状图上。 41 | 7. 将图表保存 42 | 8. y轴取值均只保留2位小数 43 | 9. 折线图y轴在柱状图y轴图层之上,防止柱子遮挡折线 44 | """ 45 | # 保存路径 46 | resultPath = "./result" 47 | if not os.path.exists(resultPath): 48 | os.mkdir(path=resultPath) 49 | # 保存文件名 50 | resultFileName = "restaurant_pareto.html" 51 | # 执行绘图并保存 52 | pareto = ( 53 | Bar() 54 | .set_global_opts(xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)), 55 | title_opts=opts.TitleOpts(title="各菜品盈利额")) 56 | .add_xaxis(xaxis_data=xaxisData) 57 | .add_yaxis(series_name="盈利额", y_axis=yaxisBar) 58 | .extend_axis(yaxis=opts.AxisOpts()) # 新y轴:index为1 59 | .overlap( 60 | chart=( 61 | Line() 62 | .add_xaxis(xaxis_data=xaxisData) 63 | .add_yaxis(series_name="盈利占比(%)", y_axis=yaxisLine, yaxis_index=1, z_level=1) 64 | ) 65 | ) 66 | .render(path=os.path.join(resultPath, resultFileName)) 67 | ) 68 | -------------------------------------------------------------------------------- /03柱线叠加图/03-2主因分析之帕累托图/example3_4/description.md: -------------------------------------------------------------------------------- 1 | # example3_4 2 | 3 | 用途:信用卡公司发现最近有一大批客户的信用卡无法激活,调查后发现有若干原因导致了这些现象,现在需要找出主要原因优先处理。 4 | 5 | > 分析:可视化的目的是``在原因结果、投入产出关系不够全面了解的情况下,描述和识别最有影响的因子类别``,故采用帕累托图进行绘制。 6 | > 7 | > 说人话意思就是:哪些原因是造成信用卡无法激活问题的主要问题(柱状图说明)?短期内优先处理哪些问题可以抓住主要矛盾,最快解决绝大多数问题(折线图说明)。 -------------------------------------------------------------------------------- /03柱线叠加图/03-2主因分析之帕累托图/example3_4/example3_4.py: -------------------------------------------------------------------------------- 1 | from pyecharts.charts import Bar, Line 2 | import pyecharts.options as opts 3 | import os 4 | 5 | 6 | """原始数据 7 | 8 | 字段:错误类型 | 近一周出现次数 9 | """ 10 | causes_statistics = { 11 | "名字拼写错误": 27, 12 | "地址错误": 16, 13 | "电话号码错误": 12, 14 | "邮箱错误": 9, 15 | "验证码错误": 3 16 | } 17 | 18 | 19 | """提取坐标轴数据 20 | 21 | x轴:错误类型(柱线公共) 22 | 柱状图y轴:x轴对应直接数据,自左向右由大到小。图例“原因” 23 | 折线图y轴:当前字段及其前柱子面积占比之和。图例“原因占比(%)” 24 | """ 25 | # 预备:将原始数据键值对按值自大到小排序 26 | causes_statistics_sorted = sorted(causes_statistics.items(), 27 | key=lambda cause: cause[1], reverse=True) 28 | # 输出一下证明它是列表 29 | # print(causes_statistics_sorted) 30 | # 提取公共x轴 31 | x_data = [xData for xData, _ in causes_statistics_sorted] 32 | # 提取柱状图y轴 33 | y_data_bar = [yDataBar for _, yDataBar in causes_statistics_sorted] 34 | 35 | # y轴数据总和 36 | yTotal = sum(y_data_bar) 37 | # 提取折线图y轴(不能直接用y_data_bar赋值柱状图存的原y轴数据,避免浅复制) 38 | y_data_line = list(y_data_bar) 39 | # 计算前所有字段面积占比(百分值去%符号),保留两位小数 40 | for index, y_data in enumerate(y_data_line[1:], start=1): 41 | y_data_line[index] = y_data + y_data_line[index - 1] 42 | y_data_line = [round(y_data*100/yTotal, 2) for y_data in y_data_line] 43 | 44 | 45 | """绘制帕累托图 46 | 47 | 1. 将未激活原因作为x轴; 48 | 2. 将未激活数量作为y轴,绘制柱状图; 49 | 3. 将柱状图的图例设置为原因,将柱状图的透明度(opacity,用法查pyecharts官方文档)设置为0.5,以防止遮挡折线图部分; 50 | 4. 将整个图表的标题设置为:信用卡未激活的原因; 51 | 5. 另起y轴,将累计频率作为y轴,绘制折线图,将折线图的图例设置为"原因占比(%)"; 52 | 6. 将折线图叠加在柱状图上。 53 | 7. 将文件保存 54 | """ 55 | # 保存路径 56 | resultPath = "./result" 57 | if not os.path.exists(path=resultPath): 58 | os.mkdir(path=resultPath) 59 | # 保存文件名 60 | resultFileName = "credit_company_pareto.html" 61 | # 执行绘图 62 | pareto = ( 63 | Bar() 64 | .set_global_opts(title_opts=opts.TitleOpts(title="信用卡未激活的原因")) 65 | .add_xaxis(xaxis_data=x_data) 66 | .add_yaxis(series_name="原因", y_axis=y_data_bar, yaxis_index=0, 67 | itemstyle_opts=opts.ItemStyleOpts(opacity=0.5)) 68 | .extend_axis(yaxis=opts.AxisOpts()) # 添加新的空y轴,index为1 69 | .overlap(chart=( 70 | Line() 71 | .add_xaxis(xaxis_data=x_data) 72 | .add_yaxis(series_name="原因占比(%)", y_axis=y_data_line, 73 | yaxis_index=1) 74 | )) 75 | .render(path=os.path.join(resultPath, resultFileName)) 76 | ) -------------------------------------------------------------------------------- /03柱线叠加图/03-2主因分析之帕累托图/whatisParetoChart.md: -------------------------------------------------------------------------------- 1 | # 帕累托图(Pareto Chart) 2 | 3 | ## 1 什么是帕累托图 4 | 5 | 帕累托图的本质是**一个柱状图和一个折线图的叠加**,二者共x轴,分别使用不同的y轴。 6 | 7 | * 柱状图部分的y轴:x轴字段对应的直接数据。且帕累托图绘制时要求从左到右**y轴必须自大到小排列下来** 8 | (当然y轴讲顺序x轴也会对应上的......) 9 | 10 | * 折线图部分的y轴:x轴当前字段,**加上当前字段之前所有字段**,的柱状图的**面积占比**, 11 | 所以由此可以发现,折线图在帕累托图中**始终是向上趋势,且上升到最后一个x轴字段的时候值一定是100%** 12 | 13 | ## 2 数学含义 14 | 15 | * 柱状图的含义:y轴从大到小排开,能够表现出x轴字段的**优先情况(重要性)** 16 | 17 | * 折线图的含义:反映出x轴字段代表的事件在依照优先次序处理的情况下**完成的进度** 18 | 19 | ## 3 指导意义 20 | 21 | 结合**80-20原则**,折线图80%处经过的x轴字段,重要性往往较高(柱状图直接取值很大), 22 | 在条件有限的情况下,先处理掉前80%的内容,可以在**控制成本的条件下尽快抓住问题主要矛盾着手应对**,提升效率。 -------------------------------------------------------------------------------- /04构成和差异之堆叠柱状图/04-1构成和差异结合分析/example4_1/example4_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Bar 3 | import pyecharts.options as opts 4 | 5 | 6 | """原始数据:2020下半年部分商品销售额变化表 7 | 8 | 下半年一共跟踪了choc(olate)、gum和walnut的销售情况(单位:元) 9 | 接下来分析销售额的组成和比较不同月份各各产品销售情况的差异 10 | """ 11 | # 设置列表 12 | months = ["7月", "8月", "9月", "10月", "11月", "12月"] 13 | choc_sales = [5340, 6078, 6460, 6475, 7431, 8038] 14 | gum_sales = [4340, 4379, 4460, 5075, 5431, 6038] 15 | walnut_sales = [6340, 5579, 4460, 4075, 3431, 3038] 16 | 17 | 18 | """执行绘图 19 | 20 | 1、采取直接数据的堆叠方式展现(同一个x轴下的数据在同一个stack展示) 21 | 2、x轴:月份 22 | 3、y轴:产品对应月份销售额。图例分别是:巧克力、口香糖、核桃 23 | 4、整个图表的标题:2020下半年商品销售额变化 24 | 5、堆叠:指定y轴数据在同一个stack(怎么搞的去查pyecharts官方文档) 25 | 6、避免数据遮挡:柱子堆叠的时候,底下柱子的数值label会被上面的柱子遮挡, 26 | 这是可以设置数值label显示在自己的柱子中间(怎么搞的去查pyecharts官方文档) 27 | """ 28 | # 创建Bar对象,赋值给变量bar 29 | stacked_bar = ( 30 | Bar() 31 | .set_global_opts(title_opts=opts.TitleOpts(title="2020下半年商品销售额变化")) 32 | .add_xaxis(xaxis_data=months) 33 | .add_yaxis( 34 | series_name="巧克力", 35 | y_axis=choc_sales, 36 | stack="sales", 37 | label_opts=opts.LabelOpts(position="inside") 38 | ) 39 | .add_yaxis( 40 | series_name="口香糖", 41 | y_axis=gum_sales, 42 | stack="sales", # stack同名就堆叠一个柱子上 43 | label_opts=opts.LabelOpts(position="inside") 44 | ) 45 | .add_yaxis( 46 | series_name="核桃", 47 | y_axis=walnut_sales, 48 | stack="sales", 49 | label_opts=opts.LabelOpts(position="inside") 50 | ) 51 | ) 52 | 53 | 54 | # 使用render函数将堆积柱状图保存在指定路径 55 | resultPath = "./result" 56 | if not os.path.exists(path=resultPath): 57 | os.mkdir(path=resultPath) 58 | resultFileName = "sales_stacked_bar.html" 59 | 60 | stacked_bar.render(path=os.path.join(resultPath, resultFileName)) 61 | -------------------------------------------------------------------------------- /04构成和差异之堆叠柱状图/04-1构成和差异结合分析/example4_2/example4_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Bar 3 | import pyecharts.options as opts 4 | 5 | """准备数据:2020年1-3季度GDP(单位:亿元) 6 | """ 7 | # 创建变量x_data储存季度名称,作为x轴的数据 8 | x_data = ["第一季度", "第二季度", "第三季度"] 9 | # 将每个产业的每个季度的生产值保存在一个字典中 10 | data = { 11 | "第一产业": [8014.7, 13992.8, 20528.5], 12 | "第二产业": [67968.9, 93094.8, 94684.4], 13 | "第三产业": [107685.8, 118408.4, 123963.2] 14 | } 15 | 16 | """执行堆叠柱状图绘制 17 | 18 | 1. x轴设置为列表x_data。 19 | 2. 逐个添加y轴数据data 20 | 图例设置为字典的key,取值为key中对应的value 21 | 堆积名称stack统一设置为"GDP", 22 | 数据标签的位置设置为内部居中(inside)。 23 | 3. 图表标题为"2020年1-3季度GDP(单位:亿元)" 24 | 4. 将图表保存。 25 | """ 26 | stacked_bar = ( 27 | Bar() 28 | .set_global_opts(title_opts=opts.TitleOpts(title="2020年1-3季度GDP(单位:亿元)")) 29 | .add_xaxis(xaxis_data=x_data) 30 | ) 31 | # 循环添加y轴数据 32 | for key, value in data.items(): 33 | stacked_bar.add_yaxis( 34 | series_name=key, 35 | y_axis=value, 36 | stack="GDP", 37 | label_opts=opts.LabelOpts(position="inside") 38 | ) 39 | # 保存路径和文件名 40 | resultPath = "./result" 41 | if not os.path.exists(path=resultPath): 42 | os.mkdir(path=resultPath) 43 | resultFileName = "GDP_stacked_bar.html" 44 | 45 | stacked_bar.render(path=os.path.join(resultPath, resultFileName)) 46 | -------------------------------------------------------------------------------- /04构成和差异之堆叠柱状图/04-1构成和差异结合分析/example4_3/example4_3.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Bar 3 | import pyecharts.options as opts 4 | 5 | """准备数据:一年来商品的销售 6 | 7 | walnut_sales可能是下半年引入的新品 8 | 前半年无数据部分用"-"填充空位,确保x轴和y轴对得上位 9 | """ 10 | # 月份 11 | months = [f"{mon}月" for mon in range(1, 13)] 12 | # 各种商品的销售额 13 | choc_sales = [2045, 2580, 2789, 3455, 3256, 3678, 5340, 6078, 6460, 6475, 7431, 8038] 14 | gum_sales = [1234, 1467, 1754, 2354, 2897, 3487, 4340, 4379, 4460, 5075, 5431, 6038] 15 | walnut_sales = ["-", "-", "-", "-", "-", "-", 6340, 5579, 4460, 4075, 3431, 3038] 16 | 17 | """执行堆叠柱状图绘制和保存 18 | 19 | 1、各月各商品销售额堆积图中: 20 | 第一层为巧克力的销售额。 21 | 第二层为口香糖的销售额。 22 | 第三层为核桃的销售额。 23 | 2、x轴是月份 24 | 3、y轴是各种销售额,图例分别为巧克力、口香糖、核桃,采用堆叠方式,堆叠stack统一命名为sales 25 | 4、数值label要防止被遮挡,显示在柱子中间 26 | 5、1~6月部分新品还没有数据,用"-"顶替数据缺项 27 | 6、整张图的标题是“2020全年商品销售额变化” 28 | 7、考虑到x轴真的太!!!多!!!了!!! 29 | 显示的时候考虑把x轴和y轴翻转(reversal)一下(横过来),不然图像太长了...... 30 | """ 31 | # 保存路径 32 | resultPath = "./result" 33 | if not os.path.exists(path=resultPath): 34 | os.mkdir(path=resultPath) 35 | # 保存文件名 36 | resultFileName = "sales_annual_stacked_bar.html" 37 | # 绘图 38 | stacked_bar = ( 39 | Bar() 40 | .set_global_opts(title_opts=opts.TitleOpts(title="2020全年商品销售额变化")) 41 | .add_xaxis(xaxis_data=months) 42 | .add_yaxis( 43 | series_name="巧克力", 44 | y_axis=choc_sales, 45 | stack="sales", # 先加y轴的堆叠在底下,后加y轴的堆叠在上面 46 | label_opts=opts.LabelOpts(position="inside") 47 | ) 48 | .add_yaxis( 49 | series_name="口香糖", 50 | y_axis=gum_sales, 51 | stack="sales", 52 | label_opts=opts.LabelOpts(position="inside") 53 | ).add_yaxis( 54 | series_name="核桃", 55 | y_axis=walnut_sales, 56 | stack="sales", 57 | label_opts=opts.LabelOpts(position="inside") 58 | ) 59 | .reversal_axis() # xy轴翻转,把图表横过来 60 | .render(path=os.path.join(resultPath, resultFileName)) 61 | ) 62 | -------------------------------------------------------------------------------- /04构成和差异之堆叠柱状图/04-2变化量分析之瀑布图/example4_4/example4_4.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Bar 3 | import pyecharts.options as opts 4 | 5 | """原数据:个体商户12个月的资金流动情况 6 | 7 | 利用瀑布图表达出每个月的盈亏变化 8 | """ 9 | x_data = ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"] 10 | # 当月资金流动情况(+盈利,-亏损) 11 | alter_data = [4000, 3450, 2850, -1800, -1500, 9000, 1300, 1000, 2100, -1000, -4200, -1510] 12 | # 年初总资金 13 | beginTotal = 5000 14 | # 年末剩余总资金 15 | endTotal = 18690 16 | 17 | """准备瀑布图数据 18 | 19 | 增加年初值和年末余值单独表示,用一组单独的柱子表示(体现不同的颜色) 20 | 中间1~12月份的数据全部用“变化量”表示(+盈-亏),变化取值悬浮于半空中,体现总值的大致走向 21 | 体现“柱子漂浮”的现象,需要柱子下方有“打底”的白色柱子垫着 22 | 打底柱子上方,放当月盈利值或者亏损值(需要创建盈利柱子和亏损柱子数据分开讨论,这样最终画出来,不同颜色的柱子区分能区分盈利和亏损) 23 | 打底柱子当月取值:当月总额-盈利值(如果是盈利)或者当月总额(如果是亏损) 24 | 所以打底柱子想求出来,先要把各个月当月总额求出来 25 | """ 26 | # 扩展x轴,增加年初值和年末余值两项 27 | x_data.insert(0, "年初值") 28 | x_data.append("年末余值") 29 | 30 | # 增加的两项对应值单独创建一组y轴,区分颜色 31 | total_data = ["-"] * len(x_data) 32 | total_data[0] = beginTotal 33 | total_data[-1] = endTotal 34 | 35 | # 盈利提取数据y轴对应项(注意两端缺项) ["-"] * 14 36 | y_profit_extracted_data = ["-"] * len(x_data) 37 | # 亏损提取数据y轴对应项(注意两端缺项) ["-"] * 14 38 | y_loss_extracted_data = ["-"] * len(x_data) 39 | # 放盈利/亏损提取数据两种情景的柱子,下标从1开始(跳过头部的缺项) 40 | for extracted_index, alter_item in enumerate(alter_data, start=1): 41 | if alter_item > 0: 42 | y_profit_extracted_data[extracted_index] = alter_item 43 | elif alter_item < 0: 44 | # 负数取相反数 45 | y_loss_extracted_data[extracted_index] = -alter_item 46 | # else,即alter_item == 0:保持缺项 47 | 48 | # 打底柱子取值的计算(两端缺项) ["-"] * 14 49 | base_data = ["-"] * len(x_data) 50 | # 辅助计算使用:存放当月变化后的总收入(月末) ["-"] * 12 51 | temp_total_data = ["-"] * len(alter_data) 52 | temp_total_data[0] = beginTotal + alter_data[0] 53 | for index, alter_item in enumerate(alter_data[1:], start=1): 54 | temp_total_data[index] = temp_total_data[index - 1] + alter_item 55 | # 计算base_data 56 | for index, alter_item in enumerate(alter_data): 57 | if alter_item > 0: 58 | base_data[index + 1] = temp_total_data[index] - alter_item 59 | elif alter_item < 0: 60 | base_data[index + 1] = temp_total_data[index] 61 | else: # alter_item == 0 62 | base_data[index] = "-" 63 | print(base_data) 64 | 65 | """绘制瀑布图 66 | 67 | - 图例统一设置为空,堆叠stack统一为"waterfall_plot" 68 | - 打底柱子颜色设置为白色; 69 | - 其它x轴和y轴按照顺序进行叠加即可,盈利和亏损的悬浮柱子要设置图例,分别为“盈利”“亏损” 70 | - 设置图片标题为"全年每月收入与支出";注意避免横坐标丢失。 71 | - 将瀑布图保存 72 | """ 73 | # 保存路径 74 | resultPath = "./result" 75 | if not os.path.exists(path=resultPath): 76 | os.mkdir(path=resultPath) 77 | # 保存文件名 78 | resultFileName = "in_out_waterfall_stacked_bar.html" 79 | 80 | waterfall_stacked_bar = ( 81 | Bar() 82 | .set_global_opts( 83 | title_opts=opts.TitleOpts(title="下半年每月收入与支出"), 84 | xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)) 85 | ) 86 | .add_xaxis( 87 | xaxis_data=x_data, 88 | ) 89 | .add_yaxis( 90 | series_name="", 91 | y_axis=base_data, 92 | color="white", 93 | stack="waterfall_plot", 94 | # 隐藏起来打底的柱子 95 | label_opts=opts.LabelOpts(is_show=False), 96 | tooltip_opts=opts.TooltipOpts(is_show=False) 97 | ) 98 | .add_yaxis( 99 | series_name="", 100 | y_axis=total_data, 101 | stack="waterfall_plot" 102 | ) 103 | .add_yaxis( 104 | series_name="盈利", 105 | y_axis=y_profit_extracted_data, 106 | stack="waterfall_plot" 107 | ) 108 | .add_yaxis( 109 | series_name="亏损", 110 | y_axis=y_loss_extracted_data, 111 | stack="waterfall_plot" 112 | ) 113 | .render(path=os.path.join(resultPath, resultFileName)) 114 | ) -------------------------------------------------------------------------------- /04构成和差异之堆叠柱状图/04-2变化量分析之瀑布图/whatisWaterfallPlot.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/04构成和差异之堆叠柱状图/04-2变化量分析之瀑布图/whatisWaterfallPlot.md -------------------------------------------------------------------------------- /05构成和差异之饼状图/05-1普通饼状图/example5_1/example5_1.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/05构成和差异之饼状图/05-1普通饼状图/example5_1/example5_1.py -------------------------------------------------------------------------------- /05构成和差异之饼状图/05-2环状图、南丁格尔玫瑰图/example5_2/example5_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Pie 3 | import pyecharts.options as opts 4 | 5 | """准备原始数据:IT网站各分区下的访问量 6 | 7 | 略去读文件过程,读取结果如下: 8 | """ 9 | # 绘制饼状图,数据项及其取值按照一个个元组进行组合 10 | user_data = [('深度学习', 1000), ('数据分析', 700), ('Web开发', 500), ('爬虫开发', 350), 11 | ('图像处理', 250), ('机器学习', 220), ('数据挖掘', 200), ('人工智能', 180), 12 | ('自然语言处理', 160), ('游戏开发', 140), ('数据库开发', 120), ('可视化工程', 832)] 13 | # 预处理:依照值将user_data从大到小排个序,后面显示会更漂亮 14 | user_data.sort(key=lambda data_item: data_item[1], reverse=True) 15 | 16 | 17 | """执行绘图 18 | 19 | 1. 将列表中的元组按照元组中的第二个数的大小,也就是阅读量的大小,从大到小排序。 20 | 2. 设置数据标签的格式为“图例: 占比”(占比在显示时要带上百分号),(怎样设置格式formatter去查pyecharts官方文档) 21 | 3. 设置按照玫瑰图的方式显示,且圆心角相同,数值大小通过每一块饼的大小直观比对(这一步需要查pyecharts官方文档)。 22 | 4. 设置图表的标题为"阅读量统计”。 23 | 5. 适当调整图表中一些元素的位置,避免遮挡、排版凌乱等问题 24 | 6. 生成图表,保存 25 | """ 26 | # 保存路径 27 | resultPath = "./result" 28 | if not os.path.exists(path=resultPath): 29 | os.mkdir(path=resultPath) 30 | # 保存文件名 31 | resultFileName = "web_visit_rose_pie.html" 32 | 33 | rose_pie = ( 34 | Pie() 35 | .set_global_opts( 36 | title_opts=opts.TitleOpts(title="阅读量统计", subtitle="技术专栏模块"), 37 | # 图例位置默认会遮挡标题,下面这样的调整是不断试错找出的布局方式 38 | legend_opts=opts.LegendOpts( 39 | pos_left="1%", 40 | pos_top="60%", 41 | orient="vertical", 42 | type_="scroll" 43 | ) 44 | ) 45 | .add( 46 | series_name="用户数据", 47 | data_pair=user_data, 48 | label_opts=opts.LabelOpts( 49 | # {b}和{d}表示图例名称和占比数值(不带百分号),这一步控制每一块饼旁边显示的东西是什么,具体地可以查文档 50 | formatter="{b}: {d}%" 51 | ), 52 | rosetype="area" # 圆心角相同,数据差别靠每一块饼的半径凸显出来 53 | ) 54 | .render(path=os.path.join(resultPath, resultFileName)) 55 | ) 56 | -------------------------------------------------------------------------------- /05构成和差异之饼状图/05-2环状图、南丁格尔玫瑰图/example5_2/result/web_visit_rose_pie.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Awesome-pyecharts 6 | 7 | 8 | 9 | 10 |
11 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /05构成和差异之饼状图/05-2环状图、南丁格尔玫瑰图/example5_3/example5_3.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Pie 3 | import pyecharts.options as opts 4 | 5 | """原数据:某连锁店开通会员的人群所在地区分布 6 | 7 | 键值对:地区名 | 人数(单位;人) 8 | """ 9 | data = { 10 | '北京': 78, '上海': 77, '黑龙江': 60, '吉林': 75, '辽宁': 91, '贵州': 93, '新疆': 82, '西藏': 61, '青海': 62, 11 | '四川': 40, '云南': 58, '陕西': 24, '重庆': 77, '内蒙古': 53, '广西': 46, '海南': 92, '澳门': 55, '湖南': 72, 12 | '江西': 65, '福建': 57, '安徽': 36, '浙江': 77, '江苏': 48, '宁夏': 32, '山西': 70, '河北': 86, '天津': 94 13 | } 14 | # 附带配色方案(生成图案顺时针依次显示的颜色) 15 | color_series = ['#FAE927', '#E9E416', '#C9DA36', '#9ECB3C', '#6DBC49', 16 | '#37B44E', '#3DBA78', '#14ADCF', '#209AC9', '#1E91CA', 17 | '#2C6BA0', '#2B55A1', '#2D3D8E', '#44388E', '#6A368B', 18 | '#7D3990', '#A63F98', '#C31C88', '#D52178', '#D5225B', 19 | '#D02C2A', '#D44C2D', '#F57A34', '#FA8F2F', '#D99D21', 20 | '#CF7B25', '#CF7B25', '#CF7B25'] 21 | # 预处理:将原数据按照从大到小取值的顺序排序,生成用于绘图的标签-数值元组 22 | data_sorted = sorted(data.items(), key=lambda data_item: data_item[1], reverse=True) 23 | 24 | 25 | """绘图南丁格尔玫瑰图 26 | 27 | 数据的系列名称(series_name)统一为“会员地区分布” 28 | 按照给定的配色方案给每块饼配色 29 | 绘制为南丁格尔环状玫瑰图 30 | 设置玫瑰图类型(rosetype)圆心角相同,数据差异仅通过半径给出 31 | 环的内半径(radius)为画布尺寸(长宽较小者)的30%,环的最大外半径(radius)(数值最大的饼的外径)为画布的100% 32 | 每块饼的标签(label)显示在饼的内部,字号为8,标签显示格式为"{数据项名}:{直接数值}人" 33 | 图例(legend)不显示 34 | 整张图标题设为“会员地区分布” 35 | 保存图表 36 | """ 37 | # 保存路径 38 | resultPath = "./result" 39 | if not os.path.exists(path=resultPath): 40 | os.mkdir(path=resultPath) 41 | # 文件名 42 | resultFileName = "vip_rose_pie.html" 43 | # 执行绘图 44 | rose_pie = ( 45 | Pie() 46 | .set_global_opts( 47 | title_opts=opts.TitleOpts(title="会员地区分布"), 48 | legend_opts=opts.LegendOpts(is_show=False) 49 | ) 50 | .set_colors(colors=color_series) 51 | .add( 52 | series_name="会员地区分布", 53 | data_pair=data_sorted, 54 | rosetype="area", 55 | radius=("30%", "100%"), 56 | label_opts=opts.LabelOpts( 57 | position="inside", 58 | font_size=8, 59 | formatter="{b}:{c}人" 60 | ) 61 | ) 62 | .render(path=os.path.join(resultPath, resultFileName)) 63 | ) -------------------------------------------------------------------------------- /05构成和差异之饼状图/05-2环状图、南丁格尔玫瑰图/example5_4/example5_4.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Pie 3 | from pyecharts import options as opts 4 | 5 | """原始数据:两场网络直播带货中,不同产品的销量情况 6 | 7 | 数据:(产品名称, 销量) 8 | """ 9 | liveCommerceOne = [("衬衫", 111), ("羊毛衫", 122), ("雪纺衫", 113), ("裤子", 210), ("高跟鞋", 170), ("袜子", 109)] 10 | liveCommerceTwo = [("衬衫", 139), ("羊毛衫", 241), ("雪纺衫", 325), ("裤子", 260), ("高跟鞋", 210), ("袜子", 335)] 11 | 12 | 13 | """绘制多个南丁格尔玫瑰图(一共2个图表) 14 | 15 | 整个图表标题设为“网络直播带货销量对比” 16 | 图例系列名(series_name)均设为空 17 | 玫瑰图最大外径为绘图区(长宽小者)的60%,内径为绘图区的20% 18 | 玫瑰图类型设置为圆心角相同,数据大小仅通过 19 | 图1位置(即圆心位置)在绘图区的(25%, 50%)处(相对绘图区水平的25%和竖直的50%处) 20 | 图2位置(即圆心位置)在绘图区的(75%, 50%)处 21 | 数据标签(label)放在每一块饼的内部显示,格式为"{百分比取值}%" 22 | """ 23 | # 保存路径 24 | resultPath = "./result" 25 | if not os.path.exists(path=resultPath): 26 | os.mkdir(path=resultPath) 27 | # 保存文件名 28 | resultFileName = "live_commerce_rose_pie.html" 29 | # 执行绘图 30 | rose_pie = ( 31 | Pie() 32 | .set_global_opts(title_opts=opts.TitleOpts(title="网络直播带货销量对比")) 33 | .add( 34 | series_name="", 35 | data_pair=liveCommerceOne, 36 | rosetype="area", 37 | radius=("20%", "60%"), 38 | center=("25%", "50%"), 39 | label_opts=opts.LabelOpts( 40 | position="inside", 41 | formatter="{d}%" 42 | ) 43 | ) 44 | .add( 45 | series_name="", 46 | data_pair=liveCommerceTwo, 47 | rosetype="area", 48 | radius=("20%", "60%"), 49 | center=("75%", "50%"), 50 | label_opts=opts.LabelOpts( 51 | position="inside", 52 | formatter="{d}%" 53 | ) 54 | ) 55 | .render(path=os.path.join(resultPath, resultFileName)) 56 | ) 57 | -------------------------------------------------------------------------------- /05构成和差异之饼状图/05-2环状图、南丁格尔玫瑰图/example5_4/result/live_commerce_rose_pie.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Awesome-pyecharts 6 | 7 | 8 | 9 | 10 |
11 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /05构成和差异之饼状图/whatisPieChart.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/05构成和差异之饼状图/whatisPieChart.md -------------------------------------------------------------------------------- /06别把数据直接放程序里之使用openpyxl/06-1openpyxl读取excel数据演示/example6_1/example6_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openpyxl 3 | from openpyxl import Workbook 4 | from openpyxl.worksheet.worksheet import Worksheet 5 | 6 | """读取数据""" 7 | # 资源文件统一所在路径 8 | resourcesPath = "./resources" 9 | # 数据文件名 10 | salesPath = "table.xlsx" 11 | # 读文件(工作簿) 12 | salesBook = openpyxl.load_workbook(filename=os.path.join(resourcesPath, salesPath)) # type: Workbook 13 | # 选择工作表 14 | fruitSalesSheet = salesBook["水果销量"] # type: Worksheet 15 | # 跳过表头,逐行读取数据 16 | for rowContent in fruitSalesSheet.iter_rows(min_row=2, values_only=True): 17 | # 以列表形式输出 18 | print(list(rowContent)) 19 | -------------------------------------------------------------------------------- /06别把数据直接放程序里之使用openpyxl/06-1openpyxl读取excel数据演示/example6_1/resources/table.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/06别把数据直接放程序里之使用openpyxl/06-1openpyxl读取excel数据演示/example6_1/resources/table.xlsx -------------------------------------------------------------------------------- /06别把数据直接放程序里之使用openpyxl/06-2openpyxl结合可视化演示/example6_2/example6_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openpyxl 3 | from openpyxl import Workbook 4 | from openpyxl.worksheet.worksheet import Worksheet 5 | from pyecharts.charts import Line 6 | import pyecharts.options as opts 7 | 8 | """指定基础配置值 9 | 10 | 所有路径配置相关的值放在单独的配置文件,或者这里为了方便就放最前面 11 | """ 12 | # 数据资源统一路径 13 | resourcesPath = "./resources" 14 | # 数据资源文件名 15 | resourcesFileName = "table.xlsx" 16 | # 数据所在工作表 17 | colaSheetName = "销量" 18 | 19 | # 保存路径 20 | resultPath = "./result" 21 | if not os.path.exists(path=resultPath): 22 | os.mkdir(path=resultPath) 23 | # 保存文件名 24 | resultFileName = "sales_line.html" 25 | 26 | """获取数据:不同的可乐在1年内的月销量变化 27 | 28 | x轴:月份 29 | y轴:月销量,图例是相应类型可乐的名字 30 | """ 31 | 32 | 33 | def read_rows(filename="./", sheetname="Sheet") -> list: 34 | """ 35 | 从excel文档中读出所有行,每一行都是列表,所有行存入一个大列表,返回出去 36 | 读取时,不做清洗,只是忠诚地把文件里的数据转移出来到列表里 37 | :param filename: excel文件名(完整路径) 38 | :param sheetname: 工作表Worksheet名 39 | :return: list 40 | """ 41 | # 加载文件+选表 两步合并 42 | colaSheet = openpyxl.load_workbook(filename=filename)[sheetname] # type: Worksheet 43 | # 读出所有行数据 44 | rowData = [list(rowContent) for rowContent in colaSheet.iter_rows(values_only=True)] 45 | return rowData 46 | 47 | 48 | # 读出表格数据 49 | rowData = read_rows(filename=os.path.join(resourcesPath, resourcesFileName), sheetname=colaSheetName) 50 | # 取出x轴数据(表头,注意第一列空的,要砍掉) 51 | x_data = rowData[0][1:] 52 | # 取出y轴数据(第2行开始) 53 | y_data = dict() 54 | for rowItem in rowData[1:]: 55 | # eval函数剥开字符串两侧引号,避免字符串数值,适当过滤一下填入数据时候出现的两端空白 56 | y_data[rowItem[0]] = [eval(str(item).strip()) for item in rowItem[1:]] 57 | 58 | 59 | """绘制多y轴折线图 60 | 61 | 1. 读取文档的月份作为x轴,一共有1~12个月; 62 | 2. 读取文档中的数据将商品销量作为y轴,绘制折线图 ; 63 | 3. 图例设置为对应行的商品名称; 64 | 4. 将整个图表标题设置为:增长趋势的比较 ; 65 | 5. 将文件保存 66 | """ 67 | line = ( 68 | Line() 69 | .set_global_opts(title_opts=opts.TitleOpts(title="增长趋势的比较")) 70 | .add_xaxis(xaxis_data=x_data) 71 | ) 72 | for yaxis_series, yaxis_data in y_data.items(): 73 | line.add_yaxis(series_name=yaxis_series, y_axis=yaxis_data) 74 | line.render(path=os.path.join(resultPath, resultFileName)) 75 | -------------------------------------------------------------------------------- /06别把数据直接放程序里之使用openpyxl/06-2openpyxl结合可视化演示/example6_2/resources/table.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/06别把数据直接放程序里之使用openpyxl/06-2openpyxl结合可视化演示/example6_2/resources/table.xlsx -------------------------------------------------------------------------------- /06别把数据直接放程序里之使用openpyxl/06-2openpyxl结合可视化演示/example6_3/example6_3.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openpyxl 3 | from openpyxl import Workbook 4 | from openpyxl.worksheet.worksheet import Worksheet 5 | from pyecharts.charts import Bar 6 | import pyecharts.options as opts 7 | 8 | """指定基础配置值 9 | 10 | 所有路径配置相关的值放在单独的配置文件,或者这里为了方便就放最前面 11 | """ 12 | # 数据资源统一路径 13 | resourcesPath = "./resources" 14 | # 数据资源文件名 15 | resourcesFileName = "核桃销量.xlsx" 16 | # 数据所在工作表 17 | yearSheetName = "2020年" 18 | 19 | # 保存路径 20 | resultPath = "./result" 21 | if not os.path.exists(path=resultPath): 22 | os.mkdir(path=resultPath) 23 | # 保存文件名 24 | resultFileName = "nut_sales_line.html" 25 | 26 | """获取数据:不同的商品在1年内的月销量变化 27 | 28 | x轴:月份 29 | y轴:月销量,图例是相应类型商品的名字 30 | """ 31 | 32 | 33 | def read_rows(filename="./", sheetname="Sheet") -> list: 34 | """ 35 | 从excel文档中读出所有行,每一行都是列表,所有行存入一个大列表,返回出去 36 | 读取时,不做清洗,只是忠诚地把文件里的数据转移出来到列表里 37 | :param filename: excel文件名(完整路径) 38 | :param sheetname: 工作表Worksheet名 39 | :return: list 40 | """ 41 | # 加载文件+选表 两步合并 42 | colaSheet = openpyxl.load_workbook(filename=filename)[sheetname] # type: Worksheet 43 | # 读出所有行数据 44 | rowData = [list(rowContent) for rowContent in colaSheet.iter_rows(values_only=True)] 45 | return rowData 46 | 47 | 48 | # 读出表格数据 49 | rowData = read_rows(filename=os.path.join(resourcesPath, resourcesFileName), sheetname=yearSheetName) 50 | # 取出x轴数据(表头,注意第一列空的,要砍掉) 51 | x_data = rowData[0][1:] 52 | # 取出y轴数据(第2行开始) 53 | y_data = dict() 54 | for rowItem in rowData[1:]: 55 | # eval函数剥开字符串两侧引号(防止单元格含字符串),避免字符串数值,适当过滤一下填入数据时候出现的两端空白 56 | y_data[rowItem[0]] = [eval(str(item).strip()) for item in rowItem[1:]] 57 | 58 | 59 | """绘制多y轴折线图 60 | 61 | - 绘制堆叠柱状图,堆叠名称统一为"sales"; 62 | - 图例设置为对应商品的名称; 63 | - 数据标签设置为柱子内居中 ; 64 | - 将整个文档标题设置为"2020年商品销售额变化" 65 | - 将文档保存 66 | """ 67 | stacked_bar = ( 68 | Bar() 69 | .set_global_opts(title_opts=opts.TitleOpts(title="2020年商品销售额变化")) 70 | .add_xaxis(xaxis_data=x_data) 71 | ) 72 | for yaxis_series, yaxis_data in y_data.items(): 73 | stacked_bar.add_yaxis( 74 | series_name=yaxis_series, 75 | y_axis=yaxis_data, 76 | stack="sales", 77 | label_opts=opts.LabelOpts(position="inside") 78 | ) 79 | stacked_bar.render(path=os.path.join(resultPath, resultFileName)) 80 | -------------------------------------------------------------------------------- /06别把数据直接放程序里之使用openpyxl/06-2openpyxl结合可视化演示/example6_3/resources/核桃销量.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/06别把数据直接放程序里之使用openpyxl/06-2openpyxl结合可视化演示/example6_3/resources/核桃销量.xlsx -------------------------------------------------------------------------------- /07转化跟踪之漏斗图/example7_1/example7_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Funnel 3 | import pyecharts.options as opts 4 | 5 | """准备原始数据:某网上商城从用户进入到下订单,中间各个操作过程中平均剩余用户的人数 6 | 7 | 漏斗图不需要x轴和y轴,但需要二维的列表,分别是某一个环节的名字,以及当前这个环节中的相对变化率数值 8 | [[环节名(变化率), 环节直接人数], [环节名(变化率), 环节直接人数], ...] 9 | 10 | * 环节名这里稍微加点东西:环节名里面要体现出各个环节相比上一环节的人数变化率 11 | 12 | 所以显然,下面的原始数据是需要组装的 13 | """ 14 | # 存储标签的列表label 15 | label = ["展现", "点击", "访问", "咨询", "订单"] 16 | # 对应存储数量的列表num(非最终数值) 17 | num = [1000, 880, 264, 52.8, 5.28] 18 | 19 | """显示的最终数值生成 20 | 21 | 1、数据项:各环节占上一个环节的相对人数变化率(百分数值,不要百分号) 22 | 最开始的环节当然是100% 23 | 这里保留一位小数 24 | 2、标签项:假如按照 标签名+变化率 这种方式进行组合 25 | 3、组装数据各项和标签各项成为二维列表 26 | """ 27 | # 计算各个环节人数相对变化率 28 | pass_rate = [100] 29 | # 从第2个元素开始,所以下标始于1 30 | for index in range(1, len(num)): 31 | relative_percentage = (num[index] / num[index - 1]) * 100 32 | # 保留一位小数 33 | relative_percentage = round(relative_percentage, 1) 34 | pass_rate.append(relative_percentage) 35 | 36 | # 标签项的组装,这种写法想象一下数据库的SQL语言,结合类比一下? 37 | label_rate = [f"{label_item}{rate_item}%" 38 | for label_index, label_item in enumerate(label) 39 | for rate_index, rate_item in enumerate(pass_rate) 40 | if label_index == rate_index] 41 | 42 | # 组装二维列表作为显示数据 43 | data_pair = [[label_rate_item, num_item] 44 | for label_rate_index, label_rate_item in enumerate(label_rate) 45 | for num_index, num_item in enumerate(num) 46 | if label_rate_index == num_index] 47 | # print(data_pair) 48 | 49 | """绘制漏斗图 50 | 51 | 每个环节(每个漏斗条)中间距离设置为10 52 | 数据系名称(series_name)设置为“网店商品浏览阶段人数变化示意” 53 | 隐藏图例 54 | 保存图片 55 | """ 56 | # 保存路径 57 | resultPath = "./result" 58 | if not os.path.exists(path=resultPath): 59 | os.mkdir(path=resultPath) 60 | # 保存文件名 61 | resultFileName = "sales_section_funnel.html" 62 | # 执行绘图 63 | funnel = ( 64 | Funnel() 65 | .set_global_opts(legend_opts=opts.LegendOpts(is_show=False)) 66 | .add( 67 | series_name="网店商品浏览阶段人数变化示意", 68 | data_pair=data_pair, 69 | gap=10 70 | ) 71 | .render(path=os.path.join(resultPath, resultFileName)) 72 | ) 73 | -------------------------------------------------------------------------------- /07转化跟踪之漏斗图/example7_1/result/sales_section_funnel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Awesome-pyecharts 6 | 7 | 8 | 9 | 10 |
11 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /07转化跟踪之漏斗图/example7_2/example7_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Funnel 3 | import pyecharts.options as opts 4 | 5 | """准备原始数据:某网上商城从用户进入到下订单,用户行为在各个购买阶段的剩余人数 6 | 7 | 漏斗图不需要x轴和y轴,但需要二维的列表,分别是某一个环节的名字,以及当前这个环节中的相对变化率数值 8 | [[环节名, 相比上一环节人数变化率], [环节名, 相比上一环节人数变化率], [环节名, 相比上一环节人数变化率], ...] 9 | 10 | 所以显然,下面的原始数据是需要组装的 11 | """ 12 | # 存储标签的列表label 13 | user_behavior = ["浏览商品", "加入购物车", "生成订单", "支付订单", "完成交易"] 14 | # 对应存储数量的列表num(非最终数值) 15 | num = [100, 40, 30, 20, 17] 16 | 17 | """显示的最终数值生成 18 | 19 | 1、数据项:各环节占上一个环节的相对人数变化率(百分数值,不要百分号) 20 | 最开始的环节当然是100% 21 | 这里保留一位小数 22 | 2、标签项:假如按照 标签名+变化率 这种方式进行组合 23 | 3、组装数据各项和标签各项成为二维列表 24 | """ 25 | # 计算各个环节人数相对变化率 26 | pass_rate = [100] 27 | # 从第2个元素开始,所以下标始于1 28 | for index in range(1, len(num)): 29 | relative_percentage = (num[index] / num[index - 1]) * 100 30 | # 保留一位小数 31 | relative_percentage = round(relative_percentage, 1) 32 | pass_rate.append(relative_percentage) 33 | 34 | # 标签项的组装,这种写法想象一下数据库的SQL语言,结合类比一下? 35 | label_rate = [f"{label_item}{rate_item}%" 36 | for label_index, label_item in enumerate(user_behavior) 37 | for rate_index, rate_item in enumerate(pass_rate) 38 | if label_index == rate_index] 39 | 40 | # 组装二维列表作为显示数据(第一维是上一个) 41 | data_pair = [[label_rate[label_rate_index], num[num_index]] 42 | for label_rate_index, _ in enumerate(label_rate) 43 | for num_index, _ in enumerate(num) 44 | if label_rate_index == num_index] 45 | print(data_pair) 46 | 47 | """绘制漏斗图 48 | 49 | 图的标题设置为“用户行为转化率” 50 | 每个环节(每个漏斗条)中间距离设置为10 51 | 数据系名称(series_name)这里不设置 52 | 隐藏图例 53 | 保存图片 54 | """ 55 | # 保存路径 56 | resultPath = "./result" 57 | if not os.path.exists(path=resultPath): 58 | os.mkdir(path=resultPath) 59 | # 保存文件名 60 | resultFileName = "user_conversion_rate_funnel.html" 61 | # 执行绘图 62 | funnel = ( 63 | Funnel() 64 | .set_global_opts( 65 | title_opts=opts.TitleOpts(title="用户行为转化率"), 66 | legend_opts=opts.LegendOpts(is_show=False) 67 | ) 68 | .add( 69 | series_name="", 70 | data_pair=data_pair, 71 | gap=10 72 | ) 73 | .render(path=os.path.join(resultPath, resultFileName)) 74 | ) 75 | -------------------------------------------------------------------------------- /07转化跟踪之漏斗图/example7_2/result/user_conversion_rate_funnel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Awesome-pyecharts 6 | 7 | 8 | 9 | 10 |
11 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /07转化跟踪之漏斗图/example7_3/example7_3.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openpyxl 3 | from openpyxl import Workbook 4 | from openpyxl.worksheet.worksheet import Worksheet 5 | from pyecharts.charts import Funnel 6 | import pyecharts.options as opts 7 | 8 | # 资源文件路径 9 | resourcesPath = "./resources" 10 | salesBookName = "销售漏斗.xlsx" 11 | 12 | 13 | def read_rows(wb: Workbook=None, sheetname=None) -> list: 14 | """ 15 | 从excel文档中读出所有行,每一行都是列表,所有行存入一个大列表,返回出去 16 | 读取时,不做清洗,只是忠诚地把文件里的数据转移出来到列表里 17 | :param wb: excel工作簿(已经打开) 18 | :param sheetname: 工作表Worksheet名 19 | :return: list 20 | """ 21 | # 选表 22 | sheet = wb[sheetname] # type: Worksheet 23 | # 读出所有行数据 24 | row_data = [list(rowContent) for rowContent in sheet.iter_rows(values_only=True)] 25 | return row_data 26 | 27 | 28 | # 加载工作簿 29 | salesBook = openpyxl.load_workbook(filename=os.path.join(resourcesPath, salesBookName)) # type: Workbook 30 | # 内有多个sheets,逐个遍历 31 | for teamSheetName in salesBook.sheetnames: 32 | # 选工作表 33 | teamSheet = salesBook[teamSheetName] # type: Worksheet 34 | 35 | # 取出表中数据 36 | rowData = read_rows(wb=salesBook, sheetname=teamSheetName) 37 | # 谈判阶段 38 | stages = rowData[0][1:] 39 | # 每个阶段达成的数量 40 | num = rowData[1][1:] 41 | 42 | # 处理数据,[标签项,数值项]处理成形如["目标客户100%", 1000]格式 43 | # 相对变化率的数值,计算时保留一位小数 44 | # 计算各个环节人数相对变化率 45 | pass_rate = [100] 46 | # 从第2个元素开始,所以下标始于1 47 | for index in range(1, len(num)): 48 | relative_percentage = (num[index] / num[index - 1]) * 100 49 | # 保留一位小数 50 | relative_percentage = round(relative_percentage, 1) 51 | pass_rate.append(relative_percentage) 52 | 53 | # 按照格式组装标签项 54 | label_item = [] 55 | for common_index, rate_item in enumerate(pass_rate): 56 | label_item.append(f"{stages[common_index]}{rate_item}%") 57 | # 组装绘图用的数据对组装 58 | data_pair = [] 59 | for common_index, num_item in enumerate(num): 60 | data_pair.append( 61 | [label_item[common_index], num_item] 62 | ) 63 | 64 | # 绘制漏斗图,要求: 65 | # 1、隐藏图例; 66 | # 2、将标题设置为:f"{小组名称}销售漏斗"格式 67 | # 3、将三个图表分别保存到result目录下,命名格式:"{小组名称}.html" 68 | # 4、漏斗项之间的间距为10 69 | resultPath = "./result" 70 | if not os.path.exists(resultPath): 71 | os.mkdir(path=resultPath) 72 | resultFileName = f"{teamSheetName}_sales_funnel.html" 73 | funnel = ( 74 | Funnel() 75 | .set_global_opts( 76 | title_opts=opts.TitleOpts(title=f"{teamSheetName}销售漏斗"), 77 | legend_opts=opts.LegendOpts(is_show=False) 78 | ) 79 | .add( 80 | series_name="", 81 | data_pair=data_pair, 82 | gap=10 83 | ) 84 | .render(path=os.path.join(resultPath, resultFileName)) 85 | ) 86 | -------------------------------------------------------------------------------- /07转化跟踪之漏斗图/example7_3/resources/销售漏斗.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/07转化跟踪之漏斗图/example7_3/resources/销售漏斗.xlsx -------------------------------------------------------------------------------- /07转化跟踪之漏斗图/example7_3/result/teamA_sales_funnel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Awesome-pyecharts 6 | 7 | 8 | 9 | 10 |
11 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /07转化跟踪之漏斗图/example7_3/result/teamB_sales_funnel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Awesome-pyecharts 6 | 7 | 8 | 9 | 10 |
11 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /07转化跟踪之漏斗图/example7_3/result/teamC_sales_funnel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Awesome-pyecharts 6 | 7 | 8 | 9 | 10 |
11 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /07转化跟踪之漏斗图/example7_4/example7_4.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openpyxl 3 | from openpyxl import Workbook 4 | from openpyxl.worksheet.worksheet import Worksheet 5 | from pyecharts.charts import Funnel, Tab 6 | import pyecharts.options as opts 7 | 8 | # 资源目录 9 | resourcesPath = "./resources" 10 | # 资源文件 11 | salesBookName = "销售.xlsx" 12 | 13 | # 打开excel文件表 14 | salesBook = openpyxl.load_workbook(filename=os.path.join(resourcesPath, salesBookName)) # type: Workbook 15 | 16 | 17 | def read_data_pair(sheet: Worksheet) -> list: 18 | """ 19 | 从一个工作表中,读出生成一个漏斗图所需的必备数据对。 20 | :param sheet:正在处理的工作表 21 | :return:二元列表[标签项,数据项]为[f"{环节}{相对变化率}%", 对应数量]的元素所构成的二维列表。相对变化率保留1位小数 22 | """ 23 | # 忠诚读取各行数据 24 | row_data = [list(rowContent) for rowContent in sheet.iter_rows(values_only=True)] 25 | # 原始数据:环节 26 | stages = row_data[0][1:] 27 | # 原始数据:各阶段达成数量 28 | num = [eval(str(data_item)) for data_item in row_data[1][1:]] 29 | 30 | # 计算各个环节人数相对变化率 31 | pass_rate = [100] 32 | # 从第2个元素开始,所以下标始于1 33 | for index in range(1, len(num)): 34 | relative_percentage = (num[index] / num[index - 1]) * 100 35 | # 保留一位小数 36 | relative_percentage = round(relative_percentage, 1) 37 | pass_rate.append(relative_percentage) 38 | 39 | # 按照格式组装标签项 40 | label_item = [] 41 | for common_index, rate_item in enumerate(pass_rate): 42 | label_item.append(f"{stages[common_index]}{rate_item}%") 43 | # 组装绘图用的数据对组装 44 | data_pair = [] 45 | for common_index, num_item in enumerate(num): 46 | data_pair.append( 47 | [label_item[common_index], num_item] 48 | ) 49 | 50 | return data_pair 51 | 52 | 53 | # 用于添加所有绘制出来的漏斗图 54 | tab = Tab() 55 | 56 | for monthSheetName in salesBook.sheetnames: 57 | # 获取该表下用于绘图的数据对 58 | data_pair = read_data_pair(salesBook[monthSheetName]) 59 | # 绘制漏斗图,要求: 60 | # 1、隐藏图例; 61 | # 2、每张图标题设置为:f"{月份}销售" 62 | # 3、图中每个漏斗项中间的距离为10 63 | # 4、多漏斗图用看板展示; 64 | # 5、保存 65 | funnel = ( 66 | Funnel() 67 | .set_global_opts( 68 | title_opts=opts.TitleOpts(title=f"{monthSheetName}销售"), 69 | legend_opts=opts.LegendOpts(is_show=False) 70 | ) 71 | .add( 72 | series_name="", 73 | data_pair=data_pair, 74 | gap=10 75 | ) 76 | ) 77 | tab.add(chart=funnel, tab_name=f"{monthSheetName}") 78 | 79 | # 保存看板图 80 | resultPath = "./result" 81 | if not os.path.exists(resultPath): 82 | os.mkdir(path=resultPath) 83 | resultFileName = "year_funnel_tab.html" 84 | 85 | tab.render(path=os.path.join(resultPath, resultFileName)) 86 | -------------------------------------------------------------------------------- /07转化跟踪之漏斗图/example7_4/resources/销售.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/07转化跟踪之漏斗图/example7_4/resources/销售.xlsx -------------------------------------------------------------------------------- /07转化跟踪之漏斗图/whatisFunnelChart.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/07转化跟踪之漏斗图/whatisFunnelChart.md -------------------------------------------------------------------------------- /08多维展示之轮播图/example8_1/example8_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openpyxl import Workbook 3 | from openpyxl.worksheet.worksheet import Worksheet 4 | from pyecharts.charts import Bar, Timeline 5 | import pyecharts.options as opts 6 | import openpyxl 7 | 8 | # 工作簿统一所在路径 9 | resourcesPath = "./resources" 10 | # 工作簿名 11 | gdpBookName = "历年前十大经济体.xlsx" 12 | # 工作表名 13 | gdpSheetName = "GDP" 14 | gdpSheet = openpyxl.load_workbook(filename=os.path.join(resourcesPath, gdpBookName))[gdpSheetName] # type: Worksheet 15 | 16 | 17 | def get_data(row_num): 18 | """ 19 | 传入行数,返回用于绘制柱状图所必备的数据信息,将已经打开的工作表作为全局信息 20 | :param row_num:工作表的行数 21 | :return:三元组(年份,国家名列表,对应的GDP数值(单位:亿元)) 22 | """ 23 | 24 | # 忠诚地读出当前行和下一行的原始数据,形如: 25 | # [(1970, '美国', '苏联', '日本', '西德', '法国', '英国', '意大利', '中国', '加拿大', '印度'), 26 | # (None, 1024.9, 433.412, 209.071, 208.869, 146.985, 124.883, 109.258, 91.506, 86.304, 61.332)] 27 | org_data = [data_item for data_item in gdpSheet.iter_rows(min_row=row_num, max_row=row_num+1, values_only=True)] 28 | 29 | # 提取年份 30 | year_ = org_data[0][0] 31 | # 提取国家列表 32 | country_list = org_data[0][1:] 33 | # 提取对应的GDP取值 34 | gdp_list = org_data[1][1:] 35 | 36 | return year_, country_list, gdp_list 37 | 38 | 39 | # 绘制轮播柱状图 40 | timeline = Timeline() 41 | 42 | # 扫描偶数行号,因为每一个偶数行号对应着一组新的数据,原表格一共有21行,暂时未找到合适的方法判断行数,所以直接用绝对数值 43 | for rowNum in range(2, 21, 2): 44 | # 获取当前行绘图所需的(年份,x轴,y轴)所需数据 45 | year, x_data, y_data = get_data(row_num=rowNum) 46 | 47 | # 绘制单个柱状图 48 | # 1. 图例隐藏 49 | # 2. 图表的标题设置为:"xxxx年前十大经济体GDP排名"; 50 | # 3. 逐个添加柱状图到轮播图,轮播图的每个时间节点设置:xxxx年; 51 | # 4. 将图表保存 52 | timeline.add( 53 | time_point=f"{year}年", 54 | chart=( 55 | Bar() 56 | .set_global_opts( 57 | title_opts=opts.TitleOpts(title=f"{year}年前十大经济体GDP排名"), 58 | legend_opts=opts.LegendOpts(is_show=False) 59 | ) 60 | .add_xaxis(xaxis_data=x_data) 61 | .add_yaxis( 62 | series_name="", 63 | y_axis=y_data 64 | ) 65 | ) 66 | ) 67 | 68 | # 保存轮播图路径 69 | resultPath = "./result" 70 | if not os.path.exists(resultPath): 71 | os.mkdir(path=resultPath) 72 | # 文件名 73 | resultFileName = "GDP_bar_timeline.html" 74 | # 执行保存 75 | timeline.render(path=os.path.join(resultPath, resultFileName)) 76 | -------------------------------------------------------------------------------- /08多维展示之轮播图/example8_1/resources/历年前十大经济体.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/08多维展示之轮播图/example8_1/resources/历年前十大经济体.xlsx -------------------------------------------------------------------------------- /08多维展示之轮播图/example8_2/example8_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | from openpyxl import Workbook 3 | from openpyxl.worksheet.worksheet import Worksheet 4 | from pyecharts.charts import Bar, Timeline 5 | import pyecharts.options as opts 6 | import openpyxl 7 | 8 | # 资源路径 9 | resourcesPath = "./resources" 10 | # 月产品线销量报表工作簿 11 | monthSalesBookName = "timeline.xlsx" 12 | # 打开工作簿 13 | monthSalesBook = openpyxl.load_workbook(filename=os.path.join(resourcesPath, monthSalesBookName)) # type: Workbook 14 | 15 | 16 | def read_sheet(sheet_name: str): 17 | """ 18 | 传入工作表,返回当前工作表中需要用于绘图的数据。 19 | 20 | 前置条件:所需的工作簿已打开. 21 | 22 | :param sheet_name: 当前工作表的名称 23 | 24 | :return: 元组(表头-x轴, (商家名1, x轴对应的y轴数据组1), (商家名2, x轴对应的y轴数据组2), ...) 25 | 26 | """ 27 | 28 | # 选中工作表 29 | month_sales_sheet = monthSalesBook[sheet_name] # type: Worksheet 30 | # 取出所有原始数据,先不做处理,形如: 31 | # [(None, '草莓', '芒果', '葡萄', '雪梨', '西瓜', '柠檬', '车厘子'), 32 | # ('商家A', 130, 136, 112, 61, 149, 99, 62), 33 | # ('商家B', 82, 112, 41, 50, 40, 91, 117)] 34 | org_data = [org for org in month_sales_sheet.iter_rows(values_only=True)] 35 | 36 | # 提取产品信息列表 37 | product_list = org_data[0][1:] 38 | # 提取商家及其销量信息 39 | sales_info = org_data[1:] 40 | 41 | # 组装 42 | plot_data = [product_list] 43 | for info in sales_info: 44 | plot_data.append(info) 45 | 46 | return tuple(plot_data) 47 | 48 | 49 | # 绘制轮播图,节点名设置为月份(工作表的名字) 50 | # 柱状图每个数据系名设置为商户的名字:商家X; 51 | # 每个月份图表的标题设置为"月份"+"销量":X月销量; 52 | # 将图表保存 53 | timeline = Timeline() 54 | # 扫描所有工作表,逐个绘制柱状图加进轮播图里面 55 | for sheetName in monthSalesBook.sheetnames: 56 | # 取出用于绘图的一组数据:(表头-x轴, (商家名1, x轴对应的y轴数据组1), (商家名2, x轴对应的y轴数据组2), ...) 57 | packedData = read_sheet(sheetName) 58 | 59 | # 提取x轴数据 60 | x_data = packedData[0] 61 | 62 | # 提取多组y轴数据字典 63 | y_data_dict = dict() 64 | for y_data_item in packedData[1:]: 65 | # 键值对——'商家名': [对应x轴的系列取值] 66 | y_data_dict[y_data_item[0]] = y_data_item[1:] 67 | 68 | # 绘柱状图 69 | bar = ( 70 | Bar() 71 | .set_global_opts(title_opts=opts.TitleOpts(title=f"{sheetName}销量")) 72 | .add_xaxis(xaxis_data=x_data) 73 | ) 74 | for k_vendor, v_y_data in y_data_dict.items(): 75 | bar.add_yaxis( 76 | series_name=k_vendor, 77 | y_axis=v_y_data 78 | ) 79 | # 加进轮播图 80 | timeline.add(chart=bar, time_point=sheetName) 81 | 82 | # 保存轮播图路径 83 | resultPath = "./result" 84 | if not os.path.exists(path=resultPath): 85 | os.mkdir(path=resultPath) 86 | # 文件名 87 | resultFileName = "monthly_sales_timeline.html" 88 | # 执行保存 89 | timeline.render(path=os.path.join(resultPath, resultFileName)) 90 | -------------------------------------------------------------------------------- /08多维展示之轮播图/example8_2/resources/timeline.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/08多维展示之轮播图/example8_2/resources/timeline.xlsx -------------------------------------------------------------------------------- /08多维展示之轮播图/example8_3/example8_3.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openpyxl 3 | from openpyxl import Workbook 4 | from openpyxl.worksheet.worksheet import Worksheet 5 | from pyecharts.charts import Pie, Timeline 6 | import pyecharts.options as opts 7 | 8 | # 资源文件夹 9 | resourcesPath = "./resources" 10 | # 每月销售额工作簿 11 | monthlySalesBookName = "每月销售额.xlsx" 12 | # 工作表名 13 | monthlySalesSheetName = "各商品每月销售额" 14 | # 打开工作表 15 | monthlySalesSheet = openpyxl.load_workbook( 16 | filename=os.path.join(resourcesPath, monthlySalesBookName))[monthlySalesSheetName] 17 | 18 | 19 | def read_excel(sheet: Worksheet) -> list: 20 | """ 21 | 忠诚地读取出工作表中的原始内容,不做任何处理。 22 | 23 | :param sheet: 正在读取的工作表 24 | 25 | :return: 由各行数据组成的列表,每行也是一个列表 26 | """ 27 | org_data = [list(data_item) for data_item in sheet.iter_rows(values_only=True)] 28 | return org_data 29 | 30 | 31 | def get_data(org_data: list, row: int) -> tuple: 32 | """ 33 | 利用read_excel读取出的数据,取出绘制一个饼图所需的数据。 34 | 35 | 屏蔽空数据或者0数据。 36 | 37 | :param row: 指定读取的excel表格中第几行的数据(从2开始,跳过第1行表头) 38 | :param org_data: excel表格里,由各行数据组成的列表,每行也是一个列表 39 | 40 | :return: 二元组:(月份,[(标签1, 数据1), (标签2, 数据2), ...]) 41 | """ 42 | # 取出用来做标签的数据 43 | labels = org_data[0][1:] 44 | 45 | # 取出相应行的数据 46 | row_data = [row_item for row_item in org_data[row]] 47 | # 月份和数据 48 | month_, data = row_data[0], row_data[1:] 49 | 50 | # 从标签、数据中组合出绘制饼状图所需的数据对 51 | sales_list = [] 52 | for index in range(len(labels)): 53 | if data[index] == 0: 54 | continue 55 | data_pair_item = (labels[index], data[index]) 56 | sales_list.append(data_pair_item) 57 | 58 | # 返回(月份, 绘图用的数据对列表) 59 | return month_, sales_list 60 | 61 | 62 | # 取出excel表格中的内容 63 | orgData = read_excel(monthlySalesSheet) 64 | 65 | # 根据12个月的数据,分别绘制出所需的图形 66 | # 1. 每组数据以环状南丁格尔玫瑰图展示 67 | # 2. 将玫瑰图的数据系名设置为空; 68 | # 3. 环内径为"20%", 最大外径为"60%"; 69 | # 4. 数据项标签的格式为"{百分比}%" 70 | # 5. 标签内置于每块饼中; 71 | # 6. 玫瑰图类型设置为圆心角相同,仅通过半径展示数据项大小差别 72 | # 7. 将每个月份图表的标题设置为"月份"+"销售额组成":x月销售额组成; 73 | # 8. 轮播图各轮播节点设置为月份:x月; 74 | # 9. 将轮播玫瑰图保存 75 | timeline = Timeline() 76 | for rowNum in range(1, len(orgData)): 77 | # 得到当前行用于绘图的数据 78 | month, dataPair = get_data(org_data=orgData, row=rowNum) 79 | timeline.add( 80 | time_point=month, 81 | chart=( 82 | Pie() 83 | .set_global_opts(title_opts=opts.TitleOpts(title=f"{month}销售额组成")) 84 | .add( 85 | series_name="", 86 | data_pair=dataPair, 87 | radius=["20%", "60%"], 88 | rosetype="radius", 89 | label_opts=opts.LabelOpts( 90 | position="inside", 91 | formatter="{d}%" 92 | ) 93 | ) 94 | ) 95 | ) 96 | 97 | # 保存路径 98 | resultPath = "./result" 99 | if not os.path.exists(path=resultPath): 100 | os.mkdir(path=resultPath) 101 | # 文件名 102 | resultFileName = "sales_rose_pie_timeline.html" 103 | # 执行保存 104 | timeline.render(path=os.path.join(resultPath, resultFileName)) 105 | -------------------------------------------------------------------------------- /08多维展示之轮播图/example8_3/resources/每月销售额.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/08多维展示之轮播图/example8_3/resources/每月销售额.xlsx -------------------------------------------------------------------------------- /08多维展示之轮播图/whatisTimeline.md: -------------------------------------------------------------------------------- 1 | # 轮播图(Timeline) 2 | 3 | 轮播图可以给原来的图表增加一个维度,可以沿着时间线或者某种逻辑滚动播放,展现出时间或逻辑的变化,展现更多信息。 4 | 5 | 轮播图其实不难画: 6 | 7 | * 按照之前的板块介绍,绘制出任何需要的图表 8 | 9 | * 创建一个Timeline,把之前画的图表按照需要逐个添加到Timeline里面去,就生成了 10 | -------------------------------------------------------------------------------- /09位置之地图/example9_1/example9_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Map 3 | import pyecharts.options as opts 4 | 5 | # 准备原始数据(从文件中读取数据的过程省略):各国排名世界top500财富榜的企业个数 6 | # 在地图上做可视化的绘图数据格式:[("地点1", 对应数值1), ("地点2", 对应数值2), ...] 7 | # 国家和对应的数据,组成了列表dataList 8 | dataList = [('China', 124), ('United States', 121), ('Japan', 53), ('France', 31), ('Germany', 27), 9 | ('United Kingdom', 22), ('Korea', 14), ('Switzerland', 14), ('Canada', 13), ('Netherlands', 13)] 10 | 11 | 12 | # 地图绘制需求 13 | # 1. 数据系列名为空 14 | # 2. 参数图片类型设置为世界地图(参数怎么指定,需要查阅文档) 15 | # 3. 数据标签隐藏 16 | # 4. 视觉映射配置项,将最大映射值设为130 17 | # 5. 设置标题为"排名前10的国家" 18 | # 6. 保存 19 | # 存储路径 20 | resultPath = "./result" 21 | if not os.path.exists(path=resultPath): 22 | os.mkdir(path=resultPath) 23 | # 存储文件名 24 | resultFileName = "top10property_world_map.html" 25 | # 执行绘图 26 | mapChart = ( 27 | Map() 28 | .set_global_opts( 29 | title_opts=opts.TitleOpts("排名前10的国家"), 30 | visualmap_opts=opts.VisualMapOpts(max_=130) 31 | ) 32 | .add( 33 | series_name="", 34 | data_pair=dataList, 35 | label_opts=opts.LabelOpts(is_show=False), 36 | maptype="world" 37 | ) 38 | .render(path=os.path.join(resultPath, resultFileName)) 39 | ) 40 | -------------------------------------------------------------------------------- /09位置之地图/example9_1/result/top10property_world_map.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Awesome-pyecharts 6 | 7 | 8 | 9 | 10 | 11 |
12 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /09位置之地图/example9_2/example9_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openpyxl 3 | from openpyxl import Workbook 4 | from openpyxl.worksheet.worksheet import Worksheet 5 | from pyecharts.charts import Map 6 | import pyecharts.options as opts 7 | 8 | # 资源文件统一所在目录 9 | resourcesPath = "./resources" 10 | # 降雨量数据工作簿名 11 | rainFallBookName = "全国降雨量.xlsx" 12 | # 2017年数据工作表名 13 | rainFallSheetName = "2017年降水量" 14 | # 打开文件选表 15 | rainFallSheet = openpyxl.load_workbook( 16 | filename=os.path.join(resourcesPath, rainFallBookName) 17 | )[rainFallSheetName] # type: Worksheet 18 | 19 | # 获取原始数据:2017年全国各省降水量(毫米),跳过表头 20 | orgData = [row_item for row_item in rainFallSheet.iter_rows(min_row=2, values_only=True)] 21 | 22 | # 清洗数据,去掉空数据。组装绘图用的数据对 23 | dataPair = [data_item for data_item in orgData 24 | if None not in data_item] 25 | 26 | # 绘制地图需求 27 | # 1. 标记(symbol)隐藏、标签隐藏 28 | # 2. 添加视觉映射,最大值映射值设为230 29 | # 3. 组件过渡颜色设置为["#E0ECF8", "#045FB4"],冷色系的那种,让人感觉是下雨的感觉 30 | # 4. 标题设为"2017年全国降雨量" 31 | # 5. 保存 32 | # 保存路径 33 | resultPath = "./result" 34 | if not os.path.exists(path=resultPath): 35 | os.mkdir(path=resultPath) 36 | # 保存文件名 37 | resultFileName = "rainfall_china_map.html" 38 | # 执行绘图 39 | mapChart = ( 40 | Map() 41 | .set_global_opts( 42 | title_opts=opts.TitleOpts(title="2017年全国降雨量", subtitle="单位:mm"), 43 | visualmap_opts=opts.VisualMapOpts( 44 | max_=230, 45 | range_color=["#E0ECF8", "#045FB4"] 46 | ), 47 | legend_opts=opts.LegendOpts(is_show=False) 48 | ) 49 | .add( 50 | series_name="降水量(单位:mm)", 51 | data_pair=dataPair, 52 | label_opts=opts.LabelOpts(is_show=False), 53 | is_map_symbol_show=False 54 | ) 55 | .render(path=os.path.join(resultPath, resultFileName)) 56 | ) 57 | -------------------------------------------------------------------------------- /09位置之地图/example9_2/resources/全国降雨量.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/09位置之地图/example9_2/resources/全国降雨量.xlsx -------------------------------------------------------------------------------- /09位置之地图/example9_3/example9_3.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openpyxl 3 | from openpyxl import Workbook 4 | from openpyxl.worksheet.worksheet import Worksheet 5 | from pyecharts.charts import Map, Timeline 6 | import pyecharts.options as opts 7 | 8 | # 资源文件统一所在目录 9 | resourcesPath = "./resources" 10 | # 降雨量数据工作簿名 11 | gpdBookName = "2010-2017年各省份历年GDP.xlsx" 12 | # 打开文件 13 | gpdBook = openpyxl.load_workbook(filename=os.path.join(resourcesPath, gpdBookName)) # type: Workbook 14 | 15 | 16 | def get_data(year: str) -> tuple: 17 | """ 18 | 指定工作表名year,返回绘图所需的数据 19 | 20 | :param year: 年份,是字符串 21 | 22 | :return: 绘图所需数据,格式(年份——数值类型的年份, [(省份1, GDP取值1), (省份2, GDP取值2), ...]) 23 | """ 24 | # 选中工作表 25 | year_sheet = gpdBook[year] # type: Worksheet 26 | 27 | # 取出全国当前的各省GDP数据 28 | gdp_list = [row_item for row_item in year_sheet.iter_rows(min_row=2, values_only=True)] 29 | # 清洗数据,去掉含空项 30 | gdp_list = [item for item in gdp_list if None not in item] 31 | 32 | return ( 33 | eval(str(year)), 34 | gdp_list 35 | ) 36 | 37 | 38 | # 扫描各个工作表,绘制轮播图 39 | timeline = Timeline() 40 | for yearSheetName in gpdBook.sheetnames: 41 | # 取出绘图所需的数据 42 | year, dataPair = get_data(year=yearSheetName) 43 | 44 | # 绘制单组地图需求: 45 | # 1. 地图类型设置为中国地图; 46 | # 2. 视觉映射配置项最大映射值设置为3000; 47 | # 3. 标题设置为f"{data[0]}年各省GDP(单位:10亿人民币)"; 48 | # 4. 轮播图时间节点设置为“xxxx年” 49 | # 5. 隐藏图例 50 | timeline.add( 51 | time_point=f"{year}年", 52 | chart=( 53 | Map() 54 | .set_global_opts( 55 | title_opts=opts.TitleOpts(title=f"{year}年各省GDP(单位:10亿人民币)"), 56 | visualmap_opts=opts.VisualMapOpts(max_=3000) 57 | ) 58 | .add( 59 | series_name=f"{year}年", 60 | maptype="china", 61 | data_pair=dataPair 62 | ) 63 | ) 64 | ) 65 | 66 | # 保存路径 67 | resultPath = "./result" 68 | if not os.path.exists(path=resultPath): 69 | os.mkdir(path=resultPath) 70 | # 保存文件名 71 | resultFileName = "gdp_map_timeline.html" 72 | # 执行保存 73 | timeline.render(path=os.path.join(resultPath, resultFileName)) 74 | -------------------------------------------------------------------------------- /09位置之地图/example9_3/resources/2010-2017年各省份历年GDP.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/09位置之地图/example9_3/resources/2010-2017年各省份历年GDP.xlsx -------------------------------------------------------------------------------- /10局部密度之热力图/example10_1/example10_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openpyxl 3 | from openpyxl import Workbook 4 | from openpyxl.worksheet.worksheet import Worksheet 5 | from pyecharts.charts import HeatMap 6 | import pyecharts.options as opts 7 | 8 | # 资源文件所在目录 9 | resourcesPath = "./resources" 10 | # 便利店文件名 11 | storeBookName = "便利店.xlsx" 12 | # 一周订单量工作表名 13 | orderSheetName = "一周订单量" 14 | # 打开工作表 15 | orderSheet = openpyxl.load_workbook( 16 | filename=os.path.join(resourcesPath, storeBookName) 17 | )[orderSheetName] # type: Worksheet 18 | # 取出各行的所有原始数据 19 | org_data = [list(row_item) for row_item in orderSheet.iter_rows(values_only=True)] 20 | # print(org_data) 21 | 22 | 23 | # 提取数据 24 | # 作为x轴坐标的几点钟数据 25 | timeList = [time_order_num[0] for time_order_num in org_data[1:]] 26 | # 作为y轴坐标的星期几数据 27 | weekList = org_data[0][1:] 28 | # 提取热力图中的色块取值信息 29 | heatMapList = [] 30 | for row_index, row_item in enumerate(org_data[1:]): 31 | for col_index, sales_value in enumerate(row_item[1:]): 32 | heatMapList.append( 33 | [row_index, col_index, sales_value] 34 | ) 35 | # print(heatMapList) 36 | 37 | 38 | # 绘制所需的热力图要求 39 | # 40 | # 1. x轴是几点钟的时间; 41 | # 2. 图例隐藏 42 | # 3. y轴是星期几的时间 43 | # 4. 色块每一个地方的坐标及取值用上; 44 | # 5. 视觉映射配置项,将最大值映射值设置为70; 45 | # 6. x轴标签90度旋转防止遮挡; 46 | # 7. 标题设置为:一周订单量; 47 | # 8. 执行保存 48 | # 保存路径 49 | resultPath = "./result" 50 | if not os.path.exists(path=resultPath): 51 | os.mkdir(path=resultPath) 52 | # 存储文件名称 53 | resultFileName = "week_order_heatmap.html" 54 | 55 | heatMap = ( 56 | HeatMap() 57 | .set_global_opts( 58 | title_opts=opts.TitleOpts(title="一周订单量"), 59 | visualmap_opts=opts.VisualMapOpts(max_=70), 60 | xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=90)) 61 | ) 62 | .add_xaxis(xaxis_data=timeList) 63 | .add_yaxis( 64 | yaxis_data=weekList, 65 | value=heatMapList, 66 | series_name="一周订单量" 67 | ) 68 | .render(path=os.path.join(resultPath, resultFileName)) 69 | ) 70 | 71 | 72 | -------------------------------------------------------------------------------- /10局部密度之热力图/example10_1/resources/便利店.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/10局部密度之热力图/example10_1/resources/便利店.xlsx -------------------------------------------------------------------------------- /10局部密度之热力图/example10_2/example10_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openpyxl 3 | from openpyxl import Workbook 4 | from openpyxl.worksheet.worksheet import Worksheet 5 | from pyecharts.charts import HeatMap 6 | import pyecharts.options as opts 7 | 8 | # 资源文件路径 9 | resourcesPath = "./resources" 10 | 11 | # 票价表文件名 12 | ticketBookName = "票价表.xlsx" 13 | # 一号线工作表 14 | lineOneSheetName = "一号线" 15 | 16 | # 读文件,选表 17 | lineOneSheet = openpyxl.load_workbook( 18 | filename=os.path.join(resourcesPath, ticketBookName) 19 | )[lineOneSheetName] # type: Worksheet 20 | 21 | # 取出表中所有数据 22 | org_data = [row_item for row_item in lineOneSheet.iter_rows(min_row=1, values_only=True)] 23 | print(org_data) 24 | 25 | # x轴上的标签和y轴的标签都是站台名称 26 | # 提取x轴和y轴的标签 27 | xData = org_data[0][1:] 28 | yData = [row_item[0] for row_item in org_data[1:]] 29 | # 扫描行列,组合出热力图取值二维列表(非常注意一点:表的列是数据的x轴,表的行是数据的y轴) 30 | value_list = [] 31 | for x_index, sheetRow in enumerate(org_data[1:]): 32 | for y_index, value_ in enumerate(sheetRow[1:]): 33 | value_list.append( 34 | [x_index, y_index, value_] 35 | ) 36 | print(value_list) 37 | 38 | # 绘制热力图需求: 39 | # 1. 画布的宽为"1000px",高为"800px"; 40 | # 2. 隐藏图例; 41 | # 3. 数据标签显示在内部居中; 42 | # 4. 视觉配置项,最大值映射值设置为10; 43 | # 5. x轴上的标签旋转90度防止遮挡; 44 | # 6. 标题设置为"一号线票价表"; 45 | # 7. 保存 46 | # 保存路径 47 | resultPath = "./result" 48 | if not os.path.exists(path=resultPath): 49 | os.mkdir(path=resultPath) 50 | # 保存文件名 51 | resultFileName = "ticket_price_heatmap.html" 52 | # 执行绘图 53 | heatMap = ( 54 | HeatMap( 55 | init_opts=opts.InitOpts(width="1000px", height="800px") 56 | ) 57 | .set_global_opts( 58 | title_opts=opts.TitleOpts(title="一号线票价表", subtitle="单位(元)"), 59 | legend_opts=opts.LegendOpts(is_show=False), 60 | visualmap_opts=opts.VisualMapOpts(max_=10), 61 | xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=90)) 62 | ) 63 | .add_xaxis(xaxis_data=xData) 64 | .add_yaxis( 65 | series_name="", 66 | yaxis_data=yData, 67 | value=value_list, 68 | label_opts=opts.LabelOpts(position="inside") 69 | ) 70 | .render(path=os.path.join(resultPath, resultFileName)) 71 | ) 72 | -------------------------------------------------------------------------------- /10局部密度之热力图/example10_2/resources/票价表.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/10局部密度之热力图/example10_2/resources/票价表.xlsx -------------------------------------------------------------------------------- /11单页多图之页面组合图/example11_1/example11_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts import options as opts 3 | from pyecharts.charts import Bar, Page 4 | 5 | 6 | def mi() -> Bar: 7 | """ 8 | 绘制小米手机的点赞、转发、评论数据的柱状图,绘图需求: 9 | 10 | 1.设置图表主题为macarons 11 | 12 | 2.设置x轴,为点赞数、转发数、评论数; 13 | 14 | 3.设置y轴,传入数据,这里为了方便演示页面组合图,openpyxl读取数据环节先跳过, 15 | 所需数据已直接给出: 16 | 17 | * 数据系列为mi10_young的三项数据为[405020, 159455, 160529] 18 | 19 | * 数据系列为mi10_pro的三项数据为[131234, 11431, 36922] 20 | 21 | * 数据系列为redmi_k30_pro的三项数据为[110892, 7518, 29415] 22 | 23 | 4.标题为“2020小米新品手机微博数据”,副标题为“各型号获赞、评论、转发数”; 24 | 25 | 5.图例右端位置在相对画布作图区右25%处位置。 26 | 27 | 6.y轴取值的最大值要和另一张图统一(取值500000), 28 | 确保和另一张柱状图直观比对时不出现可视化陷阱错误 29 | 30 | :return: 绘制完成的小米数据柱状图 31 | """ 32 | return ( 33 | Bar(init_opts=opts.InitOpts(theme="macarons")) 34 | .set_global_opts( 35 | title_opts=opts.TitleOpts(title="2020小米新品手机微博数据", subtitle="各型号获赞、评论、转发数"), 36 | legend_opts=opts.LegendOpts(pos_right="25%"), 37 | yaxis_opts=opts.AxisOpts(max_=500000) 38 | ) 39 | .add_xaxis(xaxis_data=["点赞数", "转发数", "评论数"]) 40 | .add_yaxis(series_name="mi10_young", y_axis=[405020, 159455, 160529]) 41 | .add_yaxis(series_name="mi10_pro", y_axis=[131234, 11431, 36922]) 42 | .add_yaxis(series_name="redmi_k30_pro", y_axis=[110892, 7518, 29415]) 43 | ) 44 | 45 | 46 | def huawei() -> Bar: 47 | """ 48 | 绘制华为手机的点赞、转发、评论数据的柱状图,绘图需求: 49 | 50 | 1.设置图表主题为macarons 51 | 52 | 2.设置x轴,为点赞数、转发数、评论数; 53 | 54 | 3.设置y轴,传入数据,这里为了方便演示页面组合图,openpyxl读取数据环节先跳过, 55 | 所需数据已直接给出: 56 | 57 | * 数据系列为honor_x10的三项数据为[315750, 123680, 143533] 58 | 59 | * 数据系列为honor_30s的三项数据为[101736, 9841, 28089] 60 | 61 | * 数据系列为huawei_nova7的三项数据为[156793, 12412, 35721] 62 | 63 | 4.标题为“同价位华为为手机微博数据”,副标题为“各型号获赞、评论、转发数”; 64 | 65 | 5.图例右端位置在相对画布作图区右25%处位置。 66 | 67 | 6.y轴取值的最大值要和另一张图统一(取值500000), 68 | 确保和另一张柱状图直观比对时不出现可视化陷阱错误 69 | 70 | :return: 绘制完成的华为数据柱状图 71 | """ 72 | return ( 73 | Bar(init_opts=opts.InitOpts(theme="macarons")) 74 | .set_global_opts( 75 | title_opts=opts.TitleOpts(title="同价位华为为手机微博数据", subtitle="各型号获赞、评论、转发数"), 76 | legend_opts=opts.LegendOpts(pos_right="25%"), 77 | yaxis_opts=opts.AxisOpts(max_=500000) 78 | ) 79 | .add_xaxis(xaxis_data=["点赞数", "转发数", "评论数"]) 80 | .add_yaxis(series_name="honor_x10", y_axis=[315750, 123680, 143533]) 81 | .add_yaxis(series_name="honor_30s", y_axis=[101736, 9841, 28089]) 82 | .add_yaxis(series_name="huawei_nova7", y_axis=[156793, 12412, 35721]) 83 | ) 84 | 85 | 86 | # 绘制页面组合图需求:布局形式为简单布局,就这一个,没了,此外就记得保存 87 | # 保存路径 88 | resultPath = "./result" 89 | if not os.path.exists(path=resultPath): 90 | os.mkdir(path=resultPath) 91 | # 保存文件名 92 | resultFilePath = "weiboPhoneCompete_bar_page.html" 93 | page = ( 94 | Page(layout=Page.SimplePageLayout) 95 | .add( 96 | mi(), 97 | huawei() 98 | ) 99 | .render(path=os.path.join(resultPath, resultFilePath)) 100 | ) 101 | -------------------------------------------------------------------------------- /11单页多图之页面组合图/example11_2/example11_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Pie, Funnel, Page 3 | from pyecharts import options as opts 4 | 5 | 6 | def rose(): 7 | """ 8 | 通过玫瑰图展示每个季度的销量占比,绘图需求: 9 | 10 | 1.主题为dark,标题为“销售占比” 11 | 12 | 2.隐藏图例 13 | 14 | 3.玫瑰图圆心角半径相同,仅通过半径区分数据大小 15 | 16 | 4.绘图所用数据对已给出,这里省略从文件读入数据的过程: 17 | [("数据线", 3884), ("手机膜", 7298), ("手机壳", 5763),("指环支架", 1326),("充电宝", 1889)] 18 | 19 | :return: 绘制好的玫瑰图 20 | """ 21 | return ( 22 | Pie(init_opts=opts.InitOpts(theme="dark")) 23 | .set_global_opts( 24 | title_opts=opts.TitleOpts("销售占比"), 25 | legend_opts=opts.LegendOpts(is_show=False) 26 | ) 27 | .add( 28 | series_name="", 29 | data_pair=[("数据线", 3884), ("手机膜", 7298), ("手机壳", 5763),("指环支架", 1326),("充电宝", 1889)], 30 | rosetype="area" 31 | ) 32 | ) 33 | 34 | 35 | def lou(): 36 | """ 37 | 通过漏斗图展示店铺订单的转化效率,绘制需求: 38 | 39 | 1.主题为dark 40 | 41 | 2.标题为“订单转化效率”,隐藏图例 42 | 43 | 3.绘图所用数据对已给出,这里省略从文件读入数据的过程: 44 | [("访问", 100), ("搜索", 78.12), ("点击", 35.74), ("加购", 17.17), ("订单", 2.62)] 45 | 46 | :return: 绘制好的漏斗图 47 | """ 48 | # 使用Funnel()函数创建实例赋值给funnel 49 | # 使用InitOpts(),传入参数theme="dark",赋值给init_opts 50 | return ( 51 | Funnel(init_opts=opts.InitOpts(theme="dark")) 52 | .set_global_opts( 53 | legend_opts=opts.LegendOpts(is_show=False), 54 | title_opts=opts.TitleOpts(title="订单转化效率") 55 | ) 56 | .add( 57 | series_name="", 58 | data_pair=[("访问", 100), ("搜索", 78.12), ("点击", 35.74), ("加购", 17.17), ("订单", 2.62)], 59 | ) 60 | ) 61 | 62 | 63 | # 绘制页面组合图,绘制需求:简单布局 64 | # 保存路径 65 | resultPath = "./result" 66 | if not os.path.exists(path=resultPath): 67 | os.mkdir(path=resultPath) 68 | # 保存文件名 69 | resultFileName = "sales_rose_funnel_page.html" 70 | page = ( 71 | Page(layout=Page.SimplePageLayout) 72 | .add( 73 | rose(), 74 | lou() 75 | ) 76 | .render(path=os.path.join(resultPath, resultFileName)) 77 | ) 78 | -------------------------------------------------------------------------------- /11单页多图之页面组合图/example11_3/resources/hiking1.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/11单页多图之页面组合图/example11_3/resources/hiking1.xlsx -------------------------------------------------------------------------------- /12数据分布之箱线图/example12_1/example12_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Boxplot, Grid 3 | import pyecharts.options as opts 4 | 5 | # 准备原始数据(为方便直观表达绘制过程,这里读表的过程先跳过) 6 | # x轴数据 7 | xData = ["15℃", "20℃", "25℃", "30℃", "35℃"] 8 | # 用于绘制y轴的原始数据(假设一组yi对应一个x_data下的实验组测得的一组数据) 9 | y1 = [383, 312, 348, 388, 375, 389, 432, 373, 377, 384] 10 | y2 = [412, 432, 421, 354, 378, 392, 407, 413, 415, 405] 11 | y3 = [400, 388, 397, 352, 423, 447, 378, 377, 395, 387] 12 | y4 = [278, 288, 254, 213, 256, 278, 267, 256, 278, 266] 13 | y5 = [213, 215, 234, 232, 278, 188, 223, 234, 225, 231] 14 | 15 | # 绘制箱线图 16 | boxplot = Boxplot() 17 | # 生成绘箱线图图用的y轴数据(即每一组yi)的[下限值,下四分位点,中位数,上四分位点,上限值] 18 | yData = boxplot.prepare_data([y1, y2, y3, y4, y5]) 19 | # print(y_data) 20 | # 得到绘制5组温度下对应箱线图的[下限值,下四分位点,中位数,上四分位点,上限值]数据 21 | # [[312, 366.75, 380.0, 388.25, 432], [354, 388.5, 409.5, 416.5, 432], [352, 377.75, 391.5, 405.75, 447], 22 | # [213, 255.5, 266.5, 278.0, 288], [188, 214.5, 228.0, 234.0, 278]] 23 | 24 | # 执行绘图 25 | # 添加x轴数据 26 | boxplot.add_xaxis(xaxis_data=xData) 27 | # 添加y轴数据 28 | boxplot.add_yaxis(series_name="实验组数据", y_axis=yData) 29 | 30 | # 保存路径 31 | resultPath = "./result" 32 | if not os.path.exists(path=resultPath): 33 | os.mkdir(path=resultPath) 34 | # 保存文件名 35 | resultFilePath = "experiment_gp_boxplot.html" 36 | # 设置标题和副标题 37 | boxplot.set_global_opts( 38 | title_opts=opts.TitleOpts(title="探究温度对化肥有效成分含量的影响", subtitle="每种温度下共采集10组数据"), 39 | xaxis_opts=opts.AxisOpts(name="温度"), 40 | yaxis_opts=opts.AxisOpts(name="有效含量值(单位: g/500g)") 41 | ) 42 | 43 | # 调整图形位置,解决副标题和y轴重叠问题 44 | grid = ( 45 | Grid(init_opts=opts.InitOpts(height="600px")) 46 | .add( 47 | chart=boxplot, 48 | grid_opts=opts.GridOpts(pos_top="20%") 49 | ) 50 | ) 51 | 52 | # 执行保存 53 | grid.render(path=os.path.join(resultPath, resultFilePath)) 54 | -------------------------------------------------------------------------------- /12数据分布之箱线图/example12_2/example12_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Boxplot 3 | import pyecharts.options as opts 4 | 5 | # 准备原始数据 6 | # x轴:各学科名称 7 | xData = ["物理", "化学", "生物", "历史", "政治", "地理"] 8 | # 以及xi轴对应yi,yi是该科目多次调考的考试成绩 9 | y1 = [83, 88, 93, 79, 86, 89, 95, 90, 94, 92] 10 | y2 = [77, 79, 74, 82, 73, 78, 75, 85, 83, 81] 11 | y3 = [94, 93, 97, 89, 92, 97, 91, 85, 82, 96] 12 | y4 = [82, 81, 79, 85, 88, 73, 78, 82, 75, 79] 13 | y5 = [71, 78, 74, 73, 79, 77, 75, 74, 75, 81] 14 | y6 = [62, 65, 72, 66, 78, 73, 66, 68, 61, 63] 15 | 16 | # 绘制箱线图 17 | # 注意用yi生成各科的[min, Q2, mid, Q1, max]数据,用于后续绘制箱线图 18 | # 绘图的其它需求 19 | # 1. 主题为马卡龙画风(macarons) 20 | # 2. 让箱线图的须更长,数据分布更易于观察:把y轴的最小值设为数据的最小值,而不是从0开始 21 | # (这一步怎么设置的,建议查一下文档,写得明明白白) 22 | # 3. 全图标题“各科成绩” 23 | boxplot = ( 24 | Boxplot(init_opts=opts.InitOpts(theme="macarons")) 25 | .set_global_opts( 26 | title_opts=opts.TitleOpts(title="各科成绩"), 27 | yaxis_opts=opts.AxisOpts(min_="dataMin") # dataMin怎么来的,官方文档上去查,写得明明白白 28 | ) 29 | .add_xaxis(xaxis_data=xData) 30 | ) 31 | # 添加y轴数据 32 | boxplot.add_yaxis( 33 | series_name="", 34 | y_axis=boxplot.prepare_data([y1, y2, y3, y4, y5, y6]) 35 | ) 36 | # 保存路径 37 | resultPath = "./result" 38 | if not os.path.exists(path=resultPath): 39 | os.mkdir(path=resultPath) 40 | # 保存文件名 41 | resultFileName = "scores_boxplot.html" 42 | # 执行保存 43 | boxplot.render(path=os.path.join(resultPath, resultFileName)) 44 | -------------------------------------------------------------------------------- /12数据分布之箱线图/example12_3/example12_3.py: -------------------------------------------------------------------------------- 1 | # 探究泰坦尼克号不同等级船舱的乘客年龄分布情况 2 | import os 3 | import openpyxl 4 | from openpyxl import Workbook 5 | from openpyxl.worksheet.worksheet import Worksheet 6 | from pyecharts.charts import Boxplot 7 | import pyecharts.options as opts 8 | 9 | # 资源文件目录 10 | resourcesPath = "./resources" 11 | # 泰坦尼克号遇难者名单 12 | titanicBookName = "titanic.xlsx" 13 | # 乘客名单工作表 14 | passengerSheetName = "passenger" 15 | # 打开文件、选表 16 | passengerSheet = openpyxl.load_workbook( 17 | filename=os.path.join(resourcesPath, titanicBookName) 18 | )[passengerSheetName] # type: Worksheet 19 | 20 | # 选择[船舱等级, 年龄]两列的数据,提取这两列的原始数据 21 | orgData = [ 22 | [row_item[1], row_item[4]] 23 | for row_item in passengerSheet.iter_rows(min_row=2, values_only=True) 24 | ] 25 | 26 | 27 | # 处理绘图用的数据 28 | plotData = { 29 | "一等舱": [], 30 | "二等舱": [], 31 | "三等舱": [] 32 | } 33 | # 扫描原始数据 34 | for pClass, age in orgData: 35 | if pClass == 1: 36 | plotData["一等舱"].append(age) 37 | elif pClass == 2: 38 | plotData["二等舱"].append(age) 39 | elif pClass == 3: 40 | plotData["三等舱"].append(age) 41 | 42 | 43 | # 绘制船舱等级与年龄关系的箱线图,需求: 44 | # 1. 主题为light 45 | # 2. 标题为“舱位与年龄的分布” 46 | # 3. y轴起点是上述y轴所有数据的最小值 47 | boxplot = ( 48 | Boxplot(init_opts=opts.InitOpts(theme="light")) 49 | .set_global_opts( 50 | title_opts=opts.TitleOpts(title="舱位与年龄的分布"), 51 | yaxis_opts=opts.AxisOpts(min_="dataMin") 52 | ) 53 | .add_xaxis(xaxis_data=list(plotData.keys())) 54 | ) 55 | # 获取箱线图y轴[min, Q2, mid, Q1, max]序列 56 | yData = boxplot.prepare_data(items=[plot_value for plot_value in plotData.values()]) 57 | print(yData) 58 | boxplot.add_yaxis( 59 | series_name="", 60 | y_axis=yData 61 | ) 62 | 63 | # 保存路径 64 | resultPath = "./result" 65 | if not os.path.exists(path=resultPath): 66 | os.mkdir(path=resultPath) 67 | # 保存文件名 68 | resultFileName = "titanic_boxplot.html" 69 | # 执行保存 70 | boxplot.render(path=os.path.join(resultPath, resultFileName)) 71 | -------------------------------------------------------------------------------- /12数据分布之箱线图/example12_3/resources/titanic.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/12数据分布之箱线图/example12_3/resources/titanic.xlsx -------------------------------------------------------------------------------- /13数据流向之桑基图/example13_1/example13_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Sankey 3 | import pyecharts.options as opts 4 | 5 | # 用桑基图表达月度开支的钱的各种去向 6 | 7 | # 准备桑基图的原始数据(节点、信息流),跳过从excel中读取数据的过程 8 | # 节点列表:格式[{"name": 标签名1}, {“name”: 标签名2}, ...] 9 | nodes = [ 10 | {"name": "围巾"}, 11 | {"name": "长辈"}, 12 | {"name": "网络费"}, 13 | {"name": "服装"}, 14 | {"name": "公交"}, 15 | {"name": "同学"}, 16 | {"name": "袜子"}, 17 | {"name": "总费用"}, 18 | {"name": "衣服"}, 19 | {"name": "红包"}, 20 | {"name": "交通"}, 21 | {"name": "聚餐"}, 22 | {"name": "滴滴"}, 23 | {"name": "餐饮"}, 24 | {"name": "管理费"}, 25 | {"name": "水电"}, 26 | {"name": "共享单车"}, 27 | {"name": "外卖"}, 28 | {"name": "房租"}, 29 | {"name": "住宿"}, 30 | {"name": "饮料"}, 31 | {"name": "鞋子"}, 32 | {"name": "地铁"} 33 | ] 34 | # 信息流列表:格式 35 | # [{"source": 标签名1, "target": 标签名1, "value": 取值1}, 36 | # {"source": 标签名2, "target": 标签名2, "value": 取值2}, 37 | # ......] 38 | links = [ 39 | {"source": "总费用", "target": "住宿", "value": 2580}, 40 | {"source": "总费用", "target": "餐饮", "value": 1300}, 41 | {"source": "总费用", "target": "交通", "value": 500}, 42 | {"source": "总费用", "target": "服装", "value": 900}, 43 | {"source": "总费用", "target": "红包","value": 1300}, 44 | {"source": "住宿", "target": "房租", "value": 2000}, 45 | {"source": "住宿", "target": "水电", "value": 400}, 46 | {"source": "住宿", "target": "管理费", "value": 100}, 47 | {"source": "住宿", "target": "网络费", "value": 80}, 48 | {"source": "餐饮", "target": "外卖", "value": 800}, 49 | {"source": "餐饮", "target": "聚餐", "value": 300}, 50 | {"source": "餐饮", "target": "饮料", "value": 200}, 51 | {"source": "交通", "target": "滴滴", "value": 220}, 52 | {"source": "交通", "target": "地铁", "value": 150}, 53 | {"source": "交通", "target": "公交", "value": 80}, 54 | {"source": "交通", "target": "共享单车", "value": 50}, 55 | {"source": "服装", "target": "衣服", "value": 400}, 56 | {"source": "服装", "target": "鞋子", "value": 300}, 57 | {"source": "服装", "target": "围巾", "value": 150}, 58 | {"source": "服装", "target": "袜子", "value": 50}, 59 | {"source": "红包", "target": "同学", "value": 800}, 60 | {"source": "红包", "target": "长辈", "value": 500} 61 | ] 62 | 63 | # 桑基图绘图的需求: 64 | # 1. 根据开支明细,按照节点和信息流列表结构,直接创建数据的节点和信息流列表; 65 | # 2. 绘制桑基图,系列名称为"月度开支" 66 | # 3. 数据标签统一放在节点右边 67 | # 4. 保存图片 68 | # 5. 这个图绘制出来肯定特别丑,所以后面还会改进 69 | # 保存路径 70 | resultPath = "./result" 71 | if not os.path.exists(path=resultPath): 72 | os.mkdir(path=resultPath) 73 | # 保存文件名 74 | resultFileName = "purchase_sankey.html" 75 | # 执行绘图 76 | sankey = ( 77 | Sankey() 78 | .add( 79 | series_name="月度开支", 80 | nodes=nodes, 81 | links=links, 82 | label_opts=opts.LabelOpts(position="right") 83 | ) 84 | .render(path=os.path.join(resultPath, resultFileName)) 85 | ) 86 | -------------------------------------------------------------------------------- /13数据流向之桑基图/example13_2/example13_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Sankey 3 | import pyecharts.options as opts 4 | 5 | # 使用桑基图直观表达创意馆产品不同类型产品的数量 6 | 7 | # 准备原始数据(节点、信息流),暂时略去从表中读取出数据的过程 8 | # 节点列表 9 | nodes = [ 10 | {"name": "遥控"}, 11 | {"name": "非遥控"}, 12 | {"name": "机器人"}, 13 | {"name": "猛击赛车"}, 14 | {"name": "莱肯赛车"} 15 | ] 16 | # 信息流列表 17 | links = [ 18 | {"source": "遥控", "target": "机器人", "value": 15}, 19 | {"source": "遥控", "target": "猛击赛车", "value": 23}, 20 | {"source": "遥控", "target": "莱肯赛车", "value": 36}, 21 | {"source": "非遥控", "target": "机器人", "value": 48}, 22 | {"source": "非遥控", "target": "猛击赛车", "value": 21}, 23 | {"source": "非遥控", "target": "莱肯赛车", "value": 11} 24 | ] 25 | 26 | # 绘制桑基图要求 27 | # 1. 数据系列名称为空 28 | # 2. 添加数据标签放在节点右边; 29 | # 3. 全图标题"馆内产品分类"; 30 | # 4. 保存图片 31 | # 5. 图片很丑,后面再操心怎么优化 32 | # 保存路径 33 | resultPath = "./result" 34 | if not os.path.exists(path=resultPath): 35 | os.mkdir(path=resultPath) 36 | # 保存文件名 37 | resultFileName = "product_category_sankey.html" 38 | # 执行绘图 39 | sankey = ( 40 | Sankey() 41 | .set_global_opts(title_opts=opts.TitleOpts(title="馆内产品分类")) 42 | .add( 43 | series_name="", 44 | nodes=nodes, 45 | links=links, 46 | label_opts=opts.LabelOpts(position="right") 47 | ) 48 | .render(path=os.path.join(resultPath, resultFileName)) 49 | ) 50 | -------------------------------------------------------------------------------- /13数据流向之桑基图/example13_2/result/product_category_sankey.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Awesome-pyecharts 6 | 7 | 8 | 9 | 10 |
11 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /13数据流向之桑基图/example13_3/example13_3.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Sankey 3 | import pyecharts.options as opts 4 | 5 | # 在example13_2基础上再进一步,使用桑基图直观表达创意馆产品不同分类的产品销售情况 6 | 7 | # 准备原始数据(节点、信息流),省略从表格中读进数据的步骤 8 | # 数据节点列表 9 | nodes = [ 10 | {"name": "机器人"}, 11 | {"name": "猛击赛车"}, 12 | {"name": "莱肯赛车"}, 13 | {"name": "遥控机器人"}, 14 | {"name": "遥控猛击赛车"}, 15 | {"name": "遥控莱肯赛车"}, 16 | {"name": "非遥控机器人"}, 17 | {"name": "非遥控猛击赛车"}, 18 | {"name": "非遥控莱肯赛车"}, 19 | {"name": "未购买"}, 20 | {"name": "购买"} 21 | ] 22 | # 信息流列表 23 | links = [ 24 | {"source": "机器人", "target": "遥控机器人", "value": 12}, 25 | {"source": "机器人", "target": "非遥控机器人", "value": 32}, 26 | {"source": "猛击赛车", "target": "遥控猛击赛车", "value": 23}, 27 | {"source": "猛击赛车", "target": "非遥控猛击赛车", "value": 11}, 28 | {"source": "莱肯赛车", "target": "遥控莱肯赛车", "value": 45}, 29 | {"source": "莱肯赛车", "target": "非遥控莱肯赛车", "value": 12}, 30 | {"source": "遥控机器人", "target": "未购买", "value": 12}, 31 | {"source": "遥控猛击赛车", "target": "购买", "value": 23}, 32 | {"source": "遥控莱肯赛车", "target": "未购买", "value": 45}, 33 | {"source": "非遥控机器人", "target": "购买", "value": 32}, 34 | {"source": "非遥控猛击赛车", "target": "未购买", "value": 11}, 35 | {"source": "非遥控莱肯赛车", "target": "购买", "value": 12} 36 | ] 37 | 38 | # 绘制桑基图需求 39 | # 1. 数据系列名称设置为空 40 | # 2. 数据标签放在节点右边 41 | # 3. 图表标题为“馆内产品售卖” 42 | # 4. 保存 43 | # 5. 图可能会很丑,美化的事情后面再操心 44 | # 保存路径 45 | resultPath = "./result" 46 | if not os.path.exists(path=resultPath): 47 | os.mkdir(path=resultPath) 48 | # 保存文件名 49 | resultFileName = "product_sales_sankey.html" 50 | sankey = ( 51 | Sankey() 52 | .set_global_opts(title_opts=opts.TitleOpts(title="馆内产品售卖")) 53 | .add( 54 | series_name="", 55 | nodes=nodes, 56 | links=links, 57 | label_opts=opts.LabelOpts(position="right"), 58 | linestyle_opt=opts.LineStyleOpts(color="#FFF0F5") 59 | ) 60 | ) 61 | # 执行保存 62 | sankey.render(path=os.path.join(resultPath, resultFileName)) 63 | -------------------------------------------------------------------------------- /13数据流向之桑基图/example13_4/example13_4.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Sankey 3 | import pyecharts.options as opts 4 | 5 | # 使用三维桑基图(性别-熬夜原因-人数)直观描述当代青年人熬夜的原因分布情况 6 | 7 | # 准备原始数据(节点、信息流),从表中取数据的过程略去 8 | # 节点 9 | nodes = [ 10 | {"name": "男"}, 11 | {"name": "女"}, 12 | {"name": "打游戏"}, 13 | {"name": "加班"}, 14 | {"name": "看剧"} 15 | ] 16 | # 信息流 17 | links = [ 18 | {"source": "男", "target": "打游戏", "value": 79}, 19 | {"source": "男", "target": "加班", "value": 13}, 20 | {"source": "男", "target": "看剧", "value": 24}, 21 | {"source": "女", "target": "打游戏", "value": 16}, 22 | {"source": "女", "target": "加班", "value": 5}, 23 | {"source": "女", "target": "看剧", "value": 63} 24 | ] 25 | 26 | # 绘制桑基图需求 27 | # 1. 主题为light 28 | # 2. 标题为“当代青年熬夜原因” 29 | # 3. 隐藏图例 30 | # 4. 美化图片:信息流透明度为20%,弯曲度50%,颜色取目标节点的颜色(这种特殊值怎么取,查官方文档) 31 | # 5. 标签放在节点右侧,颜色设置为黑色 32 | # 6. 保存图片 33 | # 保存路径 34 | resultPath = "./result" 35 | if not os.path.exists(path=resultPath): 36 | os.mkdir(path=resultPath) 37 | # 保存文件名 38 | resultFileName = "stayup_reason_sankey.html" 39 | # 执行绘图 40 | sankey = ( 41 | Sankey(init_opts=opts.InitOpts(theme="light")) 42 | .set_global_opts( 43 | title_opts=opts.TitleOpts(title="当代青年熬夜原因"), 44 | legend_opts=opts.LegendOpts(is_show=False) 45 | ) 46 | .add( 47 | series_name="", 48 | nodes=nodes, 49 | links=links, 50 | linestyle_opt=opts.LineStyleOpts( 51 | opacity=0.2, 52 | curve=0.5, 53 | color="target" # 取目标节点的颜色 54 | ), 55 | label_opts=opts.LabelOpts( 56 | color="rgb(0, 0, 0)", # 或者写成#000000 57 | position="right" 58 | ) 59 | ) 60 | ) 61 | # 执行保存 62 | sankey.render(path=os.path.join(resultPath, resultFileName)) 63 | -------------------------------------------------------------------------------- /13数据流向之桑基图/example13_4/result/stayup_reason_sankey.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Awesome-pyecharts 6 | 7 | 8 | 9 | 10 |
11 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /13数据流向之桑基图/example13_5/example13_5.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Sankey 3 | import pyecharts.options as opts 4 | from pyecharts.globals import ThemeType 5 | 6 | # 桑基图直观表达宠物店商品的购买路径 7 | 8 | # 准备绘制桑基图需要的数据(节点、数据流),省略从文件中取出数据的过程 9 | # 创建节点列表 10 | 11 | nodes = [ 12 | {"name": "狗粮"}, 13 | {"name": "玩具"}, 14 | {"name": "1-小规格狗粮"}, 15 | {"name": "1-大规格狗粮"}, 16 | {"name": "1-磨牙棒"}, 17 | {"name": "2-未购买"}, 18 | {"name": "2-小规格狗粮"}, 19 | {"name": "2-大规格狗粮"}, 20 | {"name": "2-磨牙棒"}, 21 | ] 22 | # 创建信息流列表 23 | links = [ 24 | {"source": "狗粮", "target": "1-小规格狗粮", "value": 613}, 25 | {"source": "狗粮", "target": "1-大规格狗粮", "value": 1018}, 26 | {"source": "玩具", "target": "1-磨牙棒", "value": 197}, 27 | {"source": "1-小规格狗粮", "target": "2-未购买", "value": 654}, 28 | {"source": "1-小规格狗粮", "target": "2-磨牙棒", "value": 21}, 29 | {"source": "1-小规格狗粮", "target": "2-小规格狗粮", "value": 231}, 30 | {"source": "1-小规格狗粮", "target": "2-大规格狗粮", "value": 112}, 31 | {"source": "1-大规格狗粮", "target": "2-未购买", "value": 375}, 32 | {"source": "1-大规格狗粮", "target": "2-磨牙棒", "value": 23}, 33 | {"source": "1-大规格狗粮", "target": "2-小规格狗粮", "value": 18}, 34 | {"source": "1-大规格狗粮", "target": "2-大规格狗粮", "value": 197}, 35 | {"source": "1-磨牙棒", "target": "2-未购买", "value": 157}, 36 | {"source": "1-磨牙棒", "target": "2-磨牙棒", "value": 3}, 37 | {"source": "1-磨牙棒", "target": "2-小规格狗粮", "value": 24}, 38 | {"source": "1-磨牙棒", "target": "2-大规格狗粮", "value": 13}, 39 | ] 40 | 41 | # 绘制桑基图的需求 42 | # 1. 主题设为essos风格 43 | # 2. 标题为“购买路径” 44 | # 3. 图例隐藏 45 | # 4. 信息流设为垂直方向(参考下官方文档里的参数设置) 46 | # 5. 标签在节点上方,颜色为黑色 47 | # 6. 美化图片:信息流透明度为0.3,弯曲度为0.5,颜色与目标节点颜色一致 48 | # 7. 保存图片 49 | # 保存路径 50 | resultPath = "./result" 51 | if not os.path.exists(path=resultPath): 52 | os.mkdir(path=resultPath) 53 | # 保存文件名 54 | resultFileName = "pet_sales_sankey.html" 55 | # 执行绘图 56 | sankey = ( 57 | Sankey(init_opts=opts.InitOpts(theme=ThemeType.ESSOS)) 58 | .set_global_opts( 59 | title_opts=opts.TitleOpts(title="购买路径"), 60 | legend_opts=opts.LegendOpts(is_show=False) 61 | ) 62 | .add( 63 | series_name="", 64 | nodes=nodes, 65 | links=links, 66 | orient="vertical", 67 | linestyle_opt=opts.LineStyleOpts( 68 | opacity=0.3, 69 | curve=0.5, 70 | color="target" 71 | ), 72 | label_opts=opts.LabelOpts( 73 | position="top", 74 | color="#000000" 75 | ) 76 | ) 77 | ) 78 | # 执行保存 79 | sankey.render(path=os.path.join(resultPath, resultFileName)) 80 | -------------------------------------------------------------------------------- /13数据流向之桑基图/example13_6/example13_6.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Sankey 3 | import pyecharts.options as opts 4 | import openpyxl 5 | from openpyxl.workbook.workbook import Workbook 6 | from openpyxl.worksheet.worksheet import Worksheet 7 | 8 | # 使用桑基图,直观描述一个人的年度歌单下不同类目的歌曲的数量构成 9 | 10 | 11 | # 配置信息 12 | 13 | # 资源文件夹 14 | resourcesPath = "./resources" 15 | # 歌单数据文件 16 | songListBookName = "song.xlsx" 17 | # 歌单工作表名 18 | songListSheetName = "年度歌单" 19 | # 打开歌单数据表 20 | songListSheet = openpyxl.load_workbook( 21 | filename=os.path.join(resourcesPath, songListBookName) 22 | )[songListSheetName] # type: Worksheet 23 | 24 | 25 | # 按照格式生成桑基图的节点数据字典 26 | def sankey_node(node_name: str) -> dict: 27 | """ 28 | 绘制桑基图节点的固定格式{"name": node_name} 29 | 30 | :param node_name: 节点名称 31 | 32 | :return: 绘制桑基图固定节点格式{"name": node_name} 33 | """ 34 | return {"name": node_name} 35 | 36 | 37 | # 按照格式生成桑基图的信息流数据字典 38 | def sankey_link(source_name: str, target_name: str, val: float) -> dict: 39 | """ 40 | 41 | 绘制桑基图节点的固定格式{"source": src_name, "target": target_name, "value": val} 42 | 43 | :param source_name: 信息流源节点的名称 44 | 45 | :param target_name: 信息流目标节点的名称 46 | 47 | :param val: 信息流权重(多少数据在这个信息流上) 48 | 49 | :return: {"source": src_name, "target": target_name, "value": val} 50 | """ 51 | return {"source": source_name, "target": target_name, "value": val} 52 | 53 | 54 | # 准备原始数据:先把表格内容都读进来 55 | orgData = [row_item for row_item in songListSheet.iter_rows(min_row=2, values_only=True)] 56 | # print(orgData) 57 | # 准备绘图用数据:节点列表和信息流列表 58 | nodes = [] 59 | links = [] 60 | 61 | 62 | # 扫描各行,添加节点原始数据 63 | for songItem in orgData: 64 | nodes.extend(list(songItem[:-1])) 65 | # 节点去重 66 | nodes = list(set(nodes)) 67 | # 修饰每个节点数据,改造成符合sankey绘图格式的字典格式 68 | for songIndex, songTypeItem in enumerate(nodes): 69 | nodes[songIndex] = sankey_node(node_name=songTypeItem) 70 | 71 | 72 | # 根据原始数据生成信息流,添加至列表 73 | for songType in orgData: 74 | # 把取值拎出来 75 | val = songType[-1] 76 | # 一共有多少个分级类目 77 | levelCount = len(songType[0:-1]) 78 | # 考虑多个分级的通用情况 79 | for level in range(levelCount-1): 80 | # 当前分级和下一分级之间存在一个信息流 81 | links.append( 82 | sankey_link( 83 | source_name=songType[level], 84 | target_name=songType[level + 1], 85 | val=val) 86 | ) 87 | 88 | # print(nodes) 89 | # print(links) 90 | 91 | 92 | # 绘制桑基图的需求 93 | # 1. 主题为dark 94 | # 2. 背景色为#253441 95 | # 3. 标题为“年度歌单” 96 | # 4. 隐藏图例 97 | # 5. 美化图片:信息流的透明度为30%,弯曲度50%,颜色与源节点统一一致(有一个特殊值,查官方文档说了) 98 | # 6. 数据标签字体10,放节点右侧,颜色为白色#FFFFFF 99 | # 7. 保存图片 100 | # 保存路径 101 | resultPath = "./result" 102 | if not os.path.exists(path=resultPath): 103 | os.mkdir(path=resultPath) 104 | # 保存文件名 105 | resultFileName = "songList_sankey.html" 106 | # 执行绘图 107 | sankey = ( 108 | Sankey( 109 | init_opts=opts.InitOpts( 110 | theme="dark", 111 | bg_color="#253441" 112 | ) 113 | ) 114 | .set_global_opts( 115 | title_opts=opts.TitleOpts(title="年度歌单"), 116 | legend_opts=opts.LegendOpts(is_show=False) 117 | ) 118 | .add( 119 | series_name="", 120 | nodes=nodes, 121 | links=links, 122 | linestyle_opt=opts.LineStyleOpts( 123 | opacity=0.3, 124 | curve=0.5, 125 | color="source" 126 | ), 127 | label_opts=opts.LabelOpts( 128 | font_size=10, 129 | position="right", 130 | color="#FFFFFF" 131 | ) 132 | ) 133 | ) 134 | # 执行保存 135 | sankey.render(path=os.path.join(resultPath, resultFileName)) 136 | -------------------------------------------------------------------------------- /13数据流向之桑基图/example13_6/resources/song.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/13数据流向之桑基图/example13_6/resources/song.xlsx -------------------------------------------------------------------------------- /14相关与分布之散点图/example14_1/example14_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openpyxl 3 | from openpyxl.workbook.workbook import Workbook 4 | from openpyxl.worksheet.worksheet import Worksheet 5 | from pyecharts.charts import Scatter 6 | import pyecharts.options as opts 7 | 8 | # 用散点图描述电竞游戏职业玩家WJ.TS的100局游戏中,经济占比对输出占比影响的相关性 9 | 10 | # 基础参数 11 | # 资源文件所在目录 12 | resourcesPath = "./resources" 13 | # 职业玩家的游戏数据文件 14 | gameBookName = "wj.xlsx" 15 | # 工作表名称 16 | gameSheetName = "选手数据" 17 | 18 | # 取出输出和经济数据,因为原表结构不是很好,代码不是很讲究复用性 19 | wb = openpyxl.load_workbook(filename=os.path.join(resourcesPath, gameBookName)) # type: Workbook 20 | sheet = wb[gameSheetName] # type: Worksheet 21 | # 100局游戏的输出数据,作为x轴 22 | attack_list = [] 23 | # 100局游戏的经济数据,作为y轴 24 | income_list = [] 25 | for attackCell, incomeCell in zip(sheet["K"], sheet["M"]): 26 | attack_list.append(attackCell.value) 27 | income_list.append(incomeCell.value) 28 | 29 | # 截取出WJ.TS的输出数据 30 | attack_list = attack_list[1:101] 31 | # 截取出WJ.TS的经济数据 32 | income_list = income_list[1:101] 33 | # print(attack_list) 34 | # print(income_list) 35 | 36 | # 散点图绘制需求 37 | # 1. x轴的数据不是用作零散的数据项,而是作为取值,注意设定x轴类型(查文档) 38 | # 2. 散点数据的标签要隐藏 39 | # 3. x轴名为"经济占比",y轴名为"伤害占比" 40 | # 4. 标题"输出占比与经济占比之间的关系" 41 | # 5. 保存 42 | # 保存路径 43 | resultPath = "./result" 44 | if not os.path.exists(path=resultPath): 45 | os.mkdir(path=resultPath) 46 | # 保存文件名 47 | resultFileName = "attack_income_scatter.html" 48 | # 执行绘图 49 | scatter = ( 50 | Scatter() 51 | .set_global_opts( 52 | title_opts=opts.TitleOpts(title="输出占比与经济占比之间的关系"), 53 | xaxis_opts=opts.AxisOpts(name="经济占比", type_="value"), 54 | yaxis_opts=opts.AxisOpts(name="伤害占比") 55 | ) 56 | .add_xaxis(xaxis_data=income_list) 57 | .add_yaxis( 58 | series_name="伤害-经济相关性", 59 | y_axis=attack_list, 60 | label_opts=opts.LabelOpts(is_show=False) 61 | ) 62 | .render(path=os.path.join(resultPath, resultFileName)) 63 | ) 64 | -------------------------------------------------------------------------------- /14相关与分布之散点图/example14_1/resources/wj.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/14相关与分布之散点图/example14_1/resources/wj.xlsx -------------------------------------------------------------------------------- /14相关与分布之散点图/example14_2/example14_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Scatter 3 | import pyecharts.options as opts 4 | import openpyxl 5 | from openpyxl.workbook.workbook import Workbook 6 | from openpyxl.worksheet.worksheet import Worksheet 7 | 8 | # 资源目录 9 | resourcesPath = "./resources" 10 | # 日均销量对比工作表名 11 | dailySalesBookName = "日均销量对比.xlsx" 12 | # 选中工作表 13 | wb = openpyxl.load_workbook(filename=os.path.join(resourcesPath, dailySalesBookName)) # type: Workbook 14 | sheet = wb["销量对比"] # type: Worksheet 15 | 16 | # 取出阿珍和竞品商的销售数据(因为本身这个表结构不是特别好,所以读的话就按照下面毫无复用性的烂代码读吧) 17 | # 取出需要对比的商品名称(作为x轴) 18 | name_list = [] 19 | for cell in sheet["B"][1:7]: 20 | name_list.append(cell.value) 21 | 22 | # 将商品销量这一列数据全部提取出 23 | sales_list = [] 24 | for cell in sheet["C"]: 25 | sales_list.append(cell.value) 26 | # 阿珍的数据sales_azhen(y轴数据1) 27 | sales_azhen = sales_list[1:7] 28 | # 竞品的数据sales_competitor(y轴数据2) 29 | sales_competitor = sales_list[7:13] 30 | 31 | # 绘制散点图需求 32 | # 1. 标题“日均销量对比” 33 | # 2. 阿珍的数据用点表示,竞品数据用菱形表示(查官方文档找参数) 34 | # 3. 添加视觉映设,最大映射取350,最小映射取20,数据大小通过视觉映射的大小体现(查文档找参数) 35 | # 4. 图例系列名分别为“阿珍”和“竞品” 36 | # 5. 设置x轴名称为“商品”,y轴名称为“销量” 37 | # 6. 保存文件 38 | # 保存路径 39 | resultPath = "./result" 40 | if not os.path.exists(path=resultPath): 41 | os.mkdir(path=resultPath) 42 | # 保存文件名 43 | resultFileName = "product_competitor_scatter.html" 44 | # 执行绘图 45 | scatter = ( 46 | Scatter() 47 | .set_global_opts( 48 | title_opts=opts.TitleOpts(title="日均销量对比"), 49 | visualmap_opts=opts.VisualMapOpts( 50 | max_=350, 51 | min_=20, 52 | type_="size" 53 | ), 54 | xaxis_opts=opts.AxisOpts(name="商品"), 55 | yaxis_opts=opts.AxisOpts(name="销量") 56 | ) 57 | .add_xaxis(xaxis_data=name_list) 58 | .add_yaxis( 59 | series_name="阿珍", 60 | y_axis=sales_azhen 61 | ) 62 | .add_yaxis( 63 | series_name="竞品", 64 | y_axis=sales_competitor, 65 | symbol="diamond" 66 | ) 67 | ) 68 | # 执行保存 69 | scatter.render(path=os.path.join(resultPath, resultFileName)) 70 | -------------------------------------------------------------------------------- /14相关与分布之散点图/example14_2/resources/日均销量对比.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/14相关与分布之散点图/example14_2/resources/日均销量对比.xlsx -------------------------------------------------------------------------------- /14相关与分布之散点图/example14_3/example14_3.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Scatter, Tab 3 | import pyecharts.options as opts 4 | from pyecharts.globals import ThemeType 5 | import openpyxl 6 | from openpyxl.workbook.workbook import Workbook 7 | from openpyxl.worksheet.worksheet import Worksheet 8 | 9 | # 散点图画下面几组很有趣的数据,放在看板里面 10 | # Alberto Cairo教授曾经构造的5组数据文件 11 | # 这5组文件很有特点:x系列数值平均数相同,标准差相同,相关系数也相同;y系列数值亦然 12 | # 但绘制出的散点图却完全不同 13 | 14 | # 资源文件目录 15 | resourcesPath = "./resources" 16 | # 工作文件名 17 | acBookName = "dino1.xlsx" 18 | # 工作表名 19 | acSheetName = "数据" 20 | 21 | # 打开文件选表 22 | acSheet = openpyxl.load_workbook(filename=os.path.join(resourcesPath, acBookName))[acSheetName] # type: Worksheet 23 | 24 | # 逐列扫描提出数据,跳过表头 25 | orgData = [list(col_item) for col_item in acSheet.iter_cols(min_row=3, values_only=True)] 26 | print(orgData) 27 | 28 | # 提取各列用于绘制散点图的数据 29 | awayX = orgData[0] 30 | awayY = orgData[1] 31 | bullseyeX = orgData[2] 32 | bullseyeY = orgData[3] 33 | circleX = orgData[4] 34 | circleY = orgData[5] 35 | dinoX = orgData[6] 36 | dinoY = orgData[7] 37 | dotsX = orgData[8] 38 | dotsY = orgData[9] 39 | 40 | 41 | def scat_plot(x_data, y_data) -> Scatter: 42 | """ 43 | 用于绘制散点图的x轴和y轴数据 44 | 45 | 1. 画布宽度为"1000px",高度为"600px",主题为"light" 46 | 47 | 2. 隐藏y轴的数据标签 48 | 49 | 3. x轴的坐标应该是连续型 50 | 51 | :param x_data: x轴数据 52 | 53 | :param y_data: y轴数据 54 | 55 | :return: 画好的散点图对象,用于后续添加到看板中 56 | """ 57 | scatter = ( 58 | Scatter(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width="1000px", height="600px")) 59 | .set_global_opts(xaxis_opts=opts.AxisOpts(type_="value")) 60 | .add_xaxis(xaxis_data=x_data) 61 | .add_yaxis( 62 | series_name="", 63 | y_axis=y_data, 64 | label_opts=opts.LabelOpts(is_show=False) 65 | ) 66 | ) 67 | return scatter 68 | 69 | 70 | # 逐个执行绘图,添加到看板中,并保存 71 | # 保存路径 72 | resultPath = "./result" 73 | if not os.path.exists(path=resultPath): 74 | os.mkdir(path=resultPath) 75 | # 文件名 76 | resultFileName = "acplot_scatter.html" 77 | # 执行绘图和保存 78 | tab = ( 79 | Tab() 80 | .add(chart=scat_plot(x_data=awayX, y_data=awayY), tab_name="away") 81 | .add(chart=scat_plot(x_data=bullseyeX, y_data=bullseyeY), tab_name="bullseye") 82 | .add(chart=scat_plot(x_data=circleX, y_data=circleY), tab_name="circle") 83 | .add(chart=scat_plot(x_data=dinoX, y_data=dinoY), tab_name="dino") 84 | .add(chart=scat_plot(x_data=dotsX, y_data=dotsY), tab_name="dots") 85 | .render(path=os.path.join(resultPath, resultFileName)) 86 | ) 87 | -------------------------------------------------------------------------------- /14相关与分布之散点图/example14_3/resources/dino1.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/14相关与分布之散点图/example14_3/resources/dino1.xlsx -------------------------------------------------------------------------------- /15综合评估之雷达图/example15_1/example15_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Radar 3 | import pyecharts.options as opts 4 | 5 | # 使用雷达图,综合评估两地的各种空气指标 6 | # [AQI(空气质量指数), PM2.5, PM10, CO, NO2, SO2] 7 | 8 | # 准备绘图用的初始顺序 9 | # 构造A城市多日空气情况的二维数据表 10 | A = [ 11 | [55, 9, 56, 0.46, 18, 6], 12 | [25, 11, 21, 0.65, 34, 9], 13 | [56, 7, 63, 0.3, 14, 5], 14 | [33, 7, 29, 0.33, 16, 6], 15 | [42, 24, 44, 0.76, 40, 16], 16 | [82, 58, 90, 1.77, 68, 33], 17 | [74, 49, 77, 1.46, 48, 27], 18 | [78, 55, 80, 1.29, 59, 29], 19 | [267, 216, 280, 4.8, 108, 64], 20 | [185, 127, 216, 2.52, 61, 27], 21 | [39, 19, 38, 0.57, 31, 15], 22 | [41, 11, 40, 0.43, 21, 7], 23 | ] 24 | # 构造B城市多日空气情况的二维数据表 25 | B = [ 26 | [91, 45, 125, 0.82, 34, 23], 27 | [65, 27, 78, 0.86, 45, 29], 28 | [83, 60, 84, 1.09, 73, 27], 29 | [109, 81, 121, 1.28, 68, 51], 30 | [106, 77, 114, 1.07, 55, 51], 31 | [109, 81, 121, 1.28, 68, 51], 32 | [106, 77, 114, 1.07, 55, 51], 33 | [89, 65, 78, 0.86, 51, 26], 34 | [53, 33, 47, 0.64, 50, 17], 35 | [80, 55, 80, 1.01, 75, 24], 36 | [117, 81, 124, 1.03, 45, 24], 37 | [99, 71, 142, 1.1, 62, 42], 38 | ] 39 | 40 | # 绘制雷达图的需求 41 | # 1. 坐标轴一共有6个维度,每个维度取名为相应空气指标的名字,每个维度限制合理的最大值和最小值 42 | # 2. 坐标轴整体为圆形 43 | # 3. A市的图例系列名称为“A市”,B市同理;颜色分别为#6495ed和#ff8c00 44 | # 4. 不显示数据标签 45 | # 5. 标题为"空气质量对比" 46 | # 6. 执行保存 47 | # 保存路径 48 | resultPath = "./result" 49 | if not os.path.exists(path=resultPath): 50 | os.mkdir(path=resultPath) 51 | # 保存文件名 52 | resultFileName = "air_quality_radar.html" 53 | # 按照格式设置坐标轴(schema)属性 54 | c_schema = [ 55 | opts.RadarIndicatorItem(name="AQI", max_=300, min_=5), 56 | opts.RadarIndicatorItem(name="PM2.5", max_=250, min_=20), 57 | opts.RadarIndicatorItem(name="PM10", max_=300, min_=5), 58 | opts.RadarIndicatorItem(name="CO", max_=5), 59 | opts.RadarIndicatorItem(name="NO2", max_=200), 60 | opts.RadarIndicatorItem(name="SO2", max_=100) 61 | # 等价于用字典创建 62 | # {"name": "AQI", "max": 300, "min": 5}, 63 | # {"name": "PM2.5", "max": 250, "min": 20}, 64 | # {"name": "PM10", "max": 300, "min": 5}, 65 | # {"name": "CO", "max": 5}, 66 | # {"name": "NO2", "max": 200}, 67 | # {"name": "SO2", "max": 100} 68 | ] 69 | # 执行绘图 70 | radar = ( 71 | Radar() 72 | .set_global_opts(title_opts=opts.TitleOpts(title="空气质量对比")) 73 | .add_schema(schema=c_schema, shape="circle") 74 | .add( 75 | series_name="A市", 76 | data=A, 77 | label_opts=opts.LabelOpts(is_show=False), 78 | color="#6495ed" 79 | ) 80 | .add( 81 | series_name="B市", 82 | data=B, 83 | label_opts=opts.LabelOpts(is_show=False), 84 | color="#ff8c00" 85 | ) 86 | .render(path=os.path.join(resultPath, resultFileName)) 87 | ) 88 | -------------------------------------------------------------------------------- /15综合评估之雷达图/example15_2/example15_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts import options as opts 3 | from pyecharts.charts import Radar 4 | 5 | # 准备用于绘制雷达图的数据,省略从文件中读取的部分 6 | # 六个数据维度的数据是[传球, 射门, 体力, 防守, 速度, 盘带] 7 | # C·罗纳尔多的数据,并赋值给cl 8 | cl = [[83, 92, 87, 49, 89, 86]] 9 | # 梅西的数据,并赋值给mx 10 | mx = [[88, 95, 66, 43, 86, 96]] 11 | # 苏亚雷斯的数据 12 | sy = [[80, 92, 87, 58, 78, 81]] 13 | # 莱万多夫斯基的数据 14 | lw = [[79, 92, 84, 53, 81, 87]] 15 | # 列兹曼的数据 16 | gl = [[84, 87, 70, 54, 86, 89]] 17 | 18 | # 雷达图绘图需求 19 | # 1. 设置雷达的坐标系 20 | # 2. 雷达图的背景色为#dcdcdc 21 | # 3. 雷达图的宽、高分别为1000px和600px 22 | # 4. 雷达图的标题为"球员表现" 23 | # 5. 数据标签全部隐藏 24 | # 6. 雷达图围起来的区域要体现出颜色,透明度设置为1 25 | # 7. 取值: 26 | # 第一个球员的数据为:图例系列名称"C·罗纳尔多",数据值cl,颜色为#6495ed,并将数据标签隐藏 27 | # 第二个球员的数据为:图例系列名称"梅西",数据值mx,颜色为#ff8c00,并将数据标签隐藏 28 | # 第三个球员的数据为:图例系列名称"苏亚雷斯",数据值sy,颜色为#00ff00,并将数据标签隐藏 29 | # 第四个球员的数据为:图例系列名称"莱万多夫斯基",数据值lw,颜色为#a0522d,并将数据标签隐藏 30 | # 第五个球员的数据为:图例系列名称"格列兹曼",数据值gl,颜色为#da70d6,并将数据标签隐藏 31 | # 8. 保存图片 32 | # 保存路径 33 | resultPath = "./result" 34 | if not os.path.exists(path=resultPath): 35 | os.mkdir(path=resultPath) 36 | # 保存文件名 37 | resultFileName = "player_radar.html" 38 | 39 | # 设置雷达图的坐标系 40 | c_schema = [ 41 | # 设置坐标轴名称"传球"和最大值100 42 | opts.RadarIndicatorItem(name="传球", max_=100), 43 | # 设置坐标轴名称"射门"和最大值100 44 | opts.RadarIndicatorItem(name="射门", max_=100), 45 | # 设置坐标轴名称"体力"和最大值100 46 | opts.RadarIndicatorItem(name="体力", max_=100), 47 | # 设置坐标轴名称"防守"和最大值100 48 | opts.RadarIndicatorItem(name="防守", max_=100), 49 | # 设置坐标轴名称"速度"和最大值100 50 | opts.RadarIndicatorItem(name="速度", max_=100), 51 | # 设置坐标轴名称"盘带"和最大值100 52 | opts.RadarIndicatorItem(name="盘带", max_=100) 53 | ] 54 | 55 | # 执行绘图 56 | radar = ( 57 | Radar( 58 | init_opts=opts.InitOpts( 59 | bg_color="#dcdcdc", 60 | width="1000px", 61 | height="600px" 62 | ) 63 | ) 64 | .set_global_opts(title_opts=opts.TitleOpts(title="球员表现")) 65 | .add_schema( 66 | schema=c_schema, 67 | splitarea_opt=opts.SplitAreaOpts( 68 | is_show=True, 69 | areastyle_opts=opts.AreaStyleOpts(opacity=1) 70 | ) 71 | ) 72 | .add( 73 | series_name="C·罗纳尔多", 74 | data=cl, 75 | color="#6495ed", 76 | label_opts=opts.LabelOpts(is_show=False) 77 | ) 78 | .add( 79 | series_name="梅西", 80 | data=mx, 81 | color="#ff8c00", 82 | label_opts=opts.LabelOpts(is_show=False) 83 | ) 84 | .add( 85 | series_name="苏亚雷斯", 86 | data=sy, 87 | color="#00ff00", 88 | label_opts=opts.LabelOpts(is_show=False) 89 | ) 90 | .add( 91 | series_name="莱万多夫斯基", 92 | data=lw, 93 | color="#a0522d", 94 | label_opts=opts.LabelOpts(is_show=False) 95 | ) 96 | .add( 97 | series_name="格列兹曼", 98 | data=gl, 99 | color="#da70d6", 100 | label_opts=opts.LabelOpts(is_show=False) 101 | ) 102 | .render(path=os.path.join(resultPath, resultFileName)) 103 | ) 104 | -------------------------------------------------------------------------------- /15综合评估之雷达图/example15_3/example15_3.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openpyxl 3 | from openpyxl.worksheet.worksheet import Worksheet 4 | from openpyxl.workbook.workbook import Workbook 5 | from pyecharts.charts import Radar 6 | import pyecharts.options as opts 7 | 8 | # 用雷达图绘制看上去比较高大上的手机品牌多项指标综合评测 9 | 10 | # 配置项 11 | # 资源文件目录 12 | resourcesPath = "./resources" 13 | # 手机测评文件名 14 | phoneTestBookName = "test.xlsx" 15 | # 手机测评工作表名 16 | phoneTestSheetName = "测评数据" 17 | 18 | # 打开文件并选表 19 | phoneTestSheet = openpyxl.load_workbook( 20 | filename=os.path.join(resourcesPath, phoneTestBookName))[phoneTestSheetName] # type: Worksheet 21 | # 取出原始数据 22 | # 数据项一共有:["外观", "性能", "拍照", "系统", "屏幕"],表头无需读取 23 | orgData = [list(row_item) for row_item in phoneTestSheet.iter_rows(min_row=2, values_only=True)] 24 | # print(orgData) 25 | # 清洗取值为None的列 26 | for row_item in orgData: 27 | while None in row_item: 28 | row_item.remove(None) 29 | 30 | # 绘制雷达图需求 31 | # 1. 设置主题为"chalk"; 32 | # 2. 标题设置为"Amy专业手机评测"; 33 | # 3. 将图例列表布局设置为纵向,图例与最左侧容器的相对距离设置为10%,与底部的相对距离设置为50% 34 | # 4. 雷达图为圆形 35 | # 5. 雷达图坐标围起来的一圈(分隔区域配置项)透明度为1 36 | # 6. 坐标轴各个部分的名称为['外观', '性能', '拍照', '系统', '屏幕'],满分均为10分 37 | # 7. 对于各种手机的取值设置:均隐藏数据标签,围起来的区域填充透明度为0.1 38 | # 图例系列名“华为”,颜色#800080 39 | # 图例系列名“OPPO”,颜色#6495ed 40 | # 图例系列名“苹果”,颜色#696969 41 | # 图例系列名“小米“,颜色#3cb371 42 | # 图例系列名“三星”,颜色#ff8c00 43 | # 8. 保存图片 44 | # 保存路径 45 | resultPath = "./result" 46 | if not os.path.exists(path=resultPath): 47 | os.mkdir(path=resultPath) 48 | # 保存文件名 49 | resultFileName = "phone_display_radar.html" 50 | 51 | # 准备坐标轴 52 | c_schema = [ 53 | opts.RadarIndicatorItem(name="外观", max_=10), 54 | opts.RadarIndicatorItem(name="性能", max_=10), 55 | opts.RadarIndicatorItem(name="拍照", max_=10), 56 | opts.RadarIndicatorItem(name="系统", max_=10), 57 | opts.RadarIndicatorItem(name="屏幕", max_=10) 58 | ] 59 | # 执行绘图 60 | radar = ( 61 | Radar(init_opts=opts.InitOpts(theme="chalk")) 62 | .set_global_opts( 63 | title_opts=opts.TitleOpts(title="Amy专业手机评测"), 64 | legend_opts=opts.LegendOpts( 65 | orient="vertical", 66 | pos_left="10%", 67 | pos_bottom="50%" 68 | ) 69 | ) 70 | .add_schema( 71 | schema=c_schema, 72 | splitarea_opt=opts.SplitAreaOpts( 73 | is_show=True, 74 | areastyle_opts=opts.AreaStyleOpts(opacity=1) 75 | ), 76 | shape="circle" 77 | ) 78 | .add( 79 | data=[orgData[0][1:6]], 80 | series_name=orgData[0][0], 81 | color="#800080", 82 | label_opts=opts.LabelOpts(is_show=False), 83 | areastyle_opts=opts.AreaStyleOpts(opacity=0.1) 84 | ) 85 | .add( 86 | data=[orgData[1][1:6]], 87 | series_name=orgData[1][0], 88 | color="#6495ed", 89 | label_opts=opts.LabelOpts(is_show=False), 90 | areastyle_opts=opts.AreaStyleOpts(opacity=0.1) 91 | ) 92 | .add( 93 | data=[orgData[2][1:6]], 94 | series_name=orgData[2][0], 95 | color="#696969", 96 | label_opts=opts.LabelOpts(is_show=False), 97 | areastyle_opts=opts.AreaStyleOpts(opacity=0.1) 98 | ) 99 | .add( 100 | data=[orgData[3][1:6]], 101 | series_name=orgData[3][0], 102 | color="#3cb371", 103 | label_opts=opts.LabelOpts(is_show=False), 104 | areastyle_opts=opts.AreaStyleOpts(opacity=0.1) 105 | ) 106 | .add( 107 | data=[orgData[4][1:6]], 108 | series_name=orgData[4][0], 109 | color="#ff8c00", 110 | label_opts=opts.LabelOpts(is_show=False), 111 | areastyle_opts=opts.AreaStyleOpts(opacity=0.1) 112 | ) 113 | .render(path=os.path.join(resultPath, resultFileName)) 114 | ) 115 | -------------------------------------------------------------------------------- /15综合评估之雷达图/example15_3/resources/test.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/15综合评估之雷达图/example15_3/resources/test.xlsx -------------------------------------------------------------------------------- /16地理描述之地理坐标图/example16_1/example16_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Geo 3 | import pyecharts.options as opts 4 | from pyecharts.globals import GeoType 5 | 6 | # 地理坐标图表达某人旅游去往某一城市的意向 7 | 8 | # 构造原始数据对(省略读表的过程):10个城市和对应的期望值 9 | 10 | data = [('台湾', '10'), ('西安', '30'), ('重庆', '80'), ('香港', '20'), ('广州', '100'), 11 | ('武汉', '90'), ('长沙', '40'), ('北京', '50'), ('上海', '70'), ('成都', '100')] 12 | 13 | # 绘图需求 14 | # 1. 地图坐标系(schema)为中国地图 15 | # 2. 图例系列名称为空,数据标签隐藏 16 | # 3. 地理坐标图的类型设置为在其上打散点(scatter) 17 | # 4. 加视觉映射 18 | # 5. 保存 19 | # 保存路径 20 | resultPath = "./result" 21 | if not os.path.exists(path=resultPath): 22 | os.mkdir(path=resultPath) 23 | # 保存文件名 24 | resultFileName = "travel_geo.html" 25 | # 执行绘图 26 | geo = ( 27 | Geo() 28 | .set_global_opts(visualmap_opts=opts.VisualMapOpts(is_show=True)) 29 | .add_schema(maptype="china") 30 | .add( 31 | series_name="", 32 | data_pair=data, 33 | label_opts=opts.LabelOpts(is_show=False), 34 | type_=GeoType.SCATTER # 或者直接"scatter" 35 | ) 36 | .render(path=os.path.join(resultPath, resultFileName)) 37 | ) 38 | -------------------------------------------------------------------------------- /16地理描述之地理坐标图/example16_2/example16_2.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Geo, Timeline 3 | import pyecharts.options as opts 4 | import openpyxl 5 | from openpyxl.worksheet.worksheet import Worksheet 6 | from openpyxl.workbook.workbook import Workbook 7 | from pyecharts.globals import GeoType 8 | 9 | # 使用地理坐标图+轮播图,描绘今年来全国气温的变化 10 | 11 | # 配置文件 12 | # 资源文件目录 13 | resourcesPath = "./resources" 14 | # 近年来的温度文件 15 | temperatureBookName = "全国十年年平均温度.xlsx" 16 | # 年平均气温工作表 17 | temperatureSheetName = "年平均气温" 18 | 19 | # 打开文件,选表 20 | temperatureSheet = openpyxl.load_workbook( 21 | filename=os.path.join(resourcesPath, temperatureBookName) 22 | )[temperatureSheetName] # type: Worksheet 23 | 24 | # 取出所有的原始数据 25 | orgData = [list(row_item) for row_item in temperatureSheet.iter_cols(values_only=True)] 26 | # print(orgData) 27 | 28 | # 清洗取值为None的列 29 | # 去掉末尾附加None值,注意,orgData[:]另外深拷贝一个副本,原列表 30 | for row_item in orgData[:]: 31 | if None in row_item: 32 | orgData.remove(row_item) 33 | # print(orgData) 34 | 35 | # 第一行的列表,去掉”城市”这个字,多余 36 | orgData[0] = orgData[0][1:] 37 | # print(orgData) 38 | 39 | 40 | # 组装可视化需要的数据 41 | def get_data(col_num) -> tuple: 42 | """ 43 | 用于绘制一张轮播图需要的数据(第i列,i始于1) 44 | :param col_num: 45 | :return: (年份,[绘图所需数据对]) 46 | """ 47 | # 从原始数据中,提取年份和各个城市需要的数据 48 | year_, city_data = orgData[col_num][0], orgData[col_num][1:] 49 | # 组装城市-数据对 50 | data_pair = zip(orgData[0], city_data) 51 | # 返回(年份,[绘图所需数据对]) 52 | return year_, list(data_pair) 53 | 54 | 55 | # 地理坐标图绘图需求 56 | # 1. 地图坐标类型选择中国地图,用热力图方式体现温度 57 | # 2. 图例为空 58 | # 3. 设置视觉配置项,但隐藏,最大映射值为25,分段型映射(怎么设置可以查查官方文档) 59 | # 4. 轮播节点名为“xxx年” 60 | # 5. 每个图的名字设置为“xxx年全国主要城市平均温度” 61 | # 6. 保存 62 | # 保存路径 63 | resultPath = "./result" 64 | if not os.path.exists(path=resultPath): 65 | os.mkdir(path=resultPath) 66 | # 保存文件名 67 | resultFileName = "TEMP_geo_timeline.html" 68 | # 执行绘图 69 | # 轮播图框架 70 | timeline = Timeline() 71 | # 一个个往里加轮播图 72 | for colNum in range(1, len(orgData)): 73 | year, dataPair = get_data(col_num=colNum) 74 | # print(year, dataPair) 75 | # 添加新的地理坐标图 76 | timeline.add( 77 | time_point=f"{year}年", 78 | chart=( 79 | Geo() 80 | .set_global_opts( 81 | title_opts=opts.TitleOpts(title=f"{year}年全国主要城市平均温度"), 82 | visualmap_opts=opts.VisualMapOpts( 83 | is_show=False, 84 | max_=25, 85 | is_piecewise=True 86 | ) 87 | ) 88 | .add_schema(maptype="china") 89 | .add( 90 | series_name="", 91 | type_=GeoType.HEATMAP, 92 | data_pair=dataPair, 93 | ) 94 | ) 95 | ) 96 | # 执行保存 97 | timeline.render(path=os.path.join(resultPath, resultFileName)) -------------------------------------------------------------------------------- /16地理描述之地理坐标图/example16_2/resources/全国十年年平均温度.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/16地理描述之地理坐标图/example16_2/resources/全国十年年平均温度.xlsx -------------------------------------------------------------------------------- /16地理描述之地理坐标图/example16_3/example16_3.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Geo 3 | from pyecharts.globals import GeoType, ThemeType 4 | import pyecharts.options as opts 5 | import openpyxl 6 | from openpyxl.worksheet.worksheet import Worksheet 7 | from openpyxl.workbook.workbook import Workbook 8 | 9 | # 用地理坐标图,描述成都一家网店寄往其他地区商品的邮费情况 10 | 11 | # 资源文件 12 | resourcesPath = "./resources" 13 | # 全国运输文件 14 | transBookName = "全国运输.xlsx" 15 | # 全国邮费工作表 16 | transSheetName = "全国邮费" 17 | # 开文件、选表 18 | transBook = openpyxl.load_workbook(filename=os.path.join(resourcesPath, transBookName)) # type: Workbook 19 | transSheet = transBook[transSheetName] # type: Worksheet 20 | 21 | # 读取所有原始数据(跳过表头) 22 | # 列含义:[起点, 终点, 邮费] 23 | orgData = [list(row_item) for row_item in transSheet.iter_cols(min_row=2, min_col=1, values_only=True)] 24 | # print(orgData) 25 | 26 | # 清洗数据None,[:]深拷贝,防止下标错位 27 | for rowItem in orgData[:]: 28 | for cellItem in rowItem[:]: 29 | if cellItem is None: 30 | rowItem.remove(cellItem) 31 | if len(rowItem) == 0: 32 | orgData.remove(rowItem) 33 | # print(orgData) 34 | 35 | # 按照[起点, 终点]的方式添加两地的边;按照[终点, 到终点的邮费]这种方式构造目的地的带权节点 36 | # 边数据对的构造 37 | routeList = zip(orgData[0], orgData[1]) 38 | # 带权节点的构造 39 | postageList = zip(orgData[1], orgData[2]) 40 | 41 | # 绘制地理坐标图的需求 42 | # 1. 坐标类型是中国地图 43 | # 2. 同时添加带权节点和边两类坐标图要素,带权节点为动态散点样式,边为流向样式(类型设置可以参照文档) 44 | # 3. 图例系列均设为空,隐藏数据标签 45 | # 4. 图的主题为dark 46 | # 5. 添加最大映射为10,最小映射为4 47 | # 6. 保存 48 | # 保存路径 49 | resultPath = "./result" 50 | if not os.path.exists(path=resultPath): 51 | os.mkdir(path=resultPath) 52 | # 保存文件名 53 | resultFileName = "postage_geo.html" 54 | # 执行绘图 55 | geo = ( 56 | Geo(init_opts=opts.InitOpts(theme=ThemeType.DARK)) 57 | .set_global_opts(visualmap_opts=opts.VisualMapOpts(min_=4, max_=10)) 58 | .add_schema(maptype="china") 59 | .add( 60 | series_name="", 61 | data_pair=postageList, 62 | type_=GeoType.EFFECT_SCATTER, 63 | label_opts=opts.LabelOpts(is_show=False) 64 | ) 65 | .add( 66 | series_name="", 67 | data_pair=routeList, 68 | type_=GeoType.LINES, 69 | label_opts=opts.LabelOpts(is_show=False) 70 | ) 71 | .render(path=os.path.join(resultPath, resultFileName)) 72 | ) 73 | -------------------------------------------------------------------------------- /16地理描述之地理坐标图/example16_3/resources/全国运输.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/16地理描述之地理坐标图/example16_3/resources/全国运输.xlsx -------------------------------------------------------------------------------- /16地理描述之地理坐标图/example16_4/example16_4.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Geo 3 | from pyecharts.globals import GeoType 4 | import pyecharts.options as opts 5 | 6 | # 使用地理坐标图,表达自己一年来的出差情况 7 | 8 | # 准备原始数据,省略读取文档的过程 9 | # 出差去往各点的次数:带权节点(地点, 出差次数) 10 | businessTimes = [("北京", 50), ("广州", 30), ("成都", 40), ("哈尔滨", 10)] 11 | # 每次出差的路线图:边(起点, 终点) 12 | businessFlow = [("上海", "广州"), ("上海", "哈尔滨"), ("上海", "北京"), ("上海", "成都"), ("北京", "成都"), ("哈尔滨", "广州")] 13 | 14 | # 绘制地理坐标图需求 15 | # 1. 坐标轴设置:选择中国地图 16 | # 2. 带权节点设置:图例系列名为空,设置为动态散点显示,隐藏数据标签 17 | # 3. 边的设置:图例名称为空,设置为流向显示,隐藏数据标签;美化涟漪特效(查文档说明):箭头大小为5,黄色,弯曲度20% 18 | # 4. 视觉映射:最大和最小设置分别为60和10 19 | # 5. 标题为“出差大盘点” 20 | # 6. 保存 21 | # 保存路径 22 | resultPath = "./result" 23 | if not os.path.exists(path=resultPath): 24 | os.mkdir(path=resultPath) 25 | # 保存文件名 26 | resultFileName = "on_business_geo.html" 27 | # 执行绘图 28 | geo = ( 29 | Geo() 30 | .set_global_opts( 31 | title_opts=opts.TitleOpts(title="出差大盘点"), 32 | visualmap_opts=opts.VisualMapOpts(max_=60, min_=10) 33 | ) 34 | .add_schema(maptype="china") 35 | .add( 36 | # 带权节点 37 | series_name="", 38 | type_=GeoType.EFFECT_SCATTER, 39 | data_pair=businessTimes, 40 | label_opts=opts.LabelOpts(is_show=False) 41 | ) 42 | .add( 43 | # 边 44 | series_name="", 45 | type_=GeoType.LINES, 46 | data_pair=businessFlow, 47 | effect_opts=opts.EffectOpts( 48 | symbol="arrow", 49 | symbol_size=5, 50 | color="yellow" 51 | ), 52 | linestyle_opts=opts.LineStyleOpts( 53 | curve=0.2 54 | ), 55 | label_opts=opts.LabelOpts(is_show=False) 56 | ) 57 | .render(path=os.path.join(resultPath, resultFileName)) 58 | ) 59 | -------------------------------------------------------------------------------- /16地理描述之地理坐标图/example16_5/example16_5.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Geo 3 | import pyecharts.options as opts 4 | from pyecharts.globals import GeoType 5 | import openpyxl 6 | from openpyxl.workbook.workbook import Workbook 7 | from openpyxl.worksheet.worksheet import Worksheet 8 | 9 | # 使用地理坐标图,表达某产品在全国范围的用户分布 10 | 11 | # 资源文件夹 12 | resourcesPath = "./resources" 13 | # 用户分布文件 14 | userBookName = "用户分布.xlsx" 15 | # 用户分布工作表 16 | userSheetName = "用户数量" 17 | 18 | # 打开文件并选表 19 | userSheet = openpyxl.load_workbook( 20 | filename=os.path.join(resourcesPath, userBookName))[userSheetName] # type: Worksheet 21 | # 取出数据对 22 | num_list = [row_item for row_item in userSheet.iter_rows(min_row=2, values_only=True)] 23 | print(num_list) 24 | 25 | # 绘制地理坐标图需求 26 | # 1. 添加但隐藏视觉映射,最大映射1000,过渡颜色设置为['#33bbff','#0015ff','#2600e5','#8a2ee5','#cc2996'] 27 | # 2. 全图背景颜色为#475262 28 | # 3. 坐标系设置:中国地图,地图底色为#2d3948,描边为#2efef7;鼠标选中高亮情况下,颜色为#2a333d 29 | # 4. 设置散点样式表达单一地点的用户分布情况,设置热力图表达单一地点及附近地区的用户分布情况,均隐藏数据标签,图例系列名不用填 30 | # 5. 图的标题:会员分布 31 | # 6. 保存 32 | # 保存路径 33 | resultPath = "./result" 34 | if not os.path.exists(path=resultPath): 35 | os.mkdir(path=resultPath) 36 | # 保存文件名 37 | resultFileName = "user_geo.html" 38 | # 执行地理坐标图绘制 39 | geo = ( 40 | Geo(init_opts=opts.InitOpts(bg_color="#475262")) 41 | .set_global_opts( 42 | title_opts=opts.TitleOpts(title="会员分布"), 43 | visualmap_opts=opts.VisualMapOpts( 44 | is_show=False, 45 | max_=1000, 46 | range_color=["#33bbff", "#0015ff", "#2600e5", "#8a2ee5", "#cc2996"] 47 | ) 48 | ) 49 | .add_schema( 50 | maptype="china", 51 | itemstyle_opts=opts.ItemStyleOpts(color="#2d3948", border_color="#2efef7"), 52 | emphasis_itemstyle_opts=opts.ItemStyleOpts(color="#2a333d") 53 | ) 54 | .add( 55 | # 单区域散点表达 56 | series_name="", 57 | data_pair=num_list, 58 | type_=GeoType.SCATTER, 59 | label_opts=opts.LabelOpts(is_show=False) 60 | ) 61 | .add( 62 | # 区域热力图表达 63 | series_name="", 64 | data_pair=num_list, 65 | type_=GeoType.HEATMAP, 66 | label_opts=opts.LabelOpts(is_show=False) 67 | ) 68 | .render(path=os.path.join(resultPath, resultFileName)) 69 | ) 70 | -------------------------------------------------------------------------------- /16地理描述之地理坐标图/example16_5/resources/用户分布.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/16地理描述之地理坐标图/example16_5/resources/用户分布.xlsx -------------------------------------------------------------------------------- /17多对多映射联系之关系图/example17_1/example17_1.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyecharts.charts import Graph 3 | import pyecharts.options as opts 4 | from pyecharts.commons.utils import JsCode 5 | import openpyxl 6 | from openpyxl.workbook.workbook import Workbook 7 | from openpyxl.worksheet.worksheet import Worksheet 8 | 9 | # 使用关系图,可视化Python知识点关联图谱 10 | 11 | # 资源文件夹 12 | resourcesPath = "./resources" 13 | # 知识点文件 14 | knowledgeBookName = "知识点.xlsx" 15 | # 存储边的父子节点所在工作表 16 | linkSheetName = "知识点的关系" 17 | # 存储各个知识点带权节点的(节点名, 权重)关系 18 | nodeSheetName = "数量统计" 19 | 20 | # 打开文件 21 | knowledgeBook = openpyxl.load_workbook(filename=os.path.join(resourcesPath, knowledgeBookName)) # type: Workbook 22 | # 边工作表 23 | linkSheet = knowledgeBook[linkSheetName] # type: Worksheet 24 | # 节点工作表 25 | nodeSheet = knowledgeBook[nodeSheetName] # type: Worksheet 26 | 27 | # 读取表格清洗后的数据(通常这个表格数据是清洗后的,得到这个表格前可能需要清洗自然语言) 28 | # (知识点, 知识点)组成的边 29 | orgLinkList = [rowItem for rowItem in linkSheet.iter_rows(min_row=2, values_only=True)] 30 | # (知识点, 权重)组成的节点 31 | orgNodeList = [rowItem for rowItem in nodeSheet.iter_rows(min_row=2, values_only=True)] 32 | print(orgLinkList) 33 | print(orgNodeList) 34 | 35 | # 按[{"source": xxx, "target": xxx}, ...]格式组合边的数据 36 | # 原始数据转化为指定格式方法 37 | linkList = [opts.GraphLink(source=linkItem[0], target=linkItem[1]) for linkItem in orgLinkList] 38 | # 按[{"id":"Python", "name":"Python ", "symbolSize":24}]格式组合节点数据,且假设id就是节点名(这里没有重名) 39 | # 注意:这里节点的id是自定义添加的字段,用作唯一标识 40 | # nodeList = [opts.GraphNode(id=nodeItem[0], name=nodeItem[0], symbol_size=nodeItem[1]) for nodeItem in orgNodeList] 41 | nodeList = [{"id": nodeItem[0], "name": nodeItem[0], "symbolSize": nodeItem[1]} for nodeItem in orgNodeList] 42 | 43 | # 绘制关系图需求: 44 | # 1. 设置图表的图例系列名称为空; 45 | # 2. 整体呈圆形布局,数据标签可依照节点实际情况进行旋转调整 46 | # 3. 用给定的js代码设置边为渐变色(怎么设置可以查文档) 47 | # 4. 边的弯曲度设为0.3,宽度设为1.5; 48 | # 5. 节点的颜色"#474747"; 49 | # 6. 标题设置为:Python知识图谱; 50 | # 7. 保存图表 51 | # 保存路径 52 | resultPath = "./result" 53 | if not os.path.exists(path=resultPath): 54 | os.mkdir(path=resultPath) 55 | # 保存文件名 56 | resultFileName = "pythonKG_graph.html" 57 | 58 | # 用于控制边渐变颜色的js代码(具体参数含义官方文档中有给出说明) 59 | line_color_js = """ 60 | new echarts.graphic.LinearGradient( 61 | 0,0,0,1, 62 | [{offset: 0, 63 | color: '#2e9afe'}, 64 | { 65 | offset: 0.3, 66 | color: '#01a9db'}, 67 | { 68 | offset: 0.6, 69 | color: '#f5bca9'}, 70 | { 71 | offset: 1, 72 | color: '#b40404'}] 73 | ) 74 | """ 75 | 76 | # 执行绘图 77 | knowledgeGraph = ( 78 | Graph() 79 | .set_global_opts(title_opts=opts.TitleOpts(title="Python知识图谱")) 80 | .add( 81 | series_name="", 82 | links=linkList, 83 | nodes=nodeList, 84 | layout="circular", 85 | is_rotate_label=True, 86 | linestyle_opts=opts.LineStyleOpts( 87 | color=JsCode(js_code=line_color_js), 88 | curve=0.3, 89 | width=1.5 90 | ), 91 | itemstyle_opts=opts.ItemStyleOpts(color="#474747") 92 | ) 93 | .render(path=os.path.join(resultPath, resultFileName)) 94 | ) 95 | -------------------------------------------------------------------------------- /17多对多映射联系之关系图/example17_1/resources/知识点.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cutelittletiantian/python-data-visualization/360c5e967be007891792e1627910959d561e1207/17多对多映射联系之关系图/example17_1/resources/知识点.xlsx -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Michael Du 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 前排提示 2 | 3 | 内容有在续建设中,请持续关注,爱你们哟ღ( ´・ᴗ・` )。 4 | 5 | # 简介 6 | 7 | 近期工作压力巨大,常年在地铁上刷着干瘪的短视频和段子,我看到了**世界的参差**\_(:з」∠)\_,对于美的追求的精神世界无比枯竭。直到有一天,我看到了,在一些学术论文中,出现了许多美丽的图片(如反映多维数据分布及相关性的**散点图和气泡图**、表现流量分布的**桑基图**等),这些图片的美感在于,它们将冰冷的数据用生动的图像演绎出来,无比炫酷,给人以无限的遐想和学习的兴趣。 8 | 9 | 想想马上就要读研究生的我,也许多年后需要自己生成~~美丽的~~图像,为了多年后别把自己~~精心研究的数据~~(当然也可能是脚踩的数据)绘图成跟shi一样,更重要的是**为了在感受世界的参差时静下心来,享受学术的美丽、数据的美丽**,我决定入坑学习Python数据可视化,并把学习成果与大家交流共享。 10 | 11 | 持续建设中,大家可以关注,平日里要打工,不定期更新(提前为自己的咕咕咕找好借口) 12 | 13 | # 配置要求 14 | 15 | > OS: ``Windows 10``或者``MacOS``均可(注意:``Windows 10``或者``MacOS``仅在某些方面,比如文件路径的表示上可能略有不同) 16 | > 17 | > Python版本: 本项目采用``3.9.x 64-bit``版本(截至2021年4月26日查询Python官网``https://www.python.org``,Python最新版本为3.9.x) 18 | > 19 | > 推荐的编辑器:``Pycharm``或``Jupyter``,看你喜好啦~推荐使用虚拟环境(venv),在为本项目进行必要的第三方库配置时,不影响其它Python项目的配置,不污染系统Python的环境。 20 | 21 | # 需要用到的Python库 22 | 23 | ``pyecharts``:本项目**最主要的**第三方库之一,打开cmd(或其它操作系统的终端),使用``pip install pyecharts``进行安装。 24 | 25 | > 用途:将数据进行可视化,生成各种可交互式的图表。 26 | > 27 | > 导入方式:直接采用``import pyecharts``导入有其不足点,通常我们这样导入pyecharts包 28 | 29 | ```python 30 | # 导入options模块并简写为opts 31 | import pyecharts.options as opts 32 | # 从pyecharts.charts中导入“某一特定类型图”(some-package)模块 33 | from pyecharts.charts import 34 | ``` 35 | 36 | 其中上述````,根据需要绘制的图形类型进行特别指定,画柱状图就换成``Bar``,画线状图就指定``Line``,画桑基图就指定``Sankey``等。 37 | 38 | 举例:假如要绘制柱状图(Bar chart),就这样导入``pyecharts``库 39 | 40 | ```python 41 | # 导入options模块并简写为opts 42 | import pyecharts.options as opts 43 | # 从pyecharts.charts中导入 Bar 模块 44 | from pyecharts.charts import Bar 45 | ``` 46 | 47 | *** 48 | 49 | ``openpyxl``:第三方库,打开cmd(或其它操作系统的终端),使用``pip install openpyxl``进行安装。 50 | 51 | > 用途:对excel表格进行读写操作。 52 | > 53 | > 导入方式:原则上采用``import openpyxl``便足以满足开发需要,但是为了尽可能发挥代码提示的功能,推荐如下方式导入 54 | 55 | ```python 56 | import openpyxl # 最主要的导入 57 | from openpyxl.utils import cell 58 | from openpyxl import Workbook # 这个导入和type注释会共同起作用 59 | from openpyxl.worksheet.worksheet import Worksheet # 这个导入和type注释会共同起作用 60 | ``` 61 | 62 | 另注:为了显示代码提示,建议在对工作簿、工作表变量赋值后,用注释在同一行指明类型(格式:``# type: 类型名``),例如 63 | 64 | ```python 65 | import openpyxl # 最主要的导入 66 | from openpyxl.utils import cell 67 | from openpyxl import Workbook # 这个导入和type注释会共同起作用 68 | from openpyxl.worksheet.worksheet import Worksheet # 这个导入和type注释会共同起作用 69 | 70 | workBook = openpyxl.load_workbook(filename=recordPath) # type: Workbook 71 | workSheet = photoParamBook["示例"] # type: Worksheet 72 | ``` 73 | 74 | *** 75 | 76 | ### 安装第三方包出错的解决方法 77 | 78 | 有时安装失败是因为国内网络有一些限制,这时您可以尝试使用清华大学镜像下载相应的包,即``pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package``,其中``some-package``换成自己所需要安装的第三方库名。 79 | 80 | > 注意:使用镜像前请确保自己的pip处于较新版本(>=10.0.0) 81 | > 82 | > 更新pip使用命令:``python -m pip install --upgrade pip`` 83 | 84 | *** 85 | 86 | # 请注意 87 | 88 | * 当您在运行Python的样例时,请预先安装好所需的第三方库依赖,**并关闭resources目录中所涉及的文件**(如果有),以免因为文件占用导致程序不能处理打开着的文件。 89 | * 使用库的时候,不要死记硬背,常见的思路记住即可,细节的东西可以随机应变或者查官方文档进行处理。 90 | * 导入第三方库时,部分第三方库(例如``openpyxl``)的类单独导入进来,结合形如``# type: ...``格式的注释,有利于充分利用好编辑器的代码填充提示,使第三方库的封装更有意义。 91 | 92 | # 快捷传送门 93 | 94 | 本项目中,所涉及库等内容的文档链接如下。 95 | 96 | ``Python``官网及其官方文档 97 | 98 | > 官网:https://www.python.org 99 | > 100 | > 文档:https://docs.python.org/3/ 101 | 102 | 本项目**最主要的**第三方库之一``pyecharts``官方文档 103 | 104 | > https://pyecharts.org/ 105 | 106 | ``openpyxl``第三方库官方文档 107 | 108 | > https://openpyxl.readthedocs.io/en/stable/index.html 109 | 110 | 清华大学开源软件镜像站(当第三方库无法直接下载时,可以考虑镜像站) 111 | 112 | > 网址:[清华大学开源软件镜像站 | Tsinghua Open Source Mirror](https://mirrors.tuna.tsinghua.edu.cn/) 113 | > 114 | > 使用镜像安装第三方库格式:``pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package`` 115 | > 116 | > (请将上述``some-package``换成自己需要的第三方库名,例如``pyecharts``) 117 | > 118 | > 注意:使用镜像前请确保自己的pip处于较新版本(>=10.0.0) 119 | > 120 | > 更新pip使用命令:``python -m pip install --upgrade pip`` 121 | 122 | # 小添添的其它Python坑 123 | 124 | **Python自动化办公**:使用``os`` ``openpyxl`` ``python-docx`` ``pdfplumber``等第三方库批量分类文件、批量读写Excel文档、批量读写Word文档、批量获取文字类Pdf文档、基于SMTP和MIME协议的邮件批量发送内容等,通过一些典型的应用场景,大幅提升职场办公室工作效率。 125 | 126 | > 传送门:https://github.com/cutelittletiantian/python-for-office 127 | -------------------------------------------------------------------------------- /综合应用:制作可视化大屏/可视化大屏demo/result/config/page_screen_config.json: -------------------------------------------------------------------------------- 1 | [{"cid":"77d3dfacc1ac4d2ebcb0072684a646f7","width":"787px","height":"408px","top":"41px","left":"8px"},{"cid":"61396965445041279331cfabc8eb57e8","width":"907px","height":"500px","top":"449px","left":"8px"},{"cid":"8942f571ea0d46c5a6579c46051d492f","width":"536px","height":"408px","top":"41px","left":"795px"},{"cid":"b21b2e3c5d89498db499337ec9935f22","width":"906px","height":"501px","top":"949px","left":"8px"},{"cid":"7ecdd15281234448ae4106fc5675d2d8","width":"683px","height":"408px","top":"41px","left":"1330px"},{"cid":"74c9da272ad441139c9f7c31f56ed405","width":"414px","height":"500px","top":"449px","left":"915px"},{"cid":"996ff074453249b8b1ee89d126cfd1d1","width":"684px","height":"500px","top":"449px","left":"1329px"},{"cid":"8b235cbdbe5743589ce70b765226c52d","width":"1099px","height":"501px","top":"949px","left":"914px"}] --------------------------------------------------------------------------------