gibbsconsulting / django-plotly-dash Goto Github PK
View Code? Open in Web Editor NEWExpose plotly dash apps as django tags
License: MIT License
Expose plotly dash apps as django tags
License: MIT License
Hi,
I think the above loading caption is possibly useful for debugging but I think that the end user shouldn't have to read that it is using django-plotly-dash. Are we able to revert back to just a "Loading..." caption ?
Add preamble to code files where appropriate.
Also, a CONTRIBUTORS document would be appropriate.
We are looking to build a Django app that integrates multiple Dash apps. We would like to limit access to each of the dash apps based on Django auth. Is there an example of how we could use Django auth to provide group-based access control to Dash apps using this wrapper?
KeyError at /new/ , In template test.html: Error during template rendering error at line 14
#below test.html:
{%load plotly_dash%}
{%block content%}
{% load plotly_dash %}
<div class="{% plotly_class name="SE"%}">
{% plotly_app name="SE" %}
<\div>
path('new/',TemplateView.as_view(template_name='test.html'),name='new'),
import dash
import dash_core_components as dcc
import dash_html_components as html
from django_plotly_dash import DjangoDash
app = DjangoDash('SE') # replaces dash.Dash
app.layout = html.Div([dcc.RadioItems(id='dropdown-color',options=[{'label': c, 'value': c.lower()} for c in ['Red', 'Green', 'Blue']],value='red'),html.Div(id='output-color'),dcc.RadioItems(id='dropdown-size',options=[{'label': i,'value': j} for i, j in [('L','large'), ('M','medium'), ('S','small˓→')]],value='medium'),html.Div(id='output-size')])
@app.callback(dash.dependencies.Output('output-color', 'children'),[dash.dependencies.Input('dropdown-color', 'value')])
def callback_color(dropdown_value):
return "The selected color is %s." % dropdown_value
@app.callback(dash.dependencies.Output('output-size', 'children'),[dash.dependencies.Input('dropdown-color', 'value'),dash.dependencies.Input('dropdown-size', 'value')])
def callback_size(dropdown_color, dropdown_size):
return "The chosen T-shirt is a %s %s one." %(dropdown_size,dropdown_color)
changes in setting.py:
ALLOWED_HOSTS = ['*']
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_plotly_dash.apps.DjangoPlotlyDashConfig',
'dash',
'channels',
'topictrends'
]
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("127.0.0.1", 8080)],
},
},
}
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'topictrends/templates/files')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'topictrends.wsgi.application'
ASGI_APPLICATION = "topictrends.routing.application"
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:8080/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient"
},
"KEY_PREFIX": "dpd-demo"
}
}
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
'hosts': [('127.0.0.1', 8080),],
},
},
}
what else i need to add ? i checked demo page and implemented this!
django_plotly_dash.middleware collects the information about which js modules are required for the apps loaded on the page. It saves this information in the request.dpd_content_handler member. These lines importing js are later substituted in place of the place-holder string inserted by the {% plotly_footer %} template tag.
The problem is that some django content management systems (specifically, wagtail) create a new dummy request object for the purpose of implementing their advanced page preview features and the like. This causes the state saved in the old request object to be lost. When a new (dummy) request object is created, the only arbitrary request fields (like dpd_content_handler above) that can be arranged to get copied over to the new request have to come from the request.META dict.
I got this problem fixed by changing the BaseMiddleware.call method like below:
def __call__(self, request):
meta = request.META
if not 'dpd_content_handler' in meta:
meta['dpd_content_handler'] = ContentCollector()
request.dpd_content_handler = meta['dpd_content_handler']
response = self.get_response(request)
response = request.dpd_content_handler.adjust_response(response)
return response
Hi!
I tried pip installing django-plotly-dash and have added
'django_plotly_dash.apps.DjangoPlotlyDashConfig',
to the settings of the django project,
copied the plotly_apps.py file into my project, imported it in my urls.py and added the {%load plotly_dash %}
in the template but I'm getting an error when i try to render this template:
django.template.exceptions.TemplateSyntaxError: 'plotly_dash' is not a registered tag library.
I'm not sure what I have to do to make sure the tag library is registered?
hi ,
{%load plotly_dash%}
{%plotly_app name="SimpleExample"%}
where should this tag need to be added ? should i create a new html file and add this as 2 lines?
that html file need to render in views file ?
When using the dash_app
template tag, the contents are rendered in an iframe. A curious user can inspect the page source and get the direct link to the Dash app directly form the iframe. The direct link might allow the user to bypass access control and other precautions built into a project. This seems to undermine the view based access control:
Each view delegated through to plotly_dash can be wrapped using a view decoration function. This enables access to be restricted to logged-in user
How can we mitigate the risk of potential abuse, particularly when dashboards may contain sensitive data?
Potential performance improvement possible through eliminating downloading the same js files from different urls (if the browser stores them separately)?
For example, in demo-three, [email protected] is downloaded from at least two paths: /django_plotly_dash/* and /static/dash/dash_renderer/*
As reported on the dash github under issue #488:
When trying to use a plotly app in django_plotly_dash, I (and other folks) get both of the following:
Refused to execute script from 'https://unpkg.com/[email protected]/dash_core_components/dash_core_components.min.js.map' because its MIME type ('application/json') is not executable, and strict MIME type checking is enabled.
127.0.0.1/:1Refused to execute script from 'https://unpkg.com/[email protected]/dash_renderer/dash_renderer.min.js.map' because its MIME type ('application/json') is not executable, and strict MIME type checking is enabled.
My environment:
using
@T4rk1n noted regarding django_plotly_dash:
They handle the bundles differently and need to patch it to not auto serve the dist items marked as dynamic.
I think @MarcSkovMadsen and possibly @edwindt and @boludo00 would be interested in a solution as well.
While building a project with django-plotly-dash, I added the django-bootstrap-components package. For some reason, the django-bootstrap-components are not binding with the DjangoDash
class, as they are probably looking for the Dash
class. As a result, my django-plotly-dash app is throwing errors:
Error loading dependencies
The browser console says:
Error: "dash_bootstrap_components was not found."
Related issue: facultyai/dash-bootstrap-components#96
The Django architecture encourages developers to separate code into separate files, such as models, views, settings, etc.. Similarly, it would be cleaner to architect Dash apps in a more Django-esque manner, by separating out the app, layout, callbacks, etc into separate files. An example of this type of architecture can be see in the slapdash project layout.
How can we architect django-plotly-dash
projects to have clean separation of code? Specifically, how can we put callbacks and layout into separate files from the DjangoDash app instance?
I've setup the dash app and I've managed to get it to load in the main website but I'm getting the error:
Error loading dependencies
Is there any method to get information about exactly what error is causing this, such as a logfile or similar? I've tried with several different dash_apps that I know can run on my system and always recieve this message
Thanks!
This is not necessarily an issue but I have noticed that Dash must be opening it's own session with the database.
I noticed this when I was accessing a database that had user specific security policies applied. In order to use a Django defined model, I had to send to the database the user id for Dash and Django separately to acquire data from the database. This makes sense considering that Dash is loaded in as an IFrame.
Are there plans on the roadmap to integrate the two more closely? Is this even practical in your opinion or will this need recoding by Plotly before this is possible?
A TravisCI build exists and includes code coverage. The results should be added to the README document and also the documentation.
I am restricted to windows machines at work and am having issues installing django-channels. I am also restricted by the versions of Visual C++ which might make working with this package impractical in the long run.
Is django-channels a must to get this to work and is this to be incorporated in every release for the future?
Are you able to recommend a way of running without django-channels?
How can we send a URL parameter, such as a query string or named router parameter, into the Dash instance? For example, specifying a date range or identifier in the router URL, which could then be used in query logic within the Dash callbacks.
I am passing an initial value with a template tag
{%plotly_app initial_arguments='{"artnum": {"value":"111"}}' name="Test" %}
to a inputfield in a dash app
dcc.Input(id='artnum', placeholder='Enter a value...',type='number',value='')
On a local machine it works fine.
After deloyment to a google cloud flexible engine the value is sometimes given to the app. Sometimes the input is blank.
Seems random.
Could i be some chache problem?
Any idea to control this?
Just FYI - you might want to mention or put somewhere that this is Django2.0+ only (because of how the URL's are structured).
If defining an app with serve_locally=True
, is there a way to pass locally served css?
Dash_app1 = DjangoDash(name='Dash_app1', serve_locally=True, add_bootstrap_links=True)
# and optionally passing some other css
Dash_app1.css.append_css({'external_url': 'http://127.0.0.1:8000/static/demoapp/css/demoapp.css'})
This results in errors from Dash such as:
A local version of ['https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css'] is not available
I suspect this is a result of the latest version of Dash.
Issue #58 concerns the location of files containing dash code (ie for layout and callbacks and the like). This discussion, or a summary of it, belongs in the FAQ
Hi,
Can you please post a tutorial to set up the demo in an anaconda virtual env (noob question, but nonetheless it would be helpful).
Add a staticfiles finder to enable Django to locate Dash assets and external resources
The documentation of view decoration for access control
is somewhat sparse.
More documentation and examples have been requested and would be helpful.
I have noticed an issue with injecting a dpd iframe in to a page where the parent div is restricting the iframe:
If amending the parent div height from 0 to X pixels, this resolves the issue:
Perhaps each parent div should be given an id that is a function of the DjangoDash name property a standard? This way, we can apply our own css to size the iframe container.
For example, in plotly_items.html:
<div id={{app.name}} style="{{dstyle}}">
<iframe src="{{app.base_url}}" style="{{istyle}}"frameborder="{{fbs}}"></iframe>
</div>
If I have media files that I wish to access, DPD appears to get hold of this request and doesn't play nicely with it:
Traceback (most recent call last):
File "C:\Users\eburm\AppData\Local\conda\conda\envs\platform\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Users\eburm\AppData\Local\conda\conda\envs\platform\lib\site-packages\django_plotly_dash\middleware.py", line 73, in __call__
response = request.dpd_content_handler.adjust_response(response)
File "C:\Users\eburm\AppData\Local\conda\conda\envs\platform\lib\site-packages\django_plotly_dash\middleware.py", line 45, in adjust_response
c1 = self._replace(response.content,
File "C:\Users\eburm\AppData\Local\conda\conda\envs\platform\lib\site-packages\django\http\response.py", line 366, in content
"`streaming_content` instead." % self.__class__.__name__
AttributeError: This FileResponse instance has no `content` attribute. Use `streaming_content` instead.
HTTP GET /media/app_thumbnails/media_9f2MF6K.jpg 500 [0.11, 127.0.0.1:51234]
If I remove DPD from the project, the link works fine.
This is an awesome project and I appreciate your work!
When installing from pip install -r requirements.txt
the install will fail because in setup.py for django-plotly-dash has the line import django_plotly_dash as dpd
which requires dash, django, etc. to work.
See point 6. https://packaging.python.org/guides/single-sourcing-package-version/
Although this technique is common, beware that it will fail if sample/__init__.py imports packages from install_requires dependencies, which will very likely not be installed yet when setup.py is run.
I was able to get it working by removing django-plotly-dash from the requirements.txt file and installing it separately after everything else. I don't know if you like any other methods proposed for version number, but I thought you would like to know about the issue.
Thank you again for your work!
I followed the installation steps here. When I run manage.py migrate
, I receive the following error:
AttributeError: 'Settings' object has no attribute 'PLOTLY_DASH'
Can you either help me understand why this error is occurring or check to see if this is just a bug?
I've attached my requirements.txt here if you need my specific versioning.
requirements.txt
From issue #51 (and also #48 ) it looks like trying to use an unregistered Dash
app does not give a helpful error message. Even if this is not the resolution for that specific issue, it would be good to have a more helpful explanation of the problem when there is an attempt to use an app that has not been registered.
Initial values from a template tag are pushed to the app through the Django cache.
The timeout for these values should be controlled through a setting.
I am trying to have a graph load based off values I get from the Django user. Is this possible using django-plotly-dash
I set up a working template with the plotly_app
template tag, and the SimpleExample
Dash app rendered. However, when I change plotly_app
to plotly_direct
, I get the following error:
'WSGIRequest' object has no attribute 'dpd_content_handler'
What is missing from the SimpleExample app that would provide the dpd_content_handler
?
I realise I am posting a lot on here, sorry!
One thought that occurred to me as I have been porting some of my existing code over is that injecting the html code instead of an iframe is more desirable to me as a developer as I can use the same css across Django and Dash as well as not having to deal with the nuances of an iframe. My dashboard code doesn't quite render with the same scaling using an iframe, even though the code is the same as when I didn't use django-dash-plotly, if that makes sense.
I plan to start looking deeper in to your code to try and understand how you are wrapping around Dash and see if this is feasible!
Create v1.0 release and tag as such in code and RTD.
Using the cache to store initial values is fine as long as there is a cache available. It would be good to have a solution for when this is not the case.
Issue #71 is an example of this being problematic.
Add a logo for the demo
Hi all,
Does dpd accept suppression of callback exceptions as per Dash's error?
If you are assigning callbacks to components
that are generated by other callbacks
(and therefore not in the initial layout), then
you can suppress this exception by setting
`app.config['suppress_callback_exceptions']=True`.
I have looked through the code but can't see this yet. I am thinking about writing another wrapper to include this but don't to duplicate.
It is a useful feature for callbacks relying on elements that haven't been produced in advance.
e.g. I need to produce components after the layout has been defined.
On a related question, I remember @delsim mentioning that the new Dash template system was looking to be utilized. Have you come up with any ideas for this?
I am wondering whether we are thinking broadly along the same lines. e.g. I have used my branch of the code in order to return complex html layouts. Essentially, I define a layout in plain html e.g. I borrow elements from the Gentellela dashboard) and then run a script that converts this in to a dash layout function, retaining html id's and classes only. It then finds the appropriate layout function in dash_layouts.py and replaces with the newly created layout. This way, I never look at a Dash layout but focus on the html, registering the Dash apps and assigning callbacks, making Dash much simpler to use for me. Whilst the UI isn't super fast for a large dashboard, it looks good, is fine for dev and I think it will speed up a little when attached to a proper server with decent specs.
I've got strange issue.. everything works perfectly fine on development django server, but when running on gunicorn i get this error:
Internal Server Error: /django_plotly_dash/instance/kr_2/
Traceback (most recent call last):
File "/opt/jpk/django_plotly_dash/dash_wrapper.py", line 61, in get_local_stateless_by_name
return usable_apps[name]
KeyError: 'kr_2'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/opt/jpk/venv/lib64/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/opt/jpk/venv/lib64/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/opt/jpk/venv/lib64/python3.6/site-packages/django/core/handlers/base.py", line 124, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/opt/jpk/django_plotly_dash/views.py", line 100, in main_view
_, app = DashApp.locate_item(ident, stateless, cache_id=cache_id)
File "/opt/jpk/django_plotly_dash/models.py", line 200, in locate_item
app = dash_app.as_dash_instance(cache_id=cache_id)
File "/opt/jpk/django_plotly_dash/models.py", line 162, in as_dash_instance
dash_app = self.stateless_app.as_dash_app() # pylint: disable=no-member
File "/opt/jpk/django_plotly_dash/models.py", line 59, in as_dash_app
dateless_dash_app = get_stateless_by_name(self.app_name)
File "/opt/jpk/django_plotly_dash/models.py", line 36, in get_stateless_by_name
return get_local_stateless_by_name(name)
File "/opt/jpk/django_plotly_dash/dash_wrapper.py", line 91, in get_local_stateless_by_name
raise KeyError("Unable to find stateless DjangoApp called %s"%name)
KeyError: 'Unable to find stateless DjangoApp called kr_2'
when running this code:
uid_counter = 0
usable_apps = {}
def add_usable_app(name, app):
'Add app to local registry by name'
name = slugify(name)
global usable_apps # pylint: disable=global-statement
usable_apps[name] = app
return name
def get_local_stateless_by_name(name):
'''
Locate a registered dash app by name, and return a DjangoDash instance encapsulating the app.
'''
name = slugify(name)
# TODO wrap this in raising a 404 if not found
try:
return usable_apps[name]
except:
raise KeyError("Unable to find stateless DjangoApp called %s"%name)
Any ideas what could go wrong?
Is there a way to serve csv files from the dash app. Similarly to what can be seen in this link in Flask https://community.plot.ly/t/allow-users-to-dowload-an-excel-in-a-click/9410
That is :
@app.server.route('/download_excel/')
def download_excel():
''' prepare excel or csv file '''
return send_file(...)
Indeed, if I do a redirect()
from django, I get a successful post from the server but I don't get redirected:
@app.callback(
Output('hidden-output', 'children'),
[Input('download_csv', 'n_clicks')])
def redirect_btn(n_clicks):
to_redirect()
return 'res'
def to_redirect():
return redirect('https://example.com/')
am I missing something? Hope there's enough info in this post
There are undocumented template tags, as noted in #48
Ideally the documentation should be extended to cover them.
Reported by user tabre on the plotly forum - a new attribute in Dash v0.22.0 register_blueprint
is not provided by PseudoFlask
.
In general, need to validate dpd against this version of Dash.
At present, the plotly_app
tag inserts an iframe that extends to 100% of the width of its parent, and sets its height as some (user controlled) relative fraction of the width.
This needs to be extended (either with more arguments for this tag, or with a different template tag) to allow more user control over the size.
Hi!
It seems that the doc does not compile anymore.
No matching distribution found for Django>=2
This is due to the virtualenv, which is in python2.7. Django>=2 does not support this version.
You have to put the python interpreter to Cython3.0 via the dashboard of Readthedoc. It should be straightforward as both dash and dajngo-plotly-dash use python3.
First of all, many thanks for this package! It looks very promising.
I am trying to integrate a very easy Dash app in a Django project, but can't seem to make it work. Whenever I run the server, I get an error no such table: django_plotly_dash_statelessapp
. Is there a table I should add or is there another meaning?
I have added the following to my project:
In urls.py:
'django_plotly_dash.apps.DjangoPlotlyDashConfig'
'django_plotly_dash.middleware.BaseMiddleware'
In urls.py:
from . import example_dash_app from django.views.generic import TemplateView path('new/', TemplateView.as_view(template_name='test/home.html')),
In test/home.html:
{% load plotly_dash %} {% plotly_app name="SimpleExample" %}
In example_dash_app.py:
`import dash
import dash_core_components as dcc
import dash_html_components as html
from django_plotly_dash import DjangoDash
app = DjangoDash('SimpleExample')
app.layout = html.Div([
dcc.RadioItems(
id='dropdown-color',
options=[{'label': c, 'value': c.lower()} for c in ['Red', 'Green', 'Blue']],
value='red'
),
html.Div(id='output-color'),
dcc.RadioItems(
id='dropdown-size',
options=[{'label': i, 'value': j} for i, j in [('L','large'), ('M','medium'), ('S','small')]],
value='medium'
),
html.Div(id='output-size')
])
@app.callback(
dash.dependencies.Output('output-color', 'children'),
[dash.dependencies.Input('dropdown-color', 'value')])
def callback_color(dropdown_value):
return "The selected color is %s." % dropdown_value
@app.callback(
dash.dependencies.Output('output-size', 'children'),
[dash.dependencies.Input('dropdown-color', 'value'),
dash.dependencies.Input('dropdown-size', 'value')])
def callback_size(dropdown_color, dropdown_size):
return "The chosen T-shirt is a %s %s one." %(dropdown_size,
dropdown_color)`
Am I missing something? Many thanks for your help!
I am looking to build a custom popover component for Dash. Not all users understand graphs and I think descriptions in popover buttons near graphs will help users understand whats going on without cluttering a UI.
This will take me a while given my inexperience with React.js but before I start this, do you expect custom Dash components to play nicely with dpd? Are there any broad considerations I should be aware of?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.