import json import os import sys import random import argparse from modules.chart_engine.template.template_registry import get_template_for_chart_type, get_template_for_chart_name from modules.chart_engine.utils.load_charts import render_chart_to_svg from modules.chart_engine.utils.file_utils import create_temp_file, cleanup_temp_file, ensure_temp_dir, create_fallback_svg import importlib def load_data_from_json(json_file_path="input.json"): """ Load chart data from a JSON file Args: json_file_path: Path to the JSON file Returns: Dict containing the JSON data """ with open(json_file_path, 'r', encoding='utf-8') as f: return json.load(f) def parse_arguments(): """ Parse command-line arguments Returns: Namespace containing the parsed arguments """ parser = argparse.ArgumentParser(description='Generate chart SVG from JSON data') parser.add_argument('--input', type=str, default='input.json', help='Path to input JSON file (default: input.json)') parser.add_argument('--output', type=str, default=None, help='Path to output SVG file (default: auto-generated in tmp directory)') parser.add_argument('--name', type=str, default=None, help='Chart name to use (default: uses value from JSON or a default name)') parser.add_argument('--html', type=str, default=None, help='Path to save intermediate HTML file (default: not saved)') return parser.parse_args() if __name__ == '__main__': # Parse command-line arguments args = parse_arguments() # Ensure tmp directory exists tmp_dir = ensure_temp_dir() # Load data from input JSON file try: json_data = load_data_from_json(args.input) print(f"Loaded data from {args.input}") except Exception as e: print(f"Error loading JSON data from {args.input}: {e}") sys.exit(1) # Determine chart name (from args, JSON, or default) chart_name = args.name if chart_name is None: # Try to get chart name from JSON data (if your JSON structure contains this info) chart_name = json_data.get("chart_name", "donut_chart_01") print(f"Using chart name: {chart_name}") # Get the appropriate template for this chart type # Prefer JavaScript template for testing engine_preference = None engine, template = get_template_for_chart_name(chart_name, engine_preference=engine_preference) if engine is None: print(f"Error: No template found for chart name '{chart_name}'") sys.exit(1) print(f"Using {engine} template for {chart_name}") # Get dimensions from JSON data width = json_data.get("variables", {}).get("width", 1200) height = json_data.get("variables", {}).get("height", 800) print(f"Using dimensions: {width}x{height}") # Determine output SVG path if args.output: output_svg_path = args.output else: # Generate a random output SVG filename in tmp directory output_svg_path = os.path.join(tmp_dir, args.input.split('.')[0].split('/')[-1] + "_" + f"{chart_name.replace(' ', '_')}.svg") # Check if HTML output is requested html_output_path = args.html if html_output_path: print(f"HTML output will be saved to: {html_output_path}") svg_file = None error_message = None # 可用的输入:engine: 名字, template: 模板对应的文件路径,chart_type: 图表类型,json_data: 图表数据 # try: if engine == 'echarts_py': # Use Python template options = template.make_options(json_data) # 保存options到临时文件 echarts_options_file = create_temp_file(prefix="echarts_options_", suffix=".json", content=json.dumps(options, indent=2)) # 使用echarts-js相同的渲染方式 print(f"Using ECharts renderer for Python-generated options") # 创建JS封装函数 js_wrapper_content = f""" function make_option(jsonData) {{ return {json.dumps(options)}; }} """ js_wrapper_file = create_temp_file(prefix="echarts_wrapper_", suffix=".js", content=js_wrapper_content) try: # 渲染SVG svg_file = render_chart_to_svg( json_data=json_data, output_svg_path=output_svg_path, js_file=js_wrapper_file, width=width, height=height, framework="echarts", # 统一使用echarts框架 html_output_path=html_output_path, # Pass HTML output path ) if svg_file is None: raise ValueError("SVG chart generation failed (returned None)") print(f"ECharts SVG chart generated successfully") except Exception as e: error_message = str(e) raise Exception(f"Failed to generate ECharts Python chart: {error_message}") finally: # 清理临时文件 cleanup_temp_file(js_wrapper_file) cleanup_temp_file(echarts_options_file) elif engine == 'echarts-js': # 使用统一的render_chart_to_svg函数直接生成SVG try: svg_file = render_chart_to_svg( json_data=json_data, output_svg_path=output_svg_path, js_file=template, width=width, height=height, framework="echarts", html_output_path=html_output_path, # Pass HTML output path ) if svg_file is None: raise ValueError("SVG chart generation failed (returned None)") print(f"ECharts SVG chart generated successfully") except Exception as e: error_message = str(e) raise Exception(f"Failed to generate ECharts JavaScript chart: {error_message}") elif engine == 'd3-js': # 使用统一的render_chart_to_svg函数直接生成SVG try: svg_file = render_chart_to_svg( json_data=json_data, output_svg_path=output_svg_path, js_file=template, width=width, height=height, framework="d3", html_output_path=html_output_path, # Pass HTML output path ) if svg_file is None: raise ValueError("SVG chart generation failed (returned None)") print(f"D3.js SVG chart generated successfully") except Exception as e: error_message = str(e) raise Exception(f"Failed to generate D3.js chart: {error_message}") elif engine == 'vegalite_py': # Use vegalite_py template print("template:", template) template_root = "template.vegalite_py" general_chart_type = template.split('/')[-2] module_name = template.split('/')[-1].split('.')[0] print("module_name:", module_name) print("") module_path = f"{template_root}.{general_chart_type}.{module_name}" print("module_path:", module_path) module = importlib.import_module(module_path) chart_words = module_name.split('_') # 把每个单词的首字母大写 chart_words = [word.capitalize() for word in chart_words] # 把每个单词拼接起来 chart_type = ''.join(chart_words) print("chart_type:", chart_type) # 获取module所有的attribute # attributes = dir(module) template_class = getattr(module, chart_type) template_object = template_class(json_data) vega_spec = template_object.make_specification(json_data) # 保存vega_spec到临时文件 vega_spec_file = create_temp_file(prefix="vega_spec_", suffix=".json", content=json.dumps(vega_spec, indent=2)) # try: svg_file, svg_content = template_object.specification_to_svg(vega_spec, output_svg_path) with open("debug.svg", "w", encoding='utf-8') as f: f.write(svg_content) if svg_file is None: raise ValueError("SVG chart generation failed (returned None)") # print("svg_content:", svg_content) element_tree = template_object.svg_to_element_tree(svg_content) print("element_tree:", element_tree) template_object.apply_variation(json_data) svg_file = output_svg_path svg_content = template_object.element_tree_to_svg(template_object.elements_tree) with open(output_svg_path, 'w', encoding='utf-8') as f: f.write(svg_content) print(f"VegaLite SVG chart generated successfully") # except Exception as e: # error_message = str(e) # raise Exception(f"Failed to generate VegaLite chart: {error_message}") else: error_message = f"Unknown engine type: {engine}" print(f"Error: {error_message}") raise Exception(error_message) # except Exception as e: # print(f"Error generating chart: {e}") # error_message = str(e) # # Create a fallback SVG with error message as a last resort # if svg_file is None or not os.path.exists(svg_file): # print("Creating fallback SVG with error message...") # svg_file = create_fallback_svg( # output_path=output_svg_path, # chart_type=chart_type, # width=width, # height=height, # error_message=error_message # ) if svg_file is not None and os.path.exists(svg_file): # Output the final SVG path print(f"Final SVG output: {svg_file}") else: print("Error: No SVG file was generated") sys.exit(1)