Skip to content

Commit

Permalink
Merge pull request #39 from delsim/html_formation
Browse files Browse the repository at this point in the history
Html formation to enable dash app without iframe
  • Loading branch information
GibbsConsulting authored Aug 30, 2018
2 parents e1b2a51 + f751a6c commit f33f600
Show file tree
Hide file tree
Showing 19 changed files with 536 additions and 48 deletions.
102 changes: 102 additions & 0 deletions demo/demo/dash_apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
'''Dash demonstration application
TODO attribution here
'''

# The linter doesn't like the members of the html and dcc imports (as they are dynamic?)
#pylint: disable=no-member

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
#import dpd_components as dpd
import numpy as np
from django_plotly_dash import DjangoDash

#from .urls import app_name
app_name = "DPD demo application"

dashboard_name1 = 'dash_example_1'
dash_example1 = DjangoDash(name=dashboard_name1,
serve_locally=True,
app_name=app_name
)

# Below is a random Dash app.
# I encountered no major problems in using Dash this way. I did encounter problems but it was because
# I was using e.g. Bootstrap inconsistenyly across the dash layout. Staying consistent worked fine for me.
dash_example1.layout = html.Div(id='main',
children=[
html.Div([dcc.Dropdown(id='my-dropdown1',
options=[{'label': 'New York City', 'value': 'NYC'},
{'label': 'Montreal', 'value': 'MTL'},
{'label': 'San Francisco', 'value': 'SF'}
],
value='NYC',
className='col-md-12',
),
html.Div(id='test-output-div')
]),

dcc.Dropdown(
id='my-dropdown2',
options=[
{'label': 'Oranges', 'value': 'Oranges'},
{'label': 'Plums', 'value': 'Plums'},
{'label': 'Peaches', 'value': 'Peaches'}
],
value='Oranges',
className='col-md-12',
),

html.Div(id='test-output-div2')

]) # end of 'main'

@dash_example1.expanded_callback(
dash.dependencies.Output('test-output-div', 'children'),
[dash.dependencies.Input('my-dropdown1', 'value')])
def callback_test(*args, **kwargs): #pylint: disable=unused-argument
'Callback to generate test data on each change of the dropdown'

# Creating a random Graph from a Plotly example:
N = 500
random_x = np.linspace(0, 1, N)
random_y = np.random.randn(N)

# Create a trace
trace = go.Scatter(x=random_x,
y=random_y)

data = [trace]

layout = dict(title='',
yaxis=dict(zeroline=False, title='Total Expense (£)',),
xaxis=dict(zeroline=False, title='Date', tickangle=0),
margin=dict(t=20, b=50, l=50, r=40),
height=350,
)


fig = dict(data=data, layout=layout)
line_graph = dcc.Graph(id='line-area-graph2', figure=fig, style={'display':'inline-block', 'width':'100%',
'height':'100%;'})
children = [line_graph]

return children


@dash_example1.expanded_callback(
dash.dependencies.Output('test-output-div2', 'children'),
[dash.dependencies.Input('my-dropdown2', 'value')])
def callback_test2(*args, **kwargs):
'Callback to exercise session functionality'

print(args)
print(kwargs)

children = [html.Div(["You have selected %s." %(args[0])]),
html.Div(["The session context message is '%s'" %(kwargs['session_state']['django_to_dash_context'])])]

return children
2 changes: 1 addition & 1 deletion demo/demo/plotly_apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def callback_c(*args, **kwargs):
return "Args are [%s] and kwargs are %s" %(",".join(args), str(kwargs))

liveIn = DjangoDash("LiveInput",
serve_locally=True,
serve_locally=False,
add_bootstrap_links=True)

