pyecharts的Tab和Legend布局详情
导言:
读者朋友有时候是不是和我有一样的困惑,用惯了matplotlib
和seaborn
绘制各种各样的小图供自己观察的时候还算得心应手,但是一旦到了要持续的大批量绘制一些图表供非数据分析人员长久观察的时候又觉得吃力,那么有没有一款第三方python模块能够帮我们解决这种困惑呢?答案是肯定的,这就要推荐我们今天的主角——pyecharts。
pyecharts
是百度开源的一款第三方绘图模块,结合的python语言的简易性和Echarts的强大绘图特性,可以用python对其调用,输出交互性好,精美乖巧且符合审美的图表,而且还可以轻松的集成到Flask,Django 等主流 Web 框架,方便自己和别人长久可持续观看。
一、布局设计思路
抛开数据谈布局简直有点天荒夜谈,数据长什么样决定了图表的花容月貌,熟稔自己手里的数据才能知自知彼绘制出优美的图表出来,首先看一下我们样例数据长什么样。
上图是我们的数据表,主要包含的字段有id
, flight_date
,cargo_type
,cargo_weight
以及cargo_rate
, 其中id类似身份识别号,数量大约有400个左右,一个id就是一个主体,flight_date是记录id的时间,单位是日期,cargo_type表示主体承载的货物类别主要有"A;B", "C;D;E"和 "M"三大类,而cargo_weight和cargo_rate分别表示货物的重量和价格,这种类型的数据是不是像极了我们平时遇到的 各个门店里各类商品每天的销售数据。
知道了数据长什么样子后,我们就可以在草稿纸上画一画,比如我希望把cargo_weight和cargo_rate两者随着时间的变化而展现出的优美走位绘制出来,自然而然,flight_date就作为时间线索横梗在下面,cargo_weight和cargo_rate画在横坐标之上的两位舞者,为了区分,可以用柱状图绘制cargo_weight, 用曲线绘制cargo_rate,犹如蛟龙在群峰之间蜿蜒向前,为了区分刻画cargo_weight和cargo_rate两者之间不同数量级,我还需要引入主纵坐标和副纵坐标,用主坐标刻画cargo_weight的度量,用副坐标刻画cargo_rate的度量,有了这些基本要素之后,接下来问题的关键是怎么把id和cargo_type各放恰当的位置?这的确需要动些脑子,考虑到id和cargo_type两者的数量,可以把cargo_type作为Tab标签,而id作为Legend图例,可以让观察者每选定一个主体就能看到这个主体不同cargo_type的历史上cargo_weight和cargo_rate走势情况,而且还可以赋予每一个cargo_type一个主体配置。
二、操作实践
有了蓝图便胸有成竹,下面便是撰写代码实现的时候了
import pandas as pd import pymysql import pyecharts from pyecharts import options as opts from pyecharts.charts import Bar, Grid, Line, Tab from pyecharts.globals import ThemeType con = pymysql.Connect(host='000.00.0.00', user ='***', passwd='******', database='***') r_sql = "select id, cargo_type, flight_date, cargo_weight, cargo_rate from adm.adm_ifs_rate_order_price order by flight_date asc, voyage desc" #航班订单数据 f_sql = "select concat(flight_no, '-', orac_3airport, '-', dstc_3airport) as id from ods.dm_flt_info where flight_date = date_sub(curdate(), INTERVAL -1 day) order by id asc" #次日航班计划 raw_data = pd.read_sql(con = con, sql = r_sql) #读取运单原数据 flight_id = pd.read_sql(con = con, sql = f_sql )['id'] #读取航班计划 con.close() #关闭链接 flight_cargo = raw_data.query("id == @flight_id[0]") #筛选具体航班 cargo_type = ['A;B', 'C;D;E', 'M'] cargo_ab = flight_cargo.query("cargo_type == @cargo_type[0] ")[["flight_date", "cargo_weight", "cargo_rate"]] #筛选某个货物类别 cargo_cde = flight_cargo.query("cargo_type == @cargo_type[1] ")[["flight_date", "cargo_weight", "cargo_rate"]] #筛选某个货物类别 cargo_m = flight_cargo.query("cargo_type == @cargo_type[2] ")[["flight_date", "cargo_weight", "cargo_rate"]] #筛选某个货物类别 def ab_() -> Grid: bar = ( Bar() .add_xaxis(cargo_ab.flight_date.values.tolist()) .add_yaxis("运量", cargo_ab.cargo_weight.values.tolist(), yaxis_index=0) .set_series_opts( itemstyle_opts=opts.ItemStyleOpts( opacity=0.5, ) ) .extend_axis( yaxis=opts.AxisOpts( type_="value", name="运价", position="right", axisline_opts=opts.AxisLineOpts( linestyle_opts=opts.LineStyleOpts(color="#675bba") ), splitline_opts=opts.SplitLineOpts( is_show=True, linestyle_opts=opts.LineStyleOpts(opacity=0.5) ), ) ) .set_global_opts( title_opts = opts.TitleOpts(title = flight_id[0]), yaxis_opts=opts.AxisOpts(name="运量"), datazoom_opts = opts.DataZoomOpts(), ) ) line = ( Line() .add_xaxis(cargo_ab.flight_date.values.tolist()) .add_yaxis("运价", cargo_ab.cargo_rate.values.tolist(),yaxis_index=1 ) ) bar.overlap(line) return Grid().add( bar, opts.GridOpts(pos_left="5%", pos_right="20%"), is_control_axis_index=True ) def cde_() -> Grid: bar = ( Bar() .add_xaxis(cargo_cde.flight_date.values.tolist()) .add_yaxis("运量", cargo_cde.cargo_weight.values.tolist(), yaxis_index=0) .set_series_opts( itemstyle_opts=opts.ItemStyleOpts( opacity=0.5, ) ) .extend_axis( yaxis=opts.AxisOpts( type_="value", name="运价", position="right", axisline_opts=opts.AxisLineOpts( linestyle_opts=opts.LineStyleOpts(color="#675bba") ), splitline_opts=opts.SplitLineOpts( is_show=True, linestyle_opts=opts.LineStyleOpts(opacity=0.5) ), ) ) .set_global_opts( title_opts=opts.TitleOpts(title=flight_id[0]), yaxis_opts=opts.AxisOpts(name="运量"), datazoom_opts=opts.DataZoomOpts(), ) ) line = ( Line() .add_xaxis(cargo_cde.flight_date.values.tolist()) .add_yaxis("运价", cargo_cde.cargo_rate.values.tolist(),yaxis_index=1 ) ) bar.overlap(line) return Grid().add( bar, opts.GridOpts(pos_left="5%", pos_right="20%"), is_control_axis_index=True ) def m_() -> Grid: bar = ( Bar() .add_xaxis(cargo_m.flight_date.values.tolist()) .add_yaxis("运量", cargo_m.cargo_weight.values.tolist(), yaxis_index=0) .set_series_opts( itemstyle_opts=opts.ItemStyleOpts( opacity=0.5, ) ) .extend_axis( yaxis=opts.AxisOpts( type_="value", name="运价", position="right", axisline_opts=opts.AxisLineOpts( linestyle_opts=opts.LineStyleOpts(color="#675bba") ), splitline_opts=opts.SplitLineOpts( is_show=True, linestyle_opts=opts.LineStyleOpts(opacity=0.5) ), ) ) .set_global_opts( title_opts=opts.TitleOpts(title=flight_id[6]), yaxis_opts=opts.AxisOpts(name="运量"), datazoom_opts=opts.DataZoomOpts(), ) ) line = ( Line() .add_xaxis(cargo_m.flight_date.values.tolist()) .add_yaxis("运价", cargo_m.cargo_rate.values.tolist(),yaxis_index=1 ) ) bar.overlap(line) return Grid().add( bar, opts.GridOpts(pos_left="5%", pos_right="20%"), is_control_axis_index=True ) tab = Tab() tab.add(ab_(), "A;B") tab.add(cde_(), "C;D;E") tab.add(m_(), "M") tab.render_notebook()
下面结合效果图对代码做一下简单的解析,整个代码可以分3大块,第一块是连接数据库读取原数据并将数据一分为三,每一份数据为一个独立的货物类别;第二块是各用一个函数实现某类别货物cargo_weight和cargo_rate展示,而每一个函数作为Tab的参数进行调用,这样,每一个类别形成一个Tab,每一个Tab下面刚好有这个id的历史cargo_weight和cargo_rate走势情况,这样做样做的好处,用Tab就可以划分了cargo_type中"A;B", "C;D;E"和 "M"三个类别;最后调用render_notebook函数把所有Tab渲染出来。
结论:
效果图可以看到如果只要画一个id的各类货物的cargo_weight和cargo_rate走势的话,效果还是不错的,然而我们的id数目高达400个,上述方法很难奏效,我们希望让id去替换上图的运量和运价两个图例,形成id簇的图例,最好还可以对图例进行选择或者翻页
栏 目:Python代码
本文地址:http://www.codeinn.net/misctech/215929.html