Plotly 注释文本:在 URL 中编码哈希 (#) 字符

Posted

技术标签:

【中文标题】Plotly 注释文本:在 URL 中编码哈希 (#) 字符【英文标题】:Plotly Annotation Text: encoding the Hash (#) character in a URL 【发布时间】:2022-01-02 12:27:38 【问题描述】:

在一个 plotly dash 应用程序中,我添加了一个带有可点击链接的文本注释,其中包含一个哈希。

topic = "Australia"  # might contain spaces
hashtag = "#" + topic

annotation_text=f"<a href=\"https://twitter.com/search?q=urllib.parse.quote_plus(hashtag)&src=typed_query&f=live\">topic</a>"

我需要输出 html 包含 "https://twitter.com/search?q=%23Australia&amp;src=typed_query&amp;f=live",但我无法正确编码“#”字符。它被双重编码为​​ %2523。


最小的工作示例:

import dash
from dash.dependencies import Input, Output
import plotly.express as px
import urllib.parse

df = px.data.gapminder()
all_continents = df.continent.unique()

app = dash.Dash(__name__)

app.layout = dash.html.Div([
    dash.dcc.Checklist(
        id="checklist",
        options=["label": x, "value": x
                 for x in all_continents],
        value=all_continents[4:],
        labelStyle='display': 'inline-block'
    ),
    dash.dcc.Graph(id="line-chart"),
])


@app.callback(
    Output("line-chart", "figure"),
    [Input("checklist", "value")])
def update_line_chart(continents):
    mask = df.continent.isin(continents)
    fig = px.line(df[mask],
                  x="year", y="lifeExp", color='country')
    annotations = []
    df_last_value = df[mask].sort_values(['country', 'year', ]).drop_duplicates('country', keep='last')
    for topic, year, last_lifeExp_value in zip(df_last_value.country, df_last_value.year, df_last_value.lifeExp):
        hashtag = "#" + topic
        annotations.append(dict(xref='paper', x=0.95, y=last_lifeExp_value,
                                xanchor='left', yanchor='middle',
                                text=f"<a href=\"https://twitter.com/search?q=urllib.parse.quote_plus(hashtag)&src=typed_query&f=live\">topic</a>",
                                # text=f"<a href=\"https://twitter.com/search?q=#urllib.parse.quote_plus(topic)&src=typed_query&f=live\">topic</a>",

                                font=dict(family='Arial',
                                          size=16),
                                showarrow=False))

    fig.update_layout(annotations=annotations)
    return fig


app.run_server(debug=True)

当您运行此程序并单击折线图末尾的文本“Australia”时,它应该会打开 #Australia 的 Twitter 搜索页面。


我尝试过的:

    只使用一个“#”字符:text=f"&lt;a href=\"https://twitter.com/search?q=#urllib.parse.quote_plus(topic)&amp;src=typed_query&amp;f=live\"&gt;topic&lt;/a&gt;"

这里,# 字符在输出中未编码为 %23,这导致 twitter 链接断开。

https://twitter.com/search?q=#mytopic&amp;amp;src=typed_query&amp;amp;f=live link

    在标签text=f"&lt;a href=\"https://twitter.com/search?q=#urllib.parse.quote_plus(hashtag)&amp;src=typed_query&amp;f=live\"&gt;topic&lt;/a&gt;" 上使用quote_plus

这里,%23(编码的#字符)再次被编码,在输出中产生 %2523。

https://twitter.com/search?q=%2523mytopic&amp;amp;src=typed_query&amp;amp;f=livelink


如何让它正确编码 #(到 %23)所以我得到

href="https://twitter.com/search?q=%23mytopic&amp;amp;src=typed_query&amp;amp;f=live

【问题讨论】:

我测试了您的代码并得到了相同的结果。似乎 uri 的查询部分(在? 之后)没有按应有的方式进行转义,并且整个编码就像没有? 一样。这可能是注释文本渲染中的一个错误。一种解决方法是通过 javascript 覆盖它。 这是一个已知的错误:plotly/plotly.js#4084 【参考方案1】:

这是一个已知的错误:plotly/plotly.js#4084

plotly.js 中的违规行:

nodeSpec.href = encodeURI(decodeURI(href));
decodeURI 不解码 %23decodeURIComponent 可以)。 encodeURI 不编码 #,但编码 %encodeURIComponent 两者都编码)。

更多信息:What is the difference between decodeURIComponent and decodeURI?

解决方法

您可以覆盖内置的encodeURI 以恢复%23% 的编码:

app._inline_scripts.append('''
_encodeURI = encodeURI;
encodeURI = uri => _encodeURI(uri).replace('%2523', '%23');
''')

【讨论】:

以上是关于Plotly 注释文本:在 URL 中编码哈希 (#) 字符的主要内容,如果未能解决你的问题,请参考以下文章

当我在 plotly 中使用 ggplotly 函数时,为啥文本注释会丢失?

Plotly:如何在带注释的热图中舍入显示文本但在悬停时保持完整格式?

Plotly 图形组件不能接受视口单位来设置文本注释字体大小

Plotly:如何在 Plotly Express 中注释多行?

在 plotly express 中添加另一个数据框作为注释

Plotly Express 防止文本值出现在悬停模板中