SciChart.js JavaScript 2D Charts API > Subcharts API > Creating Re-usable Chart Groups with SubCharts
Creating Re-usable Chart Groups with SubCharts

SubCharts give a way to create re-usable multi-chart components that are managed by a single SciChartSurface instance.

For example, if in your application you are repeatedly creating groups of charts that share a single common X-Axis, and must zoom and pan together, one way you could do this is by creating three separate SciChartSurface instances (see the tutorial on Linking Multiple Charts, or, the tutorial on Synchronizing Charts in React).

Alternatively, you could create your multi-chart control using SubCharts and manage that with a single SciChartSurface. This will provide cleaner, neater code, plus also give you a performance boost, as SubCharts are faster than standard charts in multi-chart scenarios.

Creating Re-usable Chart Groups with SubCharts

Take the example from the SciChart Demo - Realtime Audio Analyzer. This has three charts arranged in two rows, where the bottom row has two columns. The chart types are Line, Mountain and Heatmap.

If this was a control you needed to instantiate more than once in your application you might consider creating a re-usable Chart Group using SubCharts.

Let's begin.

Creating the Layout

The layout is pretty simple. We want the top chart to occupy 100% of the width of the chart panel, and the bottom charts to occupy 50% of the width each. The top and bottom charts should both by 50% of the height.

To do this we will use SciChartSurface.addSubChart() and pass the position property as a rectangle with relative coordinates (see the SubCharts API and SubChart positioning pages for more details).

Here's the code to do this.

// demonstrates how to create a reusable 1x2 panel of charts using SubCharts API
async function createThreePanelChart(divElementId) {
  const {
    SciChartSurface,
    NumericAxis,
    SciChartJsNavyTheme,
    Rect,
    ZoomPanModifier,
    XyDataSeries,
    FastLineRenderableSeries,
  } = SciChart;

  // or, for npm, import { SciChartSurface, ... } from "scichart"

  // Create a parent (regular) SciChartSurface which will contain the sub-chart
  const { wasmContext, sciChartSurface } = await SciChartSurface.create(
    divElementId,
    {
      theme: new SciChartJsNavyTheme(),
    }
  );

  // Add a Sub-Charts to the main surface. This will display a rectangle showing the current zoomed in area on the parent chart

  // Top chart to occupy 100% of the width and 50% height
  const subChartTop = sciChartSurface.addSubChart({
    position: new Rect(0, 0, 1, 0.5),
    theme: new SciChartJsNavyTheme(),
    title: "Audio Chart",
    titleStyle: { fontSize: 14 },
  });

  // Bottom left chart to occupy 50% of the width and 50% height
  const subChartBottomLeft = sciChartSurface.addSubChart({
    position: new Rect(0, 0.5, 0.5, 0.5),
    theme: new SciChartJsNavyTheme(),
    title: "Frequency Chart",
    titleStyle: { fontSize: 14 },
  });

  const subChartBottomRight = sciChartSurface.addSubChart({
    position: new Rect(0.5, 0.5, 0.5, 0.5),
    theme: new SciChartJsNavyTheme(),
    title: "Spectrogram Chart",
    titleStyle: { fontSize: 14 },
  });

  // Add common axis, interactivity and some data to all charts. Customize this as needed
  [subChartTop, subChartBottomLeft, subChartBottomRight].forEach((scs) => {
    scs.xAxes.add(
      new NumericAxis(wasmContext, {
        axisTitle: "XAxis",
        axisTitleStyle: { fontSize: 12 },
      })
    );
    scs.yAxes.add(
      new NumericAxis(wasmContext, {
        axisTitle: "YAxis",
        axisTitleStyle: { fontSize: 12 },
      })
    );
    scs.chartModifiers.add(new ZoomPanModifier());

    // Add random data series
    const dataSeries = new XyDataSeries(wasmContext);
    const randomData = generateRandomData();
    dataSeries.appendRange(
      randomData.map((pt) => pt.x),
      randomData.map((pt) => pt.y)
    );

    scs.renderableSeries.add(
      new FastLineRenderableSeries(wasmContext, {
        stroke: getRandomColor(),
        strokeThickness: 2,
        dataSeries,
      })
    );
  });

  // If you return the charts to the caller, you can now configure series, data and configure them
  return {
    sciChartSurface,
    subChartTop,
    subChartBottomLeft,
    subChartBottomRight,
  };
}

