利用Python绘制数据的瀑布图的教程_python

介绍

对于绘制某些类型的数据来说,瀑布图是一种十分有用的工具。不足为奇的是,我们可以使用Pandas和matplotlib创建一个可重复的瀑布图。

在往下进行之前,我想先告诉大家我指代的是哪种类型的图表。我将建立一个维基百科文章中描述的2D瀑布图。

这种图表的一个典型的用处是显示开始值和结束值之间起“桥梁”作用的+和-的值。因为这个原因,财务人员有时会将其称为一个桥梁。跟我之前所采用的其他例子相似,这种类型的绘图在Excel中不容易生成,当然肯定有生成它的方法,但是不容易记住。

关于瀑布图需要记住的关键点是:它本质上是一个堆叠在一起的条形图,不过特殊的一点是,它有一个空白底栏,所以顶部栏会“悬浮”在空中。那么,让我们开始吧。
创建图表

首先,执行标准的输入,并确保IPython能显示matplot图。
 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

%matplotlib inline

设置我们想画出瀑布图的数据,并将其加载到数据帧(DataFrame)中。

数据需要以你的起始值开始,但是你需要给出最终的总数。我们将在下面计算它。
 

index = ['sales','returns','credit fees','rebates','late charges','shipping']
data = {'amount': [350000,-30000,-7500,-25000,95000,-7000]}
trans = pd.DataFrame(data=data,index=index)

我使用了IPython中便捷的display函数来更简单地控制我要显示的内容。
 

from IPython.display import display
display(trans)

瀑布图的最大技巧是计算出底部堆叠条形图的内容。有关这一点,我从stackoverflow上的讨论中学到很多。

首先,我们得到累积和。
 

display(trans.amount.cumsum())
sales      350000
returns     320000
credit fees   312500
rebates     287500
late charges  382500
shipping    375500
Name: amount, dtype: int64

这看起来不错,但我们需要将一个地方的数据转移到右边。
 

blank=trans.amount.cumsum().shift(1).fillna(0)
display(blank)

sales        0
returns     350000
credit fees   320000
rebates     312500
late charges  287500
shipping    382500
Name: amount, dtype: float64

我们需要向trans和blank数据帧中添加一个净总量。
 

total = trans.sum().amount
trans.loc["net"] = total
blank.loc["net"] = total
display(trans)
display(blank)

sales        0
returns     350000
credit fees   320000
rebates     312500
late charges  287500
shipping    382500
net       375500
Name: amount, dtype: float64

创建我们用来显示变化的步骤。

step = blank.reset_index(drop=True).repeat(3).shift(-1)
step[1::3] = np.nan
display(step)

0     0
0    NaN
0  350000
1  350000
1    NaN
1  320000
2  320000
2    NaN
2  312500
3  312500
3    NaN
3  287500
4  287500
4    NaN
4  382500
5  382500
5    NaN
5  375500
6  375500
6    NaN
6    NaN
Name: amount, dtype: float64

对于“net”行,为了不使堆叠加倍,我们需要确保blank值为0。
 

blank.loc["net"] = 0

然后,将其画图,看一下什么样子。
 

my_plot = trans.plot(kind='bar', stacked=True, bottom=blank,legend=None, title="2014 Sales Waterfall")
my_plot.plot(step.index, step.values,'k')

看起来相当不错,但是让我们试着格式化Y轴,以使其更具有可读性。为此,我们使用FuncFormatter和一些Python2.7+的语法来截断小数并向格式中添加一个逗号。
 

def money(x, pos):
  'The two args are the value and tick position'
  return "${:,.0f}".format(x)

from matplotlib.ticker import FuncFormatter
formatter = FuncFormatter(money)

然后,将其组合在一起。
 

my_plot = trans.plot(kind='bar', stacked=True, bottom=blank,legend=None, title="2014 Sales Waterfall")
my_plot.plot(step.index, step.values,'k')
my_plot.set_xlabel("Transaction Types")
my_plot.yaxis.set_major_formatter(formatter)

完整脚本

基本图形能够正常工作,但是我想添加一些标签,并做一些小的格式修改。下面是我最终的脚本:
 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter

#Use python 2.7+ syntax to format currency
def money(x, pos):
  'The two args are the value and tick position'
  return "${:,.0f}".format(x)
formatter = FuncFormatter(money)

#Data to plot. Do not include a total, it will be calculated
index = ['sales','returns','credit fees','rebates','late charges','shipping']
data = {'amount': [350000,-30000,-7500,-25000,95000,-7000]}

