Hi there,
I have an horizontal barchart with a scatter (line) over it and when I hover over, it shows the wrong data/label.
Looks like if the bars had a div from where they are placed down to the x axis so the longest ones go over the shorter ones, making it imposible to hover over the short ones.
This is the example I’ve been working on (file here and full code below)
E.g. Starting with your pointer on the right side of the Power Supplies bar and moving it to the left:
- First part it is correct, Power supplies (blue)
- until it reaches the point where it would cross the line chart Other, where it shows Other (orange).
- If you keep going slowly it shows Other (blue),
- then Power Supplies (orange) when it meets the point,
- then Cables (orange) until it “goes out” of the line chart
- then Other (blue).
It’d make sense that is because the line is over the bar chart, but why 3 and 6? I can’t seem to get Cables (blue) hovered, whenever it is out of the points of the line chart, it shows Other instead of Cables.
Any ideas?
Thank you!
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd
indent preformatted text by 4 spaces
df = pd.read_csv("item2.txt", sep=',')
cols = df.columns
cols = cols.map(lambda x: x.replace(' ', '_') if isinstance(x, (str, unicode)) else x)
df.columns = cols
app = dash.Dash()
app.css.append_css({'external_url': 'https://codepen.io/chriddyp/pen/bWLwgP.css'})
app.config['suppress_callback_exceptions']=False
app.layout = html.Div(
html.Div(
children=[
#First row
html.Div(
children=[
# Location Dropdown
html.Div(
children=[
html.Label('Location'),
dcc.Dropdown(id='location',
options=[{'label': i, 'value': i} for i in df.Location.unique()],
)
], className="one columns"),
# Site Dropdown
html.Div(
children=[
html.Label('Site'),
dcc.Dropdown(id='site',
options=[{'label': i, 'value': i} for i in df.Site.unique()],
)
], className="one columns"),
# Items
html.Div(
children=[
html.Label('Items'),
html.Div(id='items_container')
#df.shape[0])
], className="one columns"),
# Quantity
html.Div(
children=[
html.Label('Quantity'),
html.Div(id='quantity_container')
], className="one columns"),
html.Div(
children=[
html.Label('Placeholder'),
html.Div(id='placeholder')
], className="eight columns", style={'width':'100%'}),
]),
html.Div(
children=[
html.Div(
children=[
# BarChart with stock by type
html.Div(id='bar_current_stock_by_type_container',
children=[dcc.Graph(id='bar_stock_by_type', clickData={'points': []}
)]
),
], className="four columns"),
]),
html.Div(
children=[
html.Div(
children=[
# Table with data
html.Div(id='table-container')
], className="twelve columns"),
])
])
)
def get_filtered_df(location, site, clickData):
if location is None and site is None:
dff = df
elif site is None:
dff = df[df.Location == location]
elif location is None:
dff = df[df.Site == site]
else:
dff = df[(df.Location == location) & (df.Site == site)]
print (clickData["points"])
if clickData["points"] != []:
dataselected = clickData["points"][0]["y"]
print dataselected
for item in dff.Stock_Type:
if item == dataselected:
dff2 = dff[(dff.Stock_Type == dataselected)]
else:
dff2=dff
return dff2
def generate_table(df, max_rows=10):
return html.Table(
[html.Tr([html.Th(col) for col in df.columns])] +
[html.Tr([html.Td(df.iloc[i][col]) for col in df.columns])
for i in range(min(len(df), max_rows))], id='full_table'
)
def generate_bar_stock_by_type(df, byStockType):
x = byStockType.sum()['Inventory_Value']/1000
line = go.Scatter(
x=x,
y=x.index,
name='Inventory value (k)'
)
x = byStockType.count()['Current_Balance']
bar = go.Bar(
x=x,
y=x.index,
orientation='h',
name='Num Stock Units'
)
graph_stock = dcc.Graph(
id='bar_stock_by_type',
figure={'data': [bar,line]},
clickData={'points': [], 'range': None},
config={'displayModeBar': True},
style={}
)
return graph_stock
# Items Metric
@app.callback(
dash.dependencies.Output('items_container', 'children'),
[dash.dependencies.Input('location', 'value'),
dash.dependencies.Input('site', 'value'),
dash.dependencies.Input('bar_stock_by_type', 'clickData')
])
def display_metric_items(location, site, clickData):
dff = get_filtered_df(location, site, clickData)
return html.H3(dff.shape[0])
# Quantity Metric
@app.callback(
dash.dependencies.Output('quantity_container', 'children'),
[dash.dependencies.Input('location', 'value'),
dash.dependencies.Input('site', 'value'),
dash.dependencies.Input('bar_stock_by_type', 'clickData')
])
def display_metric_quantity(location, site, clickData):
dff = get_filtered_df(location, site, clickData)
return html.H3(dff['Current_Balance'].sum())
# Table
@app.callback(
dash.dependencies.Output('table-container', 'children'),
[dash.dependencies.Input('location', 'value'),
dash.dependencies.Input('site', 'value'),
dash.dependencies.Input('bar_stock_by_type', 'clickData')
])
def display_table(location, site, clickData):
dff = get_filtered_df(location, site, clickData)
return generate_table(dff)
# Horizontal Bar Chart
@app.callback(
dash.dependencies.Output('bar_current_stock_by_type_container', 'children'),
[dash.dependencies.Input('location', 'value'),
dash.dependencies.Input('site', 'value')])
def display_bar_current_stock_by_type(location, site):
dff = get_filtered_df(location, site, clickData={'points': [], 'range': None})
byStockType = dff.groupby('Stock_Type')
return generate_bar_stock_by_type(dff, byStockType)
if __name__ == '__main__':
app.run_server(debug=True)