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).

ClassHow to obtainRole
chart.ChartObjectws.addChartObject(name, left, top, w, h) / `ws.getChartObject(name\index)`Placement frame on the sheet. Position, size, name, visible/hidden
chart.ChartchartObject.getChart()The chart itself. Built with chartWizard(); handles type, data source, title, axes and series
chart.ChartTitlechart.getChartTitle()Chart title. setText() / getText()
chart.Axis`chart.getAxes(enums.XlAxisType.Category\Value)`Axis. Tick marks, max/min, axis title
chart.Serieschart.getSeriesCollection(index)One series. getValues() / getXValues() / getPointSize()
chart.Legendchart.getLegend()Legend. setPosition() / getPosition()

Chart-related methods on the WorkSheet side:

MethodDescription
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

Caveats

See also