#Store data and create a blank series to use for the waterfall
trans = pd.DataFrame(data=data,index=index)
blank = trans.amount.cumsum().shift(1).fillna(0)

#Get the net total number for the final element in the waterfall
total = trans.sum().amount
trans.loc["net"]= total
blank.loc["net"] = total

#The steps graphically show the levels as well as used for label placement
step = blank.reset_index(drop=True).repeat(3).shift(-1)
step[1::3] = np.nan

#When plotting the last element, we want to show the full bar,
#Set the blank to 0
blank.loc["net"] = 0

#Plot and label
my_plot = trans.plot(kind='bar', stacked=True, bottom=blank,legend=None, figsize=(10, 5), title="2014 Sales Waterfall")
my_plot.plot(step.index, step.values,'k')
my_plot.set_xlabel("Transaction Types")

#Format the axis for dollars
my_plot.yaxis.set_major_formatter(formatter)

#Get the y-axis position for the labels
y_height = trans.amount.cumsum().shift(1).fillna(0)

#Get an offset so labels don't sit right on top of the bar
max = trans.max()
neg_offset = max / 25
pos_offset = max / 50
plot_offset = int(max / 15)

#Start label loop
loop = 0
for index, row in trans.iterrows():
  # For the last item in the list, we don't want to double count
  if row['amount'] == total:
    y = y_height[loop]
  else:
    y = y_height[loop] + row['amount']
  # Determine if we want a neg or pos offset
  if row['amount'] > 0:
    y += pos_offset
  else:
    y -= neg_offset
  my_plot.annotate("{:,.0f}".format(row['amount']),(loop,y),ha="center")
  loop+=1

#Scale up the y axis so there is room for the labels
my_plot.set_ylim(0,blank.max()+int(plot_offset))
#Rotate the labels
my_plot.set_xticklabels(trans.index,rotation=0)
my_plot.get_figure().savefig("waterfall.png",dpi=200,bbox_inches='tight')

运行该脚本将生成下面这个漂亮的图表:

最后的想法

如果你之前不熟悉瀑布图,希望这个示例能够向你展示它到底是多么有用。我想,可能一些人会觉得对于一个图表来说需要这么多的脚本代码有点糟糕。在某些方面,我同意这种想法。如果你仅仅只是做一个瀑布图,而以后不会再碰它,那么你还是继续用Excel中的方法吧。

然而,如果瀑布图真的很有用,并且你需要将它复制给100个客户,将会怎么样呢?接下来你将要怎么做呢?此时使用Excel将会是一个挑战,而使用本文中的脚本来创建100个不同的表格将相当容易。再次说明,这一程序的真正价值在于,当你需要扩展这个解决方案时,它能够便于你创建一个易于复制的程序。

我真的很喜欢学习更多Pandas、matplotlib和IPothon的知识。我很高兴这种方法能够帮到你,并希望其他人也可以从中学习到一些知识,并将这一课所学应用到他们的日常工作中。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索python
瀑布图
qt绘制频谱瀑布图、qt绘制瀑布图、python roc曲线绘制、python 表格绘制、python绘制k线图,以便于您获取更多的相关知识。

时间: 2025-01-01 18:22:54

利用Python绘制数据的瀑布图的教程_python的相关文章

Illustrator简单绘制可爱的卡通图效果教程

给各位Illustrator软件的使用者们来详细的解析分享一下简单绘制可爱的卡通图效果的教程. 教程分享:   因为图案想印在T恤上,而众所周知如果采用丝网印刷的话,成本与颜色数成正相关,因此一般都要对颜色数都要进行严格控制. 初稿图案在尽可能低少用颜色的情况下,还是用了7种颜色之多,不满足用户需求,于是硬着头皮绞尽脑汁地把颜色数一步一步减了下来.下面把减色的过程写了下来,依然不能算什么教程,只能算一点点小经验,拿出来与大家分享.由于本人没有接受过专业的艺术教育,因此用色都只是凭感觉,不足之处还

使用python绘制人人网好友关系图示例_python

代码依赖:networkx matplotlib 复制代码 代码如下:  #! /bin/env python# -*- coding: utf-8 -*- import urllibimport urllib2import cookielibimport reimport cPickle as pimport networkx as nximport matplotlib.pyplot as plt __author__ = """Reverland (lhtlyy@gma

利用Photoshop绘制漂亮的彩绘国画陶瓷教程

