Skip to content
Snippets Groups Projects
Commit e0482224 authored by Jon Mease's avatar Jon Mease
Browse files

Use go.FigureWidget

parent f2784e57
Branches
No related tags found
No related merge requests found
%% Cell type:markdown id: tags:
 
# Overview
This notebook demonstrates how to use DataShader to display large datasets inside a plotly `FigureWidget`. Change callbacks are used to recompute the datashader image whenever the axis range or figure size changes
 
%% Cell type:markdown id: tags:
 
## Imports
 
%% Cell type:code id: tags:
 
``` python
from plotly.graph_objs import FigureWidget
# core
import io
import base64
import time
 
# pandas
import pandas as pd
 
# numpy
import numpy as np
 
# scikit learn
from sklearn import datasets
 
# datashader
import datashader as ds
import datashader.transfer_functions as tf
from datashader.colors import inferno
```
 
%% Cell type:markdown id: tags:
 
## Generate dataset
We will create a large dataset by duplicating the Iris dataset many times with random noise
 
%% Cell type:code id: tags:
 
``` python
num_copies = 7000 # 1,050,000 rows
 
iris_data = datasets.load_iris()
feature_names = [name.replace(' (cm)', '').replace(' ', '_') for name in iris_data.feature_names]
iris_df_orig = pd.DataFrame(iris_data.data, columns=feature_names)
target_orig = iris_data.target + 1
 
# frame of features
iris_df = pd.concat(
np.random.normal(scale=0.2, size=iris_df_orig.shape) + iris_df_orig for i in range(num_copies)
).reset_index(drop=True)
 
# array of targets
target = [t for i in range(num_copies) for t in target_orig]
 
# dataframe that includes target as categorical
iris_target_df = pd.concat([iris_df, pd.Series(target, name='target', dtype='category')], axis=1)
 
iris_df.describe()
```
 
%% Cell type:markdown id: tags:
 
## Define DataShader image generation function
Define a function that inputs an x/y ranges and the plot width/height and generates a DataShader image of the dataset. The image will be returned as a PIL image object
 
%% Cell type:code id: tags:
 
``` python
def gen_ds_image(x_range, y_range, plot_width, plot_height):
if x_range is None or y_range is None or plot_width is None or plot_height is None:
return None
 
cvs = ds.Canvas(x_range=x_range, y_range=y_range, plot_height=plot_height, plot_width=plot_width)
agg_scatter = cvs.points(iris_target_df,
'sepal_length', 'sepal_width',
ds.count_cat('target'))
img = tf.shade(agg_scatter)
img = tf.dynspread(img, threshold=0.95, max_px=5, shape='circle')
 
return img.to_pil()
```
 
%% Cell type:markdown id: tags:
 
## Define initial ranges and plot size
 
%% Cell type:code id: tags:
 
``` python
x_range=[3, 10]
y_range=[0, 6]
plot_height=500
plot_width=700
```
 
%% Cell type:code id: tags:
 
``` python
# Test image generation function and display the PIL image
initial_img = gen_ds_image(x_range, y_range, plot_width, plot_height)
```
 
%% Cell type:code id: tags:
 
``` python
initial_img
```
 
%% Cell type:markdown id: tags:
 
# Create FigureWidget with background image
 
%% Cell type:code id: tags:
 
``` python
f = FigureWidget(data=[{'x': x_range,
'y': y_range,
'mode': 'markers',
'marker': {'opacity': 0}}], # invisible trace to init axes and to support autoresize
layout={'width': plot_width, 'height': plot_height})
import plotly.graph_objs as go
```
%% Cell type:code id: tags:
``` python
f = go.FigureWidget(data=[{'x': x_range,
'y': y_range,
'mode': 'markers',
'marker': {'opacity': 0}}], # invisible trace to init axes and to support autoresize
layout={'width': plot_width, 'height': plot_height})
f
```
 
%% Cell type:code id: tags:
 
``` python
# Set background image
f.layout.images = [dict(
f.layout.images = [go.layout.Image(
source = initial_img, # plotly now performs auto conversion of PIL image to png data URI
xref = "x",
yref = "y",
x = x_range[0],
y = y_range[1],
sizex = x_range[1] - x_range[0],
sizey = y_range[1] - y_range[0],
sizing = "stretch",
layer = "below")]
```
 
%% Cell type:markdown id: tags:
 
## Install change callback to update image on zoom/resize
 
%% Cell type:code id: tags:
 
``` python
def update_ds_image(layout, x_range, y_range, plot_width, plot_height):
img = f.layout.images[0]
 
# Update with batch_update so all updates happen simultaneously
with f.batch_update():
img.x = x_range[0]
img.y = y_range[1]
img.sizex = x_range[1] - x_range[0]
img.sizey = y_range[1] - y_range[0]
img.source = gen_ds_image(x_range, y_range, plot_width, plot_height)
 
# Install callback to run exactly once if one or more of the following properties changes
# - xaxis range
# - yaxis range
# - figure width
# - figure height
f.layout.on_change(update_ds_image, 'xaxis.range', 'yaxis.range', 'width', 'height')
```
 
%% Cell type:markdown id: tags:
 
## Image updates on drag zoom
 
%% Cell type:code id: tags:
 
``` python
f.layout.dragmode = 'zoom'
f
```
 
%% Cell type:code id: tags:
 
``` python
```
......
......@@ -262,7 +262,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.5"
"version": "3.6.6"
}
},
"nbformat": 4,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment