traçar um círculo com pyplot

158

surpreendentemente, não encontrei uma descrição direta sobre como desenhar um círculo com o matplotlib.pyplot (por favor, sem o pylab) tomando como centro de entrada (x, y) e raio r. Eu tentei algumas variantes disso:

import matplotlib.pyplot as plt
circle=plt.Circle((0,0),2)
# here must be something like circle.plot() or not?
plt.show()

... mas ainda não funcionou.

Max Li
fonte
Tenho certeza de que é possível fazer isso, mas o matplotlib visa principalmente a plotagem (ou seja, aqui estão alguns dados, coloque-os em um gráfico), não o desenho, portanto, pode não ser totalmente direto.
Thomas K
O raio dos pontos do gráfico de dispersão é cada vez mais usado para visualizar dados. Os gráficos do Google os chamam de "gráficos de bolhas". Gapminder.org é um bom exemplo. Isso é traçar, não desenhar. Pesquisei no repositório do matplotlib github "bolha" e "raio de dispersão" sem sucesso; portanto, acho que isso não está na lista de tarefas a adicionar ao recurso.
Bennett Brown
1
plt.scatter () aceita um argumento de tamanho. Você pode passar listas para as coordenadas xe y dos círculos, os raios dos círculos e as cores dos círculos. matplotlib.org/1.3.1/api/… . Meu erro anterior, ao pensar que essa funcionalidade ainda não estava no matplotlib.
Bennett Brown
3
Apenas para mencionar: plt.Circle(..)direciona para matplotlib.patches.Circle(). Portanto, uma solução sem pyplot seria circle = matplotlib.patches.Circle(..); axes.add_artist(circle).
ImportanceOfBeingErnest

Respostas:

203

Você precisa adicioná-lo aos eixos. A Circleé uma subclasse de an Artiste an axespossui um add_artistmétodo

Aqui está um exemplo de como fazer isso:

import matplotlib.pyplot as plt

circle1 = plt.Circle((0, 0), 0.2, color='r')
circle2 = plt.Circle((0.5, 0.5), 0.2, color='blue')
circle3 = plt.Circle((1, 1), 0.2, color='g', clip_on=False)

fig, ax = plt.subplots() # note we must use plt.subplots, not plt.subplot
# (or if you have an existing figure)
# fig = plt.gcf()
# ax = fig.gca()

ax.add_artist(circle1)
ax.add_artist(circle2)
ax.add_artist(circle3)

fig.savefig('plotcircles.png')

Isso resulta na seguinte figura:

O primeiro círculo está na origem, mas por padrão clip_onestá True, então o círculo é cortado sempre que se estende além do axes. O terceiro círculo (verde) mostra o que acontece quando você não recorta o Artist. Ela se estende além dos eixos (mas não além da figura, ou seja, o tamanho da figura não é ajustado automaticamente para plotar todos os seus artistas).

As unidades para x, ye raio correspondem às unidades de dados por padrão. Nesse caso, eu não plotei nada nos meus eixos ( fig.gca()retorna os eixos atuais) e, como os limites nunca foram definidos, eles assumem o padrão de x e y de 0 a 1.

Aqui está uma continuação do exemplo, mostrando como as unidades são importantes:

circle1 = plt.Circle((0, 0), 2, color='r')
# now make a circle with no fill, which is good for hi-lighting key results
circle2 = plt.Circle((5, 5), 0.5, color='b', fill=False)
circle3 = plt.Circle((10, 10), 2, color='g', clip_on=False)

ax = plt.gca()
ax.cla() # clear things for fresh plot

# change default range so that new circles will work
ax.set_xlim((0, 10))
ax.set_ylim((0, 10))
# some data
ax.plot(range(11), 'o', color='black')
# key data point that we are encircling
ax.plot((5), (5), 'o', color='y')

ax.add_artist(circle1)
ax.add_artist(circle2)
ax.add_artist(circle3)
fig.savefig('plotcircles2.png')

o que resulta em:

Você pode ver como eu defino o preenchimento do segundo círculo False, o que é útil para envolver os principais resultados (como meu ponto de dados amarelo).

