Matplotlib básico: visualización de datos con Python
- ¿Qué es Matplotlib y cuándo usarlo?
- Anatomía de una figura: Figure, Axes y Artists
- Gráficos de líneas y áreas
- Gráficos de barras: verticales y horizontales
- Scatter plots e histogramas
- Personalización: colores, estilos y anotaciones
- Subplots: múltiples gráficos en una figura
- Guardar figuras en alta calidad
- Preguntas frecuentes
Hasta ahora hemos aprendido a crear y transformar datos con NumPy y Pandas. Pero los datos en bruto, por bien estructurados que estén, son esencialmente invisibles: un DataFrame de diez mil filas no comunica nada a simple vista. Matplotlib cierra esa brecha. Es la librería que convierte números en imágenes: curvas que revelan tendencias, barras que hacen comparaciones obvias, scatter plots que muestran correlaciones que ningún coeficiente estadístico transmite tan directamente. Si NumPy es el músculo y Pandas el cerebro, Matplotlib es la voz.
¿Qué es Matplotlib y cuándo usarlo?
Matplotlib nació en 2003 de la frustración de John D. Hunter: necesitaba reproducir en Python los gráficos que MATLAB generaba para análisis de señales neuronales, sin pagar la licencia de MATLAB. El resultado fue una librería que hoy tiene más de 20 años, más de tres millones de descargas semanales y que sirve de base a prácticamente todas las librerías de visualización del ecosistema Python (Seaborn, Pandas .plot(), Plotly estático).
Matplotlib es la elección correcta cuando necesitas control total sobre el aspecto del gráfico, cuando generas figuras para publicaciones científicas o informes técnicos, cuando integras visualizaciones en aplicaciones Python (Flask, Django, scripts de análisis automatizados) o cuando combinas tipos de gráficos no estándar en una misma figura. Para exploración rápida y gráficos estadísticos comunes con mejor aspecto por defecto, Seaborn (que usa Matplotlib internamente) puede ser más conveniente.
pip install matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
print(plt.matplotlib.__version__) # 3.x es la versión actual
# El módulo principal es pyplot, que se importa siempre como plt
# matplotlib.pyplot implementa una interfaz de estado al estilo MATLAB
Anatomía de una figura: Figure, Axes y Artists
Antes de dibujar nada, conviene entender la jerarquía de objetos de Matplotlib. Todo gráfico es un árbol de objetos llamados Artists, organizados en tres niveles principales: la Figure es el lienzo completo (la ventana o la imagen final), los Axes son los sistemas de coordenadas donde se dibujan los datos (lo que normalmente llamamos "un gráfico"), y los Axis son los ejes individuales X e Y con sus escalas y etiquetas.
Matplotlib tiene dos interfaces para crear figuras. La interfaz pyplot (estilo MATLAB) mantiene un estado global y es cómoda para exploración. La interfaz orientada a objetos trabaja explícitamente con variables fig y ax, y es la recomendada para código de producción.
import matplotlib.pyplot as plt
import numpy as np
# ── Interfaz pyplot (estado global) ───────────────────────────
plt.figure(figsize=(8, 4)) # crea una Figure
plt.plot([1, 2, 3], [4, 5, 3]) # dibuja en el Axes activo
plt.title('Mi primer gráfico')
plt.xlabel('Eje X')
plt.ylabel('Eje Y')
plt.show()
# ── Interfaz OO (recomendada para producción) ──────────────────
fig, ax = plt.subplots(figsize=(8, 4)) # Figure + 1 Axes
ax.plot([1, 2, 3], [4, 5, 3])
ax.set_title('Mi primer gráfico')
ax.set_xlabel('Eje X')
ax.set_ylabel('Eje Y')
plt.tight_layout()
plt.show()
# ── La jerarquía de objetos ────────────────────────────────────
fig = plt.figure(figsize=(8, 4)) # el lienzo completo
ax = fig.add_subplot(111) # Axes: sistema de coordenadas
# Un Axes contiene:
# ax.xaxis / ax.yaxis → objetos Axis con escala y ticks
# ax.lines → lista de Line2D dibujadas
# ax.patches → rectángulos, círculos, etc.
# ax.texts → anotaciones de texto
# Obtener referencia al Axes activo (interfaz pyplot)
ax_actual = plt.gca() # get current axes
fig_actual = plt.gcf() # get current figure
Axes (plural de Axis en inglés, pero en Matplotlib es un objeto distinto) representa un gráfico completo con sus dos ejes. Axis (singular) es uno de los dos ejes numéricos de ese gráfico. Una Figure puede tener múltiples Axes (subplots); cada Axes tiene exactamente dos Axis (xaxis e yaxis).
Gráficos de líneas y áreas
El gráfico de líneas es el tipo más común en análisis temporal. ax.plot() acepta arrays de X e Y y decenas de parámetros de estilo. Cuando no se especifica X, Matplotlib usa el índice como eje horizontal.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(10, 5))
x = np.linspace(0, 4 * np.pi, 200)
y1 = np.sin(x)
y2 = np.cos(x)
# ── Parámetros principales de plot() ──────────────────────────
ax.plot(x, y1,
color='#306998', # azul Python
linewidth=2,
linestyle='-', # '-', '--', ':', '-.'
marker='o', # marcador: 'o', 's', '^', 'D', 'x', '+'
markersize=4,
markevery=20, # marcador cada 20 puntos
label='sin(x)')
ax.plot(x, y2,
color='#FFD43B', # amarillo Python
linewidth=2,
linestyle='--',
label='cos(x)')
# ── Anotaciones básicas ────────────────────────────────────────
ax.set_title('Funciones seno y coseno', fontsize=14, fontweight='bold')
ax.set_xlabel('Ángulo (radianes)')
ax.set_ylabel('Amplitud')
ax.legend() # muestra la leyenda con los labels
ax.grid(True, alpha=0.3) # rejilla semitransparente
ax.set_xlim(0, 4 * np.pi) # límites del eje X
plt.tight_layout()
plt.show()
# ── Múltiples líneas con datos reales (Pandas) ────────────────
import pandas as pd
df = pd.DataFrame({
'mes': range(1, 13),
'ventas': [120, 145, 132, 178, 190, 210, 195, 220, 205, 240, 260, 310],
'costes': [ 80, 90, 85, 100, 115, 120, 110, 125, 115, 130, 140, 160],
})
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(df['mes'], df['ventas'], label='Ventas', color='#2ecc71', linewidth=2)
ax.plot(df['mes'], df['costes'], label='Costes', color='#e74c3c', linewidth=2, linestyle='--')
ax.fill_between(df['mes'], df['ventas'], df['costes'],
alpha=0.15, color='#2ecc71') # área entre curvas
ax.set_xticks(range(1, 13))
ax.set_xticklabels(['Ene','Feb','Mar','Abr','May','Jun',
'Jul','Ago','Sep','Oct','Nov','Dic'])
ax.set_title('Ventas vs costes — 2025')
ax.legend()
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.show()
ax.fill_between(x, y1, y2) rellena el área entre dos curvas. Es especialmente útil para visualizar márgenes (ventas menos costes), intervalos de confianza o rangos mín/máx. El parámetro alpha controla la transparencia (0 = invisible, 1 = opaco). Un valor de 0.1–0.3 suele dar un aspecto elegante sin ocultar las líneas.
Gráficos de barras: verticales y horizontales
Los gráficos de barras son el formato correcto para comparar categorías. ax.bar() dibuja barras verticales; ax.barh() dibuja barras horizontales. Las barras horizontales son preferibles cuando las etiquetas de categoría son largas (no caben bien en el eje X rotadas) o cuando el número de categorías es alto y quieres priorizar la lectura de la lista.
import matplotlib.pyplot as plt
import numpy as np
# ── Barras verticales simples ──────────────────────────────────
categorias = ['Python', 'JavaScript', 'Java', 'C#', 'Go', 'Rust']
popularidad = [32.5, 22.1, 15.3, 10.8, 8.2, 5.4]
fig, ax = plt.subplots(figsize=(8, 5))
bars = ax.bar(categorias, popularidad,
color=['#306998', '#f7df1e', '#b07219', '#178600', '#00acd7', '#ce3d28'],
edgecolor='white', linewidth=0.5,
width=0.6)
# Etiquetas encima de cada barra
for bar, val in zip(bars, popularidad):
ax.text(bar.get_x() + bar.get_width() / 2,
bar.get_height() + 0.3,
f'{val}%',
ha='center', va='bottom', fontsize=9, fontweight='bold')
ax.set_title('Lenguajes más populares en 2025', fontsize=13)
ax.set_ylabel('Índice de popularidad (%)')
ax.set_ylim(0, max(popularidad) * 1.15)
ax.spines[['top', 'right']].set_visible(False) # quitar ejes superior y derecho
plt.tight_layout()
plt.show()
# ── Barras horizontales (categorías con nombres largos) ────────
departamentos = ['Ingeniería', 'Marketing', 'Ventas', 'Operaciones', 'RRHH']
presupuesto = [450000, 120000, 280000, 195000, 85000]
fig, ax = plt.subplots(figsize=(8, 4))
bars_h = ax.barh(departamentos, presupuesto,
color='#306998', alpha=0.85)
for bar, val in zip(bars_h, presupuesto):
ax.text(bar.get_width() + 5000,
bar.get_y() + bar.get_height() / 2,
f'{val:,} €',
va='center', fontsize=9)
ax.set_title('Presupuesto por departamento')
ax.set_xlabel('Presupuesto (€)')
ax.spines[['top', 'right']].set_visible(False)
plt.tight_layout()
plt.show()
# ── Barras agrupadas ───────────────────────────────────────────
trimestres = ['Q1', 'Q2', 'Q3', 'Q4']
ventas_2024 = [120, 145, 165, 200]
ventas_2025 = [135, 160, 185, 230]
x = np.arange(len(trimestres))
width = 0.35
fig, ax = plt.subplots(figsize=(8, 5))
ax.bar(x - width/2, ventas_2024, width, label='2024', color='#a8c8e8')
ax.bar(x + width/2, ventas_2025, width, label='2025', color='#306998')
ax.set_xticks(x)
ax.set_xticklabels(trimestres)
ax.set_title('Ventas por trimestre: 2024 vs 2025')
ax.set_ylabel('Ventas (miles €)')
ax.legend()
ax.spines[['top', 'right']].set_visible(False)
plt.tight_layout()
plt.show()
Scatter plots e histogramas
El scatter plot muestra la relación entre dos variables cuantitativas: cada punto es una observación, su posición en X e Y codifica los valores. Es el gráfico para detectar correlaciones, clusters, outliers. El histograma muestra la distribución de una variable: cómo se reparten los valores entre rangos (bins). Es el primer gráfico que deberías hacer con cualquier variable numérica nueva.
import matplotlib.pyplot as plt
import numpy as np
# ── Scatter plot básico ────────────────────────────────────────
np.random.seed(42)
n = 150
experiencia = np.random.uniform(1, 15, n) # años
salario = experiencia * 3500 + np.random.normal(0, 8000, n) # euros
depto_id = np.random.choice([0, 1, 2], n) # 3 departamentos
colores = ['#306998', '#FFD43B', '#2ecc71']
fig, ax = plt.subplots(figsize=(9, 6))
for dept, color, nombre in zip([0, 1, 2], colores,
['Ingeniería', 'Marketing', 'Ventas']):
mask = depto_id == dept
ax.scatter(experiencia[mask], salario[mask],
c=color, label=nombre,
alpha=0.7, # transparencia para ver solapamiento
s=60, # tamaño del marcador en puntos²
edgecolors='white', linewidths=0.5)
ax.set_title('Experiencia vs Salario por departamento')
ax.set_xlabel('Años de experiencia')
ax.set_ylabel('Salario anual (€)')
ax.legend()
ax.grid(True, alpha=0.3, linestyle='--')
ax.spines[['top', 'right']].set_visible(False)
plt.tight_layout()
plt.show()
# ── Scatter con color continuo (colormap) ─────────────────────
fig, ax = plt.subplots(figsize=(8, 5))
scatter = ax.scatter(experiencia, salario,
c=salario, # color según valor de salario
cmap='viridis', # colormap: viridis, plasma, coolwarm, RdYlGn
alpha=0.8, s=50)
plt.colorbar(scatter, ax=ax, label='Salario (€)')
ax.set_title('Scatter con escala de color continua')
ax.set_xlabel('Años de experiencia')
ax.set_ylabel('Salario (€)')
plt.tight_layout()
plt.show()
# ── Histograma ─────────────────────────────────────────────────
datos = np.random.normal(loc=50000, scale=12000, size=1000) # salarios simulados
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# Histograma de frecuencias absolutas
axes[0].hist(datos, bins=30, color='#306998', edgecolor='white', linewidth=0.5)
axes[0].set_title('Distribución de salarios (frecuencia)')
axes[0].set_xlabel('Salario (€)')
axes[0].set_ylabel('Nº de empleados')
# Histograma de densidad
axes[1].hist(datos, bins=30, density=True, # density=True → área total = 1
color='#306998', alpha=0.7, edgecolor='white')
# Superponer curva de densidad teórica
from scipy.stats import norm
mu, std = norm.fit(datos)
x_range = np.linspace(datos.min(), datos.max(), 200)
axes[1].plot(x_range, norm.pdf(x_range, mu, std),
color='#e74c3c', linewidth=2, label=f'Normal (μ={mu:.0f}, σ={std:.0f})')
axes[1].set_title('Distribución de salarios (densidad)')
axes[1].set_xlabel('Salario (€)')
axes[1].set_ylabel('Densidad')
axes[1].legend()
for ax_i in axes:
ax_i.spines[['top', 'right']].set_visible(False)
plt.tight_layout()
plt.show()
viridis es perceptualmente uniforme y apto para daltónicos; RdYlGn (rojo-amarillo-verde) codifica bien valores positivos y negativos; coolwarm es ideal para divergencias respecto a un punto central. El color incorrecto puede hacer que los datos "mietan" sin que el autor lo pretenda. Fuente: Pexels (licencia libre).Personalización: colores, estilos y anotaciones
Matplotlib da acceso completo a cada elemento visual. Desde los colores hasta el grosor de cada línea de los ejes, todo es configurable. La clave es conocer los mecanismos principales sin intentar memorizar todos los parámetros: los estilos predefinidos, los colormaps y el sistema de anotaciones cubren el 90% de los casos.
import matplotlib.pyplot as plt
import numpy as np
# ── Estilos predefinidos ───────────────────────────────────────
print(plt.style.available) # lista todos los estilos disponibles
plt.style.use('seaborn-v0_8-whitegrid') # aplicar estilo globalmente
# Estilos más útiles:
# 'seaborn-v0_8-whitegrid' → fondo blanco con rejilla gris suave
# 'ggplot' → estilo R/ggplot2
# 'bmh' → Bayesian Methods for Hackers
# 'dark_background' → fondo negro, bueno para presentaciones
# 'fivethirtyeight' → estilo del medio de datos FiveThirtyEight
# ── Colores ────────────────────────────────────────────────────
# Por nombre: 'blue', 'red', 'green', 'orange', 'purple', 'gray'
# Por código: 'C0', 'C1', 'C2'... (ciclo de color actual)
# Por hex: '#306998', '#FFD43B'
# Por RGBA: (0.19, 0.41, 0.59, 0.8) ← cuarto valor = alpha
# Por nombre abreviado: 'b','g','r','c','m','y','k','w'
# ── Anotaciones con ax.annotate() ─────────────────────────────
fig, ax = plt.subplots(figsize=(9, 5))
x = np.linspace(0, 10, 100)
y = np.sin(x) * np.exp(-x * 0.15)
ax.plot(x, y, color='#306998', linewidth=2)
# Anotar el máximo
idx_max = np.argmax(y)
ax.annotate(f'Máximo ({x[idx_max]:.2f}, {y[idx_max]:.2f})',
xy=(x[idx_max], y[idx_max]), # punto a anotar
xytext=(x[idx_max] + 1.5, y[idx_max] + 0.1), # posición del texto
arrowprops=dict(arrowstyle='->', color='#e74c3c', lw=1.5),
fontsize=10, color='#e74c3c')
ax.axhline(y=0, color='gray', linewidth=0.8, linestyle='--') # línea horizontal en y=0
ax.set_title('Onda amortiguada con anotación')
ax.set_xlabel('Tiempo (s)')
ax.set_ylabel('Amplitud')
ax.spines[['top', 'right']].set_visible(False)
plt.tight_layout()
plt.show()
# ── Personalización de ticks ───────────────────────────────────
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
[3.2, 3.8, 5.1, 7.4, 8.9, 9.2, 8.7, 8.1, 6.5, 5.0, 3.9, 3.1])
ax.set_xticks(range(1, 13))
ax.set_xticklabels(['E','F','M','A','M','J','J','A','S','O','N','D'],
fontsize=9)
ax.set_yticks([0, 2, 4, 6, 8, 10])
ax.tick_params(axis='both', which='major', length=4, width=1)
ax.set_title('Temperatura media mensual (°C)')
plt.tight_layout()
plt.show()
# ── rcParams para configuración global ────────────────────────
plt.rcParams.update({
'font.family': 'DejaVu Sans',
'font.size': 11,
'axes.titlesize': 13,
'axes.labelsize': 11,
'axes.spines.top': False,
'axes.spines.right': False,
'figure.figsize': (9, 5),
'figure.dpi': 100,
'savefig.dpi': 150,
'savefig.bbox': 'tight',
})
Subplots: múltiples gráficos en una figura
Con frecuencia necesitas comparar varios gráficos en paralelo o mostrar diferentes perspectivas del mismo dataset. Matplotlib permite crear cuadrículas de subplots con plt.subplots(nrows, ncols). Para layouts más complejos (subplots de distinto tamaño), usa GridSpec.
import matplotlib.pyplot as plt
import numpy as np
# ── Cuadrícula simple de subplots ──────────────────────────────
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
fig.suptitle('Dashboard: análisis de ventas', fontsize=15, fontweight='bold', y=1.02)
np.random.seed(0)
meses = range(1, 13)
ventas = [120, 135, 128, 175, 190, 210, 195, 225, 205, 240, 260, 305]
costes = [ 80, 90, 85, 100, 110, 125, 115, 130, 120, 135, 145, 165]
retorno = [(v - c) / c * 100 for v, c in zip(ventas, costes)]
categorias_v = {'Online': 45, 'Tienda': 30, 'Distribuidor': 25}
# Subplot (0,0): línea temporal
ax = axes[0, 0]
ax.plot(meses, ventas, 'o-', color='#306998', label='Ventas', linewidth=2)
ax.plot(meses, costes, 's--', color='#e74c3c', label='Costes', linewidth=2)
ax.set_title('Ventas vs Costes')
ax.set_xlabel('Mes')
ax.legend(fontsize=9)
ax.grid(axis='y', alpha=0.3)
# Subplot (0,1): barras
ax = axes[0, 1]
ax.bar(meses, ventas, color='#306998', alpha=0.8)
ax.set_title('Ventas mensuales')
ax.set_xlabel('Mes')
ax.set_ylabel('Miles €')
# Subplot (1,0): scatter retorno vs ventas
ax = axes[1, 0]
ax.scatter(ventas, retorno, c=retorno, cmap='RdYlGn', s=80, edgecolors='white')
ax.set_title('Volumen vs Rentabilidad')
ax.set_xlabel('Ventas (miles €)')
ax.set_ylabel('Retorno (%)')
# Subplot (1,1): histograma de ventas
ax = axes[1, 1]
ax.hist(ventas, bins=8, color='#306998', edgecolor='white')
ax.set_title('Distribución de ventas')
ax.set_xlabel('Miles €')
ax.set_ylabel('Frecuencia')
for row in axes:
for ax_i in row:
ax_i.spines[['top', 'right']].set_visible(False)
plt.tight_layout()
plt.show()
# ── GridSpec para layouts asimétricos ─────────────────────────
from matplotlib.gridspec import GridSpec
fig = plt.figure(figsize=(12, 7))
gs = GridSpec(2, 3, figure=fig, hspace=0.4, wspace=0.3)
ax_grande = fig.add_subplot(gs[0, :2]) # fila 0, columnas 0-1 (ocupa 2 columnas)
ax_derecha = fig.add_subplot(gs[0, 2]) # fila 0, columna 2
ax_inf_izq = fig.add_subplot(gs[1, 0]) # fila 1, columna 0
ax_inf_mid = fig.add_subplot(gs[1, 1]) # fila 1, columna 1
ax_inf_der = fig.add_subplot(gs[1, 2]) # fila 1, columna 2
ax_grande.plot(meses, ventas, color='#306998', linewidth=2)
ax_grande.set_title('Serie temporal — gráfico principal')
ax_derecha.pie(list(categorias_v.values()),
labels=list(categorias_v.keys()),
autopct='%1.0f%%',
colors=['#306998', '#FFD43B', '#2ecc71'])
ax_derecha.set_title('Canal')
for ax_i in [ax_inf_izq, ax_inf_mid, ax_inf_der]:
ax_i.bar(range(4), np.random.randint(50, 200, 4), color='#306998', alpha=0.7)
ax_i.spines[['top', 'right']].set_visible(False)
plt.show()
plt.tight_layout() ajusta automáticamente los márgenes para que los títulos y etiquetas no se solapen. Es el método clásico y funciona bien en la mayoría de casos. fig, axes = plt.subplots(..., layout='constrained') es la alternativa moderna, más precisa pero menos compatible con versiones antiguas. Siempre llama a uno de los dos antes de guardar la figura; sin ajuste de márgenes, las etiquetas exteriores quedan cortadas.
Guardar figuras en alta calidad
En producción, los gráficos no se muestran en pantalla: se guardan como archivos y se insertan en informes, dashboards o documentos. fig.savefig() admite múltiples formatos y resoluciones. Elegir el formato correcto evita pérdida de calidad o archivos innecesariamente pesados.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(9, 5))
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x), color='#306998', linewidth=2)
ax.set_title('Ejemplo de guardado')
ax.spines[['top', 'right']].set_visible(False)
plt.tight_layout()
# ── Formatos de guardado ───────────────────────────────────────
# PNG — mapa de bits, ideal para web y documentos
fig.savefig('grafico.png',
dpi=150, # 150 dpi: buen equilibrio calidad/tamaño
bbox_inches='tight', # recortar márgenes en blanco extra
facecolor='white') # fondo blanco explícito (a veces es transparente)
# PDF — vectorial, ideal para publicaciones e impresión
fig.savefig('grafico.pdf',
dpi=300,
bbox_inches='tight')
# SVG — vectorial, editable en Inkscape/Illustrator
fig.savefig('grafico.svg', bbox_inches='tight')
# JPG — con compresión con pérdida, no recomendado para gráficos
fig.savefig('grafico.jpg', dpi=150, quality=95, bbox_inches='tight')
# ── No mostrar ventana al guardar (para scripts de producción) ─
import matplotlib
matplotlib.use('Agg') # backend sin pantalla, antes de importar pyplot
import matplotlib.pyplot as plt
# ahora plt.show() no hace nada, solo savefig() guarda el archivo
# ── Guardar múltiples páginas en un PDF ────────────────────────
from matplotlib.backends.backend_pdf import PdfPages
with PdfPages('informe_completo.pdf') as pdf:
for mes, dato in zip(['Enero', 'Febrero', 'Marzo'],
[[1,2,3], [4,5,6], [7,8,9]]):
fig, ax = plt.subplots(figsize=(8, 4))
ax.bar(range(len(dato)), dato, color='#306998')
ax.set_title(f'Datos — {mes}')
plt.tight_layout()
pdf.savefig(fig) # añade esta figura como una página del PDF
plt.close(fig) # importante: liberar memoria
# ── Configuración global de guardado con rcParams ─────────────
plt.rcParams.update({
'savefig.dpi': 200,
'savefig.bbox': 'tight',
'savefig.format': 'png', # formato por defecto
})
# ── Resolución según el uso final ─────────────────────────────
# Pantalla web / Jupyter: dpi = 96–100
# Documentos / informes PDF: dpi = 150–200
# Publicaciones científicas: dpi = 300–600
# Carteles / impresión grande: dpi = 600+
❓ Preguntas frecuentes
❓ Preguntas frecuentes sobre Matplotlib básico: visualización de datos con Python
Las dudas más comunes respondidas de forma clara y directa.
💬 Foro de discusión
¿Tienes dudas sobre Matplotlib básico: visualización de datos con Python? Comparte tu pregunta con la comunidad.
Todavía no hay mensajes. ¡Sé el primero en participar!