Try this:
from dash import Dash, dcc, html, Input, Output, clientside_callback, State
import plotly.graph_objects as go
fig = go.Figure(
go.Bar(
x=list('ABCDE'),
y=[1, 2, 3, 4, 5],
)
)
# app initialization
app = Dash(
__name__
)
# app layout
app.layout = html.Div(
[
dcc.Graph(
id='graph',
figure=fig,
),
dcc.Store(id='axis_range'),
html.Pre(id='out'),
]
)
# callback returns the current axis range for the x-axis
clientside_callback(
"""
function (data, fig) {
[min, max] = fig.layout.xaxis.range
return [min, max]
}
""",
Output('axis_range', 'data'),
Input('graph', 'relayoutData'),
State('graph', 'figure'),
prevent_initial_call=True
)
@app.callback(
Output('out', 'children'),
Input('axis_range', 'data'),
State('graph', 'figure'),
prevent_initial_call=True
)
def decide(axis_range, figure):
# min and max values of current view
mn, mx = axis_range
# extract x-axis values
# if more than one trace in figure, you will have to adapt this
org_x = figure['data'][0]['x']
# check if axis is categorical (string)
if isinstance(org_x[0], str):
x = range(len(org_x))
else:
x = fig['data'][0]['x']
# check for each item if in min max range.
# if so, append to visible
# this could lead to problems, if the bars are quite thick and the user does
# not zoom "enough", e.g over the center x-coordinate of the bar
visible = []
for idx, val in enumerate(x):
if mn < val < mx:
visible.append(idx)
# prepare output, recreate original axis values
out = f'FULLY visible right now: {[org_x[i] for i in visible]}'
return out
if __name__ == '__main__':
app.run_server(debug=True, port=8053)