Yann
fonte
4
Eu gosto dessa resposta porque você está "desenhando" um círculo, em vez de traçar. Embora tramar teria sido meu primeiro instinto também.
Samb8s
7
FYI: Parece que a classe Circle mudou de matplotlib.pyplot para matplotlib.patches desde que esta resposta foi escrita.
Pavon
6
Mas mas mas os círculos são ovais!
21816 Rubenvb
1
@rubenvb veja minha outra resposta: stackoverflow.com/questions/9230389/…
Yann
3
@pavon Para mim matplotlib.pyplot.Circle == matplotlib.patches.Circleavalia True, então provavelmente são aliases.
Evgeni Sergeev
66
import matplotlib.pyplot as plt
circle1=plt.Circle((0,0),.2,color='r')
plt.gcf().gca().add_artist(circle1)

Uma versão resumida rápida da resposta aceita, para conectar rapidamente um círculo a um gráfico existente. Consulte a resposta aceita e outras respostas para entender os detalhes.

A propósito:

  • gcf() significa Obter figura atual
  • gca() significa obter eixo atual
jmn
fonte
4
Perfeito! exatamente o que eu precisava ver agora. Seu 'A propósito' também foi bastante útil! dir(fig)mostra mais de 30 métodos 'get', mas gcanão tem get_current_axisalias. Essas respostas são maravilhosas.
uhoh
6
você pode realmente fazer plt.gca(), em vez deplt.gcf().gca()
Andre Holzner
38

Se você deseja plotar um conjunto de círculos, pode ver esta postagem ou essa essência (um pouco mais recente). O cargo oferecido uma função chamada circles.

A função circlesfunciona assim scatter, mas os tamanhos dos círculos plotados estão na unidade de dados.

Aqui está um exemplo:

from pylab import *
figure(figsize=(8,8))
ax=subplot(aspect='equal')

#plot one circle (the biggest one on bottom-right)
circles(1, 0, 0.5, 'r', alpha=0.2, lw=5, edgecolor='b', transform=ax.transAxes)

#plot a set of circles (circles in diagonal)
a=arange(11)
out = circles(a, a, a*0.2, c=a, alpha=0.5, edgecolor='none')
colorbar(out)

xlim(0,10)
ylim(0,10)

insira a descrição da imagem aqui

Syrtis Major
fonte
O que transform=ax.transAxesfaz?
Lee
3
@ Lee É para o círculo no canto inferior direito, transforme os dados em coordenadas de eixos, ou seja, (1,1) significa canto superior direito em eixos, (1,0) significa canto inferior direito, etc.
Syrtis Major
4
Isso deve fazer parte do matplotlib.
JustAC0der
Isso pode ser usado com mplleaflet? Se sim, você poderia dar um exemplo, por favor?
François M.
@fmalaussena Como esse trecho de código é puro matplotlib, acho que deve ser compatível, mplleafletembora eu nunca tenha tentado.
Syrtis Major
21
#!/usr/bin/python
import matplotlib.pyplot as plt
import numpy as np

def xy(r,phi):
  return r*np.cos(phi), r*np.sin(phi)

fig = plt.figure()
ax = fig.add_subplot(111,aspect='equal')  

phis=np.arange(0,6.28,0.01)
r =1.
ax.plot( *xy(r,phis), c='r',ls='-' )
plt.show()

Ou, se preferir, consulte paths, http://matplotlib.sourceforge.net/users/path_tutorial.html

ev-br
fonte
2
Equação trigonométrica de um círculo e graus 0 TP 360, o que se traduz para 0 a 6,28319 radianos mathopenref.com/coordparamcircle.html
Alex Punnen
19

Se você deseja que o "círculo" mantenha uma proporção visual de 1, independentemente das coordenadas dos dados, você pode usar o método scatter (). http://matplotlib.org/1.3.1/api/pyplot_api.html#matplotlib.pyplot.scatter

import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [10, 20, 30, 40, 50]
r = [100, 80, 60, 40, 20] # in points, not data units
fig, ax = plt.subplots(1, 1)
ax.scatter(x, y, s=r)
fig.show()