createThreePanelChart("scichart-root");
// Demonstrates how to create a 1x2 panel of charts using SubCharts and the Builder API
async function builderExample(divElementId) {
  // Demonstrates how to create a line chart with SciChart.js using the Builder API
  const {
    chartBuilder,
    EAxisType,
    EThemeProviderType,
    Rect,
    EChart2DModifierType,
  } = SciChart;

  // or, for npm, import { chartBuilder, ... } from "scichart"

  const { wasmContext, sciChartSurface } = await chartBuilder.build2DChart(
    divElementId,
    {
      surface: { theme: { type: EThemeProviderType.Dark } },
      // Main chart
      subCharts: [
        {
          surface: {
            position: new Rect(0, 0, 1, 0.5),
            title: "Audio Chart",
            titleStyle: { fontSize: 14 },
            theme: { type: EThemeProviderType.Dark },
          },
          xAxes: {
            type: EAxisType.NumericAxis,
            options: { axisTitle: "XAxis", axisTitleStyle: { fontSize: 12 } },
          },
          yAxes: {
            type: EAxisType.NumericAxis,
            options: { axisTitle: "YAxis", axisTitleStyle: { fontSize: 12 } },
          },
          modifiers: [{ type: EChart2DModifierType.ZoomPan }],
        },
        {
          surface: {
            position: new Rect(0, 0.5, 0.5, 0.5),
            title: "Frequency Chart",
            titleStyle: { fontSize: 14 },
            theme: { type: EThemeProviderType.Dark },
          },
          xAxes: {
            type: EAxisType.NumericAxis,
            options: { axisTitle: "XAxis", axisTitleStyle: { fontSize: 12 } },
          },
          yAxes: {
            type: EAxisType.NumericAxis,
            options: { axisTitle: "YAxis", axisTitleStyle: { fontSize: 12 } },
          },
          modifiers: [{ type: EChart2DModifierType.ZoomPan }],
        },
        {
          surface: {
            position: new Rect(0.5, 0.5, 0.5, 0.5),
            title: "Spectrogram Chart",
            titleStyle: { fontSize: 14 },
            theme: { type: EThemeProviderType.Dark },
          },
          xAxes: {
            type: EAxisType.NumericAxis,
            options: { axisTitle: "XAxis", axisTitleStyle: { fontSize: 12 } },
          },
          yAxes: {
            type: EAxisType.NumericAxis,
            options: { axisTitle: "YAxis", axisTitleStyle: { fontSize: 12 } },
          },
          modifiers: [{ type: EChart2DModifierType.ZoomPan }],
        },
      ],
    }
  );

  return {
    sciChartSurface,
    subChartTop: sciChartSurface.subCharts.at(0),
    subChartBottomLeft: sciChartSurface.subCharts.at(1),
    subChartBottomRight: sciChartSurface.subCharts.at(2),
  };
}

This results in the following output:

<div id="scichart-root"></div>

  
body {
  margin: 0;
}
#scichart-root {
  width: 100%;
  height: 100vh;
}

  
let colorIndex = 0;
function getRandomColor() {
  return ["#274b92", "#47bde6", "#ae418d", "#e97064", "#68bcae", "#634e96"][
    colorIndex++ % 6
  ];
}

function generateRandomData(count = 100) {
  const data = [];
  for (let i = 0; i < count; i++) {
    data.push({ x: i, y: Math.random() * 100 });
  }
  return data;
}

