Created
October 24, 2018 15:44
-
-
Save mdbecker/c21e6a8a6ce893b61eecd880d9f18a83 to your computer and use it in GitHub Desktop.
miniboxplot a.la. seaborn violinplot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import seaborn as sns | |
import numpy as np | |
import matplotlib.pyplot as plt | |
class _MiniBoxPlotter(sns.categorical._ViolinPlotter): | |
def draw_violins(self, ax): | |
"""Draw the violins onto `ax`.""" | |
for i, group_data in enumerate(self.plot_data): | |
kws = dict(edgecolor=self.gray, linewidth=self.linewidth) | |
# Option 1: we have a single level of grouping | |
# -------------------------------------------- | |
if self.plot_hues is None: | |
support, density = self.support[i], self.density[i] | |
# Handle special case of no observations in this bin | |
if support.size == 0: | |
continue | |
# Handle special case of a single observation | |
elif support.size == 1: | |
val = np.asscalar(support) | |
d = np.asscalar(density) | |
self.draw_single_observation(ax, i, val, d) | |
continue | |
# Draw the interior representation of the data | |
if self.inner is None: | |
continue | |
# Get a nan-free vector of datapoints | |
violin_data = sns.utils.remove_na(group_data) | |
# Draw box and whisker information | |
self.draw_box_lines(ax, violin_data, support, density, i) | |
# Option 2: we have nested grouping by a hue variable | |
# --------------------------------------------------- | |
else: | |
offsets = self.hue_offsets | |
for j, hue_level in enumerate(self.hue_names): | |
support, density = self.support[i][j], self.density[i][j] | |
kws["facecolor"] = self.colors[j] | |
# Add legend data, but just for one set of violins | |
if not i: | |
self.add_legend_data(ax, self.colors[j], hue_level) | |
# Handle the special case where we have no observations | |
if support.size == 0: | |
continue | |
# Handle the special case where we have one observation | |
elif support.size == 1: | |
val = np.asscalar(support) | |
d = np.asscalar(density) | |
if self.split: | |
d = d / 2 | |
at_group = i + offsets[j] | |
self.draw_single_observation(ax, at_group, val, d) | |
continue | |
# Option 2a: we are drawing a single split violin | |
# ----------------------------------------------- | |
if self.split: | |
if self.inner is None: | |
continue | |
# The box and point interior plots are drawn for | |
# all data at the group level, so we just do that once | |
if not j: | |
continue | |
# Get the whole vector for this group level | |
violin_data = sns.utils.remove_na(group_data) | |
# Draw box and whisker information | |
self.draw_box_lines(ax, violin_data, | |
support, density, i) | |
# Option 2b: we are drawing full nested violins | |
# ----------------------------------------------- | |
else: | |
# Draw the interior representation | |
if self.inner is None: | |
continue | |
# Get a nan-free vector of datapoints | |
hue_mask = self.plot_hues[i] == hue_level | |
violin_data = sns.utils.remove_na(group_data[hue_mask]) | |
# Draw box and whisker information | |
self.draw_box_lines(ax, violin_data, | |
support, density, | |
i + offsets[j]) | |
def miniboxplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None, | |
bw="scott", cut=2, scale="area", scale_hue=True, gridsize=100, | |
width=.8, inner="box", split=False, dodge=True, orient=None, | |
linewidth=None, color=None, palette=None, saturation=.75, | |
ax=None, **kwargs): | |
plotter = _MiniBoxPlotter(x, y, hue, data, order, hue_order, | |
bw, cut, scale, scale_hue, gridsize, | |
width, inner, split, dodge, orient, linewidth, | |
color, palette, saturation) | |
if ax is None: | |
ax = plt.gca() | |
plotter.plot(ax) | |
return ax |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment