V

Vuer-Viz

vuer-vizv1.2.14

Publication-Quality Visualizations

Bar Chart Examples

Publication-quality bar charts with support for vertical and horizontal orientations.

Type Interface

import type { BaseChartProps, ChartChangeEvent, Formatter, Margin } from '../../types';

/** BarChart margin: left is optional and will be auto-computed from label widths when omitted. */
export type BarChartMargin = Omit<Margin, 'left'> & { left?: number };

/**
 * Columnar data for bar charts, just data no styling.
 */
export interface BarData {
  /** Bar labels (x-axis for vertical, y-axis for horizontal) */
  label: string[];
  /** Bar values (heights for vertical, widths for horizontal) */
  value: number[];
  /** Optional colors for each bar (falls back to barColor or default palette) */
  color?: string[];
}

export interface BarChartProps extends BarData, Omit<BaseChartProps, "legendFontSize" | "margin"> {
  /** Margin around the plot area. left is optional and auto-computed from label widths when omitted. */
  margin?: BarChartMargin;
  /** X-axis label */
  xLabel?: string;
  /** Y-axis label */
  yLabel?: string;
  /** Chart title */
  title?: string;
  /** Show grid lines */
  grid?: boolean;
  /** Grid line color */
  gridColor?: string;
  /** Bar orientation */
  orientation?: 'vertical' | 'horizontal';
  /** Default color for all bars (overridden by colors array) */
  barColor?: string;
  /** Bar width as fraction of available space (0-1) */
  barWidth?: number;
  /** Show value labels on bars */
  showLabels?: boolean;
  /** Minimum Y value */
  yMin?: number;
  /** Maximum Y value */
  yMax?: number;
  /** Use canvas rendering instead of SVG */
  canvas?: boolean;
  /** Custom X-axis formatter */
  xFormat?: Formatter;
  /** Custom Y-axis formatter */
  yFormat?: Formatter;
  /** Callback for bar interactions */
  onChange?: (event: ChartChangeEvent) => void;
  /** Currently selected bar indices */
  selectedIndices?: number[];
  /** Callback when selection changes */
  onSelectionChange?: (selectedIndices: number[]) => void;
  /** Allow multiple selections (default: true) */
  multiSelect?: boolean;
  /** Custom overlays and children */
  children?: React.ReactNode;
}

Vertical Bar Chart

A simple vertical bar chart with grid lines.

Sample Data00.20.40.60.81ABCDECategoriesValues
import { BarChart } from '@vuer-ai/vuer-viz';

export default function VerticalBarExample() {
  return (
    <BarChart
      label={['A', 'B', 'C', 'D', 'E']}
      value={[23, 45, 12, 67, 34]}
      width={700}
      height={300}
      title="Sample Data"
      xLabel="Categories"
      yLabel="Values"
      grid
    />
  );
}

Horizontal Bar Chart

A horizontal bar chart with values displayed. The left margin is computed automatically from the category label lengths, so you rarely need to set it manually.

Language Popularity00.20.40.60.818572684556PythonJavaScriptTypeScriptRustGoScoreLanguage
import { BarChart } from '@vuer-ai/vuer-viz';

export default function HorizontalBarExample() {
  return (
    <BarChart
      label={['Python', 'JavaScript', 'TypeScript', 'Rust', 'Go']}
      value={[85, 72, 68, 45, 56]}
      width={700}
      height={300}
      title="Language Popularity"
      xLabel="Score"
      yLabel="Language"
      orientation="horizontal"
      grid
      showLabels={true}
    />
  );
}

Custom Colors with Values

Bar chart with custom colors per bar.

Quarterly Revenue00.20.40.60.8112014598178Q1Q2Q3Q4QuarterRevenue ($K)
import { BarChart } from '@vuer-ai/vuer-viz';

export default function ColoredBarExample() {
  return (
    <BarChart
      label={['Q1', 'Q2', 'Q3', 'Q4']}
      value={[120, 145, 98, 178]}
      color={['#0000ff', '#00ff00', '#ff0000', '#ffff00']}
      width={700}
      height={300}
      title="Quarterly Revenue"
      xLabel="Quarter"
      yLabel="Revenue ($K)"
      grid
      showLabels={true}
    />
  );
}

Layout & Spacing

Bar charts support flexible layout customization through margin and padding props:

  • padding: Uniform spacing on all sides (shorthand)
  • margin: Fine-grained control with { top, right, bottom, left }
