Repository: napjon/krisk

Issue:
Add smooth line for histogram and all type of line chart as well
Echarts Density Line for Histogram: http://echarts.baidu.com/demo.html#mix-line-bar

* Add an option to disable bar, line, or using both for histogram.
* For all type of line chart, added smooth boolean as additional argument, add to every line series.

Discussion:
codecov-io: ## [Current coverage](https://codecov.io/gh/napjon/krisk/pull/41?src=pr) is 93.49% (diff: 88.23%)
> Merging [#41](https://codecov.io/gh/napjon/krisk/pull/41?src=pr) into [0.2-develop](https://codecov.io/gh/napjon/krisk/branch/0.2-develop?src=pr) will decrease coverage by **0.33%**

```diff
@@           0.2-develop        #41   diff @@
=============================================
  Files               10         10          
  Lines              308        323    +15   
  Methods              0          0          
  Messages             0          0          
  Branches            42         48     +6   
=============================================
+ Hits               289        302    +13   
- Misses               9         10     +1   
- Partials            10         11     +1   
```

> Powered by [Codecov](https://codecov.io?src=pr). Last update [6944f11...c0196f5](https://codecov.io/gh/napjon/krisk/compare/6944f1150e675a1e4ef824bc3ed6c0c41526e54a...c0196f5585fb08641348110a5537a8df2930575a?src=pr)

Patch:
diff --git a/krisk/plot/__init__.py b/krisk/plot/__init__.py
index e702c4a..842f2bd 100644
--- a/krisk/plot/__init__.py
+++ b/krisk/plot/__init__.py
@@ -55,7 +55,8 @@ def line(df,
          stacked=False,
          area=False,
          annotate=None,
-         full=False):
+         full=False,
+         smooth=False):
     """
     Parameters
     ----------
@@ -77,12 +78,15 @@ def line(df,
         category. if 'all' and stacked, annotate all category
     full: boolean, default to False.
         If true, set to full area stacked chart. Only work if stacked is True.
+    smooth: boolean, default to False.
+        If true, smooth the line.
     
     Returns
     -------
     Chart Object
     """
     return make_chart(df,type='line',x=x,y=y,c=c,how=how,stacked=stacked,area=area,full=full,
+                      smooth=smooth,
                       annotate='top' if annotate == True else annotate)
 
 
@@ -92,7 +96,8 @@ def hist(df,
          bins=10,
          normed=False,
          stacked=False,
-         annotate=None):
+         annotate=None,
+         density=False):
     """
     Parameters
     ----------
@@ -110,13 +115,16 @@ def hist(df,
         Whether to stacked category on top of the other categories.
     annotate: string, {'all',True} default to None
         if True, annotate value on top of the plot element. If stacked is also True, annotate the last
-        category. if 'all' and stacked, annotate all category 
+        category. if 'all' and stacked, annotate all category
+    density: boolean, default to False.
+        Whether to add density to the plot
     
     Returns
     -------
     Chart Object
     """
     return make_chart(df,type='hist',x=x,c=c,bins=bins,normed=normed,stacked=stacked,
+                      density=density,
                       annotate='top' if annotate == True else annotate)
    
 
@@ -134,6 +142,7 @@ def scatter(df, x, y, s=None, c=None, size_px=(10, 70)):
         column used as grouping color category
     size_px: tuple, default to (10,70)
         boundary size, lower and upper limit in pixel for min-max scatter points
+
         
     Returns
     -------
diff --git a/krisk/plot/bar_line.py b/krisk/plot/bar_line.py
index 1101415..4c35402 100644
--- a/krisk/plot/bar_line.py
+++ b/krisk/plot/bar_line.py
@@ -2,7 +2,7 @@ from copy import deepcopy
 import numpy as np
 import pandas as pd
 
-from krisk.plot.make_chart import insert_series_data
+from krisk.plot.make_chart import insert_series_data, round_list
 
 
 def set_bar_line_chart(chart, df, x, c, **kwargs):
@@ -50,9 +50,12 @@ def set_bar_line_chart(chart, df, x, c, **kwargs):
 
     if kwargs['annotate'] == 'top':
         series[-1]['label'] = d_annotate
+     # TODO: make annotate receive all kinds supported in echarts.
 
+    # Special Bar Condition: Trendline
     if kwargs['type'] == 'bar' and kwargs['trendline']:
-        trendline = {'name':'trendline', 'type': 'line'}
+        trendline = {'name':'trendline', 'type': 'line',
+                     'lineStyle': {'normal': {'color': '#000'}}}
 
         if c and kwargs['stacked']:
             trendline['data']  =  [0] * len(series[-1]['data'])
@@ -64,9 +67,39 @@ def set_bar_line_chart(chart, df, x, c, **kwargs):
 
         series.append(trendline)
 
+    # Special Line Condition: Smooth
+    if kwargs['type'] == 'line' and kwargs['smooth']:
+        for s in series:
+            s['smooth'] = True
+
+
+    # Special Histogram Condition: Density
+    #TODO NEED IMPROVEMENT!
+    if kwargs['type'] == 'hist' and kwargs['density']:
+        
+        density = {'name':'density', 'type': 'line', 'smooth': True,
+                   'lineStyle': {'normal': {'color': '#000'}}}
+        chart.option['xAxis']['boundaryGap'] = False
+
+        # The density have to be closed at zero. So all of xAxis and series must be updated
+        # To incorporate the changes
+        chart.option['xAxis']['data'] = [0] + chart.option['xAxis']['data'] + [0]
+
+        for s in series:
+            s['data'] = [0] + s['data']
+
+        if c and kwargs['stacked']:
+            density['data'] = [0] + round_list(data.sum(axis=1)) + [0]
+        elif c is None:
+            density['data'] =  [0] + round_list(data) + [0] 
+        else:
+            raise AssertionError('Density must either stacked category, or not category')
+
+        series.append(density)
+
 
     
-    # TODO: make annotate receive all kinds supported in echarts.
+   
 
 
 def get_bar_line_data(df, x, c, y, **kwargs):
@@ -89,6 +122,7 @@ def get_bar_line_data(df, x, c, y, **kwargs):
 
     if c and kwargs['stacked'] and kwargs['full']:
         data = data.div(data.sum(1),axis=0)
+
             
     return data
 


Test patch:
diff --git a/krisk/tests/data/bar_year_pop_mean_continent_trendline.json b/krisk/tests/data/bar_year_pop_mean_continent_trendline.json
index 89aa040..98ef7d2 100644
--- a/krisk/tests/data/bar_year_pop_mean_continent_trendline.json
+++ b/krisk/tests/data/bar_year_pop_mean_continent_trendline.json
@@ -1,4 +1,20 @@
 {
+    "xAxis": {
+        "data": [
+            1952,
+            1957,
+            1962,
+            1967,
+            1972,
+            1977,
+            1982,
+            1987,
+            1992,
+            1997,
+            2002,
+            2007
+        ]
+    },
     "legend": {
         "data": [
             "Africa",
@@ -14,6 +30,7 @@
     "yAxis": {},
     "series": [
         {
+            "name": "Africa",
             "stack": "continent",
             "type": "bar",
             "data": [
@@ -29,10 +46,10 @@
                 29072015,
                 31287142,
                 33333216
-            ],
-            "name": "Africa"
+            ]
         },
         {
+            "name": "Americas",
             "stack": "continent",
             "type": "bar",
             "data": [
@@ -48,10 +65,10 @@
                 36203463,
                 38331121,
                 40301927
-            ],
-            "name": "Americas"
+            ]
         },
         {
+            "name": "Asia",
             "stack": "continent",
             "type": "bar",
             "data": [
@@ -67,10 +84,10 @@
                 22227415,
                 25268405,
                 31889923
-            ],
-            "name": "Asia"
+            ]
         },
         {
+            "name": "Europe",
             "stack": "continent",
             "type": "bar",
             "data": [
@@ -86,10 +103,10 @@
                 3428038,
                 3508512,
                 3600523
-            ],
-            "name": "Europe"
+            ]
         },
         {
+            "name": "Oceania",
             "stack": "continent",
             "type": "bar",
             "data": [
@@ -105,11 +122,14 @@
                 18565243,
                 19546792,
                 20434176
-            ],
-            "name": "Oceania"
+            ]
         },
         {
-            "stack": "continent",
+            "lineStyle": {
+                "normal": {
+                    "color": "#000"
+                }
+            },
             "data": [
                 0,
                 0,
@@ -124,6 +144,7 @@
                 0,
                 0
             ],
+            "stack": "continent",
             "type": "line",
             "name": "trendline"
         }
@@ -132,21 +153,5 @@
         "axisPointer": {
             "type": ""
         }
-    },
-    "xAxis": {
-        "data": [
-            1952,
-            1957,
-            1962,
-            1967,
-            1972,
-            1977,
-            1982,
-            1987,
-            1992,
-            1997,
-            2002,
-            2007
-        ]
     }
 }
