Skip to content

ENH/VIS: Plotting DataFrame/Series with matplotlib.table #6661

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 7, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions doc/source/release.rst
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,17 @@ API Changes

- Added ``nunique`` and ``value_counts`` functions to ``Index`` for counting unique elements. (:issue:`6734`)

- ``DataFrame.plot`` and ``Series.plot`` now support a ``table`` keyword for plotting ``matplotlib.Table``. The ``table`` kewyword can receive the following values.

- ``False``: Do nothing (default).

- ``True``: Draw a table using the ``DataFrame`` or ``Series`` called ``plot`` method. Data will be transposed to meet matplotlib's default layout.

- ``DataFrame`` or ``Series``: Draw matplotlib.table using the passed data. The data will be drawn as displayed in print method (not transposed automatically).

Also, helper function ``pandas.tools.plotting.table`` is added to create a table from ``DataFrame`` and ``Series``, and add it to an ``matplotlib.Axes``.


Deprecations
~~~~~~~~~~~~

Expand Down
11 changes: 11 additions & 0 deletions doc/source/v0.14.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,17 @@ API changes

- Added ``nunique`` and ``value_counts`` functions to ``Index`` for counting unique elements. (:issue:`6734`)

- ``DataFrame.plot`` and ``Series.plot`` now support a ``table`` keyword for plotting ``matplotlib.Table``. The ``table`` kewyword can receive the following values.

- ``False``: Do nothing (default).

- ``True``: Draw a table using the ``DataFrame`` or ``Series`` called ``plot`` method. Data will be transposed to meet matplotlib's default layout.

- ``DataFrame`` or ``Series``: Draw matplotlib.table using the passed data. The data will be drawn as displayed in print method (not transposed automatically).

Also, helper function ``pandas.tools.plotting.table`` is added to create a table from ``DataFrame`` and ``Series``, and add it to an ``matplotlib.Axes``.


MultiIndexing Using Slicers
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
42 changes: 42 additions & 0 deletions doc/source/visualization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,48 @@ Here is an example of one way to easily plot group means with standard deviation
@savefig errorbar_example.png
means.plot(yerr=errors, ax=ax, kind='bar')

Plotting With Table
~~~~~~~~~~~~~~~~~~~~~~~~

.. versionadded:: 0.14

Plotting with matplotlib table is now supported in the ``DataFrame.plot`` and ``Series.plot`` by a ``table`` keyword. The ``table`` keyword can accept ``bool``, ``DataFrame`` or ``Series``. The simple way to draw a table is to specify ``table=True``. Data will be transposed to meet matplotlib's default layout.

.. ipython:: python

fig, ax = plt.subplots(1, 1)
df = DataFrame(rand(5, 3), columns=['a', 'b', 'c'])
ax.get_xaxis().set_visible(False) # Hide Ticks

@savefig line_plot_table_true.png
df.plot(table=True, ax=ax)

Also, you can pass different ``DataFrame`` or ``Series`` for ``table`` keyword. The data will be drawn as displayed in print method (not transposed automatically). If required, it should be transposed manually as below example.

.. ipython:: python

fig, ax = plt.subplots(1, 1)
ax.get_xaxis().set_visible(False) # Hide Ticks
@savefig line_plot_table_data.png
df.plot(table=np.round(df.T, 2), ax=ax)


Finally, there is a helper function ``pandas.tools.plotting.table`` to create a table from ``DataFrame`` and ``Series``, and add it to an ``matplotlib.Axes``. This function can accept keywords which matplotlib table has.

.. ipython:: python

from pandas.tools.plotting import table
fig, ax = plt.subplots(1, 1)

table(ax, np.round(df.describe(), 2),
loc='upper right', colWidths=[0.2, 0.2, 0.2])

@savefig line_plot_table_describe.png
df.plot(ax=ax, ylim=(0, 2), legend=None)

**Note**: You can get table instances on the axes using ``axes.tables`` property for further decorations. See the `matplotlib table documenation <http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.table>`__ for more.


.. _visualization.scatter_matrix:

Scatter plot matrix
Expand Down
17 changes: 17 additions & 0 deletions pandas/tests/test_graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,11 @@ def test_errorbar_plot(self):
with tm.assertRaises(TypeError):
s.plot(yerr=s_err)

def test_table(self):
_check_plot_works(self.series.plot, table=True)
_check_plot_works(self.series.plot, table=self.series)


@tm.mplskip
class TestDataFramePlots(tm.TestCase):
def setUp(self):
Expand Down Expand Up @@ -1335,6 +1340,18 @@ def test_errorbar_asymmetrical(self):

tm.close()

def test_table(self):
df = DataFrame(np.random.rand(10, 3),
index=list(string.ascii_letters[:10]))
_check_plot_works(df.plot, table=True)
_check_plot_works(df.plot, table=df)

ax = df.plot()
self.assert_(len(ax.tables) == 0)
plotting.table(ax, df.T)
self.assert_(len(ax.tables) == 1)


@tm.mplskip
class TestDataFrameGroupByPlots(tm.TestCase):
def tearDown(self):
Expand Down
63 changes: 61 additions & 2 deletions pandas/tools/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,8 @@ def __init__(self, data, kind=None, by=None, subplots=False, sharex=True,
ax=None, fig=None, title=None, xlim=None, ylim=None,
xticks=None, yticks=None,
sort_columns=False, fontsize=None,
secondary_y=False, colormap=None, **kwds):
secondary_y=False, colormap=None,
table=False, **kwds):

self.data = data
self.by = by
Expand Down Expand Up @@ -849,6 +850,8 @@ def __init__(self, data, kind=None, by=None, subplots=False, sharex=True,
else:
self.colormap = colormap

self.table = table

self.kwds = kwds

self._validate_color_args()
Expand Down Expand Up @@ -915,6 +918,7 @@ def generate(self):
self._compute_plot_data()
self._setup_subplots()
self._make_plot()
self._add_table()
self._post_plot_logic()
self._adorn_subplots()

Expand Down Expand Up @@ -1005,6 +1009,21 @@ def _compute_plot_data(self):
def _make_plot(self):
raise NotImplementedError

def _add_table(self):
if self.table is False:
return
elif self.table is True:
from pandas.core.frame import DataFrame
if isinstance(self.data, Series):
data = DataFrame(self.data, columns=[self.data.name])
elif isinstance(self.data, DataFrame):
data = self.data
data = data.transpose()
else:
data = self.table
ax = self._get_ax(0)
table(ax, data)

def _post_plot_logic(self):
pass

Expand Down Expand Up @@ -1664,7 +1683,6 @@ def _post_plot_logic(self):
for ax in self.axes:
ax.legend(loc='best')


class BarPlot(MPLPlot):

_default_rot = {'bar': 90, 'barh': 0}
Expand Down Expand Up @@ -2594,6 +2612,47 @@ def _grouped_plot_by_column(plotf, data, columns=None, by=None,
return fig, axes


def table(ax, data, rowLabels=None, colLabels=None,
**kwargs):

"""
Helper function to convert DataFrame and Series to matplotlib.table

Parameters
----------
`ax`: Matplotlib axes object
`data`: DataFrame or Series
data for table contents
`kwargs`: keywords, optional
keyword arguments which passed to matplotlib.table.table.
If `rowLabels` or `colLabels` is not specified, data index or column name will be used.

Returns
-------
matplotlib table object
"""
from pandas import DataFrame
if isinstance(data, Series):
data = DataFrame(data, columns=[data.name])
elif isinstance(data, DataFrame):
pass
else:
raise ValueError('Input data must be dataframe or series')

if rowLabels is None:
rowLabels = data.index

if colLabels is None:
colLabels = data.columns

cellText = data.values

import matplotlib.table
table = matplotlib.table.table(ax, cellText=cellText,
rowLabels=rowLabels, colLabels=colLabels, **kwargs)
return table


def _get_layout(nplots):
if nplots == 1:
return (1, 1)
Expand Down