Skip to main content
Glama

generate_radar_chart

Visualize multidimensional data in a radar chart to compare multiple entities across four or more dimensions, such as product features or performance metrics, using customizable themes and output formats.

Instructions

Generate a radar chart to display multidimensional data (four dimensions or more), such as, evaluate Huawei and Apple phones in terms of five dimensions: ease of use, functionality, camera, benchmark scores, and battery life.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
dataYesData for radar chart, such as, [{ name: 'Design', value: 70 }, { name: 'Performance', value: 85 }] or [{ name: 'Design', value: 70, group: 'iPhone' }].
heightNoSet the height of the chart, default is 600px.
outputTypeNoThe output type of the diagram. Can be 'png', 'svg' or 'option'. Default is 'png', 'png' will return the rendered PNG image, 'svg' will return the rendered SVG string, and 'option' will return the valid ECharts option.png
themeNoSet the theme for the chart, optional, default is 'default'.default
titleNoSet the title of the chart.
widthNoSet the width of the chart, default is 800px.

Implementation Reference

  • The 'run' function executes the tool logic: processes input data into radar dimensions and series (handling single or multi-group data), configures ECharts radar chart options with unified max values and styling, then generates the image using shared utility.
    run: async (params: {
      data: Array<{ name: string; value: number; group?: string }>;
      height: number;
      theme?: "default" | "dark";
      title?: string;
      width: number;
      outputType?: "png" | "svg" | "option";
    }) => {
      const { data, height, theme, title, width, outputType } = params;
    
      // Check if data has group field for multiple series
      const hasGroups = data.some((item) => item.group);
    
      // Collect all unique dimensions
      const dimensionSet = new Set<string>();
      for (const item of data) {
        dimensionSet.add(item.name);
      }
      const dimensions = Array.from(dimensionSet).sort();
    
      // Create radar indicator configuration
      // Calculate the maximum value for all dimensions, then use the same max value to avoid alignTicks warning
      const allValues = data.map((item) => item.value);
      const globalMaxValue = Math.max(...allValues);
      const unifiedMax = Math.ceil((globalMaxValue * 1.2) / 10) * 10;
    
      const indicator = dimensions.map((name) => ({
        name,
        max: unifiedMax,
      }));
    
      let series: Array<SeriesOption> = [];
    
      if (hasGroups) {
        // Handle multiple series data (grouped)
        const groupMap = new Map<
          string,
          Array<{ name: string; value: number }>
        >();
    
        // Group data by group field
        for (const item of data) {
          const groupName = item.group || "Default";
          if (!groupMap.has(groupName)) {
            groupMap.set(groupName, []);
          }
          const groupData = groupMap.get(groupName);
          if (groupData) {
            groupData.push({ name: item.name, value: item.value });
          }
        }
    
        // Create series data for each group
        const seriesData = Array.from(groupMap.entries()).map(
          ([groupName, groupData]) => {
            // Create a map for quick lookup
            const dataMap = new Map(groupData.map((d) => [d.name, d.value]));
    
            // Fill values for all dimensions (0 for missing data)
            const values = dimensions.map(
              (dimension) => dataMap.get(dimension) ?? 0,
            );
    
            return {
              name: groupName,
              value: values,
            };
          },
        );
    
        series = [
          {
            data: seriesData,
            type: "radar",
          },
        ];
      } else {
        // Handle single series data
        const dataMap = new Map(data.map((d) => [d.name, d.value]));
        const values = dimensions.map((dimension) => dataMap.get(dimension) ?? 0);
    
        series = [
          {
            data: [
              {
                value: values,
                name: title || "Data",
              },
            ],
            type: "radar",
          },
        ];
      }
    
      const echartsOption: EChartsOption = {
        legend: hasGroups
          ? {
              left: "center",
              orient: "horizontal",
              bottom: "5%",
            }
          : undefined,
        radar: {
          indicator,
          radius: "60%",
          splitNumber: 4,
          axisName: {
            formatter: "{value}",
            color: "#666",
          },
          splitArea: {
            areaStyle: {
              color: ["rgba(250, 250, 250, 0.3)", "rgba(200, 200, 200, 0.3)"],
            },
          },
        },
        series,
        title: {
          left: "center",
          text: title,
          top: "5%",
        },
        tooltip: {
          trigger: "item",
        },
      };
    
      return await generateChartImage(
        echartsOption,
        width,
        height,
        theme,
        outputType,
        "generate_radar_chart",
      );
    },
  • Zod schema for tool inputs, including radar data array, dimensions (height, width), theme, title, and output type.
    inputSchema: z.object({
      data: z
        .array(data)
        .describe(
          "Data for radar chart, such as, [{ name: 'Design', value: 70 }, { name: 'Performance', value: 85 }] or [{ name: 'Design', value: 70, group: 'iPhone' }].",
        )
        .nonempty({ message: "Radar chart data cannot be empty." }),
      height: HeightSchema,
      theme: ThemeSchema,
      title: TitleSchema,
      width: WidthSchema,
      outputType: OutputTypeSchema,
    }),
  • Zod schema for individual data points in the radar chart (dimension name, value, optional group for multi-series).
    const data = z.object({
      name: z.string().describe("Dimension name, such as 'Design'."),
      value: z.number().describe("Value of the dimension, such as 70."),
      group: z
        .string()
        .optional()
        .describe(
          "Group name for multiple series, used for comparing different entities",
        ),
    });
  • The generateRadarChartTool is registered by including it in the exported 'tools' array alongside other chart tools.
    export const tools = [
      generateEChartsTool,
      generateLineChartTool,
      generateBarChartTool,
      generatePieChartTool,
      generateRadarChartTool,
      generateScatterChartTool,
      generateSankeyChartTool,
      generateFunnelChartTool,
      generateGaugeChartTool,
      generateTreemapChartTool,
      generateSunburstChartTool,
      generateHeatmapChartTool,
      generateCandlestickChartTool,
      generateBoxplotChartTool,
      generateGraphChartTool,
      generateParallelChartTool,
      generateTreeChartTool,
    ];
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions generating a chart but doesn't cover key traits like whether this is a read-only operation, potential side effects (e.g., file creation), performance considerations, or error handling. The example adds context but doesn't compensate for the lack of behavioral details, making it insufficient for a mutation-like tool (chart generation).

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