\ No newline at end of file
diff --git a/krisk/tests/data/bar_year_pop_mean_trendline.json b/krisk/tests/data/bar_year_pop_mean_trendline.json
index 15ef467..f806836 100644
--- a/krisk/tests/data/bar_year_pop_mean_trendline.json
+++ b/krisk/tests/data/bar_year_pop_mean_trendline.json
@@ -1,4 +1,20 @@
 {
+    "xAxis": {
+        "data": [
+            1952,
+            1957,
+            1962,
+            1967,
+            1972,
+            1977,
+            1982,
+            1987,
+            1992,
+            1997,
+            2002,
+            2007
+        ]
+    },
     "legend": {
         "data": []
     },
@@ -8,6 +24,7 @@
     "yAxis": {},
     "series": [
         {
+            "name": "year",
             "type": "bar",
             "data": [
                 9111144.6,
@@ -22,10 +39,14 @@
                 21899234.8,
                 23588394.4,
                 25911953.0
-            ],
-            "name": "year"
+            ]
         },
         {
+            "lineStyle": {
+                "normal": {
+                    "color": "#000"
+                }
+            },
             "data": [
                 9111144.6,
                 10062280.4,
@@ -48,21 +69,5 @@
         "axisPointer": {
             "type": ""
         }
-    },
-    "xAxis": {
-        "data": [
-            1952,
-            1957,
-            1962,
-            1967,
-            1972,
-            1977,
-            1982,
-            1987,
-            1992,
-            1997,
-            2002,
-            2007
-        ]
     }
 }
\ No newline at end of file
diff --git a/krisk/tests/data/hist_lifeExp_b10_continent_density.json b/krisk/tests/data/hist_lifeExp_b10_continent_density.json
new file mode 100644
index 0000000..247f887
--- /dev/null
+++ b/krisk/tests/data/hist_lifeExp_b10_continent_density.json
@@ -0,0 +1,154 @@
+{
+    "xAxis": {
+        "boundaryGap": false,
+        "data": [
+            0,
+            28,
+            34,
+            39,
+            44,
+            49,
+            55,
+            60,
+            65,
+            70,
+            75,
+            81,
+            0
+        ]
+    },
+    "legend": {
+        "data": [
+            "Africa",
+            "Americas",
+            "Asia",
+            "Europe",
+            "Oceania"
+        ]
+    },
+    "title": {
+        "text": ""
+    },
+    "yAxis": {},
+    "series": [
+        {
+            "name": "Africa",
+            "stack": "continent",
+            "type": "bar",
+            "data": [
+                0,
+                0,
+                0,
+                1,
+                2,
+                2,
+                1,
+                1,
+                3,
+                2,
+                0
+            ]
+        },
+        {
+            "name": "Americas",
+            "stack": "continent",
+            "type": "bar",
+            "data": [
+                0,
+                0,
+                0,
+                0,
+                0,
+                0,
+                0,
+                3,
+                4,
+                5,
+                0
+            ]
+        },
+        {
+            "name": "Asia",
+            "stack": "continent",
+            "type": "bar",
+            "data": [
+                0,
+                3,
+                2,
+                6,
+                0,
+                0,
+                0,
+                0,
+                0,
+                0,
+                0
+            ]
+        },
+        {
+            "name": "Europe",
+            "stack": "continent",
+            "type": "bar",
+            "data": [
+                0,
+                0,
+                0,
+                0,
+                0,
+                0,
+                2,
+                1,
+                4,
+                4,
+                1
+            ]
+        },
+        {
+            "name": "Oceania",
+            "stack": "continent",
+            "type": "bar",
+            "data": [
+                0,
+                0,
+                0,
+                0,
+                0,
+                0,
+                0,
+                0,
+                2,
+                5,
+                5
+            ]
+        },
+        {
+            "lineStyle": {
+                "normal": {
+                    "color": "#000"
+                }
+            },
+            "data": [
+                0,
+                3,
+                2,
+                7,
+                2,
+                2,
+                3,
+                5,
+                13,
+                16,
+                6,
+                0
+            ],
+            "smooth": true,
+            "type": "line",
+            "name": "density"
+        }
+    ],
+    "tooltip": {
+        "axisPointer": {
+            "type": ""
+        }
+    }
+}
\ No newline at end of file
diff --git a/krisk/tests/test_plot.py b/krisk/tests/test_plot.py
index bdce2e5..08cf413 100644
--- a/krisk/tests/test_plot.py
+++ b/krisk/tests/test_plot.py
@@ -45,7 +45,18 @@ def test_bar(gapminder):
                              'xAxis': {'data': ['Africa', 'Americas', 'Asia', 'Europe', 'Oceania']},
                              'yAxis': {}}
 
