Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pandas scatter plot colors with three points and seaborn

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()

like image 524
David Brochart Avatar asked Mar 25 '15 10:03

David Brochart


People also ask

Can you use seaborn and matplotlib together?

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.

How do you plot multiple scatter plots in seaborn?

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.


1 Answers

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:-

  • a string (such as 'b' in the original matplotlib case);
  • a sequence of color specifications (say a sequence of RGB values);
  • a sequence of values to map onto the current colormap.

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.

like image 118
Ffisegydd Avatar answered Oct 29 '22 17:10

Ffisegydd