【问题标题】:Matplotlib: applying cellColours to only certain columns/cellsMatplotlib:仅将 cellColours 应用于某些列/单元格
【发布时间】:2021-10-27 17:50:08
【问题描述】:

让自己陷入困境。

我正在 Matplotlib 中创建一个基本表(通过 Pandas,但这不是问题)。我想要完成的是创建一个表,其中第一列(将是字符串值)保持白色......但第 2、3、4、5、6 列是浮动/整数,并将由自定义着色标准化颜色图。

我从基础开始,并通过下面的代码创建了“彩色”表。此时仅绘制具有整数值的列,请参见此处:

我最终需要做的是用一个额外的列来绘制它,比如在列“A”之前或在包含字符串值的列“F”之后,例如['MBIAS'、'RMSE'、'BAGSS'、'MBIAS'、'MBIAS']。

但是,如果我尝试将下面代码中的 cellColours 方法应用于混合了字符串列表和浮点/整数列表的表,它显然会失败。

是否有一种方法可以将 cellColours 方案仅应用于某些单元格或行/列?我可以循环遍历,将自定义颜色图应用到特定单元格吗?

任何帮助或提示将不胜感激!

代码:

import numpy as np
import matplotlib
from matplotlib import cm
import matplotlib.pyplot as plt
from pandas import *


#Create sample data in pandas dataframe
idx = Index(np.arange(1,6))
df = DataFrame(abs(2*np.random.randn(5, 5)), index=idx, columns=['A', 'B', 'C', 'D', 'E'])
model = ['conusarw', 'conusarw', 'conusarw', 'nam04', 'emhrrr']
df['Model'] = model
df1 = df[['A','B','C','D','E']]
test = df1.round({'A':2,'B':2,'C':2,'D':2,'E':2})
print(test)
vals = test.values
print(vals)

#Creates normalized list (from 0-1) based a user provided range and center of distribution.
norm = matplotlib.colors.TwoSlopeNorm(vmin=0,vcenter=1,vmax=10)
#Merges colormap to the normalized data based on customized normalization pattern from above.
colours = plt.cm.coolwarm(norm(vals))

#Create figure in Matplotlib in which to plot table.
fig = plt.figure(figsize=(15,8))
ax = fig.add_subplot(111, frameon=False, xticks=[], yticks=[])
#Plot table, using pandas dataframe information and data.
#Customized lists of data and names can also be provided.
the_table=plt.table(cellText=vals, rowLabels=model, colLabels=df.columns,
                    loc='center', cellColours=colours)

plt.savefig('test_table.png')

【问题讨论】:

标签: python-3.x pandas matplotlib


【解决方案1】:

您可以只使用带有 if-tests 的常规 Python 循环,而不是快速矢量化调用 colours = plt.cm.coolwarm(norm(vals))。下面的代码循环遍历各个行,然后遍历各个元素并测试它们是否为数字。一个类似的循环准备四舍五入的值。速度不是真正的问题,除非你有数千个元素。

(代码使用import pandas as pd,不推荐使用import * from pandas。)

import matplotlib.pyplot as plt
from matplotlib.colors import to_rgba, TwoSlopeNorm
import pandas as pd
import numpy as np

# Create sample data in pandas dataframe
idx = pd.Index(np.arange(1, 6))
df = pd.DataFrame(abs(2 * np.random.randn(5, 5)), index=idx, columns=['A', 'B', 'C', 'D', 'E'])
df['Model'] = ['conusarw', 'conusarw', 'conusarw', 'nam04', 'emhrrr']

cmap = plt.cm.coolwarm
norm = TwoSlopeNorm(vmin=0, vcenter=1, vmax=10)
colours = [['white' if not np.issubdtype(type(val), np.number) else cmap(norm(val)) for val in row]
           for row in df.values]
vals = [[val if not np.issubdtype(type(val), np.number) else np.round(val, 2) for val in row]
        for row in df.values]

fig = plt.figure(figsize=(15, 8))
ax = fig.add_subplot(111, frameon=False, xticks=[], yticks=[])
the_table = plt.table(cellText=vals, rowLabels=df['Model'].to_list(), colLabels=df.columns,
                      loc='center', cellColours=colours)
plt.show()

PS:如果速度是一个问题,下面的代码有点棘手。它使用:

  • 设置颜色图的“坏颜色”
  • pd.to_numeric(..., errors='coerce') 将所有字符串转换为 nans
  • 因为pd.to_numeric() 仅适用于一维数组,所以使用ravel()reshape()
  • 使用相同的数组,np.where 可以进行四舍五入
cmap = plt.cm.coolwarm.copy()
cmap.set_bad('white')
norm = TwoSlopeNorm(vmin=0, vcenter=1, vmax=10)
values = pd.to_numeric(df.values.ravel(), errors='coerce').reshape(df.shape)
colours = cmap(norm(values))
vals = np.where(np.isnan(values), df.values, np.round(values, 2))

fig = plt.figure(figsize=(15, 8))
ax = fig.add_subplot(111, frameon=False, xticks=[], yticks=[])
the_table = plt.table(cellText=vals, rowLabels=df['Model'].to_list(), colLabels=df.columns,
                      loc='center', cellColours=colours)

【讨论】:

  • 这太棒了,谢谢你!我正在提取标准化颜色列表和数据列表,并添加其他列表元素(字符串值作为数据列表的第一个元素,所有白色值作为颜色列表的第一个元素),然后绘制物理表中列出。该方法似乎有效,但步骤混乱且代码难看。这更加紧凑和便携。谢谢!
猜你喜欢
  • 2012-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-30
  • 2013-02-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多