error somewhere in the code while adding colorscale in dash barplot - python-3.x

I have written some code to represent a barplot with a colorscale, in dash. The expected result looks something like this but with only one dropdown menu
https://brandatastudio.shinyapps.io/visualization-practica/
, therefore I wrote the following code:
#!/usr/bin/env python
import dash
import dash_html_components as html
import dash_core_components as dcc
import plotly.offline as pyo
import plotly.graph_objs as go
import pandas as pd
from dash.dependencies import Input, Output
app = dash.Dash()
datause = pd.read_csv("datawind.csv" , sep = ",")
app.layout = html.Div([
dcc.Graph(
id = 'barplot1'),
dcc.Dropdown(
id="dropmenu" ,
options=[{'label' : i , 'value' : i } for i in datause.columns.values
],
value='Total Investment ($ Millions)')
],
)
#app.callback(Output(component_id = 'barplot1', component_property = 'figure'),
[Input(component_id = 'dropmenu' , component_property = 'value')])
def update_figure(dropmenuinput):
potato = dropmenuinput
return {
'data': [
go.Bar(
x = datause["State"],
y = datause[potato],
mode = 'markers',
marker = {
"color" : datause[potato],
"colorbar" : dict(title = "hola"),
"colorscale" : 'Viridis'
})],
'layout': go.Layout(
title = "pene"
,xaxis={'title': "state"},
yaxis ={'title' : potato}) }
if __name__ == '__main__':
app.run_server(debug=True)
Instead, the obtained results ends up looking like this
After testing and retesting, I discover that the main error of the code seems to be in this section
mode = 'markers',
marker = dict(
size=16,
color = datause['Total Investment ($ Millions)'],
colorbar = dict(title = "hola"),
colorscale = 'Viridis'
))]
If I remove that section of the code, the dashboard looks something like it should, without the colorscale of course.
So, the question is, what is failing in my insertion of the colorscale? I have been checking different posts of how to add them
https://community.plot.ly/t/add-a-colorbar-to-scatter-plot-in-python/13349
https://plot.ly/python/colorscales/#custom-contour-plot-colorscale
and I find no examples applied to dash dashboard, or barplots, only here can I hope to find help.
Notes: Heres is the information regarding to the enviroment and packages affecting:
chardet==3.0.4
click==6.7
Cython==0.28.2
dash==0.21.0
dash-core-components==0.22.1
dash-html-components==0.10.0
dash-renderer==0.12.1
decorator==4.3.0
nbformat==4.4.0
numpy==1.14.2
pandas==0.22.0
pandas-datareader==0.6.0
plotly==2.5.1
python-dateutil==2.7.2
pytz==2018.4
requests==2.18.4
urllib3==1.22
Werkzeug==0.14.1
Here is the dataset Iḿ using https://drive.google.com/open?id=1Cr74jKf2FHDA7XVAblQX3d9_dVHfXyVG

The only problem I see is the line
mode = 'markers',
inside the go.Bar. If you go to the reference you will see that Bar traces do not have this attribute. If it still doesn't work I suggest updating plotly, as version 3 was a major upgrade to the library (actually I would recommend updating even if it works).
Here is a minimal example from a notebook:
trace = go.Bar(
x = [1, 2, 3, 4],
y = [1, 2, 3, 4],
marker = {
"color" : [1, 2, 3, 4],
"colorbar" : dict(),
"colorscale" : 'Viridis',
"showscale": True
}
)

I have had a similar issue when adding a color scale to a Map using Dash and the way I resolved this was by finding out the underlying colour schemes by running the code:
import plotly.express as px
print(px.colors.sequential.Plasma)
['#0d0887', '#46039f', '#7201a8', '#9c179e', '#bd3786', '#d8576b', '#ed7953', '#fb9f3a', '#fdca26', '#f0f921']
Then my command in Dash is:
"colorscale":[[0.0,'#0d0887'], [0.1,'#46039f'], [0.2,'#7201a8'], [0.3,'#9c179e'], [0.4,'#bd3786'], [0.5,'#d8576b'], [0.6,'#ed7953'], [0.7,'#fb9f3a'], [0.8,'#fdca26'], [1.0,'#f0f921']]

Related

live data Dash plot with python