效果图. 原图   11.接着我们来给瓶子加高光效果. 12.现在处理瓶子底部,刻画瓶底 13.在瓶子底部创建一个新的图层,我们把底较上部暗,使用黑色填充 14.这个参数可以自己定义觉得可以就可以了,再后面就是并口的精细处理了,做完后来们考虑瓶子体的两条高光,如图. 15.最后我们仔细看看各处的,明暗交界线怎么样,如果不理想要再操作,这里需要的是耐心哦,好了最后效果完成了. 1.这里我们要设置中线来绘制一个陶瓷,如下图.     2.我绘制的是一个简单也算是典型的花瓶,这里有光线光源,一些辅助光

利用Python实现颜色色值转换的小工具_python

先看看Zeplin 的颜色色值显示示例 原有处理方式 因为我会 Python (仅限于终端输入 python 然后当做计算器算,或者用 hex() 函数把十进制转换成十六进制),所以遇到这样的问题我当然是采用python 的 hex() 函数做转换,然后手动结果输入到 Android Studio 中. 采用 hex 函数手动转换色值 动机 人总是懒得,想要写这个小工具已经很久了,我也打过有过构思就是:      输入: 类似 RGB 的十进制值(110, 122 138),用空格或者逗号分割一

MySQL中利用索引对数据进行排序的基础教程_Mysql

MySQL中,有两种方式生成有序结果集:一是使用filesort,二是按索引顺序扫描.利用索引进行排序操作是非常快的,而且可以利用同一索引同时进行查找和排序操作.当索引的顺序与ORDER BY中的列顺序相同且所有的列是同一方向(全部升序或者全部降序)时,可以使用索引来排序.如果查询是连接多个表,仅当ORDER BY中的所有列都是第一个表的列时才会使用索引.其它情况都会使用filesort. MySQL索引通常是被用于提高WHERE条件的数据行匹配或者执行联结操作时匹配其它表的数据行的搜索速度.

利用Python为iOS10生成图标和截屏_python

简介 这两天更新完Xcode8之后发现Xcode对图标的要求又有了变化,之前用的一个小应用"IconKit"还没赶上节奏,已经不能满足Xcode8的要求了. 于是就想起来用Python自己做个脚本来生成图标. 其实这个脚本很早就写了,现在为了适应iOS10,就修改完善下,并且放到了GitHub. 可以看看效果图:  1.png 代码: #encoding=utf-8 #by 不灭的小灯灯 #create date 2016/5/22 #update 2016/9/21 #support

利用Python命令行传递实例化对象的方法_python

一.前言 在开发过程中,遇到了这样一个情况:我们需要在脚本中通过 suprocess.call 方法来启动另外一个脚本(脚本 B),当然啦,还得传递一些参数.在这些参数中,有一个需要传递的是一个实例化后的对象.我们知道,通过命令行的方式传递参数是基于字符格式的,也就是说脚本 B 只能接收到字符串格式的参数,那么如何接收启动脚本传递过来的实例化后的对象呢? 今天就来聊聊我使用的两种笨方法:使用 eval 以及使用 pickle 和 base64 模块. 方法一:使用 eval 其实在代码中使用 e

用Python创建声明性迷你语言的教程_python

大多数程序员考虑编程时,他们都要设想用于编写应用程序的 命令式样式和技术.最受欢迎的通用编程语言(包括 Python 和其它面向对象的语言)在样式上绝大多数都是命令式的.另一方面,也有许多编程语言是 声明性样式,包括函数语言和逻辑语言,还包括通用语言和专用语言. 让我们列出几个属于各个种类的语言.许多读者已经使用过这些工具中的许多工具,但不见得考虑过它们之间的种类差别.Python.C.C++.Java.Perl.Ruby.Smalltalk.Fortran.Basic 和 xBase 都是简单

使用Python的PEAK来适配协议的教程_python

如果您正尝试去处理元类,或者正受困于 Twisted 中的异步编程,或者正在研究由于使用了多分派而使您精疲力尽的面向对象编程,那么您完全错了!PEAK 将所有这些中的一些要素组合到了一个组件编程框架中.PEAK 还存在一些小问题.类似于 Twisted,PEAK 的文档 -- 尽量数量巨大 -- 难以看懂.但是尽管如此,关于 Python 领袖 Phillip J. Eby 领导的这一项目还是有一些东西非常值得关注:而且,我觉得,有机会进行极具生产价值的并且层次特别高的应用程序开发. PEAK