liveIn.layout = html.Div([
Expand Down
3 changes: 3 additions & 0 deletions demo/demo/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',

'django_plotly_dash.middleware.BaseMiddleware',

'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

Expand Down
48 changes: 28 additions & 20 deletions demo/demo/templates/base.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
<!DOCTYPE HTML>
<html>
<head>
{%load plotly_dash%}
{%load staticfiles%}
{%load bootstrap4%}
{%bootstrap_css%}
{%bootstrap_javascript jquery="full"%}
{%block extra_header%}{%endblock%}
{%block app_header_css%}
{% load plotly_dash%}
{% load staticfiles%}
{% load bootstrap4%}
{% bootstrap_css%}
{% bootstrap_javascript jquery="full"%}
{% block extra_header%}{% endblock%}
{% block app_header_css%}
<link rel="stylesheet" type="text/css" href="{%static "demo/demo.css"%}"></link>
{%endblock%}
<title>Django Plotly Dash Examples - {%block title%}{%endblock%}</title>
{% endblock%}
{% plotly_header%}
<title>Django Plotly Dash Examples - {% block title%}{% endblock%}</title>
</head>
<body>
<header>
Expand All @@ -19,26 +20,33 @@
<a class="navbar-brand" href="#">
<img src="{%static "demo/logo.svg"%}" alt="Logo"/>
</a>
{%block demo_items%}
{% block demo_items %}
<a class="nav-item nav-link btn btn-lg" href="{%url "home"%}">Contents</a>
<a class="nav-item nav-link btn btn-lg" href="{%url "demo-one"%}">Demo One - Simple Use</a>
<a class="nav-item nav-link btn btn-lg" href="{%url "demo-two"%}">Demo Two - Initial State</a>
<a class="nav-item nav-link btn btn-lg" href="{%url "demo-three"%}">Demo Three - Enhanced Callbacks</a>
<a class="nav-item nav-link btn btn-lg" href="{%url "demo-four"%}">Demo Four - Live Updating</a>
{% block demo_menu_items %}
{% if 0 %}
<a class="nav-item nav-link btn btn-lg" href="{%url "demo-one"%}">One - Simple Use</a>
<a class="nav-item nav-link btn btn-lg" href="{%url "demo-two"%}">Two - Initial State</a>
<a class="nav-item nav-link btn btn-lg" href="{%url "demo-three"%}">Three - Enhanced Callbacks</a>
<a class="nav-item nav-link btn btn-lg" href="{%url "demo-four"%}">Four - Live Updating</a>
<a class="nav-item nav-link btn btn-lg" href="{%url "demo-five"%}">Five - Direct Injection</a>
<a class="nav-item nav-link btn btn-lg" href="{%url "demo-six"%}">Six - Simple Injection</a>
{% endif %}
{% endblock %}
<a class="nav-item nav-link btn btn-lg"
target="_blank"
href="https://django-plotly-dash.readthedocs.io/en/latest/">Online Documentation</a>
{%endblock%}
{% endblock %}
</div>
</nav>
</header>
<main>
<div class="container">
{%block content%}{%endblock%}
{% block content%}{% endblock%}
</div>
</main>
{%block footer%}
{%endblock%}
</body>
{%block post_body%}{%endblock%}
{% block footer%}
{% endblock%}
</body>
{% block post_body%}{% endblock%}
{% plotly_footer%}
</html>
35 changes: 35 additions & 0 deletions demo/demo/templates/demo_five.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{%extends "base.html"%}
{%load plotly_dash%}

{%block title%}Demo One - Simple Embedding{%endblock%}

{%block content%}
<h1>Direct App Embedding</h1>
<p>
This is a simple example of use of a dash application within a Django template. Use of
the plotly_direct template tag with the name of a dash application causes
the Dash application to be directly embedded within the page.
</p>
<p>
The plotly_class tag is also used to wrap the application in css class names based on the
application (django-plotly-dash), the
type of the embedding (here labelled "div-direct"), and the slugified version of the app name (simpleexample).
</p>
<div class="card bg-light border-dark">
<div class="card-body">
<p><span>{</span>% load plotly_dash %}</p>
<p>&lt;div class="<span>{</span>% plotly_class name="SimpleExample" template_type="div-direct"%}">
<p class="ml-3"><span>{</span>% plotly_direct name="SimpleExample" %}</p>
<p>&lt;\div>
</div>
</div>
<p></p>
<div class="card border-dark">
<div class="card-body">
<div class="{%plotly_class name="SimpleExample" template_type="div-direct"%}">
{%plotly_direct name="SimpleExample"%}
</div>
</div>
</div>
<p></p>
{%endblock%}
14 changes: 13 additions & 1 deletion demo/demo/templates/demo_four.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ <h1>Live Updating</h1>
Live updating uses a websocket connection. The server pushes messages to the UI, and this is then translated into a
callback through a dash component.
</p>
<p>
Each press of a button causes a new random value to be added to that colour's time series in each
chart. Separate values are generated for each chart. The top chart has values
local to this page, and the bottom chart - including its values - is shared across all views of this
page.
</p>
<p>
Reloading this page, or viewing in a second browser window, will show a new and initially empty
top chart and a copy of the bottom chart. Pressing any button in any window will cause all instances
of the bottom chart to update with the same values. Note that button presses are throttled so that
only one press per colour per second is processed.
</p>
<div class="card bg-light border-dark">
<div class="card-body">
<p><span>{</span>% load plotly_dash %}</p>
Expand Down Expand Up @@ -45,7 +57,7 @@ <h1>Live Updating</h1>
</p>
<p>
Any http command
can be used to send a message to the apps. This is equiavent to a press of
can be used to send a message to the apps. This is equivalent to a press of
the red button. Other colours can be specified, including yellow, cyan and black in
addition to the three named in the LiveInput app.
</p>
Expand Down
36 changes: 36 additions & 0 deletions demo/demo/templates/demo_six.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{%extends "base.html"%}
{%load plotly_dash%}

{%block title%}Demo Six - Simple Injection{%endblock%}

{%block content%}

<h1>Simple embedding</h1>

<p>
Direct insertion of html into a web page.
</p>

<p>
This demo is based on a contribution by, and
with thanks to, <a href="https://github.com/eddy-ojb">@eddy-ojb</a>
</p>

<div class="card bg-light border-dark">
<div class="card-body">
<p><span>{</span>% load plotly_dash %}</p>
<p>&lt;div class="<span>{</span>% plotly_class name="dash_example_1" template_type="div-direct"%}">
<p class="ml-3"><span>{</span>% plotly_direct name="dash_example_1" %}</p>
<p>&lt;\div>
</div>
</div>
<p></p>
<div class="card border-dark">
<div class="card-body">
<div class="{%plotly_class name="dash_example_1" template_type="div-direct"%}">
{%plotly_direct name="dash_example_1"%}
</div>
</div>
</div>
<p></p>
{%endblock%}
2 changes: 2 additions & 0 deletions demo/demo/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ <h1>Demonstration Application</h1>
<li><a class="btn btn-primary btnspace" href="{%url "demo-two"%}">Demo Two</a> - storage of application initial state within Django</li>
<li><a class="btn btn-primary btnspace" href="{%url "demo-three"%}">Demo Three</a> - adding Django features with enhanced callbacks</li>
<li><a class="btn btn-primary btnspace" href="{%url "demo-four"%}">Demo Four</a> - live updating of apps by pushing from the Django server</li>
<li><a class="btn btn-primary btnspace" href="{%url "demo-five"%}">Demo Five</a> - injection of a Dash application without embedding in an html iframe</li>
<li><a class="btn btn-primary btnspace" href="{%url "demo-six"%}">Demo Six</a> - simple html injection example</li>
</ul>
{%endblock%}
2 changes: 1 addition & 1 deletion demo/demo/tests/test_dpd_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
def test_template_tag_use(client):
'Check use of template tag'

for name in ['demo-one', 'demo-two', 'demo-three', 'demo-four',]:
for name in ['demo-one', 'demo-two', 'demo-three', 'demo-four', 'demo-five', 'demo-six',]:
url = reverse(name, kwargs={})

response = client.get(url)
Expand Down
5 changes: 5 additions & 0 deletions demo/demo/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,20 @@

# Load demo plotly apps - this triggers their registration
import demo.plotly_apps # pylint: disable=unused-import
import demo.dash_apps # pylint: disable=unused-import

from django_plotly_dash.views import add_to_session

from .views import dash_example_1_view

urlpatterns = [
url('^$', TemplateView.as_view(template_name='index.html'), name="home"),
url('^demo-one$', TemplateView.as_view(template_name='demo_one.html'), name="demo-one"),
url('^demo-two$', TemplateView.as_view(template_name='demo_two.html'), name="demo-two"),
url('^demo-three$', TemplateView.as_view(template_name='demo_three.html'), name="demo-three"),
url('^demo-four$', TemplateView.as_view(template_name='demo_four.html'), name="demo-four"),
url('^demo-five$', TemplateView.as_view(template_name='demo_five.html'), name="demo-five"),
url('^demo-six', dash_example_1_view, name="demo-six"),
url('^admin/', admin.site.urls),
url('^django_plotly_dash/', include('django_plotly_dash.urls')),

Expand Down
19 changes: 19 additions & 0 deletions demo/demo/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'''
Example view generating non-trivial content
'''

from django.shortcuts import render

#pylint: disable=unused-argument

def dash_example_1_view(request, template_name="demo_six.html", **kwargs):
'Example view that inserts content into the dash context passed to the dash application'

context = {}

# create some context to send over to Dash:
dash_context = request.session.get("django_plotly_dash", dict())
dash_context['django_to_dash_context'] = "I am Dash receiving context from Django"
request.session['django_plotly_dash'] = dash_context

return render(request, template_name=template_name, context=context)
Loading

0 comments on commit f33f600

Please sign in to comment.