SlideShare a Scribd company logo
Bowtie
Interactive Dashboards
Jacques Kvam
2017-05-25
1 / 50
Anonymous Chat
https://bowtie-chat.herokuapp.com
2 / 50
Who am I?
3 / 50
Who am I?
Computer Engineer turned "Data Scientist".
3 / 50
Who am I?
Computer Engineer turned "Data Scientist".
Work at energy analytics startup, Verdigris Technologies.
3 / 50
Who am I?
Computer Engineer turned "Data Scientist".
Work at energy analytics startup, Verdigris Technologies.
Heavy Python user for 3-5 years.
3 / 50
Who am I?
Computer Engineer turned "Data Scientist".
Work at energy analytics startup, Verdigris Technologies.
Heavy Python user for 3-5 years.
I'm not a frontend developer.
3 / 50
Agenda
4 / 50
Agenda
Motivation
4 / 50
Agenda
Motivation
A quick start
4 / 50
Agenda
Motivation
A quick start
Rapid prototyping tips
4 / 50
Agenda
Motivation
A quick start
Rapid prototyping tips
Advanced features
4 / 50
Agenda
Motivation
A quick start
Rapid prototyping tips
Advanced features
How to deploy
4 / 50
Agenda
Motivation
A quick start
Rapid prototyping tips
Advanced features
How to deploy
Tech stack
4 / 50
Agenda
Motivation
A quick start
Rapid prototyping tips
Advanced features
How to deploy
Tech stack
Future work and goals
4 / 50
Agenda
Motivation
A quick start
Rapid prototyping tips
Advanced features
How to deploy
Tech stack
Future work and goals
Will not be discussing similar tools.
4 / 50
Motivation
5 / 50
Motivation
Want to click on a chart and generate another chart.
5 / 50
Motivation
Want to click on a chart and generate another chart.
5 / 50
Tool Survey
6 / 50
Tool Survey
Don't want to use R!
6 / 50
Tool Survey
Don't want to use R!
Looked for solutions in Python.
6 / 50
Tool Survey
Don't want to use R!
Looked for solutions in Python.
Thought this should be easier.
6 / 50
Tool Survey
Don't want to use R!
Looked for solutions in Python.
Thought this should be easier.
Thought it would be fun to write something.
6 / 50
7 / 50
Initial Thoughts
8 / 50
Initial Thoughts
Plotly charts have lots of events: selection, click, and hover.
8 / 50
Initial Thoughts
Plotly charts have lots of events: selection, click, and hover.
Just need to communicate between Python and JS in browser.
8 / 50
Initial Thoughts
Plotly charts have lots of events: selection, click, and hover.
Just need to communicate between Python and JS in browser.
Socket.io seems like it could do the trick.
8 / 50
Initial Thoughts
Plotly charts have lots of events: selection, click, and hover.
Just need to communicate between Python and JS in browser.
Socket.io seems like it could do the trick.
That's good enough for a proof of concept.
8 / 50
Fast forward a few months
9 / 50
Your First Bowtie App
10 / 50
Your First Bowtie App
Each app has three parts
10 / 50
Your First Bowtie App
Each app has three parts
Choose the components in your app.
10 / 50
Your First Bowtie App
Each app has three parts
Choose the components in your app.
Write the callbacks (in response to events).
10 / 50
Your First Bowtie App
Each app has three parts
Choose the components in your app.
Write the callbacks (in response to events).
Layout the components and connect everything.
10 / 50
First we need some prereqs
11 / 50
First we need some prereqs
Need Node to get us yarn and webpack.
$ brew install node
$ npm install -g webpack
$ brew install yarn
Sorry for the MacOS bias.
11 / 50
First we need some prereqs
Need Node to get us yarn and webpack.
$ brew install node
$ npm install -g webpack
$ brew install yarn
Sorry for the MacOS bias.
Install Bowtie.
$ pip install bowtie
Works on Python 2 and 3
11 / 50
12 / 50
Select the components
13 / 50
Select the components
These are the widgets that exist in your app.
13 / 50
Select the components
These are the widgets that exist in your app.
Full list of components on readthedocs.
13 / 50
Select the components
These are the widgets that exist in your app.
Full list of components on readthedocs.
Split into two categories: visual widgets and controller widgets.
13 / 50
Select the components
These are the widgets that exist in your app.
Full list of components on readthedocs.
Split into two categories: visual widgets and controller widgets.
Visual: Plotly, SVG (matplotlib), Tables
13 / 50
Select the components
These are the widgets that exist in your app.
Full list of components on readthedocs.
Split into two categories: visual widgets and controller widgets.
Visual: Plotly, SVG (matplotlib), Tables
Controllers: DatePickers, Dropdown, Text, Sliders, Toggle, and a Button.
13 / 50
Select the components
These are the widgets that exist in your app.
Full list of components on readthedocs.
Split into two categories: visual widgets and controller widgets.
Visual: Plotly, SVG (matplotlib), Tables
Controllers: DatePickers, Dropdown, Text, Sliders, Toggle, and a Button.
from bowtie.visual import Plotly
from bowtie.control import Dropdown
plot = Plotly()
ddown = Dropdown()
13 / 50
What do these components do?
14 / 50
What do these components do?
Instructions for displaying itself in a webpage.
14 / 50
What do these components do?
Instructions for displaying itself in a webpage.
Commands, pre xed with do_, to update the state of the widget.
14 / 50
What do these components do?
Instructions for displaying itself in a webpage.
Commands, pre xed with do_, to update the state of the widget.
Events, pre xed with on_, to run python in response to.
14 / 50
What do these components do?
Instructions for displaying itself in a webpage.
Commands, pre xed with do_, to update the state of the widget.
Events, pre xed with on_, to run python in response to.
Getters, pre xed with get, gets the current states of the widget.
14 / 50
What do these components do?
Instructions for displaying itself in a webpage.
Commands, pre xed with do_, to update the state of the widget.
Events, pre xed with on_, to run python in response to.
Getters, pre xed with get, gets the current states of the widget.
For example: Dropdown docs.
14 / 50
De ne the callbacks
15 / 50
De ne the callbacks
We'll de ne functions to get run when events happen.
15 / 50
De ne the callbacks
We'll de ne functions to get run when events happen.
import plotlywrapper as pw
def callback(item):
chart = pw.line(range(item['value']))
plot.do_all(chart.dict)
15 / 50
De ne the callbacks
We'll de ne functions to get run when events happen.
import plotlywrapper as pw
def callback(item):
chart = pw.line(range(item['value']))
plot.do_all(chart.dict)
We'll run this function in response to a dropdown event.
15 / 50
De ne the callbacks
We'll de ne functions to get run when events happen.
import plotlywrapper as pw
def callback(item):
chart = pw.line(range(item['value']))
plot.do_all(chart.dict)
We'll run this function in response to a dropdown event.
The passed object for this dropdown is a dictionary with two keys: "label" and "value".
15 / 50
De ne the callbacks
We'll de ne functions to get run when events happen.
import plotlywrapper as pw
def callback(item):
chart = pw.line(range(item['value']))
plot.do_all(chart.dict)
We'll run this function in response to a dropdown event.
The passed object for this dropdown is a dictionary with two keys: "label" and "value".
To update the plot we call the do_all method.
15 / 50
Layout the App
16 / 50
Layout the App
We've chosen the components and de ned the functionality. Now we just need to connect events to
functions and lay out the widgets.
16 / 50
Layout the App
We've chosen the components and de ned the functionality. Now we just need to connect events to
functions and lay out the widgets.
from bowtie import command
@command
def build():
from bowtie import Layout
layout = Layout()
layout.add(plot)
layout.add_sidebar(ddown)
layout.subscribe(callback, ddown.on_change)
layout.build()
16 / 50
Layout the App
from bowtie import command
The command decorator turns this function into a command line interface.
@command
def build():
from bowtie import Layout
layout = Layout()
layout.add(plot)
layout.add_sidebar(ddown)
layout.subscribe(callback, ddown.on_change)
layout.build()
17 / 50
Layout the App
from bowtie import command
@command
def build():
from bowtie import Layout
layout = Layout()
These add* calls place widgets into our app.
layout.add(plot)
layout.add_sidebar(ddown)
layout.subscribe(callback, ddown.on_change)
layout.build()
18 / 50
Layout the App
from bowtie import command
@command
def build():
from bowtie import Layout
layout = Layout()
layout.add(plot)
layout.add_sidebar(ddown)
subscribe makes sure the callback gets run in response to the given event.
layout.subscribe(callback, ddown.on_change)
layout.build()
19 / 50
Layout the App
from bowtie import command
@command
def build():
from bowtie import Layout
layout = Layout(debug=True)
layout.add(plot)
layout.add_sidebar(ddown)
layout.subscribe(callback, ddown.on_change)
Finally, build compiles the app for us.
layout.build()
20 / 50
Build and Serve
21 / 50
Build and Serve
We're done writing the app, time to build and run it.
21 / 50
Build and Serve
We're done writing the app, time to build and run it.
The CLI we have gives us these commands:
Commands:
build Write the app, downloads the packages, and...
dev Recompile the app for development.
prod Recompile the app for production.
serve Serve the Bowtie app.
21 / 50
Build and Serve
We're done writing the app, time to build and run it.
The CLI we have gives us these commands:
Commands:
build Write the app, downloads the packages, and...
dev Recompile the app for development.
prod Recompile the app for production.
serve Serve the Bowtie app.
$ ./app.py build
21 / 50
Build and Serve
We're done writing the app, time to build and run it.
The CLI we have gives us these commands:
Commands:
build Write the app, downloads the packages, and...
dev Recompile the app for development.
prod Recompile the app for production.
serve Serve the Bowtie app.
$ ./app.py build
$ ./app.py serve
21 / 50
22 / 50
23 / 50
Rapid prototyping
24 / 50
Rapid prototyping
Set Layout(debug=True)! Enables live code reloading on write.
25 / 50
Rapid prototyping
Set Layout(debug=True)! Enables live code reloading on write.
Minimize builds by architecting app at the beginning.
25 / 50
Rapid prototyping
Set Layout(debug=True)! Enables live code reloading on write.
Minimize builds by architecting app at the beginning.
Use debuggers or prints to learn the payload.
def select(points):
one of the following:
print(points)
import ipdb; ipdb.set_trace()
import IPython; IPython.embed()
import wdb; wdb.set_trace()
25 / 50
Advanced Features
26 / 50
Listening to Plotly Events
27 / 50
Listening to Plotly Events
Plotly is a featureful Javascript charting library.
27 / 50
Listening to Plotly Events
Plotly is a featureful Javascript charting library.
It has several events and Bowtie exposes three event types: selection, click, and hover.
27 / 50
Listening to Plotly Events
Plotly is a featureful Javascript charting library.
It has several events and Bowtie exposes three event types: selection, click, and hover.
The data it returns is not well documented, but it's not too hard to gure out.
27 / 50
Subscribe to Multiple Events
28 / 50
Subscribe to Multiple Events
A common use-case is for a function to use the output from several widgets.
28 / 50
Subscribe to Multiple Events
A common use-case is for a function to use the output from several widgets.
Cumbersome to write individual callbacks for each event and get the other widgets' states.
def foo(a,b):
pass
def cb1(a):
b = b.get()
foo(a,b)
def cb2(b):
a = a.get()
foo(a,b)
28 / 50
Subscribe to Multiple Events
A common use-case is for a function to use the output from several widgets.
Cumbersome to write individual callbacks for each event and get the other widgets' states.
def foo(a,b):
pass
def cb1(a):
b = b.get()
foo(a,b)
def cb2(b):
a = a.get()
foo(a,b)
A better way is to subscribe callbacks to multiple events.
28 / 50
Subscribe to Multiple Events
A common use-case is for a function to use the output from several widgets.
Cumbersome to write individual callbacks for each event and get the other widgets' states.
def foo(a,b):
pass
def cb1(a):
b = b.get()
foo(a,b)
def cb2(b):
a = a.get()
foo(a,b)
A better way is to subscribe callbacks to multiple events.
def func(item1, item2, switch):
cool_stuff()
...
layout.subscribe(func, ddown1.on_select, ddown2.on_select, switch.on_switch)
28 / 50
Scheduling and Loading Events
29 / 50
Scheduling and Loading Events
Bowtie also de nes intrinsic event types.
29 / 50
Scheduling and Loading Events
Bowtie also de nes intrinsic event types.
Instruct a function to run when a user loads the page.
layout.load(func)
29 / 50
Scheduling and Loading Events
Bowtie also de nes intrinsic event types.
Instruct a function to run when a user loads the page.
layout.load(func)
Instruct a function to run periodically.
layout.schedule(5, func) # call func every 5 seconds
29 / 50
Storing data with the client
30 / 50
Storing data with the client
In some cases it's helpful to be able to store data with the client.
30 / 50
Storing data with the client
In some cases it's helpful to be able to store data with the client.
Could store it server-side, but that's more setup.
30 / 50
Storing data with the client
In some cases it's helpful to be able to store data with the client.
Could store it server-side, but that's more setup.
So we'll just send the data to the client and have them hold it.
30 / 50
Storing data with the client
In some cases it's helpful to be able to store data with the client.
Could store it server-side, but that's more setup.
So we'll just send the data to the client and have them hold it.
bowtie.cache gives a "key-value" store to save any python objects.
30 / 50
Storing data with the client
In some cases it's helpful to be able to store data with the client.
Could store it server-side, but that's more setup.
So we'll just send the data to the client and have them hold it.
bowtie.cache gives a "key-value" store to save any python objects.
Helpful to store results from expensive computations or client speci c data.
bowtie.cache.save(key, value)
value = bowtie.cache.load(key)
30 / 50
Progress Indicators
31 / 50
Progress Indicators
All visual widgets have an attached progress indicator.
31 / 50
Progress Indicators
All visual widgets have an attached progress indicator.
By default they are invisible so they don't get in your way.
31 / 50
Progress Indicators
All visual widgets have an attached progress indicator.
By default they are invisible so they don't get in your way.
Really helpful for long computations or slow I/O.
31 / 50
Progress Indicators
All visual widgets have an attached progress indicator.
By default they are invisible so they don't get in your way.
Really helpful for long computations or slow I/O.
Can also indicate error states.
31 / 50
Leverage CSS Grid
32 / 50
Leverage CSS Grid
New web standard to de ne grids on a page.
32 / 50
Leverage CSS Grid
New web standard to de ne grids on a page.
Bowtie uses this and makes a "pythonic" API.
32 / 50
Leverage CSS Grid
New web standard to de ne grids on a page.
Bowtie uses this and makes a "pythonic" API.
CSS Grid was just released onto major browsers.
32 / 50
Leverage CSS Grid
New web standard to de ne grids on a page.
Bowtie uses this and makes a "pythonic" API.
CSS Grid was just released onto major browsers.
Chrome >= 57, Firefox >= 52, Safari >= 10.1, Opera >= 44
32 / 50
Leverage CSS Grid
Layout class lets you specify how many rows and columns in the grid.
33 / 50
Leverage CSS Grid
Layout class lets you specify how many rows and columns in the grid.
call .add method and optionally specify which cells in the grid.
33 / 50
Leverage CSS Grid
Layout class lets you specify how many rows and columns in the grid.
call .add method and optionally specify which cells in the grid.
Widgets can span 1 or multiple cells.
33 / 50
Leverage CSS Grid
Layout class lets you specify how many rows and columns in the grid.
call .add method and optionally specify which cells in the grid.
Widgets can span 1 or multiple cells.
Rows and columns can be sized on pixels, percentage, and fraction of available space.
33 / 50
Authentication
34 / 50
Authentication
Flask makes it easy to support basic authentication.
34 / 50
Authentication
Flask makes it easy to support basic authentication.
Want to have a generic authentication solution.
34 / 50
Authentication
Flask makes it easy to support basic authentication.
Want to have a generic authentication solution.
I'm not a security expert so don't trust me.
34 / 50
35 / 50
Deploying
36 / 50
Deploying
37 / 50
Deploying
Heroku is an easy option.
37 / 50
Deploying
Heroku is an easy option.
Set Layout(debug=False)
37 / 50
Deploying
Heroku is an easy option.
Set Layout(debug=False)
Compile with production.
$ python app.py prod
Reduces JS bundle size by a factor of ~30 (from 30MB to 1MB).
37 / 50
Deploying
Heroku is an easy option.
Set Layout(debug=False)
Compile with production.
$ python app.py prod
Reduces JS bundle size by a factor of ~30 (from 30MB to 1MB).
Commit the following les
build/src/server.py
build/src/templates/index.html
build/src/static/bundle.js.gz
37 / 50
Tech Stack
38 / 50
Flask-SocketIO
39 / 50
Flask-SocketIO
Bowtie is built on Flask and Flask-SocketIO.
39 / 50
Flask-SocketIO
Bowtie is built on Flask and Flask-SocketIO.
Bowtie abstracts away most of Flask.
39 / 50
Flask-SocketIO
Bowtie is built on Flask and Flask-SocketIO.
Bowtie abstracts away most of Flask.
You can still bene t from the Flask ecosystem.
39 / 50
Flask-SocketIO
Bowtie is built on Flask and Flask-SocketIO.
Bowtie abstracts away most of Flask.
You can still bene t from the Flask ecosystem.
Kind of wish the user still touched Flask because it's a great API.
39 / 50
React
40 / 50
React
Nick Kridler (author of Pyxley) wrote about using React with Python.
40 / 50
React
Nick Kridler (author of Pyxley) wrote about using React with Python.
Frontend is written entirely in React.
40 / 50
React
Nick Kridler (author of Pyxley) wrote about using React with Python.
Frontend is written entirely in React.
Making a new widget means making a new React class that communicates via socket.io.
40 / 50
Talking through SocketIO
41 / 50
Talking through SocketIO
All communication between Python and Javascript is through SocketIO
41 / 50
Talking through SocketIO
All communication between Python and Javascript is through SocketIO
Unique events are created by combining the component id with the type of message.
41 / 50
Talking through SocketIO
All communication between Python and Javascript is through SocketIO
Unique events are created by combining the component id with the type of message.
For example: the event for updating Plotly is "{id}#all"
41 / 50
Talking through SocketIO
All communication between Python and Javascript is through SocketIO
Unique events are created by combining the component id with the type of message.
For example: the event for updating Plotly is "{id}#all"
Message payloads are encoded with msgpack to reduce payload size.
41 / 50
Javascript Tools
42 / 50
Javascript Tools
Yarn: for installing npm packages.
42 / 50
Javascript Tools
Yarn: for installing npm packages.
Webpack: for bundling the npm packages.
42 / 50
Javascript Tools
Yarn: for installing npm packages.
Webpack: for bundling the npm packages.
Leaky abstraction, but I don't want to turn bowtie into a node delivery device.
42 / 50
Future Work and Goals
43 / 50
Some things I don't like
44 / 50
Some things I don't like
You need to recompile your app to run it (when you make architectural changes) which takes a minute.
44 / 50
Some things I don't like
You need to recompile your app to run it (when you make architectural changes) which takes a minute.
Compared to some other tools, Bowtie is not as snappy.
44 / 50
Some things I don't like
You need to recompile your app to run it (when you make architectural changes) which takes a minute.
Compared to some other tools, Bowtie is not as snappy.
Perhaps too much magic happening behind the scenes, harder for users to change things and x issues.
44 / 50
User Experience Goals
45 / 50
User Experience Goals
The power to create as much interactivity as you want.
45 / 50
User Experience Goals
The power to create as much interactivity as you want.
Painless rapid prototyping
45 / 50
User Experience Goals
The power to create as much interactivity as you want.
Painless rapid prototyping
Be able to share with others
45 / 50
Non Goals
46 / 50
Non Goals
GUI for laying out widgets.
46 / 50
Non Goals
GUI for laying out widgets.
Generic web app builder (my focus is on data science applications).
46 / 50
Goals and Future Work
47 / 50
Goals and Future Work
Become Shiny!
47 / 50
Goals and Future Work
Become Shiny!
Okay, but seriously.
47 / 50
Goals and Future Work
Become Shiny!
Okay, but seriously.
Needs to be more robust, have better testing.
47 / 50
Goals and Future Work
Become Shiny!
Okay, but seriously.
Needs to be more robust, have better testing.
Make it easier to scale and deploy.
47 / 50
Goals and Future Work
Become Shiny!
Okay, but seriously.
Needs to be more robust, have better testing.
Make it easier to scale and deploy.
More charting libraries.
47 / 50
Goals and Future Work
Become Shiny!
Okay, but seriously.
Needs to be more robust, have better testing.
Make it easier to scale and deploy.
More charting libraries.
More widgets.
47 / 50
Goals and Future Work
Become Shiny!
Okay, but seriously.
Needs to be more robust, have better testing.
Make it easier to scale and deploy.
More charting libraries.
More widgets.
Make it look nicer?
47 / 50
Goals and Future Work
Become Shiny!
Okay, but seriously.
Needs to be more robust, have better testing.
Make it easier to scale and deploy.
More charting libraries.
More widgets.
Make it look nicer?
Jupyter integration (possible?)
47 / 50
My Real Goal
Whether Bowtie becomes the Shiny of Python or not, I simply
want to move the bar forward.
48 / 50
Thanks
To my Verdigris colleagues for feedback.
Danny Servén
Jared Kruzek
Martin Chang
Michael Roberts
To Je for letting me present.
49 / 50
Thanks
Github: github.com/jwkvam/bowtie
Slides: github.com/jwkvam/bowtie-talk
Docs: bowtie-py.rtfd.io
50 / 50

