Skip to content

Commit 60bb880

Browse files
committed
Merge pull request #3860 from qwhelan/plotting_colormap
Add colormap= argument to DataFrame plotting methods
2 parents c9d48b5 + b5265a5 commit 60bb880

File tree

5 files changed

+223
-47
lines changed

5 files changed

+223
-47
lines changed

doc/source/release.rst

+2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ pandas 0.12
5252
- A ``filter`` method on grouped Series or DataFrames returns a subset of
5353
the original (:issue:`3680`, :issue:`919`)
5454
- Access to historical Google Finance data in pandas.io.data (:issue:`3814`)
55+
- DataFrame plotting methods can sample column colors from a Matplotlib
56+
colormap via the ``colormap`` keyword. (:issue:`3860`)
5557

5658
**Improvements to existing features**
5759

doc/source/v0.12.0.txt

+6
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ API changes
9696
and thus you should cast to an appropriate numeric dtype if you need to
9797
plot something.
9898

99+
- Add ``colormap`` keyword to DataFrame plotting methods. Accepts either a
100+
matplotlib colormap object (ie, matplotlib.cm.jet) or a string name of such
101+
an object (ie, 'jet'). The colormap is sampled to select the color for each
102+
column. Please see :ref:`visualization.colormaps` for more information.
103+
(:issue:`3860`)
104+
99105
- ``DataFrame.interpolate()`` is now deprecated. Please use
100106
``DataFrame.fillna()`` and ``DataFrame.replace()`` instead. (:issue:`3582`,
101107
:issue:`3675`, :issue:`3676`)

doc/source/visualization.rst

+62
Original file line numberDiff line numberDiff line change
@@ -531,3 +531,65 @@ be colored differently.
531531
532532
@savefig radviz.png width=6in
533533
radviz(data, 'Name')
534+
535+
.. _visualization.colormaps:
536+
537+
Colormaps
538+
~~~~~~~~~
539+
540+
A potential issue when plotting a large number of columns is that it can be difficult to distinguish some series due to repetition in the default colors. To remedy this, DataFrame plotting supports the use of the ``colormap=`` argument, which accepts either a Matplotlib `colormap <http://matplotlib.org/api/cm_api.html>`__ or a string that is a name of a colormap registered with Matplotlib. A visualization of the default matplotlib colormaps is available `here <http://wiki.scipy.org/Cookbook/Matplotlib/Show_colormaps>`__.
541+
542+
As matplotlib does not directly support colormaps for line-based plots, the colors are selected based on an even spacing determined by the number of columns in the DataFrame. There is no consideration made for background color, so some colormaps will produce lines that are not easily visible.
543+
544+
To use the jet colormap, we can simply pass ``'jet'`` to ``colormap=``
545+
546+
.. ipython:: python
547+
548+
df = DataFrame(randn(1000, 10), index=ts.index)
549+
df = df.cumsum()
550+
551+
plt.figure()
552+
553+
@savefig jet.png width=6in
554+
df.plot(colormap='jet')
555+
556+
or we can pass the colormap itself
557+
558+
.. ipython:: python
559+
560+
from matplotlib import cm
561+
562+
plt.figure()
563+
564+
@savefig jet_cm.png width=6in
565+
df.plot(colormap=cm.jet)
566+
567+
Colormaps can also be used other plot types, like bar charts:
568+
569+
.. ipython:: python
570+
571+
dd = DataFrame(randn(10, 10)).applymap(abs)
572+
dd = dd.cumsum()
573+
574+
plt.figure()
575+
576+
@savefig greens.png width=6in
577+
dd.plot(kind='bar', colormap='Greens')
578+
579+
Parallel coordinates charts:
580+
581+
.. ipython:: python
582+
583+
plt.figure()
584+
585+
@savefig parallel_gist_rainbow.png width=6in
586+
parallel_coordinates(data, 'Name', colormap='gist_rainbow')
587+
588+
Andrews curves charts:
589+
590+
.. ipython:: python
591+
592+
plt.figure()
593+
594+
@savefig andrews_curve_winter.png width=6in
595+
andrews_curves(data, 'Name', colormap='winter')

pandas/tests/test_graphics.py

+62
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,35 @@ def test_bar_colors(self):
103103
self.assert_(xp == rs)
104104

