Mohamad Moosavi
Mohamad Moosavi

Reputation: 131

Matplotlib: scatter plot with colormaps for edgecolor but no facecolor

I want to have a scatter plot with colormap for edgecolors but no facecolors. When I use facecolor='None', it does not work.

import numpy as np
import matplotlib.pyplot as plt


N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2  # 0 to 15 point radii

plt.scatter(x, y, s=area,c=colors,facecolors='None',cmap="gist_rainbow", alpha=0.5)
plt.show()

Any solution?

Upvotes: 11

Views: 19969

Answers (4)

Fotac
Fotac

Reputation: 1

I wanted to answer to nasgold as I have found and answer for the colorbar. I have mixed answers from different topics to create the edgecolor and retrieve it for the colorbar.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcb
import matplotlib.cm as cm

N = 50
x = np.random.rand(N)
y = np.random.rand(N)
z = np.sqrt(x*y)

#we choose a colorblind palette
cmap = cm.plasma
#here we define the colors of edgecolors for the scatter plot with the min and max
norm = mcb.Normalize(z.min(),z.max())
edgecols = cmap(norm(z))

#we get the color from the edgecolors values
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array(edgecols)

plt.scatter(x,y,edgecolors=edgecols,
    c='none',marker='o',lw=1,s=10)

#we plot the colorbar with the colors from edgecolor                       
cbar = plt.colorbar(sm)

Upvotes: 0

nasgold
nasgold

Reputation: 11

I know this has been dead for a while, but I wanted to add my experience as I just encountered this same problem.

I prefer Diziet's method as passing the PathCollection object to a colorbar and having it match the cmap used in the scatter plot works exactly as it would if you didn't alter the facecolors.

With the accepted solution, however, I encountered some odd behavior where even after removing the cmap argument from the ax.scatter call the scatter plot edge colormap and the colorbar colormap didn't match.

Upvotes: 0

Diziet Asahi
Diziet Asahi

Reputation: 40737

The problem is that color= overrides the facecolors= argument.

The solution I came up with is to get the PathCollection returned by pyplot.scatter() and then change the facecolor directly. Note that you probably need to increase the line width to see the edges better.

import numpy as np
import matplotlib.pyplot as plt


N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2  # 0 to 15 point radii

a = plt.scatter(x, y, s=area,c=colors,facecolor='none',lw=2,cmap="gist_rainbow", alpha=0.5)
a.set_facecolor('none')
plt.show()

enter image description here

Upvotes: 7

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339560

The c argument will affect facecolor and edgecolor simultaneouly, the arguments facecolor and edgecolor are hence ignored.

A solution would be not to use the c argument together with a colormap, but instead use facecolors and edgecolors alone. In this case facecolors can be set to "None" and edgecolors can be given a list of colors to use.

To create this list, the same colormap can be applied.

c = plt.cm.gist_rainbow(colors)
plt.scatter(x, y, s=area,facecolors="None", edgecolors=c, lw=1,alpha=0.5)

A complete example:

import numpy as np
import matplotlib.pyplot as plt

N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2  # 0 to 15 point radii

c = plt.cm.gist_rainbow(colors)
plt.scatter(x, y, s=area,facecolors="None", edgecolors=c, lw=2,alpha=0.5)
plt.show()

enter image description here

Upvotes: 12

Related Questions