Una tabla de números te dice qué pasó. Una gráfica te muestra lo que significa. Puedes leer doce cifras de ventas mensuales y deducir que diciembre fue el mejor mes, o puedes echar un vistazo a una gráfica de barras y verlo de inmediato.
Python es una de las mejores herramientas para este trabajo. Con unas cuantas bibliotecas y un archivo CSV, puedes convertir datos en bruto en gráficas limpias y profesionales, listas para un reporte, una presentación o un dashboard para clientes.
Esta guía recorre los ocho tipos de gráficas de mi proyecto PythonVisualizationCharts en GitHub. Para cada una, aprenderás para qué sirve, verás el código clave y el resultado. Cada script admite un modo claro y uno oscuro, para que las gráficas se adapten al fondo donde terminen usándose.

Las Bibliotecas que Usarás
Cada gráfica se construye con un pequeño conjunto de bibliotecas muy conocidas:
- Pandas carga los archivos CSV y maneja los datos (ordenar, filtrar, totales).
- Matplotlib hace el dibujo: ejes, barras, líneas, etiquetas y el guardado de la imagen.
- Seaborn ofrece paletas de colores listas para usar (
pastelpara el modo claro ybrightpara el modo oscuro). - GeoPandas carga las formas de los estados de EE. UU. para el mapa.
- NumPy ayuda a calcular los arcos de la gráfica de medidor.
Si Pandas es nuevo para ti, empieza con mis guías sobre cómo acceder a tus datos y cómo limpiar datos para el análisis (ambas en inglés). Los datos limpios producen mejores gráficas.
Configuración del Proyecto
El proyecto usa Python 3.13 y uv para administrar las dependencias. Clona el repositorio e instala todo con un solo comando:
git clone https://github.com/victorhugo81/PythonVisualizationCharts.git
cd PythonVisualizationCharts
uv sync
¿Prefieres pip normal? Primero crea un entorno virtual y luego instala los paquetes:
pip install pandas matplotlib seaborn geopandas
El proyecto está organizado así:
PythonVisualizationCharts/
├── data/
│ ├── monthly_sales.csv # Month, Sales
│ ├── product_sales.csv # Product, Sales
│ └── states.csv # State, Code, Population
├── output/ # Gráficas PNG generadas
├── barchart.py
├── hbarchart.py
├── piechart.py
├── donutchart.py
├── linechart.py
├── scatterplotchart.py
├── gaugechart.py
└── map.py
Ejecuta cualquier gráfica desde la carpeta del proyecto:
uv run barchart.py
La gráfica se abre en una ventana y también se guarda en output/ como PNG.
Los Datos de Ejemplo
La mayoría de las gráficas leen data/monthly_sales.csv, un archivo sencillo de dos columnas:
Month,Sales
Jan,12000
Feb,15000
Mar,18000
...
Dec,30000
Las gráficas circular y de dona usan data/product_sales.csv (Laptops, Phones, Tablets, Accessories, Monitors), y el mapa usa data/states.csv con el nombre, el código de dos letras y la población de cada estado.
El Patrón que Sigue Cada Script
Todos los scripts del proyecto están construidos de la misma manera, así que cuando entiendes uno, los entiendes todos.
1. Un selector de modo al inicio. Cambia una sola línea para alternar entre la salida clara y la oscura:
MODE = 'light' # Opciones: 'dark' o 'light'
2. Un cargador de datos seguro. Antes de leer el archivo, el script verifica que exista y que tenga las columnas correctas. Si falta el archivo, recibes un mensaje de error claro en lugar de un traceback confuso:
from pathlib import Path
import pandas as pd
def load_data():
"""Carga los datos desde un archivo CSV."""
CSV_FILE = Path("data") / "monthly_sales.csv"
if not CSV_FILE.exists():
raise FileNotFoundError(f"{CSV_FILE} not found")
df = pd.read_csv(CSV_FILE)
required_cols = ['Month', 'Sales']
if not all(col in df.columns for col in required_cols):
raise ValueError(f"CSV must contain columns: {required_cols}")
return df
3. Colores elegidos según el modo. El modo claro usa fondo blanco con la paleta pastel de Seaborn. El modo oscuro usa el estilo dark_background de Matplotlib, un fondo #1e1e1e y la paleta bright:
if MODE == 'dark':
plt.style.use('dark_background')
bg_color = '#1e1e1e'
text_color = 'white'
bar_colors = sns.color_palette("bright", n_colors=len(df))
else:
plt.style.use('default')
bg_color = 'white'
text_color = 'black'
bar_colors = sns.color_palette("pastel", n_colors=len(df))
4. Un aspecto limpio y minimalista. Cada gráfica elimina el borde en forma de caja alrededor del área de trazado (los “spines”) y conserva solo líneas de cuadrícula tenues. Este único cambio hace que una gráfica predeterminada de Matplotlib se vea mucho más moderna:
for side in ['top', 'right', 'bottom', 'left']:
ax.spines[side].set_visible(False)
ax.grid(axis="y", linestyle="-", alpha=0.3, color='gray')
5. Guardar y luego mostrar. La gráfica se guarda en la carpeta output/ con el modo en el nombre del archivo (por ejemplo, barchart_light.png):
OUTPUT_FILE = Path("output") / f"barchart_{MODE}.png"
OUTPUT_FILE.parent.mkdir(parents=True, exist_ok=True)
plt.savefig(OUTPUT_FILE, dpi=72, bbox_inches='tight', facecolor=bg_color)
plt.show()
Pasar facecolor=bg_color a savefig() es importante. Sin él, una gráfica en modo oscuro puede guardarse con un borde blanco alrededor.
Ahora veamos cada gráfica.
1. Gráfica de Barras
Ideal para: comparar valores entre categorías, como las ventas por mes, región o producto.
Las gráficas de barras hacen que las diferencias entre grupos se vean fácilmente, por lo que son una buena opción para clasificaciones y comparaciones entre periodos.
# Mantener los meses en orden de calendario, no alfabético
month_order = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
df["Month"] = pd.Categorical(df["Month"], categories=month_order, ordered=True)
df = df.sort_values("Month")
fig, ax = plt.subplots(figsize=(6, 4), facecolor=bg_color)
ax.bar(df["Month"], df["Sales"], color=bar_colors, width=0.8)
ax.set_title("Monthly Sales Performance", pad=10, fontsize=14,
fontweight='bold', color=text_color)
ax.set_xlabel("Month", fontweight='bold', color=text_color)
ax.set_ylabel("Sales", fontweight='bold', color=text_color)
Vale la pena recordar el paso con pd.Categorical. Los nombres de los meses son texto, y si algo los ordena, se ordenarán alfabéticamente (Apr, Aug, Dec…). Convertirlos en una categoría ordenada los mantiene en orden de calendario.
2. Gráfica de Barras Horizontales
Ideal para: etiquetas largas, muchas categorías o listas clasificadas.
Una gráfica de barras horizontales es la misma idea, girada de lado. Cuando las etiquetas son largas (nombres de productos, títulos de páginas, respuestas de encuestas), las barras horizontales les dan espacio en lugar de amontonarlas o rotarlas.
El cambio en el código es pequeño: ax.bar() se convierte en ax.barh(), width pasa a ser height, y las etiquetas de los ejes y las líneas de cuadrícula se intercambian:
ax.barh(df["Month"], df["Sales"], color=bar_colors, height=0.8)
ax.set_xlabel("Sales", fontweight='bold', color=text_color)
ax.set_ylabel("Month", fontweight='bold', color=text_color)
ax.grid(axis="x", linestyle="-", alpha=0.3, color='gray')

