├── LICENSE ├── README.md ├── eplot ├── __init__.py └── eplot.py ├── examples └── eplot usage example.ipynb └── img ├── bar_figure.png ├── box_figure.png ├── box_series_figure.png ├── countplot_figure.png ├── histogram_figure.png ├── line_figure.png ├── pie_figure.png ├── pie_rose_figure.png ├── scatter3d_category_figure.png └── scatter_category_figure.png /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 quantpy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eplot 2 | 3 | `eplot` is a `pandas` interface for `pyecharts`,(now is support `pyecharts` 1.5.1 version!). 4 | 5 | As we know, `pyecharts` is a great python module as a wrapper for echarts, it is easy to use in `pandas` by function `add` . 6 | 7 | http://pyecharts.org/#/zh-cn/prepare 8 | 9 | However, it will be more simple if it can be used as raw `pandas` plot module, eg: `df.plot.bar()`. 10 | 11 | Impired by `cufflinks` to `plotly`, I created these codes for the `pyecharts` smoothly useage in `pandas` , by only registering functions to the `DataFrame` or `Series` classes. 12 | 13 | As a result, we need not to call pyecharts or creat pyecharts objects out of the `DataFrame`, we plot interacted figures in the `pyecharts` backend only in one line as follow: 14 | 15 | Useage: 16 | 17 | ```python 18 | import eplot 19 | import pandas as pd 20 | import numpy as np 21 | df = pd.DataFrame([np.random.uniform(10,1,size=1000), 22 | np.random.uniform(10,5,size=1000), 23 | np.random.randint(1,high=10,size=1000), 24 | np.random.choice(list('ABCD'),size=1000)], 25 | index=['col1','col2','col3','col4']).T 26 | ``` 27 | 28 | In the latest version, a function `set_config` is added, so you can use this function to decide whether HTML (which can be display in notebook directly) or pyecharts CHART(which can reuse the chart). 29 | 30 | If return type is HTML, you can see the chart directly in jupyter notebook, but cannot change anymore. 31 | If return type is CHART, you need `df.col1.eplot.bar().render_notebook()` in order to display in notebook. 32 | 33 | ```python 34 | eplot.set_config(return_type='CHART') 35 | eplot.set_config(return_type='HTML') # default by html 36 | ``` 37 | 38 | 39 | 40 | # line 41 | 42 | ![line_figure](./img/line_figure.png) 43 | 44 | # bar 45 | 46 | ![](./img/bar_figure.png) 47 | 48 | # histogram 49 | 50 | ![](./img/histogram_figure.png) 51 | 52 | # scatter 53 | 54 | ![](./img/scatter_category_figure.png) 55 | 56 | ![](./img/scatter3d_category_figure.png) 57 | 58 | 59 | 60 | # pie 61 | 62 | ![](./img/pie_figure.png) 63 | 64 | # rose pie 65 | 66 | ![](./img/pie_rose_figure.png) 67 | 68 | # countplot 69 | 70 | ![](./img/countplot_figure.png) 71 | 72 | # box 73 | 74 | ![](./img/box_figure.png) 75 | 76 | ![](./img/box_series_figure.png) 77 | 78 | More examples can be found in the notebook `eplot useage example.ipynb`. -------------------------------------------------------------------------------- /eplot/__init__.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | @version: 0.1 5 | @author: pjgao 6 | @city: Nanjing 7 | @file: __init__.py.py 8 | @time: 2018/12/10 16:22 9 | """ 10 | 11 | __version__ = '0.1.1' -------------------------------------------------------------------------------- /eplot/eplot.py: -------------------------------------------------------------------------------- 1 | import pandas 2 | import pyecharts 3 | import numpy as np 4 | from pandas.core.base import PandasObject 5 | from pandas.core.accessor import CachedAccessor 6 | import pyecharts.options as opts 7 | from pyecharts.render.display import HTML 8 | from pyecharts.render.engine import RenderEngine 9 | from pyecharts.commons import utils 10 | 11 | Config = {'return_type': 'HTML'} 12 | 13 | 14 | def set_config(**kwargs): 15 | ''' 16 | if return type is HTML, you can see the chart directly in jupyter notebook, but cannot change anymore 17 | if return type is CHART, you need `df.col1.eplot.bar().render_notebook()` in order to display in notebook. 18 | ''' 19 | global Config 20 | for i in kwargs.keys(): 21 | Config[i] = kwargs[i] 22 | 23 | 24 | def bar(data, title=None, useCols=None, **args): 25 | barFig = pyecharts.charts.Bar() 26 | barFig.set_global_opts(title_opts=opts.TitleOpts(title=title)) 27 | if isinstance(data, pandas.Series): 28 | barFig.add_xaxis(data.index.tolist()) 29 | barFig.add_yaxis(data.name, data.values.tolist()) 30 | elif isinstance(data, pandas.DataFrame): 31 | useCols = useCols if useCols else data.columns 32 | for i in useCols: 33 | barFig.add_xaxis(data[i].index.tolist()) 34 | barFig.add_yaxis(i, data[i].values.tolist()) 35 | result = barFig.render_notebook( 36 | ) if Config['return_type'] == 'HTML' else barFig 37 | return result 38 | 39 | 40 | def line( 41 | data, 42 | title=None, 43 | lineConfig=None, 44 | manyLineConfig=None, 45 | useCols=None, 46 | **args): 47 | lineFig = pyecharts.charts.Line() 48 | lineFig.set_global_opts(title_opts=opts.TitleOpts(title=title)) 49 | if isinstance(data, pandas.Series): 50 | lineConfig = lineConfig if lineConfig else {} 51 | 52 | lineFig.add_xaxis(data.index.tolist()) 53 | lineFig.add_yaxis(data.name, data.values.tolist(), 54 | **lineConfig, **args) 55 | elif isinstance(data, pandas.DataFrame): 56 | if useCols is None: 57 | useCols = data.columns 58 | if lineConfig is None: 59 | manyLineConfig = {} 60 | for i in useCols: 61 | lineFig.add_xaxis(data.index.tolist())\ 62 | .add_yaxis(i, data[i].tolist(), **manyLineConfig.get(i, {})) 63 | lineFig.set_series_opts(label_opts=opts.LabelOpts(is_show=False)) 64 | result = lineFig.render_notebook( 65 | ) if Config['return_type'] == 'HTML' else lineFig 66 | return result 67 | 68 | 69 | def pie(data, y=None, title=None,label_formatter="{b}: {c}({d}%)", **args): 70 | pieFig = pyecharts.charts.Pie() 71 | pieFig.set_global_opts(title_opts=opts.TitleOpts(title=title)) 72 | if isinstance(data, pandas.Series): 73 | pieFig.add(data.name, list(zip(data.index.tolist(), 74 | data.values.tolist())), **args) 75 | elif isinstance(data, pandas.DataFrame): 76 | pieFig.add(y, list(zip(data.index.tolist(), 77 | data[y].values.tolist())), **args) 78 | pieFig.set_series_opts(label_opts=opts.LabelOpts(formatter=label_formatter)) 79 | result = pieFig.render_notebook( 80 | ) if Config['return_type'] == 'HTML' else pieFig 81 | return result 82 | 83 | 84 | def hist(data, title='histogram', bins=10, **args): 85 | histFig = pyecharts.charts.Bar() 86 | histFig.set_global_opts(title_opts=opts.TitleOpts(title=title)) 87 | y, x = np.histogram(data, bins=bins) 88 | x = x.astype(int).astype(str) 89 | xlabels = [x[i - 1] + '-' + x[i] for i in range(1, len(x))] 90 | histFig.add_xaxis(xlabels) 91 | histFig.add_yaxis(data.name, y.tolist(), **args) 92 | result = histFig.render_notebook( 93 | ) if Config['return_type'] == 'HTML' else histFig 94 | return result 95 | 96 | 97 | def box(data, title=None, **args): 98 | boxFig = pyecharts.charts.Boxplot() 99 | boxFig.set_global_opts(title_opts=opts.TitleOpts(title=title)) 100 | if isinstance(data, pandas.Series): 101 | boxFig.add_xaxis([data.name]) 102 | boxFig.add_yaxis('', boxFig.prepare_data( 103 | data.values.reshape((1, -1)).tolist())) 104 | elif isinstance(data, pandas.DataFrame): 105 | boxFig.add_xaxis(data.columns.tolist()) 106 | boxFig.add_yaxis('', boxFig.prepare_data(data.values.T.tolist())) 107 | result = boxFig.render_notebook( 108 | ) if Config['return_type'] == 'HTML' else boxFig 109 | return result 110 | 111 | 112 | def countplot(data, title=None, **args): 113 | return data.value_counts().eplot.bar(title='countplot', **args) 114 | 115 | 116 | def scatter( 117 | data, 118 | x, 119 | y, 120 | category_col=None, 121 | title=None, 122 | category_name=None, 123 | **args): 124 | scatterFig = pyecharts.charts.Scatter() 125 | lineFig = pyecharts.charts.Line() 126 | scatterFig.set_global_opts(title_opts=opts.TitleOpts(title=title)) 127 | if category_col is None: 128 | (scatterFig.add_xaxis(data[x].values.tolist()) 129 | .add_yaxis('', data[y].values.tolist()) 130 | .set_series_opts(label_opts=opts.LabelOpts(is_show=False)) 131 | ) 132 | else: 133 | for cat, d in data.groupby(category_col): 134 | #scatterFig.add(cat, d[x], d[y], **args) 135 | (scatterFig.add_xaxis(d[x].values.tolist()) 136 | .add_yaxis(cat, d[y].values.tolist()) 137 | .set_series_opts(label_opts=opts.LabelOpts(is_show=False)) 138 | ) 139 | result = scatterFig.render_notebook( 140 | ) if Config['return_type'] == 'HTML' else scatterFig 141 | return result 142 | 143 | 144 | def scatter3d( 145 | data, 146 | x, 147 | y, 148 | z, 149 | category_col=None, 150 | title=None, 151 | category_name=None, 152 | **args): 153 | scatter3dFig = pyecharts.charts.Scatter3D(title) 154 | if category_col is None: 155 | scatter3dFig.add(category_name, data[[x, y, z]].values, **args) 156 | else: 157 | for cat, d in data.groupby(category_col): 158 | scatter3dFig.add(cat, d[[x, y, z]].values, **args) 159 | result = scatter3dFig.render_notebook( 160 | ) if Config['return_type'] == 'HTML' else scatter3dFig 161 | return result 162 | 163 | 164 | def eplot_series(se, kind='bar', title=None, bins=10, **kwds): 165 | if kind == 'bar': 166 | return bar(se, title=title, **kwds) 167 | if kind == 'line': 168 | return line(se, title=title, **kwds) 169 | if kind == 'pie': 170 | return pie(se, title=title, **kwds) 171 | if kind == 'hist': 172 | return hist(se, title=title, bins=bins, **kwds) 173 | if kind == 'box': 174 | return box(se, title=title, **kwds) 175 | if kind == 'countplot': 176 | return countplot(se, title=title, **kwds) 177 | 178 | 179 | def eplot_frame( 180 | df, 181 | kind='bar', 182 | x=None, 183 | y=None, 184 | z=None, 185 | category_col=None, 186 | category_name=None, 187 | title=None, 188 | **kwds): 189 | if kind == 'bar': 190 | return bar(df, title=title, **kwds) 191 | if kind == 'line': 192 | return line(df, title=title, **kwds) 193 | if kind == 'box': 194 | return box(df, title=title, **kwds) 195 | if kind == 'pie': 196 | return pie(df, y=y, title=title, **kwds) 197 | if kind == 'scatter': 198 | return scatter( 199 | df, 200 | x=x, 201 | y=y, 202 | category_col=category_col, 203 | category_name=category_name, 204 | title=title, 205 | **kwds) 206 | if kind == 'scatter3d': 207 | return scatter3d( 208 | df, 209 | x=x, 210 | y=y, 211 | z=z, 212 | category_col=category_col, 213 | category_name=category_name, 214 | title=title, 215 | **kwds) 216 | 217 | 218 | class EchartsBasePlotMethods(PandasObject): 219 | def __init__(self, data): 220 | self._parent = data # can be Series or DataFrame 221 | 222 | def __call__(self, *args, **kwargs): 223 | raise NotImplementedError 224 | 225 | 226 | class EchartsSeriesPlotMethods(EchartsBasePlotMethods): 227 | def __call__(self, kind='line', bins=10, title=None, **kwds): 228 | return eplot_series( 229 | self._parent, 230 | kind=kind, 231 | title=title, 232 | bins=bins, 233 | **kwds) 234 | 235 | def bar(self, title='bar', **kwds): 236 | return self(kind='bar', title=title, **kwds) 237 | 238 | def line(self, title='line', **kwds): 239 | return self(kind='line', title=title, **kwds) 240 | 241 | def pie( 242 | self, 243 | title='pie', 244 | y=None, 245 | color=None, 246 | radius=None, 247 | center=None, 248 | rosetype=None, 249 | label_opts=None, 250 | **kwds): 251 | if color is not None: 252 | kwds.update({'color': color}) 253 | if radius is not None: 254 | kwds.update({'radius': radius}) 255 | if center is not None: 256 | kwds.update({'center': center}) 257 | if rosetype is not None: 258 | kwds.update({'rosetype': rosetype}) 259 | if label_opts is not None: 260 | kwds.update({'label_opts': label_opts}) 261 | return self(kind='pie', title=title, **kwds) 262 | 263 | def hist(self, title='histogram', bins=10, **kwds): 264 | return self(kind='hist', title=title, bins=bins, **kwds) 265 | 266 | def box(self, title='box', **kwds): 267 | return self(kind='box', title=title, **kwds) 268 | 269 | def countplot(self, title='countplot', **kwds): 270 | return self(kind='countplot', title=title, **kwds) 271 | 272 | 273 | class EchartsFramePlotMethods(EchartsBasePlotMethods): 274 | def __call__( 275 | self, 276 | kind='line', 277 | x=None, 278 | y=None, 279 | z=None, 280 | category_col=None, 281 | category_name=None, 282 | title=None, 283 | **kwds): 284 | return eplot_frame( 285 | self._parent, 286 | kind=kind, 287 | x=x, 288 | y=y, 289 | z=z, 290 | category_col=category_col, 291 | category_name=category_name, 292 | title=title, 293 | **kwds) 294 | 295 | def bar(self, title='bar', **kwds): 296 | return self(kind='bar', title=title, **kwds) 297 | 298 | def line(self, title='line', **kwds): 299 | return self(kind='line', title='title', **kwds) 300 | 301 | def box(self, title='box', **kwds): 302 | return self(kind='box', title=title, **kwds) 303 | 304 | def pie( 305 | self, 306 | title='pie', 307 | y=None, 308 | color=None, 309 | radius=None, 310 | center=None, 311 | rosetype=None, 312 | label_opts=None, 313 | **kwds): 314 | if color is not None: 315 | kwds.update({'color': color}) 316 | if radius is not None: 317 | kwds.update({'radius': radius}) 318 | if center is not None: 319 | kwds.update({'center': center}) 320 | if rosetype is not None: 321 | kwds.update({'rosetype': rosetype}) 322 | if label_opts is not None: 323 | kwds.update({'label_opts': label_opts}) 324 | return self(kind='pie', y=y, title=title, **kwds) 325 | 326 | def scatter( 327 | self, 328 | x, 329 | y, 330 | category_col=None, 331 | category_name=None, 332 | title='scatter'): 333 | return self( 334 | kind='scatter', 335 | x=x, 336 | y=y, 337 | category_col=category_col, 338 | category_name=category_name, 339 | title=title) 340 | 341 | def scatter3d( 342 | self, 343 | x, 344 | y, 345 | z, 346 | category_col=None, 347 | category_name=None, 348 | title='scatter3d'): 349 | return self( 350 | kind='scatter3d', 351 | x=x, 352 | y=y, 353 | z=z, 354 | category_col=category_col, 355 | category_name=category_name, 356 | title=title) 357 | 358 | 359 | pandas.Series.eplot = CachedAccessor("eplot", EchartsSeriesPlotMethods) 360 | pandas.DataFrame.eplot = CachedAccessor("eplot", EchartsFramePlotMethods) 361 | -------------------------------------------------------------------------------- /img/bar_figure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjgao/eplot/e264f0cc22f02589e94135c3b987ef925a4a67aa/img/bar_figure.png -------------------------------------------------------------------------------- /img/box_figure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjgao/eplot/e264f0cc22f02589e94135c3b987ef925a4a67aa/img/box_figure.png -------------------------------------------------------------------------------- /img/box_series_figure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjgao/eplot/e264f0cc22f02589e94135c3b987ef925a4a67aa/img/box_series_figure.png -------------------------------------------------------------------------------- /img/countplot_figure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjgao/eplot/e264f0cc22f02589e94135c3b987ef925a4a67aa/img/countplot_figure.png -------------------------------------------------------------------------------- /img/histogram_figure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjgao/eplot/e264f0cc22f02589e94135c3b987ef925a4a67aa/img/histogram_figure.png -------------------------------------------------------------------------------- /img/line_figure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjgao/eplot/e264f0cc22f02589e94135c3b987ef925a4a67aa/img/line_figure.png -------------------------------------------------------------------------------- /img/pie_figure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjgao/eplot/e264f0cc22f02589e94135c3b987ef925a4a67aa/img/pie_figure.png -------------------------------------------------------------------------------- /img/pie_rose_figure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjgao/eplot/e264f0cc22f02589e94135c3b987ef925a4a67aa/img/pie_rose_figure.png -------------------------------------------------------------------------------- /img/scatter3d_category_figure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjgao/eplot/e264f0cc22f02589e94135c3b987ef925a4a67aa/img/scatter3d_category_figure.png -------------------------------------------------------------------------------- /img/scatter_category_figure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjgao/eplot/e264f0cc22f02589e94135c3b987ef925a4a67aa/img/scatter_category_figure.png --------------------------------------------------------------------------------