W3docs

Gráficos de dispersión con Matplotlib en Python — Guía completa

Aprende a crear y personalizar gráficos de dispersión en Python con Matplotlib. Cubre color, tamaño, alpha, barras de color, grupos múltiples y anotaciones.

La función scatter() de Matplotlib te permite visualizar la relación entre dos variables numéricas colocando un marcador en cada punto de datos (x, y). A diferencia de un gráfico de líneas, los gráficos de dispersión no asumen ningún orden ni continuidad — cada punto existe por sí solo. Esto los convierte en la opción predilecta para explorar correlaciones, detectar agrupaciones e identificar valores atípicos.

Este capítulo cubre todo, desde tu primer gráfico de dispersión hasta técnicas profesionales: codificación de color y tamaño por punto, transparencia, barras de color, gráficos con múltiples grupos, anotaciones de puntos y guardado de archivos listos para publicación.

Antes de comenzar, asegúrate de que Matplotlib esté instalado:

pip install matplotlib

Si eres nuevo en Matplotlib, lee primero los capítulos de Introducción a Matplotlib y Primeros pasos.

Cuándo usar un gráfico de dispersión

Usa un gráfico de dispersión cuando:

  • Quieras explorar la correlación entre dos variables numéricas (altura vs. peso, horas de estudio vs. calificación).
  • Necesites detectar agrupaciones — grupos de puntos que se concentran naturalmente.
  • Quieras identificar valores atípicos — puntos alejados de la distribución principal.
  • Estés codificando una tercera variable mediante el tamaño o el color del marcador (un "gráfico de burbujas" es un gráfico de dispersión donde el tamaño representa una tercera variable).

Evita los gráficos de dispersión cuando un eje represente categorías sin orden — un gráfico de barras es más claro en ese caso. Para tendencias a lo largo de una variable continua ordenada, un gráfico de líneas es más apropiado.

Creación de un gráfico de dispersión básico

Pasa dos secuencias de igual longitud — valores x y valores y — a plt.scatter():

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y = [2, 4, 5, 4, 7, 8, 6, 9, 10, 12]

plt.scatter(x, y)

plt.title('Basic Scatter Plot')
plt.xlabel('X Values')
plt.ylabel('Y Values')

plt.tight_layout()
plt.show()

plt.tight_layout() evita que las etiquetas queden recortadas — conviértelo en un hábito antes de cada llamada a show() o savefig().

Personalización del tamaño de los marcadores

El parámetro s controla el tamaño del marcador en puntos al cuadrado (el valor predeterminado es 20). Auméntalo para que los puntos sean más fáciles de ver, especialmente en presentaciones:

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5, 6, 7, 8]
y = [3, 1, 4, 1, 5, 9, 2, 6]

plt.scatter(x, y, s=120)

plt.title('Larger Markers')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()

También puedes pasar una lista o array a s para que cada punto tenga su propio tamaño — así es como se codifica una tercera variable numérica como tamaño de burbuja:

import matplotlib.pyplot as plt

x      = [1, 2, 3, 4, 5]
y      = [5, 3, 6, 2, 7]
sizes  = [100, 300, 50, 400, 200]   # third variable encoded as bubble area

plt.scatter(x, y, s=sizes)

plt.title('Bubble Chart — size encodes a third variable')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()

Personalización del color de los marcadores

Un solo color para todos los puntos

Pasa cualquier nombre de color, cadena hexadecimal o tupla RGB a c (o color):

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [2, 4, 1, 5, 3]

plt.scatter(x, y, s=100, c='steelblue')

plt.title('Single Color')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()

Color por punto a partir de una variable numérica

Pasar un array a c asigna a cada valor un color mediante el mapa de colores especificado en cmap. Añade plt.colorbar() para mostrar qué representan los colores:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=42)
x      = rng.random(50)
y      = rng.random(50)
values = rng.random(50)          # third variable, e.g. intensity or temperature

scatter = plt.scatter(x, y, s=80, c=values, cmap='viridis')
plt.colorbar(scatter, label='Intensity')

plt.title('Color-Mapped Scatter Plot')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()

'viridis' es un mapa de colores perceptualmente uniforme que se puede leer en escala de grises y es accesible para personas con daltonismo. Otras buenas opciones son 'plasma', 'cividis' y 'coolwarm'.

Control de la transparencia con alpha