// #region ExampleA
// demonstrates how to create a reusable 1x2 panel of charts using SubCharts API
async function createThreePanelChart(divElementId) {
  const {
    SciChartSurface,
    NumericAxis,
    SciChartJsNavyTheme,
    Rect,
    ZoomPanModifier,
    XyDataSeries,
    FastLineRenderableSeries,
  } = SciChart;

  // or, for npm, import { SciChartSurface, ... } from "scichart"

  // Create a parent (regular) SciChartSurface which will contain the sub-chart
  const { wasmContext, sciChartSurface } = await SciChartSurface.create(
    divElementId,
    {
      theme: new SciChartJsNavyTheme(),
    }
  );

  // Add a Sub-Charts to the main surface. This will display a rectangle showing the current zoomed in area on the parent chart

  // Top chart to occupy 100% of the width and 50% height
  const subChartTop = sciChartSurface.addSubChart({
    position: new Rect(0, 0, 1, 0.5),
    theme: new SciChartJsNavyTheme(),
    title: "Audio Chart",
    titleStyle: { fontSize: 14 },
  });

  // Bottom left chart to occupy 50% of the width and 50% height
  const subChartBottomLeft = sciChartSurface.addSubChart({
    position: new Rect(0, 0.5, 0.5, 0.5),
    theme: new SciChartJsNavyTheme(),
    title: "Frequency Chart",
    titleStyle: { fontSize: 14 },
  });

  const subChartBottomRight = sciChartSurface.addSubChart({
    position: new Rect(0.5, 0.5, 0.5, 0.5),
    theme: new SciChartJsNavyTheme(),
    title: "Spectrogram Chart",
    titleStyle: { fontSize: 14 },
  });

  // Add common axis, interactivity and some data to all charts. Customize this as needed
  [subChartTop, subChartBottomLeft, subChartBottomRight].forEach((scs) => {
    scs.xAxes.add(
      new NumericAxis(wasmContext, {
        axisTitle: "XAxis",
        axisTitleStyle: { fontSize: 12 },
      })
    );
    scs.yAxes.add(
      new NumericAxis(wasmContext, {
        axisTitle: "YAxis",
        axisTitleStyle: { fontSize: 12 },
      })
    );
    scs.chartModifiers.add(new ZoomPanModifier());

    // Add random data series
    const dataSeries = new XyDataSeries(wasmContext);
    const randomData = generateRandomData();
    dataSeries.appendRange(
      randomData.map((pt) => pt.x),
      randomData.map((pt) => pt.y)
    );

    scs.renderableSeries.add(
      new FastLineRenderableSeries(wasmContext, {
        stroke: getRandomColor(),
        strokeThickness: 2,
        dataSeries,
      })
    );
  });

  // If you return the charts to the caller, you can now configure series, data and configure them
  return {
    sciChartSurface,
    subChartTop,
    subChartBottomLeft,
    subChartBottomRight,
  };
}

createThreePanelChart("scichart-root");
// #endregion

// #region ExampleB
// Demonstrates how to create a 1x2 panel of charts using SubCharts and the Builder API
async function builderExample(divElementId) {
  // Demonstrates how to create a line chart with SciChart.js using the Builder API
  const {
    chartBuilder,
    EAxisType,
    EThemeProviderType,
    Rect,
    EChart2DModifierType,
  } = SciChart;

  // or, for npm, import { chartBuilder, ... } from "scichart"

  const { wasmContext, sciChartSurface } = await chartBuilder.build2DChart(
    divElementId,
    {
      surface: { theme: { type: EThemeProviderType.Dark } },
      // Main chart
      subCharts: [
        {
          surface: {
            position: new Rect(0, 0, 1, 0.5),
            title: "Audio Chart",
            titleStyle: { fontSize: 14 },
            theme: { type: EThemeProviderType.Dark },
          },
          xAxes: {
            type: EAxisType.NumericAxis,
            options: { axisTitle: "XAxis", axisTitleStyle: { fontSize: 12 } },
          },
          yAxes: {
            type: EAxisType.NumericAxis,
            options: { axisTitle: "YAxis", axisTitleStyle: { fontSize: 12 } },
          },
          modifiers: [{ type: EChart2DModifierType.ZoomPan }],
        },
        {
          surface: {
            position: new Rect(0, 0.5, 0.5, 0.5),
            title: "Frequency Chart",
            titleStyle: { fontSize: 14 },
            theme: { type: EThemeProviderType.Dark },
          },
          xAxes: {
            type: EAxisType.NumericAxis,
            options: { axisTitle: "XAxis", axisTitleStyle: { fontSize: 12 } },
          },
          yAxes: {
            type: EAxisType.NumericAxis,
            options: { axisTitle: "YAxis", axisTitleStyle: { fontSize: 12 } },
          },
          modifiers: [{ type: EChart2DModifierType.ZoomPan }],
        },
        {
          surface: {
            position: new Rect(0.5, 0.5, 0.5, 0.5),
            title: "Spectrogram Chart",
            titleStyle: { fontSize: 14 },
            theme: { type: EThemeProviderType.Dark },
          },
          xAxes: {
            type: EAxisType.NumericAxis,
            options: { axisTitle: "XAxis", axisTitleStyle: { fontSize: 12 } },
          },
          yAxes: {
            type: EAxisType.NumericAxis,
            options: { axisTitle: "YAxis", axisTitleStyle: { fontSize: 12 } },
          },
          modifiers: [{ type: EChart2DModifierType.ZoomPan }],
        },
      ],
    }
  );

  return {
    sciChartSurface,
    subChartTop: sciChartSurface.subCharts.at(0),
    subChartBottomLeft: sciChartSurface.subCharts.at(1),
    subChartBottomRight: sciChartSurface.subCharts.at(2),
  };
}
// #endregion