More Related Content

What's hot

Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)
andrewnacin
 
Power Of Zero
Power Of ZeroPower Of Zero
Power Of Zero
Andrew Forward
 
Intro To Spring Python
Intro To Spring PythonIntro To Spring Python
Intro To Spring Python
gturnquist
 
Ultimate Node.js countdown: the coolest Application Express examples
Ultimate Node.js countdown: the coolest Application Express examplesUltimate Node.js countdown: the coolest Application Express examples
Ultimate Node.js countdown: the coolest Application Express examples
Alan Arentsen
 
Testing Ember Apps: Managing Dependency
Testing Ember Apps: Managing DependencyTesting Ember Apps: Managing Dependency
Testing Ember Apps: Managing Dependency
Matthew Beale
 
Metrics-Driven Engineering
Metrics-Driven EngineeringMetrics-Driven Engineering
Metrics-Driven Engineering
Mike Brittain
 
Remote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.create
Remote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.createRemote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.create
Remote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.create
Peter Lehto
 
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Iakiv Kramarenko
 
Just Married: Zend Framework and Doctrine
Just Married: Zend Framework and DoctrineJust Married: Zend Framework and Doctrine
Just Married: Zend Framework and Doctrine
Benjamin Eberlei
 
Your code are my tests
Your code are my testsYour code are my tests
Your code are my tests
Michelangelo van Dam
 
