Repository: napjon/krisk

Issue:
Set global config for all charts in current session
Users don't have to set config for each chart. Currently targeting for:

* Themes, Color, and Pallette
* Size 

Discussion:
codecov-io: ## [Current coverage](https://codecov.io/gh/napjon/krisk/pull/51?src=pr) is 92.87% (diff: 100%)
> Merging [#51](https://codecov.io/gh/napjon/krisk/pull/51?src=pr) into [0.2-develop](https://codecov.io/gh/napjon/krisk/branch/0.2-develop?src=pr) will increase coverage by **0.80%**

```diff
@@           0.2-develop        #51   diff @@
=============================================
  Files                9          8     -1   
  Lines              353        351     -2   
  Methods              0          0          
  Messages             0          0          
  Branches            50         50          
=============================================
+ Hits               325        326     +1   
+ Misses              18         17     -1   
+ Partials            10          8     -2   
```

> Powered by [Codecov](https://codecov.io?src=pr). Last update [bc85b5f...1bf0d73](https://codecov.io/gh/napjon/krisk/compare/bc85b5f7aaff361e80bd06051650c49a00576e86...1bf0d732cc133232ed04a977a3aedbb216da826f?src=pr)

Patch:
diff --git a/.coveragerc b/.coveragerc
index 5c46c59..2c4b66b 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -2,5 +2,6 @@
 branch: True
 omit = 
   */test_*.py
+  krisk/__init__.py
 source = 
   krisk
diff --git a/krisk/__init__.py b/krisk/__init__.py
index a63c1ea..c4e343f 100644
--- a/krisk/__init__.py
+++ b/krisk/__init__.py
@@ -1,6 +1,11 @@
 # Krisk is a module to bridge E-Charts to python data science ecosystem
 
-from krisk.connections import init_notebook
+
+from krisk.util import init_notebook
+import krisk.plot.api as plot
+# Override chart to prevent all variables to be accessed except two below
+import krisk.chart.api as chart
+from krisk.chart.api import rcParams, Chart
 
 __version__ = '0.1.11'
 
diff --git a/krisk/chart/__init__.py b/krisk/chart/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/krisk/chart/api.py b/krisk/chart/api.py
new file mode 100644
index 0000000..95f3271
--- /dev/null
+++ b/krisk/chart/api.py
@@ -0,0 +1,1 @@
+from krisk.chart.core import rcParams, Chart
\ No newline at end of file
diff --git a/krisk/chart.py b/krisk/chart/core.py
similarity index 92%
rename from krisk/chart.py
rename to krisk/chart/core.py
index beb692d..5adea11 100644
--- a/krisk/chart.py
+++ b/krisk/chart/core.py
@@ -3,13 +3,17 @@
 import uuid
 import json
 from copy import deepcopy
-from krisk.connections import get_paths
 from IPython.display import Javascript
 from krisk.util import get_content, join_current_dir
 
+__all__ = ['rcParams', 'Chart']
+
+
+JS_LIBS = ['echarts', 'dark', 'vintage', 'roma', 'shine', 'infographic', 'macarons']
 JS_TEMPLATE_PATH = 'static/krisk.js'
 EVENT_TEMPLATE_PATH = 'static/on_event.js'
 HTML_TEMPLATE_PATH = 'static/template.html'
+DEFAULT_CFG_PATH = 'static/defaults.json'
 
 APPEND_ELEMENT = """
 $('#{id}').attr('id','{id}'+'_old');
@@ -30,6 +34,37 @@ OPTION_TEMPLATE = {
     'series': []
 }
 
+rcParams = dict(theme='',
+    size=dict(width=600,height=400),
+    color=dict(background='',palette=''),
+    # TODO: Add tooltip, legend, and toolbox in 0.3
+    # tooltip_style=dict(trigger='item',
+    #                   axis_pointer='line',
+    #                   trigger_on='mousemove',
+    #                   font_style='normal',
+    #                   font_family='sans-serif',
+    #                   font_size=14),
+    # legend=dict(align='auto',
+    #            orient='horizontal',
+    #            x_pos='auto',
+    #            y_pos='auto'),
+    # toolbox=dict(save_format=None,
+    #             restore=False,
+    #             data_view=None,
+    #             data_zoom=False,
+    #             magic_type=None,
+    #             brush=None,
+    #             align='auto',
+    #             orient='horizontal',
+    #             x_pos='auto',
+    #             y_pos='auto')
+    )
+
+
+# def set(rc):
+#     DEFAULTS.update(dict)
+#     return DEFAULTS
+
 
 class Chart(object):
     """Chart Object"""
@@ -45,10 +80,15 @@ class Chart(object):
         self._chartId = str(uuid.uuid4())
         self.option = deepcopy(OPTION_TEMPLATE)
         self._kwargs_chart_ = kwargs
-        self._theme = ''
         self._axes_swapped = True
         self._events = {}
-        self._size = {'width': 600, 'height': 400}
+
+        self._size = rcParams['size']
+        self._theme = rcParams['theme']
+        self.set_color(**rcParams['color'])
+        # self.set_legend(**rcParams['legend'])
+        # self.set_toolbox(**rcParams['toolbox'])
+        # self.set_tooltip_style(**rcParams['tooltip_style'])
 
     # Color and Themes
 
@@ -63,7 +103,7 @@ class Chart(object):
             {'dark','vintage','roma','shine','infographic','macarons'}, default None
         """
 
-        themes = get_paths()[1:]
+        themes = JS_LIBS[1:] + ['']
 
         if theme not in themes:
             raise AssertionError("Invalid theme name: {theme}".format(
@@ -519,7 +559,7 @@ class Chart(object):
             event=e, function=self._events[e]) for e in self._events]
 
         OPTION_KWS = dict(
-            requires=get_paths().__repr__(),
+            requires=JS_LIBS.__repr__(),
             chartId=self._chartId,
             theme=self._theme,
             option=json.dumps(
diff --git a/krisk/connections.py b/krisk/connections.py
deleted file mode 100644
index b44a60e..0000000
--- a/krisk/connections.py
+++ /dev/null
@@ -1,33 +0,0 @@
-#TODO FIX LOCAL PATH! NEED TO DO nbextension install
-#from collections import OrderedDict
-#import json
-#from krisk.util import join_current_dir
-
-# ECHARTS_URL = 'https://cdnjs.cloudflare.com/ajax/libs/echarts/3.2.0/'
-# ECHARTS_FILE = 'echarts.min'
-# d_paths = OrderedDict({})
-THEMES = ['dark', 'vintage', 'roma', 'shine', 'infographic', 'macarons']
-
-# THEMES_URL='//echarts.baidu.com/asset/theme/'
-# PATH_LOCAL = join_current_dir('static')
-# PATH_LOCAL = 'pandas-echarts/krisk/static'
-
-
-def init_notebook():
-    """
-    Inject Javascript to notebook, default using local js.
-    This function must be last executed in a cell to produce the Javascript in the output cell    
-    """
-    from IPython.display import Javascript
-    return Javascript("""
-    require.config({
-                 baseUrl : "//cdn.rawgit.com/napjon/krisk/master/krisk/static",
-                 paths: {
-                      echarts: "//cdnjs.cloudflare.com/ajax/libs/echarts/3.2.1/echarts.min"
-                  }
-    });
-    """)
-
-
-def get_paths():
-    return ['echarts'] + THEMES
diff --git a/krisk/plot/__init__.py b/krisk/plot/__init__.py
index 281688f..e69de29 100644
--- a/krisk/plot/__init__.py
+++ b/krisk/plot/__init__.py
@@ -1,153 +0,0 @@
-from krisk.plot.make_chart import make_chart
-
-
-def bar(df,
-        x,
-        y=None,
-        c=None,
-        how='count',
-        stacked=False,
-        annotate=None,
-        full=False,
-        trendline=False):
-    """
-    Parameters
-    ----------
-    df: pd.DataFrame
-        data to be used for the chart
-    x: string
-        columns to be used as category axis
-    y: string, default to None
-        if None, use count of category value. otherwise aggregate based on y columns
-    category: string, default to None
-        another grouping columns inside x-axis
-    how: string, default to None
-        to be passed to pd.group_by(x).aggregate(how). Can be mean,median, or any 
-        reduced operations.
-    stacked: Boolean, default to False.
-        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
-    full: boolean, default to False.
-        If true, set to full area stacked chart. Only work if stacked is True.
-    trendline: boolean, default to False.
-        If true, add line that connected the bars. Only work if not category, category but stacked,
-        or not full.  
-    
-    Returns
-    -------
-    Chart Object
-    """
-
-    # TODO: add optional argument trendline
-
-    return make_chart(df,type='bar',x=x,y=y,c=c,how=how,stacked=stacked,full=full,
-                      trendline=trendline,
-                      annotate='top' if annotate == True else annotate)
-
-
-def line(df,
-         x,
-         y=None,
-         c=None,
-         how=None,
-         stacked=False,
-         area=False,
-         annotate=None,
-         full=False,
-         smooth=False):
-    """
-    Parameters
-    ----------
-    df: pd.DataFrame
-        data to be used for the chart
-    x: string
-        columns to be used as category axis
-    y: string, default to None
-        if None, use count of category value. otherwise aggregate based on y columns
-    c: string, default to None
-        category column inside x-axis
-    how: string, default to None
-        to be passed to pd.group_by(x).aggregate(how). Can be mean,median, or any 
-        reduced operations.
-    stacked: Boolean, default to False.
-        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
-    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)
-
-
-def hist(df,
-         x,
-         c=None,
-         bins=10,
-         normed=False,
-         stacked=False,
-         annotate=None,
-         density=False):
-    """
-    Parameters
-    ----------
-    df: pd.DataFrame
-        data to be used for the chart
-    x: string
-        columns to be used as category axis
-    c: string, default to None
-        another grouping columns inside x-axis
-    bins: int, default to 10
-        Set number of bins in histogram
-    normed: boolean, default to False
-        Whether normalize the histogram
-    stacked: Boolean, default to False.
-        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
-    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)
-   
-
-def scatter(df, x, y, s=None, c=None, saturate=None, size_px=(10, 70)):
-    """
-    Parameters
-    ----------
-    df: pd.DataFrame
-        data to be used for the chart
-    x,y: string, columns in pd.DataFrame
-        Used as coordinate in scatter chart
-    s: string, columns in pd.DataFrame default to None
-        Used as sizing value of the scatter points
-    c: string, default to None
-        column used as grouping color category
-    saturation
-    size_px: tuple, default to (10,70)
-        boundary size, lower and upper limit in pixel for min-max scatter points
-
-        
-    Returns
-    -------
-    Chart Object
-    """
-    #TODO add saturation
-    return make_chart(df,type='scatter',x=x,y=y,s=s,c=c,saturate=saturate,size_px=size_px)
diff --git a/krisk/plot/api.py b/krisk/plot/api.py
new file mode 100644
index 0000000..281688f
--- /dev/null
+++ b/krisk/plot/api.py
@@ -0,0 +1,153 @@
+from krisk.plot.make_chart import make_chart
+
+
+def bar(df,
+        x,
+        y=None,
+        c=None,
+        how='count',
+        stacked=False,
+        annotate=None,
+        full=False,
+        trendline=False):
+    """
+    Parameters
+    ----------
+    df: pd.DataFrame
+        data to be used for the chart
+    x: string
+        columns to be used as category axis
+    y: string, default to None
+        if None, use count of category value. otherwise aggregate based on y columns
+    category: string, default to None
+        another grouping columns inside x-axis
+    how: string, default to None
+        to be passed to pd.group_by(x).aggregate(how). Can be mean,median, or any 
+        reduced operations.
+    stacked: Boolean, default to False.
+        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
+    full: boolean, default to False.
+        If true, set to full area stacked chart. Only work if stacked is True.
+    trendline: boolean, default to False.
+        If true, add line that connected the bars. Only work if not category, category but stacked,
+        or not full.  
+    
+    Returns
+    -------
+    Chart Object
+    """
+
+    # TODO: add optional argument trendline
+
+    return make_chart(df,type='bar',x=x,y=y,c=c,how=how,stacked=stacked,full=full,
+                      trendline=trendline,
+                      annotate='top' if annotate == True else annotate)
+
+
+def line(df,
+         x,
+         y=None,
+         c=None,
+         how=None,
+         stacked=False,
+         area=False,
+         annotate=None,
+         full=False,
+         smooth=False):
+    """
+    Parameters
+    ----------
+    df: pd.DataFrame
+        data to be used for the chart
+    x: string
+        columns to be used as category axis
+    y: string, default to None
+        if None, use count of category value. otherwise aggregate based on y columns
+    c: string, default to None
+        category column inside x-axis
+    how: string, default to None
+        to be passed to pd.group_by(x).aggregate(how). Can be mean,median, or any 
+        reduced operations.
+    stacked: Boolean, default to False.
+        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
+    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)
+
+
+def hist(df,
+         x,
+         c=None,
+         bins=10,
+         normed=False,
+         stacked=False,
+         annotate=None,
+         density=False):
+    """
+    Parameters
+    ----------
+    df: pd.DataFrame
+        data to be used for the chart
+    x: string
+        columns to be used as category axis
+    c: string, default to None
+        another grouping columns inside x-axis
+    bins: int, default to 10
+        Set number of bins in histogram
+    normed: boolean, default to False
+        Whether normalize the histogram
+    stacked: Boolean, default to False.
+        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
+    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)
+   
+
+def scatter(df, x, y, s=None, c=None, saturate=None, size_px=(10, 70)):
+    """
+    Parameters
+    ----------
+    df: pd.DataFrame
+        data to be used for the chart
+    x,y: string, columns in pd.DataFrame
+        Used as coordinate in scatter chart
+    s: string, columns in pd.DataFrame default to None
+        Used as sizing value of the scatter points
+    c: string, default to None
+        column used as grouping color category
+    saturation
+    size_px: tuple, default to (10,70)
+        boundary size, lower and upper limit in pixel for min-max scatter points
+
+        
+    Returns
+    -------
+    Chart Object
+    """
+    #TODO add saturation
+    return make_chart(df,type='scatter',x=x,y=y,s=s,c=c,saturate=saturate,size_px=size_px)
diff --git a/krisk/plot/make_chart.py b/krisk/plot/make_chart.py
index ea90926..924e015 100644
--- a/krisk/plot/make_chart.py
+++ b/krisk/plot/make_chart.py
@@ -1,5 +1,5 @@
 from copy import deepcopy
-from krisk.chart import Chart
+from krisk.chart.api import Chart
 
 
 def round_list(arr):
diff --git a/krisk/static/defaults.json b/krisk/static/defaults.json
new file mode 100644
index 0000000..34a9fe4
--- /dev/null
+++ b/krisk/static/defaults.json
@@ -0,0 +1,1 @@
+{"size": {"width": 600, "height": 400}, "palette": "", "background": "", "theme": ""}
\ No newline at end of file
diff --git a/krisk/util.py b/krisk/util.py
index fb01c5e..db8bcb3 100644
--- a/krisk/util.py
+++ b/krisk/util.py
@@ -14,3 +14,20 @@ def get_content(filepath):
 	abs_path = join_current_dir(filepath)
 	with open(abs_path, 'r') as f:
 		return f.read()
+
+
+def init_notebook():
+    """
+    Inject Javascript to notebook, useful when you provide html notebook generated (e.g nbviewwer).
+    You don't have to use this when using notebook, as it already provided by nbextension.
+    This function must be last executed in a cell to produce Javascript in the output cell    
+    """
+    from IPython.display import Javascript
+    return Javascript("""
+    require.config({
+                 baseUrl : "//cdn.rawgit.com/napjon/krisk/master/krisk/static",
+                 paths: {
+                      echarts: "//cdnjs.cloudflare.com/ajax/libs/echarts/3.2.1/echarts.min"
+                  }
+    });
+    """)
\ No newline at end of file
diff --git a/notebooks/declarative-visualization.ipynb b/notebooks/declarative-visualization.ipynb
index fcb4805..d59fa2f 100644
--- a/notebooks/declarative-visualization.ipynb
+++ b/notebooks/declarative-visualization.ipynb
@@ -9,7 +9,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 16,
+   "execution_count": 3,
    "metadata": {
     "collapsed": false
    },
@@ -30,7 +30,7 @@
        "<IPython.core.display.Javascript object>"
       ]
      },
-     "execution_count": 16,
+     "execution_count": 3,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -42,18 +42,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 4,
    "metadata": {
     "collapsed": false
    },
    "outputs": [],
    "source": [
-    "from krisk.chart import Chart"
+    "from krisk import Chart"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 5,
    "metadata": {
     "collapsed": false
    },
@@ -62,32 +62,32 @@
      "data": {
       "application/javascript": [
        "\n",
-       "$('#42633d9b-b939-477c-998f-6239dc3d1ad9').attr('id','42633d9b-b939-477c-998f-6239dc3d1ad9'+'_old');\n",
-       "element.append('<div id=\"42633d9b-b939-477c-998f-6239dc3d1ad9\" style=\"width: 600px;height:400px;\"></div>');require(['echarts', 'dark', 'vintage', 'roma', 'shine', 'infographic', 'macarons'],\n",
+       "$('#9e9dc869-da07-484d-b76f-c90c03d73d94').attr('id','9e9dc869-da07-484d-b76f-c90c03d73d94'+'_old');\n",
+       "element.append('<div id=\"9e9dc869-da07-484d-b76f-c90c03d73d94\" style=\"width: 600px;height:400px;\"></div>');require(['echarts', 'dark', 'vintage', 'roma', 'shine', 'infographic', 'macarons'],\n",
        "function(echarts){\n",
        "    \n",
        "    function parseFunction(str){\n",
        "        return eval('(' + str + ')');\n",
        "    }\n",
        "    \n",
-       "    var myChart = echarts.init(document.getElementById(\"42633d9b-b939-477c-998f-6239dc3d1ad9\"),\"\");\n",
+       "    var myChart = echarts.init(document.getElementById(\"9e9dc869-da07-484d-b76f-c90c03d73d94\"),\"\");\n",
        "    \n",
        "    var option = {\n",
        "    \"legend\": {\n",
        "        \"data\": []\n",
        "    },\n",
-       "    \"tooltip\": {\n",
-       "        \"axisPointer\": {\n",
-       "            \"type\": \"\"\n",
-       "        }\n",
-       "    },\n",
        "    \"series\": [],\n",
+       "    \"yAxis\": {},\n",
        "    \"title\": {\n",
        "        \"text\": \"\"\n",
        "    },\n",
-       "    \"yAxis\": {},\n",
        "    \"xAxis\": {\n",
        "        \"data\": []\n",
+       "    },\n",
+       "    \"tooltip\": {\n",
+       "        \"axisPointer\": {\n",
+       "            \"type\": \"\"\n",
+       "        }\n",
        "    }\n",
        "};\n",
        "    option['tooltip']['formatter'] = parseFunction(option['tooltip']['formatter']);\n",
@@ -100,10 +100,10 @@
        "\n"
       ],
       "text/plain": [
-       "<krisk.chart.Chart at 0x104af0588>"
+       "<krisk.chart.core.Chart at 0x104c136a0>"
       ]
      },
-     "execution_count": 18,
+     "execution_count": 5,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -163,7 +163,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": 6,
    "metadata": {
     "collapsed": false
    },
@@ -172,35 +172,35 @@
      "data": {
       "application/javascript": [
        "\n",
-       "$('#64f7e294-5831-4f59-8498-414051a776e7').attr('id','64f7e294-5831-4f59-8498-414051a776e7'+'_old');\n",
-       "element.append('<div id=\"64f7e294-5831-4f59-8498-414051a776e7\" style=\"width: 600px;height:400px;\"></div>');require(['echarts', 'dark', 'vintage', 'roma', 'shine', 'infographic', 'macarons'],\n",
+       "$('#ddb3080c-eece-494a-93a9-8d3c7c2edf23').attr('id','ddb3080c-eece-494a-93a9-8d3c7c2edf23'+'_old');\n",
+       "element.append('<div id=\"ddb3080c-eece-494a-93a9-8d3c7c2edf23\" style=\"width: 600px;height:400px;\"></div>');require(['echarts', 'dark', 'vintage', 'roma', 'shine', 'infographic', 'macarons'],\n",
        "function(echarts){\n",
        "    \n",
        "    function parseFunction(str){\n",
        "        return eval('(' + str + ')');\n",
        "    }\n",
        "    \n",
-       "    var myChart = echarts.init(document.getElementById(\"64f7e294-5831-4f59-8498-414051a776e7\"),\"vintage\");\n",
+       "    var myChart = echarts.init(document.getElementById(\"ddb3080c-eece-494a-93a9-8d3c7c2edf23\"),\"vintage\");\n",
        "    \n",
        "    var option = {\n",
-       "    \"legend\": {\n",
-       "        \"data\": []\n",
-       "    },\n",
        "    \"tooltip\": {\n",
        "        \"axisPointer\": {\n",
        "            \"type\": \"\"\n",
        "        }\n",
        "    },\n",
-       "    \"yAxis\": {},\n",
+       "    \"legend\": {\n",
+       "        \"data\": []\n",
+       "    },\n",
        "    \"title\": {\n",
        "        \"left\": \"center\",\n",
-       "        \"text\": \"This is a blank visualization\",\n",
-       "        \"bottom\": \"auto\"\n",
+       "        \"bottom\": \"auto\",\n",
+       "        \"text\": \"This is a blank visualization\"\n",
        "    },\n",
        "    \"series\": [],\n",
        "    \"xAxis\": {\n",
        "        \"data\": []\n",
-       "    }\n",
+       "    },\n",
+       "    \"yAxis\": {}\n",
        "};\n",
        "    option['tooltip']['formatter'] = parseFunction(option['tooltip']['formatter']);\n",
        "    myChart.setOption(option);\n",
@@ -212,10 +212,10 @@
        "\n"
       ],
       "text/plain": [
-       "<krisk.chart.Chart at 0x104b3ee48>"
+       "<krisk.chart.core.Chart at 0x104c13908>"
       ]
      },
-     "execution_count": 14,
+     "execution_count": 6,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -236,7 +236,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 15,
+   "execution_count": 7,
    "metadata": {
     "collapsed": false
    },
@@ -245,25 +245,20 @@
      "data": {
       "application/javascript": [
        "\n",
-       "$('#1b7e3e6c-c4f1-437b-8b02-199165980052').attr('id','1b7e3e6c-c4f1-437b-8b02-199165980052'+'_old');\n",
-       "element.append('<div id=\"1b7e3e6c-c4f1-437b-8b02-199165980052\" style=\"width: 600px;height:400px;\"></div>');require(['echarts', 'dark', 'vintage', 'roma', 'shine', 'infographic', 'macarons'],\n",
+       "$('#9e9dc869-da07-484d-b76f-c90c03d73d94').attr('id','9e9dc869-da07-484d-b76f-c90c03d73d94'+'_old');\n",
+       "element.append('<div id=\"9e9dc869-da07-484d-b76f-c90c03d73d94\" style=\"width: 600px;height:400px;\"></div>');require(['echarts', 'dark', 'vintage', 'roma', 'shine', 'infographic', 'macarons'],\n",
        "function(echarts){\n",
        "    \n",
        "    function parseFunction(str){\n",
        "        return eval('(' + str + ')');\n",
        "    }\n",
        "    \n",
-       "    var myChart = echarts.init(document.getElementById(\"1b7e3e6c-c4f1-437b-8b02-199165980052\"),\"vintage\");\n",
+       "    var myChart = echarts.init(document.getElementById(\"9e9dc869-da07-484d-b76f-c90c03d73d94\"),\"vintage\");\n",
        "    \n",
        "    var option = {\n",
        "    \"legend\": {\n",
        "        \"data\": []\n",
        "    },\n",
-       "    \"tooltip\": {\n",
-       "        \"axisPointer\": {\n",
-       "            \"type\": \"\"\n",
-       "        }\n",
-       "    },\n",
        "    \"series\": [\n",
        "        {\n",
        "            \"data\": [\n",
@@ -277,12 +272,12 @@
        "            \"type\": \"bar\"\n",
        "        }\n",
        "    ],\n",
+       "    \"yAxis\": {},\n",
        "    \"title\": {\n",
        "        \"left\": \"center\",\n",
-       "        \"text\": \"This is a blank visualization\",\n",
-       "        \"bottom\": \"auto\"\n",
+       "        \"bottom\": \"auto\",\n",
+       "        \"text\": \"This is a blank visualization\"\n",
        "    },\n",
-       "    \"yAxis\": {},\n",
        "    \"xAxis\": {\n",
        "        \"data\": [\n",
        "            \"Americas\",\n",
@@ -291,6 +286,11 @@
        "            \"Oceania\",\n",
        "            \"Europe\"\n",
        "        ]\n",
+       "    },\n",
+       "    \"tooltip\": {\n",
+       "        \"axisPointer\": {\n",
+       "            \"type\": \"\"\n",
+       "        }\n",
        "    }\n",
        "};\n",
        "    option['tooltip']['formatter'] = parseFunction(option['tooltip']['formatter']);\n",
@@ -303,10 +303,10 @@
        "\n"
       ],
       "text/plain": [
-       "<krisk.chart.Chart at 0x104b3cef0>"
+       "<krisk.chart.core.Chart at 0x104c136a0>"
       ]
      },
-     "execution_count": 15,
+     "execution_count": 7,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -326,8 +326,9 @@
   }
  ],
  "metadata": {
+  "anaconda-cloud": {},
   "kernelspec": {
-   "display_name": "Python 3",
+   "display_name": "Python [default]",
    "language": "python",
    "name": "python3"
   },
@@ -341,7 +342,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.5.2"
+   "version": "3.5.1"
   }
  },
  "nbformat": 4,


