Reputation: 483
I'm trying to produce a series of scatter plots with square and unfilled markers for each data point, with different but deterministic marker colors between runs, for each array. To that end, I tried using the following code:
import matplotlib.pyplot as plt
import numpy as np
x = np.array([1,2,3,4,5,6,7,8,9,10])
plt.scatter(x, x**2, s=50, marker='s',facecolors='none')
plt.scatter(x, x**3, s=50, marker='s',facecolors='none')
plt.scatter(x, x**4, s=50, marker='s',facecolors='none')
which unfills the square markers, but does not leave any marker edges, so no output is actually seen. If I instead use
plt.scatter(x, x**2, s=50, marker='s',facecolors='none',edgecolors='r')
plt.scatter(x, x**3, s=50, marker='s',facecolors='none',edgecolors='g')
plt.scatter(x, x**4, s=50, marker='s',facecolors='none',edgecolors='b')
then I do indeed see a series of data plots represented by unfilled red squares, but the downside is that I have to explicitly set what color I want using edgecolor
. However, since my actual data will consist of a variable number of arrays, with the actual number being unknown before runtime, I'm looking to plot each data series in the same scatter plot and with different colors, but without having to explicitly specify what colors to use. I could use
plt.scatter(x, y, s=50, marker='s',facecolors='none',edgecolor=np.random.rand(3,))
as I've seen answered on this SO, but this is not ideal, as I'm hoping to have deterministic colors between runs. So for example, if I have 3 arrays, then the first array to be plotted is always color 'x', the second is always color 'y' and the third is always color 'z'. Extending this to n
arrays, the nth
array plotted is also always the same color (where n
could be very large).
As an example, if we consider a simple plot using filled colors, we see that the first 3 plots are always the same color (blue, orange, green), and even when a 4th plot is added the first 3 plots retain their original colors.
3 plots, with default pyplot colors
4 plots, with the original 3 plots retaining their original colors as in the first image above
EDIT: As an aside, does anyone know the reason behind not including edgefaces
(that would then allow us to easily use default pyplot colors) when setting facecolors='none'
? It seems like a rather strange design choice.
Upvotes: 4
Views: 12009
Reputation: 339560
Two things to note upfront.
You want to have n
different colors where n
is unknown a priori. Matplotlib's default color cycle has 10 colors. So if there is a chance that n
becomes larger than 10, the premise not to define any colors yourself breaks down. You will then need to either choose a custom color cycle or define the colors and loop over them anyways.
Scatter is mainly useful if you want to have differently colored or sized markers. If instead all markers are to be of the same color, one can easily use plot
instead.
Hence it seems
import matplotlib.pyplot as plt
import numpy as np
x = np.array([1,2,3,4,5,6,7,8,9,10])
plt.plot(x, x**2, ls='none', ms=7, marker='s', mfc='none')
plt.plot(x, x**3, ls='none', ms=7, marker='s', mfc='none')
plt.plot(x, x**4, ls='none', ms=7, marker='s', mfc='none')
plt.show()
would actually do what you need, as long as you have less than 11 plots to make.
If you really want to use a scatter plot, you could use a marker which consists of only the outline of a square, e.g. marker="$\u25A1$"
, similar to this answer,
import matplotlib.pyplot as plt
import numpy as np
x = np.array([1,2,3,4,5,6,7,8,9,10])
plt.scatter(x, x**2, s=50, marker="$\u25A1$")
plt.scatter(x, x**3, s=50, marker="$\u25A1$")
plt.scatter(x, x**4, s=50, marker="$\u25A1$")
plt.show()
Upvotes: 1
Reputation: 36736
You can create a colormap in matplotlib, and then include that in the iteration over the series.
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
x = np.array([1,2,3,4,5,6,7,8,9,10])
powers = [2, 3, 4]
# create a list of 5 colors from viridis, we only use the last 3, but there are
# 5 in the colormap
colors = cm.get_cmap('viridis', 5)
for c, p in zip(colors(powers), powers):
plt.scatter(x, x**p, s=50, marker='s',facecolors='none', edgecolor=c)
The issue you are running into is that the default color for edgecolor
is 'face'
, indicating that it will have the same color as the face color, which you set to 'none'
.
Upvotes: 3