Skip to main content
Glama

mpl_mcp_plot_stack

Create stacked area or bar charts to visualize relationships between multiple data series using x and y values. This tool helps analyze cumulative data distributions and trends through clear visual representations.

Instructions

Plots stacked area/bar chart of given datavalues

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
x_dataYes
y_dataYes
chart_typeNoarea
labelsNo
titleNo
xlabelNo
ylabelNo
colorsNo
alphaNo
dpiNo
figsizeNo
gridNo
legendNo

Implementation Reference

  • The handler function `plot_stack` that implements the core logic for plotting stacked area or bar charts using matplotlib, handling inputs, generating the plot, and returning a PNG image.
    def plot_stack(
        x_data: Union[List[Union[float, int]], List[List[Union[float, int]]]],
        y_data: Union[List[List[Union[float, int]]], List[Union[float, int]]],
        chart_type: str = "area",  # "area" or "bar"
        labels: Optional[List[str]] = None,
        title: str = "",
        xlabel: str = "",
        ylabel: str = "",
        colors: Optional[Union[str, List[str]]] = None,
        alpha: float = 0.7,
        dpi: int = 200,
        figsize: Optional[List[Union[int, float]]] = None,
        grid: bool = True,
        legend: bool = True,
    ) -> Image:
        """
        Create a stacked area or bar chart.
    
        Args:
            x_data: X-axis data points (1D array-like)
            y_data: 2D array-like where each row represents a series to be stacked
            chart_type: Type of chart to create ("area" or "bar")
            labels: List of labels for the data series
            title: Plot title
            xlabel: Label for the x-axis
            ylabel: Label for the y-axis
            colors: Color or list of colors for the areas/bars
            alpha: Alpha transparency (0-1, default: 0.7)
            dpi: Output image resolution (dots per inch, default: 200)
            figsize: Figure size as (width, height) in inches
            grid: Whether to show grid lines (default: True)
            legend: Whether to show legend (default: True)
    
        Returns:
            FastMCP Image object with the plotted stack chart
        """
        # Convert inputs to numpy arrays with explicit float type
        x = np.asarray(x_data, dtype=float)
        y = np.asarray(y_data, dtype=float)
    
        # Ensure y_data is 2D
        if y.ndim == 1:
            y = y.reshape(1, -1)
    
        # Handle labels
        if labels is None:
            labels_list = [f"Series {i+1}" for i in range(y.shape[0])]
        elif isinstance(labels, str):
            labels_list = [labels]
        else:
            labels_list = list(labels)
    
        # Handle colors
        if colors is None:
            # Default color cycle
            default_colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
            colors = [default_colors[i % len(default_colors)] for i in range(y.shape[0])]
        elif isinstance(colors, str):
            colors = [str(colors)] * y.shape[0]
        elif isinstance(colors, list):
            # If the list is empty or contains None, use default colors
            if not colors or all(c is None for c in colors):
                default_colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
                colors = [default_colors[i % len(default_colors)] for i in range(y.shape[0])]
            else:
                # Filter out None values and ensure all elements are strings
                default_colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
                colors = [str(c) if c is not None else default_colors[i % len(default_colors)] for i, c in enumerate(colors)]
                # If colors list is shorter than y.shape[0], repeat colors
                if len(colors) < y.shape[0]:
                    colors += [default_colors[i % len(default_colors)] for i in range(len(colors), y.shape[0])]
        else:
            colors = [str(colors)] * y.shape[0]
    
        # Ensure colors is always a list for safe usage of len(colors)
        if not isinstance(colors, list):
            colors = [str(colors)] * y.shape[0]
        # If colors is still None (edge case), set to default colors
        if colors is None:
            default_colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
            colors = [default_colors[i % len(default_colors)] for i in range(y.shape[0])]
    
        # Create figure with specified size using OO interface
        # Normalize figsize
        if figsize and len(figsize) >= 2:
            figsize_vals = (float(figsize[0]), float(figsize[1]))
        else:
            figsize_vals = (8.0, 6.0)
    
        fig, ax = plt.subplots(figsize=figsize_vals, dpi=dpi)
    
        # Calculate the cumulative sum for stacking
        y_stack = np.cumsum(y, axis=0)
    
        # Create the stacked chart
        for i in range(y.shape[0] - 1, -1, -1):
            if i == 0:
                y_plot = y_stack[i]
                y_bottom = np.zeros_like(x)
            else:
                y_plot = y_stack[i] - y_stack[i - 1]
                y_bottom = y_stack[i - 1]
    
            if chart_type == "area":
                ax.fill_between(
                    x,
                    y_bottom,
                    y_stack[i],
                    label=labels_list[i] if i < len(labels_list) else f"Series {i+1}",
                    color=colors[i % len(colors)],
                    alpha=alpha,
                    edgecolor="none",
                )
            elif chart_type == "bar":
                ax.bar(
                    x,
                    y_plot,
                    bottom=y_bottom,
                    label=labels_list[i] if i < len(labels_list) else f"Series {i+1}",
                    color=colors[i % len(colors)],
                    alpha=alpha,
                    edgecolor="none",
                    width=0.8 if len(x) > 1 else 0.8 * (x[1] - x[0]) if len(x) > 1 else 0.8,
                )
    
        # Customize the plot
        ax.set_title(title)
        ax.set_xlabel(xlabel)
        ax.set_ylabel(ylabel)
    
        if grid:
            ax.grid(True, linestyle="--", alpha=0.7)
    
        if legend:
            ax.legend()
    
        plt.tight_layout()
    
        # Save the plot to a buffer and close the figure
        buf = io.BytesIO()
        fig.savefig(buf, format="png", dpi=dpi, bbox_inches="tight")
        plt.close(fig)
        buf.seek(0)
    
        return Image(data=buf.read(), format="png")
  • Registration of the `plot_stack` tool in the FastMCP server instance `mpl_mcp`. Note that the tool is likely exposed as 'mpl_mcp_plot_stack' or similar based on the server prefix.
    mpl_mcp.tool(plot_stack, description="Plots stacked area/bar chart of given datavalues")
  • Import of the `plot_stack` handler function into the server module for registration.
    from .core.stack_chart import plot_stack
  • Function signature defining the input schema (parameters with type hints) and output type (Image) for the tool.
    def plot_stack(
        x_data: Union[List[Union[float, int]], List[List[Union[float, int]]]],
        y_data: Union[List[List[Union[float, int]]], List[Union[float, int]]],
        chart_type: str = "area",  # "area" or "bar"
        labels: Optional[List[str]] = None,
        title: str = "",
        xlabel: str = "",
        ylabel: str = "",
        colors: Optional[Union[str, List[str]]] = None,
        alpha: float = 0.7,
        dpi: int = 200,
        figsize: Optional[List[Union[int, float]]] = None,
        grid: bool = True,
        legend: bool = True,
    ) -> Image:
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. It mentions plotting but doesn't describe what happens (e.g., creates a file, displays to screen, returns image data), whether it's read-only or has side effects, performance characteristics, or error conditions. This is inadequate for a 13-parameter tool with no annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise at just one sentence with zero wasted words. It's front-loaded with the core functionality and uses efficient terminology. While it's under-specified, it's not verbose or poorly structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 13-parameter plotting tool with no annotations, no output schema, and 0% schema description coverage, this description is completely inadequate. It doesn't explain what the tool returns, how parameters interact, what format the output takes, or any behavioral characteristics needed for proper invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, meaning all 13 parameters have only titles in the schema. The description mentions 'datavalues' but provides no explanation of what x_data and y_data should contain, the difference between area and bar chart types, or how other parameters like colors, alpha, or figsize affect the output. The description fails to compensate for the complete lack of schema documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states the tool creates stacked area/bar charts from data values, which is a clear purpose. However, it doesn't differentiate from sibling tools like mpl_mcp_plot_barchart or mpl_mcp_plot_chart, leaving ambiguity about when to choose this specific stacked visualization tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided about when to use this tool versus alternatives. With multiple plotting siblings (mpl_mcp_plot_barchart, mpl_mcp_plot_chart, etc.), the description offers no comparison or context for selecting this stacked chart option over other visualization tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/abhiphile/fermat-mcp'

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