// Uncomment this to use the builder example //builderExample("scichart-root");

  

Code Explanation

In the above example:

This function, createThreePanelChart, demonstrates how to create a reusable 1x2 panel layout of charts using SciChart's SubCharts API. It initializes a parent chart that contains three sub-charts, each positioned within a grid layout. This setup is useful for visualizing related datasets in audio, frequency, and spectrogram analysis.

1. Importing Required Components

imports
Copy Code
const { SciChartSurface, NumericAxis, SciChartJsNavyTheme, Rect, ZoomPanModifier } = SciChart;
// or, if using NPM
import { SciChartSurface, NumericAxis, SciChartJsNavyTheme, Rect, ZoomPanModifier } from "scichart";

These are key SciChart.js components:

  • SciChartSurface → The main chart container.
  • NumericAxis → Adds numeric axes for the sub-charts.
  • SciChartJsNavyTheme → A predefined theme for styling.
  • Rect → Defines sub-chart layout positions.
  • ZoomPanModifier → Enables zoom and pan interactions.

2. Creating the Parent SciChartSurface

Create parent chart
Copy Code
const { wasmContext, sciChartSurface } = await SciChartSurface.create(
  divElementId,
  { theme: new SciChartJsNavyTheme() }
);
  • Initializes the main SciChartSurface inside the divElementId container.
  • Applies the SciChartJsNavyTheme to maintain a consistent look.
  • wasmContext provides access to WebAssembly-powered rendering.

3. Adding Sub-Charts

The function creates three sub-charts within the parent SciChartSurface, defining their position using Rect(x, y, width, height).

Top Chart (100% width, 50% height)

Adding SubChart top
Copy Code
const subChartTop = sciChartSurface.addSubChart({
  position: new Rect(0, 0, 1, 0.5),
  theme: new SciChartJsNavyTheme(),
  title: "Audio Chart",
  titleStyle: { fontSize: 14 }
});
  • Full-width, occupies the top half of the container.
  • Labeled "Audio Chart".

Bottom Left Chart (50% Width, 50% Height)

Adding SubChart BottomLeft
Copy Code
const subChartBottomLeft = sciChartSurface.addSubChart({
  position: new Rect(0, 0.5, 0.5, 0.5),
  theme: new SciChartJsNavyTheme(),
  title: "Frequency Chart",
  titleStyle: { fontSize: 14 }
});

  • Takes up half the width and sits in the bottom left.

Bottom Right Chart (50% Width, 50% Height)
Example Title
Copy Code
const subChartBottomRight = sciChartSurface.addSubChart({
  position: new Rect(0.5, 0.5, 0.5, 0.5),
  theme: new SciChartJsNavyTheme(),
  title: "Spectrogram Chart",
  titleStyle: { fontSize: 14 }
});

Placed beside the bottom left chart.

4. Adding Axes and Interaction Controls

Adding Axis, Interaction
Copy Code
[subChartTop, subChartBottomLeft, subChartBottomRight].forEach(scs => {
  scs.xAxes.add(new NumericAxis(wasmContext, {
    axisTitle: "XAxis",
    axisTitleStyle: { fontSize: 12 }
  }));
  scs.yAxes.add(new NumericAxis(wasmContext, {
    axisTitle: "YAxis",
    axisTitleStyle: { fontSize: 12 }
  }));
  scs.chartModifiers.add(new ZoomPanModifier());
});

Loops through all sub-charts to:

  • Add numeric X and Y axes with labels.
  • Attach a ZoomPanModifier for interactive zooming and panning.

5. Returning the Created Chart

Returning Charts
Copy Code
return {
  sciChartSurface,
  subChartTop,
  subChartBottomLeft,
  subChartBottomRight
};

Finally, we return all the instances to allow further customization, such as adding data series, modifying or styling behaviour. For example:

Example Title
Copy Code
const {
   sciChartSurface,
   subChartTop,
   subChartBottomLeft,
   subChartBottomRight
} = await createThreePanelChart("chartDiv");
// Example: Add a line series to the top chart
const wasmContext = sciChartSurface.webAssemblyContext2D;
subChartTop.renderableSeries.add(new FastLineRenderableSeries(wasmContext, { stroke: "blue", dataSeries ... }));