Cuando muchos puntos se superponen, forman una mancha opaca que oculta la densidad real. Establece alpha (0 = completamente transparente, 1 = completamente opaco) para revelar la estructura superpuesta:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=0)
x = rng.normal(loc=0, scale=1, size=300)
y = rng.normal(loc=0, scale=1, size=300)

plt.scatter(x, y, s=40, alpha=0.4)

plt.title('Transparent Markers Reveal Density (alpha=0.4)')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()

Un buen punto de partida es alpha=0.4 a 0.6. Ajústalo según la cantidad de puntos que tengas.

Estilo de los bordes de los marcadores

Usa edgecolors para añadir un borde alrededor de cada marcador y linewidths para controlar el grosor del borde. Esto ayuda a que los puntos resalten sobre un fondo con color:

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5, 6]
y = [3, 1, 4, 1, 5, 9]

plt.scatter(x, y, s=150, c='gold', edgecolors='black', linewidths=1.5)

plt.title('Markers with Edges')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()

Pasa edgecolors='none' para eliminar los bordes por completo (este es el valor predeterminado para la mayoría de los mapas de colores).

Representación de múltiples grupos

Para comparar grupos, llama a plt.scatter() una vez por grupo y asigna una etiqueta. Matplotlib asigna un color predeterminado diferente a cada llamada:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=7)

# Group A — centered around (2, 3)
ax_x = rng.normal(loc=2, scale=0.5, size=30)
ax_y = rng.normal(loc=3, scale=0.5, size=30)

# Group B — centered around (5, 6)
bx_x = rng.normal(loc=5, scale=0.5, size=30)
bx_y = rng.normal(loc=6, scale=0.5, size=30)

# Group C — centered around (8, 2)
cx_x = rng.normal(loc=8, scale=0.5, size=30)
cx_y = rng.normal(loc=2, scale=0.5, size=30)

plt.scatter(ax_x, ax_y, s=60, label='Group A')
plt.scatter(bx_x, bx_y, s=60, label='Group B')
plt.scatter(cx_x, cx_y, s=60, label='Group C')

plt.legend()
plt.title('Multi-Group Scatter Plot')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()

Cada llamada a scatter() elige automáticamente el siguiente color del ciclo de colores predeterminado. Pasa c='red' (o cualquier color) para anularlo.

Anotación de puntos individuales

Usa plt.annotate() para etiquetar puntos específicos — es útil para destacar valores atípicos u observaciones clave:

import matplotlib.pyplot as plt

cities = ['London', 'Berlin', 'Madrid', 'Rome', 'Paris']
population = [9.0, 3.7, 3.3, 2.8, 2.1]   # millions
area       = [1572, 892, 604, 1285, 105]   # km²

plt.scatter(area, population, s=100, c='steelblue', edgecolors='black', linewidths=0.8)

for i, city in enumerate(cities):
    plt.annotate(
        city,
        xy=(area[i], population[i]),
        xytext=(8, 4),                      # offset in points
        textcoords='offset points',
        fontsize=9,
    )

plt.title('European City Population vs. Area')
plt.xlabel('Area (km²)')
plt.ylabel('Population (millions)')
plt.tight_layout()
plt.show()

El patrón xytext + textcoords='offset points' desplaza la etiqueta ligeramente para que no quede directamente sobre el marcador.

Uso de ejes logarítmicos

Cuando los datos abarcan varios órdenes de magnitud, los ejes lineales comprimen la mayoría de los puntos en una esquina. Cambia a escala logarítmica con plt.xscale('log') o plt.yscale('log'):

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=1)
x = np.logspace(1, 5, 60)            # 10¹ to 10⁵
y = x * rng.uniform(0.5, 2.0, 60)   # roughly proportional, with noise

plt.scatter(x, y, s=40, alpha=0.7)
plt.xscale('log')
plt.yscale('log')

plt.title('Log-Scale Scatter Plot')
plt.xlabel('X (log scale)')
plt.ylabel('Y (log scale)')
plt.tight_layout()
plt.show()

Ambos ejes ahora abarcan intervalos iguales de potencias de diez, distribuyendo los datos de manera uniforme en el área del gráfico.

Añadir una línea de regresión

Un gráfico de dispersión muestra puntos individuales; añadir una línea de mejor ajuste revela la tendencia general. Calcula la pendiente y la ordenada al origen con np.polyfit():

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=3)
x = np.linspace(0, 10, 40)
y = 2.5 * x + rng.normal(scale=3, size=40)   # linear trend + noise

