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)
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
 

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.
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',

pip install -e .
parse_log_pytest
requirements.txt
coverage pytest
apt-get update apt-get install -y gcc
3.5
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
anyio==3.6.2
argon2-cffi==21.3.0
argon2-cffi-bindings==21.2.0
async-generator==1.10
attrs==22.2.0
Babel==2.11.0
backcall==0.2.0
bleach==4.1.0
certifi==2021.5.30
cffi==1.15.1
charset-normalizer==2.0.12
comm==0.1.4
contextvars==2.4
coverage==6.2
dataclasses==0.8
decorator==5.1.1
defusedxml==0.7.1
entrypoints==0.4
idna==3.10
immutables==0.19
importlib-metadata==4.8.3
iniconfig==1.1.1
ipykernel==5.5.6
ipython==7.16.3
ipython-genutils==0.2.0
ipywidgets==7.8.5
jedi==0.17.2
Jinja2==3.0.3
json5==0.9.16
jsonschema==3.2.0
jupyter==1.1.1
jupyter-client==7.1.2
jupyter-console==6.4.3
jupyter-core==4.9.2
jupyter-server==1.13.1
jupyterlab==3.2.9
jupyterlab-pygments==0.1.2
jupyterlab-server==2.10.3
jupyterlab_widgets==1.1.11
-e git+https://github.com/napjon/krisk.git@6944f1150e675a1e4ef824bc3ed6c0c41526e54a#egg=krisk
MarkupSafe==2.0.1
mistune==0.8.4
nbclassic==0.3.5
nbclient==0.5.9
nbconvert==6.0.7
nbformat==5.1.3
nest-asyncio==1.6.0
notebook==6.4.10
numpy==1.19.5
packaging==21.3
pandas==1.1.5
pandocfilters==1.5.1
parso==0.7.1
pexpect==4.9.0
pickleshare==0.7.5
pluggy==1.0.0
prometheus-client==0.17.1
prompt-toolkit==3.0.36
ptyprocess==0.7.0
py==1.11.0
pycparser==2.21
Pygments==2.14.0
pyparsing==3.1.4
pyrsistent==0.18.0
pytest==7.0.1
python-dateutil==2.9.0.post0
pytz==2025.2
pyzmq==25.1.2
requests==2.27.1
Send2Trash==1.8.3
six==1.17.0
sniffio==1.2.0
terminado==0.12.1
testpath==0.6.0
tomli==1.2.3
tornado==6.1
traitlets==4.3.3
typing_extensions==4.1.1
urllib3==1.26.20
wcwidth==0.2.13
webencodings==0.5.1
websocket-client==1.3.1
widgetsnbextension==3.6.10
zipp==3.6.0

name: krisk
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - anyio==3.6.2
      - argon2-cffi==21.3.0
      - argon2-cffi-bindings==21.2.0
      - async-generator==1.10
      - attrs==22.2.0
      - babel==2.11.0
      - backcall==0.2.0
      - bleach==4.1.0
      - cffi==1.15.1
      - charset-normalizer==2.0.12
      - comm==0.1.4
      - contextvars==2.4
      - coverage==6.2
      - dataclasses==0.8
      - decorator==5.1.1
      - defusedxml==0.7.1
      - entrypoints==0.4
      - idna==3.10
      - immutables==0.19
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - ipykernel==5.5.6
      - ipython==7.16.3
      - ipython-genutils==0.2.0
      - ipywidgets==7.8.5
      - jedi==0.17.2
      - jinja2==3.0.3
      - json5==0.9.16
      - jsonschema==3.2.0
      - jupyter==1.1.1
      - jupyter-client==7.1.2
      - jupyter-console==6.4.3
      - jupyter-core==4.9.2
      - jupyter-server==1.13.1
      - jupyterlab==3.2.9
      - jupyterlab-pygments==0.1.2
      - jupyterlab-server==2.10.3
      - jupyterlab-widgets==1.1.11
      - markupsafe==2.0.1
      - mistune==0.8.4
      - nbclassic==0.3.5
      - nbclient==0.5.9
      - nbconvert==6.0.7
      - nbformat==5.1.3
      - nest-asyncio==1.6.0
      - notebook==6.4.10
      - numpy==1.19.5
      - packaging==21.3
      - pandas==1.1.5
      - pandocfilters==1.5.1
      - parso==0.7.1
      - pexpect==4.9.0
      - pickleshare==0.7.5
      - pluggy==1.0.0
      - prometheus-client==0.17.1
      - prompt-toolkit==3.0.36
      - ptyprocess==0.7.0
      - py==1.11.0
      - pycparser==2.21
      - pygments==2.14.0
      - pyparsing==3.1.4
      - pyrsistent==0.18.0
      - pytest==7.0.1
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - pyzmq==25.1.2
      - requests==2.27.1
      - send2trash==1.8.3
      - six==1.17.0
      - sniffio==1.2.0
      - terminado==0.12.1
      - testpath==0.6.0
      - tomli==1.2.3
      - tornado==6.1
      - traitlets==4.3.3
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - wcwidth==0.2.13
      - webencodings==0.5.1
      - websocket-client==1.3.1
      - widgetsnbextension==3.6.10
      - zipp==3.6.0
prefix: /opt/conda/envs/krisk

krisk/tests/test_plot.py::test_trendline krisk/tests/test_plot.py::test_smooth_line krisk/tests/test_plot.py::test_density
krisk/tests/test_plot.py::test_bar krisk/tests/test_plot.py::test_line krisk/tests/test_plot.py::test_full_bar_line krisk/tests/test_plot.py::test_hist krisk/tests/test_plot.py::test_scatter
krisk/plot/bar_line.py krisk/plot/__init__.py
krisk/plot/bar_line.py krisk/plot/__init__.py