4

I plot boxplots using sns.boxplot and pandas.DataFrame.boxplot in python 3.x.

And I want to ask is it possible to adjust the spacing between boxes in boxplot, so the box of Group_b is farther right to the box of Group_a than in the output figures. Thanks

Codes:

import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns

dict_a = {'value':[1,2,3,7,8,9],'name':['Group_a']*3+['Group_b']*3}
dataframe = pd.DataFrame(dict_a)
sns.boxplot( y="value" , x="name" , data=dataframe )   

Output figure:

enter image description here

dataframe.boxplot("value" ,by = "name" )

Output figure 2:

enter image description here

DilbertFan
  • 113
  • 1
  • 1
  • 9
Echan
  • 1,395
  • 14
  • 15
  • The spacing between boxplots is one data unit. The axes is roughly two data units wide. If you limit the axes to something like 1.3 units, the relative spacing between the boxes will be larger and they will appear further away from each other on screen. Not sure it this is what you're after. Probably a clear description of the desired outcome would be helpful here. – ImportanceOfBeingErnest Mar 20 '19 at 12:43
  • Possible duplicate of [seaborn boxplots at desired distances along the x axis](https://stackoverflow.com/questions/35090425/seaborn-boxplots-at-desired-distances-along-the-x-axis) – Sheldore Mar 20 '19 at 12:43
  • 1
    Closing it as a dupe. Use `dataframe.boxplot("value", by = "name", positions=[1,10])` to have a wide spacing between the two boxes. Choose the number depending on how far you want them from each other – Sheldore Mar 20 '19 at 12:43
  • Another relevant answer [here](https://stackoverflow.com/questions/28712123/matplotlib-shift-boxplots-along-x-axis) – Sheldore Mar 20 '19 at 12:47
  • @Bazingaa. Thnaks, it is working on `dataframe.boxplot`. What about `sns.boxplot()` (as `positions` is not in this function), is it possible to do it? – Echan Mar 20 '19 at 12:48
  • 1
    @Echan: Check the first answer on the marked dupe. Once can insert a column of x-values in DataFrame and then use that as the x-argument. Later, one can replace the x-ticklabels with your strings. Check the second link too which I posted – Sheldore Mar 20 '19 at 12:49
  • @Echan: You can also use `pyplot`'s boxplot as explained [here](https://stackoverflow.com/questions/16592222/matplotlib-group-boxplots) and use `positions` arguments – Sheldore Mar 20 '19 at 12:50

1 Answers1

11

The distance between the two boxes is determined by the x axis limits. For a constant distance in data units between the boxes, what makes them spaced more or less appart is the fraction of this data unit distance compared to the overall data space shown on the axis. For example, in the seaborn case, the first box sits at x=0, the second at x=1. The difference is 1 unit. The maximal distance between the two boxplots is hence achieved by setting the x axis limits to those exact limits,

ax.set_xlim(0, 1)

Of course this will cut half of each box.

enter image description here

So a more useful value would be ax.set_xlim(0-val, 1+val) with val being somewhere in the range of the width of the boxes.

One needs to mention that pandas uses different units. The first box is at x=1, the second at x=2. Hence one would need something like ax.set_xlim(1-val, 2+val).

The following would add a slider to the plot to see the effect of different values.

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

dict_a = {'value':[1,2,3,7,8,9],'name':['Group_a']*3+['Group_b']*3}
dataframe = pd.DataFrame(dict_a)

fig, (ax, ax2, ax3) = plt.subplots(nrows=3,
                                   gridspec_kw=dict(height_ratios=[4,4,1], hspace=1))

sns.boxplot( y="value" , x="name" , data=dataframe, width=0.1, ax=ax)   
dataframe.boxplot("value", by = "name", ax=ax2)


from matplotlib.widgets import Slider
slider = Slider(ax3, "", valmin=0, valmax=3)

def update(val):
    ax.set_xlim(-val, 1+val)
    ax2.set_xlim(1-val, 2+val)

slider.on_changed(update)


plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712