Method to adjust errorbars in seaborn regplot

Viewed 302

Background
I am plotting my data using sns.regplot (seaborn 0.11.0, Python 3.8.5). I use the argument 'x_estimator' to plot the mean of each category shown on the x-axis, and for each point on the x-axis I have an errorbar which is bootstrapped using the sns.regplot arguments 'ci' and 'boot'.

Since this plot needs to have a specific dots per inch (DPI) of 800, I needed to readjust the scaling of the original plot to make sure the desired DPI was obtained.

Problem
Due to the rescaling, my errorbars appear to be rather 'wide'. I would like to make them less wide, and if it is possible, I would also like to add caps on the errorbars. I have included my code below using a randomly generated dataset. Running this code, one can see that the plot that I obtain has the correct DPI, but the errorbars are too wide.

Edit for clarification

I am fine with the confidence intervals (CI) in itself. My only worry is that the CIs are a bit too wide. This is probably some formatting issue. I already checked line_kws and scatter_kws but I can't find any formatting options for the CIs. My desired output looks like this: the same bars, but not as 'heavy' as the original ones.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#%%

import matplotlib.pyplot as plt
import numpy             as np
import pandas            as pd
import seaborn           as sns

from matplotlib import rcParams

#%%

# seaborn params
sns.set_style("ticks")
sns.set_context("paper")

# plotting params
rcParams['font.family']     = 'Times New Roman'
rcParams['axes.titlesize']  = 6
rcParams['axes.labelsize']  = 5
rcParams['xtick.labelsize'] = 5
rcParams['ytick.labelsize'] = 5

#%%

# some toy data into to pandas dataframe
df = pd.DataFrame({'Y': np.random.normal(0, 1, (800,)), 
                   'X': np.repeat(range(1, 9), 100), 
                   'Condition': np.tile(["A", "B"], 400)}, 
                  index=range(800))

#%%
    
# make a subplot with 1 row and 2 columns
fig, ax_list = plt.subplots(1, 2,
                            sharex  = True, 
                            sharey  = True,
                            squeeze = True)

# A condition
g = sns.regplot(x           = "X", 
                y           = "Y", 
                data        = df.loc[df["Condition"] == "A"], 
                x_estimator = np.mean, 
                x_ci        = "ci", 
                ci          = 95,
                n_boot      = 5000,
                scatter_kws = {"s":15}, 
                line_kws    = {'lw': .75},
                color       = "darkgrey",
                ax          = ax_list[0])

# B condition
g = sns.regplot(x           = "X", 
                y           = "Y", 
                data        = df.loc[df["Condition"] == "B"], 
                x_estimator = np.mean, 
                x_ci        = "ci", 
                ci          = 95,
                n_boot      = 5000,
                scatter_kws = {"s":15}, 
                line_kws    = {'lw': .75},
                color       = "black",
                ax          = ax_list[1])

# figure parameters (left figure)
ax_list[0].set_title("A condition")   
ax_list[0].set_xticks(np.arange(1, 9))
ax_list[0].set_xlim(0.5, 8.5)
ax_list[0].set_xlabel("X")
ax_list[0].set_ylabel("Y")

# figure parameters (right figure)
ax_list[1].set_title("B condition")   
ax_list[1].set_xlabel("X")
ax_list[1].set_ylabel("Y")

# general title
fig.suptitle("Y ~ X", fontsize = 8) 

#%%

# set the size of the image
fig.set_size_inches(3, 2)

# play around until the figure is satisfactory (difficult due to high DPI)
plt.subplots_adjust(top=0.85, bottom=0.15, left=0.185, right=0.95, hspace=0.075,
                    wspace=0.2)

# save as tiff with defined DPI
plt.savefig(fname = "test.tiff", dpi = 800)

plt.close("all")


2 Answers

Try setting ci parameters in sns.regplot to a lower value

I just ran into this problem myself and found a hacky solution. It looks like keyword arguments for the confidence intervals (CI) are not yet exposed to the user (see here). But we can see that it sets the CI line width to 1.75 * linewidth from mpl.rcParams. So I think you can get what you want by hacking a matplotlib rcParams context manager.

import matplotlib as mpl
import numpy as np
import seaborn as sns

# Insert other code from your question here
# to get your dataframe
df = ...

# Play around with this number until you get the desired line width
line_width_reduction = 0.5

linewidth = mpl.rcParams["lines.linewidth"]
with mpl.rc_context({"lines.linewidth": line_width_reduction * linewidth}):
    g = sns.regplot(
        x="X", 
        y="Y", 
        data=df.loc[df["Condition"] == "A"], 
        x_estimator=np.mean, 
        x_ci="ci", 
        ci=95,
        n_boot=5000,
        scatter_kws={"s":15}, 
        line_kws={'lw': .75},
        color="darkgrey",
        ax=ax_list[0]
    )
Related