Repository: pandas-dev/pandas

Issue:
matplotlib table
it would be cool if a DataFrame could be displayed on a matplotlib plot, perhaps by calling the  table() function. 
( i am thinking about displaying the output of DataFrame.describe() or similar (small) amount of data)

related use of the table:
http://stackoverflow.com/questions/10194482/custom-matplotlib-plot-chess-board-like-table-with-colored-cells



Discussion:
Can you give an example plot?

here is an example of the table feature of matplotlib, if this is thats what you mean. 

http://matplotlib.org/examples/pylab_examples/table_demo.html

so i am using ipython notebook, which automatically displays DataFrames, which is great. but it would be nice to incorporate the table into a plot. 

here is an example  

![screenshot from 2013-09-11 10 07 35](https://f.cloud.github.com/assets/1228240/1123240/b22dfed6-1aeb-11e3-82d3-653247a52fd1.png)

you can easily do this directly with the axis

just format the 'text' with in-line matplotlib: http://stackoverflow.com/questions/8482588/putting-text-in-top-left-corner-of-matplotlib-plot

```
t = '$coef = %12.2f$\n$tstat = %12.2f$\n$r2 = %12.2f$\n'%(coeff,r.t_stat[pl],r.r2_adj)
ax.text(0.05, 0.95, t, transform=ax.transAxes, fontsize=7, family='monospace', multialignment = 'left', verticalalignment='top', bbox=props)
```

btw - that is a really nice-looking plot. Would you mind posting the code you used to generate it?

We could consider consider this as a feature (or think of it like another display backend for a DataFrame), so you could convert any DataFrame into a format suitable for inserting into a matplotlib chart as text....

http://nbviewer.ipython.org/6528228

@arsenovic pls submit a PR for this..nice!

@jreback  submit it to what exactly?

submit a pull request. see the wiki page on contributing for more details

yeah, i am familiar with contributing, i suppose i was saying its not obvious to me  where in pandas this would fit

well...this could be an additional set of options to `.plot` I suppose

e.g

`df.plot(....., table = { 'color' : 'blue', loc : 'bottom' })`

maybe need some formatting info for the actual data, (e.g. a float_format)

should be straightforward to do

i never got around to adding this, but  for anyone interested this yields nice results. 

```
import pandas as pd
from pylab import *
df= pd.DataFrame(rand(100))
df.hist()
def draw_describe_table(df, cellFmt ='%.1e', colWidths= [.1,.2], 
                        loc = 'center right', **kwargs):

    kwargs.update({'colWidths':colWidths,'loc':loc})
    kwargs['cellText'] = array([cellFmt%k for k in df.describe().values]).reshape(-1,1)
    kwargs['rowLabels'] = df.describe().index.values
    kwargs['zorder']=100 # prevents grid from drawing ontop of table

    tab = table(**kwargs )
    return tab

draw_describe_table(df)
```

![download](https://f.cloud.github.com/assets/1228240/1889437/96ef3290-7a1b-11e3-9317-870ab332b4fa.png)

pls make a pull request for that!

and API maybe would supply a `table` keyword to plot/hist?


Resolving patch:
diff --git a/pandas/tools/plotting.py b/pandas/tools/plotting.py
--- a/pandas/tools/plotting.py
+++ b/pandas/tools/plotting.py
@@ -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
@@ -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()
@@ -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()
 
@@ -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
 
@@ -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}
@@ -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)


Test patch:
diff --git a/pandas/tests/test_graphics.py b/pandas/tests/test_graphics.py
--- a/pandas/tests/test_graphics.py
+++ b/pandas/tests/test_graphics.py
@@ -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):
@@ -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):