Django for IoT: From hackathon to production (DjangoCon US)
Django for IoT: From hackathon to production (DjangoCon US)Django for IoT: From hackathon to production (DjangoCon US)
Django for IoT: From hackathon to production (DjangoCon US)
Anna Schneider
 
Towards the Cloud: Event-driven Architectures in PHP
Towards the Cloud: Event-driven Architectures in PHPTowards the Cloud: Event-driven Architectures in PHP
Towards the Cloud: Event-driven Architectures in PHP
Benjamin Eberlei
 
JetBot basic motion
JetBot basic motionJetBot basic motion
JetBot basic motion
PeiJia5
 
More android code puzzles
More android code puzzlesMore android code puzzles
More android code puzzles
Danny Preussler
 
Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...
Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...
Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...
Katy Slemon
 
Ember testing internals with ember cli
Ember testing internals with ember cliEmber testing internals with ember cli
Ember testing internals with ember cli
Cory Forsyth
 
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript...Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript...
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
Tim Chaplin
 
Web Performance Culture and Tools at Etsy
Web Performance Culture and Tools at EtsyWeb Performance Culture and Tools at Etsy
Web Performance Culture and Tools at Etsy
Mike Brittain
 
Desenvolva um game para android ou iPhone
Desenvolva um game para android ou iPhoneDesenvolva um game para android ou iPhone
Desenvolva um game para android ou iPhoneTiago Oliveira
 
Ditching JQuery
Ditching JQueryDitching JQuery
Ditching JQuery
howlowck
 

What's hot (20)

Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)
 
Power Of Zero
Power Of ZeroPower Of Zero
Power Of Zero
 
Intro To Spring Python
Intro To Spring PythonIntro To Spring Python
Intro To Spring Python
 
Ultimate Node.js countdown: the coolest Application Express examples
Ultimate Node.js countdown: the coolest Application Express examplesUltimate Node.js countdown: the coolest Application Express examples
Ultimate Node.js countdown: the coolest Application Express examples
 
Testing Ember Apps: Managing Dependency
Testing Ember Apps: Managing DependencyTesting Ember Apps: Managing Dependency
Testing Ember Apps: Managing Dependency
 
Metrics-Driven Engineering
Metrics-Driven EngineeringMetrics-Driven Engineering
Metrics-Driven Engineering
 
Remote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.create
Remote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.createRemote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.create
Remote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.create
 
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
 
Just Married: Zend Framework and Doctrine
Just Married: Zend Framework and DoctrineJust Married: Zend Framework and Doctrine
Just Married: Zend Framework and Doctrine
 
