Skip to main content
Glama
hyunjae-labs

xlwings Excel MCP Server

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