2

I have the code below that creates a two axes figure. The figure shows box plots for three categorical variables (x axis, hue and figure axes) and one numerical (y axis, shared by the two figure axes ax0 and ax1).

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

# data generation
df = pd.DataFrame([[np.random.choice(['PFOS','PFOA','PFHxS']),
                   np.random.choice(region_order),
                   np.random.choice([True, False]),
                   v] for v in np.random.normal(10,5,200)], 
                  columns=['c','r','u','value'])
dfu = df.loc[df['u']==False,:] # subset of dataframe used for second axis

# required order of categorical variables
region_order = [*reversed(['Arctic Sea', 'North Atlantic'])]
compound_order = ['PFOS', 'PFHxS', 'PFOA']

# figure with two axes
f, (ax0,ax1) = plt.subplots(nrows=1, ncols=2, figsize=(12, 8), sharey=True)

sns.boxplot(data=df, x='value', y="r", 
            hue='c', palette="PuOr", ax=ax0,
            hue_order=compound_order, order=region_order,
            fliersize=0.5, linewidth=0.75)

sns.boxplot(data=dfu, x='value', y="r", 
            hue='c', palette="PuOr", ax=ax1,
            hue_order=compound_order, order=region_order, 
            fliersize=0.5, linewidth=.75)

plt.show()

The first figure axis uses the complete data frame while the second axis uses a subset only.

I get the following image: enter image description here

As you can see, the order of the hue is not consistent between the two axes. The hue legend for the compounds (c) is the same for both axes, so the second axis reverses the hue order for some reason.

How can I have both axes keeping the same hue order?

Luc M
  • 199
  • 2
  • 13
  • 1
    If you use `sharey=False` it will work correctly. Meaning the problem is not that hue_order is reversed, but the axes are. You see that when e.g. `print(ax0.get_ylim())` and `print(ax1.get_ylim())` the axes limits are different. – ImportanceOfBeingErnest Aug 06 '19 at 22:28
  • 1
    It looks like this will be fixed again in matplotlib 3.2 (which is to appear in september). Still not sure about the origin though. – ImportanceOfBeingErnest Aug 06 '19 at 22:46
  • 1
    Ok, so this got broken in [#13330](https://github.com/matplotlib/matplotlib/pull/13330) and is fixed in [#14598](https://github.com/matplotlib/matplotlib/pull/14598), meaning it is even fixed in the already available matplotlib 3.1.1. (However, since 3.1.1 [broke seaborn heatmaps](https://stackoverflow.com/questions/56942670/matplotlib-seaborn-first-and-last-row-cut-in-half-of-heatmap-plot), you may decide to stick with 3.0.3 until 3.2 is released.) – ImportanceOfBeingErnest Aug 06 '19 at 23:05
  • Thanks for all the info. Indeed I see the reversed limits with `get_ylim()`. I'll use matplotlib 3.0.3 in the meantime, that works and that will do it for now. – Luc M Aug 07 '19 at 14:37

1 Answers1

0

The issue is specific to release 3.1.0 (from May 2019) of matplotlib as explained in the comments by ImportanceOfBeingErnest.

The solution to this is to update matplotlib to version 3.2 or above (or downgrade matplotlib to version 3.0.3 if needed).

For example,

# to install a specific version with pip
pip install matplotlib=3.6.0
# or to install the latest version
pip install matplotlib -U

# or if using conda
conda list matplotlib # show available versions 
conda install matplotlib=3.6.0 # install specific version
Luc M
  • 199
  • 2
  • 13