python 绘图交互式工具提示/悬停文本/弹出窗口

yzuktlbb  于 2023-02-07  发布在  Python
关注(0)|答案(2)|浏览(278)

图形的工具提示仅在悬停在数据点上时显示:https://plotly.com/python/hover-text-and-formatting
我想有一个简单的方法来自定义的持续时间,工具提示显示后,悬停在它或可能显示的工具提示永久时,单击数据点。
这将允许我在工具提示中包含可单击的链接。
对于数据表,您可以自定义工具提示显示持续时间,但我没有看到图形的类似选项:https://dash.plotly.com/datatable/tooltips
我认为你可以通过事件系统添加你自己的工具提示,或者改变生成的HTML的css风格,但这似乎有点过头了,我仍然接受一个工作示例的答案。

frebpwbc

frebpwbc1#

这是一个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()
ekqde3dh

ekqde3dh2#

这里有一个更复杂的解决方案,当你把鼠标悬停在工具提示上时,它可以防止工具提示淡出,为此你需要一个带有css动画的外部css文件。
有关更简单的解决方案,请参见https://stackoverflow.com/a/75277310/2474025
资产/我的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笔记本需要与assets文件夹位于同一目录中:

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,
)

相关问题