如何在Pandoc的Matplotlib过滤器中高效共享Pandas数据源?
Pandoc Matplotlib过滤器共享数据源解决方案
核心思路
利用Pandoc过滤器的全局状态保存特性,在首次执行时初始化数据源,后续代码片段直接复用资源,最后在过滤器结束时自动清理数据库连接等资源。
具体实现步骤
1. 编写自定义Pandoc过滤器脚本
用Python实现过滤器,通过全局变量维护共享的数据库连接和DataFrame:
import pandocfilters as pf import sqlite3 import pandas as pd import matplotlib.pyplot as plt import io # 全局容器存储共享资源 _shared_resources = { 'db_conn': None, 'dataset': None } def process_matplotlib_block(key, value, fmt, meta): if key == 'CodeBlock' and len(value) == 2: attrs, code = value classes, _, _ = attrs if 'matplotlib' in classes: global _shared_resources try: # 首次执行时初始化数据源 if _shared_resources['dataset'] is None: _shared_resources['db_conn'] = sqlite3.connect('somedb.db') query = '''SELECT something''' _shared_resources['dataset'] = pd.read_sql_query(query, _shared_resources['db_conn']).dropna() # 将共享变量注入代码执行环境 exec_env = { 'df': _shared_resources['dataset'], 'plt': plt, 'pd': pd } exec(code, globals(), exec_env) # 提取生成的图表并转为Base64格式嵌入文档 fig = exec_env.get('fig') or plt.gcf() buf = io.BytesIO() fig.savefig(buf, format='png') buf.seek(0) img_base64 = buf.getvalue().hex() plt.close(fig) # 返回Pandoc图片节点 return pf.Para([pf.Image(['', [], []], [], [f'data:image/png;base64,{img_base64}', 'chart'])]) except Exception as e: return pf.Str(f"图表生成失败: {str(e)}") return None if __name__ == '__main__': pf.toJSONFilter(process_matplotlib_block) # 过滤器结束时自动关闭数据库连接 if _shared_resources['db_conn'] is not None: _shared_resources['db_conn'].close()
2. 简化Markdown中的代码片段
文档内无需重复初始化数据源,直接调用共享的df变量生成图表:
第一幅图表: ~~~{.matplotlib} fig, ax = plt.subplots() ax.hist(df['target_column']) ax.set_title('数值分布直方图') ~~~ 第二幅图表: ~~~{.matplotlib} fig, ax = plt.subplots() ax.scatter(df['feature1'], df['feature2']) ax.set_title('双特征散点图') ~~~
3. 调用Pandoc并启用过滤器
执行转换命令时指定自定义过滤器脚本:
pandoc input.md -o output.pdf --filter ./matplotlib_filter.py
关键细节说明
- 资源隔离:用全局字典存储共享资源,避免与用户代码的变量命名冲突
- 自动清理:过滤器脚本末尾统一关闭数据库连接,确保会话结束后释放资源
- 容错机制:添加异常捕获,单个图表生成失败不会中断整个文档的转换流程
内容的提问来源于stack exchange,提问作者Scott Deerwester
相关产品推荐
相关产品推荐

