HOWTO · Matplotlib

Cómo trazar un círculo en Matplotlib

Dibuja un círculo en Matplotlib con un patch `Circle`, a partir de su ecuación o mediante un marcador de dispersión.

En esta página

Para dibujar un círculo geométrico en Matplotlib, usa matplotlib.patches.Circle y añade el objeto patch a un Axes. También puedes representar un círculo a partir de su ecuación o usar un marcador de dispersión como símbolo circular. El patch suele ser la opción más directa cuando necesitas definir el centro y el radio en coordenadas de datos.

Dibujar un círculo con matplotlib.patches.Circle

matplotlib.patches.Circle crea un patch a partir de un centro (x, y) y un radio. Añádelo a un Axes con add_patch y establece una relación de aspecto igual para que una unidad del eje x tenga la misma longitud visual que una unidad del eje y.

import matplotlib.pyplot as plt
from matplotlib.patches import Circle

fig, ax = plt.subplots()
ax.add_patch(Circle((2, 1), radius=0.75, fill=False, linewidth=2))
ax.set_aspect("equal", adjustable="box")
ax.set_xlim(0, 4)
ax.set_ylim(-1, 3)
ax.set_title("Circle patch")
plt.show()

Resultado renderizado del ejemplo con el patch Circle: el contorno de un círculo sin rellenar, con centro en (2, 1) y radio 0,75, sobre unos ejes que van de 0 a 4 y de -1 a 3.

Cambia el primer argumento para mover el centro y radius para modificar el tamaño del círculo. Usa fill=True (el valor predeterminado) para rellenarlo, o fill=False para mostrar solo el contorno. Circle es un Artist, así que también puedes añadirlo con ax.add_artist(circle). Si ya tienes un gráfico, plt.gcf().gca().add_artist(circle) lo añade al Axes actual de la figura actual; usar un Axes explícito resulta más claro cuando la figura contiene varios gráficos.

Si estableces manualmente los límites de los ejes, incluye toda la extensión del círculo: para un centro (cx, cy) y un radio r, el intervalo de x debe abarcar desde cx - r hasta cx + r, y el de y, desde cy - r hasta cy + r. Si los límites quedan dentro de esos intervalos, se ocultará parte del patch o de la curva trazada a partir de la ecuación. Deja también margen suficiente si quieres que el contorno se vea con claridad cerca del borde del gráfico.

Dibujar un círculo a partir de su ecuación

Una ecuación paramétrica describe los puntos que forman un círculo. Para un centro (cx, cy) y un radio r, usa x = cx + r cos(theta) e y = cy + r sin(theta). Al muestrear ángulos desde cero hasta 2π, se traza la curva completa.

import numpy as np
import matplotlib.pyplot as plt

center_x, center_y = 2, 1
radius = 0.75
theta = np.linspace(0, 2 * np.pi, 200)
x = center_x + radius * np.cos(theta)
y = center_y + radius * np.sin(theta)

fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_aspect("equal", adjustable="box")
ax.set_title("Circle from a parametric equation")
plt.show()

Resultado renderizado del ejemplo paramétrico: una curva circular trazada a partir de los ángulos muestreados, con centro en (2, 1) y radio 0,75.

También se puede representar la ecuación centro-radio (x - cx)² + (y - cy)² = r² como un contorno de nivel cero. Resta r**2 al lado izquierdo, evalúa el resultado sobre una cuadrícula y dibuja el contorno de valor cero. Elige límites para la cuadrícula que incluyan todo el círculo y mantén la misma escala en ambos ejes; de lo contrario, la curva puede verse deformada.

import numpy as np
import matplotlib.pyplot as plt

center_x, center_y = 2, 1
radius = 0.75
x = np.linspace(center_x - radius - 0.25, center_x + radius + 0.25, 100)
y = np.linspace(center_y - radius - 0.25, center_y + radius + 0.25, 100)
X, Y = np.meshgrid(x, y)
values = (X - center_x) ** 2 + (Y - center_y) ** 2 - radius ** 2

fig, ax = plt.subplots()
ax.contour(X, Y, values, levels=[0])
ax.set_aspect("equal", adjustable="box")
ax.set_title("Circle from the center-radius equation")
plt.show()

Resultado renderizado del ejemplo de contorno: el contorno de nivel cero de la ecuación centro-radio forma un círculo con centro en (2, 1) y radio 0,75.

Dibujar un círculo con un marcador de dispersión

scatter dibuja un marcador en cada punto de datos indicado. Su argumento s define el área del marcador en puntos cuadrados, por lo que sirve para mostrar un símbolo circular cuyo tamaño visual se mantiene ligado a la pantalla, en lugar de un círculo geométrico cuyo radio se mide en coordenadas de datos.

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.scatter([2], [1], s=500, marker="o")
ax.set_xlim(0, 4)
ax.set_ylim(-1, 3)
ax.set_aspect("equal", adjustable="box")
ax.set_title("Circular scatter marker")
plt.show()

Resultado renderizado del ejemplo de dispersión: un único marcador circular relleno en el punto (2, 1), cuyo tamaño define el argumento s y no un radio en coordenadas de datos.

Aumenta o reduce s para cambiar el área visual del marcador. Usa un patch Circle cuando el radio deba corresponder a distancias en los ejes del gráfico; elige un marcador de dispersión cuando quieras un símbolo de tamaño visual constante en un punto de datos.

Este tamaño ligado a la pantalla resulta útil para destacar puntos medidos, señalar un centro o colocar símbolos en gráficos que los lectores pueden ampliar. El tamaño del marcador se mantiene ligado a los puntos tipográficos aunque cambie la escala de los ejes, así que su tamaño aparente no representa una distancia fija en los datos trazados. Elige un patch o una curva basada en una ecuación cuando el círculo represente un radio que los lectores deban comparar con otros valores de datos.

Por qué un círculo puede parecer una elipse

Todos los ejemplos anteriores establecen una relación de aspecto igual con set_aspect("equal", adjustable="box"). Sin esa línea, Matplotlib usa la relación de aspecto automática: el Axes rellena su marco y, como el marco es más ancho que alto, una unidad del eje x se dibuja más larga que una unidad del eje y. El patch sigue siendo un círculo en coordenadas de datos, pero en pantalla parece una elipse. El ejemplo siguiente usa el mismo centro y radio que el primer ejemplo y solo omite la línea de la relación de aspecto.

import matplotlib.pyplot as plt
from matplotlib.patches import Circle

fig, ax = plt.subplots()
ax.add_patch(Circle((2, 1), radius=0.75, fill=False, linewidth=2))
ax.set_xlim(0, 4)
ax.set_ylim(-1, 3)
ax.set_title("Circle patch without an equal aspect ratio")
plt.show()

El mismo patch Circle sin una relación de aspecto igual: el círculo se estira hasta formar una elipse ancha porque el marco de los ejes es más ancho que alto.

La corrección consiste en añadir ax.set_aspect("equal", adjustable="box") antes de establecer los límites, como en los ejemplos anteriores. Las curvas basadas en ecuaciones y los contornos se deforman de la misma manera: sin una relación de aspecto igual, cualquier método de este artículo se ve estirado. Con adjustable="box", el Axes puede reducirse para que ambos ejes compartan la misma escala; es el comportamiento esperado y no un error en los datos.