(WIP)ENH: plot now supports cycler 
State: closed

- [x] closes #12354
- [ ] tests added / passed
- [x] passes `git diff upstream/master | flake8 --diff`
- [ ] whatsnew entry
  - [ ] plotting no try to use `cycler` regardless of mpl version (previously tried if mpl >= 1.5)
  - [ ] bug in area plot kwds handling
## Cyclic option handling

Allows to accept some option (currently only `hatch`) as a list, each element is applied to corresponding columns.

This can be more generalized, but I think it's better to refactor plotting submodule beforehand.
## Hatch example

```
df = pd.DataFrame({'A': np.random.randint(0, 10, 10), 
                   'B': np.random.randint(0, 10, 10)})
# we cannot see hatch if alpha=1.0
df.plot.area(hatch='*', alpha=0.5);
```

![index](https://cloud.githubusercontent.com/assets/1696302/13557491/be49bed4-e434-11e5-88d9-4746b78a4bf5.png)

```
from cycler import cycler
df.plot.area(hatch=cycler('hatch', ['*', '//']), alpha=0.5);
```

![indexx](https://cloud.githubusercontent.com/assets/1696302/13557494/c9c782c8-e434-11e5-9599-ce168f5385db.png)


Labels:
name: Enhancement
name: Visualization
description: plotting

Comments:
This is the sort of application that `Cycler` was written to address. See http://matplotlib.org/examples/api/filled_step.html

yes we can implicity depend on `cycler` (at least in newer version so mpl, IIRC >= 1.5``.

cycler is packaged separately (basically everywhere) so you can directly depend on it without requiring newer mpl.

hmm, ok, then we should probably do that (and add alongside the mpl dep in install).

@sinhrks can we change to use cycler? (and raise if not installed and a list provided)

@sinhrks status?

@jreback Sorry, will revisit to use cycler.

Updated to use `cycler`, and would like to decide following points.

### 1. Whether to add cycler kwds

Because one `cycler` instance can handle multiple keywords, passing single `cycler` is enough to handle all options cyclically. Thus, I think adding `cycler` kwd is simpler (it should overwrite other kwds if specified).

```
df.plot.area(cycler=cycler('hatch', ['*', '//']), alpha=0.5);

c = cycler('hatch', ['*', '//']) + cycler('ls', ['-', '--'])
df.plot.area(cycler=c, alpha=0.5);
```

Or, allow to accept `cycler` instances via every kwds (maybe we have to concatenate all `cycler` internally before plotting )

```
df.plot.area(hatch=cycler('hatch', ['*', '//']), alpha=0.5);
df.plot.area(hatch=cycler('hatch', ['*', '//']), ls=cycler('ls', ['-', '--']), alpha=0.5);

# there can be a mismatch between method and cycler kwds
df.plot.area(hatch=cycler('ls', ['-', '--']), alpha=0.5);
```

### 2. How to handle cycler which doesn't have required length

`cycler` itself doesn't repeat its content, I think raising error is natural. User must pass `cycler` which is longer than required length (number of columns, etc).

Another option is implicitly repeat.

CC: @TomAugspurger 

- We already have the `style` keyword. Could we use that to pass a cycler object instead of adding a new `cycler` keyword argument?
- 1) Having a dedicated keyword to pass cycler objects, as well as accepting those for the individual styling keywords (hatch, ls, ..) can in principle both be implemented? 
  But if we choose, I would personally start by accepting it for a specific keyword.
- 2) raising an error when the cycler is not long enough sounds good to me
- Giving users the availability of passing a cycler object, should that prevent them also being able to just pass a list? 
  Because from a user point, if you have two columns and you want different hatch for each, doing `df.plot.area(hatch=cycler('hatch', ['*', '//']))` instead of `df.plot.area(hatch=['*', '//'])` is quite a bit more complex.

I would suggest 1) and converting any lists that come in via kwargs to cyclers that are added together (and to the thing passed into the cycler kwarg) and any length 1 things are converted to length 1 cyclers that are multiplied.  

That would give you one cycler to worry about internally, not put too much burden on your user and give them access to the full power of cycler if they want it.

And if you 'call' a cycler 

``` python
for c in cyc():
   ...
```

vs 

``` python
for c in cycr:
    ...
```

It will implicitly repeat.

Thanks, how about following spec?
- `Cycler` can be used via following kwds:
  - `style`: can accept `Cycler` with whatever keys
    - if specified `Cycler` key conflicts with other keywords, raises error.
  - other mpl kwds: can accept `Cycler` with corresponding single key (e.g. `ls` kw can accept `Cycler(ls=...)`, but can't `Cycler(lw=...)`, etc)
    - if user passes `list`, it will be automatically converted to `Cycler` (as long as mpl/pandas plotting can't accept `list` via the kw). If `Cycler` is not installed, raise understandable error to show `Cycler` is required.
- `Cycler` (or passed `list`) implicitly loops (looks need `Cycler` >= 0.10)
- (Needs discussion) Show warning if `Cycler` is not installed. To replace color-cycle logic in future. 

Also if cycler has any sharp edges, we can probably fix it upstream.

@sinhrks status of this? (I think the spec you outlined above looks fine!)

Can you also add a whatsnew notice? And probably something in the install instructions. `cycler` is regarded as an optional dependency for plotting? (passing style kwargs does still work if you don't not have cycler installed?)

@sinhrks can you update

@sinhrks status?
closing, but if you can update @sinhrks pls reopen.