├── tests ├── __init__.py ├── data │ ├── __init__.py │ └── test_all.py ├── grid │ ├── __init__.py │ ├── test_grid_psp.py │ ├── test_grid_qgrid.py │ └── test_grid_plotly.py ├── plot │ ├── __init__.py │ ├── test_plot.py │ ├── test_plot_matplotlib.py │ ├── test_plot_plotly.py │ └── test_plot_bokeh.py ├── extensions │ └── __init__.py ├── test_all.py └── test_utils.py ├── lantern ├── __main__.py ├── extensions │ ├── __init__.py │ └── savehooks │ │ ├── __init__.py │ │ ├── remove_output.py │ │ └── convert_to_script.py ├── plotting │ ├── plot_perspective.py │ ├── plotobj.py │ ├── plot_altair.py │ ├── plot_nvd3.py │ ├── plot_bqplot.py │ ├── __init__.py │ ├── plotutils.py │ ├── plot_bokeh.py │ ├── plot_plotly.py │ └── plot_matplotlib.py ├── grids │ ├── grid_qgrid.py │ ├── grid_lineup.py │ ├── grid_psp.py │ ├── grid_plotly.py │ ├── grid_phosphor.py │ ├── __init__.py │ └── grid_ipysheet.py ├── widgets │ ├── __init__.py │ └── variable_inspector.py ├── __init__.py ├── utils.py └── data │ ├── __init__.py │ ├── data_cufflinks.py │ ├── other.py │ └── data_sklearn.py ├── experimental ├── flask-highcharts │ ├── .gitignore │ ├── templates │ │ ├── live-data.html │ │ └── index.html │ ├── README.md │ ├── flask-live-chart.py │ └── static │ │ └── js │ │ └── highcharts.js ├── dash │ ├── dash-vanguard-report-master │ │ ├── run.sh │ │ └── .gitignore │ ├── dash-recession-report-demo-master │ │ ├── .gitignore │ │ └── run.sh │ ├── dash-yield-curve-master │ │ └── run.sh │ └── dash-stock-tickers-demo-app-master │ │ ├── run.sh │ │ ├── .gitignore │ │ └── app.py ├── ipyvolume │ ├── Untitled.ipynb │ └── Untitled2.ipynb ├── widgets │ ├── applications │ │ ├── Factoring.ipynb │ │ └── Image Browser.ipynb │ └── 6_Widget Asynchronous.ipynb └── ipympl.ipynb ├── docs ├── img │ ├── data.gif │ ├── demo.gif │ ├── logo.png │ ├── grids.gif │ ├── plot1.png │ ├── plot2.png │ ├── preview.gif │ ├── publish.png │ ├── plot │ │ ├── area.png │ │ ├── axis.png │ │ ├── bar.png │ │ ├── grid.png │ │ ├── hist.png │ │ ├── line.png │ │ ├── step.png │ │ ├── labels.png │ │ ├── legend.png │ │ ├── plots.gif │ │ ├── scatter.png │ │ └── ticks.png │ ├── preview2.gif │ ├── export │ │ ├── email.png │ │ ├── html.png │ │ ├── html2.png │ │ ├── input.png │ │ ├── pdf.png │ │ ├── pdf2.png │ │ ├── export.png │ │ └── sample.pdf │ └── widgets │ │ ├── widgets.gif │ │ └── variableinspector.png ├── api.rst ├── publish.rst ├── table.rst ├── widgets.rst ├── Makefile ├── make.bat ├── export.rst ├── installation.rst ├── quickstart.rst ├── index.rst ├── data.rst ├── plot.rst ├── conf.py └── rstref.rst ├── setup.cfg ├── .github ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── workflows │ └── build.yml └── CODE_OF_CONDUCT.md ├── MANIFEST.in ├── .gitattributes ├── requirements.txt ├── setup.py ├── CONTRIBUTING.md ├── Makefile ├── examples ├── perspective.ipynb ├── ipysheet.ipynb ├── bqplot.ipynb └── plotly.ipynb ├── .gitignore └── README.md /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lantern/__main__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/data/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/grid/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/plot/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/extensions/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lantern/extensions/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lantern/plotting/plot_perspective.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lantern/extensions/savehooks/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /experimental/flask-highcharts/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | -------------------------------------------------------------------------------- /experimental/flask-highcharts/templates/live-data.html: -------------------------------------------------------------------------------- 1 | {{ data }} -------------------------------------------------------------------------------- /experimental/dash/dash-vanguard-report-master/run.sh: -------------------------------------------------------------------------------- 1 | gunicorn app:server 2 | -------------------------------------------------------------------------------- /experimental/dash/dash-recession-report-demo-master/.gitignore: -------------------------------------------------------------------------------- 1 | vv/* 2 | *.pyc 3 | -------------------------------------------------------------------------------- /docs/img/data.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/data.gif -------------------------------------------------------------------------------- /docs/img/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/demo.gif -------------------------------------------------------------------------------- /docs/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/logo.png -------------------------------------------------------------------------------- /experimental/dash/dash-yield-curve-master/run.sh: -------------------------------------------------------------------------------- 1 | gunicorn app:server --timeout 300 2 | -------------------------------------------------------------------------------- /docs/img/grids.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/grids.gif -------------------------------------------------------------------------------- /docs/img/plot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot1.png -------------------------------------------------------------------------------- /docs/img/plot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot2.png -------------------------------------------------------------------------------- /docs/img/preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/preview.gif -------------------------------------------------------------------------------- /docs/img/publish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/publish.png -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | API 2 | ==== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | api/lantern 8 | -------------------------------------------------------------------------------- /docs/img/plot/area.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot/area.png -------------------------------------------------------------------------------- /docs/img/plot/axis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot/axis.png -------------------------------------------------------------------------------- /docs/img/plot/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot/bar.png -------------------------------------------------------------------------------- /docs/img/plot/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot/grid.png -------------------------------------------------------------------------------- /docs/img/plot/hist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot/hist.png -------------------------------------------------------------------------------- /docs/img/plot/line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot/line.png -------------------------------------------------------------------------------- /docs/img/plot/step.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot/step.png -------------------------------------------------------------------------------- /docs/img/preview2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/preview2.gif -------------------------------------------------------------------------------- /experimental/dash/dash-stock-tickers-demo-app-master/run.sh: -------------------------------------------------------------------------------- 1 | gunicorn app:server --log-file=- 2 | -------------------------------------------------------------------------------- /experimental/dash/dash-vanguard-report-master/.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | *.pyc 3 | .DS_Store 4 | .env 5 | -------------------------------------------------------------------------------- /docs/img/export/email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/export/email.png -------------------------------------------------------------------------------- /docs/img/export/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/export/html.png -------------------------------------------------------------------------------- /docs/img/export/html2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/export/html2.png -------------------------------------------------------------------------------- /docs/img/export/input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/export/input.png -------------------------------------------------------------------------------- /docs/img/export/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/export/pdf.png -------------------------------------------------------------------------------- /docs/img/export/pdf2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/export/pdf2.png -------------------------------------------------------------------------------- /docs/img/plot/labels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot/labels.png -------------------------------------------------------------------------------- /docs/img/plot/legend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot/legend.png -------------------------------------------------------------------------------- /docs/img/plot/plots.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot/plots.gif -------------------------------------------------------------------------------- /docs/img/plot/scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot/scatter.png -------------------------------------------------------------------------------- /docs/img/plot/ticks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/plot/ticks.png -------------------------------------------------------------------------------- /docs/img/export/export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/export/export.png -------------------------------------------------------------------------------- /docs/img/export/sample.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/export/sample.pdf -------------------------------------------------------------------------------- /experimental/dash/dash-recession-report-demo-master/run.sh: -------------------------------------------------------------------------------- 1 | gunicorn report_nyt_255:server --log-file=- 2 | -------------------------------------------------------------------------------- /docs/img/widgets/widgets.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/widgets/widgets.gif -------------------------------------------------------------------------------- /lantern/grids/grid_qgrid.py: -------------------------------------------------------------------------------- 1 | 2 | def qgrid_grid(df): 3 | from qgrid import show_grid 4 | return show_grid(df) 5 | -------------------------------------------------------------------------------- /docs/img/widgets/variableinspector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkpaine/lantern/HEAD/docs/img/widgets/variableinspector.png -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal=1 3 | 4 | [metadata] 5 | description_file = README.md 6 | 7 | [flake8] 8 | max-line-length=200 -------------------------------------------------------------------------------- /lantern/grids/grid_lineup.py: -------------------------------------------------------------------------------- 1 | from lineup_widget import LineUpWidget 2 | 3 | 4 | def lineup_grid(data): 5 | return LineUpWidget(data) 6 | -------------------------------------------------------------------------------- /docs/publish.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Publish 3 | ============== 4 | .. WARNING:: This functionality is deprecated in favor of QuantStack/Voila 5 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | -------------------------------------------------------------------------------- /lantern/grids/grid_psp.py: -------------------------------------------------------------------------------- 1 | from perspective import PerspectiveWidget 2 | 3 | 4 | def psp_grid(data, **kwargs): 5 | return PerspectiveWidget(data=data, **kwargs) 6 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include lantern/extensions/hideinput/templates/ * 2 | recursive-include lantern/extensions/publish/templates/ * 3 | prune tests/ 4 | prune examples/ 5 | include requirements.txt 6 | -------------------------------------------------------------------------------- /tests/test_all.py: -------------------------------------------------------------------------------- 1 | import matplotlib 2 | matplotlib.use('Agg') 3 | 4 | from lantern.data import * 5 | from lantern.extensions import * 6 | from lantern.grids import * 7 | from lantern.plotting import * 8 | -------------------------------------------------------------------------------- /lantern/grids/grid_plotly.py: -------------------------------------------------------------------------------- 1 | from plotly.offline import iplot 2 | import plotly.figure_factory as ff 3 | 4 | 5 | def plotly_grid(data, indexed=True): 6 | return iplot(ff.create_table(data), filename='index_table_pd') 7 | -------------------------------------------------------------------------------- /lantern/grids/grid_phosphor.py: -------------------------------------------------------------------------------- 1 | 2 | def phosphor_grid(data, **kwargs): 3 | from IPython.display import display 4 | bundle = {} 5 | bundle['text/csv'] = data.reset_index().to_csv() 6 | return display(bundle, raw=True) 7 | -------------------------------------------------------------------------------- /docs/table.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Table 3 | ============== 4 | Supported Backends: 5 | 6 | - Perspective 7 | - Plotly 8 | - QGrid 9 | - ipysheet 10 | - lineup_widget 11 | 12 | 13 | Table command 14 | ============= 15 | .. method:: lantern.grid(data, **kwargs) 16 | 17 | 18 | -------------------------------------------------------------------------------- /experimental/flask-highcharts/README.md: -------------------------------------------------------------------------------- 1 | flask-live-charts 2 | ================= 3 | 4 | Live charting demo using flask and highcharts. 5 | 6 | Simply run flask-live-charts.py and point your browser to http://127.0.0.1:5000 7 | 8 | Tested on python 2.7.5 and 2.7.8 with Flask 0.10.1 9 | -------------------------------------------------------------------------------- /lantern/widgets/__init__.py: -------------------------------------------------------------------------------- 1 | from sidecar import Sidecar 2 | from IPython.display import display # noqa: F401 3 | from .variable_inspector import VariableInspector # noqa: F401 4 | 5 | 6 | def sidebar(stuff, title='Sidebar'): 7 | sc = Sidecar(title=title) 8 | with sc: 9 | display(stuff) 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | examples/* linguist-documentation 2 | experimental/* linguist-documentation 3 | experimental/beaker/* linguist-documentation 4 | experimental/widgets/* linguist-documentation 5 | experimental/widgets/applications/* linguist-documentation 6 | docs/* linguist-documentation 7 | tests/notebooks/* linguist-documentation 8 | tests/notebooks/*/* linguist-documentation -------------------------------------------------------------------------------- /docs/widgets.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Widget Tools 3 | ============== 4 | 5 | Sidebar Wrapper 6 | =============== 7 | .. method:: lantern.sidebar() 8 | 9 | 10 | Variable Inspector 11 | =================== 12 | .. method:: lantern.VariableInspector() 13 | 14 | 15 | .. image:: ./img/widgets/variableinspector.png 16 | :scale: 100% 17 | :alt: variableinspector.png 18 | -------------------------------------------------------------------------------- /lantern/__init__.py: -------------------------------------------------------------------------------- 1 | from .plotting import plot, figure 2 | from .data import * # noqa: F401, F403 3 | from .grids import grid # noqa: F401 4 | from .utils import download # noqa: F401 5 | from .extensions import * # noqa: F401, F403 6 | from .widgets import * # noqa: F401, F403 7 | 8 | 9 | __all__ = ['plot', 'figure', 'grids', 'data', 'extensions', 'widgets'] # noqa: F405 10 | __version__ = '0.1.6' 11 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | bokeh>=1.0.2 2 | bs4>=0.0.1 3 | cufflinks>=0.14.4 4 | Faker>=1.0.1 5 | finance-enums>=0.1.0 6 | future>=0.17.1 7 | ipysheet>=0.2.0 8 | ipywidgets>=7.4.2 9 | jupyterlab>=0.35.4 10 | lineup-widget>=1.0.7 11 | matplotlib>=3.0.2 12 | mimesis>=3.0.0 13 | numpy>=1.15.4 14 | pandas>=0.23.4 15 | perspective-python>=0.1.2,<0.4.0 16 | plotly>=4.0.0 17 | qgrid>=1.1.1 18 | scipy>=1.2.0 19 | seaborn>=0.9.0 20 | sidecar>=0.2.0 21 | six>=1.12.0 22 | scikit-learn>=0.21.3 23 | ujson>=1.35 24 | websocket-client>=0.54.0 25 | -------------------------------------------------------------------------------- /lantern/extensions/savehooks/remove_output.py: -------------------------------------------------------------------------------- 1 | def scrub_output_pre_save(model, **kwargs): 2 | """scrub output before saving notebooks""" 3 | # only run on notebooks 4 | if model['type'] != 'notebook': 5 | return 6 | # only run on nbformat v4 7 | if model['content']['nbformat'] != 4: 8 | return 9 | 10 | for cell in model['content']['cells']: 11 | if cell['cell_type'] != 'code': 12 | continue 13 | cell['outputs'] = [] 14 | cell['execution_count'] = None 15 | 16 | # c.FileContentsManager.pre_save_hook = scrub_output_pre_save 17 | -------------------------------------------------------------------------------- /tests/grid/test_grid_psp.py: -------------------------------------------------------------------------------- 1 | 2 | class TestConfig: 3 | def setup(self): 4 | pass 5 | # setup() before each test method 6 | 7 | def teardown(self): 8 | pass 9 | # teardown() after each test method 10 | 11 | @classmethod 12 | def setup_class(cls): 13 | pass 14 | # setup_class() before any methods in this class 15 | 16 | @classmethod 17 | def teardown_class(cls): 18 | pass 19 | # teardown_class() after any methods in this class 20 | 21 | def test_grid(self): 22 | import lantern as l 23 | df = l.bar() 24 | l.grid(df, 'psp') 25 | -------------------------------------------------------------------------------- /tests/grid/test_grid_qgrid.py: -------------------------------------------------------------------------------- 1 | 2 | class TestConfig: 3 | def setup(self): 4 | pass 5 | # setup() before each test method 6 | 7 | def teardown(self): 8 | pass 9 | # teardown() after each test method 10 | 11 | @classmethod 12 | def setup_class(cls): 13 | pass 14 | # setup_class() before any methods in this class 15 | 16 | @classmethod 17 | def teardown_class(cls): 18 | pass 19 | # teardown_class() after any methods in this class 20 | 21 | def test_grid(self): 22 | import lantern as l 23 | df = l.bar() 24 | l.grid(df, 'qgrid') 25 | -------------------------------------------------------------------------------- /tests/grid/test_grid_plotly.py: -------------------------------------------------------------------------------- 1 | 2 | class TestConfig: 3 | def setup(self): 4 | pass 5 | # setup() before each test method 6 | 7 | def teardown(self): 8 | pass 9 | # teardown() after each test method 10 | 11 | @classmethod 12 | def setup_class(cls): 13 | pass 14 | # setup_class() before any methods in this class 15 | 16 | @classmethod 17 | def teardown_class(cls): 18 | pass 19 | # teardown_class() after any methods in this class 20 | 21 | def test_grid(self): 22 | import lantern as l 23 | df = l.bar() 24 | l.grid(df, 'plotly') 25 | -------------------------------------------------------------------------------- /lantern/utils.py: -------------------------------------------------------------------------------- 1 | from IPython import get_ipython 2 | 3 | 4 | class LanternException(Exception): 5 | pass 6 | 7 | 8 | def in_ipynb(): 9 | ip = get_ipython() 10 | if ip: 11 | cfg = ip.config 12 | if cfg.get('IPKernelApp', False): 13 | return True 14 | return False 15 | return False 16 | 17 | 18 | def download(df): 19 | from IPython.display import HTML 20 | import base64 21 | csv = base64.b64encode(df.reset_index().to_csv().encode()).decode() 22 | html = 'Download'.format(payload=csv) 23 | return HTML(html) 24 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = lantern 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /experimental/flask-highcharts/flask-live-chart.py: -------------------------------------------------------------------------------- 1 | import json 2 | from time import time 3 | from random import random 4 | from flask import Flask, render_template, make_response 5 | 6 | app = Flask(__name__) 7 | 8 | 9 | @app.route('/') 10 | def hello_world(): 11 | return render_template('index.html', data='test') 12 | 13 | walk = 1 14 | @app.route('/live-data') 15 | def live_data(): 16 | global walk 17 | neg = -1 if random() > .55 else 1 18 | walk += neg * random() * 10 19 | # Create a PHP array and echo it as JSON 20 | data = [time() * 1000, walk] 21 | response = make_response(json.dumps(data)) 22 | response.content_type = 'application/json' 23 | return response 24 | 25 | if __name__ == '__main__': 26 | app.run(debug=True, host='127.0.0.1', port=5000) 27 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=lantern 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /docs/export.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Export 3 | ============== 4 | This code has moved to [jupyterlab_commands](https://github.com/timkpaine/jupyterlab_commands) 5 | 6 | Lantern provides several export targets, in addition to the ones provided by NBConvert and built in to JupyterLab 7 | 8 | - HTML with input code cells hidden 9 | - PDF with input code cells hidden 10 | - HTML Email with input code cells hidden 11 | 12 | 13 | .. image:: ./img/export/input.png 14 | :scale: 100% 15 | :alt: input.png 16 | 17 | HTML No code 18 | ============= 19 | .. image:: ./img/export/html.png 20 | :scale: 100% 21 | :alt: html.png 22 | 23 | .. image:: ./img/export/html2.png 24 | :scale: 100% 25 | :alt: html2.png 26 | 27 | PDF No code 28 | ============= 29 | .. image:: ./img/export/pdf.png 30 | :scale: 100% 31 | :alt: pdf.png 32 | 33 | .. image:: ./img/export/pdf2.png 34 | :scale: 100% 35 | :alt: pdf2.png 36 | 37 | 38 | HTML Email 39 | ============= 40 | .. WARNING:: This functionality is deprecated in favor of TimKPaine/jupyterlab_email 41 | -------------------------------------------------------------------------------- /lantern/grids/__init__.py: -------------------------------------------------------------------------------- 1 | from .grid_plotly import plotly_grid 2 | from .grid_qgrid import qgrid_grid 3 | from .grid_psp import psp_grid 4 | from .grid_phosphor import phosphor_grid 5 | from .grid_ipysheet import ipysheet_grid 6 | from .grid_lineup import lineup_grid 7 | 8 | 9 | _BACKENDS = ['plotly', 'qgrid', 'psp', 'phosphor', 'ipysheet', 'lineup'] 10 | 11 | 12 | def _backend_to_grid_foo(backend, theme=None): 13 | if backend == 'plotly' or backend == 'cufflinks': 14 | return plotly_grid 15 | if backend == 'qgrid': 16 | return qgrid_grid 17 | if backend == 'psp': 18 | return psp_grid 19 | if backend == 'phosphor': 20 | return phosphor_grid 21 | if backend == 'ipysheet': 22 | return ipysheet_grid 23 | if backend == 'lineup': 24 | return lineup_grid 25 | raise NotImplementedError() 26 | 27 | 28 | def grid(data, backend='psp', **kwargs): 29 | if backend not in _BACKENDS: 30 | raise Exception('Must pick backend in %s' % _BACKENDS) 31 | return _backend_to_grid_foo(backend)(data, **kwargs) 32 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Installation 3 | ============ 4 | 5 | From Pip 6 | ============ 7 | 8 | .. code:: bash 9 | 10 | pip install pylantern 11 | 12 | From Source 13 | ============ 14 | 15 | .. code:: bash 16 | 17 | python setup.py install 18 | 19 | or 20 | 21 | .. code:: bash 22 | 23 | make install 24 | 25 | 26 | Other Requirements 27 | ================== 28 | Lantern relies on a handful of JupyterLab extensions to operate: 29 | 30 | .. code:: bash 31 | 32 | jupyter labextension install @jupyter-widgets/jupyterlab-manager 33 | jupyter labextension install plotlywidget 34 | jupyter labextension install @jupyterlab/plotly-extension 35 | jupyter labextension install jupyterlab_bokeh 36 | jupyter labextension install qgrid 37 | jupyter labextension install @jpmorganchase/perspective-jupyterlab 38 | jupyter labextension install ipysheet 39 | jupyter labextension install lineup_widget 40 | 41 | The following are for work in-progress on master: 42 | 43 | .. code:: bash 44 | 45 | jupyter labextension install bqplot 46 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Status 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | workflow_dispatch: 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | build: 16 | runs-on: ${{ matrix.os }} 17 | 18 | strategy: 19 | matrix: 20 | os: [ubuntu-latest] 21 | python-version: [3.9] 22 | event-name: [push] 23 | 24 | steps: 25 | - uses: actions/checkout@v6 26 | - name: Set up Python ${{ matrix.python-version }} 27 | uses: actions/setup-python@v6 28 | with: 29 | python-version: ${{ matrix.python-version }} 30 | 31 | - name: Install dependencies 32 | run: | 33 | sudo apt-get install graphviz xvfb 34 | python -m pip install -r requirements.txt 35 | python -m pip install -e .[dev] 36 | 37 | - name: Test 38 | run: | 39 | xvfb-run --auto-servernum make tests 40 | if: ${{ matrix.os == 'ubuntu-latest' }} 41 | 42 | - name: Upload coverage 43 | uses: codecov/codecov-action@v5 44 | -------------------------------------------------------------------------------- /lantern/extensions/savehooks/convert_to_script.py: -------------------------------------------------------------------------------- 1 | import io 2 | import os 3 | from notebook.utils import to_api_path 4 | 5 | _script_exporter = None 6 | 7 | 8 | def script_post_save(model, os_path, contents_manager, **kwargs): 9 | """convert notebooks to Python script after save with nbconvert 10 | 11 | replaces `ipython notebook --script` 12 | """ 13 | from nbconvert.exporters.script import ScriptExporter 14 | 15 | if model['type'] != 'notebook': 16 | return 17 | 18 | global _script_exporter 19 | 20 | if _script_exporter is None: 21 | _script_exporter = ScriptExporter(parent=contents_manager) 22 | 23 | log = contents_manager.log 24 | 25 | base, ext = os.path.splitext(os_path) 26 | # py_fname = base + '.py' 27 | script, resources = _script_exporter.from_filename(os_path) 28 | script_fname = base + resources.get('output_extension', '.txt') 29 | log.info("Saving script /%s", to_api_path(script_fname, contents_manager.root_dir)) 30 | 31 | with io.open(script_fname, 'w', encoding='utf-8') as f: 32 | f.write(script) 33 | 34 | # c.FileContentsManager.post_save_hook = script_post_save 35 | -------------------------------------------------------------------------------- /lantern/grids/grid_ipysheet.py: -------------------------------------------------------------------------------- 1 | import ipysheet 2 | import pandas as pd 3 | 4 | 5 | def ipysheet_grid(data, indexed=True): 6 | if isinstance(data, list): 7 | data = pd.DataFrame(data) 8 | drop_index = False 9 | elif isinstance(data, dict): 10 | data = pd.DataFrame(data) 11 | drop_index = False 12 | else: 13 | drop_index = True 14 | 15 | if isinstance(data, pd.DataFrame): 16 | if 'index' not in data.columns and drop_index: 17 | data = data.reset_index() 18 | for x in data.dtypes.iteritems(): 19 | if 'date' in str(x[1]): 20 | data[x[0]] = data[x[0]].astype(str) 21 | elif isinstance(data, pd.Series): 22 | data = data.reset_index() 23 | for x in data.dtypes.iteritems(): 24 | if 'date' in str(x[1]): 25 | data[x[0]] = data[x[0]].astype(str) 26 | else: 27 | raise NotImplementedError() 28 | 29 | sheet = ipysheet.sheet(rows=len(data), columns=len(data.columns), column_headers=data.columns.astype(str).tolist()) 30 | for i, col in enumerate(data.columns): 31 | ipysheet.column(i, data[col].values.tolist()) 32 | return sheet 33 | -------------------------------------------------------------------------------- /tests/test_utils.py: -------------------------------------------------------------------------------- 1 | from mock import patch, MagicMock 2 | 3 | 4 | class TestConfig: 5 | def setup(self): 6 | pass 7 | # setup() before each test method 8 | 9 | def teardown(self): 10 | pass 11 | # teardown() after each test method 12 | 13 | @classmethod 14 | def setup_class(cls): 15 | pass 16 | # setup_class() before any methods in this class 17 | 18 | @classmethod 19 | def teardown_class(cls): 20 | pass 21 | # teardown_class() after any methods in this class 22 | 23 | def test_ip1(self): 24 | with patch('lantern.utils.get_ipython') as m: 25 | m.return_value = None 26 | from lantern.utils import in_ipynb 27 | assert in_ipynb() == False 28 | 29 | def test_ip2(self): 30 | 31 | with patch('lantern.utils.get_ipython') as m: 32 | m.return_value = MagicMock() 33 | from lantern.utils import in_ipynb 34 | m.return_value.config = {'IPKernelApp': False} 35 | assert in_ipynb() == False 36 | 37 | def test_ip3(self): 38 | 39 | with patch('lantern.utils.get_ipython') as m: 40 | m.return_value = MagicMock() 41 | m.return_value.config = {'IPKernelApp': True} 42 | 43 | from lantern.utils import in_ipynb 44 | assert in_ipynb() == True 45 | -------------------------------------------------------------------------------- /tests/plot/test_plot.py: -------------------------------------------------------------------------------- 1 | from mock import patch 2 | 3 | import matplotlib 4 | matplotlib.use('Agg') 5 | 6 | 7 | class TestConfig: 8 | def setup(self): 9 | pass 10 | # setup() before each test method 11 | 12 | def teardown(self): 13 | pass 14 | # teardown() after each test method 15 | 16 | @classmethod 17 | def setup_class(cls): 18 | pass 19 | # setup_class() before any methods in this class 20 | 21 | @classmethod 22 | def teardown_class(cls): 23 | pass 24 | # teardown_class() after any methods in this class 25 | 26 | def test_all(self): 27 | with patch('lantern.plotting.plot_matplotlib.in_ipynb', create=True) as mock1: 28 | import lantern as l 29 | mock1.return_value = True 30 | df = l.bar() 31 | l.plot(df, 'line', 'matplotlib') 32 | 33 | def test_list(self): 34 | with patch('lantern.plotting.plot_matplotlib.in_ipynb', create=True) as mock1: 35 | import lantern as l 36 | mock1.return_value = True 37 | df = l.bar() 38 | l.plot(df, ['line' for _ in df], 'matplotlib') 39 | 40 | def test_dict(self): 41 | with patch('lantern.plotting.plot_matplotlib.in_ipynb', create=True) as mock1: 42 | import lantern as l 43 | mock1.return_value = True 44 | df = l.bar() 45 | l.plot(df, {c: 'line' for c in df.columns}, 'matplotlib') 46 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | from codecs import open 3 | from os import path 4 | 5 | here = path.abspath(path.dirname(__file__)) 6 | 7 | with open(path.join(here, 'README.md'), encoding='utf-8') as f: 8 | long_description = f.read() 9 | 10 | with open(path.join(here, 'requirements.txt'), encoding='utf-8') as f: 11 | requires = f.read().split() 12 | 13 | setup( 14 | name='pylantern', 15 | version='0.1.6', 16 | description='Analytics library', 17 | long_description=long_description, 18 | url='https://github.com/timkpaine/lantern', 19 | download_url='https://github.com/timkpaine/lantern/archive/v0.1.5.tar.gz', 20 | author='Tim Paine', 21 | author_email='t.paine154@gmail.com', 22 | license='Apache 2.0', 23 | install_requires=requires, 24 | extras_require={'dev': requires + ['pytest', 'pytest-cov', 'pylint', 'flake8', 'mock', 'codecov', 'autopep8']}, 25 | 26 | classifiers=[ 27 | 'Development Status :: 3 - Alpha', 28 | 'Programming Language :: Python :: 3', 29 | 'Programming Language :: Python :: 3.6', 30 | 'Programming Language :: Python :: 3.7', 31 | 'Programming Language :: Python :: 3.8', 32 | ], 33 | 34 | keywords='analytics tools plotting', 35 | 36 | packages=find_packages(exclude=['tests', ]), 37 | package_data={'lantern': ['lantern/extensions/hideinput/templates/*', 38 | 'lantern/extensions/publish/templates/*']}, 39 | include_package_data=True, 40 | zip_safe=False, 41 | ) 42 | -------------------------------------------------------------------------------- /lantern/plotting/plotobj.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod, ABCMeta 2 | from future.utils import with_metaclass 3 | 4 | 5 | class BasePlot(with_metaclass(ABCMeta)): 6 | def __init__(self, backend): 7 | pass 8 | 9 | @abstractmethod 10 | def show(self, title='', xlabel='', ylabel='', xaxis=True, yaxis=True, xticks=True, yticks=True, legend=True, grid=True, **kwargs): 11 | pass 12 | 13 | @abstractmethod 14 | def area(self, data, color=None, y_axis='left', stacked=False, **kwargs): 15 | pass 16 | 17 | @abstractmethod 18 | def bar(self, data, color=None, y_axis='left', stacked=False, **kwargs): 19 | pass 20 | 21 | @abstractmethod 22 | def hist(self, data, color=None, y_axis='left', stacked=False, **kwargs): 23 | pass 24 | 25 | @abstractmethod 26 | def hline(self, y, color=None, **kwargs): 27 | pass 28 | 29 | @abstractmethod 30 | def hspan(self, yhigh, ylow, color=None, **kwargs): 31 | pass 32 | 33 | @abstractmethod 34 | def line(self, data, color=None, y_axis='left', **kwargs): 35 | pass 36 | 37 | @abstractmethod 38 | def scatter(self, data, color=None, x=None, y=None, y_axis='left', **kwargs): 39 | pass 40 | 41 | @abstractmethod 42 | def step(self, data, color=None, y_axis='left', **kwargs): 43 | pass 44 | 45 | @abstractmethod 46 | def vline(self, x, color=None, **kwargs): 47 | pass 48 | 49 | @abstractmethod 50 | def vspan(self, xhigh, xlow, color=None, **kwargs): 51 | pass 52 | -------------------------------------------------------------------------------- /experimental/flask-highcharts/static/js/highcharts.js: -------------------------------------------------------------------------------- 1 | var chart; 2 | 3 | /** 4 | * Request data from the server, add it to the graph and set a timeout 5 | * to request again 6 | */ 7 | function requestData() { 8 | $.ajax({ 9 | url: '/live-data', 10 | success: function(point) { 11 | var series = chart.series[0], 12 | shift = series.data.length > 200; // shift if the series is 13 | // longer than 20 14 | 15 | // add the point 16 | chart.series[0].addPoint(point, true, shift); 17 | 18 | // call it again after one second 19 | setTimeout(requestData, 250); 20 | }, 21 | cache: false 22 | }); 23 | } 24 | 25 | $(document).ready(function() { 26 | chart = new Highcharts.Chart({ 27 | chart: { 28 | renderTo: 'data-container', 29 | defaultSeriesType: 'line', 30 | events: { 31 | load: requestData 32 | } 33 | }, 34 | title: { 35 | text: 'Live random data' 36 | }, 37 | xAxis: { 38 | type: 'datetime', 39 | tickPixelInterval: 150, 40 | maxZoom: 20 * 1000 41 | }, 42 | yAxis: { 43 | minPadding: 0.2, 44 | maxPadding: 0.2, 45 | title: { 46 | text: 'Value', 47 | margin: 80 48 | } 49 | }, 50 | series: [{ 51 | name: 'Random data', 52 | data: [] 53 | }] 54 | }); 55 | }); -------------------------------------------------------------------------------- /tests/data/test_all.py: -------------------------------------------------------------------------------- 1 | 2 | class TestConfig: 3 | def setup(self): 4 | pass 5 | # setup() before each test method 6 | 7 | def teardown(self): 8 | pass 9 | # teardown() after each test method 10 | 11 | @classmethod 12 | def setup_class(cls): 13 | pass 14 | # setup_class() before any methods in this class 15 | 16 | @classmethod 17 | def teardown_class(cls): 18 | pass 19 | # teardown_class() after any methods in this class 20 | 21 | def test_area(self): 22 | import lantern as l 23 | l.area() 24 | 25 | def test_bar(self): 26 | import lantern as l 27 | l.bar() 28 | 29 | def test_box(self): 30 | import lantern as l 31 | l.box() 32 | 33 | def test_bubble(self): 34 | import lantern as l 35 | l.bubble() 36 | 37 | def test_heatmap(self): 38 | import lantern as l 39 | l.heatmap() 40 | 41 | def test_histogram(self): 42 | import lantern as l 43 | l.histogram() 44 | 45 | def test_line(self): 46 | import lantern as l 47 | l.line() 48 | 49 | def test_ohlc(self): 50 | import lantern as l 51 | l.ohlc() 52 | 53 | def test_ohlcv(self): 54 | import lantern as l 55 | l.ohlcv() 56 | 57 | def test_pie(self): 58 | import lantern as l 59 | l.pie() 60 | 61 | def test_scatter(self): 62 | import lantern as l 63 | l.scatter() 64 | 65 | def test_timeseries(self): 66 | import lantern as l 67 | l.timeseries() 68 | -------------------------------------------------------------------------------- /lantern/plotting/plot_altair.py: -------------------------------------------------------------------------------- 1 | # import altair as alt 2 | from .plotobj import BasePlot 3 | # from .plotutils import get_color 4 | 5 | 6 | class AltairPlot(BasePlot): 7 | def __init__(self, size=None, theme=None): 8 | self.size = size or (700, 400) 9 | self._charts = [] 10 | 11 | def show(self, title='', xlabel='', ylabel='', xaxis=True, yaxis=True, xticks=True, yticks=True, legend=True, grid=True, **kwargs): 12 | # require all data to be present before plotting 13 | return 14 | 15 | def area(self, data, color=None, y_axis='left', stacked=False, **kwargs): 16 | raise NotImplementedError() 17 | 18 | def bar(self, data, color=None, y_axis='left', stacked=False, **kwargs): 19 | raise NotImplementedError() 20 | 21 | def hist(self, data, color=None, y_axis='left', stacked=False, **kwargs): 22 | raise NotImplementedError() 23 | 24 | def hline(self, y, color=None, **kwargs): 25 | raise NotImplementedError() 26 | 27 | def hspan(self, yhigh, ylow, color=None, **kwargs): 28 | raise NotImplementedError() 29 | 30 | def line(self, data, color=None, y_axis='left', **kwargs): 31 | raise NotImplementedError() 32 | 33 | def scatter(self, data, color=None, x=None, y=None, y_axis='left', **kwargs): 34 | raise NotImplementedError() 35 | 36 | def step(self, data, color=None, y_axis='left', **kwargs): 37 | raise NotImplementedError() 38 | 39 | def vline(self, x, color=None, **kwargs): 40 | raise NotImplementedError() 41 | 42 | def vspan(self, xhigh, xlow, color=None, **kwargs): 43 | raise NotImplementedError() 44 | -------------------------------------------------------------------------------- /experimental/dash/dash-stock-tickers-demo-app-master/.gitignore: -------------------------------------------------------------------------------- 1 | vv/ 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | env/ 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # Jupyter Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # SageMath parsed files 81 | *.sage.py 82 | 83 | # dotenv 84 | .env 85 | 86 | # virtualenv 87 | .venv 88 | venv/ 89 | ENV/ 90 | 91 | # Spyder project settings 92 | .spyderproject 93 | .spyproject 94 | 95 | # Rope project settings 96 | .ropeproject 97 | 98 | # mkdocs documentation 99 | /site 100 | 101 | # mypy 102 | .mypy_cache/ 103 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for your interest in contributing to lantern! 4 | 5 | ## Reporting bugs, feature requests, etc. 6 | 7 | To report bugs, request new features or similar, please open an issue on the Github 8 | repository. 9 | 10 | A good bug report includes: 11 | 12 | - Expected behavior 13 | - Actual behavior 14 | - Steps to reproduce (preferably as minimal as possible) 15 | 16 | ## Minor changes, typos etc. 17 | 18 | Minor changes can be contributed by navigating to the relevant files on the Github repository, 19 | and clicking the "edit file" icon. By following the instructions on the page you should be able to 20 | create a pull-request proposing your changes. A repository maintainer will then review your changes, 21 | and either merge them, propose some modifications to your changes, or reject them (with a reason for 22 | the rejection). 23 | 24 | ## Setting up a development environment 25 | 26 | If you want to help resolve an issue by making some changes that are larger than that covered by the above paragraph, it is recommended that you: 27 | 28 | - Fork the repository on Github 29 | - Clone your fork to your computer 30 | - Run the following commands inside the cloned repository: 31 | - `pip install -e .[dev]` - This will install the Python package in development 32 | mode. 33 | - Validate the install by running the tests: 34 | - `py.test` - This command will run the Python tests. 35 | - `flake8 lantern` - This command will run the Python linters. 36 | 37 | Once you have such a development setup, you should: 38 | 39 | - Make the changes you consider necessary 40 | - Run the tests to ensure that your changes does not break anything 41 | - If you add new code, preferably write one or more tests for checking that your code works as expected. 42 | - Commit your changes and publish the branch to your github repo. 43 | - Open a pull-request (PR) back to the main repo on Github. 44 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | run: ## clean and make target, run target 2 | python3 -m lantern 3 | 4 | build: ## Build the repository 5 | python3 setup.py build 6 | 7 | testpy: ## Clean and Make unit tests 8 | python3 -m pytest -v tests --cov=lantern 9 | 10 | test: lint ## run the tests for travis CI 11 | @ python3 -m pytest -v tests --cov=lantern 12 | 13 | lint: ## run linter 14 | flake8 lantern 15 | 16 | fix: ## run autopep8/tslint fix 17 | autopep8 --in-place -r -a -a lantern/ 18 | 19 | annotate: ## MyPy type annotation check 20 | mypy -s lantern 21 | 22 | annotate_l: ## MyPy type annotation check - count only 23 | mypy -s lantern | wc -l 24 | 25 | clean: ## clean the repository 26 | find . -name "__pycache__" | xargs rm -rf 27 | find . -name "*.pyc" | xargs rm -rf 28 | find . -name ".ipynb_checkpoints" | xargs rm -rf 29 | rm -rf .coverage cover htmlcov logs build dist *.egg-info 30 | make -C ./docs clean 31 | 32 | install: ## install to site-packages 33 | pip3 install . 34 | 35 | preinstall: ## install dependencies 36 | python3 -m pip install -r requirements.txt 37 | 38 | postinstall: ## install other requisite labextensions 39 | jupyter labextension install @jupyter-widgets/jupyterlab-manager 40 | jupyter labextension install @jupyterlab/plotly-extension 41 | jupyter labextension install @finos/perspective-jupyterlab 42 | jupyter labextension install jupyterlab_bokeh 43 | jupyter labextension install bqplot 44 | jupyter labextension install qgrid 45 | 46 | docs: ## make documentation 47 | make -C ./docs html 48 | open ./docs/_build/html/index.html 49 | 50 | dist: ## dist to pypi 51 | rm -rf dist build 52 | python3 setup.py sdist 53 | python3 setup.py bdist_wheel 54 | twine check dist/* && twine upload dist/* 55 | 56 | # Thanks to Francoise at marmelab.com for this 57 | .DEFAULT_GOAL := help 58 | help: 59 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 60 | 61 | print-%: 62 | @echo '$*=$($*)' 63 | 64 | .PHONY: clean build run test tests help annotate annotate_l docs dist 65 | -------------------------------------------------------------------------------- /tests/plot/test_plot_matplotlib.py: -------------------------------------------------------------------------------- 1 | from mock import patch 2 | 3 | import matplotlib 4 | matplotlib.use('Agg') 5 | 6 | 7 | class TestConfig: 8 | def setup(self): 9 | pass 10 | # setup() before each test method 11 | 12 | def teardown(self): 13 | pass 14 | # teardown() after each test method 15 | 16 | @classmethod 17 | def setup_class(cls): 18 | pass 19 | # setup_class() before any methods in this class 20 | 21 | @classmethod 22 | def teardown_class(cls): 23 | pass 24 | # teardown_class() after any methods in this class 25 | 26 | def test_area(self): 27 | with patch('lantern.plotting.plot_matplotlib.in_ipynb', create=True) as mock1: 28 | import lantern as l 29 | mock1.return_value = True 30 | p = l.figure('matplotlib') 31 | df = l.bar() 32 | p.area(df) 33 | p.show() 34 | 35 | def test_bar(self): 36 | with patch('lantern.plotting.plot_matplotlib.in_ipynb', create=True) as mock1: 37 | import lantern as l 38 | mock1.return_value = True 39 | p = l.figure('matplotlib') 40 | df = l.bar() 41 | p.bar(df) 42 | p.show() 43 | 44 | def test_line(self): 45 | with patch('lantern.plotting.plot_matplotlib.in_ipynb', create=True) as mock1: 46 | import lantern as l 47 | mock1.return_value = True 48 | p = l.figure('matplotlib') 49 | df = l.bar() 50 | p.line(df) 51 | p.show() 52 | 53 | def test_scatter(self): 54 | with patch('lantern.plotting.plot_matplotlib.in_ipynb', create=True) as mock1: 55 | import lantern as l 56 | mock1.return_value = True 57 | p = l.figure('matplotlib') 58 | df = l.bar() 59 | p.scatter(df) 60 | p.show() 61 | 62 | def test_step(self): 63 | with patch('lantern.plotting.plot_matplotlib.in_ipynb', create=True) as mock1: 64 | import lantern as l 65 | mock1.return_value = True 66 | p = l.figure('matplotlib') 67 | df = l.bar() 68 | p.step(df) 69 | p.show() 70 | -------------------------------------------------------------------------------- /lantern/plotting/plot_nvd3.py: -------------------------------------------------------------------------------- 1 | from nvd3 import lineChart 2 | from nvd3.ipynb import initialize_javascript 3 | from IPython.display import display 4 | from .plotobj import BasePlot 5 | from .plotutils import get_color 6 | 7 | _INITED = False 8 | 9 | 10 | class NVD3Plot(BasePlot): 11 | def __init__(self, size=None, theme=None): 12 | global _INITED 13 | if not _INITED: 14 | initialize_javascript() 15 | _INITED = True 16 | 17 | self.size = size or (700, 400) 18 | self._lines = lineChart(name='lineChart', x_is_date=True, x_axis_format='%Y-%m-%d', height=self.size[1], width=self.size[0]) 19 | 20 | def show(self, title='', xlabel='', ylabel='', xaxis=True, yaxis=True, xticks=True, yticks=True, legend=True, grid=True, **kwargs): 21 | # require all data to be present before plotting 22 | display(self._lines) 23 | 24 | def area(self, data, color=None, y_axis='left', stacked=False, **kwargs): 25 | raise NotImplementedError() 26 | 27 | def bar(self, data, color=None, y_axis='left', stacked=False, **kwargs): 28 | raise NotImplementedError() 29 | 30 | def hist(self, data, color=None, y_axis='left', stacked=False, **kwargs): 31 | raise NotImplementedError() 32 | 33 | def hline(self, y, color=None, **kwargs): 34 | raise NotImplementedError() 35 | 36 | def hspan(self, yhigh, ylow, color=None, **kwargs): 37 | raise NotImplementedError() 38 | 39 | def line(self, data, color=None, y_axis='left', **kwargs): 40 | for i, col in enumerate(data): 41 | _color = get_color(i, col, color) 42 | y = data[col].astype(float).tolist() 43 | x = data.index.astype(str).tolist() 44 | self._lines.add_serie(y=y, 45 | x=x, 46 | color=_color, 47 | name=col, 48 | extra={"tooltip": {"y_start": "Test ", "y_end": " test"}}) 49 | 50 | def scatter(self, data, color=None, x=None, y=None, y_axis='left', **kwargs): 51 | raise NotImplementedError() 52 | 53 | def step(self, data, color=None, y_axis='left', **kwargs): 54 | raise NotImplementedError() 55 | 56 | def vline(self, x, color=None, **kwargs): 57 | raise NotImplementedError() 58 | 59 | def vspan(self, xhigh, xlow, color=None, **kwargs): 60 | raise NotImplementedError() 61 | -------------------------------------------------------------------------------- /tests/plot/test_plot_plotly.py: -------------------------------------------------------------------------------- 1 | from mock import patch 2 | 3 | 4 | class TestConfig: 5 | def setup(self): 6 | pass 7 | # setup() before each test method 8 | 9 | def teardown(self): 10 | pass 11 | # teardown() after each test method 12 | 13 | @classmethod 14 | def setup_class(cls): 15 | pass 16 | # setup_class() before any methods in this class 17 | 18 | @classmethod 19 | def teardown_class(cls): 20 | pass 21 | # teardown_class() after any methods in this class 22 | 23 | def test_area(self): 24 | with patch('lantern.plotting.plot_plotly.in_ipynb', create=True) as mock1: 25 | import cufflinks 26 | cufflinks.go_offline() 27 | import lantern as l 28 | mock1.return_value = True 29 | p = l.figure('cufflinks') 30 | df = l.bar() 31 | p.area(df) 32 | p.show() 33 | 34 | def test_bar(self): 35 | with patch('lantern.plotting.plot_plotly.in_ipynb', create=True) as mock1: 36 | import cufflinks 37 | cufflinks.go_offline() 38 | import lantern as l 39 | mock1.return_value = True 40 | p = l.figure('cufflinks') 41 | df = l.bar() 42 | p.bar(df) 43 | p.show() 44 | 45 | def test_line(self): 46 | with patch('lantern.plotting.plot_plotly.in_ipynb', create=True) as mock1: 47 | import cufflinks 48 | cufflinks.go_offline() 49 | import lantern as l 50 | mock1.return_value = True 51 | p = l.figure('cufflinks') 52 | df = l.bar() 53 | p.line(df) 54 | p.show() 55 | 56 | def test_scatter(self): 57 | with patch('lantern.plotting.plot_plotly.in_ipynb', create=True) as mock1: 58 | import cufflinks 59 | cufflinks.go_offline() 60 | import lantern as l 61 | mock1.return_value = True 62 | p = l.figure('cufflinks') 63 | df = l.bar() 64 | p.scatter(df) 65 | p.show() 66 | 67 | def test_step(self): 68 | with patch('lantern.plotting.plot_plotly.in_ipynb', create=True) as mock1: 69 | import cufflinks 70 | cufflinks.go_offline() 71 | import lantern as l 72 | mock1.return_value = True 73 | p = l.figure('cufflinks') 74 | df = l.bar() 75 | p.step(df) 76 | p.show() 77 | -------------------------------------------------------------------------------- /docs/quickstart.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Getting started 3 | =============== 4 | .. WARNING:: Lantern is under active beta development, so interfaces and functionality may change 5 | 6 | Overview 7 | =============== 8 | Lantern provides a number of utility facilities for working in Jupyter notebooks. These include: 9 | 10 | - quick and easy plotting, across several popular plotting libraries 11 | - quick and easy tables, across several popular table libraries 12 | - utilities for working with live data 13 | - easy export (including code-less) for reports 14 | - publishing read-only dashboards from notebooks 15 | - sample datasets 16 | 17 | 18 | Plotting libraries 19 | =================== 20 | Lantern utilizes the following plotting libraries: 21 | 22 | - `Matplotlib `_ / `Seaborn `_ 23 | - `Plotly `_ / `Cufflinks `_ 24 | - `Bokeh `_ 25 | 26 | 27 | Table Libraries 28 | ================ 29 | Lantern utilizes the following table libraries: 30 | 31 | - `Qgrid `_ 32 | - `Plotly `_ 33 | 34 | 35 | Live Data 36 | ========== 37 | .. WARNING:: This functionality is deprecated in favor of TimKPaine/tributary 38 | 39 | 40 | Export 41 | ======= 42 | JupyterLab uses `NBconvert `_ provides the ability to export to PDF, HTML, LaTeX, ReStructured Text, Markdown, Executable Script, and Reveal JS Slideshow. On top of this, lantern provides the ability to export to: 43 | 44 | - PDF with no code 45 | - HTML with no code 46 | 47 | .. WARNING:: Some functionality is deprecated in favor of TimKPaine/jupyterlab_email 48 | 49 | Publish 50 | ======== 51 | Lantern provides a read-only view on your notebook, for quick-and-dirty web based reports. 52 | .. WARNING:: This functionality is deprecated in favor of QuantStack/Voila 53 | 54 | 55 | Sample Datasets 56 | ================ 57 | Lantern utilizes `Cufflinks `_ and `scikit learn `_ to provide a variety of sample datasets: 58 | 59 | - Lines 60 | - Scatter 61 | - Bubble 62 | - Pie 63 | - Bars 64 | - Open, high, low, close, volume 65 | - Box 66 | - Histogram 67 | - Surface 68 | - Sinwave 69 | - Regression 70 | - Blobs 71 | - Classification 72 | - Multilabel classification 73 | - Gaussian 74 | - Hasti 75 | - Circles 76 | - Moons 77 | - Biclusters 78 | - S Curve 79 | - Checker 80 | 81 | and more. 82 | -------------------------------------------------------------------------------- /examples/perspective.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 18, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "%%capture\n", 10 | "import lantern as l\n", 11 | "df = l.line.sample()" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 19, 17 | "metadata": {}, 18 | "outputs": [ 19 | { 20 | "data": { 21 | "application/vnd.jupyter.widget-view+json": { 22 | "model_id": "23bac7ade5c641cea145a909cae43fa6", 23 | "version_major": 2, 24 | "version_minor": 0 25 | }, 26 | "text/plain": [ 27 | "PerspectiveWidget(columns=['DIY.WW'], datasrc='static', schema={'index': 'date', 'DIY.WW': 'float', 'FBH.KW': …" 28 | ] 29 | }, 30 | "metadata": {}, 31 | "output_type": "display_data" 32 | } 33 | ], 34 | "source": [ 35 | "l.grid(df, columns=[df.columns[0]])" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 20, 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "data": { 45 | "application/vnd.jupyter.widget-view+json": { 46 | "model_id": "cd3b477310f54bc0bf6fd7509b84f7a3", 47 | "version_major": 2, 48 | "version_minor": 0 49 | }, 50 | "text/plain": [ 51 | "PerspectiveWidget(aggregates={'index': 'last', 'x': 'sum', 'categories': 'last'}, columnpivots=['categories'],…" 52 | ] 53 | }, 54 | "metadata": {}, 55 | "output_type": "display_data" 56 | } 57 | ], 58 | "source": [ 59 | "df = l.scatter.sample()\n", 60 | "\n", 61 | "from perspective import PerspectiveWidget\n", 62 | "p = PerspectiveWidget(df, view='xy_scatter', columns=['index', df.columns[0], 'categories'], rowpivots=['index'], columnpivots=['categories'], aggregates={'index': 'last', df.columns[0]: 'sum', 'categories': 'last' })\n", 63 | "p" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": null, 69 | "metadata": {}, 70 | "outputs": [], 71 | "source": [] 72 | } 73 | ], 74 | "metadata": { 75 | "kernelspec": { 76 | "display_name": "Python 3", 77 | "language": "python", 78 | "name": "python3" 79 | }, 80 | "language_info": { 81 | "codemirror_mode": { 82 | "name": "ipython", 83 | "version": 3 84 | }, 85 | "file_extension": ".py", 86 | "mimetype": "text/x-python", 87 | "name": "python", 88 | "nbconvert_exporter": "python", 89 | "pygments_lexer": "ipython3", 90 | "version": "3.7.0" 91 | } 92 | }, 93 | "nbformat": 4, 94 | "nbformat_minor": 2 95 | } 96 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. lantern documentation master file, created by 2 | sphinx-quickstart on Fri Jan 12 22:07:11 2018. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | lantern 7 | =================================== 8 | An orchestration layer for plots and tables, dummy datasets, research, reports, and anything else a data scientist might need. 9 | 10 | |build-status| |issues| |codecov| |gitter| |bch| |pypiv| |pypil| |docs| 11 | 12 | Data 13 | ---- 14 | .. image:: ./img/data.gif 15 | :scale: 100% 16 | :alt: demo.gif 17 | 18 | 19 | Plots 20 | ----- 21 | .. image:: ./img/plot/plots.gif 22 | :scale: 100% 23 | :alt: plots.gif 24 | 25 | 26 | Grids 27 | ------ 28 | .. image:: ./img/grids.gif 29 | :scale: 100% 30 | :alt: grids.gif 31 | 32 | Widgets 33 | -------- 34 | .. image:: ./img/widgets/widgets.gif 35 | :scale: 100% 36 | :alt: widgets.gif 37 | 38 | 39 | .. toctree:: 40 | :maxdepth: 2 41 | :caption: Contents: 42 | 43 | installation 44 | quickstart 45 | data 46 | plot 47 | table 48 | export 49 | widgets 50 | publish 51 | api 52 | 53 | 54 | .. |build-status| image:: https://travis-ci.org/timkpaine/lantern.svg?branch=master 55 | :alt: Build Status 56 | :scale: 100% 57 | :target: https://travis-ci.org/timkpaine/lantern 58 | 59 | .. |issues| image:: https://img.shields.io/github/issues/timkpaine/lantern.svg 60 | :alt: Issues 61 | :scale: 100% 62 | :target: https://img.shields.io/github/issues/timkpaine/lantern.svg 63 | 64 | .. |codecov| image:: https://codecov.io/gh/timkpaine/lantern/branch/master/graph/badge.svg 65 | :alt: Codecov 66 | :scale: 100% 67 | :target: https://codecov.io/gh/timkpaine/lantern 68 | 69 | .. |gitter| image:: https://img.shields.io/gitter/room/nwjs/nw.js.svg 70 | :alt: Gitter 71 | :scale: 100% 72 | :target: https://gitter.im/pylantern/Lobby 73 | 74 | .. |bch| image:: https://bettercodehub.com/edge/badge/timkpaine/lantern?branch=master 75 | :alt: BCH 76 | :scale: 100% 77 | :target: https://bettercodehub.com/ 78 | 79 | .. |pypiv| image:: https://img.shields.io/pypi/v/pylantern.svg 80 | :alt: Version 81 | :scale: 100% 82 | :target: https://pypi.python.org/pypi/pylantern 83 | 84 | .. |pypil| image:: https://img.shields.io/pypi/l/pylantern.svg 85 | :alt: License 86 | :scale: 100% 87 | :target: https://pypi.python.org/pypi/pylantern 88 | 89 | .. |docs| image:: https://img.shields.io/readthedocs/pylantern.svg 90 | :alt: Docs 91 | :scale: 100% 92 | :target: http://pylantern.readthedocs.io/en/latest/ 93 | -------------------------------------------------------------------------------- /tests/plot/test_plot_bokeh.py: -------------------------------------------------------------------------------- 1 | from mock import patch 2 | 3 | 4 | class TestConfig: 5 | def setup(self): 6 | pass 7 | # setup() before each test method 8 | 9 | def teardown(self): 10 | pass 11 | # teardown() after each test method 12 | 13 | @classmethod 14 | def setup_class(cls): 15 | pass 16 | # setup_class() before any methods in this class 17 | 18 | @classmethod 19 | def teardown_class(cls): 20 | pass 21 | # teardown_class() after any methods in this class 22 | 23 | def test_area(self): 24 | with patch('lantern.plotting.plot_bokeh.in_ipynb', create=True) as mock1: 25 | from bokeh.plotting import output_notebook 26 | output_notebook() 27 | 28 | import lantern as l 29 | mock1.return_value = True 30 | p = l.figure('bokeh') 31 | df = l.bar() 32 | p.area(df) 33 | p.show() 34 | 35 | def test_bar(self): 36 | with patch('lantern.plotting.plot_bokeh.in_ipynb', create=True) as mock1: 37 | from bokeh.plotting import output_notebook 38 | output_notebook() 39 | 40 | import lantern as l 41 | mock1.return_value = True 42 | p = l.figure('bokeh') 43 | df = l.bar() 44 | p.bar(df) 45 | p.show() 46 | 47 | def test_line(self): 48 | with patch('lantern.plotting.plot_bokeh.in_ipynb', create=True) as mock1: 49 | from bokeh.plotting import output_notebook 50 | output_notebook() 51 | 52 | import lantern as l 53 | mock1.return_value = True 54 | p = l.figure('bokeh') 55 | df = l.bar() 56 | p.line(df) 57 | p.show() 58 | 59 | def test_scatter(self): 60 | with patch('lantern.plotting.plot_bokeh.in_ipynb', create=True) as mock1: 61 | from bokeh.plotting import output_notebook 62 | output_notebook() 63 | 64 | import lantern as l 65 | mock1.return_value = True 66 | p = l.figure('bokeh') 67 | df = l.bar() 68 | p.scatter(df) 69 | p.show() 70 | 71 | # def test_step(self): 72 | # with patch('lantern.plotting.plot_bokeh.in_ipynb', create=True) as mock1: 73 | # from bokeh.plotting import output_notebook 74 | # output_notebook() 75 | 76 | # import lantern as l 77 | # mock1.return_value = True 78 | # p = l.figure('bokeh') 79 | # df = l.bar() 80 | # p.step(df) 81 | # p.show() 82 | -------------------------------------------------------------------------------- /experimental/flask-highcharts/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Flask Highcharts Live Data Demo 8 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | 33 | 34 | 35 |
36 |
37 |
38 |

