Plotly y Pandas Combinando fuerzas para una visualización efectiva de datos
Plotly y Pandas se unen para visualización efectiva de datos.
Una guía rápida inspirada en Storytelling with Data
“Mis habilidades de visualización de datos son malas. Mi público parece poco impresionado con mi trabajo y, peor aún, no están convencidos”.
Hubo una vez en la que muchos de nosotros nos encontramos con este problema. A menos que tengas un talento natural o hayas tomado un curso de diseño antes, puede ser bastante desafiante y llevar mucho tiempo producir gráficos visualmente atractivos que sean intuitivos para el público al mismo tiempo.
Esto fue lo que se me ocurrió en aquel entonces: quiero ser más intencional al crear mis gráficos para transmitir información de manera intuitiva a mi público. Con eso quiero decir que no consuman demasiado su capacidad mental y su tiempo solo para entender lo que está sucediendo.
Solía pensar que cambiar de Matplotlib a Seaborn y finalmente a Plotly solucionaría el problema estético. De hecho, estaba equivocado. La visualización no se trata simplemente de estética. A continuación, hay dos visualizaciones que intenté replicar de Storytelling with Data¹ de Cole Nussbaumer Knaflic que realmente me inspiraron a cambiar mi enfoque en la visualización. Se ven limpias, elegantes y con un propósito. ¡Vamos a intentar replicar estos gráficos en este artículo!

Esto es lo que se puede aprender de esta publicación. Si estás buscando una explicación más detallada de los conceptos detrás de una gran visualización, echa un vistazo a Storytelling with Data¹, cada página es una joya que vale la pena leer. Si estás buscando consejos prácticos y específicos sobre herramientas, estás en el lugar correcto. Cole mencionó al inicio de su libro que los consejos que presenta son universales y no dependen de una herramienta en particular, aunque admitió que creó los ejemplos en el libro utilizando Excel. Algunas personas, incluyéndome a mí, no somos fanáticas de Excel y las herramientas de arrastrar y soltar por muchas razones. Algunos prefieren crear visualizaciones utilizando Python, R y otros lenguajes de programación. Si eres parte de este segmento y usas Python como tu herramienta principal, entonces este artículo es para ti.
- Async para LangChain y LLMs
- Crea tu propia aplicación ChatGPT utilizando Spring Boot
- EDA con Polars Guía paso a paso para funciones de agregación y anal...
Tabla de contenidos
- Chaining—Pandas Plot
- Gráfico de barras horizontales
- Gráfico de líneas
- Bonus: Gráfico de números
Chaining—Pandas Plot
Si eres algo experto o un jugador experimentado en el uso de Pandas para el manejo de datos, es posible que te encuentres o incluso adoptes la idea de “Chaining” tú mismo. En resumen, el chaining permite que tu código sea mucho más legible, más fácil de depurar y listo para producción. Aquí tienes un ejemplo sencillo de a qué me refiero. No tienes que leer línea por línea, solo échale un vistazo rápido para entender la idea detrás del “Chaining”. Cada paso es claro y fácil de explicar, y el código está bien organizado sin variables intermedias innecesarias.
(epl_10seasons .rename(columns=lambda df_: df_.strip()) .rename(columns=lambda df_: re.sub('\W+|[!,*)@#%(&$_?.^]', '_', df_)) .pipe(lambda df_: df_.astype({column: 'int8' for column in (df_.select_dtypes("integer").columns.tolist())})) .pipe(lambda df_: df_.astype({column: 'category' for column in (df_.select_dtypes("object").columns.tolist()[:-1])})) .assign(match_date=lambda df_: pd.to_datetime(df_.match_date, infer_datetime_format=True)) .assign(home_team=lambda df_: np.where((df_.home_team == "Arsenal"), "The Gunners", df_.home_team), away_team=lambda df_: np.where((df_.away_team == "Arsenal"), "The Gunners", df_.away_team), month=lambda df_: df_.match_date.dt.month_name()) .query('home_team == "The Gunners"'))
Esto es genial, pero ¿sabías que puedes continuar el proceso de chaining para crear gráficos de visualización básicos también? Pandas Plot, por defecto, utiliza el backend de Matplotlib para este propósito. Veamos cómo funciona y reproduzcamos algunos de los ejemplos que Cole creó en su libro.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.graph_objects as go
%matplotlib inline
pd.options.plotting.backend = 'plotly'
df = pd.DataFrame({"concerns": ["La potencia del motor es menor de lo esperado",
"Los neumáticos hacen ruido excesivo al conducir",
"El motor hace ruido anormal/excesivo",
"Preocupaciones sobre el material de los asientos",
"Ruido excesivo de viento",
"Hesitación o retraso al cambiar de marcha",
"El sistema Bluetooth tiene mala calidad de sonido",
"El sistema de dirección/volante tiene demasiado juego",
"El sistema Bluetooth es difícil de usar",
"Controles de audio/entretenimiento/navegación del asiento delantero"
],
"preocupaciones por cada 1,000": [12.9, 12.3, 11.6, 11.6, 11.0, 10.3, 10.0, 8.8, 8.6, 8.2]},
index=list(range(0,10,1)))
Tenemos un DataFrame que se ve así.

