我非常有兴趣用不同的梯度填充 barplot 的 matplotlib/seaborn 条,就像这里所做的那样(据我所知,不是用 matplotlib):
我也检查了这个相关主题Pyplot: vertical gradient fill under curve?.
正如 Pyplot:曲线下的垂直梯度填充? 可以使用图像来创建梯度图。
由于条形是矩形的,图像的范围可以直接设置为条形的位置和大小。可以遍历所有条形并在相应位置创建图像。结果是一个梯度条形图。
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
bar = ax.bar([1,2,3,4,5,6],[4,5,6,3,7,5])
def gradientbars(bars):
grad = np.atleast_2d(np.linspace(0,1,256)).T
ax = bars[0].axes
lim = ax.get_xlim()+ax.get_ylim()
for bar in bars:
bar.set_zorder(1)
bar.set_facecolor("none")
x,y = bar.get_xy()
w, h = bar.get_width(), bar.get_height()
ax.imshow(grad, extent=[x,x+w,y,y+h], aspect="auto", zorder=0)
ax.axis(lim)
gradientbars(bar)
plt.show()
我正在使用 seaborn barplot 和
palette
选项。假设您有一个简单的数据框,例如:
df = pd.DataFrame({'a':[1,2,3,4,5], 'b':[10,5,2,4,5]})
使用seaborn:
sns.barplot(df['a'], df['b'], palette='Blues_d')
你可以获得这样的东西:
然后您还可以使用
palette
选项和colormap
根据一些数据添加渐变,例如:
sns.barplot(df['a'], df['b'], palette=cm.Blues(df['b']*10)
获得:
希望有帮助。
我使用 Seaborn 而不是 Matplotlib 改编了@ImportanceOfBeingErnest 的答案here。
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
def gradientbars(bars):
grad = np.atleast_2d(np.linspace(0,1,256)).T # Gradient of your choice
rectangles = bars.containers[0]
# ax = bars[0].axes
fig, ax = plt.subplots()
xList = []
yList = []
for rectangle in rectangles:
x0 = rectangle._x0
x1 = rectangle._x1
y0 = rectangle._y0
y1 = rectangle._y1
xList.extend([x0,x1])
yList.extend([y0,y1])
ax.imshow(grad, extent=[x0,x1,y0,y1], aspect="auto", zorder=0)
ax.axis([min(xList), max(xList), min(yList), max(yList)*1.1]) # *1.1 to add some buffer to top of plot
return fig,ax
sns.set(style="whitegrid", color_codes=True)
np.random.seed(sum(map(ord, "categorical")))
# Load dataset
titanic = sns.load_dataset("titanic")
# Make Seaborn countplot
seabornAxHandle = sns.countplot(x="deck", data=titanic, palette="Greens_d")
plt.show() # Vertical bars with horizontal gradient
# Call gradientbars to make vertical gradient barplot using Seaborn ax
figVerticalGradient, axVerticalGradient = gradientbars(seabornAxHandle)
# Styling using the returned ax
axVerticalGradient.xaxis.grid(False)
axVerticalGradient.yaxis.grid(True)
# Labeling plot to match Seaborn
labels=titanic['deck'].dropna().unique().to_list() # Chaining to get tick labels as a list
labels.sort()
plt.ylabel('count')
plt.xlabel('deck')
plt.xticks(range(0,len(labels)), labels) # Set locations and labels
plt.show() # Vertical bars with vertical gradient
不确定这种风格是否有帮助,因为颜色在这里几乎没有任何意义,只会让你的身材更好看。
我结合了@ImportanceOfBeingErnest 的answer 和@unutbu 的answer 来形成这个解决方案。修改是为 ax.imshow() 提供截断的颜色图。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
def truncate_colormap(cmap, min_val=0.0, max_val=1.0, n=100):
"""
Truncate the color map according to the min_val and max_val from the
original color map.
"""
new_cmap = colors.LinearSegmentedColormap.from_list(
'trunc({n},{a:.2f},{b:.2f})'.format(n=cmap.name, a=min_val, b=max_val),
cmap(np.linspace(min_val, max_val, n)))
return new_cmap
x = ['A', 'B', 'C', 'D', 'E', 'F']
y = [1, 2, 3, 4, 5, 6]
fig, ax = plt.subplots()
bars = ax.bar(x, y)
y_min, y_max = ax.get_ylim()
grad = np.atleast_2d(np.linspace(0, 1, 256)).T
ax = bars[0].axes # axis handle
lim = ax.get_xlim()+ax.get_ylim()
for bar in bars:
bar.set_zorder(1) # put the bars in front
bar.set_facecolor("none") # make the bars transparent
x, _ = bar.get_xy() # get the corners
w, h = bar.get_width(), bar.get_height() # get the width and height
# Define a new color map.
# For instance, if one bar only takes 10% of the y-axis, then the color
# map will only use the first 10% of the color map.
c_map = truncate_colormap(plt.cm.jet, min_val=0,
max_val=(h - y_min) / (y_max - y_min))
# Let the imshow only use part of the color map
ax.imshow(grad, extent=[x, x+w, h, y_min], aspect="auto", zorder=0,
cmap=c_map)
ax.axis(lim)
plt.show()
PS:很抱歉无法使用嵌入的图形