Live data plotting using Flask and Highcharts.

39 |
40 |
41 | 42 |
43 | 44 |
45 | 46 |
47 | 48 |
49 |
50 |
51 | 52 |
53 |

© Tom Diethe 2014

54 |
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /lantern/plotting/plot_bqplot.py: -------------------------------------------------------------------------------- 1 | # import bqplot.pyplot as plt 2 | from IPython.display import display 3 | from ipywidgets import VBox 4 | from bqplot.axes import Axis 5 | from bqplot.scales import LinearScale 6 | from bqplot.marks import Lines 7 | from bqplot.figure import Figure 8 | from bqplot.interacts import BrushIntervalSelector 9 | from bqplot.toolbar import Toolbar 10 | from .plotobj import BasePlot 11 | from .plotutils import get_color 12 | 13 | 14 | class BQPlotPlot(BasePlot): 15 | def __init__(self, size=None, theme=None): 16 | self.size = size or (12, 5) 17 | self._x_sc = LinearScale() 18 | self._y_sc = LinearScale() 19 | 20 | self._axes = [] 21 | self._marks = [] 22 | 23 | def _newAx(self, y_side='left', color='black'): 24 | # axis managemens 25 | raise NotImplementedError() 26 | 27 | def show(self, title='', xlabel='', ylabel='', xaxis=True, yaxis=True, xticks=True, yticks=True, legend=True, grid=True, **kwargs): 28 | # require all data to be present before plotting 29 | x = Axis(title=xlabel, scale=self._x_sc) 30 | y = Axis(title=ylabel, scale=self._y_sc, orientation='vertical') 31 | fig = Figure(axes=[x, y], marks=self._marks, title=title, legend_location='right', interactions=BrushIntervalSelector()) 32 | 33 | display(VBox([fig, Toolbar(figure=fig)])) 34 | 35 | def area(self, data, color=None, y_axis='left', stacked=False, **kwargs): 36 | raise NotImplementedError() 37 | 38 | def bar(self, data, color=None, y_axis='left', stacked=False, **kwargs): 39 | raise NotImplementedError() 40 | 41 | def hist(self, data, color=None, y_axis='left', stacked=False, **kwargs): 42 | raise NotImplementedError() 43 | 44 | def hline(self, y, color=None, **kwargs): 45 | raise NotImplementedError() 46 | 47 | def hspan(self, yhigh, ylow, color=None, **kwargs): 48 | raise NotImplementedError() 49 | 50 | def line(self, data, color=None, y_axis='left', **kwargs): 51 | for i, col in enumerate(data): 52 | _color = get_color(i, col, color) 53 | self._marks.append(Lines(x=data.index, 54 | y=data[col], 55 | scales={'x': self._x_sc, 'y': self._y_sc}, 56 | colors=[_color])) 57 | 58 | def scatter(self, data, color=None, x=None, y=None, y_axis='left', **kwargs): 59 | raise NotImplementedError() 60 | 61 | def step(self, data, color=None, y_axis='left', **kwargs): 62 | raise NotImplementedError() 63 | 64 | def vline(self, x, color=None, **kwargs): 65 | raise NotImplementedError() 66 | 67 | def vspan(self, xhigh, xlow, color=None, **kwargs): 68 | raise NotImplementedError() 69 | -------------------------------------------------------------------------------- /lantern/plotting/__init__.py: -------------------------------------------------------------------------------- 1 | from six import iteritems 2 | from .plot_matplotlib import MatplotlibPlot 3 | from .plot_plotly import PlotlyPlot 4 | from .plot_bokeh import BokehPlot 5 | # from .plot_altair import NVD3Plot 6 | # from .plot_bqplot import BQPlotPlot 7 | # from .plot_nvd3 import NVD3Plot 8 | from ..utils import LanternException 9 | 10 | 11 | _BACKENDS = ['cufflinks', 'plotly', 'bokeh', 'highcharts', 'matplotlib', 'seaborn', 'bqplot', 'd3'] 12 | 13 | 14 | def _backend_to_plot_obj(backend, size=None, theme=None): 15 | if backend == 'matplotlib' or backend == 'seaborn': 16 | return MatplotlibPlot(size, theme) 17 | if backend == 'cufflinks' or backend == 'plotly': 18 | return PlotlyPlot(size, theme) 19 | if backend == 'bokeh': 20 | return BokehPlot(size, theme) 21 | # if backend == 'altair': 22 | # return AltairPlot(size, theme) 23 | # if backend == 'bqplot': 24 | # return BQPlotPlot(size, theme) 25 | # if backend == 'd3': 26 | # return NVD3Plot(size, theme) 27 | raise NotImplementedError() 28 | 29 | 30 | def figure(backend='matplotlib', size=None, theme=None): 31 | if backend not in _BACKENDS: 32 | raise Exception('Must pick backend in %s' % _BACKENDS) 33 | return _backend_to_plot_obj(backend, size, theme) 34 | 35 | 36 | def plot(data, kind='line', backend='matplotlib', size=None, theme=None, **kwargs): 37 | f = figure(backend, size, theme) 38 | 39 | show_args = {} 40 | show_args['title'] = kwargs.pop('title', '') 41 | show_args['xlabel'] = kwargs.pop('xlabel', '') 42 | show_args['ylabel'] = kwargs.pop('ylabel', '') 43 | show_args['xaxis'] = kwargs.pop('xaxis', True) 44 | show_args['yaxis'] = kwargs.pop('yaxis', True) 45 | show_args['xticks'] = kwargs.pop('xticks', True) 46 | show_args['yticks'] = kwargs.pop('yticks', True) 47 | show_args['legend'] = kwargs.pop('legend', True) 48 | show_args['grid'] = kwargs.pop('grid', True) 49 | 50 | # TODO 51 | if isinstance(kind, str): 52 | getattr(f, kind)(data, **kwargs) 53 | return f.show(**show_args) 54 | elif isinstance(kind, list): 55 | # TODO handle color, scatter, etc 56 | if len(kind) != len(data.columns): 57 | raise LanternException('Must specify type for each column') 58 | for i, k in enumerate(kind): 59 | getattr(f, k)(data[[data.columns[i]]], **kwargs) 60 | return f.show(**show_args) 61 | 62 | elif isinstance(kind, dict): 63 | # TODO handle color, scatter, etc 64 | if len(kind) != len(data.columns): 65 | raise LanternException('Must specify type for each column') 66 | for k, v in iteritems(kind): 67 | if k not in data.columns: 68 | raise LanternException('Unrecognized column: %s' % str(k)) 69 | getattr(f, v)(data[[k]], **kwargs) 70 | return f.show(**show_args) 71 | -------------------------------------------------------------------------------- /lantern/widgets/variable_inspector.py: -------------------------------------------------------------------------------- 1 | import ipywidgets as widgets 2 | from sidecar import Sidecar 3 | from IPython import get_ipython 4 | from IPython.core.magics.namespace import NamespaceMagics 5 | from sys import getsizeof 6 | 7 | 8 | def _getsizeof(x): 9 | if type(x).__name__ in ['ndarray', 'Series']: 10 | return x.nbytes 11 | elif type(x).__name__ == 'DataFrame': 12 | return x.memory_usage().sum() 13 | else: 14 | return getsizeof(x) 15 | 16 | 17 | def _getshapeof(x): 18 | try: 19 | return x.shape 20 | except AttributeError: 21 | return None 22 | 23 | 24 | class VariableInspector(object): 25 | def __init__(self): 26 | self._sc = Sidecar(title='Variables') 27 | get_ipython().user_ns_hidden['widgets'] = widgets 28 | get_ipython().user_ns_hidden['NamespaceMagics'] = NamespaceMagics 29 | 30 | self.closed = False 31 | self.namespace = NamespaceMagics() 32 | self.namespace.shell = get_ipython().kernel.shell 33 | 34 | self._box = widgets.Box() 35 | self._box.layout.overflow_y = 'scroll' 36 | self._table = widgets.HTML(value='Not hooked') 37 | self._box.children = [self._table] 38 | 39 | self._ipython = get_ipython() 40 | self._ipython.events.register('post_run_cell', self._fill) 41 | 42 | def close(self): 43 | """Close and remove hooks.""" 44 | if not self.closed: 45 | self._ipython.events.unregister('post_run_cell', self._fill) 46 | self._box.close() 47 | self.closed = True 48 | 49 | def _fill(self): 50 | """Fill self with variable information.""" 51 | types_to_exclude = ['module', 'function', 'builtin_function_or_method', 52 | 'instance', '_Feature', 'type', 'ufunc'] 53 | values = self.namespace.who_ls() 54 | 55 | def eval(expr): 56 | return self.namespace.shell.ev(expr) 57 | 58 | var = [(v, 59 | type(eval(v)).__name__, 60 | str(_getsizeof(eval(v))), 61 | str(_getshapeof(eval(v))) if _getshapeof(eval(v)) else '', 62 | str(eval(v))[:200]) 63 | for v in values if (v not in ['_html', '_nms', 'NamespaceMagics', '_Jupyter']) & (type(eval(v)).__name__ not in types_to_exclude)] 64 | 65 | self._table.value = '' 68 | 69 | def _ipython_display_(self): 70 | """Called when display() or pyout is used to display the Variable 71 | Inspector.""" 72 | with self._sc: 73 | self._box._ipython_display_() 74 | -------------------------------------------------------------------------------- /lantern/data/__init__.py: -------------------------------------------------------------------------------- 1 | from .data_cufflinks import getCFData 2 | from .data_sklearn import getSKData 3 | from .other import person, people, company, companies, ticker, currency, trades, superstore # noqa: F401 4 | 5 | # scikit learn 6 | regression = lambda **kwargs: getSKData('regression', **kwargs) # noqa: E731 7 | blobs = lambda **kwargs: getSKData('blobs', **kwargs) # noqa: E731 8 | classification = lambda **kwargs: getSKData('classification', **kwargs) # noqa: E731 9 | multilabel = lambda **kwargs: getSKData('multilabel', **kwargs) # noqa: E731 10 | gaussian = lambda **kwargs: getSKData('gaussian', **kwargs) # noqa: E731 11 | hastie = lambda **kwargs: getSKData('hastie', **kwargs) # noqa: E731 12 | circles = lambda **kwargs: getSKData('circles', **kwargs) # noqa: E731 13 | moons = lambda **kwargs: getSKData('moons', **kwargs) # noqa: E731 14 | biclusters = lambda **kwargs: getSKData('biclusters', **kwargs) # noqa: E731 15 | scurve = lambda **kwargs: getSKData('scurve', **kwargs) # noqa: E731 16 | checker = lambda **kwargs: getSKData('checker', **kwargs) # noqa: E731 17 | friedman = lambda **kwargs: getSKData('friedman', **kwargs) # noqa: E731 18 | friedman2 = lambda **kwargs: getSKData('friedman2', **kwargs) # noqa: E731 19 | friedman3 = lambda **kwargs: getSKData('friedman3', **kwargs) # noqa: E731 20 | 21 | # cufflinks 22 | area = lambda **kwargs: getCFData('area', **kwargs) # noqa: E731 23 | bar = lambda **kwargs: getCFData('bar', n_categories=kwargs.pop('n_categories', 5), n=kwargs.pop('n', 10), **kwargs) # noqa: E731 24 | box = lambda **kwargs: getCFData('box', **kwargs) # noqa: E731 25 | bubble = lambda **kwargs: getCFData('bubble', n_categories=kwargs.pop('n_categories', 5), n=kwargs.pop('n', 10), **kwargs) # noqa: E731 26 | bubble3d = lambda **kwargs: getCFData('bubble3d', n_categories=kwargs.pop('n_categories', 5), n=kwargs.pop('n', 10), **kwargs) # noqa: E731 27 | candlestick = lambda **kwargs: getCFData('ohlcv', **kwargs) # noqa: E731 28 | choropleth = None 29 | density = None 30 | heatmap = lambda **kwargs: getCFData('heatmap', n_x=kwargs.pop('n_x', 20), n_y=kwargs.pop('n_y', 10), **kwargs) # noqa: E731 31 | hexbin = None 32 | histogram = lambda **kwargs: getCFData('histogram', n_traces=kwargs.pop('n_traces', 2), n=kwargs.pop('n', 100), **kwargs) # noqa: E731 33 | line = lambda **kwargs: getCFData('line', **kwargs) # noqa: E731 34 | ohlc = lambda **kwargs: getCFData('ohlc', **kwargs) # noqa: E731 35 | ohlcv = lambda **kwargs: getCFData('ohlcv', **kwargs) # noqa: E731 36 | pie = lambda **kwargs: getCFData('pie', **kwargs) # noqa: E731 37 | scatter = lambda **kwargs: getCFData('scatter', n_categories=kwargs.pop('n_categories', 5), n=kwargs.pop('n', 10), **kwargs) # noqa: E731 38 | scatter3d = lambda **kwargs: getCFData('scatter3d', n_categories=kwargs.pop('n_categories', 5), n=kwargs.pop('n', 10), **kwargs) # noqa: E731 39 | scattergeo = None 40 | scattermat = None 41 | spread = None 42 | surface = None 43 | timeseries = lambda **kwargs: getCFData('line', **kwargs) # noqa: E731 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | .DS_Store 103 | # Logs 104 | logs 105 | *.log 106 | npm-debug.log* 107 | yarn-debug.log* 108 | yarn-error.log* 109 | 110 | # Runtime data 111 | pids 112 | *.pid 113 | *.seed 114 | *.pid.lock 115 | 116 | # Directory for instrumented libs generated by jscoverage/JSCover 117 | lib-cov 118 | 119 | # Coverage directory used by tools like istanbul 120 | coverage 121 | 122 | # nyc test coverage 123 | .nyc_output 124 | 125 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 126 | .grunt 127 | 128 | # Bower dependency directory (https://bower.io/) 129 | bower_components 130 | 131 | # node-waf configuration 132 | .lock-wscript 133 | 134 | # Compiled binary addons (http://nodejs.org/api/addons.html) 135 | build/Release 136 | 137 | # Dependency directories 138 | node_modules/ 139 | jspm_packages/ 140 | 141 | # Typescript v1 declaration files 142 | typings/ 143 | 144 | # Optional npm cache directory 145 | .npm 146 | 147 | # Optional eslint cache 148 | .eslintcache 149 | 150 | # Optional REPL history 151 | .node_repl_history 152 | 153 | # Output of 'npm pack' 154 | *.tgz 155 | 156 | # Yarn Integrity file 157 | .yarn-integrity 158 | 159 | # dotenv environment variables file 160 | .env 161 | 162 | .DS_Store 163 | yarn.lock 164 | package-lock.json 165 | .autoversion 166 | -------------------------------------------------------------------------------- /docs/data.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Data 3 | ============== 4 | 5 | Fake Data 6 | ============= 7 | Lantern relies on Faker and Mimesis to generate fake data 8 | 9 | People 10 | ------- 11 | Generate an individual (dict) or a dataframe of people 12 | 13 | .. code:: python3 14 | 15 | lantern.person() 16 | 17 | .. code:: bash 18 | 19 | {'first_name': 'Francoise', 20 | 'last_name': 'Houston', 21 | 'name': 'Francoise Houston', 22 | 'age': 29, 23 | 'gender': 'Female', 24 | 'id': '44-72/01', 25 | 'occupation': 'Technical Analyst', 26 | 'telephone': '519.196.0471', 27 | 'title': 'PhD', 28 | 'username': 'simoniac.2029', 29 | 'university': 'Eastern Connecticut State University (ECSU)'} 30 | 31 | .. code:: python3 32 | 33 | lantern.people() 34 | 35 | 36 | Companies 37 | ---------- 38 | Generate an individual (dict) or a dataframe of companies 39 | 40 | .. code:: python3 41 | 42 | lantern.company() 43 | 44 | .. code:: bash 45 | 46 | {'name': 'Gordon, Rodriguez and Salazar', 47 | 'address': '351 Ralph Stream Apt. 203\nMargaretview, NE 00811-8677', 48 | 'ticker': 'AYG', 49 | 'last_price': 53.96174484497788, 50 | 'market_cap': 76809360484, 51 | 'exchange': 'F', 52 | 'ceo': 'Patricia Woodard', 53 | 'sector': 'Real Estate', 54 | 'industry': 'Real Estate Management & Development'} 55 | 56 | .. code:: python3 57 | 58 | lantern.companies() 59 | 60 | Financial 61 | ---------- 62 | Generate tickers and exchange codes, currencies, and trades (dataframe) 63 | 64 | .. code:: python3 65 | 66 | lantern.ticker(country='us') 67 | lantern.currency() 68 | lantern.trades() 69 | 70 | General Purpose 71 | ---------- 72 | Generate some good general purpose data, can use for a variety of charts, clustergrammable, etc 73 | 74 | .. code:: python3 75 | 76 | lantern.superstore() 77 | 78 | 79 | 80 | Cufflinks Data 81 | =========== 82 | We wrap `cufflinks.datagen` and expose a variety of data types as dataframes 83 | 84 | .. code:: python3 85 | 86 | lantern.area() 87 | lantern.bar() 88 | lantern.box() 89 | lantern.bubble() 90 | lantern.bubble3d() 91 | lantern.candlestick() 92 | lantern.heatmap() 93 | lantern.histogram() 94 | lantern.line() 95 | lantern.ohlc() 96 | lantern.ohlcv() 97 | lantern.pie() 98 | lantern.scatter() 99 | lantern.scatter3d() 100 | lantern.timeseries() 101 | 102 | Scikit-learn Data 103 | =========== 104 | We wrap `sklearn.datasets` and expose a variety of data types as either numpy arrays or dataframes 105 | 106 | .. code:: python3 107 | 108 | lantern.regression() 109 | lantern.blobs() 110 | lantern.classification() 111 | lantern.multilabel() 112 | lantern.gaussian() 113 | lantern.hastie() 114 | lantern.circles() 115 | lantern.moons() 116 | lantern.biclusters() 117 | lantern.scurve() 118 | lantern.checker() 119 | lantern.friedman() 120 | lantern.friedman2() 121 | lantern.friedman3() 122 | 123 | -------------------------------------------------------------------------------- /examples/ipysheet.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 6, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import ipysheet\n", 10 | "import lantern as l" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 7, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "df = l.bar()\n", 20 | "df2 = df.to_dict()" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 8, 26 | "metadata": {}, 27 | "outputs": [ 28 | { 29 | "data": { 30 | "application/vnd.jupyter.widget-view+json": { 31 | "model_id": "de6eb5e1dba941a4b2f1d9dc9f4b827d", 32 | "version_major": 2, 33 | "version_minor": 0 34 | }, 35 | "text/plain": [ 36 | "Sheet(cells=(Cell(column_end=0, column_start=0, row_end=9, row_start=0, squeeze_row=False, type='text', value=…" 37 | ] 38 | }, 39 | "metadata": {}, 40 | "output_type": "display_data" 41 | } 42 | ], 43 | "source": [ 44 | "l.grid(df, 'ipysheet')" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 9, 50 | "metadata": {}, 51 | "outputs": [ 52 | { 53 | "data": { 54 | "application/vnd.jupyter.widget-view+json": { 55 | "model_id": "cc2b213ae43c4a78883f9c6c08fba563", 56 | "version_major": 2, 57 | "version_minor": 0 58 | }, 59 | "text/plain": [ 60 | "Sheet(cells=(Cell(column_end=0, column_start=0, row_end=0, row_start=0, squeeze_row=False, type='numeric', val…" 61 | ] 62 | }, 63 | "metadata": {}, 64 | "output_type": "display_data" 65 | } 66 | ], 67 | "source": [ 68 | "l.grid([{'a': 1, 'b': 2, 'c': 3}], 'ipysheet')" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": 10, 74 | "metadata": {}, 75 | "outputs": [ 76 | { 77 | "data": { 78 | "application/vnd.jupyter.widget-view+json": { 79 | "model_id": "8ca8f370674d4ab1a687019600cb6f36", 80 | "version_major": 2, 81 | "version_minor": 0 82 | }, 83 | "text/plain": [ 84 | "Sheet(cells=(Cell(column_end=0, column_start=0, row_end=2, row_start=0, squeeze_row=False, type='numeric', val…" 85 | ] 86 | }, 87 | "metadata": {}, 88 | "output_type": "display_data" 89 | } 90 | ], 91 | "source": [ 92 | "l.grid([1, 2, 3], 'ipysheet')" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": null, 98 | "metadata": {}, 99 | "outputs": [], 100 | "source": [] 101 | } 102 | ], 103 | "metadata": { 104 | "kernelspec": { 105 | "display_name": "Python 3", 106 | "language": "python", 107 | "name": "python3" 108 | }, 109 | "language_info": { 110 | "codemirror_mode": { 111 | "name": "ipython", 112 | "version": 3 113 | }, 114 | "file_extension": ".py", 115 | "mimetype": "text/x-python", 116 | "name": "python", 117 | "nbconvert_exporter": "python", 118 | "pygments_lexer": "ipython3", 119 | "version": "3.7.0" 120 | } 121 | }, 122 | "nbformat": 4, 123 | "nbformat_minor": 2 124 | } 125 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at timothy.k.paine@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /lantern/data/data_cufflinks.py: -------------------------------------------------------------------------------- 1 | from .cfgen import scattergeo, \ 2 | choropleth, \ 3 | scatter, \ 4 | scatter3d, \ 5 | bubble, \ 6 | bubble3d, \ 7 | pie, \ 8 | heatmap, \ 9 | bars, \ 10 | ohlc, \ 11 | ohlcv, \ 12 | box, \ 13 | histogram, \ 14 | surface, \ 15 | sinwave, \ 16 | getName, \ 17 | lines 18 | 19 | 20 | def getCFData(type, n_categories=5, n=100, **kwargs): 21 | if type == 'scatter': 22 | return scatter(n_categories, 23 | n, 24 | prefix=kwargs.get('prefix', 'category'), 25 | mode=kwargs.get('mode', None))[['x', 'y', 'categories', 'text']] 26 | elif type == 'scatter3d': 27 | return scatter3d(n_categories, 28 | n, 29 | prefix=kwargs.get('prefix', 'category'), 30 | mode=kwargs.get('mode', None)) 31 | elif type == 'bubble': 32 | return bubble(n_categories, 33 | n, 34 | prefix=kwargs.get('prefix', 'category'), 35 | mode=kwargs.get('mode', None))[['x', 'y', 'categories', 'size', 'text']] 36 | elif type == 'bubble3d': 37 | return bubble3d(n_categories, 38 | n, 39 | prefix=kwargs.get('prefix', 'category'), 40 | mode=kwargs.get('mode', None)) 41 | elif type == 'pie': 42 | return pie(n_labels=kwargs.get('n_lablels', 5), 43 | mode=kwargs.get('mode', None)) 44 | elif type == 'heatmap': 45 | return heatmap(n_x=kwargs.get('n_x', 5), 46 | n_y=kwargs.get('n_y', 10)) 47 | elif type == 'bars': 48 | return bars(n, 49 | n_categories, 50 | prefix=kwargs.get('prefix', 'category'), 51 | columns=kwargs.get('columns', None), 52 | mode=kwargs.get('mode', 'abc')) 53 | elif type == 'ohlc': 54 | return ohlc(n) 55 | elif type == 'ohlcv': 56 | return ohlcv(n) 57 | elif type == 'box': 58 | return box(n_traces=kwargs.get('n_traces', 5), 59 | n=n, 60 | mode=kwargs.get('mode', None)) 61 | elif type == 'histogram': 62 | return histogram(n_traces=kwargs.get('n_traces', 1), 63 | n=n, 64 | mode=None) 65 | elif type == 'surface': 66 | return surface(n_x=kwargs.get('n_x', 20), 67 | n_y=kwargs.get('n_y', 20)) 68 | elif type == 'sinwave': 69 | return sinwave(n=n, 70 | inc=kwargs.get('inc', .25)) 71 | if type == 'scattergeo': 72 | return scattergeo() 73 | elif type == 'choropleth': 74 | return choropleth() 75 | elif type == 'stock': 76 | return getName(n=1, 77 | name=kwargs.get('name', 3), 78 | exchange=kwargs.get('exchange', 2), 79 | columns=kwargs.get('columns', None), 80 | mode=kwargs.get('mode', 'abc')) 81 | else: 82 | return lines(n_traces=kwargs.get('n_traces', 5), 83 | n=n, 84 | columns=kwargs.get('columns', None), 85 | dateIndex=kwargs.get('dateIndex', True), 86 | mode=kwargs.get('mode', None)) 87 | -------------------------------------------------------------------------------- /examples/bqplot.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "%%capture\n", 10 | "import lantern as l" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 2, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "df = l.bar()" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 3, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "col1 = df.columns[0]\n", 29 | "col2 = df.columns[1]" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 4, 35 | "metadata": {}, 36 | "outputs": [ 37 | { 38 | "data": { 39 | "application/vnd.jupyter.widget-view+json": { 40 | "model_id": "8ffcfe21d3684c5f8c301856ae5c0086", 41 | "version_major": 2, 42 | "version_minor": 0 43 | }, 44 | "text/plain": [ 45 | "VBox(children=(Figure(axes=[Axis(scale=LinearScale()), Axis(orientation='vertical', scale=LinearScale())], fig…" 46 | ] 47 | }, 48 | "metadata": {}, 49 | "output_type": "display_data" 50 | } 51 | ], 52 | "source": [ 53 | "l.plot(df[[col1, col2]], backend='bqplot', size=(12,5))" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 5, 59 | "metadata": {}, 60 | "outputs": [ 61 | { 62 | "data": { 63 | "application/vnd.jupyter.widget-view+json": { 64 | "model_id": "60eba73a5bd94ff885af1bd4f9ddd6e9", 65 | "version_major": 2, 66 | "version_minor": 0 67 | }, 68 | "text/plain": [ 69 | "VBox(children=(Figure(axes=[Axis(scale=LinearScale()), Axis(orientation='vertical', scale=LinearScale())], fig…" 70 | ] 71 | }, 72 | "metadata": {}, 73 | "output_type": "display_data" 74 | } 75 | ], 76 | "source": [ 77 | "l.plot(df, backend='bqplot', size=(12,12))" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 8, 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "data": { 87 | "application/vnd.jupyter.widget-view+json": { 88 | "model_id": "78525585507d449e8e93860e4b3fa8f0", 89 | "version_major": 2, 90 | "version_minor": 0 91 | }, 92 | "text/plain": [ 93 | "VBox(children=(Figure(axes=[Axis(scale=LinearScale(), side='bottom'), Axis(orientation='vertical', scale=Linea…" 94 | ] 95 | }, 96 | "metadata": {}, 97 | "output_type": "display_data" 98 | } 99 | ], 100 | "source": [ 101 | "import bqplot.pyplot as plt\n", 102 | "plt.plot(df)\n", 103 | "plt.show()" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": null, 109 | "metadata": {}, 110 | "outputs": [], 111 | "source": [] 112 | } 113 | ], 114 | "metadata": { 115 | "kernelspec": { 116 | "display_name": "Python 3", 117 | "language": "python", 118 | "name": "python3" 119 | }, 120 | "language_info": { 121 | "codemirror_mode": { 122 | "name": "ipython", 123 | "version": 3 124 | }, 125 | "file_extension": ".py", 126 | "mimetype": "text/x-python", 127 | "name": "python", 128 | "nbconvert_exporter": "python", 129 | "pygments_lexer": "ipython3", 130 | "version": "3.7.0" 131 | } 132 | }, 133 | "nbformat": 4, 134 | "nbformat_minor": 2 135 | } 136 | -------------------------------------------------------------------------------- /examples/plotly.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "%%capture\n", 10 | "import lantern as l" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 2, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "df = l.bar()" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 3, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "col1 = df.columns[0]\n", 29 | "col2 = df.columns[1]\n", 30 | "df = abs(df)" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 4, 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "data": { 40 | "application/vnd.jupyter.widget-view+json": { 41 | "model_id": "3ead23e087f947508dff353a806b7f25", 42 | "version_major": 2, 43 | "version_minor": 0 44 | }, 45 | "text/plain": [ 46 | "FigureWidget({\n", 47 | " 'data': [{'line': {'color': 'rgba(68, 32, 130, 1.0)', 'dash': 'solid', 'shape': 'linear', '…" 48 | ] 49 | }, 50 | "metadata": {}, 51 | "output_type": "display_data" 52 | } 53 | ], 54 | "source": [ 55 | "f = l.figure('cufflinks')\n", 56 | "f.line(df[df.columns[:1]], y_axis='right')\n", 57 | "f.bar(df[df.columns[1:2]], y_axis='right')\n", 58 | "f.area(df[df.columns[1:2]])\n", 59 | "f.show()" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 5, 65 | "metadata": {}, 66 | "outputs": [ 67 | { 68 | "data": { 69 | "application/vnd.jupyter.widget-view+json": { 70 | "model_id": "3dfb0a73384f4fd385235557a8f92d2e", 71 | "version_major": 2, 72 | "version_minor": 0 73 | }, 74 | "text/plain": [ 75 | "FigureWidget({\n", 76 | " 'data': [{'marker': {'color': '#30F90E'},\n", 77 | " 'mode': 'markers',\n", 78 | " 'n…" 79 | ] 80 | }, 81 | "metadata": {}, 82 | "output_type": "display_data" 83 | } 84 | ], 85 | "source": [ 86 | "l.plot(df, 'scatter', 'cufflinks')" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": 7, 92 | "metadata": {}, 93 | "outputs": [ 94 | { 95 | "data": { 96 | "application/vnd.jupyter.widget-view+json": { 97 | "model_id": "3a50716f11214fb59f990f01ede7584e", 98 | "version_major": 2, 99 | "version_minor": 0 100 | }, 101 | "text/plain": [ 102 | "FigureWidget({\n", 103 | " 'data': [{'histfunc': 'count',\n", 104 | " 'histnorm': '',\n", 105 | " 'marker': {'colo…" 106 | ] 107 | }, 108 | "metadata": {}, 109 | "output_type": "display_data" 110 | } 111 | ], 112 | "source": [ 113 | "df = l.histogram()\n", 114 | "l.plot(df, 'hist', 'cufflinks')" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": null, 120 | "metadata": {}, 121 | "outputs": [], 122 | "source": [] 123 | } 124 | ], 125 | "metadata": { 126 | "kernelspec": { 127 | "display_name": "Python 3", 128 | "language": "python", 129 | "name": "python3" 130 | }, 131 | "language_info": { 132 | "codemirror_mode": { 133 | "name": "ipython", 134 | "version": 3 135 | }, 136 | "file_extension": ".py", 137 | "mimetype": "text/x-python", 138 | "name": "python", 139 | "nbconvert_exporter": "python", 140 | "pygments_lexer": "ipython3", 141 | "version": "3.7.0" 142 | } 143 | }, 144 | "nbformat": 4, 145 | "nbformat_minor": 2 146 | } 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 2 | An orchestration layer for plots and tables, dummy datasets, widgets, research, reports, and anything else a data scientist might need. 3 | 4 | [![Build Status](https://github.com/timkpaine/lantern/workflows/Build%20Status/badge.svg)](https://github.com/timkpaine/lantern/actions/) 5 | [![GitHub issues](https://img.shields.io/github/issues/timkpaine/lantern.svg)]() 6 | [![codecov](https://codecov.io/gh/timkpaine/lantern/branch/main/graph/badge.svg)](https://codecov.io/gh/timkpaine/lantern) 7 | [![PyPI](https://img.shields.io/pypi/l/pylantern.svg)](https://pypi.python.org/pypi/pylantern) 8 | [![PyPI](https://img.shields.io/pypi/v/pylantern.svg)](https://pypi.python.org/pypi/pylantern) 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ## Note: Lantern Live has moved to [tributary](https://github.com/timkpaine/tributary) 17 | ## Note: Email reports have moved to [jupyterlab_email](https://github.com/timkpaine/jupyterlab_email) 18 | ## Note: `Publish` is removed in favor of [Voila](https://github.com/voila-dashboards/voila) 19 | ## Note: `Export` code has has moved to [jupyterlab_commands](https://github.com/timkpaine/jupyterlab_commands/) and [jupyterlab_nbconvert_nocode](https://github.com/timkpaine/jupyterlab_nbconvert_nocode) 20 | 21 | ## About 22 | This library is designed to fill gaps between other libraries with the JupyterLab ecosystem. The motivation was initially to allow for plots generated with a javascript library (like `plotly` or `bokeh`) to trivially swap out for `matplotlib` in non-browser contexts such as NBConvert generation of PDFs. 23 | 24 | It has expanded to include a variety of functions, including grids, emailing notebooks, publishing notebooks, custom nbconvert exporters for JupyterLab, variable inpection, custom streaming operations, and other helpful functions and widgets. As these functionalities mature, or as competeting libraries emerge, they are cut out into their own standalone libraries or removed from `Lantern`, respectively. 25 | 26 | This library has produced or ceded functionality to: 27 | - [jupyterlab_email](https://github.com/timkpaine/jupyterlab_email) 28 | - [tributary](https://github.com/timkpaine/tributary) 29 | - [jupyterlab_commands](https://github.com/timkpaine/jupyterlab_commands/) 30 | - [jupyterlab_nbconvert_nocode](https://github.com/timkpaine/jupyterlab_nbconvert_nocode) 31 | - [Voila](https://github.com/voila-dashboards/voila) 32 | 33 | ## Install 34 | To install the base package from pip: 35 | 36 | `pip install pylantern` 37 | 38 | To Install from source: 39 | 40 | `make install` 41 | 42 | 43 | Lantern relies on JupyterLab extensions: 44 | 45 | ``` 46 | jupyter labextension install @jupyter-widgets/jupyterlab-manager 47 | jupyter labextension install plotlywidget 48 | jupyter labextension install @jupyterlab/plotly-extension 49 | jupyter labextension install jupyterlab_bokeh 50 | jupyter labextension install qgrid 51 | jupyter labextension install @finos/perspective-jupyterlab 52 | jupyter labextension install ipysheet 53 | jupyter labextension install lineup_widget 54 | ``` 55 | 56 | The following are for work in-progress on main: 57 | 58 | ``` 59 | jupyter labextension install bqplot 60 | ``` 61 | 62 | 63 | ## Data 64 | ![](https://raw.githubusercontent.com/timkpaine/lantern/main/docs/img/data.gif) 65 | 66 | ## Plots 67 | ![](https://raw.githubusercontent.com/timkpaine/lantern/main/docs/img/plot/plots.gif) 68 | 69 | ## Grids 70 | ![](https://raw.githubusercontent.com/timkpaine/lantern/main/docs/img/grids.gif) 71 | 72 | 73 | ## Export Without Code: 74 | Note: this has moved to [jupyterlab_commands](https://github.com/timkpaine/jupyterlab_commands/) 75 | 76 | ## Widget Tools 77 | ![](https://raw.githubusercontent.com/timkpaine/lantern/main/docs/img/widgets/widgets.gif) 78 | 79 | -------------------------------------------------------------------------------- /docs/plot.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Plotting 3 | ============== 4 | Supported Backends: 5 | 6 | - Matplotlib 7 | - Plotly 8 | - Bokeh 9 | 10 | In progress: 11 | 12 | - Altair 13 | - bqplot 14 | 15 | .. image:: ./img/plot/plots.gif 16 | :scale: 100% 17 | :alt: plot.png 18 | 19 | 20 | Plot command 21 | ============= 22 | .. method:: lantern.plot(data, kind='line', backend='matplotlib', theme=None, **kwargs) 23 | 24 | 25 | Object Oriented 26 | ================ 27 | .. method:: lantern.figure(backend='matplotlib', theme=None) 28 | 29 | .. code:: python3 30 | 31 | import lantern as l 32 | f = l.figure('matplotlib') 33 | 34 | 35 | 36 | Plot Types 37 | =========== 38 | - line 39 | - area 40 | - step 41 | - bar 42 | - scatter 43 | 44 | For the following code, we will assume the following commands were executed: 45 | 46 | .. code:: python3 47 | 48 | import lantern as l 49 | df = l.bar.sample() 50 | f = l.figure('matplotlib') 51 | 52 | 53 | Line 54 | ----- 55 | .. method:: line(self, data, color=None, y_axis='left', **kwargs): 56 | .. code:: python3 57 | 58 | f.line(df) 59 | f.show() 60 | 61 | .. image:: ./img/plot/line.png 62 | :scale: 100% 63 | :alt: line.png 64 | 65 | Area 66 | ----- 67 | .. method:: area(self, data, color=None, y_axis='left', stacked=False, **kwargs): 68 | .. code:: python3 69 | 70 | f.area(df) 71 | f.show() 72 | 73 | .. image:: ./img/plot/area.png 74 | :scale: 100% 75 | :alt: area.png 76 | 77 | Bar 78 | ---- 79 | .. NOTE:: Not yet available when using Bokeh backend. 80 | 81 | .. method:: bar(self, data, color=None, y_axis='left', stacked=False, **kwargs): 82 | .. code:: python3 83 | 84 | f.bar(df) 85 | f.show() 86 | 87 | .. image:: ./img/plot/bar.png 88 | :scale: 100% 89 | :alt: bar.png 90 | 91 | Histogram 92 | --------- 93 | .. NOTE:: Not yet available when using Bokeh backend. 94 | 95 | .. method:: hist(self, data, color=None, y_axis='left', stacked=False, **kwargs): 96 | .. code:: python3 97 | 98 | f.hist(df) 99 | f.show() 100 | 101 | .. image:: ./img/plot/hist.png 102 | :scale: 100% 103 | :alt: hist.png 104 | 105 | Scatter 106 | -------- 107 | .. method:: scatter(self, data, color=None, x=None, y=None, y_axis='left', **kwargs): 108 | .. code:: python3 109 | 110 | f.scatter(df) 111 | f.show() 112 | 113 | .. image:: ./img/plot/scatter.png 114 | :scale: 100% 115 | :alt: scatter.png 116 | 117 | 118 | Step 119 | ----- 120 | .. NOTE:: Not yet available when using Bokeh backend. 121 | 122 | .. method:: step(self, data, color=None, y_axis='left', **kwargs): 123 | .. code:: python3 124 | 125 | f.step(df) 126 | f.show() 127 | 128 | .. image:: ./img/plot/step.png 129 | :scale: 100% 130 | :alt: step.png 131 | 132 | 133 | Mixed-type Plots 134 | ================= 135 | 136 | .. WARNING:: Mixing temporal and categorical charts can yield unexpected results! 137 | 138 | Advanced Usage 139 | =============== 140 | .. method:: show(self, title='', xlabel='', ylabel='', xaxis=True, yaxis=True, xticks=True, yticks=True, legend=True, grid=True, **kwargs): 141 | 142 | For the following examples, we assume the following code: 143 | 144 | .. code:: python3 145 | 146 | import lantern as l 147 | df = l.bar.sample() 148 | f = l.figure('matplotlib') 149 | f.line(df) 150 | 151 | 152 | Axis labels 153 | ------------ 154 | .. code:: python3 155 | 156 | f.show(xlabel='Test X', ylabel='Test Y') 157 | 158 | .. image:: ./img/plot/labels.png 159 | :scale: 100% 160 | :alt: labels.png 161 | 162 | Axis ticks 163 | ------------ 164 | .. code:: python3 165 | 166 | f.show(yticks=False) 167 | 168 | .. image:: ./img/plot/ticks.png 169 | :scale: 100% 170 | :alt: ticks.png 171 | 172 | Axis lines 173 | ----------- 174 | .. code:: python3 175 | 176 | f.show(xaxis=False, yaxis=False) 177 | 178 | .. image:: ./img/plot/axis.png 179 | :scale: 100% 180 | :alt: axis.png 181 | 182 | Grid 183 | -------- 184 | .. code:: python3 185 | 186 | f.show(grid=False) 187 | 188 | .. image:: ./img/plot/grid.png 189 | :scale: 100% 190 | :alt: grid.png 191 | 192 | Legend 193 | -------- 194 | .. code:: python3 195 | 196 | f.show(legend=False) 197 | 198 | .. image:: ./img/plot/legend.png 199 | :scale: 100% 200 | :alt: legend.png 201 | 202 | Right Y Axis 203 | ------------- 204 | .. WARNING:: TODO 205 | 206 | Horizontal Lines 207 | ----------------- 208 | .. WARNING:: TODO 209 | 210 | Vertical Lines 211 | ----------------- 212 | .. WARNING:: TODO 213 | -------------------------------------------------------------------------------- /experimental/dash/dash-stock-tickers-demo-app-master/app.py: -------------------------------------------------------------------------------- 1 | import dash 2 | import dash_core_components as dcc 3 | import dash_html_components as html 4 | 5 | import colorlover as cl 6 | import datetime as dt 7 | import flask 8 | import os 9 | import pandas as pd 10 | import time 11 | import pyEX 12 | 13 | app = dash.Dash('stock-tickers') 14 | server = app.server 15 | 16 | app.scripts.config.serve_locally = False 17 | dcc._js_dist[0]['external_url'] = 'https://cdn.plot.ly/plotly-finance-1.28.0.min.js' 18 | 19 | colorscale = cl.scales['9']['qual']['Paired'] 20 | 21 | df_symbol = pd.read_csv('tickers.csv') 22 | 23 | app.layout = html.Div([ 24 | html.Div([ 25 | html.H2('IEX Finance Explorer', 26 | style={'display': 'inline', 27 | 'float': 'left', 28 | 'font-size': '2.65em', 29 | 'margin-left': '7px', 30 | 'font-weight': 'bolder', 31 | 'font-family': 'Product Sans', 32 | 'color': "rgba(117, 117, 117, 0.95)", 33 | 'margin-top': '20px', 34 | 'margin-bottom': '0' 35 | }), 36 | html.Img(src="https://s3-us-west-1.amazonaws.com/plotly-tutorials/logo/new-branding/dash-logo-by-plotly-stripe.png", 37 | style={ 38 | 'height': '100px', 39 | 'float': 'right' 40 | }, 41 | ), 42 | ]), 43 | dcc.Dropdown( 44 | id='stock-ticker-input', 45 | options=[{'label': s[0], 'value': str(s[1])} 46 | for s in zip(df_symbol.Company, df_symbol.Symbol)], 47 | value=['AAPL', 'GOOGL'], 48 | multi=True 49 | ), 50 | html.Div(id='graphs') 51 | ], className="container") 52 | 53 | def bbands(price, window_size=10, num_of_std=5): 54 | rolling_mean = price.rolling(window=window_size).mean() 55 | rolling_std = price.rolling(window=window_size).std() 56 | upper_band = rolling_mean + (rolling_std*num_of_std) 57 | lower_band = rolling_mean - (rolling_std*num_of_std) 58 | return rolling_mean, upper_band, lower_band 59 | 60 | @app.callback( 61 | dash.dependencies.Output('graphs','children'), 62 | [dash.dependencies.Input('stock-ticker-input', 'value')]) 63 | def update_graph(tickers): 64 | graphs = [] 65 | for i, ticker in enumerate(tickers): 66 | try: 67 | df = pyEX.chartDF(str(ticker), '6m').reset_index() 68 | except: 69 | graphs.append(html.H3( 70 | 'Data is not available for {}, please retry later.'.format(ticker), 71 | style={'marginTop': 20, 'marginBottom': 20} 72 | )) 73 | continue 74 | 75 | candlestick = { 76 | 'x': df['date'], 77 | 'open': df['open'], 78 | 'high': df['high'], 79 | 'low': df['low'], 80 | 'close': df['close'], 81 | 'type': 'candlestick', 82 | 'name': ticker, 83 | 'legendgroup': ticker, 84 | 'increasing': {'line': {'color': colorscale[0]}}, 85 | 'decreasing': {'line': {'color': colorscale[1]}} 86 | } 87 | bb_bands = bbands(df.close) 88 | bollinger_traces = [{ 89 | 'x': df['date'], 'y': y, 90 | 'type': 'scatter', 'mode': 'lines', 91 | 'line': {'width': 1, 'color': colorscale[(i*2) % len(colorscale)]}, 92 | 'hoverinfo': 'none', 93 | 'legendgroup': ticker, 94 | 'showlegend': True if i == 0 else False, 95 | 'name': '{} - bollinger bands'.format(ticker) 96 | } for i, y in enumerate(bb_bands)] 97 | graphs.append(dcc.Graph( 98 | id=ticker, 99 | figure={ 100 | 'data': [candlestick] + bollinger_traces, 101 | 'layout': { 102 | 'margin': {'b': 0, 'r': 10, 'l': 60, 't': 0}, 103 | 'legend': {'x': 0} 104 | } 105 | } 106 | )) 107 | 108 | return graphs 109 | 110 | 111 | external_css = ["https://fonts.googleapis.com/css?family=Product+Sans:400,400i,700,700i", 112 | "https://cdn.rawgit.com/plotly/dash-app-stylesheets/2cc54b8c03f4126569a3440aae611bbef1d7a5dd/stylesheet.css"] 113 | 114 | for css in external_css: 115 | app.css.append_css({"external_url": css}) 116 | 117 | 118 | if 'DYNO' in os.environ: 119 | app.scripts.append_script({ 120 | 'external_url': 'https://cdn.rawgit.com/chriddyp/ca0d8f02a1659981a0ea7f013a378bbd/raw/e79f3f789517deec58f41251f7dbb6bee72c44ab/plotly_ga.js' 121 | }) 122 | 123 | 124 | if __name__ == '__main__': 125 | app.run_server(debug=True) 126 | -------------------------------------------------------------------------------- /lantern/plotting/plotutils.py: -------------------------------------------------------------------------------- 1 | import random 2 | import numpy as np 3 | 4 | 5 | def _r(): 6 | '''generate random color''' 7 | return '#%02X%02X%02X' % (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) 8 | 9 | 10 | def get_color(i, col, color): 11 | if isinstance(color, list): 12 | c = (color[i:i + 1] or [_r()])[0] 13 | elif isinstance(color, dict): 14 | c = color.get(col, _r()) 15 | elif isinstance(color, str) and color: 16 | c = color 17 | else: 18 | c = _r() 19 | return c 20 | 21 | 22 | # def _conf(type, colors, x, y, i, col): 23 | # from .plottypes import lookup 24 | # '''select type and color from their options, allow strings for some''' 25 | # if isinstance(type, str): 26 | # typ = lookup(type) 27 | # if isinstance(colors, list): 28 | # color = (colors[i:i+1] or [_r()])[0] 29 | # elif isinstance(colors, dict): 30 | # color = colors.get(col, _r()) 31 | # elif isinstance(colors, str) and colors: 32 | # color = colors 33 | # else: 34 | # color = _r() 35 | 36 | # if isinstance(type, list): 37 | # typ = (type[i:i+1] or ['line'])[0] 38 | # if isinstance(typ, str): 39 | # typ = lookup(typ) 40 | # if isinstance(colors, list): 41 | # color = (colors[i:i+1] or [_r()])[0] 42 | # elif isinstance(colors, dict): 43 | # color = colors.get(col, _r()) 44 | # elif isinstance(colors, str) and colors: 45 | # color = colors 46 | # else: 47 | # color = _r() 48 | 49 | # elif isinstance(type, dict): 50 | # typ = type.get(col, 'line') 51 | # if isinstance(type.get(col, 'line'), str): 52 | # typ = lookup(typ) 53 | 54 | # if isinstance(colors, list): 55 | # color = (colors[i:i+1] or [_r()])[0] 56 | # elif isinstance(colors, dict): 57 | # color = colors.get(col, _r()) 58 | # elif isinstance(colors, str): 59 | # color = colors 60 | # else: 61 | # color = _r() 62 | 63 | # if y and isinstance(y, dict): 64 | # y = y.get(col, 'left') 65 | # else: 66 | # y = 'left' 67 | 68 | # if x and isinstance(x, dict): 69 | # x = x.get(col, 'left') 70 | # else: 71 | # x = 'bottom' 72 | 73 | # return typ, color, x, y 74 | 75 | 76 | def _parseScatter(kwargs, col): 77 | ret = {} 78 | ret['x'] = kwargs.get(col, {}).get('x', col) 79 | ret['y'] = kwargs.get(col, {}).get('y', col) 80 | ret['categories'] = kwargs.get(col, {}).get('categories', col) 81 | ret['text'] = kwargs.get(col, {}).get('text', col) 82 | ret['size'] = kwargs.get(col, {}).get('size', 10) 83 | return ret 84 | 85 | 86 | def _parseScatterPie(kwargs, col): 87 | ret = {} 88 | ret['values'] = kwargs.get(col, {}).get('values', col) 89 | ret['labels'] = kwargs.get(col, {}).get('labels', col) 90 | return ret 91 | 92 | 93 | def align_yaxis_np(axes): 94 | """Align zeros of the two axes, zooming them out by same ratio""" 95 | axes = np.array(axes) 96 | extrema = np.array([ax.get_ylim() for ax in axes]) 97 | 98 | # reset for divide by zero issues 99 | for i in range(len(extrema)): 100 | if np.isclose(extrema[i, 0], 0.0): 101 | extrema[i, 0] = -1 102 | if np.isclose(extrema[i, 1], 0.0): 103 | extrema[i, 1] = 1 104 | 105 | # upper and lower limits 106 | lowers = extrema[:, 0] 107 | uppers = extrema[:, 1] 108 | 109 | # if all pos or all neg, don't scale 110 | all_positive = False 111 | all_negative = False 112 | if lowers.min() > 0.0: 113 | all_positive = True 114 | 115 | if uppers.max() < 0.0: 116 | all_negative = True 117 | 118 | if all_negative or all_positive: 119 | # don't scale 120 | return 121 | 122 | # pick "most centered" axis 123 | res = abs(uppers + lowers) 124 | min_index = np.argmin(res) 125 | 126 | # scale positive or negative part 127 | multiplier1 = abs(uppers[min_index] / lowers[min_index]) 128 | multiplier2 = abs(lowers[min_index] / uppers[min_index]) 129 | 130 | for i in range(len(extrema)): 131 | # scale positive or negative part based on which induces valid 132 | if i != min_index: 133 | lower_change = extrema[i, 1] * -1 * multiplier2 134 | upper_change = extrema[i, 0] * -1 * multiplier1 135 | if upper_change < extrema[i, 1]: 136 | extrema[i, 0] = lower_change 137 | else: 138 | extrema[i, 1] = upper_change 139 | 140 | # bump by 10% for a margin 141 | extrema[i, 0] *= 1.1 142 | extrema[i, 1] *= 1.1 143 | 144 | # set axes limits 145 | [axes[i].set_ylim(*extrema[i]) for i in range(len(extrema))] 146 | -------------------------------------------------------------------------------- /experimental/ipyvolume/Untitled.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "application/vnd.jupyter.widget-view+json": { 11 | "model_id": "7499cf6856514af3a368a33b804d1142", 12 | "version_major": 2, 13 | "version_minor": 0 14 | }, 15 | "text/plain": [ 16 | "VBox(children=(Figure(camera_center=[0.0, 0.0, 0.0], height=500, matrix_projection=[0.0, 0.0, 0.0, 0.0, 0.0, 0…" 17 | ] 18 | }, 19 | "metadata": {}, 20 | "output_type": "display_data" 21 | } 22 | ], 23 | "source": [ 24 | "import ipyvolume as ipv\n", 25 | "import numpy as np\n", 26 | "x, y, z = np.random.random((3, 10000))\n", 27 | "ipv.quickscatter(x, y, z, size=1, marker=\"sphere\")" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 2, 33 | "metadata": {}, 34 | "outputs": [ 35 | { 36 | "data": { 37 | "application/vnd.jupyter.widget-view+json": { 38 | "model_id": "3bb30c6a02c9422885d8dce8fdbb3b6e", 39 | "version_major": 2, 40 | "version_minor": 0 41 | }, 42 | "text/plain": [ 43 | "VBox(children=(Figure(camera_center=[0.0, 0.0, 0.0], height=500, matrix_projection=[0.0, 0.0, 0.0, 0.0, 0.0, 0…" 44 | ] 45 | }, 46 | "metadata": {}, 47 | "output_type": "display_data" 48 | } 49 | ], 50 | "source": [ 51 | "import ipyvolume as ipv\n", 52 | "import numpy as np\n", 53 | "x, y, z, u, v, w = np.random.random((6, 1000))*2-1\n", 54 | "quiver = ipv.quickquiver(x, y, z, u, v, w, size=5)\n", 55 | "quiver" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 8, 61 | "metadata": {}, 62 | "outputs": [ 63 | { 64 | "data": { 65 | "application/vnd.jupyter.widget-view+json": { 66 | "model_id": "000f131c05ae42a49073cab7ceb3eed4", 67 | "version_major": 2, 68 | "version_minor": 0 69 | }, 70 | "text/plain": [ 71 | "VBox(children=(Figure(camera_center=[0.0, 0.0, 0.0], height=500, matrix_projection=[0.0, 0.0, 0.0, 0.0, 0.0, 0…" 72 | ] 73 | }, 74 | "metadata": {}, 75 | "output_type": "display_data" 76 | } 77 | ], 78 | "source": [ 79 | "import ipyvolume as ipv\n", 80 | "x, y, z, u, v = ipv.examples.klein_bottle(draw=False)\n", 81 | "ipv.figure()\n", 82 | "m = ipv.plot_mesh(x, y, z, wireframe=False)\n", 83 | "ipv.squarelim()\n", 84 | "ipv.show()" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": null, 90 | "metadata": {}, 91 | "outputs": [], 92 | "source": [] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 7, 97 | "metadata": {}, 98 | "outputs": [ 99 | { 100 | "data": { 101 | "application/vnd.jupyter.widget-view+json": { 102 | "model_id": "1e942613b84542c1b6bc31091aa78864", 103 | "version_major": 2, 104 | "version_minor": 0 105 | }, 106 | "text/plain": [ 107 | "VBox(children=(VBox(children=(Figure(camera_center=[0.0, 0.0, 0.0], height=500, matrix_projection=[0.0, 0.0, 0…" 108 | ] 109 | }, 110 | "metadata": {}, 111 | "output_type": "display_data" 112 | } 113 | ], 114 | "source": [ 115 | "import ipyvolume as ipv\n", 116 | "import numpy as np\n", 117 | "x, y, z, u, v, w = np.random.random((6, 1000))*2-1\n", 118 | "selected = np.random.randint(0, 1000, 100)\n", 119 | "ipv.figure()\n", 120 | "quiver = ipv.quiver(x, y, z, u, v, w, size=5, size_selected=8, selected=selected)\n", 121 | "\n", 122 | "from ipywidgets import FloatSlider, ColorPicker, VBox, jslink\n", 123 | "size = FloatSlider(min=0, max=30, step=0.1)\n", 124 | "size_selected = FloatSlider(min=0, max=30, step=0.1)\n", 125 | "color = ColorPicker()\n", 126 | "color_selected = ColorPicker()\n", 127 | "jslink((quiver, 'size'), (size, 'value'))\n", 128 | "jslink((quiver, 'size_selected'), (size_selected, 'value'))\n", 129 | "jslink((quiver, 'color'), (color, 'value'))\n", 130 | "jslink((quiver, 'color_selected'), (color_selected, 'value'))\n", 131 | "VBox([ipv.gcc(), size, size_selected, color, color_selected])" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": null, 137 | "metadata": {}, 138 | "outputs": [], 139 | "source": [] 140 | } 141 | ], 142 | "metadata": { 143 | "kernelspec": { 144 | "display_name": "Python 3", 145 | "language": "python", 146 | "name": "python3" 147 | }, 148 | "language_info": { 149 | "codemirror_mode": { 150 | "name": "ipython", 151 | "version": 3 152 | }, 153 | "file_extension": ".py", 154 | "mimetype": "text/x-python", 155 | "name": "python", 156 | "nbconvert_exporter": "python", 157 | "pygments_lexer": "ipython3", 158 | "version": "3.7.0" 159 | } 160 | }, 161 | "nbformat": 4, 162 | "nbformat_minor": 2 163 | } 164 | -------------------------------------------------------------------------------- /experimental/ipyvolume/Untitled2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "application/vnd.jupyter.widget-view+json": { 11 | "model_id": "a76fa34922294f8ea73d6b234907a99e", 12 | "version_major": 2, 13 | "version_minor": 0 14 | }, 15 | "text/plain": [ 16 | "VBox(children=(Figure(animation=200.0, animation_exponent=1.0, camera_center=[0.0, 0.0, 0.0], height=500, matr…" 17 | ] 18 | }, 19 | "metadata": {}, 20 | "output_type": "display_data" 21 | } 22 | ], 23 | "source": [ 24 | "import ipyvolume.pylab as p3\n", 25 | "import numpy as np\n", 26 | "\n", 27 | "# only x is a sequence of arrays\n", 28 | "x = np.array([[-1, -0.8], [1, -0.1], [0., 0.5]])\n", 29 | "y = np.array([0.0, 0.0])\n", 30 | "z = np.array([0.0, 0.0])\n", 31 | "p3.figure()\n", 32 | "s = p3.scatter(x, y, z)\n", 33 | "p3.xyzlim(-1, 1)\n", 34 | "p3.animation_control(s) # shows controls for animation controls\n", 35 | "p3.show()\n" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 2, 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "name": "stdout", 45 | "output_type": "stream", 46 | "text": [ 47 | "x,y and z are of shape (25, 25)\n", 48 | "and flattened of shape (625,)\n", 49 | "z is of shape (15, 625)\n" 50 | ] 51 | }, 52 | { 53 | "data": { 54 | "application/vnd.jupyter.widget-view+json": { 55 | "model_id": "282b4abf21bc4216a4b38ba3128b7da1", 56 | "version_major": 2, 57 | "version_minor": 0 58 | }, 59 | "text/plain": [ 60 | "VBox(children=(Figure(animation=200.0, animation_exponent=1.0, camera_center=[0.0, 0.0, 0.0], height=500, matr…" 61 | ] 62 | }, 63 | "metadata": {}, 64 | "output_type": "display_data" 65 | } 66 | ], 67 | "source": [ 68 | "# create 2d grids: x, y, and r\n", 69 | "u = np.linspace(-10, 10, 25)\n", 70 | "x, y = np.meshgrid(u, u)\n", 71 | "r = np.sqrt(x**2+y**2)\n", 72 | "print(\"x,y and z are of shape\", x.shape)\n", 73 | "\n", 74 | "# and turn them into 1d\n", 75 | "x = x.flatten()\n", 76 | "y = y.flatten()\n", 77 | "r = r.flatten()\n", 78 | "print(\"and flattened of shape\", x.shape)\n", 79 | "\n", 80 | "\n", 81 | "# create a sequence of 15 time elements\n", 82 | "time = np.linspace(0, np.pi*2, 15)\n", 83 | "z = np.array([(np.cos(r + t) * np.exp(-r/5)) for t in time])\n", 84 | "print(\"z is of shape\", z.shape)\n", 85 | "\n", 86 | "\n", 87 | "# draw the scatter plot, and add controls with animate_glyphs\n", 88 | "p3.figure()\n", 89 | "s = p3.scatter(x, z, y, marker=\"sphere\")\n", 90 | "p3.animation_control(s, interval=200)\n", 91 | "p3.ylim(-3,3)\n", 92 | "p3.show()" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": 3, 98 | "metadata": {}, 99 | "outputs": [ 100 | { 101 | "name": "stdout", 102 | "output_type": "stream", 103 | "text": [ 104 | "color is of shape (15, 3, 625)\n" 105 | ] 106 | }, 107 | { 108 | "data": { 109 | "application/vnd.jupyter.widget-view+json": { 110 | "model_id": "583f362ca0bc472595d3a8c7a98b00a4", 111 | "version_major": 2, 112 | "version_minor": 0 113 | }, 114 | "text/plain": [ 115 | "VBox(children=(Figure(animation=200.0, animation_exponent=1.0, camera_center=[0.0, 0.0, 0.0], height=500, matr…" 116 | ] 117 | }, 118 | "metadata": {}, 119 | "output_type": "display_data" 120 | } 121 | ], 122 | "source": [ 123 | "# Now also include, color, which containts rgb values\n", 124 | "color = np.array([[np.cos(r + t), 1-np.abs(z[i]), 0.1+z[i]*0] for i, t in enumerate(time)])\n", 125 | "size = (z+1)\n", 126 | "print(\"color is of shape\", color.shape)\n", 127 | "\n", 128 | "\n", 129 | "\n", 130 | "color = np.transpose(color, (0, 2, 1)) # flip the last axes\n", 131 | "\n", 132 | "p3.figure()\n", 133 | "s = p3.scatter(x, z, y, color=color, size=size, marker=\"sphere\")\n", 134 | "p3.animation_control(s, interval=200)\n", 135 | "p3.ylim(-3,3)\n", 136 | "p3.show()" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": null, 142 | "metadata": {}, 143 | "outputs": [], 144 | "source": [] 145 | } 146 | ], 147 | "metadata": { 148 | "kernelspec": { 149 | "display_name": "Python 3", 150 | "language": "python", 151 | "name": "python3" 152 | }, 153 | "language_info": { 154 | "codemirror_mode": { 155 | "name": "ipython", 156 | "version": 3 157 | }, 158 | "file_extension": ".py", 159 | "mimetype": "text/x-python", 160 | "name": "python", 161 | "nbconvert_exporter": "python", 162 | "pygments_lexer": "ipython3", 163 | "version": "3.7.0" 164 | } 165 | }, 166 | "nbformat": 4, 167 | "nbformat_minor": 2 168 | } 169 | -------------------------------------------------------------------------------- /experimental/widgets/applications/Factoring.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Factoring Polynomials with SymPy" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Here is an example that uses [SymPy](http://sympy.org/en/index.html) to factor polynomials." 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 1, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "from ipywidgets import interact" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 2, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "from sympy import Symbol, Eq, factor" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 3, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "x = Symbol('x')" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 4, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "def factorit(n):\n", 51 | " return Eq(x**n-1, factor(x**n-1))" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 5, 57 | "metadata": {}, 58 | "outputs": [ 59 | { 60 | "data": { 61 | "text/plain": [ 62 | "Eq(x**12 - 1, (x - 1)*(x + 1)*(x**2 + 1)*(x**2 - x + 1)*(x**2 + x + 1)*(x**4 - x**2 + 1))" 63 | ] 64 | }, 65 | "execution_count": 5, 66 | "metadata": {}, 67 | "output_type": "execute_result" 68 | } 69 | ], 70 | "source": [ 71 | "factorit(12)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 6, 77 | "metadata": {}, 78 | "outputs": [ 79 | { 80 | "data": { 81 | "application/vnd.jupyter.widget-view+json": { 82 | "model_id": "3f24e52f643e4e5383dca988983cca9e", 83 | "version_major": 2, 84 | "version_minor": 0 85 | }, 86 | "text/plain": [ 87 | "interactive(children=(IntSlider(value=21, description='n', max=40, min=2), Output()), _dom_classes=('widget-in…" 88 | ] 89 | }, 90 | "metadata": {}, 91 | "output_type": "display_data" 92 | } 93 | ], 94 | "source": [ 95 | "interact(factorit, n=(2,40));" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": null, 101 | "metadata": {}, 102 | "outputs": [], 103 | "source": [] 104 | } 105 | ], 106 | "metadata": { 107 | "kernelspec": { 108 | "display_name": "Python 3", 109 | "language": "python", 110 | "name": "python3" 111 | }, 112 | "language_info": { 113 | "codemirror_mode": { 114 | "name": "ipython", 115 | "version": 3 116 | }, 117 | "file_extension": ".py", 118 | "mimetype": "text/x-python", 119 | "name": "python", 120 | "nbconvert_exporter": "python", 121 | "pygments_lexer": "ipython3", 122 | "version": "3.7.0" 123 | }, 124 | "widgets": { 125 | "application/vnd.jupyter.widget-state+json": { 126 | "state": { 127 | "682f381cd5aa4f02a7a8312dcae01cd0": { 128 | "model_module": "@jupyter-widgets/controls", 129 | "model_module_version": "1.2.0", 130 | "model_name": "SliderStyleModel", 131 | "state": { 132 | "description_width": "" 133 | } 134 | }, 135 | "6de126c2da374e9f94b341aed648178b": { 136 | "model_module": "@jupyter-widgets/base", 137 | "model_module_version": "1.0.0", 138 | "model_name": "LayoutModel", 139 | "state": {} 140 | }, 141 | "772a2ccb3a0a4fbd9252616a2a5164cc": { 142 | "model_module": "@jupyter-widgets/base", 143 | "model_module_version": "1.0.0", 144 | "model_name": "LayoutModel", 145 | "state": {} 146 | }, 147 | "8dc6700c8f1c4e52a102fc9fd4f79da8": { 148 | "model_module": "@jupyter-widgets/output", 149 | "model_module_version": "1.0.0", 150 | "model_name": "OutputModel", 151 | "state": { 152 | "layout": "IPY_MODEL_c66a2093c5a641f6b3f741a85572b54d", 153 | "outputs": [ 154 | { 155 | "data": { 156 | "text/plain": "Eq(x**21 - 1, (x - 1)*(x**2 + x + 1)*(x**6 + x**5 + x**4 + x**3 + x**2 + x + 1)*(x**12 - x**11 + x**9 - x**8 + x**6 - x**4 + x**3 - x + 1))" 157 | }, 158 | "metadata": {}, 159 | "output_type": "display_data" 160 | } 161 | ] 162 | } 163 | }, 164 | "9fed22007d0e448d993e599820066da1": { 165 | "model_module": "@jupyter-widgets/controls", 166 | "model_module_version": "1.2.0", 167 | "model_name": "VBoxModel", 168 | "state": { 169 | "_dom_classes": [ 170 | "widget-interact" 171 | ], 172 | "children": [ 173 | "IPY_MODEL_f7bcb9ee8a18475db168ee5b973f2022", 174 | "IPY_MODEL_8dc6700c8f1c4e52a102fc9fd4f79da8" 175 | ], 176 | "layout": "IPY_MODEL_772a2ccb3a0a4fbd9252616a2a5164cc" 177 | } 178 | }, 179 | "c66a2093c5a641f6b3f741a85572b54d": { 180 | "model_module": "@jupyter-widgets/base", 181 | "model_module_version": "1.0.0", 182 | "model_name": "LayoutModel", 183 | "state": {} 184 | }, 185 | "f7bcb9ee8a18475db168ee5b973f2022": { 186 | "model_module": "@jupyter-widgets/controls", 187 | "model_module_version": "1.2.0", 188 | "model_name": "IntSliderModel", 189 | "state": { 190 | "description": "n", 191 | "layout": "IPY_MODEL_6de126c2da374e9f94b341aed648178b", 192 | "max": 40, 193 | "min": 2, 194 | "style": "IPY_MODEL_682f381cd5aa4f02a7a8312dcae01cd0", 195 | "value": 21 196 | } 197 | } 198 | }, 199 | "version_major": 2, 200 | "version_minor": 0 201 | } 202 | } 203 | }, 204 | "nbformat": 4, 205 | "nbformat_minor": 2 206 | } 207 | -------------------------------------------------------------------------------- /experimental/ipympl.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# The Matplotlib Jupyter Widget Backend\n", 8 | "\n", 9 | "Enabling interaction with matplotlib charts in the Jupyter notebook and JupyterLab\n", 10 | "\n", 11 | "https://github.com/matplotlib/jupyter-matplotlib" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 3, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "# Enabling the `widget` backend.\n", 21 | "# This requires jupyter-matplotlib a.k.a. ipympl.\n", 22 | "# ipympl can be install via pip or conda.\n", 23 | "%matplotlib widget" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 4, 29 | "metadata": {}, 30 | "outputs": [ 31 | { 32 | "data": { 33 | "application/vnd.jupyter.widget-view+json": { 34 | "model_id": "7da8f712c59e40a78067301f5a5c75c2", 35 | "version_major": 2, 36 | "version_minor": 0 37 | }, 38 | "text/plain": [ 39 | "FigureCanvasNbAgg()" 40 | ] 41 | }, 42 | "metadata": {}, 43 | "output_type": "display_data" 44 | } 45 | ], 46 | "source": [ 47 | "# Testing matplotlib interactions with a simple plot\n", 48 | "\n", 49 | "import matplotlib.pyplot as plt\n", 50 | "import numpy as np\n", 51 | "\n", 52 | "plt.figure(1)\n", 53 | "plt.plot(np.sin(np.linspace(0, 20, 100)))\n", 54 | "plt.show()" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": 12, 60 | "metadata": {}, 61 | "outputs": [ 62 | { 63 | "data": { 64 | "application/vnd.jupyter.widget-view+json": { 65 | "model_id": "0a7c53ea26d9404e81f721cd7fa2af54", 66 | "version_major": 2, 67 | "version_minor": 0 68 | }, 69 | "text/plain": [ 70 | "FigureCanvasNbAgg()" 71 | ] 72 | }, 73 | "metadata": {}, 74 | "output_type": "display_data" 75 | } 76 | ], 77 | "source": [ 78 | "# A more complex example from the matplotlib gallery\n", 79 | "\n", 80 | "import numpy as np\n", 81 | "import matplotlib.pyplot as plt\n", 82 | "\n", 83 | "np.random.seed(0)\n", 84 | "\n", 85 | "n_bins = 10\n", 86 | "x = np.random.randn(1000, 3)\n", 87 | "\n", 88 | "fig, axes = plt.subplots(nrows=2, ncols=2)\n", 89 | "ax0, ax1, ax2, ax3 = axes.flatten()\n", 90 | "\n", 91 | "colors = ['red', 'tan', 'lime']\n", 92 | "ax0.hist(x, n_bins, density=1, histtype='bar', color=colors, label=colors)\n", 93 | "ax0.legend(prop={'size': 10})\n", 94 | "ax0.set_title('bars with legend')\n", 95 | "\n", 96 | "ax1.hist(x, n_bins, density=1, histtype='bar', stacked=True)\n", 97 | "ax1.set_title('stacked bar')\n", 98 | "\n", 99 | "ax2.hist(x, n_bins, histtype='step', stacked=True, fill=False)\n", 100 | "ax2.set_title('stack step (unfilled)')\n", 101 | "\n", 102 | "# Make a multiple-histogram of data-sets with different length.\n", 103 | "x_multi = [np.random.randn(n) for n in [10000, 5000, 2000]]\n", 104 | "ax3.hist(x_multi, n_bins, histtype='bar')\n", 105 | "ax3.set_title('different sample sizes')\n", 106 | "\n", 107 | "\n", 108 | "fig.tight_layout()\n", 109 | "plt.show()" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": 13, 115 | "metadata": {}, 116 | "outputs": [ 117 | { 118 | "data": { 119 | "application/vnd.jupyter.widget-view+json": { 120 | "model_id": "09b306227930436c927d73f4abe4fc25", 121 | "version_major": 2, 122 | "version_minor": 0 123 | }, 124 | "text/plain": [ 125 | "HBox(children=(FloatSlider(value=1.0, max=2.0, min=0.02, orientation='vertical'), FigureCanvasNbAgg()))" 126 | ] 127 | }, 128 | "metadata": {}, 129 | "output_type": "display_data" 130 | } 131 | ], 132 | "source": [ 133 | "# When using the `widget` backend from ipympl,\n", 134 | "# fig.canvas is a proper Jupyter interactive widget, which can be embedded in\n", 135 | "# Layout classes like HBox and Vbox.\n", 136 | "\n", 137 | "# One can bound figure attributes to other widget values.\n", 138 | "\n", 139 | "from ipywidgets import HBox, FloatSlider\n", 140 | "\n", 141 | "plt.ioff()\n", 142 | "plt.clf()\n", 143 | "\n", 144 | "slider = FloatSlider(\n", 145 | " orientation='vertical',\n", 146 | " value=1.0,\n", 147 | " min=0.02,\n", 148 | " max=2.0\n", 149 | ")\n", 150 | "\n", 151 | "fig = plt.figure(3)\n", 152 | "\n", 153 | "x = np.linspace(0, 20, 500)\n", 154 | "\n", 155 | "lines = plt.plot(x, np.sin(slider.value * x))\n", 156 | "\n", 157 | "def update_lines(change):\n", 158 | " lines[0].set_data(x, np.sin(change.new * x))\n", 159 | " fig.canvas.draw()\n", 160 | " fig.canvas.flush_events()\n", 161 | "\n", 162 | "slider.observe(update_lines, names='value')\n", 163 | "\n", 164 | "HBox([slider, fig.canvas])" 165 | ] 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "metadata": {}, 170 | "source": [ 171 | "### " 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "execution_count": null, 177 | "metadata": {}, 178 | "outputs": [], 179 | "source": [] 180 | } 181 | ], 182 | "metadata": { 183 | "kernelspec": { 184 | "display_name": "Python 3", 185 | "language": "python", 186 | "name": "python3" 187 | }, 188 | "language_info": { 189 | "codemirror_mode": { 190 | "name": "ipython", 191 | "version": 3 192 | }, 193 | "file_extension": ".py", 194 | "mimetype": "text/x-python", 195 | "name": "python", 196 | "nbconvert_exporter": "python", 197 | "pygments_lexer": "ipython3", 198 | "version": "3.7.0" 199 | } 200 | }, 201 | "nbformat": 4, 202 | "nbformat_minor": 2 203 | } 204 | -------------------------------------------------------------------------------- /lantern/plotting/plot_bokeh.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import pandas as pd 3 | from bokeh.plotting import figure, show, output_notebook 4 | from bokeh.models import Legend, Span 5 | # from bokeh.models import HoverTool 6 | from ..utils import in_ipynb 7 | from .plotobj import BasePlot 8 | from .plotutils import get_color 9 | 10 | _INITED = False 11 | 12 | 13 | class BokehPlot(BasePlot): 14 | def __init__(self, size=None, theme=None): 15 | global _INITED 16 | if not _INITED: 17 | if in_ipynb(): 18 | output_notebook(hide_banner=True) 19 | 20 | size = size or (800, 500) 21 | self.width = size[0] 22 | self.height = size[1] 23 | self.figure = figure(toolbar_location="below", 24 | toolbar_sticky=False, 25 | x_axis_type='datetime', 26 | plot_width=self.width, 27 | plot_height=self.height) # TODO remove 28 | self.legend = [] 29 | 30 | def show(self, title='', xlabel='', ylabel='', xaxis=True, yaxis=True, xticks=True, yticks=True, legend=True, grid=True, **kwargs): 31 | # self.figure.add_tools(*[HoverTool( 32 | # tooltips=[('x', '@x{%F}'), ('y', '@y')], 33 | # formatters={'x': 'datetime'}, 34 | # mode='vline' 35 | # ) for _ in data]) 36 | 37 | self.figure.outline_line_color = None 38 | # vline = Span(location=0, dimension='height', line_color='red', line_width=3) 39 | hline = Span(location=0, dimension='width', line_color='black', line_width=1) 40 | self.figure.renderers.append(hline) 41 | 42 | if xlabel: 43 | self.figure.xaxis.axis_label = kwargs.get('xlabel') 44 | if ylabel: 45 | self.figure.yaxis.axis_label = kwargs.get('ylabel') 46 | if title: 47 | self.figure.title.text = kwargs.get('title') 48 | 49 | if legend: 50 | self.figure.legend.location = (self.width + 10, self.height + 10) 51 | legend = Legend(items=self.legend, location=(10, 100)) 52 | legend.items = self.legend 53 | legend.click_policy = "mute" 54 | self.figure.add_layout(legend, 'right') 55 | else: 56 | self.figure.legend.location = None 57 | 58 | if not grid: 59 | self.figure.xgrid.grid_line_color = None 60 | self.figure.ygrid.grid_line_color = None 61 | 62 | # FIXME 63 | if not yaxis: 64 | for ax in self.figure.yaxis: 65 | ax.axis_line_color = 'white' 66 | if not xaxis: 67 | for ax in self.figure.xaxis: 68 | ax.axis_line_color = 'white' 69 | 70 | # Turn off labels: 71 | # self.figure.xaxis.major_label_text_font_size = '0pt' 72 | 73 | show(self.figure) 74 | return self.figure 75 | 76 | def area(self, data, color=None, y_axis='left', stacked=False, **kwargs): 77 | data2 = data.append(data.iloc[-1] * 0) 78 | data2 = data2.append(data2.iloc[0] * 0) 79 | data2 = data2.sort_index() 80 | data2 = data2.sort_index() 81 | x, y = copy.deepcopy(data2.iloc[0]), copy.deepcopy(data2.iloc[1]) 82 | data2.iloc[0], data2.iloc[1] = y, x 83 | 84 | for i, col in enumerate(data): 85 | c = get_color(i, col, color) 86 | fig = self.figure.patch(x=data2.index, y=data2[col].values, legend=col, fill_alpha=.2, color=c, **kwargs) 87 | self.legend.append((col, [fig])) 88 | 89 | # for stacked: https://bokeh.pydata.org/en/latest/docs/gallery/brewer.html 90 | # p.patches([x2] * areas.shape[1], [areas[c].values for c in areas], color=colors, alpha=0.8, line_color=None) 91 | 92 | def _stacked(df): 93 | df_top = df.cumsum(axis=1) 94 | df_bottom = df_top.shift(axis=1).fillna({'y0': 0})[::-1] 95 | df_stack = pd.concat([df_bottom, df_top], ignore_index=True) 96 | return df_stack 97 | 98 | def bar(self, data, color=None, y_axis='left', stacked=False, **kwargs): 99 | # stacked bar: https://bokeh.pydata.org/en/latest/docs/gallery/bar_stacked.html 100 | # stacked bar: https://bokeh.pydata.org/en/latest/docs/gallery/bar_stacked_split.html 101 | c = [] 102 | for i, col in enumerate(data): 103 | c.append(get_color(i, col, color)) 104 | fig = self.figure.vbar(x=data.index, top=data[col].values, width=.9, color=c, **kwargs) 105 | self.legend.append((col, [fig])) 106 | 107 | def hist(self, data, color=None, y_axis='left', stacked=False, **kwargs): 108 | raise NotImplementedError() 109 | 110 | def hline(self, y, color=None, **kwargs): 111 | raise NotImplementedError() 112 | 113 | def hspan(self, yhigh, ylow=0, color=None, **kwargs): 114 | raise NotImplementedError() 115 | 116 | # def candlestick(self, data): 117 | # # https://bokeh.pydata.org/en/latest/docs/gallery/candlestick.html 118 | 119 | def line(self, data, color=None, y_axis='left', **kwargs): 120 | for i, col in enumerate(data): 121 | c = get_color(i, col, color) 122 | fig = self.figure.line(x=data.index, y=data[col].values, legend=col, color=c, **kwargs) 123 | self.legend.append((col, [fig])) 124 | 125 | def scatter(self, data, color=None, y_axis='left', **kwargs): 126 | for i, col in enumerate(data): 127 | if i == 0: 128 | continue # don't scatter against self 129 | x = data.columns[0] 130 | y = data.columns[i] 131 | c = get_color(i, col, color) 132 | fig = self.figure.scatter(x=data[x], 133 | y=data[y], 134 | legend='%s vs %s' % (x, y), 135 | fill_color=c, 136 | fill_alpha=0.6, 137 | line_color=None, 138 | **kwargs) 139 | self.legend.append(('%s vs %s' % (x, y), [fig])) 140 | 141 | def step(self, data, color=None, y_axis='left', **kwargs): 142 | raise NotImplementedError() 143 | 144 | def vline(self, x, color=None, **kwargs): 145 | raise NotImplementedError() 146 | 147 | def vspan(self, xhigh, xlow=0, color=None, **kwargs): 148 | raise NotImplementedError() 149 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # lantern documentation build configuration file, created by 5 | # sphinx-quickstart on Fri Jan 12 22:07:11 2018. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | # 20 | import sys 21 | import os 22 | import os.path 23 | import subprocess 24 | import sphinx_rtd_theme 25 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) 26 | import sphinx_rtd_theme 27 | 28 | # -- General configuration ------------------------------------------------ 29 | 30 | # If your documentation needs a minimal Sphinx version, state it here. 31 | # 32 | # needs_sphinx = '1.0' 33 | 34 | # Add any Sphinx extension module names here, as strings. They can be 35 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 36 | # ones. 37 | extensions = ['sphinx.ext.coverage', 'sphinx.ext.viewcode', 'sphinx.ext.autodoc', 'sphinx.ext.napoleon'] 38 | 39 | # Add any paths that contain templates here, relative to this directory. 40 | templates_path = ['_templates'] 41 | 42 | # The suffix(es) of source filenames. 43 | # You can specify multiple suffix as a list of string: 44 | # 45 | # source_suffix = ['.rst', '.md'] 46 | source_suffix = '.rst' 47 | 48 | # The master toctree document. 49 | master_doc = 'index' 50 | 51 | # General information about the project. 52 | project = 'lantern' 53 | copyright = '2018, Tim Paine' 54 | author = 'Tim Paine' 55 | 56 | # The version info for the project you're documenting, acts as replacement for 57 | # |version| and |release|, also used in various other places throughout the 58 | # built documents. 59 | # 60 | # The short X.Y version. 61 | version = 'v0.1.6' 62 | # The full version, including alpha/beta/rc tags. 63 | release = 'v0.1.6' 64 | 65 | # The language for content autogenerated by Sphinx. Refer to documentation 66 | # for a list of supported languages. 67 | # 68 | # This is also used if you do content translation via gettext catalogs. 69 | # Usually you set "language" from the command line for these cases. 70 | language = None 71 | 72 | # List of patterns, relative to source directory, that match files and 73 | # directories to ignore when looking for source files. 74 | # This patterns also effect to html_static_path and html_extra_path 75 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 76 | 77 | # The name of the Pygments (syntax highlighting) style to use. 78 | pygments_style = 'sphinx' 79 | 80 | # If true, `todo` and `todoList` produce output, else they produce nothing. 81 | todo_include_todos = False 82 | 83 | 84 | # -- Options for HTML output ---------------------------------------------- 85 | 86 | # The theme to use for HTML and HTML Help pages. See the documentation for 87 | # a list of builtin themes. 88 | # 89 | # html_theme = 'alabaster' 90 | html_theme = "sphinx_rtd_theme" 91 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 92 | 93 | # Theme options are theme-specific and customize the look and feel of a theme 94 | # further. For a list of options available for each theme, see the 95 | # documentation. 96 | # 97 | # html_theme_options = {} 98 | 99 | # Add any paths that contain custom static files (such as style sheets) here, 100 | # relative to this directory. They are copied after the builtin static files, 101 | # so a file named "default.css" will overwrite the builtin "default.css". 102 | html_static_path = ['_static'] 103 | 104 | # Custom sidebar templates, must be a dictionary that maps document names 105 | # to template names. 106 | # 107 | # This is required for the alabaster theme 108 | # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars 109 | html_sidebars = { 110 | '**': [ 111 | 'relations.html', # needs 'show_related': True theme option to display 112 | 'searchbox.html', 113 | ] 114 | } 115 | 116 | 117 | # -- Options for HTMLHelp output ------------------------------------------ 118 | 119 | # Output file base name for HTML help builder. 120 | htmlhelp_basename = 'lanterndoc' 121 | 122 | 123 | # -- Options for LaTeX output --------------------------------------------- 124 | 125 | latex_elements = { 126 | # The paper size ('letterpaper' or 'a4paper'). 127 | # 128 | # 'papersize': 'letterpaper', 129 | 130 | # The font size ('10pt', '11pt' or '12pt'). 131 | # 132 | # 'pointsize': '10pt', 133 | 134 | # Additional stuff for the LaTeX preamble. 135 | # 136 | # 'preamble': '', 137 | 138 | # Latex figure (float) alignment 139 | # 140 | # 'figure_align': 'htbp', 141 | } 142 | 143 | # Grouping the document tree into LaTeX files. List of tuples 144 | # (source start file, target name, title, 145 | # author, documentclass [howto, manual, or own class]). 146 | latex_documents = [ 147 | (master_doc, 'lantern.tex', 'lantern Documentation', 148 | 'Tim Paine', 'manual'), 149 | ] 150 | 151 | 152 | # -- Options for manual page output --------------------------------------- 153 | 154 | # One entry per manual page. List of tuples 155 | # (source start file, name, description, authors, manual section). 156 | man_pages = [ 157 | (master_doc, 'lantern', 'lantern Documentation', 158 | [author], 1) 159 | ] 160 | 161 | 162 | # -- Options for Texinfo output ------------------------------------------- 163 | 164 | # Grouping the document tree into Texinfo files. List of tuples 165 | # (source start file, target name, title, author, 166 | # dir menu entry, description, category) 167 | texinfo_documents = [ 168 | (master_doc, 'lantern', 'lantern Documentation', 169 | author, 'lantern', 'One line description of project.', 170 | 'Miscellaneous'), 171 | ] 172 | 173 | 174 | def run_apidoc(_): 175 | out_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'api')) 176 | proj_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'lantern')) 177 | cmd_path = 'sphinx-apidoc' 178 | if hasattr(sys, 'real_prefix'): # Check to see if we are in a virtualenv 179 | # If we are, assemble the path manually 180 | cmd_path = os.path.abspath(os.path.join(sys.prefix, 'bin', 'sphinx-apidoc')) 181 | subprocess.check_call([cmd_path, 182 | '-E', 183 | '-M', 184 | '-o', 185 | out_dir, 186 | proj_dir, 187 | '--force']) 188 | 189 | 190 | def setup(app): 191 | app.connect('builder-inited', run_apidoc) 192 | -------------------------------------------------------------------------------- /lantern/data/other.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import string 4 | import mimesis 5 | import finance_enums 6 | from faker import Faker 7 | from datetime import date, timedelta 8 | from random import seed, random, sample, randint, choice 9 | 10 | try: 11 | xrange # noqa: F821 12 | range = xrange # noqa: F821 13 | except NameError: 14 | pass 15 | 16 | seed(1) 17 | fake = Faker() 18 | 19 | _MIMESIS_LOCALES = ('cs', 'da', 'de', 'el', 'en', 'es', 'et', 'fa', 'fi', 'fr', 'hu', 'is', 'it', 'ja', 'kk', 'ko', 'nl', 'no', 'pl', 'pt', 'ru', 'sv', 'tr', 'uk', 'zh') 20 | 21 | 22 | def _genAsciiTicker(): 23 | return ''.join(sample(string.ascii_uppercase, randint(3, 4))) 24 | 25 | 26 | def _genNumTicker(count=4): 27 | return ''.join([str(randint(0, 9)) for _ in range(count)]) 28 | 29 | 30 | def _genExchangeCode(): 31 | return ''.join(sample(string.ascii_uppercase, randint(1, 2))) 32 | 33 | 34 | def _genEquityTicker(country='any'): 35 | western = [_genAsciiTicker() + '.' + _genExchangeCode() for _ in range(10)] 36 | jp_hk = [_genNumTicker() + '.' + _genExchangeCode() for _ in range(5)] 37 | kr = [_genNumTicker(6) + '.' + _genExchangeCode() for _ in range(6)] 38 | if country.lower() == 'any': 39 | return choice(western + jp_hk + kr) 40 | elif country.lower() in ['jp', 'hk']: 41 | return choice(jp_hk) 42 | elif country.lower() in ['kr']: 43 | return choice(kr) 44 | else: 45 | return choice(western) 46 | 47 | 48 | def ticker(type='equity', country='any'): 49 | return _genEquityTicker() 50 | 51 | 52 | def getTsData(series=2, datetime_index=True, trend=.47, volatility=1): 53 | random_walk = np.zeros((1000, series)) 54 | randbase = random() 55 | random_walk[0] = np.array([-1 * randbase * volatility if random() < trend else randbase * volatility for _ in range(series)]) 56 | for i in range(1, 1000): 57 | movement = np.array([-1 * random() * volatility if random() < trend else random() * volatility for _ in range(series)]) 58 | random_walk[i] = random_walk[i - 1] + movement 59 | 60 | ret = pd.DataFrame(random_walk, columns=['Series ' + str(x) for x in range(series)]) 61 | 62 | if datetime_index is True: 63 | ret.index = np.array([date.today() - timedelta(days=1000) + timedelta(x) for x in range(1000)]) 64 | return ret 65 | 66 | 67 | # mimesis 68 | def _company(): 69 | return mimesis.Business().company() 70 | 71 | 72 | def _companytype(): 73 | return mimesis.Business().company_type() 74 | 75 | 76 | def _mname(locale='en'): 77 | return mimesis.Person(locale).full_name() 78 | 79 | 80 | def _occupation(locale='en'): 81 | return mimesis.Person(locale).occupation() 82 | 83 | 84 | # Fakers 85 | # names 86 | def _name(): 87 | return fake.name() 88 | 89 | 90 | # locations 91 | def _address(): 92 | return fake.address() 93 | 94 | 95 | def _email(): 96 | return fake.email() 97 | 98 | 99 | def _countrycode(): 100 | return fake.bank_country() 101 | 102 | 103 | def _city(): 104 | return fake.city() 105 | 106 | 107 | def _phone_number(): 108 | return fake.phone_number() 109 | 110 | 111 | def _zipcode(): 112 | return fake.zipcode() 113 | 114 | 115 | # other 116 | def _currencycode(): 117 | return fake.currency_code() 118 | 119 | 120 | # pickers 121 | def person(locale=None): 122 | if locale is None: 123 | locales = _MIMESIS_LOCALES 124 | else: 125 | locales = [locale] 126 | p = mimesis.Person(locale=choice(locales)) 127 | gender = choice(['Male'] * 20 + ['Female'] * 21 + ['Other']) 128 | 129 | g = mimesis.enums.Gender.MALE if gender.lower() == 'male' else mimesis.enums.Gender.FEMALE 130 | first = p.name(g) 131 | last = p.last_name(g) 132 | 133 | return { 134 | 'first_name': first, 135 | 'last_name': last, 136 | 'name': first + ' ' + last, # western 137 | 'age': p.age(), 138 | 'gender': gender, 139 | 'id': p.identifier(), 140 | 'occupation': p.occupation(), 141 | 'telephone': p.telephone(), 142 | 'title': p.title(g), 143 | 'username': p.username(), 144 | 'university': p.university(), 145 | } 146 | 147 | 148 | def people(count=50, locale=None): 149 | acc = [] 150 | for _ in range(count): 151 | acc.append(person(locale)) 152 | return pd.DataFrame(acc) 153 | 154 | 155 | def company(exchanges=None): 156 | sector = choice(list(finance_enums.US_SECTORS)) 157 | industry = choice(list(finance_enums.US_SECTORS_MAP[sector])) 158 | if exchanges: 159 | exchange = choice(exchanges) 160 | else: 161 | exchange = _genExchangeCode() 162 | 163 | return { 164 | 'name': fake.company(), 165 | 'address': _address(), 166 | 'ticker': _genAsciiTicker(), 167 | 'last_price': random() * 100, 168 | 'market_cap': randint(10**8, 10**11), 169 | 'exchange': exchange, 170 | 'ceo': _name(), 171 | 'sector': sector, 172 | 'industry': industry, 173 | } 174 | 175 | 176 | def companies(count=1000): 177 | exchanges = [_genExchangeCode() for _ in range(5)] 178 | acc = [] 179 | for _ in range(count): 180 | acc.append(company(exchanges)) 181 | return pd.DataFrame(acc) 182 | 183 | 184 | def currency(): 185 | return _currencycode() 186 | 187 | 188 | def trades(count=1000, interval='daily'): 189 | if interval not in ('daily', 'intraday'): 190 | raise Exception('interval must be in ("daily", "intraday")') 191 | comps = companies(100) 192 | 193 | acc = [] 194 | for _ in range(count): 195 | row = comps.sample().to_dict(orient='records')[-1] 196 | row.pop('address') 197 | row.pop('ceo') 198 | row['volume'] = randint(1, 100) * 10 199 | row['price'] = (random() - .5) * 10 + row['last_price'] 200 | acc.append(row) 201 | return pd.DataFrame(acc) 202 | 203 | 204 | def superstore(count=1000): 205 | data = [] 206 | for id in range(count): 207 | dat = {} 208 | dat['Row ID'] = id 209 | dat['Order ID'] = fake.ein() 210 | dat['Order Date'] = fake.date_this_year() 211 | dat['Ship Date'] = fake.date_between_dates(dat['Order Date']).strftime('%Y-%m-%d') 212 | dat['Order Date'] = dat['Order Date'].strftime('%Y-%m-%d') 213 | dat['Ship Mode'] = choice(['First Class', 'Standard Class', 'Second Class']) 214 | dat['Ship Mode'] = choice(['First Class', 'Standard Class', 'Second Class']) 215 | dat['Customer ID'] = fake.license_plate() 216 | dat['Segment'] = choice(['A', 'B', 'C', 'D']) 217 | dat['Country'] = 'US' 218 | dat['City'] = fake.city() 219 | dat['State'] = fake.state() 220 | dat['Postal Code'] = fake.zipcode() 221 | dat['Region'] = choice(['Region %d' % i for i in range(5)]) 222 | dat['Product ID'] = fake.bban() 223 | sector = choice(list(finance_enums.US_SECTORS)) 224 | industry = choice(list(finance_enums.US_SECTORS_MAP[sector])) 225 | dat['Category'] = sector 226 | dat['Sub-Category'] = industry 227 | dat['Sales'] = randint(1, 100) * 100 228 | dat['Quantity'] = randint(1, 100) * 10 229 | dat['Discount'] = round(random() * 100, 2) 230 | dat['Profit'] = round(random() * 1000, 2) 231 | data.append(dat) 232 | return pd.DataFrame(data) 233 | -------------------------------------------------------------------------------- /docs/rstref.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | The reStructuredText_ Cheat Sheet: Syntax Reminders 3 | ===================================================== 4 | :Info: See for introductory docs. 5 | :Author: David Goodger 6 | :Date: $Date: 2013-02-20 01:10:53 +0000 (Wed, 20 Feb 2013) $ 7 | :Revision: $Revision: 7612 $ 8 | :Description: This is a "docinfo block", or bibliographic field list 9 | 10 | .. NOTE:: If you are reading this as HTML, please read 11 | ``_ instead to see the input syntax examples! 12 | 13 | Section Structure 14 | ================= 15 | Section titles are underlined or overlined & underlined. 16 | 17 | Body Elements 18 | ============= 19 | Grid table: 20 | 21 | +--------------------------------+-----------------------------------+ 22 | | Paragraphs are flush-left, | Literal block, preceded by "::":: | 23 | | separated by blank lines. | | 24 | | | Indented | 25 | | Block quotes are indented. | | 26 | +--------------------------------+ or:: | 27 | | >>> print 'Doctest block' | | 28 | | Doctest block | > Quoted | 29 | +--------------------------------+-----------------------------------+ 30 | | | Line blocks preserve line breaks & indents. [new in 0.3.6] | 31 | | | Useful for addresses, verse, and adornment-free lists; long | 32 | | lines can be wrapped with continuation lines. | 33 | +--------------------------------------------------------------------+ 34 | 35 | Simple tables: 36 | 37 | ================ ============================================================ 38 | List Type Examples (syntax in the `text source `_) 39 | ================ ============================================================ 40 | Bullet list * items begin with "-", "+", or "*" 41 | Enumerated list 1. items use any variation of "1.", "A)", and "(i)" 42 | #. also auto-enumerated 43 | Definition list Term is flush-left : optional classifier 44 | Definition is indented, no blank line between 45 | Field list :field name: field body 46 | Option list -o at least 2 spaces between option & description 47 | ================ ============================================================ 48 | 49 | ================ ============================================================ 50 | Explicit Markup Examples (visible in the `text source`_) 51 | ================ ============================================================ 52 | Footnote .. [1] Manually numbered or [#] auto-numbered 53 | (even [#labelled]) or [*] auto-symbol 54 | Citation .. [CIT2002] A citation. 55 | Hyperlink Target .. _reStructuredText: http://docutils.sf.net/rst.html 56 | .. _indirect target: reStructuredText_ 57 | .. _internal target: 58 | Anonymous Target __ http://docutils.sf.net/docs/ref/rst/restructuredtext.html 59 | Directive ("::") .. image:: images/biohazard.png 60 | Substitution Def .. |substitution| replace:: like an inline directive 61 | Comment .. is anything else 62 | Empty Comment (".." on a line by itself, with blank lines before & after, 63 | used to separate indentation contexts) 64 | ================ ============================================================ 65 | 66 | Inline Markup 67 | ============= 68 | *emphasis*; **strong emphasis**; `interpreted text`; `interpreted text 69 | with role`:emphasis:; ``inline literal text``; standalone hyperlink, 70 | http://docutils.sourceforge.net; named reference, reStructuredText_; 71 | `anonymous reference`__; footnote reference, [1]_; citation reference, 72 | [CIT2002]_; |substitution|; _`inline internal target`. 73 | 74 | Directive Quick Reference 75 | ========================= 76 | See for full info. 77 | 78 | ================ ============================================================ 79 | Directive Name Description (Docutils version added to, in [brackets]) 80 | ================ ============================================================ 81 | attention Specific admonition; also "caution", "danger", 82 | "error", "hint", "important", "note", "tip", "warning" 83 | admonition Generic titled admonition: ``.. admonition:: By The Way`` 84 | image ``.. image:: picture.png``; many options possible 85 | figure Like "image", but with optional caption and legend 86 | topic ``.. topic:: Title``; like a mini section 87 | sidebar ``.. sidebar:: Title``; like a mini parallel document 88 | parsed-literal A literal block with parsed inline markup 89 | rubric ``.. rubric:: Informal Heading`` 90 | epigraph Block quote with class="epigraph" 91 | highlights Block quote with class="highlights" 92 | pull-quote Block quote with class="pull-quote" 93 | compound Compound paragraphs [0.3.6] 94 | container Generic block-level container element [0.3.10] 95 | table Create a titled table [0.3.1] 96 | list-table Create a table from a uniform two-level bullet list [0.3.8] 97 | csv-table Create a table from CSV data [0.3.4] 98 | contents Generate a table of contents 99 | sectnum Automatically number sections, subsections, etc. 100 | header, footer Create document decorations [0.3.8] 101 | target-notes Create an explicit footnote for each external target 102 | math Mathematical notation (input in LaTeX format) 103 | meta HTML-specific metadata 104 | include Read an external reST file as if it were inline 105 | raw Non-reST data passed untouched to the Writer 106 | replace Replacement text for substitution definitions 107 | unicode Unicode character code conversion for substitution defs 108 | date Generates today's date; for substitution defs 109 | class Set a "class" attribute on the next element 110 | role Create a custom interpreted text role [0.3.2] 111 | default-role Set the default interpreted text role [0.3.10] 112 | title Set the metadata document title [0.3.10] 113 | ================ ============================================================ 114 | 115 | Interpreted Text Role Quick Reference 116 | ===================================== 117 | See for full info. 118 | 119 | ================ ============================================================ 120 | Role Name Description 121 | ================ ============================================================ 122 | emphasis Equivalent to *emphasis* 123 | literal Equivalent to ``literal`` but processes backslash escapes 124 | math Mathematical notation (input in LaTeX format) 125 | PEP Reference to a numbered Python Enhancement Proposal 126 | RFC Reference to a numbered Internet Request For Comments 127 | raw For non-reST data; cannot be used directly (see docs) [0.3.6] 128 | strong Equivalent to **strong** 129 | sub Subscript 130 | sup Superscript 131 | title Title reference (book, etc.); standard default role 132 | ================ ============================================================ -------------------------------------------------------------------------------- /experimental/widgets/6_Widget Asynchronous.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "nbsphinx": "hidden" 7 | }, 8 | "source": [ 9 | "[Index](Index.ipynb) - [Back](Widget Custom.ipynb)" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "# Asynchronous Widgets\n", 17 | "\n", 18 | "This notebook covers two scenarios where we'd like widget-related code to run without blocking the kernel from acting on other execution requests:\n", 19 | "\n", 20 | "1. Pausing code to wait for user interaction with a widget in the frontend\n", 21 | "2. Updating a widget in the background" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "## Waiting for user interaction" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "You may want to pause your Python code to wait for some user interaction with a widget from the frontend. Typically this would be hard to do since running Python code blocks any widget messages from the frontend until the Python code is done.\n", 36 | "\n", 37 | "We'll do this in two approaches: using the event loop integration, and using plain generator functions." 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "### Event loop integration\n", 45 | "\n", 46 | "If we take advantage of the event loop integration IPython offers, we can have a nice solution using the async/await syntax in Python 3.\n", 47 | "\n", 48 | "First we invoke our asyncio event loop. This requires ipykernel 4.7 or later." 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 1, 54 | "metadata": { 55 | "collapsed": true 56 | }, 57 | "outputs": [], 58 | "source": [ 59 | "%gui asyncio" 60 | ] 61 | }, 62 | { 63 | "cell_type": "markdown", 64 | "metadata": {}, 65 | "source": [ 66 | "We define a new function that returns a future for when a widget attribute changes." 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 2, 72 | "metadata": { 73 | "collapsed": true 74 | }, 75 | "outputs": [], 76 | "source": [ 77 | "import asyncio\n", 78 | "def wait_for_change(widget, value):\n", 79 | " future = asyncio.Future()\n", 80 | " def getvalue(change):\n", 81 | " # make the new value available\n", 82 | " future.set_result(change.new)\n", 83 | " widget.unobserve(getvalue, value)\n", 84 | " widget.observe(getvalue, value)\n", 85 | " return future" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "metadata": {}, 91 | "source": [ 92 | "And we finally get to our function where we will wait for widget changes. We'll do 10 units of work, and pause after each one until we observe a change in the widget. Notice that the widget's value is available to us, since it is what the `wait_for_change` future has as a result.\n", 93 | "\n", 94 | "Run this function, and change the slider 10 times." 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": 3, 100 | "metadata": { 101 | "collapsed": true 102 | }, 103 | "outputs": [ 104 | { 105 | "data": { 106 | "application/vnd.jupyter.widget-view+json": { 107 | "model_id": "5cdbbdc61cf34dd998d910023d5e257f", 108 | "version_major": 2, 109 | "version_minor": 0 110 | }, 111 | "text/plain": [ 112 | "IntSlider(value=0)" 113 | ] 114 | }, 115 | "metadata": {}, 116 | "output_type": "display_data" 117 | }, 118 | { 119 | "name": "stdout", 120 | "output_type": "stream", 121 | "text": [ 122 | "did work 0\n" 123 | ] 124 | } 125 | ], 126 | "source": [ 127 | "from ipywidgets import IntSlider\n", 128 | "slider = IntSlider()\n", 129 | "\n", 130 | "async def f():\n", 131 | " for i in range(10):\n", 132 | " print('did work %s'%i)\n", 133 | " x = await wait_for_change(slider, 'value')\n", 134 | " print('async function continued with value %s'%x)\n", 135 | "asyncio.ensure_future(f())\n", 136 | "\n", 137 | "slider" 138 | ] 139 | }, 140 | { 141 | "cell_type": "markdown", 142 | "metadata": {}, 143 | "source": [ 144 | "### Generator approach\n", 145 | "\n", 146 | "If you can't take advantage of the async/await syntax, or you don't want to modify the event loop, you can also do this with generator functions." 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "metadata": {}, 152 | "source": [ 153 | "First, we define a decorator which hooks a generator function up to widget change events." 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": 4, 159 | "metadata": { 160 | "collapsed": true 161 | }, 162 | "outputs": [], 163 | "source": [ 164 | "from functools import wraps\n", 165 | "def yield_for_change(widget, attribute):\n", 166 | " \"\"\"Pause a generator to wait for a widget change event.\n", 167 | " \n", 168 | " This is a decorator for a generator function which pauses the generator on yield\n", 169 | " until the given widget attribute changes. The new value of the attribute is\n", 170 | " sent to the generator and is the value of the yield.\n", 171 | " \"\"\"\n", 172 | " def f(iterator):\n", 173 | " @wraps(iterator)\n", 174 | " def inner():\n", 175 | " i = iterator()\n", 176 | " def next_i(change):\n", 177 | " try:\n", 178 | " i.send(change.new)\n", 179 | " except StopIteration as e:\n", 180 | " widget.unobserve(next_i, attribute)\n", 181 | " widget.observe(next_i, attribute)\n", 182 | " # start the generator\n", 183 | " next(i)\n", 184 | " return inner\n", 185 | " return f" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": {}, 191 | "source": [ 192 | "Then we set up our generator." 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": 5, 198 | "metadata": { 199 | "collapsed": true 200 | }, 201 | "outputs": [ 202 | { 203 | "name": "stdout", 204 | "output_type": "stream", 205 | "text": [ 206 | "did work 0\n" 207 | ] 208 | }, 209 | { 210 | "data": { 211 | "application/vnd.jupyter.widget-view+json": { 212 | "model_id": "04425d58ce994b6da8b0dbce08f5a55a", 213 | "version_major": 2, 214 | "version_minor": 0 215 | }, 216 | "text/plain": [ 217 | "IntSlider(value=0)" 218 | ] 219 | }, 220 | "metadata": {}, 221 | "output_type": "display_data" 222 | } 223 | ], 224 | "source": [ 225 | "from ipywidgets import IntSlider, VBox, HTML\n", 226 | "slider2=IntSlider()\n", 227 | "\n", 228 | "@yield_for_change(slider2, 'value')\n", 229 | "def f():\n", 230 | " for i in range(10):\n", 231 | " print('did work %s'%i)\n", 232 | " x = yield\n", 233 | " print('generator function continued with value %s'%x)\n", 234 | "f()\n", 235 | "\n", 236 | "slider2" 237 | ] 238 | }, 239 | { 240 | "cell_type": "markdown", 241 | "metadata": {}, 242 | "source": [ 243 | "### Modifications\n", 244 | "\n", 245 | "The above two approaches both waited on widget change events, but can be modified to wait for other things, such as button event messages (as in a \"Continue\" button), etc." 246 | ] 247 | }, 248 | { 249 | "cell_type": "markdown", 250 | "metadata": {}, 251 | "source": [ 252 | "## Updating a widget in the background\n", 253 | "\n", 254 | "Sometimes you'd like to update a widget in the background, allowing the kernel to also process other execute requests. We can do this with threads. In the example below, the progress bar will update in the background and will allow the main kernel to do other computations." 255 | ] 256 | }, 257 | { 258 | "cell_type": "code", 259 | "execution_count": 6, 260 | "metadata": { 261 | "collapsed": true 262 | }, 263 | "outputs": [ 264 | { 265 | "data": { 266 | "application/vnd.jupyter.widget-view+json": { 267 | "model_id": "aa1a4e5a72b349cdb1bb13e943020943", 268 | "version_major": 2, 269 | "version_minor": 0 270 | }, 271 | "text/plain": [ 272 | "FloatProgress(value=0.0, max=1.0)" 273 | ] 274 | }, 275 | "metadata": {}, 276 | "output_type": "display_data" 277 | } 278 | ], 279 | "source": [ 280 | "import threading\n", 281 | "from IPython.display import display\n", 282 | "import ipywidgets as widgets\n", 283 | "import time\n", 284 | "progress = widgets.FloatProgress(value=0.0, min=0.0, max=1.0)\n", 285 | "\n", 286 | "def work(progress):\n", 287 | " total = 100\n", 288 | " for i in range(total):\n", 289 | " time.sleep(0.2)\n", 290 | " progress.value = float(i+1)/total\n", 291 | "\n", 292 | "thread = threading.Thread(target=work, args=(progress,))\n", 293 | "display(progress)\n", 294 | "thread.start()" 295 | ] 296 | }, 297 | { 298 | "cell_type": "markdown", 299 | "metadata": { 300 | "nbsphinx": "hidden" 301 | }, 302 | "source": [ 303 | "[Index](Index.ipynb) - [Back](Widget Custom.ipynb)" 304 | ] 305 | } 306 | ], 307 | "metadata": { 308 | "kernelspec": { 309 | "display_name": "Python 3", 310 | "language": "python", 311 | "name": "python3" 312 | }, 313 | "language_info": { 314 | "codemirror_mode": { 315 | "name": "ipython", 316 | "version": 3 317 | }, 318 | "file_extension": ".py", 319 | "mimetype": "text/x-python", 320 | "name": "python", 321 | "nbconvert_exporter": "python", 322 | "pygments_lexer": "ipython3", 323 | "version": "3.7.0" 324 | } 325 | }, 326 | "nbformat": 4, 327 | "nbformat_minor": 2 328 | } 329 | -------------------------------------------------------------------------------- /lantern/plotting/plot_plotly.py: -------------------------------------------------------------------------------- 1 | import plotly.graph_objs as go 2 | from colorlover import to_rgb 3 | from plotly.graph_objs import FigureWidget 4 | from .plotobj import BasePlot 5 | from .plotutils import get_color 6 | 7 | 8 | class PlotlyPlot(BasePlot): 9 | def __init__(self, size=None, theme=None): 10 | self.figures = [] 11 | self.bars = [] 12 | self.hlines = [] 13 | self.vlines = [] 14 | self.hspans = [] 15 | self.vspans = [] 16 | self.size = size or (800, 500) 17 | 18 | def show(self, title='', xlabel='', ylabel='', xaxis=True, yaxis=True, xticks=True, yticks=True, legend=True, grid=True, **kwargs): 19 | # get before wrapper strips 20 | tdata = [] 21 | ldata = {} 22 | 23 | y2_count = sum([1 for (_, _, a, _) in self.figures if a == 'right']) 24 | 25 | y2s = 2 26 | y2p = .05 / y2_count if y2_count > 0 else 0 27 | y2_base = .95 if y2_count > 0 else 1.0 28 | 29 | for col, figure, axis, color in self.figures: 30 | for trace in figure['data']: 31 | if axis == 'right': 32 | trace['yaxis'] = 'y%d' % y2s 33 | trace['xaxis'] = 'x' 34 | else: 35 | trace['yaxis'] = 'y1' 36 | trace['xaxis'] = 'x' 37 | tdata.append(trace) 38 | 39 | if axis == 'right': 40 | ldata['yaxis%d' % y2s] = dict( 41 | side='right', 42 | overlaying='y', 43 | color=color, 44 | position=y2_base 45 | ) 46 | y2s += 1 47 | y2_base += y2p 48 | else: 49 | ldata['yaxis1'] = dict( 50 | side='left', 51 | ) 52 | ldata['xaxis'] = dict(domain=[0, 0.95]) 53 | 54 | ldata['shapes'] = [] 55 | for line in self.hlines: 56 | ldata['shapes'].append({'x0': 0, 57 | 'x1': 1, 58 | 'y0': line[0], 59 | 'y1': line[0], 60 | 'line': {'color': line[1], 'width': 1, 'dash': 'solid'}, 61 | 'xref': 'paper', 62 | 'yref': 'y', 63 | 'type': 'line'}) 64 | for line in self.vlines: 65 | ldata['shapes'].append({'y0': 0, 66 | 'y1': 1, 67 | 'x0': line[0], 68 | 'x1': line[0], 69 | 'line': {'color': line[1], 'width': 1, 'dash': 'solid'}, 70 | 'xref': 'x', 71 | 'yref': 'paper', 72 | 'type': 'line'}) 73 | 74 | for line in self.hspans: 75 | col = to_rgb(line[2]) 76 | r = str(round(col[0] * 255)) 77 | g = str(round(col[1] * 255)) 78 | b = str(round(col[2] * 255)) 79 | 80 | ldata['shapes'].append({'x0': 0, 81 | 'x1': 1, 82 | 'y0': line[1], 83 | 'y1': line[0], 84 | 'line': {'color': line[2], 'width': 1, 'dash': 'solid'}, 85 | 'xref': 'paper', 86 | 'yref': 'y', 87 | 'type': 'rect', 88 | 'fillcolor': 'rgba(' + r + ',' + g + ',' + b + ',.5)'}) 89 | 90 | for line in self.vspans: 91 | col = to_rgb(line[2]) 92 | r = str(round(col[0] * 255)) 93 | g = str(round(col[1] * 255)) 94 | b = str(round(col[2] * 255)) 95 | 96 | ldata['shapes'].append({'y0': 0, 97 | 'y1': 1, 98 | 'x0': line[1], 99 | 'x1': line[0], 100 | 'line': {'color': line[2], 'width': 1, 'dash': 'solid'}, 101 | 'xref': 'x', 102 | 'yref': 'paper', 103 | 'type': 'rect', 104 | 'fillcolor': 'rgba(' + r + ',' + g + ',' + b + ',.5)'}) 105 | 106 | if title: 107 | ldata['title'] = title 108 | 109 | if ylabel: 110 | for k in ldata: 111 | if 'yaxis' in k: 112 | ldata[k] = dict( 113 | title=ylabel, 114 | titlefont=dict( 115 | family='Courier New, monospace', 116 | size=18, 117 | color='#7f7f7f', 118 | ), 119 | showgrid=grid, 120 | showline=yaxis, 121 | showticklabels=yticks, 122 | ) 123 | 124 | if xlabel: 125 | for k in ldata: 126 | if 'xaxis' in k: 127 | ldata['xaxis'] = dict( 128 | title=xlabel, 129 | titlefont=dict( 130 | family='Courier New, monospace', 131 | size=18, 132 | color='#7f7f7f', 133 | ), 134 | showgrid=grid, 135 | showline=xaxis, 136 | showticklabels=xticks, 137 | ) 138 | 139 | ldata['showlegend'] = legend 140 | x_size = self.size[0] if self.size[0] > 100 else self.size[0] * 100 141 | y_size = self.size[1] if self.size[1] > 100 else self.size[1] * 100 142 | ldata['width'], ldata['height'] = x_size, y_size 143 | return FigureWidget(data=tdata, layout=ldata) 144 | 145 | def area(self, data, color=None, y_axis='left', stacked=False, subplot=False, **kwargs): 146 | for i, col in enumerate(data): 147 | c = get_color(i, col, color) 148 | fig = data[[col]].iplot(fill=True, 149 | asFigure=True, 150 | filename='cufflinks/filled-area', 151 | color=c, 152 | **kwargs) 153 | self.figures.append((col, fig, y_axis, c)) 154 | 155 | def bar(self, data, color=None, y_axis='left', stacked=False, subplot=False, **kwargs): 156 | for i, col in enumerate(data): 157 | c = get_color(i, col, color) 158 | fig = data[[col]].iplot(kind='bar', 159 | asFigure=True, 160 | bargap=.1, 161 | color=c, 162 | filename='cufflinks/categorical-bar-chart', 163 | **kwargs) 164 | self.figures.append((col, fig, y_axis, c)) 165 | 166 | def hist(self, data, color=None, y_axis='left', stacked=False, subplot=False, **kwargs): 167 | for i, col in enumerate(data): 168 | c = get_color(i, col, color) 169 | '''barmode (overlay | group | stack) 170 | bins (int) 171 | histnorm ('' | 'percent' | 'probability' | 'density' | 'probability density') 172 | histfunc ('count' | 'sum' | 'avg' | 'min' | 'max') 173 | ''' 174 | 175 | fig = data[[col]].iplot(kind='histogram', 176 | asFigure=True, 177 | bargap=.1, 178 | color=c, 179 | barmode='stack' if stacked else 'overlay', 180 | filename='cufflinks/multiple-histograms', 181 | **kwargs) 182 | self.figures.append((col, fig, y_axis, c)) 183 | 184 | def hline(self, y, color=None, **kwargs): 185 | self.hlines.append((y, color)) 186 | 187 | def hspan(self, yhigh, ylow, color=None, **kwargs): 188 | self.hspans.append((yhigh, ylow, color)) 189 | 190 | def line(self, data, color=None, y_axis='left', **kwargs): 191 | for i, col in enumerate(data): 192 | c = get_color(i, col, color) 193 | fig = data[[col]].iplot(kind='scatter', 194 | asFigure=True, 195 | filename='cufflinks/cf-simple-line', 196 | color=c, 197 | **kwargs) 198 | self.figures.append((col, fig, y_axis, c)) 199 | 200 | def scatter(self, data, color=None, x=None, y=None, y_axis='left', subplot=False, **kwargs): 201 | # Scatter all 202 | for i, col in enumerate(data): 203 | if i == 0: 204 | continue # don't scatter against self 205 | x = data.columns[0] 206 | y = data.columns[i] 207 | c = get_color(i, col, color) 208 | fig = go.Figure(data=[go.Scatter( 209 | x=data[x], 210 | y=data[y], 211 | mode='markers', 212 | marker={'color': c}, 213 | name='%s vs %s' % (x, y), 214 | **kwargs)]) 215 | self.figures.append((col, fig, y_axis, c)) 216 | 217 | def step(self, data, color=None, y_axis='left', subplot=False, **kwargs): 218 | for i, col in enumerate(data): 219 | c = get_color(i, col, color) 220 | fig = data[[col]].iplot(kind='scatter', 221 | asFigure=True, 222 | interpolation='hv', 223 | filename='cufflinks/cf-simple-line', 224 | color=c, 225 | **kwargs) 226 | self.figures.append((col, fig, y_axis, c)) 227 | 228 | def vline(self, x, color=None, **kwargs): 229 | self.vlines.append((x, color)) 230 | 231 | def vspan(self, xhigh, xlow, color=None, **kwargs): 232 | self.vspans.append((xhigh, xlow, color)) 233 | -------------------------------------------------------------------------------- /lantern/plotting/plot_matplotlib.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from .plotobj import BasePlot 3 | from .plotutils import align_yaxis_np, get_color 4 | from ..utils import in_ipynb 5 | 6 | _INITED = False 7 | 8 | 9 | class MatplotlibPlot(BasePlot): 10 | def __init__(self, size=None, theme=None): 11 | global _INITED 12 | if not _INITED: 13 | if in_ipynb(): 14 | from IPython import get_ipython 15 | ipython = get_ipython() 16 | if ipython: 17 | ipython.magic("matplotlib inline") 18 | ipython.magic("config InlineBackend.figure_format = 'retina'") 19 | _INITED = True 20 | 21 | size = size or (12, 5) 22 | self._figure, self._ax = plt.subplots(figsize=size) 23 | self._axes = [self._ax] 24 | self._axes_by_side = {'left': [], 25 | 'right': [], 26 | 'top': [], 27 | 'bottom': []} 28 | self._axes_by_side['left'].append(self._ax) 29 | self._axes_by_side['bottom'].append(self._ax) 30 | self._ax.legend_ = None 31 | self._ax.get_xaxis().set_label_position("bottom") 32 | self._ax.autoscale(True) 33 | 34 | # store data for legend 35 | self._legend = [] 36 | 37 | # require all data to be present before plotting 38 | self._bars = [] 39 | self._hists = [] 40 | 41 | # subplot support 42 | self._subplot = 111 43 | 44 | def _newAx(self, y_side='left', color='black'): 45 | # axis managemens 46 | if y_side == 'left': 47 | return self._ax 48 | elif y_side == 'right': 49 | ax = self._ax.twinx() 50 | self._axes_by_side[y_side].append(ax) 51 | 52 | # set positioning 53 | ax.get_xaxis().set_label_position("bottom") 54 | ax.tick_params(axis='both', 55 | which='both', 56 | bottom=True, 57 | top=False, 58 | left=(y_side == 'left'), 59 | right=(y_side == 'right'), 60 | labelbottom=False, 61 | labeltop=False, 62 | colors=color, 63 | labelleft=(y_side == 'left'), 64 | labelright=(y_side == 'right')) 65 | 66 | # pad axes 67 | xpad = 30 * (len(self._axes_by_side['bottom']) - 1) 68 | ypad = 30 * (len(self._axes_by_side[y_side]) - 1) 69 | ax.tick_params(axis='x', pad=xpad + 2) 70 | ax.tick_params(axis='y', pad=ypad + 2) 71 | 72 | # colorize 73 | if isinstance(color, list): 74 | # Take just the first color 75 | color = color[0] 76 | elif color is None: 77 | # reset to black if no color 78 | color = 'black' 79 | 80 | ax.yaxis.label.set_color(color) 81 | ax.tick_params(axis='y', colors=color) 82 | 83 | # autoscale 84 | ax.autoscale(True) 85 | self._axes.append(ax) 86 | return ax 87 | 88 | def show(self, title='', xlabel='', ylabel='', xaxis=True, yaxis=True, xticks=True, yticks=True, legend=True, grid=True, **kwargs): 89 | # require all data to be present before plotting 90 | self._bar() 91 | self._hist() 92 | 93 | lines = [] 94 | labels = [] 95 | 96 | to_delete = [] 97 | for ax in self._axes: 98 | # no top spines if no right 99 | if len(self._axes_by_side['right']) == 0: 100 | ax.spines['top'].set_visible(False) 101 | ax.spines['right'].set_visible(False) 102 | 103 | if ax.has_data(): 104 | ax.legend_ = None 105 | ax.relim() 106 | ax.autoscale_view() 107 | 108 | else: 109 | self._figure.delaxes(ax) 110 | to_delete.append(ax) 111 | for ax in to_delete: 112 | self._axes.remove(ax) 113 | 114 | align_yaxis_np(self._axes) 115 | 116 | for m in self._axes: 117 | line, label = m.get_legend_handles_labels() 118 | lines += line 119 | labels += label 120 | 121 | if legend: 122 | self._axes[-1].legend(lines, labels, loc='center left', bbox_to_anchor=(1 + .05 * (min(len(self._axes_by_side['right']), 1) + 1), 0.5), fancybox=True) 123 | 124 | if xlabel: 125 | self._axes[-1].set_xlabel(xlabel) 126 | if ylabel: 127 | self._axes[-1].set_ylabel(ylabel) 128 | if title: 129 | plt.title(title) 130 | 131 | self._axes[-1].spines['left'].set_visible(yaxis) 132 | self._axes[-1].spines['bottom'].set_visible(xaxis) 133 | 134 | if not yticks: 135 | for ax in self._axes: 136 | ax.yaxis.set_ticks([]) 137 | 138 | if not xticks: 139 | # FIXME this doesnt work 140 | for ax in self._axes: 141 | ax.xaxis.set_ticks([]) 142 | 143 | if grid: 144 | self._axes[-1].grid(which='both') 145 | self._axes[-1].grid(which='minor', alpha=0.2) 146 | self._axes[-1].grid(which='major', alpha=0.5) 147 | 148 | self._figure.canvas.draw() 149 | plt.draw() 150 | 151 | def area(self, data, color=None, y_axis='left', stacked=False, **kwargs): 152 | for i, col in enumerate(data): 153 | _color = get_color(i, col, color) 154 | ax = self._newAx(y_side=y_axis, color=_color) 155 | x = ax.plot(data.index, data[col], color=_color, **kwargs) 156 | ax.fill_between(data.index, data[col], alpha=.7, color=_color) 157 | self._legend.append((col, x[0], y_axis)) 158 | 159 | def bar(self, data, color=None, y_axis='left', stacked=False, **kwargs): 160 | for i, col in enumerate(data): 161 | self._bars.append((data[[col]], get_color(i, col, color), y_axis, stacked, kwargs)) 162 | 163 | def _bar(self): 164 | if not self._bars: 165 | return 166 | data = [] 167 | colors = [] 168 | y_axises = [] 169 | stackedes = [] 170 | kwargses = [] 171 | 172 | left_count = 1 173 | right_count = 1 174 | 175 | for d in self._bars: 176 | data.append(d[0]) 177 | colors.append(d[1]) 178 | y_axises.append(d[2]) 179 | stackedes.append(d[3]) 180 | kwargses.append(d[4]) 181 | for col in d[0].columns: 182 | if (d[2] is None or d[2] == 'left') and not d[3]: 183 | left_count += 1 184 | elif d[2] == 'right' and not d[3]: 185 | right_count += 1 186 | 187 | width = 1 / (left_count + right_count) 188 | count = 0 189 | 190 | ax = self._newAx(y_side='left', color=colors) 191 | ax2 = self._newAx(y_side='right', color=colors) 192 | 193 | for d in self._bars: 194 | for col in d[0].columns: 195 | if d[2] == 'right': 196 | x = ax2.bar(d[0].index + count * ((d[0].index[1] - d[0].index[0]) / (left_count + right_count)), d[0][col], width=width, color=d[1], **d[4]) 197 | self._legend.append((col, x, d[2])) 198 | x.set_label(col) 199 | count += 1 200 | else: 201 | x = ax.bar(d[0].index + count * ((d[0].index[1] - d[0].index[0]) / (left_count + right_count)), d[0][col], width=width, color=d[1], **d[4]) 202 | self._legend.append((col, x, d[2])) 203 | x.set_label(col) 204 | count += 1 205 | 206 | def _hist(self): 207 | if not self._hists: 208 | return 209 | data = [] 210 | colors = [] 211 | y_axises = [] 212 | stackedes = [] 213 | kwargses = [] 214 | for d in self._hists: 215 | data.append(d[0]) 216 | colors.append(d[1]) 217 | y_axises.append(d[2]) 218 | stackedes.append(d[3]) 219 | kwargses.append(d[4]) 220 | df = data[0] 221 | df = df.join(data[1:]) 222 | y_axis = 'left' 223 | color = colors 224 | ax = self._newAx(y_side=y_axis, color=color) 225 | df.plot(kind='hist', alpha=.5, ax=ax, color=colors, stacked=stackedes[-1], **kwargses[-1]) 226 | 227 | def hist(self, data, color=None, y_axis='left', stacked=False, **kwargs): 228 | for i, col in enumerate(data): 229 | self._hists.append((data[[col]], get_color(i, col, color), y_axis, stacked, kwargs)) 230 | 231 | def hline(self, y, color=None, **kwargs): 232 | ax = self._newAx() 233 | color = color or get_color(None, None, None) 234 | ax.axhline(y, color=color, **kwargs) 235 | 236 | def hspan(self, yhigh, ylow, color=None, **kwargs): 237 | ax = self._newAx(x=False, y=False) 238 | color = color or get_color(None, None, None) 239 | ax.axhspan(ymin=ylow, ymax=yhigh, color=color, **kwargs) 240 | 241 | def line(self, data, color=None, y_axis='left', **kwargs): 242 | for i, col in enumerate(data): 243 | _color = get_color(i, col, color) 244 | ax = self._newAx(y_side=y_axis, color=_color) 245 | x = ax.plot(data.index, data[col], color=_color, **kwargs) 246 | self._legend.append((col, x[0], y_axis)) 247 | 248 | def scatter(self, data, color=None, x=None, y=None, y_axis='left', **kwargs): 249 | for i, col in enumerate(data): 250 | if i == 0: 251 | continue # don't scatter against self 252 | x = data.columns[0] 253 | y = data.columns[i] 254 | c = get_color(i, col, color) 255 | plt.plot(data[x], data[y], marker='.', linewidth=0, color=c, label='%s vs %s' % (x, y)) 256 | 257 | def step(self, data, color=None, y_axis='left', **kwargs): 258 | for i, col in enumerate(data): 259 | _color = get_color(i, col, color) 260 | ax = self._newAx(y_side=y_axis, color=_color) 261 | x = ax.plot(data.index, data[col], drawstyle='steps', color=_color, **kwargs) 262 | self._legend.append((col, x[0], y_axis)) 263 | 264 | def vline(self, x, color=None, **kwargs): 265 | ax = self._newAx() 266 | _color = color or get_color(None, None, None) 267 | ax.axvline(x, color=_color, **kwargs) 268 | 269 | def vspan(self, xhigh, xlow, color=None, **kwargs): 270 | ax = self._newAx() 271 | _color = color or get_color(None, None, None) 272 | ax.axvspan(xmin=xlow, xmax=xhigh, color=_color, **kwargs) 273 | -------------------------------------------------------------------------------- /experimental/widgets/applications/Image Browser.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Image Browser" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "This example shows how to browse through a set of images with a slider." 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 1, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "%matplotlib inline\n", 24 | "import matplotlib.pyplot as plt" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 2, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "from ipywidgets import interact" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 3, 39 | "metadata": {}, 40 | "outputs": [ 41 | { 42 | "name": "stderr", 43 | "output_type": "stream", 44 | "text": [ 45 | "/usr/local/lib/python3.7/site-packages/sklearn/utils/__init__.py:4: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working\n", 46 | " from collections import Sequence\n" 47 | ] 48 | } 49 | ], 50 | "source": [ 51 | "from sklearn import datasets" 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "metadata": {}, 57 | "source": [ 58 | "We will use the digits dataset from [scikit-learn](http://scikit-learn.org/stable/)." 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 4, 64 | "metadata": {}, 65 | "outputs": [], 66 | "source": [ 67 | "digits = datasets.load_digits()" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 5, 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [ 76 | "def browse_images(digits):\n", 77 | " n = len(digits.images)\n", 78 | " def view_image(i):\n", 79 | " plt.imshow(digits.images[i], cmap=plt.cm.gray_r, interpolation='nearest')\n", 80 | " plt.title('Training: %s' % digits.target[i])\n", 81 | " plt.show()\n", 82 | " interact(view_image, i=(0,n-1))" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 6, 88 | "metadata": {}, 89 | "outputs": [ 90 | { 91 | "data": { 92 | "application/vnd.jupyter.widget-view+json": { 93 | "model_id": "87db5647ce854aafbb05a669e382726b", 94 | "version_major": 2, 95 | "version_minor": 0 96 | }, 97 | "text/plain": [ 98 | "interactive(children=(IntSlider(value=898, description='i', max=1796), Output()), _dom_classes=('widget-intera…" 99 | ] 100 | }, 101 | "metadata": {}, 102 | "output_type": "display_data" 103 | } 104 | ], 105 | "source": [ 106 | "browse_images(digits)" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [] 115 | } 116 | ], 117 | "metadata": { 118 | "kernelspec": { 119 | "display_name": "Python 3", 120 | "language": "python", 121 | "name": "python3" 122 | }, 123 | "language_info": { 124 | "codemirror_mode": { 125 | "name": "ipython", 126 | "version": 3 127 | }, 128 | "file_extension": ".py", 129 | "mimetype": "text/x-python", 130 | "name": "python", 131 | "nbconvert_exporter": "python", 132 | "pygments_lexer": "ipython3", 133 | "version": "3.7.0" 134 | }, 135 | "widgets": { 136 | "application/vnd.jupyter.widget-state+json": { 137 | "state": { 138 | "0c884f05d0cb40178320ac5b1f344029": { 139 | "model_module": "@jupyter-widgets/base", 140 | "model_module_version": "1.0.0", 141 | "model_name": "LayoutModel", 142 | "state": {} 143 | }, 144 | "1461fd745aef4251b1490e6793199b18": { 145 | "model_module": "@jupyter-widgets/base", 146 | "model_module_version": "1.0.0", 147 | "model_name": "LayoutModel", 148 | "state": {} 149 | }, 150 | "2bb226276ed046a78b1bfa1bf8697a7e": { 151 | "model_module": "@jupyter-widgets/controls", 152 | "model_module_version": "1.2.0", 153 | "model_name": "IntSliderModel", 154 | "state": { 155 | "description": "i", 156 | "layout": "IPY_MODEL_1461fd745aef4251b1490e6793199b18", 157 | "max": 1796, 158 | "style": "IPY_MODEL_977de331262947c1b65c80dcb44b2f4a", 159 | "value": 898 160 | } 161 | }, 162 | "30147ec2f5af4428864c7ae4fa60c910": { 163 | "model_module": "@jupyter-widgets/base", 164 | "model_module_version": "1.0.0", 165 | "model_name": "LayoutModel", 166 | "state": {} 167 | }, 168 | "3b0cfbf6ceb44fbfa2fac0a465020824": { 169 | "model_module": "@jupyter-widgets/output", 170 | "model_module_version": "1.0.0", 171 | "model_name": "OutputModel", 172 | "state": { 173 | "layout": "IPY_MODEL_0c884f05d0cb40178320ac5b1f344029", 174 | "outputs": [ 175 | { 176 | "data": { 177 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPgAAAEICAYAAAByNDmmAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAADXdJREFUeJzt3X+s3XV9x/Hny4JjyI9mAw1SxoUpOLcEShoS0kUYbgsoUpeZCBtmNUvcH8NgZmZ0yZbMLfM/xrYsZgYVE346FOYY6EyoDDZFCrSbWHGsdFILQrdUEIis8N4f5zSp2HK/t/f7/Z5zPz4fyU3Pj+85n/e5zet+vud7vufzTlUhqU2vmnUBkoZjwKWGGXCpYQZcapgBlxpmwKWGGfAGJVmV5AdJfq7PbbXyGPA5MA3Yvp+Xkjy/3/XfXurzVdWLVXVUVX2nz22XKxMfS7IryZ4km5L8wtDj/iQz4HNgGrCjquoo4DvAO/a77bqXb5/ksPGr7MWlwGXAeuA44D7gMzOtqHEGfAVI8udJbkpyQ5JngMuSnJPka9OZ8PEkf53k8On2hyWpJAvT69dO778jyTNJvprklKVuO73/wiTfTvL9JH+T5F+TbOz4Uk4B7q6qR6tqL3Ad8Iv9/JZ0IAZ85fgN4HrgWOAmYC9wBZOZcD1wAfB7r/D43wL+GPgZJnsJf7bUbZO8Fvgs8IfTcR8Fzt73oCSnTP/gvP4gz3sDcHqSNyR5NfA7wB2vUIeWyYCvHPdU1T9W1UtV9XxV3VdV91bV3qraDnwCOPcVHn9zVW2uqv9jMnOeeQjbXgRsqap/mN73l8DufQ+azsyrq2rXQZ73u8C/Af8JPAdsAD64+EvXoTLgK8dj+19J8qYk/5TkiSRPAx9lMqsezBP7XX4OOOoQtn39/nXU5JtKOzvUvs9HgbXAicARwMeAO5McsYTn0BIY8JXj5V/7+zvgG8AbquoY4E+ADFzD48CafVeShElYuzoDuKGqdk33PK4GXge8qd8ytY8BX7mOBr4PPDv9qOmV3n/35TbgrCTvmB7JvwI4fgmPvw94d5LXJnlVkvcy+cO1fYBahQFfyT7I5CDVM0xm85uGHrCqvge8G7gS+B/g54EHgR8CJDl1+tn9wQ6y/QXwELAV2ANcDvxmVT09dO0/qeKCDzpUSVYBu4B3VdXds65HP84ZXEuS5IIkxyb5KSYfpe0Fvj7jsnQQBlxL9ctM3jPvZvLZ+zur6oezLUkH4y661DBncKlhg3xp4bjjjquFhYUhnnqmXnzxxVHHe/TRR0cb6/nnnx9trDF/j6eddtpoYwEceeSRo4yzY8cOdu/eveh5D4MEfGFhgc2bNw/x1DO1Z8+eUcfbuHHjaGNt2bJltLHG/D1ef/31o40FcOaZr3QGcH/WrVvXaTt30aWGGXCpYQZcapgBlxpmwKWGGXCpYQZcapgBlxpmwKWGdQr49CuCDyd5JMmHhy5KUj8WDfj0S/1/C1wIvBm4NMmbhy5M0vJ1mcHPBh6pqu1V9QJwI5PlbiXNuS4BP5EfXbJ3JwdYSTPJ+5JsTrL5qaee6qs+ScvQJeAH+kraj60SUVWfqKp1VbXu+OOXstCmpKF0CfhO4KT9rq9hstCepDnXJeD3AW+c9p16NXAJ8IVhy5LUh0UXfKiqvUkuB74ErAI+VVUPDV6ZpGXrtKJLVd0O3D5wLZJ65plsUsMMuNQwAy41zIBLDTPgUsMMuNQwAy41bJDOJmMas0vGeeedN9pYAFu3bh1trHPPPXe0se66667Rxrr11ltHGwvG62zSlTO41DADLjXMgEsNM+BSwwy41DADLjXMgEsNM+BSwwy41DADLjWsS2eTTyV5Msk3xihIUn+6zODXABcMXIekASwa8Kr6F+B/R6hFUs96ew9u6yJp/vQWcFsXSfPHo+hSwwy41LAuH5PdAHwVOD3JziS/O3xZkvrQpTfZpWMUIql/7qJLDTPgUsMMuNQwAy41zIBLDTPgUsMMuNSwFd+66KqrrhptrDFbCQFs2rRptLF27Ngx2lhjti5au3btaGPNI2dwqWEGXGqYAZcaZsClhhlwqWEGXGqYAZcaZsClhhlwqWEGXGpYlzXZTkqyKcm2JA8luWKMwiQtX5dz0fcCH6yqB5IcDdyf5MtV9c2Ba5O0TF1aFz1eVQ9MLz8DbANOHLowScu3pPfgSRaAtcC9B7jP1kXSnOkc8CRHAZ8DPlBVT7/8flsXSfOnU8CTHM4k3NdV1eeHLUlSX7ocRQ/wSWBbVV05fEmS+tJlBl8PvAc4P8mW6c/bBq5LUg+6tC66B8gItUjqmWeySQ0z4FLDDLjUMAMuNcyASw0z4FLDDLjUMAMuNWzF9yYbs/fUscceO9pYMG7ftTF7k5188smjjbVhw4bRxppHzuBSwwy41DADLjXMgEsNM+BSwwy41DADLjXMgEsNM+BSw7osunhEkq8n2TptXfSnYxQmafm6nKr6Q+D8qvrBdPnke5LcUVVfG7g2ScvUZdHFAn4wvXr49KeGLEpSP7o2PliVZAvwJPDlqrJ1kbQCdAp4Vb1YVWcCa4Czk/zSAbaxdZE0Z5Z0FL2q9gBfAS4YpBpJvepyFP34JKunl38a+FXgW0MXJmn5uhxFPwH4TJJVTP4gfLaqbhu2LEl96HIU/d+Z9ASXtMJ4JpvUMAMuNcyASw0z4FLDDLjUMAMuNcyASw0z4FLDVnzrojFb02zZsmW0sQA2btw42lhbt24dbawzzjhjtLF+0jmDSw0z4FLDDLjUMAMuNcyASw0z4FLDDLjUMAMuNcyASw0z4FLDOgd82vzgwSQuuCitEEuZwa8Atg1ViKT+dW1dtAZ4O3D1sOVI6lPXGfwq4EPASwfbwN5k0vzp0tnkIuDJqrr/lbazN5k0f7rM4OuBi5PsAG4Ezk9y7aBVSerFogGvqo9U1ZqqWgAuAe6sqssGr0zSsvk5uNSwJS3ZVFVfYdI+WNIK4AwuNcyASw0z4FLDDLjUMAMuNcyASw0z4FLDVnzrojEtLCyMOt6ePXtGHW8sY7ZJuuaaa0YbC8ZtN9WFM7jUMAMuNcyASw0z4FLDDLjUMAMuNcyASw0z4FLDDLjUMAMuNazTqarTFVWfAV4E9lbVuiGLktSPpZyL/itVtXuwSiT1zl10qWFdA17APye5P8n7DrSBrYuk+dM14Our6izgQuD3k7zl5RvYukiaP50CXlW7pv8+CdwCnD1kUZL60aX54GuSHL3vMvDrwDeGLkzS8nU5iv464JYk+7a/vqq+OGhVknqxaMCrajtwxgi1SOqZH5NJDTPgUsMMuNQwAy41zIBLDTPgUsMMuNQwWxfNsTFb/LSq1fZPXTmDSw0z4FLDDLjUMAMuNcyASw0z4FLDDLjUMAMuNcyASw0z4FLDOgU8yeokNyf5VpJtSc4ZujBJy9f1XPS/Ar5YVe9K8mrgyAFrktSTRQOe5BjgLcBGgKp6AXhh2LIk9aHLLvqpwFPAp5M8mOTq6froP8LWRdL86RLww4CzgI9X1VrgWeDDL9/I1kXS/OkS8J3Azqq6d3r9ZiaBlzTnFg14VT0BPJbk9OlNbwW+OWhVknrR9Sj6+4HrpkfQtwPvHa4kSX3pFPCq2gKsG7gWST3zTDapYQZcapgBlxpmwKWGGXCpYQZcapgBlxpmwKWG2Ztsjm3YsGG0sXbs2DHaWKtXrx5trI0bN4421jxyBpcaZsClhhlwqWEGXGqYAZcaZsClhhlwqWEGXGqYAZcatmjAk5yeZMt+P08n+cAYxUlankVPVa2qh4EzAZKsAr4L3DJwXZJ6sNRd9LcC/1VV/z1EMZL6tdSAXwLccKA7bF0kzZ/OAZ+uiX4x8PcHut/WRdL8WcoMfiHwQFV9b6hiJPVrKQG/lIPsnkuaT50CnuRI4NeAzw9bjqQ+dW1d9BzwswPXIqlnnskmNcyASw0z4FLDDLjUMAMuNcyASw0z4FLDDLjUsFRV/0+aPAUs9SulxwG7ey9mPrT62nxds3NyVS36ra5BAn4okmyuqnWzrmMIrb42X9f8cxddapgBlxo2TwH/xKwLGFCrr83XNefm5j24pP7N0wwuqWcGXGrYXAQ8yQVJHk7ySJIPz7qePiQ5KcmmJNuSPJTkilnX1Kckq5I8mOS2WdfSpySrk9yc5FvT/7tzZl3Tcsz8Pfi0mcK3mSwJtRO4D7i0qr4508KWKckJwAlV9UCSo4H7gXeu9Ne1T5I/ANYBx1TVRbOupy9JPgPcXVVXT1cSPrKq9sy6rkM1DzP42cAjVbW9ql4AbgQ2zLimZauqx6vqgenlZ4BtwImzraofSdYAbweunnUtfUpyDPAW4JMAVfXCSg43zEfATwQe2+/6ThoJwj5JFoC1wL2zraQ3VwEfAl6adSE9OxV4Cvj09O3H1UleM+uilmMeAp4D3NbMZ3dJjgI+B3ygqp6edT3LleQi4Mmqun/WtQzgMOAs4ONVtRZ4FljRx4TmIeA7gZP2u74G2DWjWnqV5HAm4b6uqlpZcno9cHGSHUzeTp2f5NrZltSbncDOqtq3p3Uzk8CvWPMQ8PuANyY5ZXpQ4xLgCzOuadmShMl7uW1VdeWs6+lLVX2kqtZU1QKT/6s7q+qyGZfVi6p6AngsyenTm94KrOiDop3WRR9SVe1NcjnwJWAV8KmqemjGZfVhPfAe4D+SbJne9kdVdfsMa9Li3g9cN51stgPvnXE9yzLzj8kkDWcedtElDcSASw0z4FLDDLjUMAMuNcyASw0z4FLD/h8gmb6UzbDP+AAAAABJRU5ErkJggg==\n", 178 | "text/plain": "
" 179 | }, 180 | "metadata": {}, 181 | "output_type": "display_data" 182 | } 183 | ] 184 | } 185 | }, 186 | "977de331262947c1b65c80dcb44b2f4a": { 187 | "model_module": "@jupyter-widgets/controls", 188 | "model_module_version": "1.2.0", 189 | "model_name": "SliderStyleModel", 190 | "state": { 191 | "description_width": "" 192 | } 193 | }, 194 | "a3d01c363bae49fdbdc10b9c8d6b6218": { 195 | "model_module": "@jupyter-widgets/controls", 196 | "model_module_version": "1.2.0", 197 | "model_name": "VBoxModel", 198 | "state": { 199 | "_dom_classes": [ 200 | "widget-interact" 201 | ], 202 | "children": [ 203 | "IPY_MODEL_2bb226276ed046a78b1bfa1bf8697a7e", 204 | "IPY_MODEL_3b0cfbf6ceb44fbfa2fac0a465020824" 205 | ], 206 | "layout": "IPY_MODEL_30147ec2f5af4428864c7ae4fa60c910" 207 | } 208 | } 209 | }, 210 | "version_major": 2, 211 | "version_minor": 0 212 | } 213 | } 214 | }, 215 | "nbformat": 4, 216 | "nbformat_minor": 2 217 | } 218 | -------------------------------------------------------------------------------- /lantern/data/data_sklearn.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from sklearn.datasets import make_regression, \ 3 | make_blobs, \ 4 | make_classification, \ 5 | make_multilabel_classification, \ 6 | make_gaussian_quantiles, \ 7 | make_hastie_10_2, \ 8 | make_circles, \ 9 | make_moons, \ 10 | make_biclusters, \ 11 | make_s_curve, \ 12 | make_checkerboard, \ 13 | make_friedman1, \ 14 | make_friedman2, \ 15 | make_friedman3 16 | 17 | # make_swiss_roll(n_samples=100, noise=0.0, random_state=None) 18 | # make_sparse_uncorrelated(n_samples=100, n_features=10, random_state=None) 19 | # make_low_rank_matrix(n_samples=100, n_features=100, effective_rank=10, tail_strength=0.5, random_state=None) 20 | # make_sparse_coded_signal(n_samples, n_components, n_features, n_nonzero_coefs, random_state=None) 21 | # make_spd_matrix(n_dim, random_state=None) 22 | # make_sparse_spd_matrix(dim=1, alpha=0.95, norm_diag=False, smallest_coef=0.1, largest_coef=0.9, random_state=None) 23 | 24 | 25 | class RegressionArgs: 26 | n_samples = 100 27 | n_features = 100 28 | n_informative = 10 29 | n_targets = 1 30 | bias = 0.0 31 | effective_rank = None 32 | tail_strength = 0.5 33 | noise = 0.0 34 | shuffle = True 35 | coef = False 36 | random_state = None 37 | 38 | 39 | class BlobsArgs: 40 | n_samples = 100 41 | n_features = 2 42 | centers = 3 43 | cluster_std = 1.0 44 | center_box = (-10.0, 10.0) 45 | shuffle = True 46 | random_state = None 47 | 48 | 49 | class ClassificationArgs: 50 | n_samples = 100 51 | n_features = 20 52 | n_informative = 2 53 | n_redundant = 2 54 | n_repeated = 0 55 | n_classes = 2 56 | n_clusters_per_class = 2 57 | weights = None 58 | flip_y = 0.01 59 | class_sep = 1.0 60 | hypercube = True 61 | shift = 0.0 62 | scale = 1.0 63 | shuffle = True 64 | random_state = None 65 | 66 | 67 | class MultilabelClassificationArgs: 68 | n_samples = 100 69 | n_features = 20 70 | n_classes = 5 71 | n_labels = 2 72 | length = 50 73 | allow_unlabeled = True 74 | sparse = False 75 | return_indicator = 'dense' 76 | return_distributions = False 77 | random_state = None 78 | 79 | 80 | class GaussianArgs: 81 | n_samples = 100 82 | n_features = 2 83 | mean = None 84 | cov = 1.0 85 | n_classes = 3 86 | shuffle = True 87 | random_state = None 88 | 89 | 90 | class HastieArgs: 91 | n_samples = 12000 92 | random_state = None 93 | 94 | 95 | class CirclesArgs: 96 | n_samples = 100 97 | shuffle = True 98 | noise = None 99 | random_state = None 100 | factor = 0.8 101 | 102 | 103 | class MoonsArgs: 104 | n_samples = 100 105 | shuffle = True 106 | noise = None 107 | random_state = None 108 | 109 | 110 | class BiclusterArgs: 111 | shape = (10, 10) 112 | n_clusters = 4 113 | noise = 0.0 114 | minval = 10 115 | maxval = 100 116 | shuffle = True 117 | random_state = None 118 | 119 | 120 | class SCurveArgs: 121 | n_samples = 100 122 | noise = 0.0 123 | random_state = None 124 | 125 | 126 | class CheckerArgs: 127 | shape = (10, 10) 128 | n_clusters = 4 129 | noise = 0.0 130 | minval = 10 131 | maxval = 100 132 | shuffle = True 133 | random_state = None 134 | 135 | 136 | class FriedmanArgs: 137 | n_samples = 100 138 | n_features = 10 139 | noise = 0.0 140 | random_state = None 141 | 142 | 143 | class Friedman2Args: 144 | n_samples = 100 145 | noise = 0.0 146 | random_state = None 147 | 148 | 149 | class Friedman3Args: 150 | n_samples = 100 151 | noise = 0.0 152 | random_state = None 153 | 154 | 155 | def getSKData(style='timeseries', as_dataframe=False, n_samples=10, **kwargs): 156 | if style == 'regression': 157 | return make_regression(n_samples, 158 | kwargs.get('n_features', RegressionArgs.n_features), 159 | kwargs.get('n_informative', RegressionArgs.n_informative), 160 | kwargs.get('n_targets', RegressionArgs.n_targets), 161 | kwargs.get('bias', RegressionArgs.bias), 162 | kwargs.get('effective_rank', RegressionArgs.effective_rank), 163 | kwargs.get('tail_strength', RegressionArgs.tail_strength), 164 | kwargs.get('noise', RegressionArgs.noise), 165 | kwargs.get('shuffle', RegressionArgs.shuffle), 166 | kwargs.get('coef', RegressionArgs.coef), 167 | kwargs.get('random_state', RegressionArgs.random_state)) 168 | elif style == 'blobs': 169 | return make_blobs(n_samples, 170 | kwargs.get('n_features', BlobsArgs.n_features), 171 | kwargs.get('centers', BlobsArgs.centers), 172 | kwargs.get('cluster_std', BlobsArgs.cluster_std), 173 | kwargs.get('center_box', BlobsArgs.center_box), 174 | kwargs.get('shuffle', BlobsArgs.shuffle), 175 | kwargs.get('random_state', BlobsArgs.random_state)) 176 | elif style == 'classification': 177 | return make_classification(n_samples, 178 | kwargs.get('n_features', ClassificationArgs.n_features), 179 | kwargs.get('n_informative', ClassificationArgs.n_informative), 180 | kwargs.get('n_redundant', ClassificationArgs.n_redundant), 181 | kwargs.get('n_repeated', ClassificationArgs.n_repeated), 182 | kwargs.get('n_classes', ClassificationArgs.n_classes), 183 | kwargs.get('n_clusters_per_class', ClassificationArgs.n_clusters_per_class), 184 | kwargs.get('weights', ClassificationArgs.weights), 185 | kwargs.get('flip_y', ClassificationArgs.flip_y), 186 | kwargs.get('class_sep', ClassificationArgs.class_sep), 187 | kwargs.get('hypercube', ClassificationArgs.hypercube), 188 | kwargs.get('shift', ClassificationArgs.shift), 189 | kwargs.get('scale', ClassificationArgs.scale), 190 | kwargs.get('shuffle', ClassificationArgs.shuffle), 191 | kwargs.get('random_state', ClassificationArgs.random_state)) 192 | elif style == 'multilabel': 193 | return make_multilabel_classification(n_samples, 194 | kwargs.get('n_features', MultilabelClassificationArgs.n_features), 195 | kwargs.get('n_classes', MultilabelClassificationArgs.n_classes), 196 | kwargs.get('n_labels', MultilabelClassificationArgs.n_labels), 197 | kwargs.get('length', MultilabelClassificationArgs.length), 198 | kwargs.get('allow_unlabeled', MultilabelClassificationArgs.allow_unlabeled), 199 | kwargs.get('sparse', MultilabelClassificationArgs.sparse), 200 | kwargs.get('return_indicator', MultilabelClassificationArgs.return_indicator), 201 | kwargs.get('return_distributions', MultilabelClassificationArgs.return_distributions), 202 | kwargs.get('random_state', MultilabelClassificationArgs.random_state)) 203 | elif style == 'gaussian': 204 | return make_gaussian_quantiles(n_samples=n_samples, 205 | n_features=kwargs.get('n_features', GaussianArgs.n_features), 206 | mean=kwargs.get('mean', GaussianArgs.mean), 207 | cov=kwargs.get('cov', GaussianArgs.cov), 208 | n_classes=kwargs.get('n_classes', GaussianArgs.n_classes), 209 | shuffle=kwargs.get('shuffle', GaussianArgs.shuffle), 210 | random_state=kwargs.get('random_state', GaussianArgs.random_state)) 211 | elif style == 'hastie': 212 | return make_hastie_10_2(n_samples, 213 | random_state=kwargs.get('random_state', HastieArgs.random_state)) 214 | elif style == 'circles': 215 | return make_circles(n_samples, 216 | kwargs.get('shuffle', CirclesArgs.shuffle), 217 | kwargs.get('noise', CirclesArgs.noise), 218 | kwargs.get('random_state', CirclesArgs.random_state), 219 | kwargs.get('factor', CirclesArgs.factor)) 220 | elif style == 'moons': 221 | return make_moons(n_samples, 222 | kwargs.get('shuffle', MoonsArgs.shuffle), 223 | kwargs.get('noise', MoonsArgs.noise), 224 | kwargs.get('random_state', MoonsArgs.random_state)) 225 | elif style == 'biclusters': 226 | x = make_biclusters(kwargs.get('shape', BiclusterArgs.shape), 227 | kwargs.get('n_clusters', BiclusterArgs.n_clusters), 228 | kwargs.get('noise', BiclusterArgs.noise), 229 | kwargs.get('minval', BiclusterArgs.minval), 230 | kwargs.get('maxval', BiclusterArgs.maxval), 231 | kwargs.get('shuffle', BiclusterArgs.shuffle), 232 | kwargs.get('random_state', BiclusterArgs.random_state)) 233 | if as_dataframe: 234 | return pd.concat([pd.DataFrame(x[0]), pd.DataFrame(x[1].T)], axis=1) 235 | else: 236 | return x 237 | 238 | elif style == 'scurve': 239 | return make_s_curve(n_samples, 240 | kwargs.get('noise', SCurveArgs.noise), 241 | kwargs.get('random_state', SCurveArgs.random_state)) 242 | elif style == 'checker': 243 | return make_checkerboard(kwargs.get('shape', CheckerArgs.shape), 244 | kwargs.get('n_clusters', CheckerArgs.n_clusters), 245 | kwargs.get('noise', CheckerArgs.noise), 246 | kwargs.get('minval', CheckerArgs.minval), 247 | kwargs.get('maxval', CheckerArgs.maxval), 248 | kwargs.get('shuffle', CheckerArgs.shuffle), 249 | kwargs.get('random_state', CheckerArgs.random_state)) 250 | elif style == 'friedman': 251 | return make_friedman1(n_samples, 252 | kwargs.get('n_features', FriedmanArgs.n_features), 253 | kwargs.get('noise', FriedmanArgs.noise), 254 | kwargs.get('random_state', FriedmanArgs.random_state)) 255 | elif style == 'friedman2': 256 | return make_friedman2(n_samples, 257 | kwargs.get('noise', Friedman2Args.noise), 258 | kwargs.get('random_state', Friedman2Args.random_state)) 259 | elif style == 'friedman3': 260 | return make_friedman3(n_samples, 261 | kwargs.get('noise', Friedman3Args.noise), 262 | kwargs.get('random_state', Friedman3Args.random_state)) 263 | --------------------------------------------------------------------------------