设置自定义中线颜色并将刻度标签颜色设置为箱线图面颜色

mac*_*pat 1 python boxplot seaborn

我正在使用这个漂亮的箱线图,来自 @Parfait 的回答

  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)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

Joh*_*anC 5

更新:更改ax.artistsax.patches, 以使代码适用于较新的 matplotlib 和 seaborn 版本。

要更改中位数的颜色,您可以使用medianpropsin sns.boxplot(..., 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)
box_container = ax.patches if len(ax.patches) > 0 else ax.artists
lines_per_boxplot = len(ax.lines) // len(box_container)
for i, (box, ytick) in enumerate(zip(box_container, 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()
Run Code Online (Sandbox Code Playgroud)

sns.boxplot 的线条颜色更改为箱线图颜色