如何在Python Plotly时间轴中添加可打开本地Word文档的点击链接?
问题:Plotly时间轴文本添加本地Word文档可点击链接(Jupyter预览+PDF导出)
我在Jupyter环境用Python 3,通过以下代码用Plotly生成PDF时间轴:
import plotly.express as px import pandas as pd source = pd.DataFrame([ {"filename": 'blablabla', "start": '1795-01-01', "end": '1810-01-01'}, {"filename": "Sense and Sensibility","start": '1792-01-01', "end": '1797-01-01'}, {"filename": "Call the Midwife", "start": '1957-01-01', "end": '1967-02-01'}, ]) source['start'] = pd.to_datetime(source['start']) source['end'] = pd.to_datetime(source['end']) fig = px.timeline(source.sort_values('start'), x_start="start", x_end="end", y="filename", text="filename", color_discrete_sequence=["tan"]) fig.show() fig.write_image("C://Users/mytimeline.pdf")
生成和导出PDF都正常,但想把文件名改成可点击的超链接,点击打开本地Word文档。尝试用HTML <a> 标签替换文件名:
{"filename": '<a href=".1CL.docx">Call the Midwife</a>', "start": '1957-01-01', "end": '1967-02-01'}
遇到两个问题:
- Jupyter预览时,文本显示为蓝色链接,但点击会打开新标签页报错;用完整本地路径(
C://Users...1CL.docx)时,连新标签页都不会打开。 - 导出PDF后,链接样式消失,也无法点击。
解决方案
1. Jupyter预览中实现可点击本地链接
Plotly的text参数默认不解析HTML链接的本地协议,浏览器对file://协议有安全限制,直接点击会被拦截。需通过自定义JavaScript事件+customdata存储路径实现:
import plotly.express as px import pandas as pd from IPython.display import display, HTML # 新增本地路径列,空路径对应无需链接的项 source = pd.DataFrame([ {"filename": 'blablabla', "start": '1795-01-01', "end": '1810-01-01', "local_path": ""}, {"filename": "Sense and Sensibility","start": '1792-01-01', "end": '1797-01-01', "local_path": ""}, {"filename": "Call the Midwife", "start": '1957-01-01', "end": '1967-02-01', "local_path": "C://Users/xxx/1CL.docx"}, ]) source['start'] = pd.to_datetime(source['start']) source['end'] = pd.to_datetime(source['end']) fig = px.timeline(source.sort_values('start'), x_start="start", x_end="end", y="filename", text="filename", color_discrete_sequence=["tan"]) # 给图形trace绑定本地路径数据 fig.data[0].customdata = source['local_path'].tolist() # 添加点击事件监听,仅在Jupyter环境生效 display(HTML(''' <script> document.addEventListener('DOMContentLoaded', function() { let plotDiv = document.querySelector('.plotly-graph-div'); plotDiv.on('plotly_click', function(data) { let localPath = data.points[0].customdata; if (localPath) { // 转换路径格式并调用浏览器打开 let formattedPath = 'file:///' + localPath.replace(/\\\\/g, '/'); window.open(formattedPath, '_blank'); } }); }); </script> ''')) fig.show()
注意:Chrome等浏览器默认禁止网页打开本地文件,需启动时添加参数解除限制:
- Windows:
chrome.exe --allow-file-access-from-files - macOS:
open /Applications/Google\ Chrome.app --args --allow-file-access-from-files
2. 导出PDF时保留可点击本地链接
Plotly的write_image依赖Kaleido,不支持导出HTML链接到PDF。需先导出为HTML,再用weasyprint转PDF:
步骤1:安装依赖
pip install weasyprint
步骤2:导出带链接的Plotly HTML
import plotly.express as px import pandas as pd source = pd.DataFrame([ {"filename": 'blablabla', "start": '1795-01-01', "end": '1810-01-01', "local_path": ""}, {"filename": "Sense and Sensibility","start": '1792-01-01', "end": '1797-01-01', "local_path": ""}, {"filename": "Call the Midwife", "start": '1957-01-01', "end": '1967-02-01', "local_path": "C://Users/xxx/1CL.docx"}, ]) source['start'] = pd.to_datetime(source['start']) source['end'] = pd.to_datetime(source['end']) fig = px.timeline(source.sort_values('start'), x_start="start", x_end="end", y="filename", color_discrete_sequence=["tan"]) # 手动修改y轴标签为带本地链接的HTML fig.update_yaxes( tickmode='array', tickvals=source['filename'], ticktext=[ f'<a href="file:///{row["local_path"].replace("\\\\", "/")}">{row["filename"]}</a>' if row["local_path"] else row["filename"] for _, row in source.iterrows() ] ) # 导出HTML文件 fig.write_html("timeline_with_links.html")
步骤3:HTML转PDF
from weasyprint import HTML HTML("timeline_with_links.html").write_pdf("C://Users/mytimeline_with_links.pdf")
导出的PDF中,文件名会显示为可点击链接,点击后可打开对应本地Word文档(需PDF阅读器支持本地链接跳转)。
内容的提问来源于stack exchange,提问作者Hugo
相关产品推荐
相关产品推荐

