Skip to main content
Glama
hyunjae-labs

xlwings Excel MCP Server

by hyunjae-labs

create_chart

Create charts in Excel worksheets using specified data ranges and chart types, placing them at target cells with optional titles and axis labels.

Instructions

Create chart in worksheet. Args: sheet_name: Name of worksheet data_range: Data range for chart chart_type: Type of chart target_cell: Cell where chart will be placed session_id: Session ID from open_workbook (preferred) filepath: Path to Excel file (legacy, deprecated) title: Chart title (optional) x_axis: X-axis label (optional) y_axis: Y-axis label (optional) Note: Use session_id for better performance. filepath parameter is deprecated.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
sheet_nameYes
data_rangeYes
chart_typeYes
target_cellYes
session_idNo
filepathNo
titleNo
x_axisNo
y_axisNo

Implementation Reference

  • MCP tool registration and handler for 'create_chart'. Dispatches to session-based or legacy filepath-based implementations.
    @mcp.tool() def create_chart( sheet_name: str, data_range: str, chart_type: str, target_cell: str, session_id: Optional[str] = None, filepath: Optional[str] = None, title: str = "", x_axis: str = "", y_axis: str = "" ) -> str: """ Create chart in worksheet. Args: sheet_name: Name of worksheet data_range: Data range for chart chart_type: Type of chart target_cell: Cell where chart will be placed session_id: Session ID from open_workbook (preferred) filepath: Path to Excel file (legacy, deprecated) title: Chart title (optional) x_axis: X-axis label (optional) y_axis: Y-axis label (optional) Note: Use session_id for better performance. filepath parameter is deprecated. """ try: # Support both new (session_id) and old (filepath) API if session_id: # New API: use session session = SESSION_MANAGER.get_session(session_id) if not session: return ERROR_TEMPLATES['SESSION_NOT_FOUND'].format( session_id=session_id, ttl=10 # Default TTL is 10 minutes (600 seconds) ) with session.lock: from xlwings_mcp.xlwings_impl.advanced_xlw import create_chart_xlw_with_wb result = create_chart_xlw_with_wb( session.workbook, sheet_name=sheet_name, data_range=data_range, chart_type=chart_type, target_cell=target_cell, title=title, x_axis=x_axis, y_axis=y_axis ) elif filepath: # Legacy API: backwards compatibility logger.warning("Using deprecated filepath parameter. Please use session_id instead.") full_path = get_excel_path(filepath) from xlwings_mcp.xlwings_impl.advanced_xlw import create_chart_xlw result = create_chart_xlw( filepath=full_path, sheet_name=sheet_name, data_range=data_range, chart_type=chart_type, target_cell=target_cell, title=title, x_axis=x_axis, y_axis=y_axis ) else: return ERROR_TEMPLATES['PARAMETER_MISSING'].format( param1='session_id', param2='filepath' ) return result.get("message", "Chart created successfully") if "error" not in result else f"Error: {result['error']}" except (ValidationError, ChartError) as e: return f"Error: {str(e)}" except Exception as e: logger.error(f"Error creating chart: {e}") raise
  • Core implementation of chart creation for session-based (with existing workbook) usage. Called by the main handler when session_id is provided.
    def create_chart_xlw_with_wb( wb, sheet_name: str, data_range: str, chart_type: str, target_cell: str, title: str = "", x_axis: str = "", y_axis: str = "" ) -> Dict[str, Any]: """Session-based version using existing workbook object. Args: wb: Workbook object from session sheet_name: Name of worksheet data_range: Range of data for chart (e.g., "A1:C10") chart_type: Type of chart (line, bar, pie, scatter, area, column) target_cell: Cell where chart will be positioned title: Chart title x_axis: X-axis label y_axis: Y-axis label Returns: Dict with success message or error """ try: logger.info(f"πŸ“ˆ Creating {chart_type} chart in {sheet_name}") # Check if sheet exists sheet_names = [s.name for s in wb.sheets] if sheet_name not in sheet_names: return {"error": f"Sheet '{sheet_name}' not found"} sheet = wb.sheets[sheet_name] # Map chart types to Excel constants (Microsoft XlChartType enumeration) chart_type_map = { 'column': -4100, # xlColumnClustered 'bar': -4099, # xlBarClustered 'line': 4, # xlLine 'pie': 5, # xlPie 'area': 1, # xlArea 'scatter': -4169, # xlXYScatter 'doughnut': -4120, # xlDoughnut 'radar': -4151, # xlRadarMarkers } if chart_type.lower() not in chart_type_map: available_types = ', '.join(chart_type_map.keys()) return {"error": f"CHART_TYPE_ERROR: '{chart_type}' is not supported. Available types: {available_types}"} excel_chart_type = chart_type_map[chart_type.lower()] # Get data range first data_range_obj = sheet.range(data_range) # Create chart using xlwings method chart = sheet.charts.add() # Set data source chart.set_source_data(data_range_obj) # Set chart type - use xlwings chart_type property or COM API try: # First try xlwings native method (accepts string) if hasattr(chart, 'chart_type'): try: # xlwings accepts the string directly chart.chart_type = chart_type.lower() logger.info(f"Set chart type to {chart_type} using xlwings method") except: # If string doesn't work, try the constant chart.chart_type = excel_chart_type logger.info(f"Set chart type to {chart_type} using constant {excel_chart_type}") else: # Fallback to COM API chart_api = chart.api if hasattr(chart_api, 'ChartType'): chart_api.ChartType = excel_chart_type logger.info(f"Set chart type to {chart_type} via COM API (constant: {excel_chart_type})") else: # Last resort - chart may already have correct type from creation logger.warning(f"Could not explicitly set chart type, using default") except Exception as e: # Non-fatal: log but continue (chart may still work with default type) logger.warning(f"Chart type setting had issues but continuing: {e}") # Set chart position target = sheet.range(target_cell) chart.top = target.top chart.left = target.left # Calculate chart size based on data range data_rows = data_range_obj.rows.count data_cols = data_range_obj.columns.count # Dynamic sizing based on data chart.width = min(600, max(400, data_cols * 80)) # Adjust width based on columns chart.height = min(450, max(300, data_rows * 15)) # Adjust height based on rows # Set chart properties safely try: chart_com = chart.api # Set title if title and hasattr(chart_com, 'HasTitle'): chart_com.HasTitle = True if hasattr(chart_com, 'ChartTitle'): chart_com.ChartTitle.Text = title # Set axis labels if hasattr(chart_com, 'Axes'): try: if x_axis: x_axis_obj = chart_com.Axes(1) # xlCategory x_axis_obj.HasTitle = True x_axis_obj.AxisTitle.Text = x_axis if y_axis: y_axis_obj = chart_com.Axes(2) # xlValue y_axis_obj.HasTitle = True y_axis_obj.AxisTitle.Text = y_axis except Exception as e: logger.warning(f"Axis label setting failed: {e}") except: # Some chart types don't have axes pass # Save the workbook wb.save() logger.info(f"βœ… Successfully created {chart_type} chart") return { "message": f"Successfully created {chart_type} chart", "chart_type": chart_type, "data_range": data_range, "position": target_cell, "sheet": sheet_name } except Exception as e: logger.error(f"❌ Error creating chart: {str(e)}") return {"error": str(e)}
  • Legacy filepath-based chart creation implementation. Called when no session_id is provided.
    def create_chart_xlw( filepath: str, sheet_name: str, data_range: str, chart_type: str, target_cell: str, title: str = "", x_axis: str = "", y_axis: str = "" ) -> Dict[str, Any]: """ Create a chart in Excel using xlwings. Args: filepath: Path to Excel file sheet_name: Name of worksheet data_range: Range of data for chart (e.g., "A1:C10") chart_type: Type of chart (line, bar, pie, scatter, area, column) target_cell: Cell where chart will be positioned title: Chart title x_axis: X-axis label y_axis: Y-axis label Returns: Dict with success message or error """ app = None wb = None # Initialize COM for thread safety (Windows) _com_initialize() try: logger.info(f"Creating {chart_type} chart in {sheet_name}") # Check if file exists if not os.path.exists(filepath): return {"error": f"File not found: {filepath}"} # Open Excel app and workbook app = xw.App(visible=False, add_book=False) wb = app.books.open(filepath) # Check if sheet exists sheet_names = [s.name for s in wb.sheets] if sheet_name not in sheet_names: return {"error": f"Sheet '{sheet_name}' not found"} sheet = wb.sheets[sheet_name] # Map chart types to Excel constants chart_type_map = { 'line': 4, # xlLine 'bar': 57, # xlBarClustered 'column': 51, # xlColumnClustered 'pie': 5, # xlPie 'scatter': 74, # xlXYScatter 'area': 1, # xlArea } if chart_type.lower() not in chart_type_map: return {"error": f"Unsupported chart type: {chart_type}"} excel_chart_type = chart_type_map[chart_type.lower()] # Get data range first data_range_obj = sheet.range(data_range) # Create chart using xlwings method chart = sheet.charts.add() # Set data source chart.set_source_data(data_range_obj) # Set chart type - handle COM API properly try: if hasattr(chart, 'chart_type'): # Use xlwings built-in chart type property chart.chart_type = chart_type.lower() else: # Use COM API more carefully chart_api = chart.api if hasattr(chart_api, 'ChartType'): chart_api.ChartType = excel_chart_type else: logger.warning("Cannot set chart type - using default") except Exception as e: logger.warning(f"Chart type setting failed: {e}, using default") # Set chart position target = sheet.range(target_cell) chart.top = target.top chart.left = target.left # Calculate chart size based on data range data_rows = data_range_obj.rows.count data_cols = data_range_obj.columns.count # Dynamic sizing based on data chart.width = min(600, max(400, data_cols * 80)) # Adjust width based on columns chart.height = min(450, max(300, data_rows * 15)) # Adjust height based on rows # Set chart properties safely try: chart_com = chart.api # Set title if title and hasattr(chart_com, 'HasTitle'): chart_com.HasTitle = True if hasattr(chart_com, 'ChartTitle'): chart_com.ChartTitle.Text = title # Set axis labels if hasattr(chart_com, 'Axes'): try: if x_axis: x_axis_obj = chart_com.Axes(1) # xlCategory x_axis_obj.HasTitle = True x_axis_obj.AxisTitle.Text = x_axis if y_axis: y_axis_obj = chart_com.Axes(2) # xlValue y_axis_obj.HasTitle = True y_axis_obj.AxisTitle.Text = y_axis except Exception as e: logger.warning(f"Axis label setting failed: {e}") except: # Some chart types don't have axes pass # Save the workbook wb.save() logger.info(f"βœ… Successfully created {chart_type} chart") return { "message": f"Successfully created {chart_type} chart", "chart_type": chart_type, "data_range": data_range, "position": target_cell, "sheet": sheet_name } except Exception as e: logger.error(f"❌ Error creating chart: {str(e)}") return {"error": str(e)} finally: if wb: wb.close() if app: app.quit()
  • Import of the session-based helper functions into the advanced_xlw module.
    from .advanced_xlw_with_wb import ( create_chart_xlw_with_wb, create_pivot_table_xlw_with_wb, create_table_xlw_with_wb )

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hyunjae-labs/xlwings-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server