Set space between boxplots in Python Graphs generated nested box plots with Seaborn?

2024/9/8 10:44:08

I am trying to set a space between the boxplots (between the green and orange boxes) created with Python Seaborn module's sns.boxplot(). Please see attached the graph, that the green and orange subplot boxes are stuck to each other, making it visually not the most appealing.

Can't find a way to do that, anyone could find a way (code attached)?

Seaborn Boxplots

import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
tips = sns.load_dataset("tips")
sns.set(style="ticks", palette='Set2', font='Roboto Condensed')
sns.set_context("paper", font_scale=1.1, rc={"lines.linewidth": 1.1})
g=sns.factorplot(x="time", y="total_bill", hue="smoker",col="day", data=tips, kind="box", size=4, aspect=0.5,width=0.8,fliersize=2.5,linewidth=1.1, notch=False,orient="v")
sns.despine(trim=True)
g.savefig('test6.png', format='png', dpi=600)

The Seaborn boxplot documentation is here: http://stanford.edu/~mwaskom/software/seaborn/generated/seaborn.boxplot.html

Answer

Running the danger that this is not needed anymore, I found a solution to this problem. When drawing boxplots directly with matplotlib, the arrangement of the boxes can be controlled with the width and position keywords. However, when passing the positions keyword to sns.factorplot(kind='box',...), one gets a

TypeError: boxplot() got multiple values for keyword argument 'positions'

To get around this, one can set the widths of the boxes 'manually' after the boxplot has been created. This is a bit tedious, because the boxes are stored as PatchPatches within the individual Axes instances of the FacedGrid that is returned by sns.factorplot. Instead of the simple (x,y,width,height) syntax that Rects have, PathPatches use vertices to define the corners, which involves slightly more computation when one wants to adjust the boxes. On top of everything else, the PathPatches returned by matplotlib.boxplot contain an extra (ignored) vertex for the Path.CLOSEPOLY code, which is set to (0,0) and is best ignored. In addition to the box, the horizontal line that marks the median is now too wide and needs to be adjusted as well.

Below I define a function that adjusts widths of the boxes generated by the OP's example code(note the extra import):

from matplotlib.patches import PathPatch
def adjust_box_widths(g, fac):"""Adjust the withs of a seaborn-generated boxplot."""##iterating through Axes instancesfor ax in g.axes.flatten():##iterating through axes artists:for c in ax.get_children():##searching for PathPatchesif isinstance(c, PathPatch):##getting current width of box:p = c.get_path()verts = p.verticesverts_sub = verts[:-1]xmin = np.min(verts_sub[:,0])xmax = np.max(verts_sub[:,0])xmid = 0.5*(xmin+xmax)xhalf = 0.5*(xmax - xmin)##setting new width of boxxmin_new = xmid-fac*xhalfxmax_new = xmid+fac*xhalfverts_sub[verts_sub[:,0] == xmin,0] = xmin_newverts_sub[verts_sub[:,0] == xmax,0] = xmax_new##setting new width of median linefor l in ax.lines:if np.all(l.get_xdata() == [xmin,xmax]):l.set_xdata([xmin_new,xmax_new])

calling this function with

adjust_box_widths(g, 0.9)

gives the following output:

seaborn boxplot with adjusted box width

https://en.xdnf.cn/q/72429.html

Related Q&A

Geocoding using Geopy and Python

I am trying to Geocode a CSV file that contains the name of the location and a parsed out address which includes Address number, Street name, city, zip, country. I want to use GEOPY and ArcGIS Geocodes…

Making Python scripts work with xargs

What would be the process of making my Python scripts work well with xargs? For instance, I would like the following command to work through each line of text file, and execute an arbitrary command:c…

TypeError: expected string or buffer in Google App Engines Python

I want to show the content of an object using the following code:def get(self):url="https://www.googleapis.com/language/translate/v2?key=MY-BILLING-KEY&q=hello&source=en&target=ja&quo…

Returning a row from a CSV, if specified value within the row matches condition

Ahoy, Im writing a Python script to filter some large CSV files.I only want to keep rows which meet my criteria.My input is a CSV file in the following formatLocus Total_Depth Average_Depth_sa…

Python multiprocessing pool: dynamically set number of processes during execution of tasks

We submit large CPU intensive jobs in Python 2.7 (that consist of many independent parallel processes) on our development machine which last for days at a time. The responsiveness of the machine slows …

TypeError: cant escape psycopg2.extensions.Binary to binary

I try to store binary file into postgresql through sqlalchemy and file is uploaded from client. A bit google on the error message brings me to this source file:" wrapped object is not bytes or a…

Keras: Cannot Import Name np_utils [duplicate]

This question already has answers here:ImportError: cannot import name np_utils(19 answers)Closed 6 years ago.Im using Python 2.7 and a Jupyter notebook to do some basic machine learning. Im following…

Python 3 string index lookup is O(1)?

Short story:Is Python 3 unicode string lookup O(1) or O(n)?Long story:Index lookup of a character in a C char array is constant time O(1) because we can with certainty jump to a contiguous memory loca…

Using PIL to detect a scan of a blank page

So I often run huge double-sided scan jobs on an unintelligent Canon multifunction, which leaves me with a huge folder of JPEGs. Am I insane to consider using PIL to analyze a folder of images to detec…

Pandas: Filling data for missing dates

Lets say Ive got the following table:ProdID Date Val1 Val2 Val3 Prod1 4/1/2019 1 3 4 Prod1 4/3/2019 2 3 54 Prod1 4/4/2019 3 4 54 Prod2 4/1/2019 1 3 3…