V

Vuer-Viz

vuer-vizv1.0.2

Publication-Quality Visualizations

Bar Chart Examples

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

Type Interface

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

/**
 * 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"> {
  /** 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;
}

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 }

Examples

// 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 padding prop provides a convenient shorthand for setting equal margins on all sides, while margin allows precise control over each side individually. When both are provided, margin takes precedence.

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

Default Margin

Framework Usage00.20.40.60.81ReactVueAngularSvelteSolidPercentage

Compact (padding=20)

Framework Usage00.20.40.60.81ReactVueAngularSvelteSolidPercentage

Custom Margin

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={250}
          height={200}
          title="Framework Usage"
          yLabel="Percentage"
          grid={true}
        />
      </div>

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

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

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]}
      title="Sample Data"
      xLabel="Categories"
      yLabel="Values"
      grid
    />
  );
}

Horizontal Bar Chart

A horizontal bar chart with values displayed.

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]}
      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']}
      title="Quarterly Revenue"
      xLabel="Quarter"
      yLabel="Revenue ($K)"
      grid
      showLabels={true}
    />
  );
}

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}
          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