Test patch:
diff --git a/krisk/tests/conftest.py b/krisk/tests/conftest.py
index bbf3e2e..8e09042 100644
--- a/krisk/tests/conftest.py
+++ b/krisk/tests/conftest.py
@@ -24,7 +24,7 @@ def gapminder():
 @pytest.fixture(scope="module")
 def decl_chart():
     "Declarative Chart"
-    from krisk.chart import Chart
+    from krisk.chart.api import Chart
     chart = Chart()
     chart.option['series'] = [{'data': [10, 3, 7, 4, 5], 'name': 'continent', 'type': 'bar'}]
     chart.option['xAxis'] =  {'data': ['Americas', 'Asia', 'Africa', 'Oceania', 'Europe']}
diff --git a/krisk/tests/test_template.py b/krisk/tests/test_template.py
index 041f0db..e5ef7e5 100644
--- a/krisk/tests/test_template.py
+++ b/krisk/tests/test_template.py
@@ -4,7 +4,7 @@ ECHARTS_VERSION = '3.2.1'
 
 
 def test_html():
-    from krisk.chart import Chart
+    from krisk.chart.api import Chart
 
     c = Chart()
     c.to_html('../sample.html')
@@ -16,7 +16,7 @@ def test_html():
 
 
 def test_init_nb():
-    from krisk.connections import init_notebook
+    from krisk.util import init_notebook
 
     js_data = init_notebook().data
     js_init_template = """