(df .plot .barh())
Esta es la manera más rápida de generar un gráfico de visualización básico. Al encadenar el atributo .plot
y el método .line
directamente desde un DataFrame, obtenemos el siguiente gráfico.

Reserva tu reacción y juicio si piensas que el gráfico anterior no pasa la prueba estética. De hecho, se ve feo, por decir lo menos. Vamos a darle un poco de sabor y hacerlo mejor. Aquí está el truco, cambia el backend de representación de Pandas de Matplotlib a Plotly para la magia que está a punto de desvelarse.
pd.options.plotting.backend = 'plotly'
Puede que te preguntes: “¿Por qué lo cambio a Plotly? ¿No es capaz Matplotlib de hacer lo mismo?” Bueno, aquí está la diferencia.
Si usamos el backend de Matplotlib en Pandas, devuelve un objeto Axes, intenta verificarlo tú mismo usando el método incorporado type()
. Esto es genial porque el objeto axes nos permite acceder a los métodos para modificar aún más nuestro gráfico. Echa un vistazo a esta documentación² para conocer los posibles métodos que se pueden realizar en un objeto Axes. Elije uno para ilustrarlo rápidamente.
(df .plot .barh() .set_xlabel("preocupaciones por cada 1,000"))

Hemos establecido exitosamente la etiqueta del eje x en “preocupaciones por cada 1,000”, pero al hacerlo, obtenemos un objeto Text y perdemos nuestro preciado objeto Axis que nos permite acceder a métodos valiosos para modificar aún más nuestro gráfico. ¡Qué lástima!
Aquí hay una alternativa para evitar la limitación anterior,
(df .plot .barh(xlabel="Preocupaciones por cada 1,000", ylabel="Preocupaciones", title="Top 10 preocupaciones de diseño"))

