├── README.md ├── assets └── Plotly-on-Zeppelin-screenie.png ├── offline ├── __init__.py └── offline.py └── sample └── Plot.ly on Zeppelin.json /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | [Apache Zeppelin](https://zeppelin.incubator.apache.org/) comes with basic charts out of the box and even offers the ability to call into the underlying NVD3 library. Sometimes, though, you just want some [Plot.ly](https://plot.ly/) goodness. While this awesome visualization library can be imported directly within Jupyter, having it work on Zeppelin needs a bit more of work. This repository is one way of making that happen. 4 | 5 |  6 | 7 | It does two things: 8 | * The Zeppelin web app sources `plotly-latest.min.js` from the CDN. 9 | * It overrides Plot.ly's offline module with the code contained here such that calls to it will render via Zeppelin's display system instead of Jupyter's. 10 | 11 | # Setup 12 | 13 | These steps apply to the node that runs Zeppelin. 14 | 15 | 1. Install the following Python libraries: 16 | * [Plot.ly](https://plot.ly/python/getting-started/) 17 | * [Cufflinks](https://plot.ly/ipython-notebooks/cufflinks/) 18 | * [Pandas](http://pandas.pydata.org/) 19 | * [IPython](https://ipython.org/ipython-doc/2/install/install.html) 20 | 21 | 1. Clone this repository in a commonly accessible path. 22 | 23 | 1. Update `index.html` in zeppelin-web such that it sources `plotly-latest.min.js` during startup. The cleaner way would be to modify Zeppelin's code and then compile. But I assume you have already have Zeppelin set up and you just want to get Plot.ly running on it as fast as possible. In this case, we just extract `index.html` from `zeppelin-web-*.war`, insert the script tag for plotly.js, and then add `index.html` back into the same WAR file. 24 | 25 | 1. Find the `zeppelin-web-*.war` file inside the root folder of your Zeppelin install (i.e. `zeppelin-web-0.6.0-incubating-SNAPSHOT.war`). Back it up somewhere so you can restore the original copy if you need to. 26 | 1. Extract `index.html` 27 | 28 | ``` 29 | jar xvf zeppelin-web-0.6.0-incubating-SNAPSHOT.war index.html 30 | ``` 31 | 32 | 1. Edit `index.html` to insert `plotly-latest.min.js` script tag just before the `
` tag. 33 | 34 | ``` 35 | 36 | ``` 37 | 1. Insert this modified `index.html` back into the WAR file. 38 | 39 | ``` 40 | jar uvf zeppelin-web-0.6.0-incubating-SNAPSHOT.war index.html 41 | ``` 42 | 43 | Your modifications to the setup are now done and you can just start or restart your Zeppelin instance. In case it fails to start, you probably mistyped something when editing `index.html`. You can always restore the original WAR file you backed up if all else fails. 44 | 45 | # Usage 46 | 47 | 1. At the top of a Zeppelin notebook, copy and execute the following code. Replace with the actual path where you cloned the repository. 48 | 49 | ``` 50 | %pyspark 51 | # Load this module from a non-standard path (non-installed package) 52 | import sys 53 | sys.path.insert(0, "PATH_TO_YOUR_REPO/zeppelin-plotly") 54 | 55 | import offline 56 | 57 | # Override Plotly's module loading to use our patch instead. 58 | sys.modules["plotly"].offline = offline 59 | sys.modules["plotly.offline"] = offline 60 | 61 | # Import cufflinks (Pandas, etc) like usual. 62 | import cufflinks as cf 63 | 64 | # We need to use Cufflinks in offline mode. 65 | cf.go_offline() 66 | ``` 67 | 68 | 1. You can then use Plotly and Cufflinks (offline mode) as usual in the suceeding notebook paragraphs. 69 | 70 | ``` 71 | %pyspark 72 | import pandas as pd 73 | import numpy as np 74 | 75 | df = pd.DataFrame(np.random.randn(1000, 4), columns=['a', 'b', 'c', 'd']) 76 | df.scatter_matrix() 77 | ``` 78 | 79 | Check out the showcase notebook included inside the `sample` folder if you want to see the different visualizations available on Plot.ly. Just import the `json` file like how you would any other Zeppelin notebookand then point the `sys.path.insert` bit to the actual location of your cloned repo. 80 | 81 | # TODO 82 | 83 | * Maybe contribute this back to the Plot.ly and/or Zeppelin projects so that integration becomes even easier. 84 | * Write tests 85 | 86 | -------------------------------------------------------------------------------- /assets/Plotly-on-Zeppelin-screenie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beljun/zeppelin-plotly/8ed116738a1aa56d138378c20fc1318dae83d325/assets/Plotly-on-Zeppelin-screenie.png -------------------------------------------------------------------------------- /offline/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | offline 3 | ====== 4 | This module provides offline functionality. 5 | """ 6 | from . offline import ( 7 | init_notebook_mode, 8 | iplot 9 | ) 10 | 11 | -------------------------------------------------------------------------------- /offline/offline.py: -------------------------------------------------------------------------------- 1 | """ Plotly Offline 2 | A module to use Plotly's graphing library with Python 3 | without connecting to a public or private plotly enterprise 4 | server. 5 | """ 6 | from __future__ import absolute_import 7 | 8 | import json 9 | import os 10 | import uuid 11 | import warnings 12 | from pkg_resources import resource_string 13 | 14 | import plotly 15 | from plotly import tools, utils 16 | from plotly.exceptions import PlotlyError 17 | 18 | 19 | __PLOTLY_OFFLINE_INITIALIZED = True 20 | 21 | def get_plotlyjs(): 22 | path = os.path.join('offline', 'plotly.min.js') 23 | plotlyjs = resource_string('plotly', path).decode('utf-8') 24 | return plotlyjs 25 | 26 | def init_notebook_mode(): 27 | pass 28 | 29 | def iplot(figure_or_data, show_link=False, link_text='', 30 | validate=True): 31 | """ 32 | Draw plotly graphs inside a Zeppelin notebook without 33 | connecting to an external server. 34 | To save the chart to Plotly Cloud or Plotly Enterprise, use 35 | `plotly.plotly.iplot`. 36 | To embed an image of the chart, use `plotly.image.ishow`. 37 | 38 | figure_or_data -- a plotly.graph_objs.Figure or plotly.graph_objs.Data or 39 | dict or list that describes a Plotly graph. 40 | See https://plot.ly/python/ for examples of 41 | graph descriptions. 42 | 43 | Keyword arguments: 44 | show_link (default=True) -- display a link in the bottom-right corner of 45 | of the chart that will export the chart to 46 | Plotly Cloud or Plotly Enterprise 47 | link_text (default='Export to plot.ly') -- the text of export link 48 | validate (default=True) -- validate that all of the keys in the figure 49 | are valid? omit if your version of plotly.js 50 | has become outdated with your version of 51 | graph_reference.json or if you need to include 52 | extra, unnecessary keys in your figure. 53 | 54 | Example: 55 | ``` 56 | from plotly.offline import init_notebook_mode, iplot 57 | init_notebook_mode() 58 | 59 | iplot([{'x': [1, 2, 3], 'y': [5, 2, 7]}]) 60 | ``` 61 | """ 62 | 63 | figure = tools.return_figure_from_figure_or_data(figure_or_data, validate) 64 | 65 | width = figure.get('layout', {}).get('width', '100%') 66 | height = figure.get('layout', {}).get('height', 525) 67 | try: 68 | float(width) 69 | except (ValueError, TypeError): 70 | pass 71 | else: 72 | width = str(width) + 'px' 73 | 74 | try: 75 | float(width) 76 | except (ValueError, TypeError): 77 | pass 78 | else: 79 | width = str(width) + 'px' 80 | 81 | plotdivid = uuid.uuid4() 82 | jdata = json.dumps(figure.get('data', []), cls=utils.PlotlyJSONEncoder) 83 | jlayout = json.dumps(figure.get('layout', {}), cls=utils.PlotlyJSONEncoder) 84 | 85 | config = {} 86 | config['showLink'] = show_link 87 | config['linkText'] = link_text 88 | config['displayModeBar'] = False 89 | jconfig = json.dumps(config) 90 | 91 | script = '\n'.join([ 92 | 'Plotly.plot("{id}", {data}, {layout}, {config}).then(function() {{', 93 | ' $(".{id}.loading").remove();', 94 | '}})' 95 | ]).format(id=plotdivid, 96 | data=jdata, 97 | layout=jlayout, 98 | config=jconfig) 99 | 100 | print("""%html 101 |