// Uniform padding
<BarChart padding={30} label={['A', 'B']} value={[10, 20]} />

// Custom margins per side
<BarChart
  margin={{ top: 20, right: 40, bottom: 50, left: 60 }}
  label={['A', 'B']}
  value={[10, 20]}
/>

The priority order is: margin prop → padding prop → default margin with auto left.

Default margin: { top: 40, right: 20, bottom: 50, left: auto }

BarChart computes the left margin automatically from actual label widths, so you rarely need to set it manually:

  • Vertical orientation: derived from the widest y-tick label
  • Horizontal orientation: derived from the longest category label string

left is optional in BarChartMargin. Omit it and the chart measures the widest label to set the margin automatically. Provide an explicit left to override auto-computation.

When padding is set (and no margin prop is provided), it replaces all four sides with a single uniform value, bypassing the auto left-margin. If your chart has xLabel or yLabel, a small padding value will clip the axis labels — use margin for fine-grained control in those cases.

Default Margin

Framework Usage00.20.40.60.81ReactVueAngularSvelteSolidPercentage

Compact(padding=50)

Framework Usage00.20.40.60.81ReactVueAngularSvelteSolidPercentage

Custom Margin(top: 30, right: 10, bottom: 60, left: 80)

Framework Usage00.20.40.60.81ReactVueAngularSvelteSolidFrameworkPercentage (%)
import { BarChart } from '@vuer-ai/vuer-viz';

export default function CustomPaddingExample() {
  const data = {
    label: ['React', 'Vue', 'Angular', 'Svelte', 'Solid'],
    value: [42, 28, 21, 12, 8],
  };

  return (
    <div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap' }}>
      <div>
        <h3 style={{ fontSize: '14px', marginBottom: '10px' }}>Default Margin</h3>
        <BarChart
          {...data}
          width={350}
          height={200}
          title="Framework Usage"
          yLabel="Percentage"
          grid={true}
        />
      </div>

      <div>
        <h3 style={{ fontSize: '14px', marginBottom: '10px' }}>Compact(padding=50)</h3>
        <BarChart
          {...data}
          width={350}
          height={200}
          padding={50}
          title="Framework Usage"
          yLabel="Percentage"
          grid={true}
        />
      </div>

      <div>
        <h3 style={{ fontSize: '14px', marginBottom: '10px' }}>Custom Margin(top: 30, right: 10, bottom: 60, left: 80)</h3>
        <BarChart
          {...data}
          width={350}
          height={200}
          margin={{ top: 30, right: 10, bottom: 60, left: 80 }}
          title="Framework Usage"
          yLabel="Percentage (%)"
          xLabel="Framework"
          grid={true}
        />
      </div>
    </div>
  );
}

Event Handling & Selection API

BarChart supports interactive selection, allowing users to click bars to select/deselect them. This is useful for building data exploration interfaces where users can inspect details of specific bars.

Basic Selection

import { useState } from 'react';
import { BarChart } from '@vuer-ai/vuer-viz';

function MyChart() {
  const [selectedIndices, setSelectedIndices] = useState<number[]>([]);

  return (
    <BarChart
      label={['Q1', 'Q2', 'Q3', 'Q4']}
      value={[120, 145, 98, 178]}
      selectedIndices={selectedIndices}
      onSelectionChange={setSelectedIndices}
      multiSelect={true} // Allow multiple selections (default)
    />
  );
}

Selection Behavior

  • Visual Feedback: Selected bars maintain full opacity while unselected bars fade to 30% opacity
  • Click to Toggle: Click a bar to select it; click again to deselect
  • Multi-select Mode: When multiSelect={true} (default), you can select multiple bars
  • Single-select Mode: When multiSelect={false}, only one bar can be selected at a time
  • Stroke Highlight: Selected bars show a 2px stroke outline for clear visual indication

Programmatic Control

You can programmatically control selections:

// Select specific bars
setSelectedIndices([0, 2, 4]);

// Clear all selections
setSelectedIndices([]);

// Select all bars
setSelectedIndices(labels.map((_, i) => i));

// Select top N by value
const selectTopN = (n: number) => {
  const sorted = values
    .map((val, i) => ({ index: i, value: val }))
    .sort((a, b) => b.value - a.value)
    .slice(0, n)
    .map(item => item.index);
  setSelectedIndices(sorted);
};

