There is a strange behavior when using pandas and seaborn to plot a scatter plot that has only three points: the points don't have the same color. The problem disappears when seaborn is not loaded or when there are more than three points, or when plotting with matplotlib's scatter method directly. See the following example:
from pandas import DataFrame #0.16.0
import matplotlib.pyplot as plt #1.4.3
import seaborn as sns #0.5.1
import numpy as np #1.9.2
df = DataFrame({'x': np.random.uniform(0, 1, 3), 'y': np.random.uniform(0, 1, 3)})
df.plot(kind = 'scatter', x = 'x', y = 'y')
plt.show()
df = DataFrame({'x': np.random.uniform(0, 1, 4), 'y': np.random.uniform(0, 1, 4)})
df.plot(kind = 'scatter', x = 'x', y = 'y')
plt.show()
Seaborn provides an API on top of Matplotlib that offers sane choices for plot style and color defaults, defines simple high-level functions for common statistical plot types, and integrates with the functionality provided by Pandas DataFrame s.
In Seaborn, we will plot multiple graphs in a single window in two ways. First with the help of Facetgrid() function and other by implicit with the help of matplotlib. data: Tidy dataframe where each column is a variable and each row is an observation.
I've tracked down the bug. The bug is in pandas
technically, not seaborn
as I originally thought, though it involves code from pandas
, seaborn
, and matplotlib
...
In pandas.tools.plotting.ScatterPlot._make_plot
the following code occurs to choose the colours to be used in the scatter plot
if c is None:
c_values = self.plt.rcParams['patch.facecolor']
elif c_is_column:
c_values = self.data[c].values
else:
c_values = c
In your case c
will be equal to None
, which is the default value, and so c_values
will be given by plt.rcParams['patch.facecolor']
.
Now, as part of setting itself up, seaborn modifies plt.rcParams['patch.facecolor']
to (0.5725490196078431, 0.7764705882352941, 1.0)
which is an RGB tuple. If seaborn
is not used then the value is the matplotlib default which is 'b'
(a string indicating the colour "blue").
c_values
is then used later on to actually plot the graph within ax.scatter
scatter = ax.scatter(data[x].values, data[y].values, c=c_values,
label=label, cmap=cmap, **self.kwds)
The issue arises because the keyword argument c
can accept multiple different types of argument, it can accept:-
'b'
in the original matplotlib case); The matplotlib docs specifically state the following, highlighting mine
c can be a single color format string, or a sequence of color specifications of length N, or a sequence of N numbers to be mapped to colors using the cmap and norm specified via kwargs (see below). Note that c should not be a single numeric RGB or RGBA sequence because that is indistinguishable from an array of values to be colormapped. c can be a 2-D array in which the rows are RGB or RGBA, however.
What basically happens is that matplotlib takes the c_values
value (which is a tuple of three numbers) and then maps those colours onto the current colormap (which is set by pandas to be Greys
by default). As such, you get three scatter points with different "greyishness". When you have more than 3 scatter points, matplotlib assumes that it must be a RGB tuple because the length doesn't match the length of the data arrays (3 != 4) and so uses it as a constant RBG colour.
This has been written up as a bug report on the pandas Github here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With