Skip to main content
Glama

create_histogram

Generate ASCII histograms to visualize frequency distributions of numeric data in terminal environments, enabling quick data analysis without GUI dependencies.

Instructions

Create ASCII histograms for frequency distribution

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
dataYesArray of numeric values for distribution
titleNoOptional chart title
widthNoChart width (10-200, default: 60)
heightNoChart height (5-50, default: 15)
colorNoANSI color name
binsNoNumber of histogram bins (default: 10)

Implementation Reference

  • Main handler function executing the core logic for generating ASCII histogram charts from numeric data, including bin calculation, ASCII grid rendering with bars, axes, labels, and summary statistics.
    export function createHistogram(data: ChartData, options: HistogramOptions = {}): ChartResult { const { data: values, title, width = 60, height = 15, color = 'white' } = data; const { bins = 10, showFrequency = true } = options; if (values.length === 0) { throw new Error('Data array cannot be empty'); } // Calculate histogram bins const histogramBins = calculateHistogramBins(values, bins); const maxCount = Math.max(...histogramBins.map(bin => bin.count)); const chartWidth = width - 12; // Reserve space for y-axis labels const chartHeight = height - 3; // Reserve space for x-axis and title // Create the chart grid const grid = createGrid(width, height); // Draw y-axis labels (counts or frequencies) for (let y = 0; y < chartHeight; y++) { const value = maxCount - (y / (chartHeight - 1)) * maxCount; const label = showFrequency ? ((value / values.length) * 100).toFixed(1) + '%' : Math.round(value).toString(); const labelStr = padLeft(label, 10); // Place y-axis label for (let i = 0; i < Math.min(labelStr.length, 10); i++) { if (10 - i < width) { grid[y][10 - i] = labelStr[i]; } } // Draw y-axis line if (11 < width) { grid[y][11] = y === chartHeight - 1 ? ASCII_CHARS.bottomLeft : y === 0 ? ASCII_CHARS.topLeft : ASCII_CHARS.teeRight; } // Draw horizontal grid lines for (let x = 12; x < width; x++) { if (y === chartHeight - 1) { grid[y][x] = ASCII_CHARS.horizontal; } else if (y % 2 === 0) { grid[y][x] = '·'; // Light grid dots } } } // Draw histogram bars const barWidth = Math.max(1, Math.floor(chartWidth / histogramBins.length)); for (let i = 0; i < histogramBins.length; i++) { const bin = histogramBins[i]; const barStartX = 12 + Math.floor(i * chartWidth / histogramBins.length); const normalizedCount = maxCount === 0 ? 0 : normalize(bin.count, 0, maxCount); const barHeight = Math.floor(normalizedCount * chartHeight); // Draw bar from bottom up for (let y = 0; y < barHeight; y++) { const gridY = chartHeight - 1 - y; if (gridY >= 0 && gridY < chartHeight) { for (let x = 0; x < barWidth && barStartX + x < width; x++) { grid[gridY][barStartX + x] = ASCII_CHARS.fullBlock; } } } // Add count/frequency on top of bar if space allows if (barHeight < chartHeight - 1) { const valueStr = showFrequency ? ((bin.count / values.length) * 100).toFixed(0) : bin.count.toString(); const valueY = chartHeight - barHeight - 1; if (valueY >= 0 && valueY < chartHeight) { for (let j = 0; j < valueStr.length && barStartX + j < width; j++) { grid[valueY][barStartX + j] = valueStr[j]; } } } } // Draw x-axis labels (bin ranges) for (let i = 0; i < Math.min(histogramBins.length, 6); i++) { // Limit labels to avoid crowding const bin = histogramBins[i]; const barStartX = 12 + Math.floor(i * chartWidth / histogramBins.length); const labelY = height - 1; // Create range label const rangeLabel = `${bin.min.toFixed(1)}-${bin.max.toFixed(1)}`; const label = rangeLabel.substring(0, Math.min(rangeLabel.length, barWidth + 2)); if (labelY >= 0) { for (let j = 0; j < label.length && barStartX + j < width; j++) { grid[labelY][barStartX + j] = label[j]; } } } // Convert grid to string and apply coloring let chart = gridToString(grid); if (color !== 'white') { chart = colorize(chart, color); } // Add title and statistics let result = ''; if (title) { result += center(title, width) + '\n'; } result += chart; // Add summary statistics const mean = values.reduce((a, b) => a + b, 0) / values.length; const sortedValues = [...values].sort((a, b) => a - b); const median = sortedValues.length % 2 === 0 ? (sortedValues[sortedValues.length / 2 - 1] + sortedValues[sortedValues.length / 2]) / 2 : sortedValues[Math.floor(sortedValues.length / 2)]; const statsLine = `n=${values.length}, μ=${mean.toFixed(2)}, median=${median.toFixed(2)}`; result += '\n' + center(statsLine, width); return { chart: result, title, dimensions: { width, height: height + 1 } // Account for stats line }; }
  • MCP tool schema definition including input validation schema with properties for data, title, dimensions, color, and bins; registered in ListTools response.
    name: 'create_histogram', description: 'Create ASCII histograms for frequency distribution', inputSchema: { type: 'object', properties: { data: { type: 'array', items: { type: 'number' }, description: 'Array of numeric values for distribution' }, title: { type: 'string', description: 'Optional chart title', optional: true }, width: { type: 'number', description: 'Chart width (10-200, default: 60)', optional: true }, height: { type: 'number', description: 'Chart height (5-50, default: 15)', optional: true }, color: { type: 'string', description: 'ANSI color name', optional: true }, bins: { type: 'number', description: 'Number of histogram bins (default: 10)', minimum: 3, maximum: 50, optional: true } }, required: ['data'], examples: getToolExamples('create_histogram') }
  • src/index.ts:367-375 (registration)
    Tool registration in the generateChart switch statement, dispatching calls to the createHistogram handler with parsed parameters.
    case 'create_histogram': { progress.nextStep('Generating histogram'); const bins = params.bins || 10; result = await withRequestTracking( () => Promise.resolve(createHistogram(chartData, { bins })), 'create_histogram' )(); break; }
  • Helper function to compute histogram bins from input data values, used by the main handler.
    function calculateHistogramBins(values: number[], numBins: number): HistogramBin[] { const minValue = Math.min(...values); const maxValue = Math.max(...values); const range = maxValue - minValue; const binWidth = range / numBins; const bins: HistogramBin[] = []; // Create bins for (let i = 0; i < numBins; i++) { const min = minValue + i * binWidth; const max = i === numBins - 1 ? maxValue : minValue + (i + 1) * binWidth; bins.push({ min, max, count: 0, frequency: 0 }); } // Count values in each bin for (const value of values) { for (let i = 0; i < bins.length; i++) { const bin = bins[i]; if (value >= bin.min && (value <= bin.max || (i === bins.length - 1 && value === bin.max))) { bin.count++; break; } } } // Calculate frequencies for (const bin of bins) { bin.frequency = bin.count / values.length; } return bins; }
  • Example inputs for the create_histogram tool, used in tool registration for documentation.
    create_histogram: { distribution: { data: [1, 2, 2, 3, 3, 3, 4, 4, 5, 6, 6, 7, 8, 9], title: "Value Distribution", bins: 5 }, performance: { data: [85, 87, 90, 92, 88, 91, 89, 93, 86, 94, 88, 90, 92], title: "Performance Scores", bins: 8, color: "yellow" }, large_dataset: { data: Array.from({length: 100}, () => Math.random() * 100), title: "Random Data Distribution", bins: 12, width: 70, height: 20 } },

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/gianlucamazza/mcp-ascii-charts'

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