介绍瀑布图是一种非常有用的工具,用于绘制某些类型的数据。毫不奇怪,我们可以使用Pandas和matplotlib创建可重复的瀑布图。在继续之前,我想告诉你我指的是什么类型的图表。我将按照维基百科文章中的描述构建一个2D瀑布图。此类图表的典型用途是显示+和-值,它们充当起始值和结束值之间的“桥梁”。因此,财务人员有时将其称为桥梁。和我之前做过的其他例子类似,这种图在Excel中是不容易生成的,当然肯定有生成的方法,但是不太好记。关于瀑布图要记住的关键是,它本质上是一个相互堆叠的条形图,但以一种特殊的方式,它有一个空白的底部条,因此顶部条“漂浮”在空中。那么,让我们开始吧。创建图形首先,执行标准输入并确保IPython可以显示matplot图形。importnumpyasnpimportpandasaspdimportmatplotlib.pyplotasplt%matplotlibinline设置我们要绘制瀑布图的数据,加载到数据框(DataFrame)中。数据需要从您的起始值开始,但您需要给出最终总计。我们将在下面进行计算。index=['sales','returns','creditfees','rebates','latecharges','shipping']data={'amount':[350000,-30000,-7500,-25000,95000,-7000]}trans=pd.DataFrame(data=data,index=index)我使用IPython中方便的显示功能来更轻松地控制我想要显示的内容。fromIPython.displayimportdisplaydisplay(trans)瀑布图的技巧是弄清楚底部堆积条是什么。我从关于stackoverflow的讨论中学到了很多这方面的知识。首先,我们得到累计和。display(trans.amount.cumsum())sales350000returns320000creditfees312500rebates287500latecharges382500shipping375500Name:amount,dtype:int64这看起来不错,但我们需要将一个地方的数据向右移动。blank=trans.amount.cumsum().shift(1).fillna(0)display(blank)sales0returns350000creditfees320000rebates312500latecharges287500shipping382500Name:amount,dtype:float64我们需要向trans和blank数据帧添加一个净总数。total=trans.sum().amounttrans.loc["net"]=totalblank.loc["net"]=totaldisplay(trans)display(blank)sales0returns350000creditfees320000rebates312500latecharges287500shipping382500net375500Name:amount,dtype:float64由我们的步骤创建。step=blank.reset_index(drop=True).repeat(3).shift(-1)step[1::3]=np.nandisplay(step)000NaN035000013500001NaN132000023200002NaN231250033125003NaN328750042875004NaN438250053825005NaN537550063755006NaN6NaNName:amount,dtype:float64对于“net”行,为了不要使堆栈加倍,我们需要确保空白值为0。blank.loc["net"]=0然后,绘制它,看看它是什么样子。my_plot=trans.plot(kind='bar',stacked=True,bottom=blank,legend=None,title="2014SalesWaterfall")my_plot.plot(step.index,step.values,'k')看起来不错,但让我们尝试格式化Y轴以使其更具可读性。为此,我们使用FuncFormatter和一些Python2.7+语法来截断小数点并在格式中添加逗号。defmoney(x,pos):'Thetwoargsarethevalueandtickposition'return"${:,.0f}".format(x)frommatplotlib.tickerimportFuncFormatterformatter=FuncFormatter(money)然后,放在一起。my_plot=trans.plot(kind='bar',stacked=True,bottom=blank,legend=None,title="2014SalesWaterfall")my_plot.plot(step.index,step.values,'k')my_plot.set_xlabel("TransactionTypes")my_plot.yaxis.set_major_formatter(formatter)#p#fullscript基本图形工作正常,但我想添加一些标签并做一些小的格式更改。下面是我最后的脚本:importnumpyasnpimportpandasaspdimportmatplotlib.pyplotaspltfrommatplotlib.tickerimportFuncFormatter#Usepython2.7+syntaxtoformatcurrencydefmoney(x,pos):'Thetwoargsarethevalueandtickposition'return"${:,.0f}".format(x)formatter=funcDataformatter(.Donotincludeatotal,itwillbecalculatedindex=['sales','returns','creditfees','rebates','latecharges','shipping']data={'amount':[350000,-30000,-7500,-25000,95000,-7000]}#Storedataandcreateablankseriestouseforthewaterfalltrans=pd.DataFrame(data=data,index=index)blank=trans.amount.cumsum().shift(1).fillna(0)#Getthenettotalnumberforthefinalelementinthewaterfalltotal=trans.sum().amounttrans.loc["net"]=totalblank.loc["net"]=total#Thestepsgraphicallyshowthelevelsaswellasusedforlabelplacementstep=blank.reset_index(drop=True).repeat(3).shift(-1)step[1::3]=np.nan#Whenplottingthelastelement,wewanttoshowthefullbar,#Settheblankto0blank.loc["net"]=0#Plotandlabe复制代码lmy_plot=trans.plot(kind='bar',stacked=True,bottom=blank,legend=None,figsize=(10,5),title="2014SalesWaterfall")my_plot.plot(step.index,step.values,'k')my_plot.set_xlabel("TransactionTypes")#Formattheaxisfordollarsmy_plot.yaxis.set_major_formatter(formatter)#Getthey-axispositionforthelabelsy_height=trans.amount.cumsum().shift(1).fillna(0)#Getanoffsetsolabelsdon'tsitrightontopofthebarmax=trans。max()neg_offset=max/25pos_offset=max/50plot_offset=int(max/15)#Startlabellooploop=0forindex,rowintrans.iterrows():#Forthelastiteminthelist,wedon'twanttodoublecountifrow['amount']==total:y=y_height[循环]else:y=y_height[loop]+row['amount']#Determineifwewantanegorposoffsetifrow['amount']>0:y+=pos_offsetelse:y-=neg_offsetmy_plot.annotate("{:,.0f}".format(row['数量']),(loop,y),ha="center")loop+=1#Scaleuptheyaxissothereisroomforthelabelsmy_plot.set_ylim(0,blank.max()+int(plot_offset))#Rotatethelabelsmy_plot.set_xticklabels(trans.index,rotation=0)my_plot.get_figure().savefig("waterfall.png",dpi=200,bbox_inches='tight')运行这个脚本将生成下面这个漂亮的图表:***Ideas如果你以前不熟悉瀑布图,希望这个例子能告诉你它到底有多有用。我想有些人可能会觉得一张图表需要这么多脚本代码有点不好。在某些方面,我同意这种想法。如果你只是想做一个瀑布图,不会再去碰它,那你还是继续用Excel中的方法吧。但是,如果瀑布图真的很有用并且您需要将它复制给100个客户怎么办?你接下来要做什么?此时使用Excel将是一个挑战,使用本文中的脚本创建100个不同的工作表将相当容易。同样,该程序的真正价值在于它允许您在需要扩展解决方案时创建易于重现的程序。我真的很喜欢学习更多关于Pandas、matplotlib和Ipothon的知识。很高兴这种方法对您有所帮助,并希望其他人可以从中学习并将这一课应用到他们的日常工作中。