105105
plt.close('all')
106+
107+
from matplotlib import cm
108+
109+
# Test str -> colormap functionality
110+
ax = df.plot(kind='bar', colormap='jet')
111+
112+
rects = ax.patches
113+
114+
rgba_colors = map(cm.jet, np.linspace(0, 1, 5))
115+
for i, rect in enumerate(rects[::5]):
116+
xp = rgba_colors[i]
117+
rs = rect.get_facecolor()
118+
self.assert_(xp == rs)
119+
120+
plt.close('all')
121+
122+
# Test colormap functionality
123+
ax = df.plot(kind='bar', colormap=cm.jet)
124+
125+
rects = ax.patches
126+
127+
rgba_colors = map(cm.jet, np.linspace(0, 1, 5))
128+
for i, rect in enumerate(rects[::5]):
129+
xp = rgba_colors[i]
130+
rs = rect.get_facecolor()
131+
self.assert_(xp == rs)
132+
133+
plt.close('all')
134+
106135
df.ix[:, [0]].plot(kind='bar', color='DodgerBlue')
107136

108137
@slow
@@ -600,6 +629,7 @@ def test_andrews_curves(self):
600629
def test_parallel_coordinates(self):
601630
from pandas import read_csv
602631
from pandas.tools.plotting import parallel_coordinates
632+
from matplotlib import cm
603633
path = os.path.join(curpath(), 'data/iris.csv')
604634
df = read_csv(path)
605635
_check_plot_works(parallel_coordinates, df, 'Name')
@@ -611,6 +641,7 @@ def test_parallel_coordinates(self):
611641
colors=('#556270', '#4ECDC4', '#C7F464'))
612642
_check_plot_works(parallel_coordinates, df, 'Name',
613643
colors=['dodgerblue', 'aquamarine', 'seagreen'])
644+
_check_plot_works(parallel_coordinates, df, 'Name', colormap=cm.jet)
614645

615646
df = read_csv(
616647
path, header=None, skiprows=1, names=[1, 2, 4, 8, 'Name'])
@@ -622,9 +653,11 @@ def test_parallel_coordinates(self):
622653
def test_radviz(self):
623654
from pandas import read_csv
624655
from pandas.tools.plotting import radviz
656+
from matplotlib import cm
625657
path = os.path.join(curpath(), 'data/iris.csv')
626658
df = read_csv(path)
627659
_check_plot_works(radviz, df, 'Name')
660+
_check_plot_works(radviz, df, 'Name', colormap=cm.jet)
628661

629662
@slow
630663
def test_plot_int_columns(self):
@@ -666,6 +699,7 @@ def test_line_colors(self):
666699
import matplotlib.pyplot as plt
667700
import sys
668701
from StringIO import StringIO
702+
from matplotlib import cm
669703

670704
custom_colors = 'rgcby'
671705

@@ -691,6 +725,30 @@ def test_line_colors(self):
691725
finally:
692726
sys.stderr = tmp
693727

728+
plt.close('all')
729+
730+
ax = df.plot(colormap='jet')
731+
732+
rgba_colors = map(cm.jet, np.linspace(0, 1, len(df)))
733+
734+
lines = ax.get_lines()
735+
for i, l in enumerate(lines):
736+
xp = rgba_colors[i]
737+
rs = l.get_color()
738+
self.assert_(xp == rs)
739+
740+
plt.close('all')
741+
742+
ax = df.plot(colormap=cm.jet)
743+
744+
rgba_colors = map(cm.jet, np.linspace(0, 1, len(df)))
745+
746+
lines = ax.get_lines()
747+
for i, l in enumerate(lines):
748+
xp = rgba_colors[i]
749+
rs = l.get_color()
750+
self.assert_(xp == rs)
751+
694752
# make color a list if plotting one column frame
695753
# handles cases like df.plot(color='DodgerBlue')
696754
plt.close('all')
@@ -862,6 +920,10 @@ def test_option_mpl_style(self):
862920
except ValueError:
863921
pass
864922

923+
def test_invalid_colormap(self):
924+
df = DataFrame(np.random.randn(500, 2), columns=['A', 'B'])
925+
926+
self.assertRaises(ValueError, df.plot, colormap='invalid_colormap')
865927

866928
def _check_plot_works(f, *args, **kwargs):
867929
import matplotlib.pyplot as plt

0 commit comments

Comments
 (0)