Seaborn boxplot:设置中值颜色并将刻度标签颜色设置为框颜色

Seaborn boxplot : set median color and set tick label colors to boxes color

我正在使用这个漂亮的箱线图,

  1. 我在 j 上遇到了越界错误,不得不使用 range(i*5,i*5+5)。为什么?
  2. 我想将中位数设置为特定颜色,比方说 redmedianprops=dict(color="red") 将不起作用。怎么做?
  3. 如何将 y 轴刻度标签设置为与框相同的颜色?

免责声明:我不知道我在做什么。

这是使用随机数据的代码:

# import the required library 
import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt
import seaborn as sns

import string 
import matplotlib.colors as mc
import colorsys

# data
df = pd.DataFrame(np.random.normal(np.random.randint(5,15),np.random.randint(1,5),size=(100, 16)), columns=list(string.ascii_uppercase)[:16])

# Boxplot
fig, ax = plt.subplots(figsize=(9, 10))
medianprops=dict(color="red")
ax = sns.boxplot(data=df, orient="h", showfliers=False, palette = "husl")
ax = sns.stripplot(data=df, orient="h", jitter=True, size=7, alpha=0.5, palette = "husl")     # show data points
ax.set_title("Title")
plt.xlabel("X label")

def lighten_color(color, amount=0.5):  
    # --------------------- SOURCE: @IanHincks ---------------------
    try:
        c = mc.cnames[color]
    except:
        c = color
    c = colorsys.rgb_to_hls(*mc.to_rgb(c))
    return colorsys.hls_to_rgb(c[0], 1 - amount * (1 - c[1]), c[2])

for i,artist in enumerate(ax.artists):
    # Set the linecolor on the artist to the facecolor, and set the facecolor to None
    col = lighten_color(artist.get_facecolor(), 1.2)
    artist.set_edgecolor(col)    

    # Each box has 6 associated Line2D objects (to make the whiskers, fliers, etc.)
    # Loop over them here, and use the same colour as above
    for j in range(i*5,i*5+5):
        line = ax.lines[j]
        line.set_color(col)
        line.set_mfc(col)
        line.set_mec(col)
        #line.set_linewidth(0.5)

我只回答我问题的第 2 点。

修改之后,我发现这个可以工作:

    # Each box has 5 associated Line2D objects (the whiskers and median)
    # Loop over them here, and use the same colour as above
    n=5  # this was for tinkering
    for j in range(i*n,i*n+n):
        if j != i*n+4 : line = ax.lines[j]  # not the median
        line.set_color(col)

同样,我不知道自己在做什么。所以知识渊博的人可能会提供更有价值的答案。

为了清楚起见,我删除了 stripplot

要更改中位数的颜色,您可以使用 sns.boxplot(..., medianprops=...) 中的 medianprops。如果您还设置了唯一标签,则可以在遍历行时再次测试该标签。

要知道每个箱线图有多少条线,您可以将线数除以艺术家人数(就在箱线图创建之后,其他元素添加到绘图之前)。请注意,一条线可能有 3 种颜色:线颜色、标记面颜色和标记边缘颜色。 Matplotlib 将传单创建为带有标记的不可见线条。因此,下面的代码也更改了这些颜色,以使其对不同的选项和可能的未来更改更加健壮。

同时循环遍历框和 y 刻度标签允许复制颜色。使它们更大和更暗有助于提高可读性。

import matplotlib.pyplot as plt
from matplotlib.colors import rgb_to_hsv, hsv_to_rgb, to_rgb
import seaborn as sns
import pandas as pd
import numpy as np

def enlighten(color, factor=0.5):
    h, s, v = rgb_to_hsv(to_rgb(color))
    return hsv_to_rgb((h, s, 1 - factor * (1 - v)))

def endarken(color, factor=0.5):
    h, s, v = rgb_to_hsv(to_rgb(color))
    return hsv_to_rgb((h, s, factor * v))

df = pd.DataFrame(np.random.normal(1, 5, size=(100, 16)).cumsum(axis=0),
                  columns=['Hydrogen', 'Helium', 'Lithium', 'Beryllium', 'Boron', 'Carbon', 'Nitrogen', 'Oxygen',
                           'Fluorine', 'Neon', 'Sodium', 'Magnesium', 'Aluminum', 'Silicon', 'Phosphorus', 'Sulfur'])

sns.set_style('white')
fig, ax = plt.subplots(figsize=(9, 10))

colors = sns.color_palette("husl", len(df.columns))
sns.boxplot(data=df, orient="h", showfliers=False, palette='husl',
            medianprops=dict(color="yellow", label='median'), ax=ax)

lines_per_boxplot = len(ax.lines) // len(ax.artists)
for i, (box, ytick) in enumerate(zip(ax.artists, ax.get_yticklabels())):
    ytick.set_color(endarken(box.get_facecolor()))
    ytick.set_fontsize(20)
    color = enlighten(box.get_facecolor())
    box.set_color(color)
    for lin in ax.lines[i * lines_per_boxplot: (i + 1) * lines_per_boxplot]:
        if lin.get_label() != 'median':
            lin.set_color(color)
            lin.set_markerfacecolor(color)
            lin.set_markeredgecolor(color)
sns.stripplot(data=df, orient="h", jitter=True, size=7, alpha=0.5, palette='husl', ax=ax)
sns.despine(ax=ax)
ax.set_title("Title")
ax.set_xlabel("X label")
plt.tight_layout()
plt.show()