对于图表而言,颜色至关重要。所谓着色,怎么着,是技术问题;着什么色,是艺术问题。本节介绍着色和配色的基础知识,以及怎么给不同类型的图形元素进行着色。[大谦Excel,dqexcel点com]
颜色的表示
关于图形的颜色,Excel提供了4种设置方法,即RGB着色、主题颜色着色、配色方案着色和索引着色。
图形对象,不管是线形对象还是面对象,它们的BackColor属性和ForeColor属性都会返回一个ColorFormat对象,该对象提供了RGB, ObjectThemeColor, SchemeColor等属性,用它们设置RGB着色、主题颜色着色和配色方案着色。
一、RGB颜色着色
所谓RGB颜色着色,就是用红色、绿色和兰色分量来定义颜色。使用图形对象的颜色相关的属性设置RGB颜色。如果习惯于指定RGB分量来设置颜色,可以使用xlwings.utils模块中的rgb_to_int方法将类似(255,0,0)的RGB分量指定转换为整型值,然后设置给Color属性。还可以将颜色相关属性的值设置为10进制整数或16进制整数。
16进制整数方式也是使用红色、绿色和兰色三种颜色混合得到新的颜色。表示颜色的16进制整数类似于0xFF0000的形式。
表1-7中列出了一些常用颜色的10进制整数、16进制整数和RGB表示。
表1-7 一些颜色的16进制整数和RGB定义
| 红 | 绿 | 蓝 | 10进制整数 | 16进制整数 | 颜色 | 演示 |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0x000000 | 黑色 | |
| 255 | 255 | 255 | 16777215 | 0xFFFFFF | 白色 | |
| 255 | 0 | 0 | 16711680 | 0xFF0000 | 红色 | |
| 0 | 255 | 0 | 65280 | 0x00FF00 | 绿色 | |
| 0 | 0 | 255 | 255 | 0x0000FF | 兰色 | |
| 255 | 255 | 0 | 16776960 | 0xFFFF00 | 黄色 | |
| 255 | 0 | 255 | 16711935 | 0xFF00FF | 粉红 | |
| 0 | 255 | 255 | 65535 | 0x00FFFF | 青色 | |
| 128 | 128 | 128 | 8421504 | 0x808080 | 灰色 | |
| 128 | 0 | 0 | 8388608 | 0x800000 | 深红色 | |
| 255 | 158 | 102 | 16777478 | 0xFF9E66 | 紫铜色 | |
| 125 | 255 | 212 | 8236403 | 0x7CFFD3 | 碧绿色 |
下面代码中ForeColor属性返回一个ColorFormat对象,用它的RGB属性设置RGB分量表示的颜色。
shp.Fill.ForeColor.RGB=xw.utils.rgb_to_int((0, 255,0))
shp.Line.ForeColor.RGB=xw.utils.rgb_to_int((0,0,255))
下面代码将一个表示颜色的10进制整数,也就是xw.utils.rgb_to_int()函数的结果赋给RGB属性。
shp.Fill.ForeColor.RGB=65280
shp.Line.ForeColor.RGB=16711680
也可以直接将一个十六进制整数赋给RGB属性。
shp.Line.ForeColor.RGB=0xFF0000
二、主题颜色着色
Excel提供了10余种主题颜色,如表1-8中所示。使用这些主题颜色,可以很方便地给图形着色。
表1-8 主题颜色
| 名 称 | 值 | 说 明 | 演示 |
|---|---|---|---|
| xlThemeColorAccent1 | 5 | Accent1 | |
| xlThemeColorAccent2 | 6 | Accent2 | |
| xlThemeColorAccent3 | 7 | Accent3 | |
| xlThemeColorAccent4 | 8 | Accent4 | |
| xlThemeColorAccent5 | 9 | Accent5 | |
| xlThemeColorAccent6 | 10 | Accent6 | |
| xlThemeColorDark1 | 1 | Dark1 | |
| xlThemeColorDark2 | 3 | Dark2 | |
| xlThemeColorFollowedHyperlink | 12 | Followed hyperlink | |
| xlThemeColorHyperlink | 11 | Hyperlink | |
| xlThemeColorLight1 | 2 | Light1 | |
| xlThemeColorLight2 | 4 | Light2 |
对于图形对象,使用ForeColor属性和BackColor属性返回的ColorFormat对象的ObjectThemeColor属性,进行主题颜色着色。
shp.Fill.ForeColor.ObjectThemeColor=10
shp.Line.ForeColor.ObjectThemeColor=3
三、配色方案着色
利用Excel提供的配色方案中的颜色,也可以给图形对象着色。对于图形对象, ForeColor属性和BackColor属性返回的ColorFormat对象有一个SchemeColor属性,而配色方案中的每个颜色都有一个索引号,将它指定给SchemeColor属性即可。
shp.Fill.ForeColor.SchemeColor=3
shp.Line.ForeColor.SchemeColor=4
四、索引着色
索引着色需要两张表,第一张表中曲面的每个数据点对应一个索引值,第二张表中每个索引值对应一种颜色,称为颜色查找表,如图1-14所示。两张表通过索引值建立数据点和颜色值之间的映射关系。
图1-14 颜色查找表
索引着色常常用于控件和字体的着色。下面将工作表sht中单元格C3的字体颜色设置为红色。
sht.api.Range('C3').Font.ColorIndex=3
sht.api.Range('C3').Value='Hello '
1.3.5小节将在Excel中引入MATLAB和Python中经常使用的颜色查找表。使用它们,可以很方便地对一组图形对象进行渐变着色。
下面的代码绘制复合线形图,并用不同的方法给图元对象着色。完整代码见:Samples->ch04 美化Excel图表->10 颜色的表示->py.py。
root=os.getcwd() #获取当前工作目录
app=xw.App(visible=True, add_book=False) #创建Excel应用
wb=app.books.open(root+r'/data.xlsx',read_only=False) #打开数据文件返回工作簿对象
sht=wb.sheets('Sheet1') #获取指定工作表对象
sht.api.Range('A2:C11').Select() #数据
shp=sht.api.Shapes.AddChart2(-1, xw.constants.ChartType.xlColumnClustered,20,20,350,250,True)
cht=shp.Chart #添加图表
ser=cht.SeriesCollection(1) #获取第1个序列
ser.Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((0,255,0)) #序列1面的颜色
#ser.Format.Fill.ForeColor.RGB=0x00FF00 #更多颜色表示方式
#ser.Format.Fill.ForeColor.RGB=65280
#ser.Format.Fill.ForeColor.ObjectThemeColor=10
#ser.Format.Fill.ForeColor.SchemeColor=3
运行代码生成图1-15。
图1-15 给复合线形图着色
配色理论
配色理论中比较有名的是色轮配色理论。有很多种色轮,但是最常用的色轮是12色径向上每种颜色有5个色阶的色轮,如图1-16所示。12种颜色中,红色、黄色和蓝色是三原色,其他颜色都是由这三种颜色混合而成。三原色两两之间一半位置上的橙色、绿色和紫色称为二次色,是由它两边的原色混合而成。剩下的称为三次色,是由它们各自两边的原色和二次色混合而成。
图1-16 12色色轮
使用色轮配色的方法有下面几种:
- 单色配色
- 色轮中每种颜色在径向上都有从浅到深5个色阶,单色配色就是使用同一种颜色的不同色阶对图表进行着色。如图1-17中第一个图所示。
- 对比色配色
- 对比色即补色,指的是色轮中直线相对的两种颜色,如图1-17中的红色和绿色,或蓝色和橙色等。对比色适合表现活力,效果如图1-17中右上图所示。
- 类比色配色
- 色轮上相邻的颜色称为类比色,如色轮中的黄橙色、橙色和红橙色,它们拥有共同的颜色,都由黄色和红色混合而成。所以,类别色对比度较低,如图1-17中左下角图所示。
- 三色配色
- 三色配色,可以使用原色配色和二次色配色,也可以使用分裂补色。所谓分裂补色,是取对比色中的一种颜色,以及另一种颜色两侧的颜色。效果如图1-17中右下角图所示。
图1-17 用色轮配色
下面列出实现图1-17中左上角图的部分代码。完整代码见:Samples->ch04 美化Excel图表->11 配色理论->py.py。
root=os.getcwd() #获取当前工作目录
app=xw.App(visible=True, add_book=False) #创建Excel应用
wb=app.books.open(root+r'/data.xlsx',read_only=False) #打开数据文件返回工作簿对象
sht=wb.sheets('Sheet1') #获取指定工作表对象
sht.api.Range('A1:B4').Select() #数据
shp=sht.api.Shapes.AddChart2(-1, xw.constants.ChartType.xlColumnClustered,20,20,350,250,True)
cht=shp.Chart #添加图表
cht.ChartGroups(1).GapWidth=100 #分组之间的距离
#分别设置序列1中各数据点对应的柱面的颜色
cht.SeriesCollection(1).Points(1).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((0,51,51))
cht.SeriesCollection(1).Points(2).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((0,102,102))
cht.SeriesCollection(1).Points(3).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((0,153,153))
cht.SeriesCollection(1).Points(4).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((0,204,204))
下面列出实现图1-17中右上角图的部分代码。完整代码见:Samples->ch04 美化Excel图表->12 配色理论2->py.py。
root=os.getcwd() #获取当前工作目录
app=xw.App(visible=True, add_book=False) #创建Excel应用
wb=app.books.open(root+r'/data.xlsx',read_only=False) #打开数据文件返回工作簿对象
sht=wb.sheets('Sheet1') #获取指定工作表对象
sht.api.Range('A1:C4').Select() #数据
shp=sht.api.Shapes.AddChart2(-1, xw.constants.ChartType.xlColumnClustered,20,20,350,250,True)
cht=shp.Chart #添加图表
cht.ChartGroups(1).GapWidth=100 #分组之间的距离
#分别设置序列1中各数据点对应的柱面的颜色
cht.SeriesCollection(1).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((0,0,255))
cht.SeriesCollection(2).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((255,128,0))
下面列出实现图1-17中左下角角图的部分代码。完整代码见:Samples->ch04 美化Excel图表->13 配色理论3->py.py。
root=os.getcwd() #获取当前工作路径
app=xw.App(visible=True,add_book=False) #创建Excel应用
wb=app.books.open(root+r'/data.xlsx',read_only=False) #打开数据文件返回工作簿对象
sht=wb.sheets('Sheet1') #获取指定工作表对象
sht.api.Range('A1:B4').Select() #数据
shp=sht.api.Shapes.AddChart2(-1, xw.constants.ChartType.xlColumnClustered,20,20,350,250,True)
cht=shp.Chart #添加图表
cht.ChartGroups(1).GapWidth=100 #分组之间的距离
#分别设置序列1中各数据点对应的柱面的颜色
cht.SeriesCollection(1).Points(1).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((255,255,0))
cht.SeriesCollection(1).Points(2).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((255,199,10))
cht.SeriesCollection(1).Points(3).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((242,128,0))
cht.SeriesCollection(1).Points(4).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((235,97,31))
下面列出实现图1-17中右下角图的部分代码。完整代码见:Samples->ch04 美化Excel图表->14 配色理论1->py.py。
root=os.getcwd() #获取当前工作路径
app=xw.App(visible=True,add_book=False) #创建Excel应用
wb=app.books.open(root+r'/data.xlsx',read_only=False) #打开数据文件返回工作簿对象
sht=wb.sheets('Sheet1') #获取指定工作表对象
sht.api.Range('A1:B3').Select() #数据
shp=sht.api.Shapes.AddChart2(-1,xw.constants.ChartType.xlColumnClustered,20,20,350,250,True)
cht=shp.Chart #添加图表
cht.ChartGroups(1).GapWidth=100 #分组之间的距离
#分别设置序列1中各数据点对应的柱面的颜色
cht.SeriesCollection(1).Points(1).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((255,0,0))
cht.SeriesCollection(1).Points(2).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((140,186,38))
cht.SeriesCollection(1).Points(3).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((5,150,186))
配色工具和资源
对学术图表进行配色,不可避免地要用到一些配色工具。网上有专门的帮助配色的网站,比如Adobe Color, Coolors, Colorspire, ColorBlender等。国内也有一些微信公众号专门讨论学术图表的配色,给出2种、3种或更多种颜色的配色方案和各颜色的RGB值。目前这方面的资料还是比较多的,搜索一下就可以找到。
有时候看到好的配色,想知道各种颜色对应的RGB分量,可用专门的取色器进行获取。一般比较专业的绘图软件和平面设计软件都会提供取色器,网上也有一些在线的取色器。
给一组对象着色
绘制图表时经常需要给一组对象着色,例如给简单柱状图中的一组柱面着色,或者给饼图的各扇区着色。可以使用前面介绍的方法给序列中的单个点逐个修改颜色,也可以先将需要用到的颜色放到一个数组中,然后用循环绘制各数据点并从数组中取色绘图。这里介绍后者。
下面先将需要用到的颜色放到一个数组colors中,然后用循环从数组中依次取色并用于修改各柱面的颜色。完整代码见:Samples->ch04 美化Excel图表->15 给一组对象着色->py.py。
root=os.getcwd() #获取当前工作路径
app=xw.App(visible=True,add_book=False) #创建Excel应用
wb=app.books.open(root+r'/data.xlsx',read_only=False) #打开数据文件返回工作簿对象
sht=wb.sheets('Sheet1') #获取指定工作表对象
sht.api.Range('A1:B4').Select() #数据
shp=sht.api.Shapes.AddChart2(-1,xw.constants.ChartType.xlColumnClustered,20,20,350,250,True)
cht=shp.Chart #添加图表
cht.ChartGroups(1).GapWidth=100 #分组之间的距离
#把全部颜色放到一个数组
colors=[[51,51,0],
[102,102,0],
[153,153,0],
[204,204,0]]
#从数组中取色,给各柱面着色
for i in range(4):
cht.SeriesCollection(1).Points(i+1).Format.Fill.ForeColor.RGB \
=xw.utils.rgb_to_int((colors[i][0],colors[i][1],colors[i][2]))
运行代码生成图1-18。
图1-18 给一组对象着色
使用颜色查找表
Python和MATLAB软件中提供了很多颜色查找表,使用它们可以很方便地对一组图形对象进行渐变着色。本小节在Excel中引入MATLAB中的大部分颜色查找表并结合实例进行使用。
所谓的颜色查找表实际上是一个N行3列的数组,数组中每行3个数表示一种颜色的R、G、B分量,即红色、绿色和兰色分量。笔者在Excel中引入了MATLAB的主要颜色查找表。在本书的随书资料中,在Samples目录下可以找到一个名为colormap.xlsx的Excel文件,打开该文件如图1-19所示。
图1-19 在Excel中引入MATLAB中的颜色查找表
工作簿中,每个工作表存放一个颜色查找表的颜色矩阵数据,它们都是256行3列的矩阵。工作表的名称就是颜色查找表的名称。各颜色查找表的颜色说明和对应的色条如表1-9所示。
表1-9 引入MATLAB内置的颜色查找表
| 名称 | 说 明 | 色 条 |
|---|---|---|
| parula | 兰色、青色、橙色和黄色之间渐变 | |
| turbo | 兰色和红色之间渐变 | |
| hsv | 变化HSV颜色模型中的色度组分 | |
| hot | 黑色、红色、橘红色、黄色和白色之间渐变 | |
| cool | 青色和洋红之间渐变 | |
| spring | 洋红和黄色之间渐变 | |
| summer | 绿色和黄色之间渐变 | |
| autumn | 红色向橘黄色、黄色渐变 | |
| winter | 兰色和绿色渐变 | |
| gray | 线性灰阶颜色查找表 | |
| bone | 为含有较高的兰色组分的gray颜色查找表 | |
| copper | 黑色和亮铜色之间渐变 | |
| pink | 品红色和白色渐变 | |
| sky | 白色和天兰色之间渐变 | |
| abyss | 深兰色和天兰色之间渐变 | |
| jet | 兰色、青色、黄色、橘红色、红色之间渐变 |
使用颜色查找表时,需要给定一组着色数据,将该数据从小到大进行排序,并与颜色查找表中的颜色数据建立映射关系。将着色数据的最小值对应表数据的末行,将着色数据的最大值对应表数据的首行,中间的数据根据它的位置取表数据中相应位置的颜色。这样,通过线性插值,可以获取每个着色数据对应的颜色,用于绘制图表。
下面创建有8个柱面的简单柱状图,使用parula颜色查找表对每个柱面单独着色。完整代码见:Samples->ch04 美化Excel图表->16 使用颜色查找表->py.py。
root=os.getcwd() #获取当前工作路径
app=xw.App(visible=True,add_book=False) #创建Excel应用
wb=app.books.open(root+r'/data.xlsx',read_only=False) #打开数据文件返回工作簿对象
sht=wb.sheets('Sheet1') #获取指定工作表对象
sht.api.Range('A2:B9').Select() #数据
shp=sht.api.Shapes.AddChart2(-1,xw.constants.ChartType.xlColumnClustered,20,20,350,250,True)
cht=shp.Chart #添加图表
cht.ChartGroups(1).GapWidth=50 #分组之间的间隔
cm=wb.sheets('parula').range('A1:C256').value #获取颜色查找表的颜色数据
#对于每个柱面,根据序号从颜色查找表中取色进行着色
for i in range(8):
count=int((i+1)/8*256)
if count==256:
r=int(cm[255][0])
g=int(cm[255][1])
b=int(cm[255][2])
else:
r=int(cm[count][0])
g=int(cm[count][1])
b=int(cm[count][2])
cht.SeriesCollection(1).Points(i+1).Format.Fill.ForeColor.RGB=xw.utils.rgb_to_int((r,g,b))
运行代码生成图1-20。
图1-20 使用parula颜色查找表 图1-21 使用cool颜色查找表
下面创建有8个柱面的简单柱状图,使用cool颜色查找表对每个柱面单独着色。完整代码见:Samples->ch04 美化Excel图表->17 使用颜色查找表2->py.py。
#... 省略部分代码
cm=wb.sheets('cool').range('A1:C256').value #获取颜色查找表的颜色数据
#... 省略部分代码
运行代码生成图1-21。
下面创建有8个柱面的简单柱状图,使用summer颜色查找表对每个柱面单独着色。完整代码见:Samples->ch04 美化Excel图表->18 使用颜色查找表3->py.py。
#... 省略部分代码
cm=wb.sheets('summer').range('A1:C256').value #获取颜色查找表的颜色数据
#... 省略部分代码
运行代码生成图1-22。
图1-22 使用summer颜色查找表 图1-23 使用jet颜色查找表
下面创建有8个柱面的简单柱状图,使用jet颜色查找表对每个柱面单独着色。完整代码见:Samples->ch04 美化Excel图表->19 使用颜色查找表1->py.py。
#... 省略部分代码
cm=wb.sheets('jet').range('A1:C256').value #获取颜色查找表的颜色数据
#... 省略部分代码
运行代码生成图1-23。
使用颜色查找表对图表进行着色时,往往需要绘制色条,作为图例标示各颜色对应的着色数据的大小。色条实际上是一个多色渐变填充的矩形,如图1-25所示。
本书随书资料中,在Samples目录下可以找到一个名为colormaps.txt的文本文件,打开该文件如图1-24所示。文件中罗列了各颜色查找表中颜色节点处的位置和颜色,利用该数据,以及1.2.3小节介绍的多色渐变填充的方法,可以绘制对应的色条。
图1-24 绘制色条的数据
上面使用parula, cool, summer和jet 4个颜色查找表对简单柱状图进行了着色,它们对应的色条如图1-25所示。每个色条右侧用标签标示了色条种指定颜色对应的着色数据的大小。
图1-25 绘制色条
下面是绘制图1-25的部分代码。这部分代码涉及到坐标转换,需要学习第5章的内容后才能看懂。完整代码见:Samples->ch04 美化Excel图表->20 绘制色条->py.py。[大谦Excel,dqexcel点com]
root=os.getcwd() #获取当前工作路径
app=xw.App(visible=True,add_book=False) #创建Excel应用
wb=app.books.open(root+r'/data.xlsx',read_only=False) #打开数据文件返回工作簿对象
sht=wb.sheets('Sheet1') #获取指定工作表对象
shp=sht.api.Shapes.AddChart2() #创建空白图表
shp.Left=20
cht=shp.Chart #获取图表
cht.ChartType=xw.constants.ChartType.xlXYScatter #图表类型为散点图
ax1=cht.Axes(1) #获取横轴
ax2=cht.Axes(2) #获取纵轴
ax1.MinimumScale=0 #横轴最小值
ax1.MaximumScale=300
ax2.MinimumScale=0 #纵轴最小值
ax2.MaximumScale=300
set_style(cht) #设置样式
cht.SeriesCollection().NewSeries() #新建序列
#第1个色条,矩形垂向多色渐变填充
x=shape_x(cht,50) #转换坐标
y=shape_y(cht,250)
w=cht.PlotArea.InsideWidth/(ax1.MaximumScale-ax1.MinimumScale)*10 #宽度,需要转换
h=cht.PlotArea.InsideHeight/(ax2.MaximumScale-ax2.MinimumScale)*200
shp2=cht.Shapes.AddShape(1,x,y,w,h) #绘制矩形面
#垂向多色渐变填充
shp2.Fill.ForeColor.RGB=xw.utils.rgb_to_int((255,255,26))
shp2.Fill.OneColorGradient(1,1,1)
shp2.Fill.GradientStops.Insert(xw.utils.rgb_to_int((255,204,51)),0.25)
shp2.Fill.GradientStops.Delete(2)
shp2.Fill.GradientStops.Insert(xw.utils.rgb_to_int((204,204,51)),0.5)
shp2.Fill.GradientStops.Insert(xw.utils.rgb_to_int((0,179,179)),0.75)
shp2.Fill.GradientStops.Insert(xw.utils.rgb_to_int((51,128,255)),0.85)
shp2.Fill.GradientStops.Insert(xw.utils.rgb_to_int((255,204,51)),1)
shp2.Line.Weight=1
#给色条添加标签
cm_labels=['0','0.5','1']
cm_label_pos=[50,150,250]
for i in range(3):
lf=shape_x(cht,57)
tp=shape_y(cht,cm_label_pos[i]+20)
wd=cht.PlotArea.InsideWidth/(cht.Axes(1).MaximumScale-cht.Axes(1).MinimumScale)*40
ht=cht.PlotArea.InsideHeight/(cht.Axes(2).MaximumScale-cht.Axes(2).MinimumScale)*30
shp6=cht.Shapes.AddLabel(1,lf,tp,wd,ht)
shp6.TextFrame2.TextRange.Characters.Text=cm_labels[i]
shp6.TextFrame2.TextRange.Characters.Font.Size=8
shp6.TextFrame2.AutoSize=1 #msoAutoSizeTextToFitShape
#第2个色条,矩形垂向多色渐变填充
#... 省略代码
#第3个色条,矩形垂向多色渐变填充
#... 省略代码
#第4个色条,矩形垂向多色渐变填充
#... 省略代码