MEP28: Eliminar la complejidad de Axes.boxplot #
Estado #
Discusión
Sucursales y solicitudes de extracción #
A continuación se enumeran los RP abiertos o sucursales relacionadas con este eurodiputado:
Desactive los kwargs estadísticos redundantes en
Axes.boxplot
: https://github.com/phobson/matplotlib/tree/MEP28-initial-deprecationsDesactive las opciones de estilo redundantes en
Axes.boxplot
: https://github.com/phobson/matplotlib/tree/MEP28-initial-deprecationsDesaprobar pasar matrices 2D NumPy como entrada: Ninguno
Agregue opciones de procesamiento previo y posterior a
cbook.boxplot_stats
: https://github.com/phobson/matplotlib/tree/boxplot-stat-transformsExponer
cbook.boxplot_stats
a travésAxes.boxplot
de kwargs: NingunoEliminar kwargs estadísticos redundantes en
Axes.boxplot
: NingunoEliminar opciones de estilo redundantes en
Axes.boxplot
: NingunoElementos restantes que surgen a través de la discusión: Ninguno
Resumen #
En los últimos lanzamientos, el Axes.boxplot
método ha crecido en complejidad para admitir el estilo de artista y el cálculo estadístico totalmente personalizables. Esto llevó a Axes.boxplot
que se dividiera en varias partes. Las estadísticas necesarias para dibujar un diagrama de caja se calculan en
cbook.boxplot_stats
, mientras que los artistas reales se dibujan en Axes.bxp
. El método original Axes.boxplot
sigue siendo la API más pública que maneja el paso de los datos proporcionados por el usuario cbook.boxplot_stats
, la alimentación de los resultados Axes.bxp
y el preprocesamiento de la información de estilo para cada faceta de los diagramas de caja.
Este eurodiputado delineará un camino a seguir para revertir la complejidad adicional y simplificar la API mientras mantiene una compatibilidad con versiones anteriores razonable.
Descripción detallada #
Actualmente, el Axes.boxplot
método acepta parámetros que permiten a los usuarios especificar medianas e intervalos de confianza para cada caja que se dibujará en el gráfico. Estos se proporcionaron para que los usuarios avanzados pudieran proporcionar estadísticas calculadas de una manera diferente al método simple proporcionado por matplotlib. Sin embargo, manejar esta entrada requiere una lógica compleja para asegurarse de que las formas de la estructura de datos coincidan con lo que se necesita dibujar. Por el momento, esa lógica contiene 9 instrucciones if/else separadas anidadas hasta 5 niveles de profundidad con un bucle for, y puede generar hasta 2 errores. Estos parámetros se agregaron antes de la creación del Axes.bxp
método, que dibuja diagramas de caja de una lista de diccionarios que contienen las estadísticas relevantes. Matplotlib también proporciona una función que calcula estas estadísticas a través decbook.boxplot_stats
. Tenga en cuenta que los usuarios avanzados ahora pueden a) escribir su propia función para calcular las estadísticas requeridas por
Axes.bxp
, o b) modificar el resultado devuelto por cbook.boxplots_stats
para personalizar completamente la posición de los artistas de las tramas. Con esta flexibilidad, los parámetros para especificar manualmente solo las medianas y sus intervalos de confianza permanecen para la compatibilidad con versiones anteriores.
Casi al mismo tiempo que los dos roles de Axes.boxplot
se dividieron en
cbook.boxplot_stats
computación y Axes.bxp
dibujo, ambos
Axes.boxplot
y Axes.bxp
se escribieron para aceptar parámetros que alternan individualmente el dibujo de todos los componentes de los diagramas de caja y parámetros que configuran individualmente el estilo de esos artistas. Sin embargo, para mantener la compatibilidad con versiones anteriores, se mantuvo el sym
parámetro (anteriormente utilizado para especificar el símbolo de los volantes). Este parámetro en sí requiere una lógica bastante compleja para conciliar los sym
parámetros con el flierprops
parámetro más nuevo en el estilo predeterminado especificado por matplotlibrc
.
Este eurodiputado busca simplificar drásticamente la creación de diagramas de caja para usuarios novatos y avanzados por igual. Es importante destacar que los cambios propuestos aquí también estarán disponibles para paquetes posteriores como seaborn, ya que seaborn inteligentemente permite a los usuarios pasar diccionarios arbitrarios de parámetros a través de la API de seaborn a las funciones subyacentes de matplotlib.
Esto se logrará de la siguiente manera:
cbook.boxplot_stats
se modificará para permitir que se pasen funciones de transformación previas y posteriores al cálculo (por ejemplo,np.log
ynp.exp
para datos distribuidos lognormalmente)
Axes.boxplot
se modificará para aceptarlos y pasarlos ingenuamente acbook.boxplots_stats
(Alt: pasar la función stat y un dict de sus parámetros opcionales).Los parámetros obsoletos de
Axes.boxplot
quedarán en desuso y luego se eliminarán.
Importancia #
Dado que los límites de los bigotes se calculan aritméticamente, existe una suposición implícita de normalidad en los diagramas de caja y bigotes. Esto afecta principalmente qué puntos de datos se clasifican como valores atípicos.
Permitir transformaciones a los datos y los resultados utilizados para dibujar diagramas de caja permitirá a los usuarios optar por no participar en esa suposición si se sabe que los datos no se ajustan a una distribución normal.
A continuación, se muestra un ejemplo de cómo se Axes.boxplot
clasifican los valores atípicos de los datos lognormales de manera diferente según uno de estos tipos de transformaciones.
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()
( Código fuente , png )
Implementación #
Pasar funciones de transformación a cbook.boxplots_stats
#
Este eurodiputado propone que se agreguen dos parámetros (p. ej., transform_in
y
transform_out
a la función de libro de recetas que calcula las estadísticas para la función de gráfico de caja). Estos serán argumentos opcionales de solo palabras clave y se pueden configurar fácilmente como no operativos cuando el usuario los omite. La función se aplicará a los datos a medida que la función recorre cada subconjunto de los datos que se le pasan.Después de calcular la lista de diccionarios de estadísticas, la
función se aplica a cada valor en los diccionarios.lambda x: x
transform_in
boxplot_stats
transform_out
Estas transformaciones se pueden agregar a la firma de llamada
Axes.boxplot
con poco impacto en la complejidad de ese método. Esto se debe a que se pueden pasar directamente a cbook.boxplot_stats
. Alternativamente, Axes.boxplot
podría modificarse para aceptar una función estadística opcional kwarg y un diccionario de parámetros para pasarle directamente.
En este punto de la implementación, los usuarios y las bibliotecas externas como seaborn tendrían un control total a través del Axes.boxplot
método. Más importante aún, al menos, seaborn no requeriría cambios en su API para permitir que los usuarios aprovechen estas nuevas opciones.
Simplificaciones a la Axes.boxplot
API y otras funciones #
La simplificación del método de diagrama de caja consiste principalmente en desaprobar y luego eliminar los parámetros redundantes. Opcionalmente, un próximo paso incluiría la rectificación de inconsistencias terminológicas menores entre Axes.boxplot
y Axes.bxp
.
Los parámetros que serán obsoletos y eliminados incluyen:
usermedians
- procesado por 10 SLOC, 3if
bloques, unfor
bucle
conf_intervals
- manejado por 15 SLOC, 6if
bloques, unfor
bucle
sym
- procesado por 12 SLOC, 4if
bloques
Eliminar la sym
opción permite que todo el código en el manejo de los parámetros de estilo restantes se mueva a Axes.bxp
. Esto no elimina ninguna complejidad, pero refuerza el principio de responsabilidad única entre Axes.bxp
, cbook.boxplot_stats
y Axes.boxplot
.
Además, notch
se podría cambiar el nombre del parámetro shownotches
para que sea coherente con Axes.bxp
. Este tipo de limpieza podría llevarse un paso más allá y el whis
, bootstrap
, autorange
podría incorporarse a los kwargs pasados al nuevo statfxn
parámetro.
Compatibilidad con versiones anteriores #
La implementación de este MEP eventualmente resultaría en la desaprobación incompatible con versiones anteriores y luego en la eliminación de los parámetros de palabra clave
usermedians
, conf_intervals
y sym
. Las búsquedas rápidas en GitHub indicaron que son utilizados por pocos usuarios usermedians
, conf_intervals
quienes parecen tener un conocimiento muy sólido de matplotlib. Un ciclo de desuso sólido debería proporcionar tiempo suficiente para que estos usuarios migren a una nueva API.
sym
Sin embargo, la desaprobación puede tener un alcance mucho más amplio en la base de usuarios de matplotlib .
Horario #
Una línea de tiempo acelerada podría tener el siguiente aspecto:
v2.0.1 agregar transformaciones a
cbook.boxplots_stats
, exponer enAxes.boxplot
v2.1.0 Obsolescencias iniciales y uso de matrices 2D NumPy como entrada
Usando matrices 2D NumPy como entrada. La semántica en torno a las matrices 2D suele ser confusa.
usermedians
,conf_intervals
,sym
parámetros
v2.2.0
eliminar
usermedians
,conf_intervals
,sym
parámetrosdesaprobar
notch
a favor deshownotches
ser consistente con otros parámetros yAxes.bxp
- v2.3.0
eliminar
notch
parámetromover todo el estilo y la lógica de alternancia del artista a
Axes.bxp
talAxes.boxplot
es poco más que un intermediario entreAxes.bxp
ycbook.boxplots_stats
Impactos previstos para los usuarios #
Como se describió anteriormente, es obsoleto usermedians
y conf_intervals
probablemente afectará a pocos usuarios. Los que se verán afectados son casi con certeza usuarios avanzados que podrán adaptarse al cambio.
Desactivar la sym
opción puede importar más usuarios y se debe hacer un esfuerzo para recopilar comentarios de la comunidad al respecto.
Impactos previstos para las bibliotecas secundarias #
Se inspeccionó el código fuente (maestro de GitHub a partir del 17 de octubre de 2016) en busca de seaborn y python-ggplot para ver si estos cambios afectarían su uso. Ninguno de los parámetros propuestos para su eliminación en este MEP son utilizados por la navegación marítima. Las API marinas que utilizan la función boxplot de matplotlib permiten que los usuarios pasen arbitrariamente **kwargs
a través de la API de matplotlib. Por lo tanto, los usuarios marinos con instalaciones modernas de matplotlib podrán aprovechar al máximo las nuevas funciones agregadas como resultado de este MEP.
Python-ggplot ha implementado su propia función para dibujar diagramas de caja. Por lo tanto, ningún impacto puede tener como resultado de la implementación de este MEP.
Alternativas #
Variaciones sobre el tema #
Este eurodiputado se puede dividir en unos pocos componentes débilmente acoplados:
Permitiendo la función de transformación previa y posterior al cálculo en
cbook.boxplot_stats
Exponiendo esa transformación en la
Axes.boxplot
APIEliminar opciones estadísticas redundantes en
Axes.boxplot
Cambiar todo el procesamiento de parámetros de estilo de
Axes.boxplot
aAxes.bxp
.
Con este enfoque, el n.° 2 depende del n.° 1, y el n.° 4 depende del n.° 3.
Hay dos enfoques posibles para el #2. La primera y más directa sería reflejar los nuevos parámetros
transform_in
y pasarlos directamente.transform_out
cbook.boxplot_stats
Axes.boxplot
El segundo enfoque sería agregar statfxn
y statfxn_args
parámetros a Axes.boxplot
. Bajo esta implementación, el valor predeterminado de statfxn
sería cbook.boxplot_stats
, pero los usuarios podrían pasar su propia función. Luego transform_in
y transform_out
luego se pasarían como elementos del statfxn_args
parámetro.
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, ...)
Ambos casos permitirían a los usuarios hacer lo siguiente:
fig, ax1 = plt.subplots()
artists1 = ax1.boxplot_optionX(data, transform_in=np.log,
transform_out=np.exp)
Pero la opción dos le permite al usuario escribir una función estadística completamente personalizada (por ejemplo, my_box_stats
) con intervalos de confianza BCA elegantes y los bigotes configurados de manera diferente según algún atributo de los datos.
Esto está disponible bajo la API actual:
fig, ax1 = plt.subplots()
my_stats = my_box_stats(data, bootstrap_method='BCA',
whisker_method='dynamic')
ax1.bxp(my_stats)
Y sería más conciso con la opción dos
fig, ax = plt.subplots()
statopts = dict(transform_in=np.log, transform_out=np.exp)
ax.boxplot(data, ..., **statopts)
Los usuarios también pueden pasar su propia función para calcular las estadísticas:
fig, ax1 = plt.subplots()
ax1.boxplot(data, statfxn=my_box_stats, bootstrap_method='BCA',
whisker_method='dynamic')
De los ejemplos anteriores, la Opción Dos parece tener solo un beneficio marginal, pero en el contexto de las bibliotecas posteriores como seaborn, su ventaja es más evidente ya que lo siguiente sería posible sin parches para 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')
Este tipo de flexibilidad fue la intención detrás de dividir la API de diagrama de caja general en las tres funciones actuales. Sin embargo, en la práctica, las bibliotecas posteriores, como las versiones de soporte marítimo de matplotlib, se remontan mucho antes de la división. Por lo tanto, agregar un poco más de flexibilidad
Axes.boxplot
podría exponer toda la funcionalidad a los usuarios de las bibliotecas posteriores con la instalación moderna de matplotlib sin la intervención de los mantenedores de bibliotecas posteriores.
Haciendo menos #
Otra alternativa obvia sería omitir la funcionalidad de transformación agregada antes y después del cálculo en cbook.boxplot_stats
y
Axes.boxplot
, y simplemente eliminar los parámetros estadísticos y de estilo redundantes como se describió anteriormente.
sin hacer nada #
Como con muchas cosas en la vida, no hacer nada es una opción aquí. Esto significa que simplemente abogamos por que los usuarios y las bibliotecas secundarias aprovechen la división entre cbook.boxplot_stats
y Axes.bxp
y les permitamos decidir cómo proporcionar una interfaz para eso.