Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ cover/
venv/
.cache/
*.swp
*.rdb
coverage.xml
htmlcov/
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ python:
- 'pypy'
install: pip install -U nose .
script:
- nosetests --verbose
- nosetests --with-coverage --cover-package=echarts --verbose
after_success:
- pip install codecov
- codecov
Expand Down
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ recursive-exclude *.egg-info *
recursive-exclude * *.py[co]

recursive-include docs *.rst
recursive-include echarts *.j2

49 changes: 36 additions & 13 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ Echarts for Python

An unofficial Echarts options generator with Python.

.. image:: https://img.shields.io/pypi/v/Echarts.svg
:target: https://pypi.python.org/pypi/Echarts/
.. image:: https://img.shields.io/pypi/v/echarts-python.svg
:target: https://pypi.python.org/pypi/echarts-python/
:alt: Latest Version
.. image:: https://travis-ci.org/yufeiminds/echarts-python.svg?branch=develop
:target: https://travis-ci.org/yufeiminds/echarts-python
Expand All @@ -17,8 +17,10 @@ An unofficial Echarts options generator with Python.
:alt: Doc Status

- Free software: MIT license
- Documentation: https://echarts-python.readthedocs.com/en/
- Online demo: https://yufeiminds.github.io/echarts-python/
- Documentation: http://echarts-python.readthedocs.io/en/stable/ (NOT Ready)
- Online demo: https://yufeiminds.github.io/echarts-python/ (NOT Ready)

This repo still on developing (ALPHA), DON'T USE IT IN PRODUCTION.

Installation
------------
Expand Down Expand Up @@ -46,30 +48,51 @@ The `chart.json` property will be
.. code-block:: javascript

{
"title": {
"text": "GDP",
"subtext": "This is a fake chart"
},
"series": [
{
"type": "bar",
"zlevel": 0,
"data": [2, 3, 4, 5],
"data": [
2,
3,
4,
5
],
"name": "China"
}
],
"legend": {
"y": "top",
"x": "center",
"data": [
"China"
"GDP"
],
"orient": "horizontal"
},
"title": {
"text": "GDP",
"subtext": "This is a fake chart"
},
"xAxis": [],
"yAxis": []
"xAxis": [
{
"position": "bottom",
"data": [
"Nov",
"Dec",
"Jan",
"Feb"
],
"type": "category"
}
],
"yAxis": {}
}

on Mac OSX, you also can execute ::

chart.plot()

and invoke a browser to display the chart.


Contribution
------------
Expand Down
61 changes: 44 additions & 17 deletions echarts/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,28 @@
import tempfile
import webbrowser
from .option import Base
from .option import Axis, Legend, Series, Tooltip, Toolbox
from .option import Axis, Legend, Series, Tooltip, Toolbox, VisualMap
from .datastructure import *

__version__ = '0.1'
__release__ = '0.1.1'
__release__ = '0.1.3'
__author__ = 'Hsiaoming Yang <me@lepture.com>'


class Echart(Base):
def __init__(self, title, description=None, **kwargs):
def __init__(self, title, description=None, axis=True, **kwargs):
self.title = {
'text': title,
'subtext': description,
}

self.x_axis = []
self.y_axis = []
self.axis = axis
if self.axis:
self.x_axis = []
self.y_axis = []

self.series = []
self.kwargs = kwargs

self.logger = logging.getLogger(__name__)

Expand All @@ -53,6 +57,8 @@ def use(self, obj):
self.series.append(obj)
elif isinstance(obj, Toolbox):
self.toolbox = obj
elif isinstance(obj, VisualMap):
self.visualMap = obj

return self

Expand All @@ -65,28 +71,49 @@ def json(self):
"""JSON format data."""
json = {
'title': self.title,
'xAxis': list(map(dict, self.x_axis)) or {},
'yAxis': list(map(dict, self.y_axis)) or {},
'series': list(map(dict, self.series)),
}

if not hasattr(self, 'legend'):
self.legend = Legend(list(map(lambda o: o.name, self.data)))

json['legend'] = self.legend.json
if self.axis:
json['xAxis'] = list(map(dict, self.x_axis)) or [{}]
json['yAxis'] = list(map(dict, self.y_axis)) or [{}]

