着色与配色

对于图表而言,颜色至关重要。所谓着色,怎么着,是技术问题;着什么色,是艺术问题。本节介绍着色和配色的基础知识,以及怎么给不同类型的图形元素进行着色。[大谦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分量表示的颜色。

code.python
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属性。

code.python
shp.Fill.ForeColor.RGB=65280
shp.Line.ForeColor.RGB=16711680

也可以直接将一个十六进制整数赋给RGB属性。

code.python
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属性,进行主题颜色着色。

code.python
shp.Fill.ForeColor.ObjectThemeColor=10
shp.Line.ForeColor.ObjectThemeColor=3

三、配色方案着色

利用Excel提供的配色方案中的颜色,也可以给图形对象着色。对于图形对象, ForeColor属性和BackColor属性返回的ColorFormat对象有一个SchemeColor属性,而配色方案中的每个颜色都有一个索引号,将它指定给SchemeColor属性即可。

code.python
shp.Fill.ForeColor.SchemeColor=3
shp.Line.ForeColor.SchemeColor=4

四、索引着色

索引着色需要两张表,第一张表中曲面的每个数据点对应一个索引值,第二张表中每个索引值对应一种颜色,称为颜色查找表,如图1-14所示。两张表通过索引值建立数据点和颜色值之间的映射关系。

Document Image

图1-14 颜色查找表

索引着色常常用于控件和字体的着色。下面将工作表sht中单元格C3的字体颜色设置为红色。

code.python
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。

code.python
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。

Document Image

图1-15 给复合线形图着色

配色理论

配色理论中比较有名的是色轮配色理论。有很多种色轮,但是最常用的色轮是12色径向上每种颜色有5个色阶的色轮,如图1-16所示。12种颜色中,红色、黄色和蓝色是三原色,其他颜色都是由这三种颜色混合而成。三原色两两之间一半位置上的橙色、绿色和紫色称为二次色,是由它两边的原色混合而成。剩下的称为三次色,是由它们各自两边的原色和二次色混合而成。

Document Image

图1-16 12色色轮

使用色轮配色的方法有下面几种:

  • 单色配色
  • 色轮中每种颜色在径向上都有从浅到深5个色阶,单色配色就是使用同一种颜色的不同色阶对图表进行着色。如图1-17中第一个图所示。
  • 对比色配色
  • 对比色即补色,指的是色轮中直线相对的两种颜色,如图1-17中的红色和绿色,或蓝色和橙色等。对比色适合表现活力,效果如图1-17中右上图所示。
  • 类比色配色
  • 色轮上相邻的颜色称为类比色,如色轮中的黄橙色、橙色和红橙色,它们拥有共同的颜色,都由黄色和红色混合而成。所以,类别色对比度较低,如图1-17中左下角图所示。
  • 三色配色
  • 三色配色,可以使用原色配色和二次色配色,也可以使用分裂补色。所谓分裂补色,是取对比色中的一种颜色,以及另一种颜色两侧的颜色。效果如图1-17中右下角图所示。
Document Image Document Image

Document Image Document Image

图1-17 用色轮配色

下面列出实现图1-17中左上角图的部分代码。完整代码见:Samples->ch04 美化Excel图表->11 配色理论->py.py。

code.python
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。

code.python
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。

code.python
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。

code.python
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。

code.python
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。

Document Image

图1-18 给一组对象着色

使用颜色查找表

Python和MATLAB软件中提供了很多颜色查找表,使用它们可以很方便地对一组图形对象进行渐变着色。本小节在Excel中引入MATLAB中的大部分颜色查找表并结合实例进行使用。

所谓的颜色查找表实际上是一个N行3列的数组,数组中每行3个数表示一种颜色的R、G、B分量,即红色、绿色和兰色分量。笔者在Excel中引入了MATLAB的主要颜色查找表。在本书的随书资料中,在Samples目录下可以找到一个名为colormap.xlsx的Excel文件,打开该文件如图1-19所示。

Document Image

图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。

code.python
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。

Document Image Document Image

图1-20 使用parula颜色查找表 图1-21 使用cool颜色查找表

下面创建有8个柱面的简单柱状图,使用cool颜色查找表对每个柱面单独着色。完整代码见:Samples->ch04 美化Excel图表->17 使用颜色查找表2->py.py。

code.python
#... 省略部分代码
cm=wb.sheets('cool').range('A1:C256').value    #获取颜色查找表的颜色数据
#... 省略部分代码

运行代码生成图1-21。

下面创建有8个柱面的简单柱状图,使用summer颜色查找表对每个柱面单独着色。完整代码见:Samples->ch04 美化Excel图表->18 使用颜色查找表3->py.py。

code.python
#... 省略部分代码
cm=wb.sheets('summer').range('A1:C256').value    #获取颜色查找表的颜色数据
#... 省略部分代码

运行代码生成图1-22。

Document Image Document Image

图1-22 使用summer颜色查找表 图1-23 使用jet颜色查找表

下面创建有8个柱面的简单柱状图,使用jet颜色查找表对每个柱面单独着色。完整代码见:Samples->ch04 美化Excel图表->19 使用颜色查找表1->py.py。

code.python
#... 省略部分代码
cm=wb.sheets('jet').range('A1:C256').value    #获取颜色查找表的颜色数据
#... 省略部分代码

运行代码生成图1-23。

使用颜色查找表对图表进行着色时,往往需要绘制色条,作为图例标示各颜色对应的着色数据的大小。色条实际上是一个多色渐变填充的矩形,如图1-25所示。

本书随书资料中,在Samples目录下可以找到一个名为colormaps.txt的文本文件,打开该文件如图1-24所示。文件中罗列了各颜色查找表中颜色节点处的位置和颜色,利用该数据,以及1.2.3小节介绍的多色渐变填充的方法,可以绘制对应的色条。

Document Image

图1-24 绘制色条的数据

上面使用parula, cool, summer和jet 4个颜色查找表对简单柱状图进行了着色,它们对应的色条如图1-25所示。每个色条右侧用标签标示了色条种指定颜色对应的着色数据的大小。

Document Image

图1-25 绘制色条

下面是绘制图1-25的部分代码。这部分代码涉及到坐标转换,需要学习第5章的内容后才能看懂。完整代码见:Samples->ch04 美化Excel图表->20 绘制色条->py.py。[大谦Excel,dqexcel点com]

code.python
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个色条,矩形垂向多色渐变填充
#... 省略代码