Como fazer um gráfico de dispersão com círculos vazios em Python?

166

No Python, com o Matplotlib, como um gráfico de dispersão com círculos vazios pode ser plotado? O objetivo é desenhar círculos vazios em torno de alguns dos discos coloridos já plotados scatter(), de modo a destacá-los, idealmente sem ter que redesenhar os círculos coloridos.

Eu tentei facecolors=None, sem sucesso.

Eric O Lebigot
fonte
1
Pessoas que desejam desenhar gráficos de dispersão vazios / ocos com cores diferentes podem analisar esta questão .
ImportanceOfBeingErnest

Respostas:

242

Na documentação para dispersão:

Optional kwargs control the Collection properties; in particular:

    edgecolors:
        The string none to plot faces with no outlines
    facecolors:
        The string none to plot unfilled outlines

Tente o seguinte:

import matplotlib.pyplot as plt 
import numpy as np 

x = np.random.randn(60) 
y = np.random.randn(60)

plt.scatter(x, y, s=80, facecolors='none', edgecolors='r')
plt.show()

imagem de exemplo

Nota: Para outros tipos de gráficos, consulte este post sobre o uso de markeredgecolore markerfacecolor.

Gary Kerr
fonte
4
Obrigado! O problema é que o mais usual (em Python) facecolors=Nonenão funciona, o que me tropeçou.
Eric O Lebigot
24
Muito útil. É markerfacecolor='none'assim que é agora.
Hesham_EE 28/05
2
Eu tive meu estilo matplotlib de uma maneira que definiu as larguras das arestas como zero. Se você não vê quaisquer marcadores com markerfacecolor='none'tente adicionarmarkeredgewidth=1.0
olas
Essa abordagem também pode ser usada no Seaborn após fazer a importação padrão do Matplotlib %matplotlib inlinee import matplotlib.pyplot as plt, em seguida, definir o Seaborn como o padrão de plotagem porimport seaborn as sns; sns.set()
Jakob
68

Isso funcionaria?

plt.scatter(np.random.randn(100), np.random.randn(100), facecolors='none')

imagem de exemplo

ou usando plot ()

plt.plot(np.random.randn(100), np.random.randn(100), 'o', mfc='none')

imagem de exemplo

Gökhan Sever
fonte
3
isso é útil quando você usa em plotvez de #scatter
Trevor Boyd Smith
2
Para scatter, você precisa especificar edgecolorscomo edgecolors='r'. Caso contrário, os círculos desaparecem. Veja aqui
T_T
14

Aqui está outra maneira: isso adiciona um círculo aos eixos atuais, plotagem ou imagem ou o que for:

from matplotlib.patches import Circle  # $matplotlib/patches.py

def circle( xy, radius, color="lightsteelblue", facecolor="none", alpha=1, ax=None ):
    """ add a circle to ax= or current axes
    """
        # from .../pylab_examples/ellipse_demo.py
    e = Circle( xy=xy, radius=radius )
    if ax is None:
        ax = pl.gca()  # ax = subplot( 1,1,1 )
    ax.add_artist(e)
    e.set_clip_box(ax.bbox)
    e.set_edgecolor( color )
    e.set_facecolor( facecolor )  # "none" not None
    e.set_alpha( alpha )

texto alternativo

(Os círculos na imagem são compactados em reticências porque imshow aspect="auto").

denis
fonte
5

No matplotlib 2.0, existe um parâmetro chamado fillstyle que permite um melhor controle na maneira como os marcadores são preenchidos. No meu caso, usei-o com barras de erro, mas funciona para marcadores em geral http://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.errorbar.html

fillstyleaceita os seguintes valores: ['full' | 'esquerda' | 'certo' | 'fundo' | 'top' | 'Nenhum']

Há duas coisas importantes a serem lembradas ao usar fillstyle,

1) Se mfc for definido com qualquer tipo de valor, ele terá prioridade; portanto, se você definiu o estilo de preenchimento como 'none', isso não entrará em vigor. Portanto, evite usar mfc em conjunção com fillstyle

2) Você pode controlar a largura da borda do marcador (usando markeredgewidthou mew) porque se o marcador for relativamente pequeno e a largura da borda for espessa, os marcadores parecerão preenchidos, mesmo que não sejam.

A seguir, um exemplo usando barras de erro:

myplot.errorbar(x=myXval, y=myYval, yerr=myYerrVal, fmt='o', fillstyle='none', ecolor='blue',  mec='blue')
Salvatore Cosentino
fonte
2

Baseando-se no exemplo de Gary Kerr e, conforme proposto aqui, é possível criar círculos vazios relacionados aos valores especificados com o seguinte código:

import matplotlib.pyplot as plt 
import numpy as np 
from matplotlib.markers import MarkerStyle

x = np.random.randn(60) 
y = np.random.randn(60)
z = np.random.randn(60)

g=plt.scatter(x, y, s=80, c=z)
g.set_facecolor('none')
plt.colorbar()
plt.show()
Aroc
fonte
Esta é a versão essencialmente complexificada, a resposta aceita…
Eric O Lebigot
Do meu ponto, não é. O uso da plotagem de dispersão com cores não inclui facecolor = "none" no comando. Portanto, a remoção subsequente da cor da face é necessária, conforme descrito no link fornecido. Infelizmente, essa solução complexada é necessária para remover a cor da face em gráficos de dispersão com código de cores.
Aroc # 3/19
A abordagem nesta resposta é realmente útil se alguém deseja atualizar um gráfico que originalmente não contém círculos vazios. No entanto, a pergunta sobre a criação desses círculos diretamente, portanto, a solução aceita é o caminho a seguir, pois faz o mesmo que essa resposta, mas diretamente, sem nenhuma atualização estranha de um primeiro gráfico.
Eric O Lebigot
Essa "versão complexificada" funcionou para mim ao incorporar o argumento .scatter()não. Por contexto, eu também estava aplicando um mapa de cores ( c=z, cmap='jet').
Andrew Silver
1

Então, suponho que você queira destacar alguns pontos que se encaixam em um determinado critério. Você pode usar o comando do Prelude para fazer um segundo gráfico de dispersão dos pontos iluminados com um círculo vazio e uma primeira chamada para plotar todos os pontos. Verifique se o parâmetro s é suficientemente pequeno para que os círculos vazios maiores incluam os menores preenchidos.

A outra opção é não usar dispersão e desenhar os patches individualmente usando o comando circle / ellipse. Estes estão em matplotlib.patches, aqui está um código de exemplo sobre como desenhar retângulos de círculos etc.

whatnick
fonte