A imagem é um gráfico de dispersão.  Cinco círculos ao longo da linha y = 10x têm raios decrescentes do canto inferior esquerdo para o canto superior direito.  Embora o gráfico tenha formato quadrado, o eixo y tem 10 vezes o intervalo do eixo x.  Mesmo assim, a proporção dos círculos é 1 na tela.

Bennett Brown
fonte
11

Estendendo a resposta aceita para um caso de uso comum. Em particular:

  1. Veja os círculos em uma proporção natural.

  2. Estenda automaticamente os limites dos eixos para incluir os círculos recentemente plotados.

Exemplo independente:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.add_patch(plt.Circle((0, 0), 0.2, color='r', alpha=0.5))
ax.add_patch(plt.Circle((1, 1), 0.5, color='#00ffff', alpha=0.5))
ax.add_artist(plt.Circle((1, 0), 0.5, color='#000033', alpha=0.5))

#Use adjustable='box-forced' to make the plot area square-shaped as well.
ax.set_aspect('equal', adjustable='datalim')
ax.plot()   #Causes an autoscale update.
plt.show()

Observe a diferença entre ax.add_patch(..)e ax.add_artist(..): dos dois, apenas o primeiro faz com que o mecanismo de autoescalonamento leve em consideração o círculo (referência: discussão ); portanto, depois de executar o código acima, obtemos:

add_patch (..) vs add_artist (..)

Veja também: set_aspect(..)documentação .

Evgeni Sergeev
fonte
No python3, você precisa remover fig, ax = plt.subplots(), caso contrário, você terá duas janelas (uma está em branco).
albus_c
1

Vejo gráficos com o uso de (.circle), mas com base no que você pode querer fazer, também pode tentar isso:

import matplotlib.pyplot as plt
import numpy as np

x = list(range(1,6))
y = list(range(10, 20, 2))

print(x, y)

for i, data in enumerate(zip(x,y)):
    j, k = data
    plt.scatter(j,k, marker = "o", s = ((i+1)**4)*50, alpha = 0.3)

Gráfico de círculo concêntrico simples usando pontos de progresso lineares

centers = np.array([[5,18], [3,14], [7,6]])
m, n = make_blobs(n_samples=20, centers=[[5,18], [3,14], [7,6]], n_features=2, 
cluster_std = 0.4)
colors = ['g', 'b', 'r', 'm']

plt.figure(num=None, figsize=(7,6), facecolor='w', edgecolor='k')
plt.scatter(m[:,0], m[:,1])

for i in range(len(centers)):

    plt.scatter(centers[i,0], centers[i,1], color = colors[i], marker = 'o', s = 13000, alpha = 0.2)
    plt.scatter(centers[i,0], centers[i,1], color = 'k', marker = 'x', s = 50)

plt.savefig('plot.png')

Pontos circulados de um problema de classificação.

inyang kpongette
fonte
0

Olá, eu escrevi um código para desenhar um círculo. Isso ajudará a desenhar todos os tipos de círculos. A imagem mostra o círculo com raio 1 e centro em 0,0 O centro e o raio podem ser editados de qualquer escolha.

## Draw a circle with center and radius defined
## Also enable the coordinate axes
import matplotlib.pyplot as plt
import numpy as np
# Define limits of coordinate system
x1 = -1.5
x2 = 1.5
y1 = -1.5
y2 = 1.5

circle1 = plt.Circle((0,0),1, color = 'k', fill = False, clip_on = False)
fig, ax = plt.subplots()
ax.add_artist(circle1)
plt.axis("equal")
ax.spines['left'].set_position('zero')
ax.spines['bottom'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
plt.xlim(left=x1)
plt.xlim(right=x2)
plt.ylim(bottom=y1)
plt.ylim(top=y2)
plt.axhline(linewidth=2, color='k')
plt.axvline(linewidth=2, color='k')

##plt.grid(True)
plt.grid(color='k', linestyle='-.', linewidth=0.5)
plt.show()

Boa sorte

AJEET
fonte
0

Da mesma forma que a plotagem de dispersão, você também pode usar a plotagem normal com estilo de linha de círculo. Usando o markersizeparâmetro, você pode ajustar o raio de um círculo:

import matplotlib.pyplot as plt

plt.plot(200, 2, 'o', markersize=7)
Marcin Szałajski
fonte