i have write a code in python to plot data in realtime. there is only one problem the code run i get no errors but there is also no plot in web page that i created.
can any one help me pleadse?
thanks
ma code
#app work
app = dash.Dash(__name__)
#html layout
app.layout = html.Div(
[
dcc.Graph(id = 'live-graph',
animate = True),
dcc.Interval(
id = 'graph-update',
interval = 1*1000,
n_intervals = 0 ),])
I recommend checking the data in raw[0] and raw1 and I do not think you need list(str()). You need also to bring the data from the database by increasing the value after LIMIT. Therefore, you should let the size of the data coming from the database increase dynamically and being controlled by n_intervals such that select * from ..... LIMIT + n and absolutely the value of n should start from 1, therefore set n_intervals to 1 accordingly. Another error in your program, you return figure which is not graph_object and dbc.Graph expects graph_object.
In the example below, I created a dataframe from CSV file, but you can understand the logic and apply it directly to your example:
from dash import Dash, html, dcc
import plotly.graph_objects as go
from dash.dependencies import Input, Output
import pandas as pd
import numpy
app = Dash(__name__)
df = pd.read_csv("data.csv")
app.layout = html.Div(
[
dcc.Graph(id='live-graph'),
dcc.Interval(
id='interval-component',
interval=1000, # in milliseconds
n_intervals = 1, # start
),
]
)
#app.callback(
Output('live-graph', 'figure'),
[Input('interval-component', 'n_intervals')]
)
def update_graph_scatter(n):
if n <= len(df):
row = df.iloc[:n,:]
w = numpy.asarray(row[df.columns[0]])
volt = numpy.asarray(row[df.columns[1]])
data = go.Scatter( x = w , y = volt , hoverinfo='text+name+y', name='Scatter', mode= 'lines+markers', )
layout = go.Layout(xaxis = dict(range=[min(w),max(w)]), yaxis = dict(range=[min(volt)-1,max(volt)+1]))
figure = go.Figure({'data' :data, 'layout' : layout})
return figure
app.run_server(debug=True, use_reloader=False)

Controlling which elements receive hover tooltip in Bokeh

I'm currently trying to find a way to use an boolean array in order to decide which elements recive HoverTooltips in bokeh while only using one dictonary for the plot.
I allready tryed to use the bokeh rendering function but this didn't quite work.
source.data = dict(
x=data_source.loc[:, 'x_col_name'],
y=data_source.loc[:, 'y_col_name'],
color=color_selection(selected), # Translates bool to color
alpha=alpha_selection(selected), # Translates bool to transparency
active=selection # boolean array of selected elements
)
Only active datapoints should recieve a HoverTooltip
As a temporary work-around you could hide the tooltips in a callback like this (works for Bokeh v1.3.0):
from bokeh.plotting import figure, show
from bokeh.models import CustomJS
data = dict(
x=[1, 2, 3, 4, 5],
y=[1, 2, 3, 4, 5],
color=['red', 'green', 'red', 'green', 'red'],
active=[False, True, False, True, False],
)
p = figure(tooltips=[('x','#x'),('y', '#y'), ('active', '#active')])
p.circle('x', 'y', color='color', size=10, source = data)
code_hover = '''
if (cb_data.index.indices.length > 0) {
var active_index = cb_data.index.indices[0]
var data = cb_data.renderer.data_source.data
var show_tooltip = data['active'][active_index]
var tooltip_index = 0
if (show_tooltip) {
document.getElementsByClassName('bk-tooltip')[tooltip_index].style.display = 'block';
}
else {
document.getElementsByClassName('bk-tooltip')[tooltip_index].style.display = 'none';
}
}
'''
p.hover.callback = CustomJS(code = code_hover)
show(p)
Please note the tooltip_index in the callback. If you have more tooltips you need to change that index. See also this post
Result:
As of Bokeh 1.x there is no built-in capability to filter hover results. That feature is planned for the 2.0 release, you can follow this issue here: https://github.com/bokeh/bokeh/issues/9087

Plotly Dash Graph With Multiple Dropdown Inputs Not Working

