Repository: pandas-dev/pandas

Issue:
pandas.core.groupby.SeriesGroupBy.hist doesn't take kwargs
I'd like to pass certain kwargs to the hist function of a SeriesGroupBy object (alpha, legend, etc). The plot function provides more kwargs (e.g. legend, but not alpha) but no **kwargs to forward to matplotlib. The documentation (viewed with ? in ipython) suggests that there should be a kwds argument, but in reality this is not the case.



Discussion:
hmm can u show pandas version and how you are calling?

Here is a simple case:

```
from pandas import DataFrame

df = DataFrame({'a': [1, 1, 2, 2, 3, 3], 'b': [0, 1, 2, 3, 4, 5]})

series = df.groupby('a').b

series.hist(legend=True)
```

The last line fails with

```
TypeError: hist() got an unexpected keyword argument 'legend'
```

as a work-around you can do:

`series.plot(kind='hist',legend=True)` (and it accepts arbitrary keywords).

Sadly, as I mentioned in my original post, plot does not take arbitrary keywords. The following fails:

```
series.plot(kind='hist', alpha=0.5)
TypeError: plot() got an unexpected keyword argument 'alpha'
```

you must have an older version. Works in 0.15

```
In [1]: df = DataFrame({'a': [1, 1, 2, 2, 3, 3], 'b': [0, 1, 2, 3, 4, 5]})

In [2]: series = df.groupby('a').b

In [3]: series.hist(legend=True)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-813022ddf964> in <module>()
----> 1 series.hist(legend=True)

TypeError: hist() got an unexpected keyword argument 'legend'

In [4]: series.plot(kind='hist',legend=True)
Out[4]: 
a
1    Axes(0.125,0.1;0.775x0.8)
2    Axes(0.125,0.1;0.775x0.8)
3    Axes(0.125,0.1;0.775x0.8)
Name: b, dtype: object

In [5]: pd.__version__
Out[5]: '0.15.0'
```

I recently pip installed pandas 0.15:

```
import pandas.version
print pandas.version.version
0.15.0
```

you changed the example. `legend`is a defined kw. Ok. pls submit a pull-request if you can.

@TomAugspurger 

Can you tell me what you thought works in 0.15?

exactly what I wrote before

`series.plot(kind='hist',legend=False)`

Right. As I said, plot takes more kwargs than hist, but no **kwargs to pass to matplotlib. So for example I cannot do the example shown here (http://pandas.pydata.org/pandas-docs/version/0.15.0/visualization.html#visualization-hist) as it uses alpha.

that is a completely different example. This is a curried method on a Series/DataFrame GroupyBy object. Its different. You CAN do that example. try it (otherwise the docs would show an error).

I am not entirely sure why you can't pass the args, it _looks_ like it should work.

Is there a way to turn my GroupBy object back into a Series/DataFrame so I can use the full plot functionality?

if you are grouping the point is then to transform or aggregate.

you can just do:

`df.plot(....)`

what are you trying to do by grouping in the first place?

I tried transform and aggregate but those failed with errors, which I could not manage to fix. I suppose my intended output is something like:

```
df = DataFrame({'a': [1, 1, 2, 2, 3, 3], 'b': [0, 1, 2, 3, 4, 5]})
aggregated = DataFrame({'a': [1, 2, 3], 'b': [[0, 1], [2, 3], [4, 5]]})
```

Normally you do an aggregation of some sort 

```
In [8]: df.groupby('a').sum()
Out[8]: 
   b
a   
1  1
2  5
3  9
```

You _can_ do this, but its is very inefficient and won't scale. A list is not a natural representation.
So you need to figure out what you want to do.

```
In [7]: df.groupby('a').apply(lambda x: x['b'].tolist())
Out[7]: 
a
1    [0, 1]
2    [2, 3]
3    [4, 5]
dtype: object


```

Well, in order to plot a histogram, I need to maintain the whole set of data points.

Also, is there some way to do what you did above but to each column (not just 'b', but also 'c', 'd', etc)? Or do I have to do those separately?

try using value_counts()

Ok, that's close, but now when I do plot(kind='hist', ...) I no longer get separate series. My legend only has one entry named "None" instead of three labeled 1, 2, 3.

@vladfi1 I think it is really helpful to re-read the docs / post to stack overflow with a specific example of help needed

I'm a bit swamped right now, but I'll look into why the groupby.plot method doesn't accept arbitrary kwargs when I can.


Resolving patch:
diff --git a/pandas/util/decorators.py b/pandas/util/decorators.py
--- a/pandas/util/decorators.py
+++ b/pandas/util/decorators.py
@@ -282,5 +282,9 @@ def make_signature(func) :
     args = []
     for i, (var, default) in enumerate(zip(spec.args, defaults)) :
         args.append(var if default=='' else var+'='+repr(default))
+    if spec.varargs:
+        args.append('*' + spec.varargs)
+    if spec.keywords:
+        args.append('**' + spec.keywords)
     return args, spec.args
 


Test patch:
diff --git a/pandas/tests/test_groupby.py b/pandas/tests/test_groupby.py
--- a/pandas/tests/test_groupby.py
+++ b/pandas/tests/test_groupby.py
@@ -4415,6 +4415,26 @@ def test_regression_whitelist_methods(self) :
                 expected = getattr(frame,op)(level=level,axis=axis)
                 assert_frame_equal(result, expected)
 
+    def test_regression_kwargs_whitelist_methods(self):
+        # GH8733
+
+        index = MultiIndex(levels=[['foo', 'bar', 'baz', 'qux'],
+                                   ['one', 'two', 'three']],
+                           labels=[[0, 0, 0, 1, 1, 2, 2, 3, 3, 3],
+                                   [0, 1, 2, 0, 1, 1, 2, 0, 1, 2]],
+                           names=['first', 'second'])
+        raw_frame = DataFrame(np.random.randn(10, 3), index=index,
+                               columns=Index(['A', 'B', 'C'], name='exp'))
+
+        grouped = raw_frame.groupby(level=0, axis=1)
+        grouped.all(test_kwargs='Test kwargs')
+        grouped.any(test_kwargs='Test kwargs')
+        grouped.cumcount(test_kwargs='Test kwargs')
+        grouped.mad(test_kwargs='Test kwargs')
+        grouped.cummin(test_kwargs='Test kwargs')
+        grouped.skew(test_kwargs='Test kwargs')
+        grouped.cumprod(test_kwargs='Test kwargs')
+
     def test_groupby_blacklist(self):
         from string import ascii_lowercase
         letters = np.array(list(ascii_lowercase))
@@ -4460,6 +4480,9 @@ def test_series_groupby_plotting_nominally_works(self):
         tm.close()
         height.groupby(gender).hist()
         tm.close()
+        #Regression test for GH8733
+        height.groupby(gender).plot(alpha=0.5)
+        tm.close()
 
     def test_plotting_with_float_index_works(self):
         _skip_if_mpl_not_installed()