From f4504252c0ef7c903761117a781a4767140e832d Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sat, 6 Feb 2021 12:26:09 +0100 Subject: [PATCH] Shorten the implementation of violin(). Just some standard rewriting. --- lib/matplotlib/axes/_axes.py | 100 +++++++++++++---------------------- 1 file changed, 36 insertions(+), 64 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 592dd0d5adaf..950d575300f1 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -8100,7 +8100,6 @@ def violin(self, vpstats, positions=None, vert=True, widths=0.5, - ``cquantiles``: A `~.collections.LineCollection` instance created to identify the quantiles values of each of the violin's distribution. - """ # Statistical quantities to be plotted on the violins @@ -8108,10 +8107,11 @@ def violin(self, vpstats, positions=None, vert=True, widths=0.5, mins = [] maxes = [] medians = [] - quantiles = np.asarray([]) + quantiles = [] + + qlens = [] # Number of quantiles in each dataset. - # Collections to be returned - artists = {} + artists = {} # Collections to be returned N = len(vpstats) datashape_message = ("List of violinplot statistics and `{0}` " @@ -8129,84 +8129,56 @@ def violin(self, vpstats, positions=None, vert=True, widths=0.5, elif len(widths) != N: raise ValueError(datashape_message.format("widths")) - # Calculate ranges for statistics lines - pmins = -0.25 * np.array(widths) + positions - pmaxes = 0.25 * np.array(widths) + positions + # Calculate ranges for statistics lines (shape (2, N)). + line_ends = [[-0.25], [0.25]] * np.array(widths) + positions + + # Colors. + if rcParams['_internal.classic_mode']: + fillcolor = 'y' + linecolor = 'r' + else: + fillcolor = linecolor = self._get_lines.get_next_color() # Check whether we are rendering vertically or horizontally if vert: fill = self.fill_betweenx - perp_lines = self.hlines - par_lines = self.vlines + perp_lines = functools.partial(self.hlines, colors=linecolor) + par_lines = functools.partial(self.vlines, colors=linecolor) else: fill = self.fill_between - perp_lines = self.vlines - par_lines = self.hlines - - if rcParams['_internal.classic_mode']: - fillcolor = 'y' - edgecolor = 'r' - else: - fillcolor = edgecolor = self._get_lines.get_next_color() + perp_lines = functools.partial(self.vlines, colors=linecolor) + par_lines = functools.partial(self.hlines, colors=linecolor) # Render violins bodies = [] for stats, pos, width in zip(vpstats, positions, widths): - # The 0.5 factor reflects the fact that we plot from v-p to - # v+p + # The 0.5 factor reflects the fact that we plot from v-p to v+p. vals = np.array(stats['vals']) vals = 0.5 * width * vals / vals.max() - bodies += [fill(stats['coords'], - -vals + pos, - vals + pos, - facecolor=fillcolor, - alpha=0.3)] + bodies += [fill(stats['coords'], -vals + pos, vals + pos, + facecolor=fillcolor, alpha=0.3)] means.append(stats['mean']) mins.append(stats['min']) maxes.append(stats['max']) medians.append(stats['median']) - q = stats.get('quantiles') - if q is not None: - # If exist key quantiles, assume it's a list of floats - quantiles = np.concatenate((quantiles, q)) + q = stats.get('quantiles') # a list of floats, or None + if q is None: + q = [] + quantiles.extend(q) + qlens.append(len(q)) artists['bodies'] = bodies - # Render means - if showmeans: - artists['cmeans'] = perp_lines(means, pmins, pmaxes, - colors=edgecolor) - - # Render extrema - if showextrema: - artists['cmaxes'] = perp_lines(maxes, pmins, pmaxes, - colors=edgecolor) - artists['cmins'] = perp_lines(mins, pmins, pmaxes, - colors=edgecolor) - artists['cbars'] = par_lines(positions, mins, maxes, - colors=edgecolor) - - # Render medians - if showmedians: - artists['cmedians'] = perp_lines(medians, - pmins, - pmaxes, - colors=edgecolor) - - # Render quantile values - if quantiles.size > 0: - # Recalculate ranges for statistics lines for quantiles. - # ppmins are the left end of quantiles lines - ppmins = np.asarray([]) - # pmaxes are the right end of quantiles lines - ppmaxs = np.asarray([]) - for stats, cmin, cmax in zip(vpstats, pmins, pmaxes): - q = stats.get('quantiles') - if q is not None: - ppmins = np.concatenate((ppmins, [cmin] * np.size(q))) - ppmaxs = np.concatenate((ppmaxs, [cmax] * np.size(q))) - # Start rendering - artists['cquantiles'] = perp_lines(quantiles, ppmins, ppmaxs, - colors=edgecolor) + if showmeans: # Render means + artists['cmeans'] = perp_lines(means, *line_ends) + if showextrema: # Render extrema + artists['cmaxes'] = perp_lines(maxes, *line_ends) + artists['cmins'] = perp_lines(mins, *line_ends) + artists['cbars'] = par_lines(positions, mins, maxes) + if showmedians: # Render medians + artists['cmedians'] = perp_lines(medians, *line_ends) + if quantiles: # Render quantiles: each width is repeated qlen times. + artists['cquantiles'] = perp_lines( + quantiles, *np.repeat(line_ends, qlens, axis=1)) return artists