I’m trying to create a time-series Dash line graph that has multiple interactive dropdown user input variables. I would ideally like each of the dropdown inputs to allow for multiple selections.
While I’m able to create the drop down menus successfully, the chart isn’t updating like I’d like. When I allow the dropdowns to have multiple selections, I get an error that arrays are different lengths. And when I limit the dropdowns to one selection, I get an error that [‘Vendor_Name’] is not in index. So this may be two separate problems.
Graph that doesn’t work:
Snippet of Excel data imported into DF
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
#import plotly.graph_objs as go
df = pd.read_csv("Data.csv", sep = "\t")
df['YearMonth'] = pd.to_datetime(df['YearMonth'], format = '%Y-%m')
cols = ['Product_1', 'Product_2', 'Product_3']
vendor = df['Vendor'].unique()
app = dash.Dash('Data')
app.layout = html.Div([
html.Div([
html.Div([
html.Label('Product'),
dcc.Dropdown(
id = 'product',
options = [{
'label' : i,
'value' : i
} for i in cols],
multi = True,
value = 'Product_1'
),
]),
html.Div([
html.Label('Vendor'),
dcc.Dropdown(
id = 'vendor',
options = [{
'label' : i,
'value' : i
} for i in vendor],
multi = True,
value = 'ABC')
,
]),
]),
dcc.Graph(id = 'feature-graphic')
])
#app.callback(Output('feature-graphic', 'figure'),
[Input('product', 'value'),
Input('vendor', 'value')])
def update_graph(input_vendor, input_column):
df_filtered = df[df['Vendor'] == input_vendor]
##also tried setting an index because of the error I was getting. Not sure if necessary
df_filtered = df_filtered.set_index(['Vendor'])
traces = []
df_by_col = df_filtered[[input_column, 'YearMonth']]
traces.append({
'x' :pd.Series(df_by_col['YearMonth']),
'y' : df_by_col[input_column],
'mode' : 'lines',
'type' : 'scatter',
'name' :'XYZ'}
)
fig = {
'data': traces,
'layout': {'title': 'Title of Chart'}
}
return fig
if __name__ == '__main__':
app.run_server(debug=False)
Thanks in advance for helping! Still new-ish to Python, but very excited about Dash’s capabilities. I’ve been able to create other graphs with single inputs, and have read through documentation.
Here is the approach I followed: (editing common example available in google with my approach):
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash(__name__)
all_options = {
'America': ['New York City', 'San Francisco', 'Cincinnati'],
'Canada': [u'Montréal', 'Toronto', 'Ottawa']
}
app.layout = html.Div([
dcc.Dropdown(
id='countries-dropdown',
options=[{'label': k, 'value': k} for k in all_options.keys()],
value='America', #default value to show
multi=True,
searchable=False
),
dcc.Dropdown(id='cities-dropdown', multi=True, searchable=False, placeholder="Select a city"),
html.Div(id='display-selected-values')
])
#app.callback(
dash.dependencies.Output('cities-dropdown', 'options'),
[dash.dependencies.Input('countries-dropdown', 'value')])
def set_cities_options(selected_country):
if type(selected_country) == 'str':
return [{'label': i, 'value': i} for i in all_options[selected_country]]
else:
return [{'label': i, 'value': i} for country in selected_country for i in all_options[country]]
if __name__ == '__main__':
app.run_server(debug=True)
Workaround here is: When there is single input present in parent dropdown, the value is in string format. But for multiple values, it comes in list format.
This code also work perfectly and gets updated automatically even when you click on cross option to remove any selected option.
Note: I have used 'placeholder' attribute instead of defining default value for it as it made no sense in this case. But you can also update the value dynamically in similar way.
1 input data
The data as it is in the csv is hard to loop.
And I would argue that it is the main reason your code does not work,
because you seem to understand the fundamental code structure.
Having put on my SQL glasses I think you should try to get it to sth like
Date, Vendor, ProductName, Value
2 callback input types change
multi is tricky because it changes switches between returning a str if only 1 item is selected and list if more than one is selected
3 callback return type
you code returns a dict but the callback declared figure as the return type
but here is the code with debugging traces of print() and sleep()
import pandas as pd
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import time
df = pd.read_csv("Data.csv", sep="\t")
df['YearMonth'] = pd.to_datetime(df['YearMonth'], format='%Y-%m')
products = ['Product_1', 'Product_2', 'Product_3']
vendors = df['Vendor'].unique()
app = dash.Dash('Data')
app.layout = html.Div([
html.Div([
html.Div([
html.Label('Product'),
dcc.Dropdown(
id='product',
options=[{'label' : p, 'value' : p} for p in products],
multi=True,
value='Product_1'
),
]),
html.Div([
html.Label('Vendor'),
dcc.Dropdown(
id='vendor',
options=[{'label': v, 'value': v} for v in vendors],
multi=True,
value='ABC'
),
]),
]),
dcc.Graph(id='feature-graphic', figure=go.Figure())
])
#app.callback(
Output('feature-graphic', 'figure'),
[Input('product', 'value'),
Input('vendor', 'value')])
def update_graph(input_product, input_vendor):
# df_filtered[['Product_1', 'YearMonth']]
if type(input_product) == str:
input_product = [input_product]
if type(input_vendor) == str:
input_vendor= [input_vendor]
datasets = ['']
i = 1
for vendor in input_vendor:
df_filtered = df[df['Vendor'] == vendor]
for product in input_product:
datasets.append((df_filtered[['YearMonth', 'Vendor', product]]).copy())
datasets[i]['ProductName'] = product
datasets[i].rename(columns={product: 'Value'}, inplace=True)
i += 1
datasets.pop(0)
print(datasets)
traces = ['']
for dataset in datasets:
print(dataset)
time.sleep(1)
traces.append(
go.Scatter({
'x': dataset['YearMonth'],
'y': dataset['Value'],
'mode': 'lines',
'name': f"Vendor: {dataset['Vendor'].iloc[0]} Product: {dataset['ProductName'].iloc[0]}"
}))
traces.pop(0)
layout = {'title': 'Title of Chart'}
fig = {'data': traces, 'layout': go.Layout(layout)}
return go.Figure(fig)
if __name__ == '__main__':
app.run_server()
quick and dirty disclosure:
If you handle the 1. issue it will dramatically simplify everything.
So I'd try to isolate the pd.DataFrame() juggling out of the callback and into the upper I/O part.
1) don't use counters in for loops
2) my variable names aren't the best either
3) the following style is caveman's python and there must be a better way:
traces = ['']
traces.append(this_and_that)
traces.pop(0)
Generally:
using print(input_variable) and print(type(input_variable))
gets my wheels most of the time out of the mud.
after all
you should notice that each trace got its individual name which will show up in the legend. Clicking on the name in the legend will add or remove the trace without the need for#app.callback()

