Adds custom plot formatting for TimedeltaIndex.
State: closed

Instead of hacking the PeriodIndex plotting code to work for TimedeltaIndex, this just creates a simple formatter unique to TimedeltaIndex. It does fine for regular intervals up to a day, then the labels and run into eachothter. If this happens, you can use plt.autofmt_xdate() to fix it.

 - [x] closes #8711
 - [ ] tests  passed, none added
 - [x] passes ``git diff upstream/master | flake8 --diff``


```python
d.t_sensor_gyro_0__f_x.plot()
plt.grid()
```
![image](https://cloud.githubusercontent.com/assets/473772/21677741/76393d44-d309-11e6-90aa-b94fd4e2e989.png)


```python
index =  pd.timedelta_range('1 day 2 hr 30 min 10 s', periods=10, freq='1 d')
s = pd.Series(np.random.randn(len(index)), index)
s.plot()
plt.gcf().autofmt_xdate()
plt.grid()
```

![image](https://cloud.githubusercontent.com/assets/473772/21677435/24779c86-d308-11e6-9350-2251a8eca334.png)


```python
index =  pd.timedelta_range('1 day 2 hr 30 min 10 s', periods=10, freq='1 ns')
s = pd.Series(np.random.randn(len(index)), index)
s.plot()
plt.gcf().autofmt_xdate()
plt.grid()
```

![image](https://cloud.githubusercontent.com/assets/473772/21677429/1bd28794-d308-11e6-9ed6-72fa831a60f9.png)

```python
index =  pd.timedelta_range('0s', periods=10, freq='100000 ns')
s = pd.Series(np.random.randn(len(index)), index)
s.plot()
plt.gcf().autofmt_xdate()
plt.grid()
plt.xlabel('time')
plt.ylabel('y')
```

![image](https://cloud.githubusercontent.com/assets/473772/21677938/7ef8392a-d30a-11e6-8c5c-f77cc0f49a7c.png)



Labels:
name: Visualization
description: plotting
name: Timedelta
description: Timedelta data type

Comments:
I think this is ready to merge, it is functional for me now.
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/15067?src=pr&el=h1) Report
> Merging [#15067](https://codecov.io/gh/pandas-dev/pandas/pull/15067?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/f62e8f242d90d849e4854f4fe82e9ebb5b731d74?src=pr&el=desc) will **decrease** coverage by `-4.85%`.
> The diff coverage is `73.46%`.


```diff
@@            Coverage Diff             @@
##           master   #15067      +/-   ##
==========================================
- Coverage   90.37%   85.52%   -4.85%     
==========================================
  Files         135      145      +10     
  Lines       49476    51325    +1849     
==========================================
- Hits        44713    43896     -817     
- Misses       4763     7429    +2666
```


| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/15067?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/tseries/converter.py](https://codecov.io/gh/pandas-dev/pandas/compare/f62e8f242d90d849e4854f4fe82e9ebb5b731d74...7db61ec1947309bccb2feaa84b8e56a478baba71?src=pr&el=tree#diff-cGFuZGFzL3RzZXJpZXMvY29udmVydGVyLnB5) | `62.95% <100%> (+1.1%)` | :white_check_mark: |
| [pandas/tools/plotting.py](https://codecov.io/gh/pandas-dev/pandas/compare/f62e8f242d90d849e4854f4fe82e9ebb5b731d74...7db61ec1947309bccb2feaa84b8e56a478baba71?src=pr&el=tree#diff-cGFuZGFzL3Rvb2xzL3Bsb3R0aW5nLnB5) | `68.48% <100%> (-3.31%)` | :x: |
| [pandas/tseries/plotting.py](https://codecov.io/gh/pandas-dev/pandas/compare/f62e8f242d90d849e4854f4fe82e9ebb5b731d74...7db61ec1947309bccb2feaa84b8e56a478baba71?src=pr&el=tree#diff-cGFuZGFzL3RzZXJpZXMvcGxvdHRpbmcucHk=) | `61.78% <55.17%> (-2.96%)` | :x: |
| [pandas/io/sas/sas_constants.py](https://codecov.io/gh/pandas-dev/pandas/compare/f62e8f242d90d849e4854f4fe82e9ebb5b731d74...7db61ec1947309bccb2feaa84b8e56a478baba71?src=pr&el=tree#diff-cGFuZGFzL2lvL3Nhcy9zYXNfY29uc3RhbnRzLnB5) | `0% <ø> (-100%)` | :x: |
| [pandas/io/sas/sas7bdat.py](https://codecov.io/gh/pandas-dev/pandas/compare/f62e8f242d90d849e4854f4fe82e9ebb5b731d74...7db61ec1947309bccb2feaa84b8e56a478baba71?src=pr&el=tree#diff-cGFuZGFzL2lvL3Nhcy9zYXM3YmRhdC5weQ==) | `0% <ø> (-90.67%)` | :x: |
| [pandas/io/sas/sas_xport.py](https://codecov.io/gh/pandas-dev/pandas/compare/f62e8f242d90d849e4854f4fe82e9ebb5b731d74...7db61ec1947309bccb2feaa84b8e56a478baba71?src=pr&el=tree#diff-cGFuZGFzL2lvL3Nhcy9zYXNfeHBvcnQucHk=) | `0% <ø> (-90.28%)` | :x: |
| [pandas/io/sas/sasreader.py](https://codecov.io/gh/pandas-dev/pandas/compare/f62e8f242d90d849e4854f4fe82e9ebb5b731d74...7db61ec1947309bccb2feaa84b8e56a478baba71?src=pr&el=tree#diff-cGFuZGFzL2lvL3Nhcy9zYXNyZWFkZXIucHk=) | `7.4% <ø> (-77.78%)` | :x: |
| [pandas/computation/__init__.py](https://codecov.io/gh/pandas-dev/pandas/compare/f62e8f242d90d849e4854f4fe82e9ebb5b731d74...7db61ec1947309bccb2feaa84b8e56a478baba71?src=pr&el=tree#diff-cGFuZGFzL2NvbXB1dGF0aW9uL19faW5pdF9fLnB5) | `76.92% <ø> (-13.99%)` | :x: |
| [pandas/util/decorators.py](https://codecov.io/gh/pandas-dev/pandas/compare/f62e8f242d90d849e4854f4fe82e9ebb5b731d74...7db61ec1947309bccb2feaa84b8e56a478baba71?src=pr&el=tree#diff-cGFuZGFzL3V0aWwvZGVjb3JhdG9ycy5weQ==) | `60.78% <ø> (-7.83%)` | :x: |
| ... and [93 more](https://codecov.io/gh/pandas-dev/pandas/pull/15067?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/15067?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/15067?src=pr&el=footer). Last update [f62e8f2...945ec14](https://codecov.io/gh/pandas-dev/pandas/compare/f62e8f242d90d849e4854f4fe82e9ebb5b731d74...945ec14315ea96b5c2fffa2066e1e47b06173c5c?el=footer&src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
@TomAugspurger @jreback do you guys think you can help me clean this up. I'm not familiar with your docs and unit tests and have to get back to what I wrote this for today.

I gave you push access to my branch since I can't push the branch to upstream.
I just pushed the full implementation of the unit test. Can we merge this now? It is definitely an improvement over master's mem allocation error and we can revisit the small details later.
@jgoppert things are merged when they pass all tests, have documentation, and unit tests to the satisfaction of the maintainers. This has not been reviewed as yet.

of course if *you* or really anyone wants to pull in your commits on top of master, they can certainly do this.
I understand,  I'm just running out of development bandwidth and don't want it to stall. Let me know what the delta is and I'll try to do what I can.
@jreback Any idea why clang 3.5 failed to set the xticks label?
cc @tacaswell 
So weird that osx with python 3.5 keeps failing and all of the others work. I'm running out of ideas.
@jorisvandenbossche I think I addressed your review. Hopefully mac passes CI now.
@jreback Any idea how to proceed with this. Can we put a skip in for mac and file an issue?
Roughly I mean something like:

```
# this is part of what you have now in a test
rng = timedelta_range('0', periods=10, freq='ns')
df = DataFrame(np.random.randn(len(rng), 3), rng)
ax = df.plot(fontsize=2)

# this could also test the formatting in another way that should not be skipped on mac osx
formatter =  ax.xaxis.get_major_formatter()
assert isinstance(formatter, TimeSeries_TimedeltaFormatter)
self.assertEqual(formatter(1.), '00:00:00.000000001')
```
I replicated the exact travis env for 3.5 / OSX and these test passed for me. so ok to skip i guess (though I wonder if these have something to do with some output settings, e.g. LOCALE).
This is not unreasonable.  It might be worth adding a `format_data_short` method to the formatter to customize how the mouse-over gets displayed (instead of `format_coords`)
thanks @jgoppert I merged this (and skip those 2 comparisons on mac).

They seem kind of odd, though I couldn't reproduce them with a very similar local environment.

If you want to keep looking at them great (otherwise ok too).

Similarly if you want to do a mouse-over formatter as @tacaswell suggest would be great as well.
![image](https://cloud.githubusercontent.com/assets/953992/23220400/e9cfcb2c-f8ef-11e6-8023-2c4dd987adb1.png)

hmm the tick locations look a bit odd, is this normal? (this is the just merged PR)

cc @tacaswell 
@jgoppert 
Thanks for getting this in:

![image](https://cloud.githubusercontent.com/assets/473772/23225970/eb01b840-f901-11e6-99fc-b06002b1645f.png)

When you do rot=45, it works pretty well, but it does't align to tics, the autofmt_xdate does. Also, internally the tics are just set by the nanoseconds, so it isn't intelligent about frequency. If you look at the plot you will notice that the tic locations are at meaningful locations for nanoseconds. Staring at 1 day with a period of 5 starts at an odd place in terms of nanoseconds. If you look at when I just do seconds, it works well because seconds are just related to nano-seconds via a power of 10.
thanks for the expl @jgoppert 
Is it intentional that this doesn't work for histograms?
![image](https://user-images.githubusercontent.com/1078042/32811852-2265dae8-c9a2-11e7-9864-8fab4d8599d6.png)

it works only for fixed time step between points on the plot

consider following code:
idx2[0] was changed from 00:00 to 00:01 and xlabels on the plot are missing

```
import pandas as pd
import matplotlib.pyplot as plt

idx1 = pd.to_timedelta(['00:00:00', '00:00:30', '00:01:00', '00:01:30', '00:02:00'])
idx2 = pd.to_timedelta(['00:00:01', '00:00:30', '00:01:00', '00:01:30', '00:02:00'])
vals = range(5)
s1= pd.Series(vals, idx1)
s2= pd.Series(vals, idx2)

# Labels on x are ok
plt.figure()
plt.gca().set_title('fixed frequency f=30s')
s1.plot()
plt.gcf().autofmt_xdate()
plt.show()

# Labels on x are messed up
plt.figure()
plt.gca().set_title('variable frequency')
s2.plot()
plt.gcf().autofmt_xdate()
plt.show()
```


![image](https://user-images.githubusercontent.com/25963560/45159048-09cfae00-b1e6-11e8-9bc2-3ff8372e2344.png)