Selection with Table Example

Interactive bar chart with a table showing selected items. Click bars to select/deselect them and view details in the table below.

Product Sales (Click bars to select)00.20.40.60.81LaptopsPhonesTabletsMonitorsKeyboardsMiceHeadphonesProductSales ($K)

Selected Products (0)

ProductSales ($K)
this table is empty
import { BarChart } from '@vuer-ai/vuer-viz';
import { useState } from 'react';

// Sample product sales data
const productData = {
  label: ['Laptops', 'Phones', 'Tablets', 'Monitors', 'Keyboards', 'Mice', 'Headphones'],
  value: [2450, 3890, 1560, 980, 650, 420, 1120],
  color: ['#0000ff', '#00ff00', '#ff0000', '#ffff00', '#ff00ff', '#00ffff', '#ff8800'],
};

export default function SelectionWithTableExample() {
  const [selectedIndices, setSelectedIndices] = useState<number[]>([]);

  // Get selected products
  const selectedProducts = selectedIndices.map(i => ({
    label: productData.label[i],
    value: productData.value[i],
    color: productData.color[i],
  }));

  return (
    <div className="space-y-6">
      {/* Bar Chart */}
      <div>
        <BarChart
          label={productData.label}
          value={productData.value}
          color={productData.color}
          width={700}
          height={300}
          margin={{ top: 40, right: 20, bottom: 50, left: 80 }}
          title="Product Sales (Click bars to select)"
          xLabel="Product"
          yLabel="Sales ($K)"
          grid
          selectedIndices={selectedIndices}
          onSelectionChange={setSelectedIndices}
          multiSelect={true}
        />
      </div>

      {/* Selected Products Table */}
      <div>
        <h3 className="text-lg font-semibold mb-3">
          Selected Products ({selectedProducts.length})
        </h3>

        <div className="overflow-x-auto">
          <table className="min-w-full border border-gray-300 dark:border-gray-700">
            <thead className="bg-gray-100 dark:bg-gray-800">
              <tr>
                <th className="px-4 py-2 text-left border-b border-gray-300 dark:border-gray-700">
                  Product
                </th>
                <th className="px-4 py-2 text-left border-b border-gray-300 dark:border-gray-700">
                  Sales ($K)
                </th>
              </tr>
            </thead>
            <tbody>
              {selectedProducts.length === 0 ? (
                <tr>
                  <td
                    colSpan={2}
                    className="px-4 py-8 text-center text-gray-400 dark:text-gray-600 italic"
                  >
                    this table is empty
                  </td>
                </tr>
              ) : (
                selectedProducts.map((product, idx) => (
                  <tr
                    key={product.label}
                    className={idx % 2 === 0 ? 'bg-white dark:bg-gray-900' : 'bg-gray-50 dark:bg-gray-800'}
                  >
                    <td className="px-4 py-2 border-b border-gray-200 dark:border-gray-700 font-mono">
                      <span
                        className="inline-block w-3 h-3 rounded-full mr-2"
                        style={{ backgroundColor: product.color }}
                      />
                      {product.label}
                    </td>
                    <td className="px-4 py-2 border-b border-gray-200 dark:border-gray-700 font-semibold">
                      ${product.value.toLocaleString()}
                    </td>
                  </tr>
                ))
              )}
            </tbody>
          </table>
        </div>
      </div>

      {/* Controls */}
      <div className="flex gap-3 text-sm">
        <button
          onClick={() => setSelectedIndices([])}
          className="px-3 py-1.5 bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 rounded"
          disabled={selectedProducts.length === 0}
        >
          Clear Selection
        </button>
        <button
          onClick={() => setSelectedIndices(productData.label.map((_, i) => i))}
          className="px-3 py-1.5 bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 rounded"
        >
          Select All
        </button>
        <button
          onClick={() => {
            // Select top 3 by sales
            const sorted = productData.value
              .map((val, i) => ({ index: i, value: val }))
              .sort((a, b) => b.value - a.value)
              .slice(0, 3)
              .map(item => item.index);
            setSelectedIndices(sorted);
          }}
          className="px-3 py-1.5 bg-blue-500 hover:bg-blue-600 text-white rounded"
        >
          Select Top 3
        </button>
      </div>
    </div>
  );
}

← Back to all charts