Your code are my tests
Your code are my testsYour code are my tests
Your code are my tests
 
Django for IoT: From hackathon to production (DjangoCon US)
Django for IoT: From hackathon to production (DjangoCon US)Django for IoT: From hackathon to production (DjangoCon US)
Django for IoT: From hackathon to production (DjangoCon US)
 
Towards the Cloud: Event-driven Architectures in PHP
Towards the Cloud: Event-driven Architectures in PHPTowards the Cloud: Event-driven Architectures in PHP
Towards the Cloud: Event-driven Architectures in PHP
 
JetBot basic motion
JetBot basic motionJetBot basic motion
JetBot basic motion
 
More android code puzzles
More android code puzzlesMore android code puzzles
More android code puzzles
 
Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...
Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...
Flutter hooks tutorial (part 1) flutter animation using hooks (use effect and...
 
Ember testing internals with ember cli
Ember testing internals with ember cliEmber testing internals with ember cli
Ember testing internals with ember cli
 
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript...Fullstack Conference -  Proxies before proxies: The hidden gems of Javascript...
Fullstack Conference - Proxies before proxies: The hidden gems of Javascript...
 
Web Performance Culture and Tools at Etsy
Web Performance Culture and Tools at EtsyWeb Performance Culture and Tools at Etsy
Web Performance Culture and Tools at Etsy
 
Desenvolva um game para android ou iPhone
Desenvolva um game para android ou iPhoneDesenvolva um game para android ou iPhone
Desenvolva um game para android ou iPhone
 
Ditching JQuery
Ditching JQueryDitching JQuery
Ditching JQuery
 

Similar to Bowtie: Interactive Dashboards

Incredible Machine with Pipelines and Generators
Incredible Machine with Pipelines and GeneratorsIncredible Machine with Pipelines and Generators
Incredible Machine with Pipelines and Generators
dantleech
 
Demystifying Maven
Demystifying MavenDemystifying Maven
Demystifying Maven
Mike Desjardins
 
React & The Art of Managing Complexity
React &  The Art of Managing ComplexityReact &  The Art of Managing Complexity
React & The Art of Managing Complexity
Ryan Anklam
 
Behavior & Specification Driven Development in PHP - #OpenWest
Behavior & Specification Driven Development in PHP - #OpenWestBehavior & Specification Driven Development in PHP - #OpenWest
Behavior & Specification Driven Development in PHP - #OpenWestJoshua Warren
 
Adding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsAdding a modern twist to legacy web applications
Adding a modern twist to legacy web applications
Jeff Durta
 
Rits Brown Bag - Salesforce Lightning
Rits Brown Bag - Salesforce LightningRits Brown Bag - Salesforce Lightning
Rits Brown Bag - Salesforce Lightning
Right IT Services
 
Google Wave API: Now and Beyond
Google Wave API: Now and BeyondGoogle Wave API: Now and Beyond
Google Wave API: Now and Beyond
Marakana Inc.
 
Using prime[31] to connect your unity game to azure mobile services
Using prime[31] to connect your unity game to azure mobile servicesUsing prime[31] to connect your unity game to azure mobile services
Using prime[31] to connect your unity game to azure mobile services
David Voyles
 
Shift Remote: Mobile - Devops-ify your life with Github Actions - Nicola Cort...
Shift Remote: Mobile - Devops-ify your life with Github Actions - Nicola Cort...Shift Remote: Mobile - Devops-ify your life with Github Actions - Nicola Cort...
Shift Remote: Mobile - Devops-ify your life with Github Actions - Nicola Cort...
Shift Conference
 
Modern Release Engineering in a Nutshell - Why Researchers should Care!
Modern Release Engineering in a Nutshell - Why Researchers should Care!Modern Release Engineering in a Nutshell - Why Researchers should Care!
Modern Release Engineering in a Nutshell - Why Researchers should Care!
Bram Adams
 
Reactive programming with tracker
Reactive programming with trackerReactive programming with tracker
Reactive programming with tracker
Designveloper
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
Jose Manuel Pereira Garcia
 
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac..."Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
Fwdays
 
ReactJS for Programmers
ReactJS for ProgrammersReactJS for Programmers
ReactJS for Programmers
David Rodenas
 
Developer Student Clubs NUK - Flutter for Beginners
Developer Student Clubs NUK - Flutter for BeginnersDeveloper Student Clubs NUK - Flutter for Beginners
Developer Student Clubs NUK - Flutter for Beginners
Jiaxuan Lin
 
Understanding Framework Architecture using Eclipse
Understanding Framework Architecture using EclipseUnderstanding Framework Architecture using Eclipse
Understanding Framework Architecture using Eclipse
anshunjain
 
Scala Future & Promises
Scala Future & PromisesScala Future & Promises
Scala Future & Promises
Knoldus Inc.
 
Release with confidence
Release with confidenceRelease with confidence
Release with confidence
John Congdon
 
Introduction to React for Frontend Developers
Introduction to React for Frontend DevelopersIntroduction to React for Frontend Developers
Introduction to React for Frontend Developers
Sergio Nakamura
 
React Native custom components
React Native custom componentsReact Native custom components
React Native custom components
Jeremy Grancher
 

Similar to Bowtie: Interactive Dashboards (20)

Incredible Machine with Pipelines and Generators
Incredible Machine with Pipelines and GeneratorsIncredible Machine with Pipelines and Generators
Incredible Machine with Pipelines and Generators
 
Demystifying Maven
Demystifying MavenDemystifying Maven
Demystifying Maven
 
React & The Art of Managing Complexity
React &  The Art of Managing ComplexityReact &  The Art of Managing Complexity
React & The Art of Managing Complexity
 
Behavior & Specification Driven Development in PHP - #OpenWest
Behavior & Specification Driven Development in PHP - #OpenWestBehavior & Specification Driven Development in PHP - #OpenWest
Behavior & Specification Driven Development in PHP - #OpenWest
 
Adding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsAdding a modern twist to legacy web applications
Adding a modern twist to legacy web applications
 
Rits Brown Bag - Salesforce Lightning
Rits Brown Bag - Salesforce LightningRits Brown Bag - Salesforce Lightning
Rits Brown Bag - Salesforce Lightning
 
Google Wave API: Now and Beyond
Google Wave API: Now and BeyondGoogle Wave API: Now and Beyond
Google Wave API: Now and Beyond
 
Using prime[31] to connect your unity game to azure mobile services
Using prime[31] to connect your unity game to azure mobile servicesUsing prime[31] to connect your unity game to azure mobile services
Using prime[31] to connect your unity game to azure mobile services
 
Shift Remote: Mobile - Devops-ify your life with Github Actions - Nicola Cort...
Shift Remote: Mobile - Devops-ify your life with Github Actions - Nicola Cort...Shift Remote: Mobile - Devops-ify your life with Github Actions - Nicola Cort...
Shift Remote: Mobile - Devops-ify your life with Github Actions - Nicola Cort...
 
Modern Release Engineering in a Nutshell - Why Researchers should Care!
Modern Release Engineering in a Nutshell - Why Researchers should Care!Modern Release Engineering in a Nutshell - Why Researchers should Care!
Modern Release Engineering in a Nutshell - Why Researchers should Care!
 
Reactive programming with tracker
Reactive programming with trackerReactive programming with tracker
Reactive programming with tracker
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
 
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac..."Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
 
ReactJS for Programmers
ReactJS for ProgrammersReactJS for Programmers
ReactJS for Programmers
 
Developer Student Clubs NUK - Flutter for Beginners
Developer Student Clubs NUK - Flutter for BeginnersDeveloper Student Clubs NUK - Flutter for Beginners
Developer Student Clubs NUK - Flutter for Beginners
 
Understanding Framework Architecture using Eclipse
Understanding Framework Architecture using EclipseUnderstanding Framework Architecture using Eclipse
Understanding Framework Architecture using Eclipse
 
Scala Future & Promises
Scala Future & PromisesScala Future & Promises
Scala Future & Promises
 
Release with confidence
Release with confidenceRelease with confidence
Release with confidence
 
Introduction to React for Frontend Developers
Introduction to React for Frontend DevelopersIntroduction to React for Frontend Developers
Introduction to React for Frontend Developers
 
React Native custom components
React Native custom componentsReact Native custom components
React Native custom components
 

Recently uploaded

Levelwise PageRank with Loop-Based Dead End Handling Strategy : SHORT REPORT ...
Levelwise PageRank with Loop-Based Dead End Handling Strategy : SHORT REPORT ...Levelwise PageRank with Loop-Based Dead End Handling Strategy : SHORT REPORT ...
Levelwise PageRank with Loop-Based Dead End Handling Strategy : SHORT REPORT ...
Subhajit Sahu
 
Q1’2024 Update: MYCI’s Leap Year Rebound
Q1’2024 Update: MYCI’s Leap Year ReboundQ1’2024 Update: MYCI’s Leap Year Rebound
Q1’2024 Update: MYCI’s Leap Year Rebound
Oppotus
 
一比一原版(CBU毕业证)卡普顿大学毕业证成绩单
一比一原版(CBU毕业证)卡普顿大学毕业证成绩单一比一原版(CBU毕业证)卡普顿大学毕业证成绩单
一比一原版(CBU毕业证)卡普顿大学毕业证成绩单
nscud
 
做(mqu毕业证书)麦考瑞大学毕业证硕士文凭证书学费发票原版一模一样
做(mqu毕业证书)麦考瑞大学毕业证硕士文凭证书学费发票原版一模一样做(mqu毕业证书)麦考瑞大学毕业证硕士文凭证书学费发票原版一模一样
做(mqu毕业证书)麦考瑞大学毕业证硕士文凭证书学费发票原版一模一样
axoqas
 
Opendatabay - Open Data Marketplace.pptx
Opendatabay - Open Data Marketplace.pptxOpendatabay - Open Data Marketplace.pptx
Opendatabay - Open Data Marketplace.pptx
Opendatabay
 
Criminal IP - Threat Hunting Webinar.pdf
Criminal IP - Threat Hunting Webinar.pdfCriminal IP - Threat Hunting Webinar.pdf
Criminal IP - Threat Hunting Webinar.pdf
Criminal IP
 
Data Centers - Striving Within A Narrow Range - Research Report - MCG - May 2...
Data Centers - Striving Within A Narrow Range - Research Report - MCG - May 2...Data Centers - Striving Within A Narrow Range - Research Report - MCG - May 2...
Data Centers - Striving Within A Narrow Range - Research Report - MCG - May 2...
pchutichetpong
 
06-04-2024 - NYC Tech Week - Discussion on Vector Databases, Unstructured Dat...
06-04-2024 - NYC Tech Week - Discussion on Vector Databases, Unstructured Dat...06-04-2024 - NYC Tech Week - Discussion on Vector Databases, Unstructured Dat...
06-04-2024 - NYC Tech Week - Discussion on Vector Databases, Unstructured Dat...
Timothy Spann
 
Chatty Kathy - UNC Bootcamp Final Project Presentation - Final Version - 5.23...
Chatty Kathy - UNC Bootcamp Final Project Presentation - Final Version - 5.23...Chatty Kathy - UNC Bootcamp Final Project Presentation - Final Version - 5.23...
Chatty Kathy - UNC Bootcamp Final Project Presentation - Final Version - 5.23...
John Andrews
 
一比一原版(YU毕业证)约克大学毕业证成绩单
一比一原版(YU毕业证)约克大学毕业证成绩单一比一原版(YU毕业证)约克大学毕业证成绩单
一比一原版(YU毕业证)约克大学毕业证成绩单
enxupq
 
Quantitative Data AnalysisReliability Analysis (Cronbach Alpha) Common Method...
Quantitative Data AnalysisReliability Analysis (Cronbach Alpha) Common Method...Quantitative Data AnalysisReliability Analysis (Cronbach Alpha) Common Method...
Quantitative Data AnalysisReliability Analysis (Cronbach Alpha) Common Method...
2023240532
 
一比一原版(NYU毕业证)纽约大学毕业证成绩单
一比一原版(NYU毕业证)纽约大学毕业证成绩单一比一原版(NYU毕业证)纽约大学毕业证成绩单
一比一原版(NYU毕业证)纽约大学毕业证成绩单
ewymefz
 
一比一原版(爱大毕业证书)爱丁堡大学毕业证如何办理
一比一原版(爱大毕业证书)爱丁堡大学毕业证如何办理一比一原版(爱大毕业证书)爱丁堡大学毕业证如何办理
一比一原版(爱大毕业证书)爱丁堡大学毕业证如何办理
g4dpvqap0
 
Sample_Global Non-invasive Prenatal Testing (NIPT) Market, 2019-2030.pdf
Sample_Global Non-invasive Prenatal Testing (NIPT) Market, 2019-2030.pdfSample_Global Non-invasive Prenatal Testing (NIPT) Market, 2019-2030.pdf
Sample_Global Non-invasive Prenatal Testing (NIPT) Market, 2019-2030.pdf
Linda486226
 
Influence of Marketing Strategy and Market Competition on Business Plan
Influence of Marketing Strategy and Market Competition on Business PlanInfluence of Marketing Strategy and Market Competition on Business Plan
Influence of Marketing Strategy and Market Competition on Business Plan
jerlynmaetalle
 
一比一原版(Bradford毕业证书)布拉德福德大学毕业证如何办理
一比一原版(Bradford毕业证书)布拉德福德大学毕业证如何办理一比一原版(Bradford毕业证书)布拉德福德大学毕业证如何办理
一比一原版(Bradford毕业证书)布拉德福德大学毕业证如何办理
mbawufebxi
 
一比一原版(UofS毕业证书)萨省大学毕业证如何办理
一比一原版(UofS毕业证书)萨省大学毕业证如何办理一比一原版(UofS毕业证书)萨省大学毕业证如何办理
一比一原版(UofS毕业证书)萨省大学毕业证如何办理
v3tuleee
 
一比一原版(UofM毕业证)明尼苏达大学毕业证成绩单
一比一原版(UofM毕业证)明尼苏达大学毕业证成绩单一比一原版(UofM毕业证)明尼苏达大学毕业证成绩单
一比一原版(UofM毕业证)明尼苏达大学毕业证成绩单
ewymefz
 
一比一原版(UIUC毕业证)伊利诺伊大学|厄巴纳-香槟分校毕业证如何办理
一比一原版(UIUC毕业证)伊利诺伊大学|厄巴纳-香槟分校毕业证如何办理一比一原版(UIUC毕业证)伊利诺伊大学|厄巴纳-香槟分校毕业证如何办理
一比一原版(UIUC毕业证)伊利诺伊大学|厄巴纳-香槟分校毕业证如何办理
ahzuo
 
【社内勉強会資料_Octo: An Open-Source Generalist Robot Policy】
【社内勉強会資料_Octo: An Open-Source Generalist Robot Policy】【社内勉強会資料_Octo: An Open-Source Generalist Robot Policy】
【社内勉強会資料_Octo: An Open-Source Generalist Robot Policy】
NABLAS株式会社
 

Recently uploaded (20)

Levelwise PageRank with Loop-Based Dead End Handling Strategy : SHORT REPORT ...
Levelwise PageRank with Loop-Based Dead End Handling Strategy : SHORT REPORT ...Levelwise PageRank with Loop-Based Dead End Handling Strategy : SHORT REPORT ...
Levelwise PageRank with Loop-Based Dead End Handling Strategy : SHORT REPORT ...
 
Q1’2024 Update: MYCI’s Leap Year Rebound
Q1’2024 Update: MYCI’s Leap Year ReboundQ1’2024 Update: MYCI’s Leap Year Rebound
Q1’2024 Update: MYCI’s Leap Year Rebound
 
一比一原版(CBU毕业证)卡普顿大学毕业证成绩单
一比一原版(CBU毕业证)卡普顿大学毕业证成绩单一比一原版(CBU毕业证)卡普顿大学毕业证成绩单
一比一原版(CBU毕业证)卡普顿大学毕业证成绩单
 
做(mqu毕业证书)麦考瑞大学毕业证硕士文凭证书学费发票原版一模一样
做(mqu毕业证书)麦考瑞大学毕业证硕士文凭证书学费发票原版一模一样做(mqu毕业证书)麦考瑞大学毕业证硕士文凭证书学费发票原版一模一样
做(mqu毕业证书)麦考瑞大学毕业证硕士文凭证书学费发票原版一模一样
 
Opendatabay - Open Data Marketplace.pptx
Opendatabay - Open Data Marketplace.pptxOpendatabay - Open Data Marketplace.pptx
Opendatabay - Open Data Marketplace.pptx
 
Criminal IP - Threat Hunting Webinar.pdf
Criminal IP - Threat Hunting Webinar.pdfCriminal IP - Threat Hunting Webinar.pdf
Criminal IP - Threat Hunting Webinar.pdf
 
Data Centers - Striving Within A Narrow Range - Research Report - MCG - May 2...
Data Centers - Striving Within A Narrow Range - Research Report - MCG - May 2...Data Centers - Striving Within A Narrow Range - Research Report - MCG - May 2...
Data Centers - Striving Within A Narrow Range - Research Report - MCG - May 2...
 
06-04-2024 - NYC Tech Week - Discussion on Vector Databases, Unstructured Dat...
06-04-2024 - NYC Tech Week - Discussion on Vector Databases, Unstructured Dat...06-04-2024 - NYC Tech Week - Discussion on Vector Databases, Unstructured Dat...
06-04-2024 - NYC Tech Week - Discussion on Vector Databases, Unstructured Dat...
 
Chatty Kathy - UNC Bootcamp Final Project Presentation - Final Version - 5.23...
Chatty Kathy - UNC Bootcamp Final Project Presentation - Final Version - 5.23...Chatty Kathy - UNC Bootcamp Final Project Presentation - Final Version - 5.23...
Chatty Kathy - UNC Bootcamp Final Project Presentation - Final Version - 5.23...
 
一比一原版(YU毕业证)约克大学毕业证成绩单
一比一原版(YU毕业证)约克大学毕业证成绩单一比一原版(YU毕业证)约克大学毕业证成绩单
一比一原版(YU毕业证)约克大学毕业证成绩单
 
Quantitative Data AnalysisReliability Analysis (Cronbach Alpha) Common Method...
Quantitative Data AnalysisReliability Analysis (Cronbach Alpha) Common Method...Quantitative Data AnalysisReliability Analysis (Cronbach Alpha) Common Method...
Quantitative Data AnalysisReliability Analysis (Cronbach Alpha) Common Method...
 
一比一原版(NYU毕业证)纽约大学毕业证成绩单
一比一原版(NYU毕业证)纽约大学毕业证成绩单一比一原版(NYU毕业证)纽约大学毕业证成绩单
一比一原版(NYU毕业证)纽约大学毕业证成绩单
 
一比一原版(爱大毕业证书)爱丁堡大学毕业证如何办理
一比一原版(爱大毕业证书)爱丁堡大学毕业证如何办理一比一原版(爱大毕业证书)爱丁堡大学毕业证如何办理
一比一原版(爱大毕业证书)爱丁堡大学毕业证如何办理
 
Sample_Global Non-invasive Prenatal Testing (NIPT) Market, 2019-2030.pdf
Sample_Global Non-invasive Prenatal Testing (NIPT) Market, 2019-2030.pdfSample_Global Non-invasive Prenatal Testing (NIPT) Market, 2019-2030.pdf
Sample_Global Non-invasive Prenatal Testing (NIPT) Market, 2019-2030.pdf
 
Influence of Marketing Strategy and Market Competition on Business Plan
Influence of Marketing Strategy and Market Competition on Business PlanInfluence of Marketing Strategy and Market Competition on Business Plan
Influence of Marketing Strategy and Market Competition on Business Plan
 
一比一原版(Bradford毕业证书)布拉德福德大学毕业证如何办理
一比一原版(Bradford毕业证书)布拉德福德大学毕业证如何办理一比一原版(Bradford毕业证书)布拉德福德大学毕业证如何办理
一比一原版(Bradford毕业证书)布拉德福德大学毕业证如何办理
 
一比一原版(UofS毕业证书)萨省大学毕业证如何办理
一比一原版(UofS毕业证书)萨省大学毕业证如何办理一比一原版(UofS毕业证书)萨省大学毕业证如何办理
一比一原版(UofS毕业证书)萨省大学毕业证如何办理
 
一比一原版(UofM毕业证)明尼苏达大学毕业证成绩单
一比一原版(UofM毕业证)明尼苏达大学毕业证成绩单一比一原版(UofM毕业证)明尼苏达大学毕业证成绩单
一比一原版(UofM毕业证)明尼苏达大学毕业证成绩单
 
一比一原版(UIUC毕业证)伊利诺伊大学|厄巴纳-香槟分校毕业证如何办理
一比一原版(UIUC毕业证)伊利诺伊大学|厄巴纳-香槟分校毕业证如何办理一比一原版(UIUC毕业证)伊利诺伊大学|厄巴纳-香槟分校毕业证如何办理
一比一原版(UIUC毕业证)伊利诺伊大学|厄巴纳-香槟分校毕业证如何办理
 
【社内勉強会資料_Octo: An Open-Source Generalist Robot Policy】
【社内勉強会資料_Octo: An Open-Source Generalist Robot Policy】【社内勉強会資料_Octo: An Open-Source Generalist Robot Policy】
【社内勉強会資料_Octo: An Open-Source Generalist Robot Policy】
 

Bowtie: Interactive Dashboards

  • 3. Who am I? 3 / 50
  • 4. Who am I? Computer Engineer turned "Data Scientist". 3 / 50
  • 5. Who am I? Computer Engineer turned "Data Scientist". Work at energy analytics startup, Verdigris Technologies. 3 / 50
  • 6. Who am I? Computer Engineer turned "Data Scientist". Work at energy analytics startup, Verdigris Technologies. Heavy Python user for 3-5 years. 3 / 50
  • 7. Who am I? Computer Engineer turned "Data Scientist". Work at energy analytics startup, Verdigris Technologies. Heavy Python user for 3-5 years. I'm not a frontend developer. 3 / 50
  • 11. Agenda Motivation A quick start Rapid prototyping tips 4 / 50
  • 12. Agenda Motivation A quick start Rapid prototyping tips Advanced features 4 / 50
  • 13. Agenda Motivation A quick start Rapid prototyping tips Advanced features How to deploy 4 / 50
  • 14. Agenda Motivation A quick start Rapid prototyping tips Advanced features How to deploy Tech stack 4 / 50
  • 15. Agenda Motivation A quick start Rapid prototyping tips Advanced features How to deploy Tech stack Future work and goals 4 / 50
  • 16. Agenda Motivation A quick start Rapid prototyping tips Advanced features How to deploy Tech stack Future work and goals Will not be discussing similar tools. 4 / 50
  • 18. Motivation Want to click on a chart and generate another chart. 5 / 50
  • 19. Motivation Want to click on a chart and generate another chart. 5 / 50
  • 21. Tool Survey Don't want to use R! 6 / 50
  • 22. Tool Survey Don't want to use R! Looked for solutions in Python. 6 / 50
  • 23. Tool Survey Don't want to use R! Looked for solutions in Python. Thought this should be easier. 6 / 50
  • 24. Tool Survey Don't want to use R! Looked for solutions in Python. Thought this should be easier. Thought it would be fun to write something. 6 / 50
  • 27. Initial Thoughts Plotly charts have lots of events: selection, click, and hover. 8 / 50
  • 28. Initial Thoughts Plotly charts have lots of events: selection, click, and hover. Just need to communicate between Python and JS in browser. 8 / 50
  • 29. Initial Thoughts Plotly charts have lots of events: selection, click, and hover. Just need to communicate between Python and JS in browser. Socket.io seems like it could do the trick. 8 / 50
  • 30. Initial Thoughts Plotly charts have lots of events: selection, click, and hover. Just need to communicate between Python and JS in browser. Socket.io seems like it could do the trick. That's good enough for a proof of concept. 8 / 50
  • 31. Fast forward a few months 9 / 50
  • 32. Your First Bowtie App 10 / 50
  • 33. Your First Bowtie App Each app has three parts 10 / 50
  • 34. Your First Bowtie App Each app has three parts Choose the components in your app. 10 / 50
  • 35. Your First Bowtie App Each app has three parts Choose the components in your app. Write the callbacks (in response to events). 10 / 50
  • 36. Your First Bowtie App Each app has three parts Choose the components in your app. Write the callbacks (in response to events). Layout the components and connect everything. 10 / 50
  • 37. First we need some prereqs 11 / 50
  • 38. First we need some prereqs Need Node to get us yarn and webpack. $ brew install node $ npm install -g webpack $ brew install yarn Sorry for the MacOS bias. 11 / 50
  • 39. First we need some prereqs Need Node to get us yarn and webpack. $ brew install node $ npm install -g webpack $ brew install yarn Sorry for the MacOS bias. Install Bowtie. $ pip install bowtie Works on Python 2 and 3 11 / 50
  • 42. Select the components These are the widgets that exist in your app. 13 / 50
  • 43. Select the components These are the widgets that exist in your app. Full list of components on readthedocs. 13 / 50
  • 44. Select the components These are the widgets that exist in your app. Full list of components on readthedocs. Split into two categories: visual widgets and controller widgets. 13 / 50
  • 45. Select the components These are the widgets that exist in your app. Full list of components on readthedocs. Split into two categories: visual widgets and controller widgets. Visual: Plotly, SVG (matplotlib), Tables 13 / 50
  • 46. Select the components These are the widgets that exist in your app. Full list of components on readthedocs. Split into two categories: visual widgets and controller widgets. Visual: Plotly, SVG (matplotlib), Tables Controllers: DatePickers, Dropdown, Text, Sliders, Toggle, and a Button. 13 / 50
  • 47. Select the components These are the widgets that exist in your app. Full list of components on readthedocs. Split into two categories: visual widgets and controller widgets. Visual: Plotly, SVG (matplotlib), Tables Controllers: DatePickers, Dropdown, Text, Sliders, Toggle, and a Button. from bowtie.visual import Plotly from bowtie.control import Dropdown plot = Plotly() ddown = Dropdown() 13 / 50
  • 48. What do these components do? 14 / 50
  • 49. What do these components do? Instructions for displaying itself in a webpage. 14 / 50
  • 50. What do these components do? Instructions for displaying itself in a webpage. Commands, pre xed with do_, to update the state of the widget. 14 / 50
  • 51. What do these components do? Instructions for displaying itself in a webpage. Commands, pre xed with do_, to update the state of the widget. Events, pre xed with on_, to run python in response to. 14 / 50
  • 52. What do these components do? Instructions for displaying itself in a webpage. Commands, pre xed with do_, to update the state of the widget. Events, pre xed with on_, to run python in response to. Getters, pre xed with get, gets the current states of the widget. 14 / 50
  • 53. What do these components do? Instructions for displaying itself in a webpage. Commands, pre xed with do_, to update the state of the widget. Events, pre xed with on_, to run python in response to. Getters, pre xed with get, gets the current states of the widget. For example: Dropdown docs. 14 / 50
  • 54. De ne the callbacks 15 / 50
  • 55. De ne the callbacks We'll de ne functions to get run when events happen. 15 / 50
  • 56. De ne the callbacks We'll de ne functions to get run when events happen. import plotlywrapper as pw def callback(item): chart = pw.line(range(item['value'])) plot.do_all(chart.dict) 15 / 50
  • 57. De ne the callbacks We'll de ne functions to get run when events happen. import plotlywrapper as pw def callback(item): chart = pw.line(range(item['value'])) plot.do_all(chart.dict) We'll run this function in response to a dropdown event. 15 / 50
  • 58. De ne the callbacks We'll de ne functions to get run when events happen. import plotlywrapper as pw def callback(item): chart = pw.line(range(item['value'])) plot.do_all(chart.dict) We'll run this function in response to a dropdown event. The passed object for this dropdown is a dictionary with two keys: "label" and "value". 15 / 50
  • 59. De ne the callbacks We'll de ne functions to get run when events happen. import plotlywrapper as pw def callback(item): chart = pw.line(range(item['value'])) plot.do_all(chart.dict) We'll run this function in response to a dropdown event. The passed object for this dropdown is a dictionary with two keys: "label" and "value". To update the plot we call the do_all method. 15 / 50
  • 61. Layout the App We've chosen the components and de ned the functionality. Now we just need to connect events to functions and lay out the widgets. 16 / 50
  • 62. Layout the App We've chosen the components and de ned the functionality. Now we just need to connect events to functions and lay out the widgets. from bowtie import command @command def build(): from bowtie import Layout layout = Layout() layout.add(plot) layout.add_sidebar(ddown) layout.subscribe(callback, ddown.on_change) layout.build() 16 / 50
  • 63. Layout the App from bowtie import command The command decorator turns this function into a command line interface. @command def build(): from bowtie import Layout layout = Layout() layout.add(plot) layout.add_sidebar(ddown) layout.subscribe(callback, ddown.on_change) layout.build() 17 / 50
  • 64. Layout the App from bowtie import command @command def build(): from bowtie import Layout layout = Layout() These add* calls place widgets into our app. layout.add(plot) layout.add_sidebar(ddown) layout.subscribe(callback, ddown.on_change) layout.build() 18 / 50
  • 65. Layout the App from bowtie import command @command def build(): from bowtie import Layout layout = Layout() layout.add(plot) layout.add_sidebar(ddown) subscribe makes sure the callback gets run in response to the given event. layout.subscribe(callback, ddown.on_change) layout.build() 19 / 50
  • 66. Layout the App from bowtie import command @command def build(): from bowtie import Layout layout = Layout(debug=True) layout.add(plot) layout.add_sidebar(ddown) layout.subscribe(callback, ddown.on_change) Finally, build compiles the app for us. layout.build() 20 / 50
  • 68. Build and Serve We're done writing the app, time to build and run it. 21 / 50
  • 69. Build and Serve We're done writing the app, time to build and run it. The CLI we have gives us these commands: Commands: build Write the app, downloads the packages, and... dev Recompile the app for development. prod Recompile the app for production. serve Serve the Bowtie app. 21 / 50
  • 70. Build and Serve We're done writing the app, time to build and run it. The CLI we have gives us these commands: Commands: build Write the app, downloads the packages, and... dev Recompile the app for development. prod Recompile the app for production. serve Serve the Bowtie app. $ ./app.py build 21 / 50
  • 71. Build and Serve We're done writing the app, time to build and run it. The CLI we have gives us these commands: Commands: build Write the app, downloads the packages, and... dev Recompile the app for development. prod Recompile the app for production. serve Serve the Bowtie app. $ ./app.py build $ ./app.py serve 21 / 50
  • 75. Rapid prototyping Set Layout(debug=True)! Enables live code reloading on write. 25 / 50
  • 76. Rapid prototyping Set Layout(debug=True)! Enables live code reloading on write. Minimize builds by architecting app at the beginning. 25 / 50
  • 77. Rapid prototyping Set Layout(debug=True)! Enables live code reloading on write. Minimize builds by architecting app at the beginning. Use debuggers or prints to learn the payload. def select(points): one of the following: print(points) import ipdb; ipdb.set_trace() import IPython; IPython.embed() import wdb; wdb.set_trace() 25 / 50
  • 79. Listening to Plotly Events 27 / 50
  • 80. Listening to Plotly Events Plotly is a featureful Javascript charting library. 27 / 50
  • 81. Listening to Plotly Events Plotly is a featureful Javascript charting library. It has several events and Bowtie exposes three event types: selection, click, and hover. 27 / 50
  • 82. Listening to Plotly Events Plotly is a featureful Javascript charting library. It has several events and Bowtie exposes three event types: selection, click, and hover. The data it returns is not well documented, but it's not too hard to gure out. 27 / 50
  • 83. Subscribe to Multiple Events 28 / 50
  • 84. Subscribe to Multiple Events A common use-case is for a function to use the output from several widgets. 28 / 50
  • 85. Subscribe to Multiple Events A common use-case is for a function to use the output from several widgets. Cumbersome to write individual callbacks for each event and get the other widgets' states. def foo(a,b): pass def cb1(a): b = b.get() foo(a,b) def cb2(b): a = a.get() foo(a,b) 28 / 50
  • 86. Subscribe to Multiple Events A common use-case is for a function to use the output from several widgets. Cumbersome to write individual callbacks for each event and get the other widgets' states. def foo(a,b): pass def cb1(a): b = b.get() foo(a,b) def cb2(b): a = a.get() foo(a,b) A better way is to subscribe callbacks to multiple events. 28 / 50
  • 87. Subscribe to Multiple Events A common use-case is for a function to use the output from several widgets. Cumbersome to write individual callbacks for each event and get the other widgets' states. def foo(a,b): pass def cb1(a): b = b.get() foo(a,b) def cb2(b): a = a.get() foo(a,b) A better way is to subscribe callbacks to multiple events. def func(item1, item2, switch): cool_stuff() ... layout.subscribe(func, ddown1.on_select, ddown2.on_select, switch.on_switch) 28 / 50
  • 88. Scheduling and Loading Events 29 / 50
  • 89. Scheduling and Loading Events Bowtie also de nes intrinsic event types. 29 / 50
  • 90. Scheduling and Loading Events Bowtie also de nes intrinsic event types. Instruct a function to run when a user loads the page. layout.load(func) 29 / 50
  • 91. Scheduling and Loading Events Bowtie also de nes intrinsic event types. Instruct a function to run when a user loads the page. layout.load(func) Instruct a function to run periodically. layout.schedule(5, func) # call func every 5 seconds 29 / 50
  • 92. Storing data with the client 30 / 50
  • 93. Storing data with the client In some cases it's helpful to be able to store data with the client. 30 / 50
  • 94. Storing data with the client In some cases it's helpful to be able to store data with the client. Could store it server-side, but that's more setup. 30 / 50
  • 95. Storing data with the client In some cases it's helpful to be able to store data with the client. Could store it server-side, but that's more setup. So we'll just send the data to the client and have them hold it. 30 / 50
  • 96. Storing data with the client In some cases it's helpful to be able to store data with the client. Could store it server-side, but that's more setup. So we'll just send the data to the client and have them hold it. bowtie.cache gives a "key-value" store to save any python objects. 30 / 50
  • 97. Storing data with the client In some cases it's helpful to be able to store data with the client. Could store it server-side, but that's more setup. So we'll just send the data to the client and have them hold it. bowtie.cache gives a "key-value" store to save any python objects. Helpful to store results from expensive computations or client speci c data. bowtie.cache.save(key, value) value = bowtie.cache.load(key) 30 / 50
  • 99. Progress Indicators All visual widgets have an attached progress indicator. 31 / 50
  • 100. Progress Indicators All visual widgets have an attached progress indicator. By default they are invisible so they don't get in your way. 31 / 50
  • 101. Progress Indicators All visual widgets have an attached progress indicator. By default they are invisible so they don't get in your way. Really helpful for long computations or slow I/O. 31 / 50
  • 102. Progress Indicators All visual widgets have an attached progress indicator. By default they are invisible so they don't get in your way. Really helpful for long computations or slow I/O. Can also indicate error states. 31 / 50
  • 104. Leverage CSS Grid New web standard to de ne grids on a page. 32 / 50
  • 105. Leverage CSS Grid New web standard to de ne grids on a page. Bowtie uses this and makes a "pythonic" API. 32 / 50
  • 106. Leverage CSS Grid New web standard to de ne grids on a page. Bowtie uses this and makes a "pythonic" API. CSS Grid was just released onto major browsers. 32 / 50
  • 107. Leverage CSS Grid New web standard to de ne grids on a page. Bowtie uses this and makes a "pythonic" API. CSS Grid was just released onto major browsers. Chrome >= 57, Firefox >= 52, Safari >= 10.1, Opera >= 44 32 / 50
  • 108. Leverage CSS Grid Layout class lets you specify how many rows and columns in the grid. 33 / 50
  • 109. Leverage CSS Grid Layout class lets you specify how many rows and columns in the grid. call .add method and optionally specify which cells in the grid. 33 / 50
  • 110. Leverage CSS Grid Layout class lets you specify how many rows and columns in the grid. call .add method and optionally specify which cells in the grid. Widgets can span 1 or multiple cells. 33 / 50
  • 111. Leverage CSS Grid Layout class lets you specify how many rows and columns in the grid. call .add method and optionally specify which cells in the grid. Widgets can span 1 or multiple cells. Rows and columns can be sized on pixels, percentage, and fraction of available space. 33 / 50
  • 113. Authentication Flask makes it easy to support basic authentication. 34 / 50
  • 114. Authentication Flask makes it easy to support basic authentication. Want to have a generic authentication solution. 34 / 50
  • 115. Authentication Flask makes it easy to support basic authentication. Want to have a generic authentication solution. I'm not a security expert so don't trust me. 34 / 50
  • 119. Deploying Heroku is an easy option. 37 / 50
  • 120. Deploying Heroku is an easy option. Set Layout(debug=False) 37 / 50
  • 121. Deploying Heroku is an easy option. Set Layout(debug=False) Compile with production. $ python app.py prod Reduces JS bundle size by a factor of ~30 (from 30MB to 1MB). 37 / 50
  • 122. Deploying Heroku is an easy option. Set Layout(debug=False) Compile with production. $ python app.py prod Reduces JS bundle size by a factor of ~30 (from 30MB to 1MB). Commit the following les build/src/server.py build/src/templates/index.html build/src/static/bundle.js.gz 37 / 50
  • 125. Flask-SocketIO Bowtie is built on Flask and Flask-SocketIO. 39 / 50
  • 126. Flask-SocketIO Bowtie is built on Flask and Flask-SocketIO. Bowtie abstracts away most of Flask. 39 / 50
  • 127. Flask-SocketIO Bowtie is built on Flask and Flask-SocketIO. Bowtie abstracts away most of Flask. You can still bene t from the Flask ecosystem. 39 / 50
  • 128. Flask-SocketIO Bowtie is built on Flask and Flask-SocketIO. Bowtie abstracts away most of Flask. You can still bene t from the Flask ecosystem. Kind of wish the user still touched Flask because it's a great API. 39 / 50
  • 130. React Nick Kridler (author of Pyxley) wrote about using React with Python. 40 / 50
  • 131. React Nick Kridler (author of Pyxley) wrote about using React with Python. Frontend is written entirely in React. 40 / 50
  • 132. React Nick Kridler (author of Pyxley) wrote about using React with Python. Frontend is written entirely in React. Making a new widget means making a new React class that communicates via socket.io. 40 / 50
  • 134. Talking through SocketIO All communication between Python and Javascript is through SocketIO 41 / 50
  • 135. Talking through SocketIO All communication between Python and Javascript is through SocketIO Unique events are created by combining the component id with the type of message. 41 / 50
  • 136. Talking through SocketIO All communication between Python and Javascript is through SocketIO Unique events are created by combining the component id with the type of message. For example: the event for updating Plotly is "{id}#all" 41 / 50
  • 137. Talking through SocketIO All communication between Python and Javascript is through SocketIO Unique events are created by combining the component id with the type of message. For example: the event for updating Plotly is "{id}#all" Message payloads are encoded with msgpack to reduce payload size. 41 / 50
  • 139. Javascript Tools Yarn: for installing npm packages. 42 / 50
  • 140. Javascript Tools Yarn: for installing npm packages. Webpack: for bundling the npm packages. 42 / 50
  • 141. Javascript Tools Yarn: for installing npm packages. Webpack: for bundling the npm packages. Leaky abstraction, but I don't want to turn bowtie into a node delivery device. 42 / 50
  • 142. Future Work and Goals 43 / 50
  • 143. Some things I don't like 44 / 50
  • 144. Some things I don't like You need to recompile your app to run it (when you make architectural changes) which takes a minute. 44 / 50
  • 145. Some things I don't like You need to recompile your app to run it (when you make architectural changes) which takes a minute. Compared to some other tools, Bowtie is not as snappy. 44 / 50
  • 146. Some things I don't like You need to recompile your app to run it (when you make architectural changes) which takes a minute. Compared to some other tools, Bowtie is not as snappy. Perhaps too much magic happening behind the scenes, harder for users to change things and x issues. 44 / 50
  • 148. User Experience Goals The power to create as much interactivity as you want. 45 / 50
  • 149. User Experience Goals The power to create as much interactivity as you want. Painless rapid prototyping 45 / 50
  • 150. User Experience Goals The power to create as much interactivity as you want. Painless rapid prototyping Be able to share with others 45 / 50
  • 152. Non Goals GUI for laying out widgets. 46 / 50
  • 153. Non Goals GUI for laying out widgets. Generic web app builder (my focus is on data science applications). 46 / 50
  • 154. Goals and Future Work 47 / 50
  • 155. Goals and Future Work Become Shiny! 47 / 50
  • 156. Goals and Future Work Become Shiny! Okay, but seriously. 47 / 50
  • 157. Goals and Future Work Become Shiny! Okay, but seriously. Needs to be more robust, have better testing. 47 / 50
  • 158. Goals and Future Work Become Shiny! Okay, but seriously. Needs to be more robust, have better testing. Make it easier to scale and deploy. 47 / 50
  • 159. Goals and Future Work Become Shiny! Okay, but seriously. Needs to be more robust, have better testing. Make it easier to scale and deploy. More charting libraries. 47 / 50
  • 160. Goals and Future Work Become Shiny! Okay, but seriously. Needs to be more robust, have better testing. Make it easier to scale and deploy. More charting libraries. More widgets. 47 / 50
  • 161. Goals and Future Work Become Shiny! Okay, but seriously. Needs to be more robust, have better testing. Make it easier to scale and deploy. More charting libraries. More widgets. Make it look nicer? 47 / 50
  • 162. Goals and Future Work Become Shiny! Okay, but seriously. Needs to be more robust, have better testing. Make it easier to scale and deploy. More charting libraries. More widgets. Make it look nicer? Jupyter integration (possible?) 47 / 50
  • 163. My Real Goal Whether Bowtie becomes the Shiny of Python or not, I simply want to move the bar forward. 48 / 50
  • 164. Thanks To my Verdigris colleagues for feedback. Danny Servén Jared Kruzek Martin Chang Michael Roberts To Je for letting me present. 49 / 50