Repository: holoviz/hvplot

Issue:
hvPlot doesnot sort date automatically like pandas.plot()
Simple setup 
```
import numpy as np
import pandas as pd
index = pd.date_range('1/1/2000', periods=1000)
index = [d.strftime("%a, %d %b %Y %H:%M:%S +0000") for d in index]
df = pd.DataFrame(np.random.randn(1000, 4), columns=list('ABCD')).cumsum()
shuffle(index)
df['date'] = index
df['date'] = df["date"].apply(pd.to_datetime)
df.head()
```

With pandas plot()
```
%matplotlib inline
df.plot(x='date')
```
![image](https://user-images.githubusercontent.com/25283272/49363356-c0f29d00-f6e1-11e8-9b60-d5e62450b253.png)

```
import hvplot.pandas
df.hvplot(x='date')
```
![image](https://user-images.githubusercontent.com/25283272/49363368-c819ab00-f6e1-11e8-8ef3-7ed4041d42c8.png)

The graph is sorted if no type is applied to **date** column (just comment the line to the the result). 



Discussion:

Resolving patch:
diff --git a/hvplot/converter.py b/hvplot/converter.py
--- a/hvplot/converter.py
+++ b/hvplot/converter.py
@@ -141,6 +141,8 @@ class HoloViewsConverter(object):
         The width and height of the plot in pixels
     attr_labels (default=True): bool
         Whether to use an xarray object's attributes as labels
+    sort_date (default=True): bool
+        Whether to sort the x-axis by date before plotting
 
     Datashader options
     ------------------
@@ -270,7 +272,8 @@ def __init__(self, data, x, y, kind=None, by=None, use_index=True,
                  clabel=None, xformatter=None, yformatter=None, tools=[],
                  padding=None, responsive=False, min_width=None,
                  min_height=None, max_height=None, max_width=None,
-                 attr_labels=True, coastline=False, tiles=False, **kwds):
+                 attr_labels=True, coastline=False, tiles=False,
+                 sort_date=True, **kwds):
 
         # Process data and related options
         self._redim = fields
@@ -288,6 +291,7 @@ def __init__(self, data, x, y, kind=None, by=None, use_index=True,
         self.tiles = tiles
         self.row = row
         self.col = col
+        self.sort_date = sort_date
 
         # Import geoviews if geo-features requested
         if self.geo or self.datatype == 'geopandas':
@@ -1006,6 +1010,14 @@ def _process_args(self, data, x, y):
         elif not x:
             raise ValueError('Could not determine what to plot. Expected '
                              'x to be declared or use_index to be enabled.')
+        if self.sort_date and self.datatype == 'pandas':
+            from pandas.api.types import is_datetime64_any_dtype as is_datetime
+            if x in self.indexes:
+                index = self.indexes.index(x)
+                if is_datetime(data.axes[index]):
+                    data = data.sort_index(axis=self.indexes.index(x))
+            elif is_datetime(data[x]):
+                data = data.sort_values(x)
 
         y = y or self.y
         if not y:


Test patch:
diff --git a/hvplot/tests/testcharts.py b/hvplot/tests/testcharts.py
--- a/hvplot/tests/testcharts.py
+++ b/hvplot/tests/testcharts.py
@@ -52,6 +52,10 @@ def setUp(self):
                                    columns=['x', 'y', 'category'])
         self.cat_only_df = pd.DataFrame([['A', 'a'], ['B', 'b'], ['C', 'c']],
                                         columns=['upper', 'lower'])
+        self.time_df = pd.DataFrame({
+            'time': pd.date_range('1/1/2000', periods=10, tz='UTC'),
+            'A': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+            'B': 'abcdefghij'})
 
     @parameterized.expand([('line', Curve), ('area', Area), ('scatter', Scatter)])
     def test_wide_chart(self, kind, element):
@@ -153,6 +157,33 @@ def test_includes_str_if_no_num_chart(self, kind, element):
                         }, 'Variable')
         self.assertEqual(plot, obj)
 
+    def test_time_df_sorts_on_plot(self):
+        scrambled = self.time_df.sample(frac=1)
+        plot = scrambled.hvplot(x='time')
+        assert (plot.data == self.time_df).all().all()
+        assert (plot.data.time.diff()[1:].astype('int') > 0).all()
+
+    def test_time_df_does_not_sort_on_plot_if_sort_date_off(self):
+        scrambled = self.time_df.sample(frac=1)
+        plot = scrambled.hvplot(x='time', sort_date=False)
+        assert (plot.data == scrambled).all().all()
+        assert not (plot.data.time.diff()[1:].astype('int') > 0).all()
+
+    def test_time_df_sorts_on_plot_using_index_as_x(self):
+        df = self.time_df.set_index('time')
+        scrambled = df.sample(frac=1)
+        plot = scrambled.hvplot()
+        assert (plot.data['time'] == df.index).all()
+        assert (plot.data.time.diff()[1:].astype('int') > 0).all()
+
+    def test_time_df_does_not_sort_on_plot_if_sort_date_off_using_index_as_x(self):
+        df = self.time_df.set_index('time')
+        scrambled = df.sample(frac=1)
+        plot = scrambled.hvplot(sort_date=False)
+        assert (plot.data.time == scrambled.index).all().all()
+        assert not (plot.data.time.diff()[1:].astype('int') > 0).all()
+
+
 class TestChart1DDask(TestChart1D):
 
     def setUp(self):