如何在Dash应用中导出全尺寸Cytoscape图谱为图片?
解决Dash Cytoscape完整图谱导出为PNG的问题
问题说明
使用Python Dash的Cytoscape组件构建故事编排交互式流程图时,场景节点及关联边组成的图谱常超出屏幕尺寸。当前通过generateImage回调仅能捕获屏幕可见区域的内容,缩小视图虽能容纳全图谱但会导致细节模糊;尝试过全页截图方案,因图谱画布超出网页范围无效。
当前代码
@self.app.callback( Output("network", "generateImage"), Input('dashboard-export-project-button', 'n_clicks'), prevent_initial_call=True ) def get_image(export_clicks): # Get the timezone local_tz = pytz.timezone('My Country') # Get the current time in UTC current_time_utc = datetime.utcnow() # Convert the UTC time to the Local timezone current_time = current_time_utc.replace(tzinfo=pytz.utc).astimezone(local_tz) time_stamp = current_time_local.strftime("%d/%m/%Y - %H:%M") # File type to output of 'svg, 'png', 'jpg', or 'jpeg' (alias of 'jpg') ftype = "png" # 'store': Stores the image data in 'imageData' !only jpg/png are supported # 'download'`: Downloads the image as a file with all data handling # 'both'`: Stores image data and downloads image as file. action = 'store' if ctx.triggered: if ctx.triggered_id == "dashboard-export-project-button": action = "download" return { 'type': ftype, 'action': action, 'filename': f'{self.project.title} - {time_stamp}', }
解决方案
方案1:临时适配布局后导出
通过临时将Cytoscape布局切换为fit模式,让所有节点自动适配容器可见区域,导出完成后恢复原布局,避免细节模糊。
修改后的回调代码:
from dash import ctx, Input, Output, State, no_update import pytz from datetime import datetime @self.app.callback( [Output("network", "generateImage"), Output("network", "layout")], Input('dashboard-export-project-button', 'n_clicks'), State("network", "layout"), prevent_initial_call=True ) def export_full_graph(export_clicks, original_layout): # 处理时间戳 local_tz = pytz.timezone('My Country') current_time_utc = datetime.utcnow() current_time = current_time_utc.replace(tzinfo=pytz.utc).astimezone(local_tz) time_stamp = current_time.strftime("%d/%m/%Y - %H:%M") if ctx.triggered_id == "dashboard-export-project-button": # 临时设置fit布局,让所有节点完整显示 fit_layout = { 'name': 'fit', 'padding': 50 # 预留边距防止节点被截断 } return ( { 'type': 'png', 'action': 'download', 'filename': f'{self.project.title} - {time_stamp}', }, fit_layout ) # 无触发时保持原状态 return (no_update, original_layout)
补充说明:可添加额外回调监听generateImage的imageData变化,在导出完成后自动恢复原布局,避免视图持续变化。
方案2:通过JavaScript获取完整SVG转PNG
直接利用Cytoscape的原生API获取完整图谱的SVG数据,再通过Canvas转换为PNG下载,无需调整视图,导出内容清晰完整。
添加客户端回调代码:
from dash import Input, Output, State # 新增一个dummy组件用于触发客户端回调 self.app.clientside_callback( """ function(n_clicks, project_title) { if (!n_clicks) return; // 获取Cytoscape实例 const cy = document.getElementById('network')._cy; // 获取完整图谱的SVG数据 const svgContent = cy.svg({ full: true }); // 将SVG转换为PNG const img = new Image(); img.onload = function() { const canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); // 触发下载 canvas.toBlob(function(blob) { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; const timestamp = new Date().toLocaleString().replace(/[/:,]/g, '-'); a.download = `${project_title} - ${timestamp}.png`; a.click(); URL.revokeObjectURL(url); }, 'image/png'); }; img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgContent); } """, Output('dummy-output', 'children'), # 无需实际输出,仅作为回调载体 Input('dashboard-export-project-button', 'n_clicks'), State('project-title', 'children'), # 替换为你存储项目标题的组件ID prevent_initial_call=True )
优势:无视图闪烁,直接导出完整清晰的图谱,无需依赖后端额外处理。
内容的提问来源于stack exchange,提问作者coco.abutbul
相关产品推荐
相关产品推荐