Bokeh return empty map

I am trying to create a map with bokeh to show the population in US_cities, but as soon as I run the code, it returns empty map, frame is there but map is not. I am trying to do something like this but for all US Cities.
Here is my code using "us_cities.json" file in bokeh data:
import pandas as pd
from bokeh.io import show
from bokeh.models import (
ColumnDataSource,
HoverTool,
LogColorMapper
)
from bokeh.palettes import Viridis6 as palette
from bokeh.plotting import figure
palette.reverse()
new_data = pd.read_json("/home/alvin/.bokeh/data/us_cities.json")
#Creating random data that I want to show on map
new_data['pop'] = ((new_data['lat'] * 100) - new_data["lon"])/ 800
#Converting pd series to array
xs = new_data['lat'].tolist()
ys = new_data['lon'].tolist()
pops = new_data['pop'].tolist()
#creating ColumnDataSource
source = ColumnDataSource(data=dict(
x=xs,
y=ys,
pop = pops,
))
TOOLS = "pan,wheel_zoom,reset,hover,save"
p = figure(
title="Just a US Map", tools=TOOLS,
x_axis_location=None, y_axis_location=None
)
color_mapper = LogColorMapper(palette=palette)
p.grid.grid_line_color = None
p.patches('x', 'y', source=source,
fill_color={'field': 'pop', 'transform': color_mapper},
fill_alpha=0.7, line_color="white", line_width=0.5)
hover = p.select_one(HoverTool)
hover.point_policy = "follow_mouse"
hover.tooltips = [
("population)", "#pop%"),
("(Long, Lat)", "($x, $y)"),
]
show(p)
What could be the problem here?
I am running python3 and bokeh 0.12.6
If I check my data it looks like this:
enter image description here
The US cities data does not contain glyphs, like the counties data. You can show the counties data, and overlay the cities data as a scatter plot on top:
import pandas as pd
from bokeh.io import show
from bokeh.models import (
ColumnDataSource,
HoverTool,
LogColorMapper
)
from bokeh.palettes import Viridis6 as palette
from bokeh.plotting import figure
from bokeh.sampledata.us_counties import data as counties
palette.reverse()
counties = {
code: county for code, county in counties.items() if county["state"] == "tx"
}
county_xs = [county["lons"] for county in counties.values()]
county_ys = [county["lats"] for county in counties.values()]
csource = ColumnDataSource(data=dict(
x=county_xs,
y=county_ys,
))
new_data = pd.read_json("/home/tc427/.bokeh/data/us_cities.json")[::100]
#Creating random data that I want to show on map
new_data['pop'] = ((new_data['lat'] * 100) - new_data["lon"])/ 800
#Converting pd series to array
xs = new_data['lon'].tolist()
ys = new_data['lat'].tolist()
pops = new_data['pop'].tolist()
#creating ColumnDataSource
source = ColumnDataSource(data=dict(
x=xs,
y=ys,
pop = pops,
))
TOOLS = "pan,wheel_zoom,reset,hover,save"
p = figure(
title="Just a US Map", tools=TOOLS,
)
color_mapper = LogColorMapper(palette=palette, low=0, high=10)
p.patches('x', 'y', source=csource)
#p.patches('x', 'y', source=csource,
# fill_color={'field': 'pop', 'transform': color_mapper},
# fill_alpha=0.7, color="red", line_width=0.5)
p.scatter('x', 'y', source=source, color={'field': 'pop', 'transform': color_mapper})
hover = p.select_one(HoverTool)
hover.point_policy = "follow_mouse"
hover.tooltips = [
("population)", "#pop%"),
("(Long, Lat)", "($x, $y)"),
]
show(p)
I assume you are using a jupyter notebook...
As i have faced the same problem recently, I would suggest you try following steps;
open your browser's JavaScript console and check for errors.
read the discussion in link It seems to be a cronical problem.
It might be caused by many reasons like internet connetction issues, API problems etc. You can find and solve the problem by following above steps.
Once you detect and solve your problem, restarting the kernel will not help since the bokehjs is still loaded in the page. You will need to reload the page.

