Charts (graphs) basics — add, title, type, reading back series/axes, delete
level: intermediate / verified: 2026-10-01 / tabs: Node.js・Python・Java・WebAssembly / 日本語
What you want to do
Create charts (graphs) from a data table on a worksheet. Build two kinds — a clustered column chart and a line chart — set their titles, legend and axes, and read the results back as properties to verify them. Finally, delete a chart.
A chart's appearance cannot be checked from the console, so this sample prints the type, title string, series values, axis settings and chart count with console.log, letting you programmatically confirm that everything was built as intended.
Classes involved
Charts are split into two layers: the "frame" (ChartObject) and the "content" (Chart).
| Class | How to obtain | Role | |
|---|---|---|---|
chart.ChartObject | ws.addChartObject(name, left, top, w, h) / `ws.getChartObject(name\ | index)` | Placement frame on the sheet. Position, size, name, visible/hidden |
chart.Chart | chartObject.getChart() | The chart itself. Built with chartWizard(); handles type, data source, title, axes and series | |
chart.ChartTitle | chart.getChartTitle() | Chart title. setText() / getText() | |
chart.Axis | `chart.getAxes(enums.XlAxisType.Category\ | Value)` | Axis. Tick marks, max/min, axis title |
chart.Series | chart.getSeriesCollection(index) | One series. getValues() / getXValues() / getPointSize() | |
chart.Legend | chart.getLegend() | Legend. setPosition() / getPosition() |
Chart-related methods on the WorkSheet side:
| Method | Description |
|---|---|
addChartObject(name, left, top, width, height) | Adds a chart frame. Position and size are in points (pt) |
getChartObject(name) / getChartObject(index) | Gets by name or index (1-based). Out of range throws |
deleteChartObject(name) / deleteChartObject(index) | Deletes by name or index |
Code
Output:
// charts.js — charts (graphs) basics: add, title, type, reading back series/axes, delete
const { nodeosbxl, enums } = require("nodeosbxl");
const app = new nodeosbxl.App();
const wb = app.createWorkBook("charts.xlsx");
const ws = wb.openWorkSheet("Sheet1");
// Helper: chart type numeric code -> enum name
const chartTypeName = (code) =>
Object.keys(enums.XlChartType).find((k) => enums.XlChartType[k] === code) || String(code);
// Helper: number of charts on the sheet (getChartObject throws out of range -> count until it does)
const countCharts = () => {
let n = 0;
for (;;) { try { ws.getChartObject(n + 1); n++; } catch (e) { break; } }
return n;
};
// Helper: number of series in a chart (getSeriesCollection throws out of range)
const countSeries = (chart) => {
let n = 0;
for (;;) { try { chart.getSeriesCollection(n + 1); n++; } catch (e) { break; } }
return n;
};
// ---------- 1. Build the data table (monthly sales of 2 products) ----------
["Month", "Product A", "Product B"].forEach((h, c) => ws.getCells(1, c + 1).setValue(h));
const sales = [
["Jan", 120, 90], ["Feb", 135, 95], ["Mar", 150, 110],
["Apr", 142, 125], ["May", 160, 118], ["Jun", 175, 130],
];
sales.forEach((row, i) => {
ws.getCells(i + 2, 1).setValue(row[0]);
ws.getCells(i + 2, 2).setNumberValue(row[1]);
ws.getCells(i + 2, 3).setNumberValue(row[2]);
});
console.log("[1] Created data table A1:C7 / Product A total =",
sales.reduce((s, r) => s + r[1], 0));
// ---------- 2. Add a clustered column chart (chartWizard) ----------
// addChartObject(name, left, top, width, height) — position and size are in points (pt)
const co1 = ws.addChartObject("SalesColumn", 320, 10, 360, 220);
const chart1 = co1.getChart();
// chartWizard(source, type, plotBy, seriesLabelLines, categoryLabelLines,
// styleNo, colorNo, hasLegend, title)
chart1.chartWizard(
"Sheet1!A1:C7",
enums.XlChartType.ChartTypeColumnClustered,
enums.XlRowCol.Columns, // take series by column (Product A / Product B, one series each)
1, // seriesLabelLines: first 1 row is the series-name header
1, // categoryLabelLines: first 1 column is the category-name header
1, // chartStyleNo (1-based)
enums.XlChartColorPalette.XlPaletteColorful1,
true, // hasLegend: show the legend
"Monthly Sales" // title: setting this displays the title
);
console.log("[2] type =", chartTypeName(chart1.getChartType()),
"/ hasTitle =", chart1.hasTitle(),
"/ title =", JSON.stringify(chart1.getChartTitle().getText()));
console.log(" data source =", chart1.getDataSource(),
"/ plotBy =", chart1.getPlotBy(),
"/ hasLegend =", chart1.hasLegend());
// ---------- 3. Read back series and axes ----------
// There is no API that returns the series name directly. Series names come from the
// chartWizard header row, so count them with getSeriesCollection and match each one
// to its header cell.
const n1 = countSeries(chart1);
console.log("[3] series count =", n1);
for (let i = 1; i <= n1; i++) {
const s = chart1.getSeriesCollection(i);
const name = Object.values(ws.getCells(1, i + 1).getValue())[0]; // series i -> header of column i+1
console.log(` series ${i} "${name}" values =`, JSON.stringify(s.getValues()),
"/ point count =", s.getPointSize());
}
console.log(" category names =",
JSON.stringify(chart1.getAxes(enums.XlAxisType.Category).getCategoryNames()));
// ---------- 4. Second chart (line with markers) + axis/legend settings ----------
const co2 = ws.addChartObject("SalesLine", 320, 250, 360, 220);
const chart2 = co2.getChart();
chart2.chartWizard(
"Sheet1!A1:C7",
enums.XlChartType.ChartTypeLineMarkers,
enums.XlRowCol.Columns, 1, 1,
1, enums.XlChartColorPalette.XlPaletteColorful1, true); // without hasLegend=true, getLegend() throws
// The title can also be set via setTitle(true) -> getChartTitle().setText()
chart2.setTitle(true);
chart2.getChartTitle().setText("Monthly Sales Trend");
// Value axis: fix max/min/major unit (read back with getMajorUnit and the ...IsAuto family)
const valAxis = chart2.getAxes(enums.XlAxisType.Value);
valAxis.setMaximumScale(200);
valAxis.setMinimumScale(0);
valAxis.setMajorUnit(50);
valAxis.setTitle(true);
valAxis.getTitle().setText("Sales (10K JPY)");
// Move the legend to the right
chart2.getLegend().setPosition(enums.XlLegendPosition.LegendPositionRight);
console.log("[4] type =", chartTypeName(chart2.getChartType()),
"/ title =", JSON.stringify(chart2.getChartTitle().getText()));
console.log(" value axis major unit =", valAxis.getMajorUnit(),
"/ max auto =", valAxis.getMaximumScaleIsAuto(),
"/ min auto =", valAxis.getMinimumScaleIsAuto());
console.log(" value axis title =", JSON.stringify(valAxis.getTitle().getText()),
"/ legend position =", chart2.getLegend().getPosition(),
`(Right=${enums.XlLegendPosition.LegendPositionRight})`);
// ---------- 5. Read back chart count, position and size ----------
console.log("[5] chart count =", countCharts(),
"/ SalesColumn(left,top,width,height) =",
[co1.getLeft(), co1.getTop(), co1.getWidth(), co1.getHeight()].join(","));
// ---------- 6. Delete a chart ----------
ws.deleteChartObject("SalesLine"); // by name; deleteChartObject(2) by index (1-based) also works
console.log("[Done] Chart count after delete =", countCharts(),
"/ remaining =", ws.getChartObject(1).getName());
wb.save();
wb.close();
[1] Created data table A1:C7 / Product A total = 882
[2] type = ChartTypeColumnClustered / hasTitle = true / title = "Monthly Sales"
data source = Sheet1!$A$1:$C$7 / plotBy = 2 / hasLegend = true
[3] series count = 2
series 1 "Product A" values = ["120","135","150","142","160","175"] / point count = 6
series 2 "Product B" values = ["90","95","110","125","118","130"] / point count = 6
category names = ["Jan","Feb","Mar","Apr","May","Jun"]
[4] type = ChartTypeLineMarkers / title = "Monthly Sales Trend"
value axis major unit = 50 / max auto = false / min auto = false
value axis title = "Sales (10K JPY)" / legend position = 4 (Right=4)
[5] chart count = 2 / SalesColumn(left,top,width,height) = 320,10,360,220
[Done] Chart count after delete = 1 / remaining = SalesColumn
Notes
- Creation is a two-step process: build the frame with
addChartObject(), then the content withgetChart().chartWizard().addChartObject(name, left, top, width, height)only returns the placement frame (ChartObject); at that point the chart is not built yet. Only after callingchartWizard()on theChartobtained viachartObject.getChart()are the type and data set.
Position and size are in points (pt). - The argument order of
chartWizard()differs from Excel macros — be careful. The signature ischartWizard(source, chartType, plotBy, seriesLabelLines, categoryLabelLines, styleNo?, colorNo?, hasLegend?, title?, ...).sourceis an A1C1-style string like"Sheet1!A1:C7",seriesLabelLines=1means "the first row holds series names" andcategoryLabelLines=1means "the first column holds category names". plotByis "which direction series are taken from". In a table like the one above — months in rows, products in columns (B/C) — passingenums.XlRowCol.Columns(=2) gives one series per column (Product A, Product B); the sample confirms 2 series.- The title can be set in two ways. Either pass a string as the
titleargument ofchartWizard()(which makeshasTitle()returntrue), or callchart.setTitle(true)→chart.getChartTitle().setText("..."). Both can be read back withgetChartTitle().getText(). - Axes are obtained with
getAxes(enums.XlAxisType.Category|Value). Set the value axis max/min withsetMaximumScale()/setMinimumScale()and the tick interval withsetMajorUnit(). The axis title isaxis.setTitle(true)→axis.getTitle().setText(). - Series values can be read back with
getSeriesCollection(i).getValues()/getXValues()(both string arrays). There is no API that returns the series count itself, so the sample counts untilgetSeriesCollection()throws.
Caveats
- A chart's appearance (colors, the actual legend rendering, line shapes, etc.) cannot be verified from the console. This sample confirms correctness by reading properties back — type, title string, series values, axis settings, count. Always open
charts.xlsxin Excel to visually check the final appearance. setChartType()/setDataSource()on an unbuilt chart throws. Trying to set the type or data source on a chart right afteraddChartObject()(beforechartWizard()) raises achart is not builtexception (it does not segfault). Always build the chart withchartWizard()first.
Invalid chart type values (-2,0, out of range) are also rejected with achartType is invalidexception.getLegend()only works on charts whose legend is enabled. On a chart without a legend it throwslegend not found. There are two ways to enable it: passchartWizard(…, hasLegend=true, …)at build time, or callchart.setLegend(true)afterwards (verified: aftersetLegend(true)bothgetLegend()andsetPosition()work;setLegend(false)makes it throw again).- There are no getters for the value axis max/min. There is no
getMaximumScale()/getMinimumScale()counterpart tosetMaximumScale()/setMinimumScale(); you can only check "is it automatic" viagetMaximumScaleIsAuto()/getMinimumScaleIsAuto()(boolean), which returnfalseafter manual settings.
The major unit can be read back withgetMajorUnit(). - There is no API that returns series names (legend entry names).
Serieshas nogetName()equivalent andLegendEntryhas no text getter, so the sample reads the series names from the source table's header cells (B1/C1) and matches them up. getValues()returns numeric cells as numeric strings and string cells as empty strings""(verified). Chart series values are expected to be numbers, so cells containing only strings come back as"". Feed series data in as numbers withsetNumberValue().- There is no API that returns the chart count, and
ws.getShapes().getCount()cannot be used (typeofisundefined). You must countgetChartObject(1), getChartObject(2), ...until they throw (the sample'scountCharts()). - Optional arguments of
chartWizard()cannot be skipped in the middle. If you want to passtitleorhasLegend, you must also give values for the precedingstyleNo/colorNo(passingundefined/nullin a middle position throws). - Some chart types are unsupported.
enums.XlChartType.ChartTypeRegionMapraises anunsupportedexception inchartWizard().
See also
- Index
- Previous: Conditional formatting / Next: Pivot tables
- Building a Table with Values and Formulas (creating chart source data) / Bulk input of large data
- API reference: ChartObject / Chart / ChartTitle / Axis / Series / Legend / XlChartType / XlRowCol / XlAxisType / XlLegendPosition