# Fit a degree-1 polynomial (straight line)
slope, intercept = np.polyfit(x, y, 1)
trend_line = slope * x + intercept

plt.scatter(x, y, s=50, label='Data points', alpha=0.7)
plt.plot(x, trend_line, color='red', linewidth=2, label=f'Trend (slope={slope:.2f})')

plt.legend()
plt.title('Scatter Plot with Regression Line')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()

np.polyfit(x, y, 1) devuelve [slope, intercept] para la línea de mejor ajuste a través de los puntos.

Guardar un gráfico de dispersión en un archivo

Usa plt.savefig() en lugar de plt.show() para escribir el gráfico en el disco. Llámalo antes de plt.show() — después de show() la figura se borra:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=9)
x = rng.random(60)
y = rng.random(60)

plt.scatter(x, y, s=60, alpha=0.6, c='teal', edgecolors='white', linewidths=0.5)
plt.title('Saved Scatter Plot')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()

plt.savefig('scatter.png', dpi=150)   # PNG at 150 DPI
plt.savefig('scatter.pdf')             # vector PDF — best for publication
plt.show()

Opciones de formato comunes: 'png' (raster, web), 'pdf' (vector, publicación), 'svg' (vector, web). Aumenta dpi a 300 para rasters de calidad de impresión.

scatter() vs plot() — ¿Cuál usar?

Ambas funciones pueden dibujar gráficos solo con marcadores, pero sirven para propósitos distintos:

Característicaplt.scatter()plt.plot()
Tamaño por punto (s)Sí — pasa un arrayNo
Color por punto (c)Sí — pasa un arrayNo (un color por llamada)
Soporte de mapa de coloresSí (cmap)Limitado
Rendimiento en conjuntos de datos grandesMás lentoMás rápido
Línea de conexiónNo

Usa scatter() cuando necesites estilo por punto (el color o el tamaño varía según los datos). Usa plot(marker='o', linestyle='None') para gráficos simples de marcadores en conjuntos de datos grandes donde la velocidad importa. Consulta el capítulo de Marcadores de Matplotlib para más información sobre estilos de marcadores.

Ejemplo completo

El siguiente script autónomo combina las técnicas más útiles — mapeado de colores, codificación de tamaño, transparencia, una barra de color y una leyenda:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=42)

n = 80
x      = rng.standard_normal(n)
y      = 0.8 * x + rng.standard_normal(n) * 0.6   # correlated
sizes  = rng.uniform(30, 200, n)                   # bubble area
values = rng.random(n)                             # third variable for color

fig, ax = plt.subplots(figsize=(8, 5))

sc = ax.scatter(
    x, y,
    s=sizes,
    c=values,
    cmap='plasma',
    alpha=0.75,
    edgecolors='white',
    linewidths=0.5,
)

plt.colorbar(sc, ax=ax, label='Intensity')

ax.set_title('Comprehensive Scatter Plot Example', fontsize=13)
ax.set_xlabel('X Variable')
ax.set_ylabel('Y Variable (correlated)')
fig.tight_layout()
plt.savefig('scatter_complete.png', dpi=150)
plt.show()

Puntos clave:

  • fig, ax = plt.subplots() te proporciona objetos explícitos de figura y ejes — el enfoque recomendado para cualquier cosa más allá de un prototipo rápido.
  • ax.scatter() en un objeto Axes se comporta de forma idéntica a plt.scatter().
  • plt.colorbar(sc, ax=ax, label='...') adjunta la barra de color a los ejes específicos.

Buenas prácticas

  • Muestra la escala. Si usas c con un mapa de colores, añade siempre una barra de color para que los lectores sepan qué representan los colores.
  • Evita el solapamiento excesivo de puntos. Para más de ~500 puntos, establece alpha < 1 o cambia a un histograma 2D (plt.hist2d()) o un gráfico hexbin (plt.hexbin()).
  • Elige mapas de colores accesibles. 'viridis', 'plasma' y 'cividis' son perceptualmente uniformes y aptos para personas con daltonismo. Evita 'jet' y 'rainbow'.
  • Etiqueta los ejes con unidades. plt.xlabel('Altura (cm)') es más informativo que plt.xlabel('Altura').
  • Añade un título que indique el hallazgo. "Altura vs. Peso — correlación positiva" es más útil que "Gráfico de dispersión".

Capítulos relacionados

Was this page helpful?