3. Gráfica Circular
Ideal para: mostrar cómo las partes forman un todo, con pocas categorías.
Las gráficas circulares sirven para porcentajes y proporciones cuyo total es 100 %, como la participación de mercado o el desglose de un presupuesto. Limítalas a unas cinco o seis rebanadas. Más allá de eso, las rebanadas se vuelven demasiado delgadas para compararlas.
labels = df['Product']
sizes = df['Sales']
wedges, texts, autotexts = ax.pie(
sizes,
labels=labels,
colors=colors,
autopct='%1.1f%%', # mostrar el porcentaje de cada rebanada
startangle=140,
textprops={'color': text_color, 'fontsize': 10}
)
# Poner en negritas las etiquetas de porcentaje
for autotext in autotexts:
autotext.set_fontweight('bold')
ax.axis('equal') # mantener el círculo como círculo, no como óvalo
autopct='%1.1f%%' le indica a Matplotlib que calcule la proporción de cada rebanada y la imprima con un decimal. No necesitas calcular los porcentajes tú mismo.
El script también revisa si hay datos incorrectos antes de graficar. Una gráfica circular no puede mostrar un valor negativo, así que las ventas negativas se filtran con una advertencia:
if (df['Sales'] < 0).any():
print("Warning: Negative sales values detected")
df = df[df['Sales'] >= 0]