Conciseness4/5

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

The description is front-loaded with the core purpose in the first sentence, followed by a helpful example. It's appropriately sized with no redundant information, though the example could be slightly more concise. Overall, it's efficient and well-structured, earning a high score for clarity without waste.

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

Completeness3/5

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

Given the complexity (6 parameters, no output schema, no annotations), the description is moderately complete. It covers the purpose and provides an example, but lacks details on behavioral aspects, output format (beyond implied chart generation), and usage distinctions from siblings. With no output schema, it should ideally hint at return values, but the example partially compensates, resulting in an adequate but incomplete picture.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents all parameters thoroughly. The description adds minimal value beyond the schema: it implies the 'data' parameter is for 'multidimensional data' and gives an example, but doesn't explain parameter interactions or semantics not covered in the schema. With high schema coverage, the baseline is 3, and the description doesn't significantly enhance understanding.

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

Purpose4/5

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

The description clearly states the tool's purpose: 'Generate a radar chart to display multidimensional data (four dimensions or more)'. It specifies the verb ('generate'), resource ('radar chart'), and scope ('multidimensional data'), and the example helps illustrate usage. However, it doesn't explicitly differentiate from sibling tools like 'generate_parallel_chart' which might also handle multidimensional data, missing full sibling distinction.

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

Usage Guidelines3/5

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

The description implies usage through the example ('evaluate Huawei and Apple phones in terms of five dimensions'), suggesting it's for comparing entities across multiple dimensions. However, it lacks explicit guidance on when to use this tool versus alternatives (e.g., 'generate_parallel_chart' for similar purposes) or any exclusions, leaving usage context somewhat inferred rather than clearly stated.

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

Related 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/hustcc/mcp-echarts'

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