Bokeh: One url per glyph

I have a set of datapoints, each with a url unique to it. What I want to do is to be able to scatter plot my data, and then open the associated url when clicking the glyph. I have read the discussion here and followed the example here, but neither gets me where I want to be.
I have, somewhat arbitrarily and haphazardly, tried to save the urls in the tag property, to be recalled by the TapTool:
from bokeh.models import OpenURL, TapTool
from bokeh.plotting import figure, show
p = figure(plot_width = 1200,
plot_height = 700,
tools = 'tap')
p.circle(data_x,
data_y,
tags = list(data_urls))
taptool = p.select(type = TapTool, arg = "tag")
taptool.callback = OpenURL(url = '#tag')
show(p)
I have not been able to find any place in the Bokeh documentation that explains the nuts and bolts needed to assemble the behaviour that i want. At least not in terms I can understand.
Could someone please point me in the right direction? Thanks!
The tags property is not relevant, and largely disused. You need to put the URLs in a column in the plot data source, so that the OpenURL callback can access it:
from bokeh.models import ColumnDataSource, OpenURL, TapTool
from bokeh.plotting import figure, show
p = figure(plot_width=400, plot_height=400,
tools="tap", title="Click the Dots")
source = ColumnDataSource(data=dict(
x=[1, 2, 3, 4, 5],
y=[2, 5, 8, 2, 7],
color=["navy", "orange", "olive", "firebrick", "gold"]
))
p.circle('x', 'y', color='color', size=20, source=source)
# use the "color" column of the CDS to complete the URL
# e.g. if the glyph at index 10 is selected, then #color
# will be replaced with source.data['color'][10]
url = "http://www.colors.commutercreative.com/#color/"
taptool = p.select(type=TapTool)
taptool.callback = OpenURL(url=url)
show(p)
This example is documented (and live) here:
https://docs.bokeh.org/en/latest/docs/user_guide/interaction/callbacks.html#openurl

Resources