Violin Plot

Python
code
Visualization
Author

Marco Aguirre

Published

September 17, 2025

Un gráfico de violín es una técnica de visualización de datos que combina elementos de un boxplot (o gráfico de caja y bigotes) con la representación de la densidad de probabilidad de los datos.
Mientras que el boxplot resume una distribución en cuartiles, mediana y valores extremos, el gráfico de violín añade la forma de la distribución mediante un estimador de densidad kernel, lo que permite observar si los datos presentan asimetrías, picos múltiples (modas) o distribuciones inusuales.

Componentes comunes de un boxplot y un violin plot

0.1 Descripción

  • La anchura del “violín” en cada altura refleja la densidad de probabilidad de los datos en ese rango de valores.
  • Incluye un boxplot interno que marca la mediana y los cuartiles.
  • Puede mostrar también todos los puntos de datos individuales, si la muestra no es demasiado grande.
  • Al colocar varios violines lado a lado, es posible comparar cómo cambia la distribución entre grupos o categorías.

0.2 Utilidad

  • Permite visualizar la forma completa de la distribución en lugar de limitarse a medidas de resumen.
  • Facilita la detección de asimetrías, concentraciones de datos y distribuciones multimodales.
  • Es especialmente útil en grandes conjuntos de datos, donde graficar todas las observaciones es inviable.
  • Combina la capacidad de síntesis del boxplot con la riqueza visual de un histograma suavizado.

0.3 Errores Comunes

  1. Pocos grupos: si solo se comparan dos o tres categorías, puede ser más adecuado un gráfico tipo ridgeline.
  2. Tamaños de muestra muy diferentes: conviene señalarlo explícitamente para evitar malas interpretaciones.
  3. No ordenar los violines por la mediana u otro criterio relevante puede dificultar la comparación entre categorías.

1 Dataset: Precios Agroindustria de Cacao (2012 - 2025)

Archivo: MAG_PreciosAgroindustriaCacao_2025Junio.csv
Fuente: Ministerio de Agricultura y Ganadería (MAG), Ecuador
Última actualización: Junio 2025

import pandas as pd
import plotly.express as px
import plotly.io as pio
import numpy as np
pio.renderers.default = "notebook"
import pandas as pd
df = pd.read_csv("mag_preciosagroindustriacacao_2025junio.csv", sep=";")
print(df.head())
print(df.info())
   PACC_ANIO PACC_MES DPA_PROVINCIA DPA_CANTON        PACC_PRODUCTO  \
0       2012    Enero        El Oro  Arenillas  Cacao seco mezclado   
1       2012    Enero        El Oro  Arenillas  Cacao seco mezclado   
2       2012    Enero        El Oro   El Guabo  Cacao seco mezclado   
3       2012    Enero        El Oro   El Guabo  Cacao seco mezclado   
4       2012    Enero        El Oro    Machala  Cacao seco mezclado   

          PACC_PRESENTACION PACC_TIPO  PACC_PRECIO_USD  PACC_USD_KG  
0  Quintal de 100,00 libras    Compra            71.41         1.57  
1  Quintal de 100,00 libras     Venta            74.06         1.63  
2  Quintal de 100,00 libras    Compra            73.75         1.63  
3  Quintal de 100,00 libras     Venta            84.00         1.85  
4  Quintal de 100,00 libras    Compra            75.00         1.65  
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 26246 entries, 0 to 26245
Data columns (total 9 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   PACC_ANIO          26246 non-null  int64  
 1   PACC_MES           26246 non-null  object 
 2   DPA_PROVINCIA      26246 non-null  object 
 3   DPA_CANTON         26246 non-null  object 
 4   PACC_PRODUCTO      26246 non-null  object 
 5   PACC_PRESENTACION  26246 non-null  object 
 6   PACC_TIPO          26246 non-null  object 
 7   PACC_PRECIO_USD    26246 non-null  float64
 8   PACC_USD_KG        26246 non-null  float64
dtypes: float64(2), int64(1), object(6)
memory usage: 1.8+ MB
None

2 Iteración 1

import plotly.express as px

# Opción A — Un solo violín
fig = px.violin(
    df,
    y="PACC_PRECIO_USD",                 # la variable numérica va en 'y'
    box=True,                            # muestra boxplot interno (mediana y cuartiles)
    points="all",                        # muestra puntos individuales (opcional)
    title="Violin Plot de Precio USD Cacao",
    labels={"PACC_PRECIO_USD": "Precio en USD Cacao"}
)
fig.show()
import plotly.express as px

# Opción A — Un solo violín
fig = px.violin(
    df,
    y="PACC_PRECIO_USD",                 
    box=True,                            
    title="Violin Plot de Precio USD Cacao",
    labels={"PACC_PRECIO_USD": "Precio en USD Cacao"}
)
fig.show()

3 Iteración 2

import plotly.express as px

fig = px.violin(
    df,
    x="PACC_ANIO",             # agrupa por año
    y="PACC_PRECIO_USD",       # valores numéricos
    box=True,                  # muestra boxplot interno
    points="outliers",         # solo muestra outliers
    title="Violin Plot de Precio USD Cacao por Año",
    labels={
        "PACC_ANIO": "Año",
        "PACC_PRECIO_USD": "Precio en USD Cacao"
    }
)

# Fondo blanco
fig.update_layout(
    plot_bgcolor="white",
    paper_bgcolor="white"
)

# Cambiar color de puntos (outliers)
fig.update_traces(
    marker=dict(
        color="red",        # color para los puntos (outliers)
        line=dict(color="red", width=2)
    )
)

fig.show()

4 Iteracion 3

import plotly.express as px

fig = px.violin(
    df,
    x="PACC_ANIO",             # agrupa por año
    y="PACC_PRECIO_USD",       # valores numéricos
    box=True,                  # incluye boxplot interno
    points="outliers",         # muestra solo outliers
    title="Violin Plot de Precio USD Cacao por Año",
    labels={
        "PACC_ANIO": "Año",
        "PACC_PRECIO_USD": "Precio en USD Cacao"
    },
    color_discrete_sequence=["saddlebrown"]  # color café
)

# Fondo blanco y ejes
fig.update_layout(
    plot_bgcolor="white",
    paper_bgcolor="white",
    xaxis=dict(
        tickmode="linear",      # ticks regulares en eje X
        tickangle=0,            # etiquetas horizontales
        showgrid=True,
        gridcolor="lightgray"
    ),
    yaxis=dict(
        tickformat=",.0f"       # separador de miles en eje Y
    )
)

# Cambiar color de outliers
fig.update_traces(
    marker=dict(
        color="saddlebrown",   # puntos de outliers en café
        line=dict(color="saddlebrown", width=2)
    )
)

fig.show()