基于官方Doc的xlwings入门教程(1)
In [3]:
##//// 2016/08 by YZN ////##
'''xlwings教程适合给有一点点基础的用户阅读,内容参考Doc阅读'''
####导入一些模块####
import pandas as pd
import numpy as np
import xlwings as xw
In [3]:
##/////////////////////////////////////////////////////////////////////////
////////////////////////##
'#########这个部分讲怎么导入一个文件以及选取范围和切片,具体的很多选项放在教程(2)介绍
##############'
##/////////////////////////////////////////////////////////////////////////
////////////////////////##
#打开一个文件
test=xw.Book('test.xlsx')
#Range的用法
xw.Range('A1').value = 'something'
xw.Range('A1')
xw.Range('A1:C3')
xw.Range((1,1))
xw.Range((1,1), (3,3))
xw.Range('NamedRange')
xw.Range(xw.Range('A1'), xw.Range('B2'))
#圆括号是1-based取法,而方括号是0-based取法,xlwings遵循着app到book到sheet的层次,
以下都一样
xw.apps[0].books[0].sheets[0].range('A1')
xw.apps(1).books(1).sheets(1).range('A1')
xw.apps[0].books['Book1'].sheets['Sheet1'].range('A1')
xw.apps(1).books('Book1').sheets('Sheet1').range('A1')
#range本身也能切片,只是要记着,就是range[]里面的仍然是0-based,所以3代表第4个
>>> rng = xw.Book().sheets[0].range('A1:D5')
>>> rng[0, 0]
#
>>> rng[1]
#
>>> rng[:, 3:]
>>> rng[1:3, 1:3]
#
#其实不用range也一样吧
>>> sht = xw.Book().sheets['Sheet1']
>>> sht['A1']
#
>>> sht['A1:B5']
#
>>> sht[0, 1]
#
xlwings by Ye
基于官方Doc的xlwings入门教程(1)
>>> sht[:10, :10]
#
In [ ]:
###//////////////////////////////////////////////////////////////##
'##########################查看和赋值语句###########################'
###//////////////////////////////////////////////////////////////##
####这里你会发现给列赋值用的是多一个方括号,给行则是直接的[1,2,3,4,5]
>>> sht = xw.Book().sheets[0]
>>> sht.range('A1').value = [[1],[2],[3],[4],[5]] # Column orientation (
nested list)
>>> sht.range('A1:A5').value
[1.0, 2.0, 3.0, 4.0, 5.0]
####似乎是说也可以用下面这句话来实现对列输出
sht.range('A1').options(transpose=True).value = [1,2,3,4]
>>> sht.range('A1').value = [1, 2, 3, 4, 5]
>>> sht.range('A1:E1').value
[1.0, 2.0, 3.0, 4.0, 5.0]
####一般来说单个单元格返回的数值是float型,你如果要让他返回的是list型可以这么做
sht.range('A1').options(ndim=1).value
sht.range('A1:A5').options(ndim=2).value #也会把每个格子的值作为list放在一个li
st中返回,其中2是作为list,1就是作为float
sht.range('A1:E1').options(ndim=2).value #然而神奇的是,你对一行的value返回时
,居然是list中间包含了一个大list
#[[1.0, 2.0, 3.0, 4.0, 5.0]]
#这边单独说明一下ndim选项,因为后续会用到,Number of array dimensions是这个选项
的意思,就是用来控制你输入的列表内元素维度
#换句话来说,xlwings是这样看待orientation的,每次在大方框下面,同一个小方框是同一
行的数据,而另一个方框则是换行了
sht.range('A1').value = [[1,2],[3,4]]#A1和B1赋值,然后换行到A2和B2赋值
In [ ]:
In [ ]:
###//////////////////////////////////////////////////////////////##
'##########这个单元格讲一些和array和dataframe相关的东西############'
'##########请参看Converters和Options有很多的补充说明###############'
###//////////////////////////////////////////////////////////////##
####Numpy.array相关
#np的eye应该是实现几阶的单位矩阵,然后在range的option下面np.array实际上是conver
t的选项,就是希望用array的方式来显示
import numpy as np
>>> sht = xw.Book().sheets[0]
>>> sht.range('A1').value = np.eye(3)
>>> sht.range('A1').options(np.array, expand='table').value
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
type(sht.range('A1').options(np.array, expand='table').value)#这句话运行你会
发现输出了一个array对象,而不是一个数值的list
####DataFrame相关
xlwings by Ye
基于官方Doc的xlwings入门教程(1)
sht = xw.Book().sheets[0]
df = pd.DataFrame([[1.1, 2.2], [3.3, None]], columns=['one', 'two'])
>>> df
one two
0 1.1 2.2
1 3.3 NaN
>>> sht.range('A1').value = df
>>> sht.range('A1:C3').options(pd.DataFrame).value
one two
0 1.1 2.2
1 3.3 NaN
#这里读出来是一个dataframe的格式,如果你直接用range.value来读取的话,会连带index
和columns一起读进来
# options: work for reading and writing
>>> sht.range('A5').options(index=False).value = df '''后面会看到Index在读取
和写入的时候作用不同'''
>>> sht.range('A9').options(index=False, header=False).value = df#变成这样
以后,用range.value就可以只读出数据,应该是控制了index和columns读不读
In [ ]:
###//////////////////////////////////////////////////////////////##
'##################在excel中构建xlwing的环境########################'
###//////////////////////////////////////////////////////////////##
#64位电脑下载pywin32包才可以
#打开CMD,输入xlwings addin install
#或者在excel中打开VB然后从xw.__path__获取安装的bas文件导入,记得文件要用xlsm保存
['D:\\anacondas\\lib\\site-packages\\xlwings']
#xlwings quickstart myproject这个会在当前目录下创造新的支持的excel文件和.py程序文
件
In [ ]:
##/////////////////////////////////////////////////////////////////////////
///////////##
'#########这一段主要讲在excel中怎么调用python,这里暂时不细说,可以参见后面的UDF####
#####'
'########################UDF那里提供了Macros方法我觉得可以参考#################
##########'
##/////////////////////////////////////////////////////////////////////////
///////////##
#靠RunPython程序来调用,import hello;中hello应该是.py的文件名,然后调用了world函数
#个人测试在打开VBA后用xlwings下新建一个模块来运行会比较可靠
Sub HelloWorld()
RunPython ("import hello; hello.world()")
End Sub
# hello.py
import numpy as np
import xlwings as xw
def world():
wb = xw.Book.caller()#仅仅在被excel调用的时候才出现
wb.sheets[0].range('A1').value = 'Hello World!'
xlwings by Ye
基于官方Doc的xlwings入门教程(1)
############给了一段Debug的程序代码,这个暂时不细说####################
# my_module.py
import os
import xlwings as xw
def my_macro():
wb = xw.Book.caller()
wb.sheets[0].range('A1').value = 1
if __name__ == '__main__':
# Expects the Excel file next to this source file, adjust accordingly.
xw.Book('myfile.xlsxm').set_mock_caller()
my_macro()
#######
Sub my_macro()
RunPython ("import my_module; my_module.my_macro()")
End Sub
In [ ]:
##///////////////////////////////////////////////////////////////##
'####################又是最核心的一块,如何使用UDF##################'
##///////////////////////////////////////////////////////////////##
##UDF现在只能在Windows上运行##
#xlwings quickstart myproject#
##一般来说就把文件放在要用的excel文件夹下面,或者用VBA SETTING去改PATH##
'######如何操作UDF########'
#####如何在一个单元格中应用UDF########
#假设现在有个a.xlsm,然后有个a.py写着下面的code
import xlwings as xw
@xw.func #这句话只在excel导入python的时候用到(@是个装饰符),用来给VBA指明哪个(下
一个)函数要建立wrapper
def double_sum(x, y): #这个函数在VBA中也可以调用
"""Returns twice the sum of the two arguments"""
return 2 * (x + y)
#点击AddIn的按钮import这个UDF,在某一个格子输入=double_sum(1,2)就会输出6
#######如何在一个array中应用相同的公式,或者是Doc中说的array fomula###
@xw.func
def add_one(data): ####首先建立一个UDF
return [[cell + 1 for cell in row] for row in data]
#在A1:B3输入数字,在另外一个地方选中同样大小的一个区域,输入=add_one(A1:B3),然
后摁Ctrl+Shift+Enter ,会发现公式外面有个{}这就是区域公式了
#此时可能出现了一个问题,就是你有可能对某一个单元格用了这个,你就需要如下代码来调整一
下
@xw.func
@xw.arg('data', ndim=2)#这个arg应该是控制内容的一个option(argument的简称),dat
a和ndim=2告诉你函数输入的【数据】应当是【2维的数组】
def add_one(data):
return [[cell + 1 for cell in row] for row in data]
xlwings by Ye
基于官方Doc的xlwings入门教程(1)
#这是如何引入dataframe和numpy进入到函数中
import xlwings as xw
import numpy as np
@xw.func
@xw.arg('x', np.array, ndim=2)
@xw.arg('y', np.array, ndim=2)
def matrix_mult(x, y):
return x.dot(y)
##////////////这里Doc举了一个很好的例子,有关于计算相关系数的///////////////////##
##///////////Excel只能计算两个array之间的corr,而且比较笨重/////////////////////
##
##///////////用pandas配合xw和excel就好了/////////////////////##
import xlwings as xw
import pandas as pd
@xw.func
#你得在excel选取一块数据,需要注意的是index=和header=控制着你输入的区域是否要包含
索引!!!
@xw.arg('x', pd.DataFrame, index=False, header=False)
@xw.ret(index=False, header=False) #ret是控制return的
def CORREL2(x):
"""Like CORREL, but as array formula for more than 2 data sets""" #这个
基于某个dataframe的多列之间计算
return x.corr()
'##//////////////如何在UDF的内容中调用VBA///////////////##'
@xw.func
@xw.arg('xl_app', vba='Application') #当设定vba的关键字为Application之后,就可
以用VBA的属性了,比如Caller.Address返回当前call的单元格区域
def get_caller_address(xl_app)
return xl_app.Caller.Address
##///////////相对于从VBA中用RunPython来调用,这里提供了一种Macros方法很方便/////##
import xlwings as xw
#这个@xw.sub是关键,其实个人感觉就是替代了VBA中的sub过程
#一般来说我们def的东西只能在单元格或者区域引用,而加入这个之后,在AddIn导入之后你就
可以用宏来选中并运行它了
@xw.sub
def my_macro():
"""Writes the name of the Workbook into Range("A1") of Sheet 1"""
wb = xw.Book.caller()
wb.sheets[0].range('A1').value = wb.name
In [ ]:
##//////////////////////////////////////////////////////////##
'##############主要讲matplotlib在xlwings的使用#################'
##//////////////////////////////////////////////////////////##
####把fig这个图加入新创立的book的sheet0中
>>> import matplotlib.pyplot as plt
xlwings by Ye
基于官方Doc的xlwings入门教程(1)
>>> fig = plt.figurexw.apps[0].books[0].sheets[0].range('A1')
>>> plt.plot([1, 2, 3, 4, 5])
>>> wb = xw.Book()
>>> wb.sheets[0].pictures.add(fig, name='MyPlot', update=True)#update指的
是你在excel可以改变图片的位置和大小
####说这个部分的作图可以完美的和excel结合#######
#####使用UDF可以很方便地设定画图函数######
@xw.func
def myplot(n):
sht = xw.Book.caller().sheets.active
fig = plt.figure()
plt.plot(range(int(n)))
sht.pictures.add(fig, name='MyPlot', update=True)
return 'Plotted with n={}'.format(n)
#然后在xlwings的addin下把这个玩意import,在B2格直接输入=myplot(B1),B1中写个
5,就可以实现自动画图了
####你可以改变图的大小和位置#####
sht = xw.Book().sheets[0]
>>> sht.pictures.add(fig, name='MyPlot', update=True,left=sht.range('B5')
.left, top=sht.range('B5').top)
#或者
>>> plot = sht.pictures.add(fig, name='MyPlot', update=True)
>>> plot.height /= 2
>>> plot.width /= 2
#####也可以通过pandas来画画###
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.rand(10, 4), columns=['a', 'b', 'c', 'd'])
ax = df.plot(kind='bar')
fig = ax.get_figure()
In [ ]:
##/////////////////////////////////////////////////////////////////////////
///////////##
'#########################最后一个也是非常重要的部分,Converters和Options#######
#########'
##/////////////////////////////////////////////////////////////////////////
///////////##
##简单理解来看converters可以在你读取或者写入Excel的时候对对象类型进行匹配###
'''常见的就是用在Range的option内,以及应用UDF的时候,而且务必注意converters区分读取
和写入的情况!'''
#在之前的例子里面我们就见到很多这样的语句,设定读取或写入的格式,比如
@xw.arg('x', pd.DataFrame, index=False, header=False) #这里就是制定了DataFra
me作为形式
sht.range('A1:E1').options(ndim=2).value #这里用了default的形式,只是说明数据类
型为二维
####介绍一些default的converters######
'''u'单个Cell根据里面是数值还是文字或是日期分为float,unicode以及datetime三种,以及
空的None''''
'''而一维数据作为list,二维或者多维就是nested list,多重的list'''
xlwings by Ye
基于官方Doc的xlwings入门教程(1)
'''///////////////一些常用的可以设定的converters内容介绍//////////////////'''
##----- ndim:这个介绍过了 -------##
##----- number:设置单元格数值是float还是int -----##
sht.range('A1').options(numbers=int).value '''这里是读取的时候用int来展示'''
@xw.arg('x', numbers=int)'''这里是所有输入的x参数的number都被设定成int'''
##----- dates: 用来设定日期时间格式,决定是日期还是‘日期+时间’的格式 -----##
'''对Range使用的时候,通俗易懂不解释'''
>>> import datetime as dt
>>> sht.range('A1').options(dates=dt.date).value
'''在UDF中格式化的时候'''
###这里的lambda函数不细说,可以理解成一个针对每个参数都进行的转换过程(非定义的临时函
数),**kwargs是可变参数,%04i表示‘格式+位数+形式’
>>> my_date_handler = lambda year, month, day, **kwargs: "%04i-%02i-%02i"
% (year, month, day)
>>> sht.range('A1').options(dates=my_date_handler).value
'2017-02-20'
##----- empty=‘NA’ 你可以设置空值的形式,而不是None -----##
##----- transpose:可以用一个list对column进行输出 ,后面也会看到它起到转置的作用
-----##
sht.range('A1').options(transpose=True).value = [1, 2, 3] #之前有提到输出某
一列要[[1],[2],[3]] ,现在用这句就可以
##------------ expand(只在Range中有用):具体参看下方,除了table,还有vertical
和horizontal 可以选择 -----------##
######特别需要注意,‘gives back an expanded Range object, options are only ev
aluated when accessing the values of a Range.’大概就是说
######expand函数返回的是一个直接由range函数定义的扩展区域,也就是说是针对某一个单元格
进行range一个list后的区域,即使相邻区域有东西也不要
######option中的expand是我们理解的excel中的,凡是基于这个单元周围有数值的全选中(测试
了一下,似乎有空值就不会选中)
######table指的是方式,即先down再right,因此定义的是左上角单元格,也有单独选行或者列的
sht = xw.Book().sheets[0]
>>> sht.range('A1').value = [[1,2], [3,4]]
>>> rng1 = sht.range('A1').expand('table') # or just .expand()
>>> rng2 = sht.range('A1').options(expand='table')
>>> rng1.value
#[[1.0, 2.0], [3.0, 4.0]]
>>> rng2.value
#[[1.0, 2.0], [3.0, 4.0]]
>>> sht.range('A3').value = [5, 6]
>>> rng1.value
#[[1.0, 2.0], [3.0, 4.0]]
>>> rng2.value
#[[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]
'''///////////一些BuiltIn的参数介绍/////////////////'''
xlwings by Ye
基于官方Doc的xlwings入门教程(1)
##----- dict:可以把两列变成一个字典进行匹配 -----##
>>> sht = xw.sheets.active
>>> sht.range('A1:B2').options(dict).value
{'a': 1.0, 'b': 2.0}
>>> sht.range('A4:B5').options(dict, transpose=True).value
{'a': 1.0, 'b': 2.0}
##----- numpy的array属性,这个之前介绍过 -----##
sht.range('A1:A3').options(np.array, ndim=2).value
array([[ 1.],
[ 2.],
[ 3.]])
##----- Pandas的Series:之前没有详细介绍 -----##
'''Index在写入的时候类似于pandas的index_col设定把哪一列作为index展示,而读取的时候为
布尔值,是否将数据输入进index'''
'''header如果在读取时为False,则不会显示index和column,写入时是否包含了index或者col
umn的name,注意!是index的name而非index本身'''
'''主要写一下Index和header属性,DataFrame也是类似的,除了header在读取时是显示将前几
行作为列的标签'''
##这里补充一下,header这个属性,按照越上方的行层次越高,如果第一行[a,a,b]下一行[d,e,f
],那么双重的column索引,d和e都属于a类,第二个a不显示
>>> sht = xw.Book().sheets[0]
>>> s = sht.range('A1').options(pd.Series, expand='table').value
>>> s
date
2001-01-01 1
2001-01-02 2
2001-01-03 3
Name: series name, dtype: float64
>>> sht.range('D1', header=False).value = s
##----- raw:这个能提取原始的东西,就是原来excel写了啥就提取出啥 -----##
>>> sht.range('A1:B2').value
[[1.0, 'text'], [datetime.datetime(2016, 2, 1, 0, 0), None]]
>>> sht.range('A1:B2').options('raw').value # or sht.range('A1:B2').raw_v
alue
((1.0, 'text'), (pywintypes.datetime(2016, 2, 1, 0, 0, tzinfo=TimeZoneInfo
('GMT Standard Time', True)), None))
In [ ]:
##/////////////////////////////////////////////////////////////////////////
///////////##
'#########################单独将Custom converters抽出来讲一下,自定义转换#######
#########'
##/////////////////////////////////////////////////////////////////////////
///////////##
'''定义一个contervers需要特别注意是read_value or write_value,这里以扩展原来的Dat
aFrame为例'''
from xlwings.conversion import Converter, PandasDataFrameConverter
class DataFrameDropna(Converter): ##类的概念暂时不管,记住这个形式
xlwings by Ye