4. Gráfica de Dona
Ideal para: las mismas tareas que una gráfica circular, con un aspecto más limpio y espacio en el centro.
Una gráfica de dona es una gráfica circular con el centro removido. A muchas personas les resulta más fácil de leer, porque se comparan las longitudes de los arcos en lugar de los ángulos de las rebanadas. El centro vacío también es un buen lugar para colocar un total o una etiqueta.
Solo se necesita un argumento adicional, wedgeprops, para recortar el centro:
wedges, texts, autotexts = ax.pie(
sizes,
labels=labels,
colors=colors,
autopct='%1.1f%%',
startangle=140,
wedgeprops={"width": 0.45}, # grosor del anillo; esto la convierte en dona
pctdistance=0.75, # colocar los porcentajes sobre el anillo
labeldistance=1.10, # mover los nombres de producto hacia afuera
textprops={'color': text_color, 'fontsize': 10}
)

5. Gráfica de Líneas
Ideal para: tendencias a lo largo del tiempo u otros datos continuos.
Las gráficas de líneas muestran alzas, caídas y patrones a lo largo de intervalos de tiempo, como las ventas mensuales, el tráfico de un sitio web, las temperaturas o los precios de las acciones. Úsalas cuando cada punto de datos se conecta con el siguiente.
ax.plot(
df['Month'],
df['Sales'],
marker='o', # un punto en cada dato
markerfacecolor=marker_color,
linestyle='-',
color=line_color,
linewidth=2
)
ax.grid(True, linestyle='-', alpha=0.3, color='gray')
plt.xticks(rotation=45, ha='right') # inclinar las etiquetas para que no se encimen
plt.tight_layout() # evitar que las etiquetas se recorten
Los marcadores facilitan identificar el valor de cada mes, y la línea muestra la dirección general. Aquí, las ventas suben claramente a lo largo del año.

6. Gráfica de Dispersión
Ideal para: relaciones o correlaciones entre dos variables numéricas.
Las gráficas de dispersión te ayudan a encontrar patrones, agrupaciones y valores atípicos, como estatura vs. peso o ventas vs. gasto en publicidad. A diferencia de una gráfica de líneas, los puntos no están conectados, por lo que el enfoque está en cómo se distribuyen los valores y no en una secuencia.
# Asegurarse de que Sales sea realmente numérico antes de graficar
if not pd.api.types.is_numeric_dtype(df['Sales']):
raise ValueError("Sales column must contain numeric values")
ax.scatter(
df['Month'],
df['Sales'],
color=point_color,
alpha=1.0,
s=100 # tamaño del punto
)
La verificación numérica es una buena práctica. Si un CSV contiene un valor como "$12,000", Pandas lee toda la columna como texto, y la gráfica lo representará de forma incorrecta sin avisar.

7. Gráfica de Medidor
Ideal para: mostrar un solo valor frente a una meta o un rango.
Las gráficas de medidor son comunes en los dashboards para KPIs, seguimiento de metas y métricas de sistemas. Responden una pregunta de un vistazo: ¿qué tan cerca estamos?
Matplotlib no incluye una gráfica de medidor, así que este script la dibuja desde cero. Construye dos arcos semicirculares con polígonos: un arco gris de fondo para el rango completo y un arco de color para el valor actual.
import numpy as np
import matplotlib.patches as patches
percentage = (value / max_value) * 100
outer_radius, inner_radius = 1.0, 0.7
# Arco de color: empieza en 180° (izquierda) y avanza a la derecha según el porcentaje
end_angle_value = 180 - (percentage / 100 * 180)
theta = np.linspace(np.radians(180), np.radians(end_angle_value), 100)
outer = list(zip(outer_radius * np.cos(theta), outer_radius * np.sin(theta)))
inner = list(zip(inner_radius * np.cos(theta[::-1]), inner_radius * np.sin(theta[::-1])))
ax.add_patch(patches.Polygon(outer + inner, facecolor=gauge_value_color, edgecolor='none'))
# Número grande en el centro
ax.text(0, 0.2, f'{percentage:.1f}%', ha='center', va='center', fontsize=36)
El valor viene directamente de los datos. El script suma las ventas de los primeros ocho meses y las compara con el total del año completo:
reported_sale = df["Sales"].iloc[0:8].sum()
total_sales = df["Sales"].sum()
Sustituye la meta por la tuya, como un objetivo trimestral, y la misma gráfica de medidor se convierte en un indicador de avance.

