plotly / plotly.js

Open-source JavaScript charting library behind Plotly and Dash
https://plotly.com/javascript/
MIT License
17.08k stars 1.87k forks source link

text annotations with with hrefs containing encoded characters such as '#' break links #4084

Open ned2 opened 5 years ago

ned2 commented 5 years ago

The solution that was adopted in #2471 to enable support for encoded hrefs seems to break for characters like # and :. This seems to be because JavaScript's encodeURI and decodeURI do not encode/decode these characters. Perhaps more nuanced used of encodeURIComponent and decodeURIComponent needs to be used?

Here's a minimal working example in Python, which is trying to link to a Twitter query for #food lang:en, in which the #and : characters need to be encoded:

import plotly.io as pio
fig = {"data": [{"type": "bar", "x": ['<a href="http://twitter.com/search? q=%23food%20lang%3Aen">query</a>'], "y": [1]}]}
pio.show(fig)

The generated link ends up being scrambled because the hash and colon escape sequences are not decoded, but are then encoded again, resulting in the following Twitter search: %23food lang%3Aen

etpinard commented 5 years ago

Thanks very much for reporting!

etpinard commented 5 years ago

related: https://github.com/plotly/plotly.js/issues/3449

etpinard commented 5 years ago

More on the topic:

https://stackoverflow.com/questions/747641/what-is-the-difference-between-decodeuricomponent-and-decodeuri

RichardNeill commented 5 years ago

Currently, it seems to also struggle with text of the form
<a href='#item3'>third</a> because, when clicking on the link, we actually get the effect of: <a href='thispage.html#item3'>third</a>

In other words, rather than simply scrolling down to the matching , the effect is to completely reload the page. Thanks for your help.

etpinard commented 5 years ago

Some interesting thoughts in https://github.com/plotly/plotly.js/issues/2239#issuecomment-356497602

vpicouet commented 2 years ago

Hello! is there a way to bypass this issue for now?

acjh commented 2 years ago

You can hijack plotly.io._html._window_plotly_config to override encodeURI.

pio._html._window_plotly_config += """
<script>
_encodeURI = encodeURI;
encodeURI = uri => _encodeURI(uri)
    .replace('%2523', '%23')  // #
    .replace('%253A', '%3A'); // :
</script>
"""
vpicouet commented 2 years ago

Thanks for the hack! Do you have a bigger example? I do not manage to have it working: I integrated it in a minimalist example:

import plotly.graph_objects as go
import plotly.io as pio 
from  plotly.io import _html
from plotly.offline import init_notebook_mode, iplot,  download_plotlyjs 

_html._window_plotly_config += """
<script>
_encodeURI = encodeURI;
encodeURI = uri => _encodeURI(uri)
    .replace('%252b', '%2b')  // #
</script>
"""

text = "<a href='http://simbad.u-strasbg.fr/simbad/sim-id?Ident=SDSS+J000102.74%2b012941.9'>Link</a>"
print(text)
data=go.Scatter(x=[1],y=[1],mode='markers+text',
                hovertext = text,
                text=[text])
fig=go.Figure([data])
iplot(fig)

You can see that the link I prink works: http://simbad.u-strasbg.fr/simbad/sim-id?Ident=SDSS+J000102.74%2b012941.9 While the one return my plotly changes the %2b into %252b and then the links fails: http://simbad.u-strasbg.fr/simbad/sim-id?Ident=SDSS+J000102.74%252b012941.9 Basically I do not see any change from the pio._html._window_plotly_config change

Thanks for you help!

acjh commented 2 years ago

Your example works fine for me. Which version of plotly are you on?

vpicouet commented 2 years ago

5.5.0. You mean that if you click on the plotly image link you get a result form the SQL query with a galaxy image and properties or it returns the website with the error: "this identifier has an incorrect format for catalog" My example can be directly found on binder (last cell) https://mybinder.org/v2/gh/vpicouet/notebooks/main?labpath=Plotly.ipynb

acjh commented 2 years ago

Yes, it should work in your terminal too.

For JupyterLab (on Binder), you can run:

from IPython.display import display, Javascript

display(Javascript("""
window._encodeURI = window._encodeURI || encodeURI;
encodeURI = uri => _encodeURI(uri)
    .replace('%2523', '%23')  // #
    .replace('%253A', '%3A')  // :
    .replace('%252b', '%2b'); // +
"""))
vpicouet commented 2 years ago

Thanks a lot for your help!!!! It works perfectly !

caleblf commented 7 months ago

I've run into this issue in a JS application where the URIs I'd like to link to may contain escaped characters, including %2F. Replacing window.encodeURI as suggested above breaks other libraries that rely on the normal behavior.

My ideal solution would be to add a config parameter to disable Plotly's broken URI sanitization for a single plot. Then I can do my own sanitization elsewhere.