Sin embargo, todavía no podemos hacer modificaciones extensas ya que la integración está bastante limitada por la implementación de Pandas aquí.
Plotly, por otro lado, no devuelve un objeto Axes. Devuelve un objeto go.Figure
. La diferencia aquí es que los métodos responsables de actualizar los gráficos también te devuelven un objeto go.Figure
, lo que te permite continuar encadenando tu método para actualizar aún más tu gráfico. ¡Vamos a probarlo!
Por cierto, en caso de que te preguntes cómo obtengo las combinaciones de métodos y argumentos que se muestran a continuación, todos están disponibles en la documentación oficial aquí³.
Aquí tienes algunos métodos importantes para que puedas empezar: .update_traces
, .add_traces
, .update_layout
, .update_xaxes
, .update_yaxes
, .add_annotation
, .update_annotations
.
Gráfico de Barras Horizontales
Definamos un conjunto de paletas de colores para nuestra visualización a continuación.
GRAY1, GRAY2, GRAY3 = '#231F20', '#414040', '#555655'GRAY4, GRAY5, GRAY6 = '#646369', '#76787B', '#828282'GRAY7, GRAY8, GRAY9, GRAY10 = '#929497', '#A6A6A5', '#BFBEBE', '#FFFFFF'BLUE1, BLUE2, BLUE3, BLUE4, BLUE5 = '#25436C', '#174A7E', '#4A81BF', '#94B2D7', '#94AFC5'BLUE6, BLUE7 = '#92CDDD', '#2E869D'RED1, RED2, RED3 = '#B14D4A', '#C3514E', '#E6BAB7'GREEN1, GREEN2 = '#0C8040', '#9ABB59'ORANGE1, ORANGE2, ORANGE3 = '#F36721', '#F79747', '#FAC090'gray_palette = [GRAY1, GRAY2, GRAY3, GRAY4, GRAY5, GRAY6, GRAY7, GRAY8, GRAY9, GRAY10]blue_palette = [BLUE1, BLUE2, BLUE3, BLUE4, BLUE5, BLUE6, BLUE7]red_palette = [RED1, RED2, RED3]green_palette = [GREEN1, GREEN2]orange_palette = [ORANGE1, ORANGE2, ORANGE3]sns.set_style("darkgrid")sns.set_palette(gray_palette)sns.palplot(sns.color_palette())

Aquí, queremos resaltar las preocupaciones que son iguales o superiores al 10 por ciento mediante la definición de un color separado.
color = np.array(['rgb(255,255,255)']*df.shape[0])color[df .set_index("concerns", drop=True) .iloc[::-1] ["concerns per 1,000"]>=10] = red_palette[0]color[df .set_index("concerns", drop=True) .iloc[::-1] ["concerns per 1,000"]<10] = gray_palette[4]
Luego creamos el gráfico directamente desde el DataFrame.
(df .set_index("concerns", drop=True) .iloc[::-1] .plot .barh() .update_traces(marker=dict(color=color.tolist())))