8. Mapa de EE. UU. (Coroplético)
Ideal para: datos con un componente geográfico.
Un mapa coroplético sombrea cada región según su valor. La población, las ventas por territorio y las ubicaciones de los clientes se vuelven fáciles de leer al colocarlas en un mapa, porque los patrones regionales saltan a la vista de una manera en que nunca lo hacen en una tabla.
Este script usa GeoPandas para descargar los contornos de los estados de EE. UU. desde Natural Earth, y luego los une con los datos de población usando el código de dos letras del estado:
import geopandas as gpd
url = "https://naciscdn.org/naturalearth/110m/cultural/ne_110m_admin_1_states_provinces.zip"
states = gpd.read_file(url)
# Solo los estados continentales de EE. UU.
usa = states[states['admin'] == 'United States of America']
usa = usa[~usa['postal'].isin(['AK', 'HI'])]
# Unir las formas del mapa con los datos de nuestro CSV
usa = usa.merge(df, left_on='postal', right_on='Code', how='left')
usa.plot(
column='Population',
ax=ax,
cmap='Blues', # azul más oscuro = más habitantes
legend=True,
edgecolor=edge_color,
linewidth=0.5,
missing_kwds={'color': missing_color} # estados sin datos
)
ax.axis('off')
El merge() es el paso clave. Funciona como un join de SQL: cada forma de estado se relaciona con su fila en el CSV. Usar how='left' conserva todos los estados en el mapa, incluso si no tienen datos, y missing_kwds les asigna un gris neutro.
Ten en cuenta que el archivo de formas se descarga cada vez, por lo que este script necesita conexión a internet. Además, guarda el mapa en output/ sin abrir una ventana.

¿Qué Gráfica Debes Usar?
| Gráfica | Úsala cuando quieras… | Ejemplo |
|---|---|---|
| Barras | Comparar categorías | Ventas por mes |
| Barras horizontales | Comparar categorías con etiquetas largas | Los 10 mejores productos |
| Circular | Mostrar partes de un todo (pocas categorías) | Participación de mercado |
| Dona | Mostrar partes de un todo con un aspecto más limpio | Desglose de un presupuesto |
| Líneas | Mostrar una tendencia a lo largo del tiempo | Tráfico mensual de un sitio web |
| Dispersión | Encontrar relaciones entre dos números | Gasto en publicidad vs. ventas |
| Medidor | Mostrar el avance hacia una meta | KPI vs. objetivo |
| Mapa | Mostrar patrones geográficos | Clientes por estado |
Una buena regla: empieza por lo que quieres que el lector note, y luego elige la gráfica que lo haga más fácil de ver. Para una comparación, usa barras. Para una tendencia, usa una línea. Para la proporción de un total, usa una gráfica circular o de dona. Para una ubicación, usa un mapa.
Consejos para Mejores Gráficas
- Siempre agrega un título y etiquetas en los ejes. Una gráfica sin etiquetas obliga al lector a adivinar.
- Elimina el desorden. Ocultar los bordes y atenuar las líneas de cuadrícula, como hacen estos scripts, mantiene la atención en los datos.
- Ordena las categorías con intención. Usa el orden de calendario para los meses y de mayor a menor para las clasificaciones.
- Limita las rebanadas de las gráficas circulares y de dona a unas cinco o seis. Agrupa el resto en “Otros”.
- Valida tus datos primero. Revisa si faltan archivos, si faltan columnas, si hay valores negativos y si hay texto en columnas numéricas antes de graficar.
- Haz coincidir el tema con el destino. Usa el modo claro para reportes impresos y la mayoría de los sitios web, y el modo oscuro para dashboards y presentaciones oscuras.
Obtén el Código
Los ocho scripts, los datos de ejemplo y las imágenes de salida en modo claro y oscuro están en GitHub:
github.com/victorhugo81/PythonVisualizationCharts
Clona el repositorio, reemplaza los archivos CSV con tus propios datos y tendrás gráficas profesionales en minutos. Si también trabajas con Power BI, mi publicación Power BI 101: Introduction to Visualization Charts cubre los mismos tipos de gráficas desde la perspectiva de inteligencia de negocios.