+def test_trendline(gapminder):
 
+    p = kk.bar(gapminder,'year',how='mean',y='pop',trendline=True)
+    assert p.get_option() == read_option_tests('bar_year_pop_mean_trendline.json')
+
+    p = kk.bar(gapminder,'year',how='mean',y='pop',trendline=True,c='continent',stacked=True)
+    assert p.get_option() == read_option_tests('bar_year_pop_mean_continent_trendline.json')
+
+    try:
+        kk.bar(gapminder,'year',how='mean',y='pop',trendline=True,c='continent')
+    except AssertionError:
+        pass
 
 def test_line(gapminder):
 
@@ -62,6 +73,11 @@ def test_line(gapminder):
 
     assert p.get_option() == true_option
 
+def test_smooth_line(gapminder):
+
+    p = kk.line(gapminder[gapminder.year == 1952],'continent',y='pop',how='mean',smooth=True)
+    assert p.get_option()['series'][0]['smooth'] == True
+
 def test_full_bar_line(gapminder):
     bar = kk.bar(gapminder,'year',c='continent',y='pop',how='mean',stacked=True,full=True,annotate='all')
     line = kk.line(gapminder,'year',c='continent',y='pop',how='mean',stacked=True,full=True,annotate='all')
@@ -78,19 +94,6 @@ def test_full_bar_line(gapminder):
     assert bar.option == line.option == true_option
 
 
-def test_trendline(gapminder):
-
-    p = kk.bar(gapminder,'year',how='mean',y='pop',trendline=True)
-    assert p.get_option() == read_option_tests('bar_year_pop_mean_trendline.json')
-
-    p = kk.bar(gapminder,'year',how='mean',y='pop',trendline=True,c='continent',stacked=True)
-    assert p.get_option() == read_option_tests('bar_year_pop_mean_continent_trendline.json')
-
-    try:
-        kk.bar(gapminder,'year',how='mean',y='pop',trendline=True,c='continent')
-    except AssertionError:
-        pass
-
 def test_hist(gapminder):
 
     true_option  = read_option_tests('hist_x.json')
@@ -98,7 +101,7 @@ def test_hist(gapminder):
     assert p.get_option() == true_option
 
 
-    true_option = json.load(open(DATA_DIR + '/hist.json', 'r'))
+    true_option = read_option_tests('hist.json')
     p = kk.hist(
         gapminder,
         'lifeExp',
@@ -110,6 +113,30 @@ def test_hist(gapminder):
     assert p.get_option() == true_option
 
 
+def test_density(gapminder):
+
+    option = kk.hist(gapminder,'lifeExp',density=True).get_option()
+
+    assert option['series'][0]['data'] == [0, 4, 2, 7, 2, 2, 3, 5, 13, 16, 6]
+    assert option['series'][-1] == {'data': [0, 4, 2, 7, 2, 2, 3, 5, 13, 16, 6, 0],
+                                   'lineStyle': {'normal': {'color': '#000'}},
+                                   'name': 'density',
+                                   'smooth': True,
+                                   'type': 'line'}
+    assert option['xAxis'] == {'boundaryGap': False,
+                               'data': [0, 28, 34, 39, 44, 49, 55, 60, 65, 70, 75, 81, 0]}
+
+    true_option = read_option_tests('hist_lifeExp_b10_continent_density.json')
+    option2 = kk.hist(gapminder,'lifeExp',bins=10,c='continent',stacked=True,density=True).get_option()
+    assert true_option == option2
+
+    try:
+        kk.hist(gapminder,'year',density=True,c='continent')
+    except AssertionError:
+        pass
+
+
+
 def test_scatter(gapminder):
     # Simple Scatter
     p = kk.scatter(gapminder[gapminder.year == 1952],'pop','lifeExp')
@@ -117,7 +144,7 @@ def test_scatter(gapminder):
     assert p.get_option() == true_option
 
     # Grouped Scatter
-    true_option = json.load(open(DATA_DIR + '/scatter.json', 'r'))
+    true_option = read_option_tests('scatter.json')
     p = kk.scatter(
         gapminder[gapminder.year == 1952],
         'lifeExp',