Подсказки фигуры отображаются только при наведении курсора на точку данных: https://plotly.com/python/hover-text-and-formatting
Я хотел бы иметь простой способ настроить продолжительность отображения всплывающей подсказки после наведения на нее или, возможно, постоянно отображать всплывающую подсказку при нажатии на точку данных.
Это позволит мне включить кликабельные ссылки в подсказку.
Для таблиц данных вы можете настроить продолжительность отображения всплывающей подсказки, но я не вижу аналогичной опции для рисунков: https://dash.plotly.com/datatable/tooltips
Я думаю, вы можете добавить свои собственные всплывающие подсказки через систему событий или, возможно, каким-то образом изменить стиль CSS результирующего HTML, но это кажется излишним. Я бы все равно принял ответ с рабочим примером.
Кажется, предпринимаются некоторые усилия по устранению этой проблемы. Я не совсем понял, возможно ли это решение или как его применить: github.com/plotly/plotly.js/pull/1265 Это открытая проблема, которая, надеюсь, в конечном итоге добавит эту функцию: github .com/plotly/plotly.js/issues/998
Это решение css, которое отключает обычные всплывающие подсказки и вместо этого использует обратный вызов для отображения информации в элементе div. Когда мышь отходит от узла, мы используем css, чтобы сделать div невидимым за несколько секунд.
Ни в коем случае не отличное решение, но оно работает.
Я также попробовал решение, основанное на анимации атрибутов css, которое работает, но немного сложнее.
Я попытался изменить имя класса div вместо стиля и остановить переход при наведении курсора мыши на div, добавив к переходу условие css :not:hover
, но не смог заставить его работать полностью.
from dash import Dash, dcc, html, Input, Output, no_update
import plotly.express as px
df = px.data.tips()
fig = px.scatter(df, x = "total_bill", y = "tip")
# Turn off native plotly.js hover effects - make sure to use
# hoverinfo='none' rather than 'skip' which also halts events.
fig.update_traces(hoverinfo='none', hovertemplate=None)
# Hover distance defaults to 20 and means call hover event if mouse pointer is within x units close to the node.
fig.update_layout(hoverdistance=5)
app = Dash(__name__)
# Clear on unhover means the hover callback is called with hoverDate=None when moving away from the point.log_queue
app.layout = html.Div(
[
dcc.Graph(id='graph', figure=fig, clear_on_unhover=True),
html.Div(id='graph-tooltip'),
],
)
# Store previous style globally.
previous_style = None
@app.callback(
Output('graph-tooltip', 'style'),
Output('graph-tooltip', 'children'),
Input('graph', 'hoverData'),
prevent_initial_call=True,
)
def display_hover(hoverData):
'''When hovering over a node, show a HTML div element with some Node info and two links. When moving the mouse away from the node the div fades out slowly.'''
global previous_style
if hoverData is None:
# When the mouse moves a way from the node hoverData is None and we hide the element with opacity=0.
# The transition to hide the element happens over 4 seconds as defined below via the css attribute transition.
previous_style['opacity'] = 0
return previous_style, no_update
# Get attribute NAME from dataframe to display it.
# And get the x/y coordinates of the current node the mouse is hovering over.
pt = hoverData['points'][0]
box = pt['bbox']
num = pt['pointNumber']
df_row = df.iloc[num]
df_value = df_row['time']
children = [
html.P(f'{df_value}'),
html.A('Link to external site 1', href='https://plot.ly', target='_blank'),
html.Br(),
html.A('Link to external site 2', href='https://plot.ly', target='_blank'),
]
previous_style = {
'position': 'absolute',
'left': f'{box["x1"] + 20}px', # Display the div next to the node.
'top': f'{box["y1"] + 20}px',
'background-color': 'rgba(100, 100, 100, 0.8)',
'transition': 'opacity 4s ease-out', # Fade in / Fade out the div element gradually.
}
return previous_style, children
app.run_server()
Вот более сложное решение, которое предотвращает исчезновение всплывающей подсказки при наведении на нее курсора. Для этого вам нужен внешний файл css с анимацией css.
См. https://stackoverflow.com/a/75277310/2474025 для более простого решения.
активы/my.css:
.hideclass:not(:hover) {
animation: hideanimation 5s ease-in;
animation-fill-mode: forwards;
}
.showclass {
animation: showanimation 5s ease-out;
animation-fill-mode: forwards;
}
@keyframes showanimation {
0% {
opacity: 0;
}
25% {
opacity: 0.4;
}
50% {
opacity: 0.7;
}
75% {
opacity: 0.8;
}
100% {
opacity: 1;
}
}
@keyframes hideanimation {
0% {
opacity: 1;
}
25% {
opacity: 0.5;
}
50% {
opacity: 0;
}
75% {
opacity: 0;
max-width: 0;
max-height: 0;
overflow: hidden;
}
100% {
opacity: 0;
max-width: 0;
max-height: 0;
overflow: hidden;
}
}
Блокнот Python со следующим кодом должен находиться в том же каталоге, что и папка ресурсов:
from dash import Dash, dcc, html, Input, Output, no_update
import plotly.express as px
df = px.data.tips()
fig = px.scatter(df, x='total_bill', y='tip')
# Turn off native plotly.js hover effects - make sure to use
# hoverinfo='none' rather than 'skip' which also halts events.
fig.update_traces(hoverinfo='none', hovertemplate=None)
# Hover distance defaults to 20 and means call hover event if mouse pointer is within x units close to the node.
fig.update_layout(hoverdistance=5)
app = Dash(__name__)
app.layout = html.Div(
[
html.Link(rel='stylesheet', href='/assets/my.css'),
# clear on unhover means the hover callback is called with hoverDate=None when moving away from the point.log_queue
dcc.Graph(
id='graph-basic-2',
figure=fig,
clear_on_unhover=True,
),
html.Div(
id='graph-tooltip',
className='dash-bootstrap',
),
],
className='dash-bootrstrap',
)
previous_style = None
@app.callback(
Output('graph-tooltip', 'style'),
Output('graph-tooltip', 'className'),
Output('graph-tooltip', 'children'),
Input('graph-basic-2', 'hoverData'),
prevent_initial_call=True,
)
def display_hover(hoverData):
global previous_style
if hoverData is None:
return no_update, 'hideclass', no_update
print('display')
# demo only shows the first point, but other points may also be available
pt = hoverData['points'][0]
bbox = pt['bbox']
children = [
html.A('Link to external site 1', href='https://plot.ly', target='_blank'),
html.Br(),
html.A('Link to external site 2', href='https://plot.ly', target='_blank'),
]
previous_style = {
'position': 'absolute',
'left': f'{bbox["x1"] + 20}px',
'top': f'{bbox["y1"] + 20}px',
'background-color': 'rgba(100, 100, 100, 0.8)',
'padding': '1em',
}
return previous_style, 'showclass', children
# if __name__ == '__main__':
app.run_server(
dev_tools_hot_reload=True,
)
Обходной путь, когда вам нужна только одна ссылка, — использовать свойство
text
временной шкалы в качестве ссылки, например:"<a href='https://en.wikipedia.org/wiki/"+df['topic']+"' target='_blank'>"+df['topic']+"</a>"
. Это не решит первоначальную проблему, но позволит кликнуть хотя бы по тексту внутри ноды.