MEP28 : Supprimer la complexité de Axes.boxplot #
Statut #
Discussion
Branches et demandes d'extraction #
La liste suivante répertorie tous les PR ouverts ou les succursales liées à ce MEP :
Déprécier les kwargs statistiques redondants dans
Axes.boxplot
: https://github.com/phobson/matplotlib/tree/MEP28-initial-deprecationsDéprécier les options de style redondantes dans
Axes.boxplot
: https://github.com/phobson/matplotlib/tree/MEP28-initial-deprecationsDéprécier les passages de tableaux NumPy 2D en entrée : aucun
Ajoutez des options de pré- et post-traitement à
cbook.boxplot_stats
: https://github.com/phobson/matplotlib/tree/boxplot-stat-transformsExposer
cbook.boxplot_stats
à traversAxes.boxplot
les kwargs : aucunSupprimer les kwargs statistiques redondants dans
Axes.boxplot
: AucunSupprimer les options de style redondantes dans
Axes.boxplot
: AucunAutres éléments soulevés lors de la discussion : aucun
Résumé #
Au cours des dernières versions, la Axes.boxplot
méthode est devenue plus complexe pour prendre en charge un style d'artiste et un calcul statistique entièrement personnalisables. Cela a conduit à Axes.boxplot
être divisé en plusieurs parties. Les statistiques nécessaires pour dessiner une boîte à moustaches sont calculées dans
cbook.boxplot_stats
, tandis que les artistes réels sont dessinés par Axes.bxp
. La méthode d'origine Axes.boxplot
reste l'API la plus publique qui gère la transmission des données fournies par l'utilisateur à cbook.boxplot_stats
, l'envoi des résultats à Axes.bxp
et le prétraitement des informations de style pour chaque facette des tracés de boîtes à moustaches.
Ce MEP décrira une voie à suivre pour annuler la complexité supplémentaire et simplifier l'API tout en maintenant une rétrocompatibilité raisonnable.
Descriptif détaillé #
Actuellement, la Axes.boxplot
méthode accepte des paramètres qui permettent aux utilisateurs de spécifier des médianes et des intervalles de confiance pour chaque boîte qui sera dessinée dans le tracé. Celles-ci ont été fournies afin que les utilisateurs avancés puissent fournir des statistiques calculées d'une manière différente de la méthode simple fournie par matplotlib. Cependant, la gestion de cette entrée nécessite une logique complexe pour s'assurer que les formes de la structure de données correspondent à ce qui doit être dessiné. Pour le moment, cette logique contient 9 instructions if/else séparées imbriquées jusqu'à 5 niveaux de profondeur avec une boucle for et peut générer jusqu'à 2 erreurs. Ces paramètres ont été ajoutés avant la création de la Axes.bxp
méthode, qui dessine des boîtes à moustaches à partir d'une liste de dictionnaires contenant les statistiques pertinentes. Matplotlib fournit également une fonction qui calcule ces statistiques viacbook.boxplot_stats
. Notez que les utilisateurs avancés peuvent désormais a) écrire leur propre fonction pour calculer les statistiques requises par
Axes.bxp
, ou b) modifier la sortie renvoyée par cbook.boxplots_stats
pour personnaliser entièrement la position des artistes des tracés. Avec cette flexibilité, les paramètres permettant de spécifier manuellement uniquement les médianes et leurs intervalles de confiance restent pour une rétrocompatibilité.
À peu près au même moment où les deux rôles de Axes.boxplot
ont été divisés en
cbook.boxplot_stats
calcul et Axes.bxp
en dessin, les deux
Axes.boxplot
et Axes.bxp
ont été écrits pour accepter des paramètres qui basculent individuellement le dessin de tous les composants des boîtes à moustaches, et des paramètres qui configurent individuellement le style de ces artistes. Cependant, pour maintenir la rétrocompatibilité, le sym
paramètre (précédemment utilisé pour spécifier le symbole des dépliants) a été conservé. Ce paramètre lui-même nécessite une logique assez complexe pour réconcilier les sym
paramètres avec le nouveau flierprops
paramètre au style par défaut spécifié par matplotlibrc
.
Ce MEP vise à simplifier considérablement la création de boîtes à moustaches pour les utilisateurs novices et avancés. Il est important de noter que les modifications proposées ici seront également disponibles pour les packages en aval comme seaborn, car seaborn permet intelligemment aux utilisateurs de transmettre des dictionnaires arbitraires de paramètres via l'API seaborn aux fonctions matplotlib sous-jacentes.
Ceci sera réalisé de la manière suivante :
cbook.boxplot_stats
sera modifié pour permettre aux fonctions de transformation pré- et post-calcul d'être transmises (par exemple,np.log
etnp.exp
pour les données distribuées log-normalement)
Axes.boxplot
sera modifié pour les accepter également et les transmettre naïvement àcbook.boxplots_stats
(Alt : transmettre la fonction stat et un dict de ses paramètres optionnels).Les paramètres obsolètes de
Axes.boxplot
seront obsolètes et supprimés ultérieurement.
Importance #
Étant donné que les limites des moustaches sont calculées arithmétiquement, il existe une hypothèse implicite de normalité dans les diagrammes en boîte et moustaches. Cela affecte principalement les points de données classés comme valeurs aberrantes.
Autoriser les transformations des données et des résultats utilisés pour dessiner des boîtes à moustaches permettra aux utilisateurs de refuser cette hypothèse si les données sont connues pour ne pas correspondre à une distribution normale.
Vous trouverez ci-dessous un exemple de la manière dont Axes.boxplot
les valeurs aberrantes des données log-normales sont classées différemment en fonction de ces types de transformations.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cbook
np.random.seed(0)
fig, ax = plt.subplots(figsize=(4, 6))
ax.set_yscale('log')
data = np.random.lognormal(-1.75, 2.75, size=37)
stats = cbook.boxplot_stats(data, labels=['arithmetic'])
logstats = cbook.boxplot_stats(np.log(data), labels=['log-transformed'])
for lsdict in logstats:
for key, value in lsdict.items():
if key != 'label':
lsdict[key] = np.exp(value)
stats.extend(logstats)
ax.bxp(stats)
fig.show()
( Code source , png )
Mise en œuvre #
Passer des fonctions de transformation à cbook.boxplots_stats
#
Ce MEP propose que deux paramètres (par exemple, transform_in
et
transform_out
soient ajoutés à la fonction de livre de recettes qui calcule les statistiques pour la fonction de boîte à moustaches. Ce seront des arguments facultatifs de mot-clé uniquement et peuvent facilement être définis comme non-op lorsqu'ils sont omis par l'utilisateur. La fonction sera appliquée aux données au fur et à mesure que la fonction parcourt chaque sous-ensemble des données qui lui sont transmises. Une fois la liste des dictionnaires de statistiques calculée, la
fonction est appliquée à chaque valeur des dictionnaires.lambda x: x
transform_in
boxplot_stats
transform_out
Ces transformations peuvent ensuite être ajoutées à la signature d'appel
Axes.boxplot
avec peu d'impact sur la complexité de cette méthode. C'est parce qu'ils peuvent être directement passés à cbook.boxplot_stats
. Alternativement, Axes.boxplot
pourrait être modifié pour accepter une fonction statistique facultative kwarg et un dictionnaire de paramètres à lui transmettre directement.
À ce stade de l'implémentation, les utilisateurs et les bibliothèques externes comme seaborn auraient un contrôle total via la Axes.boxplot
méthode. Plus important encore, à tout le moins, seaborn ne nécessiterait aucune modification de son API pour permettre aux utilisateurs de profiter de ces nouvelles options.
Simplifications de l' Axes.boxplot
API et d'autres fonctions #
La simplification de la méthode du boxplot consiste principalement à déprécier puis à supprimer les paramètres redondants. Facultativement, une prochaine étape consisterait à rectifier les incohérences terminologiques mineures entre Axes.boxplot
et Axes.bxp
.
Les paramètres à déconseiller et à supprimer incluent :
usermedians
- traité par 10 SLOC, 3if
blocs, unefor
boucle
conf_intervals
- géré par 15 SLOC, 6if
blocs, unefor
boucle
sym
- traité par 12 SLOC, 4if
blocs
La suppression de l' sym
option permet de déplacer tout le code de gestion des paramètres de style restants vers Axes.bxp
. Cela ne supprime aucune complexité, mais renforce le principe de responsabilité unique entre Axes.bxp
, cbook.boxplot_stats
et Axes.boxplot
.
De plus, le notch
paramètre peut être renommé shownotches
pour être cohérent avec Axes.bxp
. Ce type de nettoyage pourrait être poussé plus loin et les whis
, bootstrap
, autorange
pourraient être intégrés aux kwargs passés au nouveau statfxn
paramètre.
Rétrocompatibilité #
La mise en œuvre de ce MEP entraînerait éventuellement l'obsolescence rétrocompatible, puis la suppression des paramètres de mot-clé
usermedians
, conf_intervals
et sym
. Des recherches rapides sur GitHub ont indiqué que usermedians
, conf_intervals
sont utilisés par quelques utilisateurs, qui semblent tous avoir une très bonne connaissance de matplotlib. Un cycle de dépréciation robuste devrait laisser suffisamment de temps à ces utilisateurs pour migrer vers une nouvelle API.
sym
Cependant, la dépréciation de peut avoir une portée beaucoup plus large dans la base d'utilisateurs de matplotlib .
Horaire #
Une chronologie accélérée pourrait ressembler à ceci :
v2.0.1 ajouter des transformations à
cbook.boxplots_stats
, exposer dansAxes.boxplot
v2.1.0 Dépréciations initiales et utilisation de tableaux NumPy 2D en entrée
Utilisation de tableaux NumPy 2D en entrée. La sémantique autour des tableaux 2D est généralement déroutante.
usermedians
,conf_intervals
,sym
paramètres
v2.2.0
supprimer les paramètres
usermedians
,conf_intervals
,sym
déprécier
notch
en faveur deshownotches
pour être cohérent avec d'autres paramètres etAxes.bxp
- v2.3.0
supprimer le
notch
paramètredéplacer tout le style et la logique de basculement de l'artiste vers
Axes.bxp
telAxes.boxplot
n'est guère plus qu'un courtier entreAxes.bxp
etcbook.boxplots_stats
Impacts anticipés sur les utilisateurs #
Comme décrit ci-dessus, il est obsolète usermedians
et conf_intervals
aura probablement un impact sur quelques utilisateurs. Ceux qui seront impactés sont presque certainement des utilisateurs avancés qui sauront s'adapter au changement.
L'abandon de l' sym
option peut importer plus d'utilisateurs et des efforts doivent être faits pour recueillir les commentaires de la communauté à ce sujet.
Impacts anticipés sur les bibliothèques en aval #
Le code source (maître GitHub au 17/10/2016) a été inspecté pour seaborn et python-ggplot pour voir si ces changements auraient un impact sur leur utilisation. Aucun des paramètres désignés pour suppression dans ce MEP n'est utilisé par seaborn. Les API Seaborn qui utilisent la fonction boxplot de matplotlib permettent à l'utilisateur de passer arbitrairement **kwargs
à l'API de matplotlib. Ainsi, les utilisateurs marins disposant d'installations matplotlib modernes pourront profiter pleinement de toutes les nouvelles fonctionnalités ajoutées à la suite de ce MEP.
Python-ggplot a implémenté sa propre fonction pour dessiner des boxplots. Par conséquent, aucun impact ne peut lui arriver à la suite de la mise en œuvre de ce PEM.
Alternatives #
Variations sur le thème #
Ce MEP peut être divisé en quelques composants faiblement couplés :
Permettre la fonction de transformation pré- et post-calcul dans
cbook.boxplot_stats
Exposer cette transformation dans l'
Axes.boxplot
APISuppression des options statistiques redondantes dans
Axes.boxplot
Déplacement de tous les paramètres de style de traitement de
Axes.boxplot
àAxes.bxp
.
Avec cette approche, #2 dépend et #1, et #4 dépend de #3.
Il y a deux approches possibles pour #2. La première et la plus directe serait de refléter les nouveaux paramètres de
in transform_in
et de les transmettre directement.transform_out
cbook.boxplot_stats
Axes.boxplot
La deuxième approche consisterait à ajouter statfxn
et statfxn_args
des paramètres à Axes.boxplot
. Dans cette implémentation, la valeur par défaut de statfxn
serait cbook.boxplot_stats
, mais les utilisateurs pourraient transmettre leur propre fonction. Alors transform_in
et transform_out
seraient alors passés en tant qu'éléments du statfxn_args
paramètre.
def boxplot_stats(data, ..., transform_in=None, transform_out=None):
if transform_in is None:
transform_in = lambda x: x
if transform_out is None:
transform_out = lambda x: x
output = []
for _d in data:
d = transform_in(_d)
stat_dict = do_stats(d)
for key, value in stat_dict.item():
if key != 'label':
stat_dict[key] = transform_out(value)
output.append(d)
return output
class Axes(...):
def boxplot_option1(data, ..., transform_in=None, transform_out=None):
stats = cbook.boxplot_stats(data, ...,
transform_in=transform_in,
transform_out=transform_out)
return self.bxp(stats, ...)
def boxplot_option2(data, ..., statfxn=None, **statopts):
if statfxn is None:
statfxn = boxplot_stats
stats = statfxn(data, **statopts)
return self.bxp(stats, ...)
Les deux cas permettraient aux utilisateurs d'effectuer les opérations suivantes :
fig, ax1 = plt.subplots()
artists1 = ax1.boxplot_optionX(data, transform_in=np.log,
transform_out=np.exp)
Mais la deuxième option permet à un utilisateur d'écrire une fonction statistique entièrement personnalisée (par exemple, my_box_stats
) avec des intervalles de confiance BCA sophistiqués et des moustaches définies différemment en fonction de certains attributs des données.
Ceci est disponible sous l'API actuelle :
fig, ax1 = plt.subplots()
my_stats = my_box_stats(data, bootstrap_method='BCA',
whisker_method='dynamic')
ax1.bxp(my_stats)
Et serait plus concis avec l'option deux
fig, ax = plt.subplots()
statopts = dict(transform_in=np.log, transform_out=np.exp)
ax.boxplot(data, ..., **statopts)
Les utilisateurs peuvent également transmettre leur propre fonction pour calculer les statistiques :
fig, ax1 = plt.subplots()
ax1.boxplot(data, statfxn=my_box_stats, bootstrap_method='BCA',
whisker_method='dynamic')
D'après les exemples ci-dessus, l'option 2 semble n'avoir qu'un avantage marginal, mais dans le contexte des bibliothèques en aval comme seaborn, son avantage est plus apparent car ce qui suit serait possible sans aucun correctif pour seaborn :
import seaborn
tips = seaborn.load_data('tips')
g = seaborn.factorplot(x="day", y="total_bill", hue="sex", data=tips,
kind='box', palette="PRGn", shownotches=True,
statfxn=my_box_stats, bootstrap_method='BCA',
whisker_method='dynamic')
Ce type de flexibilité était l'intention derrière la division de l'API boxplot globale dans les trois fonctions actuelles. En pratique cependant, les bibliothèques en aval comme seaborn prennent en charge les versions de matplotlib datant bien avant la scission. Ainsi, ajouter un peu plus de flexibilité à
Axes.boxplot
pourrait exposer toutes les fonctionnalités aux utilisateurs des bibliothèques en aval avec une installation moderne de matplotlib sans intervention des responsables de la bibliothèque en aval.
Faire moins #
Une autre alternative évidente consisterait à omettre la fonctionnalité de transformation pré- et post-calcul ajoutée dans cbook.boxplot_stats
et
Axes.boxplot
, et à supprimer simplement les paramètres statistiques et de style redondants, comme décrit ci-dessus.
Ne rien faire #
Comme pour beaucoup de choses dans la vie, ne rien faire est une option ici. Cela signifie que nous préconisons simplement que les utilisateurs et les bibliothèques en aval profitent de la séparation entre cbook.boxplot_stats
et Axes.bxp
et les laissent décider comment fournir une interface à cela.