Actualizar el diseño produce lo siguiente. Aquí, especificamos la plantilla, agregamos un título y un margen a nuestro gráfico, y especificamos el tamaño de nuestro objeto figura. Comentemos sobre las anotaciones por el momento.
(df .set_index("concerns", drop=True) .iloc[::-1] .plot .barh() .update_traces(marker=dict(color=color.tolist())) .update_layout(template="plotly_white", title=dict(text="<b>Principales 10 preocupaciones de diseño</b> <br><sup><i>preocupaciones por 1,000</i></sup>", font_size=30, font_color=gray_palette[4]), margin=dict(l=50, r=50, b=50, t=100, pad=20), width=1000, height=800, showlegend=False, #annotations=annotations ))

Actualizando las propiedades del eje x e y se obtiene lo siguiente.
(df .set_index("preocupaciones", drop=True) .iloc[::-1] .plot .barh() .update_traces(marker=dict(color=color.tolist())) .update_layout(template="plotly_white", title=dict(text="<b>Principales 10 preocupaciones de diseño</b> <br><sup><i>preocupaciones por cada 1,000</i></sup>", font_size=30, font_color=gray_palette[4]), margin=dict(l=50, r=50, b=50, t=100, pad=20), width=1000, height=800, showlegend=False, #annotations=annotations ) .update_xaxes(title_standoff=10, showgrid=False, visible=False, tickfont=dict( family='Arial', size=16, color=gray_palette[4],), title="") .update_yaxes(title_standoff=10, tickfont=dict( family='Arial', size=16, color=gray_palette[4],), title=""))

Por último, agregaremos algunas anotaciones a nuestro gráfico. Aquí, tenemos algunas anotaciones: agregar etiquetas de datos al gráfico de barras horizontales y una nota al pie. Hagámoslo juntos. Primero, definimos las anotaciones en una celda separada.
annotations = []y_s = np.round(df["preocupaciones por cada 1,000"], decimals=2)# Agregar etiquetas de datosfor yd, xd in zip(y_s, df.preocupaciones): # etiquetar la barra de valor neto annotations.append(dict(xref='x1', yref='y1', y=xd, x=yd - 1, text=str(yd) + '%', font=dict(family='Arial', size=16, color=gray_palette[-1]), showarrow=False)) # Agregar anotaciones de origenannotations.append(dict(xref='paper', yref='paper', x=-0.72, y=-0.050, text='Fuente: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco' '<br>laboris nisi ut aliquip ex ea commodo consequat.', font=dict(family='Arial', size=10, color=gray_palette[4]), showarrow=False, align='left'))
(df .set_index("preocupaciones", drop=True) .iloc[::-1] .plot .barh() .update_traces(marker=dict(color=color.tolist())) .update_layout(template="plotly_white", title=dict(text="<b>Principales 10 preocupaciones de diseño</b> <br><sup><i>preocupaciones por cada 1,000</i></sup>", font_size=30, font_color=gray_palette[4]), margin=dict(l=50, r=50, b=50, t=100, pad=20), width=1000, height=800, showlegend=False, annotations=annotations ) .update_xaxes(title_standoff=10, showgrid=False, visible=False, tickfont=dict( family='Arial', size=16, color=gray_palette[4],), title="") .update_yaxes(title_standoff=10, tickfont=dict( family='Arial', size=16, color=gray_palette[4],), title=""))

¿No es este un gráfico mucho mejor en comparación con la versión predeterminada inicial? Sigamos explorando otro gráfico popular: el gráfico de líneas.
Solo una advertencia de que el ejemplo a continuación es más complicado que el anterior. Sin embargo, la idea sigue siendo la misma.
Gráfico de Líneas
Echemos un vistazo rápido a la interfaz de trazado predeterminada de Matplotlib para el gráfico de líneas.
pd.options.plotting.backend = 'matplotlib'df = pd.DataFrame({"Recibidos": [160,184,241,149,180,161,132,202,160,139,149,177], "Procesados":[160,184,237,148,181,150,123,156,126,104,124,140]}, index=['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'])(df .plot .line());

¡Cambiemos nuestra interfaz de trazado a Plotly!
pd.options.plotting.backend = 'plotly'(df .plot(x=df.index, y=df.Recibidos, labels=dict(index="", value="Número de entradas"),))
Después de cambiar la interfaz de trazado de Pandas a Plotly, el código anterior nos proporciona lo siguiente. Aquí, empezamos trazando solo la Serie Recibidos.

Actualicemos la propiedad de la línea agregando más cadenas al método anterior. Aquí, modificamos el color, el ancho y colocamos marcadores en los puntos de datos.
(df .plot(x=df.index, y=df.Recibidos, labels=dict(index="", value="Número de entradas"),) .update_traces(go.Scatter(mode='lines+markers+text', line={"color": gray_palette[4], "width":4}, marker=dict(size=12)),))

¡Agreguemos la Serie Procesados al gráfico!
(df .plot(x=df.index, y=df.Recibidos, labels=dict(index="", value="Número de entradas"),) .update_traces(go.Scatter(mode='lines+markers+text', line={"color": gray_palette[4], "width":4}, marker=dict(size=12)),) .add_traces(go.Scatter(x=df.index, #Agregar columna Procesados y=df.Procesados, mode="lines+markers+text", line={"color": blue_palette[0], "width":4}, marker=dict(size=12))))

¡Agreguemos una línea vertical en el índice Mayo para mostrar el punto en el que las dos líneas comienzan a divergir!
(df .plot(x=df.index, y=df.Recibidos, labels=dict(index="", value="Número de entradas"),) .update_traces(go.Scatter(mode='lines+markers+text', line={"color": gray_palette[4], "width":4}, marker=dict(size=12)),) .add_traces(go.Scatter(x=df.index, #Agregar columna Procesados y=df.Procesados, mode="lines+markers+text", line={"color": blue_palette[0], "width":4}, marker=dict(size=12))) .add_traces(go.Scatter(x=["Mayo", "Mayo"], #Agregar vline y=[0,230], fill="toself", mode="lines", line_width=0.5, line_color= gray_palette[4])))

A continuación, vamos a actualizar el diseño general cambiando el fondo a blanco, y agregando el título, margen y otros elementos. Para las anotaciones, las comentaremos por el momento.
(df .plot(x=df.index, y=df.Recibido, labels=dict(index="", value="Número de tickets"),) .update_traces(go.Scatter(mode='lines+markers+text', line={"color": gray_palette[4], "width":4}, marker=dict(size=12)),) .add_traces(go.Scatter(x=df.index, #Agregar columna Procesado y=df.Procesado, mode="lines+markers+text", line={"color": blue_palette[0], "width":4}, marker=dict(size=12))) .add_traces(go.Scatter(x=["Mayo", "Mayo"], #Agregar vline y=[0,230], fill="toself", mode="lines", line_width=0.5, line_color= gray_palette[4])) .update_layout(template="plotly_white", title=dict(text="<b>Por favor, apruebe la contratación de 2 FTEs</b> <br><sup>para cubrir las vacantes de quienes renunciaron en el último año</sup> <br>Volumen de tickets a lo largo del tiempo <br><br><br>", font_size=30,), margin=dict(l=50, r=50, b=100, t=200,), width=900, height=700, yaxis_range=[0, 300], showlegend=False, #annotations=right_annotations, ))

A continuación, realizaremos una actualización tanto en los ejes x como en los ejes y.
(df .plot(x=df.index, y=df.Recibido, labels=dict(index="", value="Número de tickets"),) .update_traces(go.Scatter(mode='lines+markers+text', line={"color": gray_palette[4], "width":4}, marker=dict(size=12)),) .add_traces(go.Scatter(x=df.index, #Agregar columna Procesado y=df.Procesado, mode="lines+markers+text", line={"color": blue_palette[0], "width":4}, marker=dict(size=12))) .add_traces(go.Scatter(x=["Mayo", "Mayo"], #Agregar vline y=[0,230], fill="toself", mode="lines", line_width=0.5, line_color= gray_palette[4])) .update_layout(template="plotly_white", title=dict(text="<b>Por favor, apruebe la contratación de 2 FTEs</b> <br><sup>para cubrir las vacantes de quienes renunciaron en el último año</sup> <br>Volumen de tickets a lo largo del tiempo <br><br><br>", font_size=30,), margin=dict(l=50, r=50, b=100, t=200,), width=900, height=700, yaxis_range=[0, 300], showlegend=False, #annotations=right_annotations, ) .update_xaxes(dict(range=[0, 12], showline=True, showgrid=False, linecolor=gray_palette[4], linewidth=2, ticks='', tickfont=dict( family='Arial', size=13, color=gray_palette[4], ), )) .update_yaxes(dict(showline=True, showticklabels=True, showgrid=False, ticks='outside', linecolor=gray_palette[4], linewidth=2, tickfont=dict( family='Arial', size=13, color=gray_palette[4], ), title_text="Número de tickets" )))

Por último, agregaremos algunas anotaciones a nuestro gráfico. Aquí, tenemos algunas anotaciones: agregar etiquetas al gráfico de líneas (Recibido, Procesado), así como agregar etiquetas a los puntos dispersos, lo cual puede ser un poco complicado. Hagámoslo juntos. Primero, definimos las anotaciones en una celda separada.
y_data = df.to_numpy()colors = [gray_palette[3], blue_palette[0]]labels = df.columns.to_list()right_annotations = []# Agregar etiquetas a la líneafor y_trace, label, color in zip(y_data[-1], labels, colors): right_annotations.append(dict(xref='paper', x=0.95, y=y_trace, xanchor='left', yanchor='middle', text=label, font=dict(family='Arial',size=16,color=color), showarrow=False))# Agregar etiquetas a los puntos dispersosscatter_annotations = []y_received = [each for each in df.Received]y_processed = [float(each) for each in df.Processed]x_index = [each for each in df.index]y_r = np.round(y_received)y_p = np.rint(y_processed)for ydn, yd, xd in zip(y_r[-5:], y_p[-5:], x_index[-5:]): scatter_annotations.append(dict(xref='x2 domain', yref='y2 domain', y=ydn, x=xd, text='{:,}'.format(ydn), font=dict(family='Arial',size=16,color=gray_palette[4]), showarrow=False, xanchor='center', yanchor='bottom', )) scatter_annotations.append(dict(xref='x2 domain', yref='y2 domain', y=yd, x=xd, text='{:,}'.format(yd), font=dict(family='Arial',size=16,color=blue_palette[0]), showarrow=False, xanchor='center', yanchor='top', ))
Después de definir las anotaciones, solo necesitamos poner la variable de anotación dentro del método de concatenación como se muestra a continuación.
(df .plot(x=df.index, y=df.Received, labels=dict(index="", value="Número de tickets"),) .update_traces(go.Scatter(mode='lines+markers+text', line={"color": gray_palette[4], "width":4}, marker=dict(size=12)),) .add_traces(go.Scatter(x=df.index, #Agregar la columna Processed y=df.Processed, mode="lines+markers+text", line={"color": blue_palette[0], "width":4}, marker=dict(size=12))) .add_traces(go.Scatter(x=["May", "May"], #Agregar una línea vertical y=[0,230], fill="toself", mode="lines", line_width=0.5, line_color= gray_palette[4])) .update_layout(template="plotly_white", title=dict(text="<b>Por favor apruebe la contratación de 2 empleados a tiempo completo</b> <br><sup>para cubrir las vacantes de los que renunciaron en el último año</sup> <br>Volumen de tickets a lo largo del tiempo <br><br><br>", font_size=30,), margin=dict(l=50, r=50, b=100, t=200,), width=900, height=700, yaxis_range=[0, 300], showlegend=False, annotations=right_annotations, ) .update_layout(annotations=scatter_annotations * 2) .update_xaxes(dict(range=[0, 12], showline=True, showgrid=False, linecolor=gray_palette[4], linewidth=2, ticks='', tickfont=dict( family='Arial', size=13, color=gray_palette[4], ), )) .update_yaxes(dict(showline=True, showticklabels=True, showgrid=False, ticks='outside', linecolor=gray_palette[4], linewidth=2, tickfont=dict( family='Arial', size=13, color=gray_palette[4], ), title_text="Número de tickets" )) .add_annotation(dict(text="<b>2 empleados renunciaron en mayo.</b> Casi pudimos mantener el volumen de tickets entrantes <br>en los dos meses siguientes, pero nos quedamos atrás con el aumento en agosto <br>y no hemos podido ponernos al día desde entonces.", font_size=18, align="left", x=7.5, y=265, showarrow=False)) .add_annotation(dict(xref='paper', yref='paper', x=0.5, y=-0.15, text='Fuente: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco' '<br>laboris nisi ut aliquip ex ea commodo consequat.', font=dict(family='Arial', size=10, color='rgb(150,150,150)'), showarrow=False, align='left')) .update_annotations(yshift=0) .show())

Bonus: Tabla de números
¡Felicitaciones por llegar a esta parte del artículo! ¡Aquí hay un gráfico adicional para que te lleves! Aquí estamos creando una tabla para presentar estéticamente un número por sí mismo. En resumen, a esto me refiero.

Dado que este no es un resultado de un DataFrame, podemos comenzar creando un objeto vacío go.Figure
desde cero, y luego agregar gradualmente las anotaciones. Luego, finalizamos actualizando el diseño en consecuencia.
(go .Figure() # Crear una figura vacía .add_annotation( x=0.0, y=1, text='El programa piloto fue un éxito', showarrow=False, font={'size': 36, 'color': 'white'}, bgcolor=gray_palette[-3], bordercolor='gray', borderwidth=0, xref='paper', yref='paper', xanchor='left', yanchor='top', align='left', ax=0, ay=-10 ) .add_annotation( x=-1.0, # Coordenada X de la posición del texto y=3.0, # Coordenada Y de la posición del texto text="Después del programa piloto,", # Contenido del texto showarrow=False, # Ocultar la flecha font=dict(size=20, color=blue_palette[1]), # Personalizar el tamaño de la fuente xanchor='left', yanchor='top', align='left', ) .add_annotation( x=-1.0, # Coordenada X de la posición del texto y=1.6, # Coordenada Y de la posición del texto text="<b>68%</b>", # Contenido del texto showarrow=False, # Ocultar la flecha font=dict(size=160, color=blue_palette[1]), # Personalizar el tamaño de la fuente xanchor='left', align='left', ) .add_annotation( x=-1.0, # Coordenada X de la posición del texto y=0.2, # Coordenada Y de la posición del texto text="<b>de los niños expresaron interés hacia la ciencia,</b>", # Contenido del texto showarrow=False, # Ocultar la flecha font=dict(size=20, color=blue_palette[1]), # Personalizar el tamaño de la fuente xanchor='left', align='left', ) .add_annotation( x=-1.0, # Coordenada X de la posición del texto y=-0.2, # Coordenada Y de la posición del texto text="en comparación con el 44% al comienzo del programa.", # Contenido del texto showarrow=False, # Ocultar la flecha font=dict(size=20, color=gray_palette[-3]), # Personalizar el tamaño de la fuente xanchor='left', align='left', ) .add_annotation( x=-1.0, # Coordenada X de la posición del texto y=-0.7, # Coordenada Y de la posición del texto text='Basado en una encuesta de 100 estudiantes ' 'realizada antes y después del programa piloto ' '(tasa de respuesta del 100% en ambas encuestas).', # Contenido del texto showarrow=False, # Ocultar la flecha font=dict(size=10.5, color=gray_palette[-3]), # Personalizar el tamaño de la fuente xanchor='left', align='left', ) .update_layout( xaxis=dict(visible=False), # Ocultar el eje x yaxis=dict(visible=False), # Ocultar el eje y margin=dict(l=0, r=0, b=0, t=0, pad=0), font=dict(size=26, color=gray_palette[-3]), # Personalizar el tamaño de la fuente paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)' ) .show())
Epílogo
¡Ahí lo tienes! La clave es actualizar y refinar tu gráfico paso a paso hasta obtener un resultado deseable. Por supuesto, cada técnica tiene sus propias limitaciones. Si tu gráfico se está volviendo demasiado complicado de producir, podría ser beneficioso recurrir a Plotly Express o incluso construir todo desde cero utilizando Plotly Graph Objects. Puede parecer difícil y desconocido adoptar esta técnica al principio, ¡pero sigue practicando y pronto crearás visualizaciones hermosas que tienen sentido!
Si encuentras algo útil en este artículo, considera seguirme en VoAGI. ¡Fácil, 1 artículo a la semana para mantenerte actualizado y estar un paso adelante!
¡Conéctate conmigo!
- LinkedIn 👔
- Twitter 🖊
Referencias
- Storytelling with Data de Cole Nussbaumer Knaflic. https://www.storytellingwithdata.com/books
- API de Axes de Matplotlib. https://matplotlib.org/stable/api/axes_api.html
- Bibliotecas de gráficos de Plotly. https://plotly.com/python/reference/