|
|
| (13 intermediate revisions by the same user not shown) |
| Line 1: |
Line 1: |
| − | | + | ~ Migrated |
| − | <br />
| |
| − | What is Dash: https://dash.plotly.com/introduction
| |
| − | | |
| − | What is Plotly: https://plotly.com/python/
| |
| − | : Plotly gallery: https://plot.ly/python/
| |
| − | | |
| − | https://plotly.com/dash/
| |
| − | | |
| − | | |
| − | | |
| − | '''Material from the Udemy's course I'm doing:''' https://www.udemy.com/course/interactive-python-dashboards-with-plotly-and-dash/
| |
| − | | |
| − | *https://docs.google.com/document/d/1DjWL2DxLiRaBrlD3ELyQlCBRu7UQuuWfgjv9LncNp_M/edit#heading=h.6kzspbaklmdx
| |
| − | *https://docs.google.com/document/d/1vI84_EpRTh4xfcFkTunFzZT0RWMcRSqdkPueVNBcLx8/edit
| |
| − | *https://github.com/Pierian-Data/Plotly-Dashboards-with-Dash
| |
| − | | |
| − | | |
| − | Dash apps consist of a Flask server that communicates with front-end React components using JSON packets over HTTP requests. https://www.tutorialspoint.com/python_web_development_libraries/python_web_development_libraries_dash_framework.htm
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ==Installation==
| |
| − | https://dash.plot.ly/installation
| |
| − | | |
| − | <syntaxhighlight lang="python3">
| |
| − | pip install dash==1.7.0
| |
| − | | |
| − | # Note: starting with dash 0.37.0, dash automatically installs dash-renderer, dash-core-components, dash-html-components, and dash-table, using known-compatible versions of each. You need not and should not install these separately any longer, only dash itself.
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | A quick note on checking your versions and on upgrading. These docs are run using the versions listed above and these versions should be the latest versions available. To check which version that you have installed, you can run e.g:
| |
| − | <syntaxhighlight lang="python3">
| |
| − | >>> import dash_core_components
| |
| − | >>> print(dash_core_components.__version__)
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | To see the latest changes of any package, check the GitHub repo's CHANGELOG.md file:
| |
| − | | |
| − | *[https://github.com/plotly/dash/blob/master/CHANGELOG.md dash & dash-renderer changelog]
| |
| − | **<code>dash-renderer</code> is a separate package installed automatically with dash but its updates are included in the main dash changelog. These docs are using dash-renderer==1.1.2.
| |
| − | *[https://github.com/plotly/dash-core-components/blob/master/CHANGELOG.md dash-core-components changelog]
| |
| − | *[https://github.com/plotly/dash-html-components/blob/master/CHANGELOG.md dash-html-components changelog]
| |
| − | *[https://github.com/plotly/dash-table/blob/master/CHANGELOG.md dash-table changelog]
| |
| − | *[https://github.com/plotly/plotly.py/blob/master/CHANGELOG.md plotly changelog]
| |
| − | **the <code>plotly</code> package is also installed automatically with dash. It is the Python interface to the plotly.js graphing library, so is mainly used by dash-core-components, but it's also used by dash itself. These docs are using plotly==3.3.0.
| |
| − | | |
| − | All of these packages adhere to [https://semver.org/ semver].
| |
| − | | |
| − | | |
| − | <br />
| |
| − | | |
| − | ==Examples==
| |
| − | * '''Dash App Gallery:''' https://dash-gallery.plotly.host/Portal/
| |
| − | : GitHub repository: https://github.com/plotly/dash-sample-apps
| |
| − | | |
| − | :* This one is with a sidebar: https://dash-gallery.plotly.host/dash-svm/
| |
| − | ::* https://github.com/plotly/dash-sample-apps/tree/master/apps/dash-svm
| |
| − | :* https://dash-gallery.plotly.host/dash-oil-and-gas/
| |
| − | :* https://dash-gallery.plotly.host/dash-web-trader/
| |
| − | | |
| − | | |
| − | '''Dash Core Components Gallery:''' https://dash.plot.ly/dash-core-components
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ===Hello world example===
| |
| − | app.py
| |
| − | <syntaxhighlight lang="python3">
| |
| − | import dash
| |
| − | import dash_core_components as dcc
| |
| − | import dash_html_components as html
| |
| − | | |
| − | | |
| − | app = dash.Dash(__name__)
| |
| − | | |
| − | app.layout = html.Div(children=[
| |
| − | html.H1(children='Hello Dash'),
| |
| − | html.Div(children='Dash: A web application framework for Python')
| |
| − | ])
| |
| − | | |
| − | | |
| − | if __name__ == '__main__':
| |
| − | app.run_server(debug=True, port=8551)
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | '''To run the app:'''
| |
| − | python app.ph
| |
| − | <span style="color:#FF0000">Es importante utilizar un port que no esté ocupado por otro proceso.</span>
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ===A nice example===
| |
| − | app.py
| |
| − | <syntaxhighlight lang="python3">
| |
| − | import dash
| |
| − | import dash_core_components as dcc
| |
| − | import dash_html_components as html
| |
| − | import pandas as pd
| |
| − | import plotly.graph_objs as go
| |
| − | | |
| − | external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
| |
| − | | |
| − | app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
| |
| − | | |
| − | df = pd.read_csv(
| |
| − | 'https://gist.githubusercontent.com/chriddyp/'
| |
| − | 'cb5392c35661370d95f300086accea51/raw/'
| |
| − | '8e0768211f6b747c0db42a9ce9a0937dafcbd8b2/'
| |
| − | 'indicators.csv')
| |
| − | | |
| − | available_indicators = df['Indicator Name'].unique()
| |
| − | | |
| − | app.layout = html.Div([
| |
| − | html.Div([
| |
| − | | |
| − | html.Div([
| |
| − | dcc.Dropdown(
| |
| − | id='crossfilter-xaxis-column',
| |
| − | options=[{'label': i, 'value': i} for i in available_indicators],
| |
| − | value='Fertility rate, total (births per woman)'
| |
| − | ),
| |
| − | dcc.RadioItems(
| |
| − | id='crossfilter-xaxis-type',
| |
| − | options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],
| |
| − | value='Linear',
| |
| − | labelStyle={'display': 'inline-block'}
| |
| − | )
| |
| − | ],
| |
| − | style={'width': '49%', 'display': 'inline-block'}),
| |
| − | | |
| − | html.Div([
| |
| − | dcc.Dropdown(
| |
| − | id='crossfilter-yaxis-column',
| |
| − | options=[{'label': i, 'value': i} for i in available_indicators],
| |
| − | value='Life expectancy at birth, total (years)'
| |
| − | ),
| |
| − | dcc.RadioItems(
| |
| − | id='crossfilter-yaxis-type',
| |
| − | options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],
| |
| − | value='Linear',
| |
| − | labelStyle={'display': 'inline-block'}
| |
| − | )
| |
| − | ], style={'width': '49%', 'float': 'right', 'display': 'inline-block'})
| |
| − | ], style={
| |
| − | 'borderBottom': 'thin lightgrey solid',
| |
| − | 'backgroundColor': 'rgb(250, 250, 250)',
| |
| − | 'padding': '10px 5px'
| |
| − | }),
| |
| − | | |
| − | html.Div([
| |
| − | dcc.Graph(
| |
| − | id='crossfilter-indicator-scatter',
| |
| − | hoverData={'points': [{'customdata': 'Japan'}]}
| |
| − | )
| |
| − | ], style={'width': '49%', 'display': 'inline-block', 'padding': '0 20'}),
| |
| − | html.Div([
| |
| − | dcc.Graph(id='x-time-series'),
| |
| − | dcc.Graph(id='y-time-series'),
| |
| − | ], style={'display': 'inline-block', 'width': '49%'}),
| |
| − | | |
| − | html.Div(dcc.Slider(
| |
| − | id='crossfilter-year--slider',
| |
| − | min=df['Year'].min(),
| |
| − | max=df['Year'].max(),
| |
| − | value=df['Year'].max(),
| |
| − | marks={str(year): str(year) for year in df['Year'].unique()}
| |
| − | ), style={'width': '49%', 'padding': '0px 20px 20px 20px'})
| |
| − | ])
| |
| − | | |
| − | | |
| − | @app.callback(
| |
| − | dash.dependencies.Output('crossfilter-indicator-scatter', 'figure'),
| |
| − | [dash.dependencies.Input('crossfilter-xaxis-column', 'value'),
| |
| − | dash.dependencies.Input('crossfilter-yaxis-column', 'value'),
| |
| − | dash.dependencies.Input('crossfilter-xaxis-type', 'value'),
| |
| − | dash.dependencies.Input('crossfilter-yaxis-type', 'value'),
| |
| − | dash.dependencies.Input('crossfilter-year--slider', 'value')])
| |
| − | def update_graph(xaxis_column_name, yaxis_column_name,
| |
| − | xaxis_type, yaxis_type,
| |
| − | year_value):
| |
| − | dff = df[df['Year'] == year_value]
| |
| − | | |
| − | return {
| |
| − | 'data': [go.Scatter(
| |
| − | x=dff[dff['Indicator Name'] == xaxis_column_name]['Value'],
| |
| − | y=dff[dff['Indicator Name'] == yaxis_column_name]['Value'],
| |
| − | text=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name'],
| |
| − | customdata=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name'],
| |
| − | mode='markers',
| |
| − | marker={
| |
| − | 'size': 15,
| |
| − | 'opacity': 0.5,
| |
| − | 'line': {'width': 0.5, 'color': 'white'}
| |
| − | }
| |
| − | )],
| |
| − | 'layout': go.Layout(
| |
| − | xaxis={
| |
| − | 'title': xaxis_column_name,
| |
| − | 'type': 'linear' if xaxis_type == 'Linear' else 'log'
| |
| − | },
| |
| − | yaxis={
| |
| − | 'title': yaxis_column_name,
| |
| − | 'type': 'linear' if yaxis_type == 'Linear' else 'log'
| |
| − | },
| |
| − | margin={'l': 40, 'b': 30, 't': 10, 'r': 0},
| |
| − | height=450,
| |
| − | hovermode='closest'
| |
| − | )
| |
| − | }
| |
| − | | |
| − | | |
| − | def create_time_series(dff, axis_type, title):
| |
| − | return {
| |
| − | 'data': [go.Scatter(
| |
| − | x=dff['Year'],
| |
| − | y=dff['Value'],
| |
| − | mode='lines+markers'
| |
| − | )],
| |
| − | 'layout': {
| |
| − | 'height': 225,
| |
| − | 'margin': {'l': 20, 'b': 30, 'r': 10, 't': 10},
| |
| − | 'annotations': [{
| |
| − | 'x': 0, 'y': 0.85, 'xanchor': 'left', 'yanchor': 'bottom',
| |
| − | 'xref': 'paper', 'yref': 'paper', 'showarrow': False,
| |
| − | 'align': 'left', 'bgcolor': 'rgba(255, 255, 255, 0.5)',
| |
| − | 'text': title
| |
| − | }],
| |
| − | 'yaxis': {'type': 'linear' if axis_type == 'Linear' else 'log'},
| |
| − | 'xaxis': {'showgrid': False}
| |
| − | }
| |
| − | }
| |
| − | | |
| − | | |
| − | @app.callback(
| |
| − | dash.dependencies.Output('x-time-series', 'figure'),
| |
| − | [dash.dependencies.Input('crossfilter-indicator-scatter', 'hoverData'),
| |
| − | dash.dependencies.Input('crossfilter-xaxis-column', 'value'),
| |
| − | dash.dependencies.Input('crossfilter-xaxis-type', 'value')])
| |
| − | def update_y_timeseries(hoverData, xaxis_column_name, axis_type):
| |
| − | country_name = hoverData['points'][0]['customdata']
| |
| − | dff = df[df['Country Name'] == country_name]
| |
| − | dff = dff[dff['Indicator Name'] == xaxis_column_name]
| |
| − | title = '<b>{}</b><br>{}'.format(country_name, xaxis_column_name)
| |
| − | return create_time_series(dff, axis_type, title)
| |
| − | | |
| − | | |
| − | @app.callback(
| |
| − | dash.dependencies.Output('y-time-series', 'figure'),
| |
| − | [dash.dependencies.Input('crossfilter-indicator-scatter', 'hoverData'),
| |
| − | dash.dependencies.Input('crossfilter-yaxis-column', 'value'),
| |
| − | dash.dependencies.Input('crossfilter-yaxis-type', 'value')])
| |
| − | def update_x_timeseries(hoverData, yaxis_column_name, axis_type):
| |
| − | dff = df[df['Country Name'] == hoverData['points'][0]['customdata']]
| |
| − | dff = dff[dff['Indicator Name'] == yaxis_column_name]
| |
| − | return create_time_series(dff, axis_type, yaxis_column_name)
| |
| − | | |
| − | | |
| − | if __name__ == '__main__':
| |
| − | app.run_server(debug=True, port=8051)
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | [[File:Dash example2.png|center|900x900px|thumb]]
| |
| − | | |
| − | | |
| − | <br />
| |
| − | | |
| − | ==Deploying Dash Apps==
| |
| − | https://dash.plot.ly/deployment
| |
| − | | |
| − | | |
| − | Dash uses Flask under the hood. This makes deployment easy: you can deploy a Dash app just like you would deploy a Flask app. Almost every cloud server provider has a guide for deploying Flask apps. There is also a Dash Deployment Server, but is not free (commercial).
| |
| − | | |
| − | * Flask Deployment
| |
| − | * Dash Deployment Server (commercial)
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ===Flask Deployment===
| |
| − | https://flask.palletsprojects.com/en/1.1.x/deploying/
| |
| − | | |
| − | <span style="color:#0000FF; background:#F0E68C">'''Es este archivo está paso por paso el procedimiento que realicé la última vez to deploy my Dash Application en AWS: '''</span> [[File:Deploying_a_Dash_App_in_AWS.zip]]
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ====Gunicorn====
| |
| − | https://flask.palletsprojects.com/en/1.1.x/deploying/wsgi-standalone/#gunicorn
| |
| − | | |
| − | https://gunicorn.org/
| |
| − | | |
| − | | |
| − | <br />
| |
| − | <blockquote>
| |
| − | '''Installation:'''
| |
| − | | |
| − | https://anaconda.org/conda-forge/gunicorn
| |
| − | <syntaxhighlight>
| |
| − | conda install -c conda-forge gunicorn
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | or
| |
| − | | |
| − | <syntaxhighlight>
| |
| − | pip install gunicorn
| |
| − | </syntaxhighlight>
| |
| − | </blockquote>
| |
| − | | |
| − | | |
| − | <br />
| |
| − | <code>Gunicorn</code> «Green Unicorn» is a WSGI HTTP Server for UNIX. It's a pre-fork worker model ported from Ruby's Unicorn project. It supports both <code>eventlet</code> and <code>greenlet</code>. Running a Flask application on this server is quite simple:
| |
| − | | |
| − | gunicorn myproject:app
| |
| − | | |
| − | | |
| − | Gunicorn provides many command-line options (see <code>gunicorn -h</code>). For example, to run a Flask application with 4 worker processes (<code>-w 4</code>) binding to localhost port 4000 (<code>-b 127.0.0.1:4000</code>):
| |
| − | | |
| − | gunicorn -w 4 -b 127.0.0.1:4000 myproject:app
| |
| − | | |
| − | | |
| − | The <code>gunicorn</code> command expects the names of your application module or package and the application instance within the module. If you use the application factory pattern, you can pass a call to that:
| |
| − | | |
| − | gunicorn "myproject:create_app()"
| |
| − | | |
| − | | |
| − | <br />
| |
| − | '''First example:'''
| |
| − | <syntaxhighlight lang="python3">
| |
| − | def app(environ, start_response):
| |
| − | data = b"Hello, World!\n"
| |
| − | start_response("200 OK", [
| |
| − | ("Content-Type", "text/plain"),
| |
| − | ("Content-Length", str(len(data)))
| |
| − | ])
| |
| − | return iter([data])
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | To run the server:
| |
| − | gunicorn -w 4 myapp:app
| |
| − | | |
| − | Executing the above command will only run the development server. In the next section we will explain how to deploy a <code>Gunicorn</code>
| |
| − | | |
| − | | |
| − | <br />
| |
| − | =====Deploying a Gunicorn server=====
| |
| − | This is the official page. It doesn't explain well how to do it:
| |
| − | : http://docs.gunicorn.org/en/latest/deploy.html
| |
| − | | |
| − | | |
| − | This tutorial explain well hot to do deploy a Flask Applications with <code>Gunicorn</code> and <code>Nginx</code>:
| |
| − | : https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-gunicorn-and-nginx-on-ubuntu-16-04
| |
| − | | |
| − | | |
| − | Now, when using <code>Dash</code>, we have to make a few changes with respect to the above tutorial. The following posts helped me to find the solution:
| |
| − | : https://community.plot.ly/t/error-with-gunicorn/8247
| |
| − | : https://community.plot.ly/t/failed-to-find-application-object-server-in-app/13723
| |
| − | | |
| − | | |
| − | <br />
| |
| − | '''Example - Deploying a Dash aplications with Gunicorn and Nginx on Ubuntu 16.04''' (based on https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-gunicorn-and-nginx-on-ubuntu-16-04)
| |
| − | | |
| − | | |
| − | * '''Create and activate a Python Virtual Environment :'''
| |
| − | <span style="background: grey; color:red">See this source to understand how to create a virtualenv for an specific python version</span>: https://help.dreamhost.com/hc/en-us/articles/115000695551-Installing-and-using-virtualenv-with-Python-3
| |
| − | | |
| − | ::<syntaxhighlight lang="shell">
| |
| − | sudo pip3 install virtualenv
| |
| − | | |
| − | mkdir ~/myproject
| |
| − | cd ~/myproject
| |
| − | | |
| − | virtualenv myprojectenv # This will install a local copy of Python and pip into a directory called myprojectenv
| |
| − | | |
| − | source myprojectenv/bin/activate
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | :: Your prompt will change to indicate that you are now operating within the virtual environment. It will look something like this:
| |
| − | :: <syntaxhighlight>
| |
| − | (myprojectenv)user@host:~/myproject$.
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | | |
| − | * '''Install Flask, Dash and Gunicorn inside the virtual environment:'''
| |
| − | :: <syntaxhighlight>
| |
| − | pip install gunicorn flask
| |
| − | | |
| − | ver «Dash» installation
| |
| − | ver «gunicorn» installation
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | | |
| − | * '''Create a Sample App:'''
| |
| − | :: <syntaxhighlight lang="python3">
| |
| − | import os
| |
| − | import dash
| |
| − | import dash_core_components as dcc
| |
| − | import dash_html_components as html
| |
| − | | |
| − | external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
| |
| − | | |
| − | app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
| |
| − | | |
| − | server = app.server
| |
| − | | |
| − | app.layout = html.Div(children=[
| |
| − | html.H1(children='Hello Dash'),
| |
| − | | |
| − | html.Div(children='''
| |
| − | Dash: A web application framework for Python.
| |
| − | '''),
| |
| − | | |
| − | dcc.Graph(
| |
| − | id='example-graph',
| |
| − | figure={
| |
| − | 'data': [
| |
| − | {'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar', 'name': 'SF'},
| |
| − | {'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'bar', 'name': u'Montréal'},
| |
| − | ],
| |
| − | 'layout': {
| |
| − | 'title': 'Dash Data Visualization'
| |
| − | }
| |
| − | }
| |
| − | )
| |
| − | ])
| |
| − | | |
| − | if __name__ == '__main__':
| |
| − | app.run_server(debug=True, host='0.0.0.0')
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | :: <span style="color:#FF0000">Notice that we have included: <code>server = app.server</code>.</span>
| |
| − | | |
| − | | |
| − | | |
| − | * '''Now, you can test your Dash app by typing:'''
| |
| − | :: <syntaxhighlight>
| |
| − | (myprojectenv)$ python myproject.py
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | :: Visit your server's domain name or IP address followed by :<code>port</code> in your web browser to verify your App is working.
| |
| − | | |
| − | | |
| − | | |
| − | * '''Create the WSGI Entry Point:''' We'll create a file that will serve as the entry point for our application. This will tell our Gunicorn server how to interact with the application:
| |
| − | :: <syntaxhighlight>
| |
| − | (myprojectenv)$ vi ~/myproject/wsgi.py
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | :: <syntaxhighlight lang="python3">
| |
| − | from myproject import server
| |
| − | | |
| − | if __name__ == "__main__":
| |
| − | server.run()
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | :: <span style="color:#FF0000">Notice that we have import the variable <code>server</code> from <code>myproject.py</code></span>
| |
| − | :: <span style="color:#FF0000">This is the different with respect to a pure Flask application, where you would import <code>App</code> instead of <code>server</code>. In Dash, we require <code>app.server</code>, which is in the <code>server</code> variable we have created. So if we were deploying a pure flak App, it would be:</span>
| |
| − | ::: <syntaxhighlight>
| |
| − | from myproject import app
| |
| − | | |
| − | if __name__ == "__main__":
| |
| − | app.run()
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | | |
| − | * '''Testing Gunicorn's Ability to Serve the Project:'''
| |
| − | :: <syntaxhighlight>
| |
| − | (myprojectenv)$ cd ~/myproject
| |
| − | (myprojectenv)$ gunicorn --bind 0.0.0.0:5000 wsgi:server
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | :: <span style="color:#FF0000">For a pure Flask application, would be <code>wsgi:App</code>.</span>
| |
| − | | |
| − | :: Visit your server's domain name or IP address with :<code>port</code> appended to the end in your web browser again.
| |
| − | | |
| − | | |
| − | * '''We're now done with our virtual environment, so we can deactivate it:'''
| |
| − | :: <syntaxhighlight>
| |
| − | (myprojectenv)$ deactivate
| |
| − | </syntaxhighlight>
| |
| − | :: Any Python commands will now use the system’s Python environment again.
| |
| − | | |
| − | | |
| − | | |
| − | * '''Create a <code>systemd Unit</code> File:'''
| |
| − | :: <syntaxhighlight>
| |
| − | $ vi /etc/systemd/system/myproject.service
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | :: <syntaxhighlight lang="bash">
| |
| − | [Unit]
| |
| − | Description=Gunicorn instance to serve myproject
| |
| − | After=network.target
| |
| − | | |
| − | [Service]
| |
| − | User=root
| |
| − | Group=www-data
| |
| − | WorkingDirectory=/root/myproject
| |
| − | Environment="PATH=/root/myproject/myprojectenv/bin"
| |
| − | ExecStart=/root/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:server
| |
| − | | |
| − | [Install]
| |
| − | WantedBy=multi-user.target
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | | |
| − | * '''We can now start the Gunicorn service we created and enable it so that it starts at boot:'''
| |
| − | :: <syntaxhighlight>
| |
| − | $ sudo systemctl start myproject
| |
| − | $ sudo systemctl enable myproject
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | | |
| − | * '''Configuring Nginx to Proxy Requests:'''
| |
| − | :: <syntaxhighlight>
| |
| − | $ vi /etc/nginx/sites-available/default
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | | |
| − | :: <syntaxhighlight lang="bash">
| |
| − | # Esta es la configuración por defecto (eliminando lo que en el archive original está comentado para simplificarlo aquí)
| |
| − | server {
| |
| − | listen 80 default_server;
| |
| − | listen [::]:80 default_server;
| |
| − | | |
| − | index index.html index.htm index.nginx-debian.html;
| |
| − | | |
| − | server_name _;
| |
| − | | |
| − | location / {
| |
| − | include proxy_params;
| |
| − | proxy_pass http://unix:/home/ubuntu/SADashboard/index.sock;
| |
| − | }
| |
| − | | |
| − | }
| |
| − | | |
| − | | |
| − | # Aquí estamos realizando la configuración
| |
| − | server {
| |
| − | listen 80;
| |
| − | server_name awsdashboard.sinfronteras.ws;
| |
| − | | |
| − | location / {
| |
| − | include proxy_params;
| |
| − | proxy_pass http://unix:/home/ubuntu/SADashboard/index.sock;
| |
| − | }
| |
| − | }
| |
| − | </syntaxhighlight>
| |
| − | :: <span style="color:#FF0000">ES EXTREMADAMENTE IMPORTANTE NOTAR QUE «gofaaaz.sinfronteras.ws» no puede ser reemplazado por la IP del server. La última vez perdí muchísimo tiempo porque intenté hacerlo con la IP y no funcionaba; pues la IP va hacial el «default_server;» y buscá el directorio root de nginx. Tampoco funciona si no se hace esta modificación en Nginx y se trata de acceder sólo con la IP:PORT en donde hemos iniciado la Dash applicatioin. Lo que tuve que hacer para que funcionara fue crear un subdominio y agregar el subdominio en vez de la IP como se muestra a continuación. </span>
| |
| − | | |
| − | | |
| − | :: <span style="color:#FF0000">Ahora, si queremos ingresar a la aplicación Dash utilizando al IP del server, podemo realizar la configuración de la siguiente forma. Note que en «location» hemos configurado la ruta hacia el «index.sock» en donde está corriendo la Dash Application</span>
| |
| − | :: <syntaxhighlight lang="bash">
| |
| − | server {
| |
| − | listen 80 default_server;
| |
| − | listen [::]:80 default_server;
| |
| − | | |
| − | index index.html index.htm index.nginx-debian.html;
| |
| − | | |
| − | server_name _;
| |
| − | | |
| − | location / {
| |
| − | include proxy_params;
| |
| − | proxy_pass http://unix:/home/ubuntu/SADashboard/index.sock;
| |
| − | }
| |
| − | | |
| − | }
| |
| − | | |
| − | | |
| − | # server {
| |
| − | # listen 80;
| |
| − | # server_name awsdashboard.sinfronteras.ws;
| |
| − | #
| |
| − | # location / {
| |
| − | # include proxy_params;
| |
| − | # proxy_pass http://unix:/home/ubuntu/SADashboard/index.sock;
| |
| − | # }
| |
| − | # }
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | * '''Finally, we restart the Nginx process:'''
| |
| − | :: <syntaxhighlight>
| |
| − | sudo systemctl restart nginx.service
| |
| − | </syntaxhighlight>
| |
| − | :: You should now be able to go to your server's domain name or IP address in your web browser and see your App.
| |
| − | | |
| − | | |
| − | <br />
| |
| − | | |
| − | ==Dash Tutorial==
| |
| − | https://dash.plot.ly/
| |
| − | | |
| − | Dash apps are composed of two parts:
| |
| − | :*'''The first part''' is' the "layout" of the app and it describes what the application looks like.
| |
| − | :*'''The second part''' describes the interactivity of the application and will be covered in the next chapter.
| |
| − | | |
| − | | |
| − | <br />
| |
| − | Dash provides Python classes for all of the visual components of the application. We maintain a set of components in the <code>dash_core_components</code> and the <code>dash_html_components</code> library but <span style="color:#FF0000">you can also [https://github.com/plotly/dash-component-boilerplate build your own] with <code>JavaScript</code> and <code>React.js</code>.</span>
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ===Dash Layout===
| |
| − | https://dash.plot.ly/getting-started
| |
| − | | |
| − | The layout of a Dash app describes what the app looks like. The layout is composed of a tree of "components" like <code>html.Div</code> and <code>dcc.Graph</code>.
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ====HTML components====
| |
| − | * '''<code>dash_html_components</code>'''
| |
| − | :* The <code>dash_html_components</code> library provides classes for all of the </code>HTML</code> tags and the keyword arguments describe the <code>HTML</code> attributes like <code>style</code>, <code>className</code>, and <code>id</code>.
| |
| − | | |
| − | :* For example, the html.H1(children='Hello Dash') component generates a <nowiki><h1>Hello Dash</h1></nowiki> HTML element in your application.
| |
| − | | |
| − | :* The <code>HTML</code> class attribute is <code>className</code> in Dash.
| |
| − | | |
| − | :* The children property is special. By convention, it's always the first attribute which means that you can omit it: html.H1(children='Hello Dash') is the same as html.H1('Hello Dash'). Also, it can contain a string, a number, a single component, or a list of components.
| |
| − | | |
| − | :* '''dash_html_components gallery:''' https://dash.plot.ly/dash-html-components
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ====Core components====
| |
| − | * '''<code>dash_core_components</code>''':
| |
| − | :* Not all components are pure HTML. The <code>dash_core_components</code> describe higher-level components that are interactive and are generated with JavaScript, HTML, and CSS through the React.js library.
| |
| − | | |
| − | :* Examples of core components are: dropdowns, graphs, markdown blocks, and more.
| |
| − | | |
| − | :* '''dash_core_components gallery:''' https://dash.plot.ly/dash-core-components
| |
| − | | |
| − | | |
| − | <br />
| |
| − | =====The Graph component=====
| |
| − | The <code>dash_core_components</code> library includes a component called Graph.
| |
| − | | |
| − | Graph renders interactive data visualizations using the open source plotly.js JavaScript graphing library. Plotly.js supports over 35 chart types and renders charts in both vector-quality SVG and high-performance WebGL.
| |
| − | | |
| − | The figure argument in the dash_core_components.Graph component is the same figure argument that is used by plotly.py, Plotly's open source Python graphing library. Check out the plotly.py documentation and gallery to learn more: https://plot.ly/python/
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ====CSS tutorial====
| |
| − | * '''CSS tutorial:''' https://dash.plot.ly/external-resources
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ====Markdown====
| |
| − | While Dash exposes HTML through the <code>dash_html_components</code> library, it can be tedious to write your copy in HTML. For writing blocks of text, you can use the Markdown component in the <code>dash_core_components</code> library.
| |
| − | | |
| − | * Dash uses the CommonMark specification of Markdown: https://commonmark.org/
| |
| − | * Check out their 60 Second Markdown Tutorial if this is your first introduction to Markdown: https://commonmark.org/help/
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ====Example - Including a Graph and style====
| |
| − | <syntaxhighlight lang="python3">
| |
| − | import dash
| |
| − | import dash_core_components as dcc
| |
| − | import dash_html_components as html
| |
| − | | |
| − | external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
| |
| − | | |
| − | app = dash.Dash(__name__,external_stylesheets=external_stylesheets)
| |
| − | | |
| − | colors = {
| |
| − | 'backgroud': '#111111',
| |
| − | 'text': '#7FDBFF'
| |
| − | }
| |
| − | | |
| − | app.layout = html.Div(
| |
| − | style={
| |
| − | 'backgroundColor': colors['backgroud']
| |
| − | },
| |
| − | children=[
| |
| − | html.H1(
| |
| − | style={
| |
| − | 'textAlign': 'center',
| |
| − | 'color': colors['text']
| |
| − | },
| |
| − | children='Hello Dash'
| |
| − | ),
| |
| − | html.Div(
| |
| − | style={
| |
| − | 'textAlign': 'center',
| |
| − | 'color': colors['text']
| |
| − | },
| |
| − | children='Dash: A web application framework for Python'
| |
| − | ),
| |
| − | dcc.Graph(
| |
| − | id='example-graph',
| |
| − | figure={
| |
| − | 'data': [
| |
| − | {'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar', 'name': 'SF'},
| |
| − | {'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'bar', 'name': u'Montréal'},
| |
| − | ],
| |
| − | 'layout': {
| |
| − | 'title': 'Dash Data Visualisation',
| |
| − | 'plot_bgcolor': colors['backgroud'],
| |
| − | 'paper_bgcolor': colors['backgroud'],
| |
| − | 'font': {
| |
| − | 'color': colors['text']
| |
| − | }
| |
| − | }
| |
| − | }
| |
| − | )
| |
| − | ]
| |
| − | )
| |
| − | | |
| − | if __name__ == '__main__':
| |
| − | app.run_server(debug=True, port=8551)
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ====Example - Reusable Components - Generating a Table from a Pandas dataframe====
| |
| − | By writing our markup in Python, we can create complex reusable components like tables without switching contexts or languages.
| |
| − | Here's a quick example that generates a 'Table' from a Pandas dataframe:
| |
| − | | |
| − | <syntaxhighlight lang="python3">
| |
| − | import dash
| |
| − | import dash_core_components as dcc
| |
| − | import dash_html_components as html
| |
| − | import pandas as pd
| |
| − | | |
| − | | |
| − | external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
| |
| − | df = pd.read_csv('https://gist.githubusercontent.com/chriddyp/c78bf172206ce24f77d6363a2d754b59/raw/c353e8ef842413cae56ae3920b8fd78468aa4cb2/usa-agricultural-exports-2011.csv')
| |
| − | | |
| − | | |
| − | def generate_table(dataframe, max_rows=10):
| |
| − | return html.Table(
| |
| − | # Header
| |
| − | [html.Tr([html.Th(col) for col in dataframe.columns])] +
| |
| − | | |
| − | # Body
| |
| − | [html.Tr([
| |
| − | html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
| |
| − | ]) for i in range(min(len(dataframe), max_rows))]
| |
| − | )
| |
| − | | |
| − | | |
| − | app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
| |
| − | | |
| − | app.layout = html.Div(children=[
| |
| − | html.H4(children='US agriculture Exports (2011)'),
| |
| − | generate_table(df)
| |
| − | ])
| |
| − | | |
| − | | |
| − | if __name__ == '__main__':
| |
| − | app.run_server(debug=True, port=8551)
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ===Dash Callbacks===
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ===Multi-Page Apps and URL Support===
| |
| − | https://dash.plotly.com/urls
| |
| − | | |
| − | Dash renders web applications as a "single-page app". This means that the application does not completely reload when the user navigates the application, making browsing very fast.
| |
| − | | |
| − | There are two components that aid page navigation: '''dash_core_components.Location''' and '''dash_core_components.Link'''
| |
| − | | |
| − | | |
| − | <br />
| |
| − | ====dash-multipage====
| |
| − | https://pypi.org/project/dash-multipage/
| |
| − | | |
| − | dash-multipage A framework to simplify some of the challenges in setting up multipage dash pages
| |
| − | | |
| − | | |
| − | <br />
| |