if hasattr(self, 'legend'):
json['legend'] = self.legend.json
if hasattr(self, 'tooltip'):
json['tooltip'] = self.tooltip.json
if hasattr(self, 'toolbox'):
json['toolbox'] = self.toolbox.json
if hasattr(self, 'visualMap'):
json['visualMap'] = self.visualMap.json

json.update(self.kwargs)
return json

def plot(self):
html = tempfile.NamedTemporaryFile(suffix='.html', delete=False)
def _html(self):
with open(os.path.join(os.path.dirname(__file__), 'plot.j2')) as f:
template = f.read()
content = template.replace('{{ opt }}', json.dumps(self.json, indent=4))
html.write(content)
webbrowser.open('file://' + os.path.realpath(html.name))
html.close()
return template.replace('{{ opt }}', json.dumps(self.json, indent=4))

def plot(self, persist=True):
"""
Plot into html file

:param persist: persist output html to disk
"""
with tempfile.NamedTemporaryFile(suffix='.html', delete=not persist) as fobj:
fobj.write(self._html())
fobj.flush()
webbrowser.open('file://' + os.path.realpath(fobj.name))
persist or raw_input('Press enter for continue')

def save(self, path, name):
"""
Save html file into project dir
:param path: project dir
:param name: html file name
"""
if not os.path.exists(path):
os.makedirs(path)
with open(path+str(name)+".html", "w") as html_file:
html_file.write(self._html())
23 changes: 23 additions & 0 deletions echarts/option.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,26 @@ def json(self):
if self._kwargs:
json.update(self._kwargs)
return json


class VisualMap(Base):
"""maps data to visual channels"""

def __init__(self, type, min, max, **kwargs):
assert type in ("continuous", "piecewise")
self.type = type
self.min = min
self.max = max
self._kwargs = kwargs

@property
def json(self):
"""JSON format data"""
json = {
"type": self.type,
'min': self.min,
'max': self.max
}
if self._kwargs:
json.update(self._kwargs)
return json
62 changes: 62 additions & 0 deletions samples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Echarts Python Sample

A simple flask server && A simple html with webpack

## Code

### Python

```python
@app.route('/opt/bar')
def bar():
chart = Echart('GDP', 'This is a fake chart')
chart.use(Bar('China', [2, 3, 4, 5]))
chart.use(Legend(['GDP']))
chart.use(Axis('category', 'bottom', data=['Nov', 'Dec', 'Jan', 'Feb']))
return jsonify(chart.json)
```

### ES5

```javascript
// XHR callback
function callback () {
var chart = echarts.init(document.getElementById('main'));
chart.setOption(response.data)
}
```

### ES6

```javascript
fetch('http://127.0.0.1:5000/opt/bar').then(resp => {
var chart = echarts.init(document.getElementById('main'));
chart.setOption(response.data)
})
```

## Run Example

### Server

```
pip install -r requirements.txt

python -m index
```

### Frontend

```
sudo npm install

webpack
```

### Open Page

```
python -m SimpleHTTPServer

open http://localhost:8000/
```
1 change: 1 addition & 0 deletions samples/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ def bar():

if __name__ == '__main__':
app = create_app()
print('Serve on http://localhost:5000')
http_server = WSGIServer(('', 5000), app)
http_server.serve_forever()
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def fread(filename):

setup(
name='echarts-python',
version=echarts.__version__,
version=echarts.__release__,
author=author,
author_email=author_email,
url='https://github.com/yufeiminds/echarts-python',
Expand Down
3 changes: 2 additions & 1 deletion tests/test_echart.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

def test_axis():
chart = Echart('Axis', 'Proportion of Browser')
assert not chart.json['xAxis'] and not chart.json['yAxis']
assert len(chart.json['xAxis'][0]) == 0
assert len(chart.json['yAxis'][0]) == 0
chart.use(Axis('category', 'bottom', 'proportion', inverse=True))
assert chart.json['xAxis']
chart.use(Axis('category', 'left', 'proportion', inverse=True))
Expand Down
Loading