When I copy a range using the below code, I expect the chart to update to reference the data within the destination, not the original.
Scenario: In the below code, a chart is bound to A1:B5, then the sheet range A1:J10 (including the chart and table) is copied to A11:J20 (targetRange.copy(sourceRange)). Values in the second table (B12:B15) are updated to 300/400/500/600.
Expected: The chart in the copied range should point to the destination table (A11:B15) and display the updated values (300–600).
Actual: The second chart still references the original table (A1:B5), so it shows the original 120/80/150/60 values (see attached screenshot: top and bottom charts identical).
Repro steps:
Run the below code in Node to generate Result.xlsx.
Open Result.xlsx and compare the two tables and charts.
Environment: Aspose.Cells for Node.js v25.12.0
Ask: When copying a range that includes a chart and table, please have the chart in the destination automatically rebind to the destination table range instead of the original, or provide guidance/workaround to achieve that behavior.
const path = require("path");
const AsposeCells = require("aspose.cells.node");
// -----------------------------------------------------------------
// 1. Initialise a new workbook and get the first worksheet
// -----------------------------------------------------------------
const workbook = new AsposeCells.Workbook(); // empty workbook
const sheet = workbook.worksheets.get(0); // first worksheet
const cells = sheet.cells;
// -----------------------------------------------------------------
// 2. Insert sample data (A1:C5)
// -----------------------------------------------------------------
/* Header row */
cells.get("A1").putValue("Category");
cells.get("B1").putValue("Value");
cells.get("C1").putValue("Notes");
/* Data rows */
const data = [
["A", 120, "First"],
["B", 80, "Second"],
["C", 150, "Third"],
["D", 60, "Fourth"],
];
for (let i = 0; i < data.length; i++) {
const row = i + 2; // Excel rows start at 1 → A2, …
cells.get(`A${row}`).putValue(data[i][0]); // Category
cells.get(`B${row}`).putValue(data[i][1]); // Value (numeric)
cells.get(`C${row}`).putValue(data[i][2]); // Notes (text)
}
// -----------------------------------------------------------------
// 3. Convert the range A1:C5 into a Table (ListObject)
// -----------------------------------------------------------------
const tableIndex = sheet.getListObjects().add("A1", "C5", true); // true → first row is header
const table = sheet.listObjects.get(tableIndex);
table.setTableStyleType(AsposeCells.TableStyleType.TableStyleMedium9);
table.setShowTotals(false); // hide totals row (optional)
// -----------------------------------------------------------------
// 4. Add a Bar‑Clustered chart that uses the Table as its data source
// -----------------------------------------------------------------
const chartIndex = sheet.charts.add(
AsposeCells.ChartType.Bar, // chart type
1,
4,
9,
10
);
const chart = sheet.getCharts().get(chartIndex);
// Bind the chart to the table range (A1:C5)
// – Category (X‑axis) → first column (Category)
// – Values → second column (Value)
chart.setChartDataRange("A1:B5", true); // whole table
// Optional visual settings
chart.title.setText("Sample Bar Chart");
chart.title.setIsVisible(true);
chart.setShowLegend(false);
const sourceRange = sheet.cells.createRange(0, 0, 10, 10);
const targetRange = sheet.cells.createRange(10, 0, 10, 10);
targetRange.copy(sourceRange);
// ------
// Update the values in the second table
// ----
const cell = sheet.cells.get(11, 1);
cell.putValue(300);
const cell2 = sheet.cells.get(12, 1);
cell2.putValue(400);
const cell3 = sheet.cells.get(13, 1);
cell3.putValue(500);
const cell4 = sheet.cells.get(14, 1);
cell4.putValue(600);
// -----------------------------------------------------------------
// 6. Save the workbook
// -----------------------------------------------------------------
const outputPath = path.join(__dirname, "Result.xlsx");
workbook.save(outputPath);
console.log(`Workbook saved to ${outputPath}`);
The copy operation only duplicates the objects – it does not rewrite the data‑source formulas that a chart uses. After targetRange.copy(sourceRange) the chart that appears in the destination still points to the original address (A1:B5). This is the current behaviour of Aspose.Cells for Node.js.
Work‑around
Identify the chart that belongs to the copied area
After the copy the workbook contains two charts. The second one can be obtained by index:
// original chart index
const srcChart = sheet.getCharts().get(chartIndex);
// chart that was copied (usually the next index)
const dstChart = sheet.getCharts().get(chartIndex + 1);
Re‑bind the chart to the new table range
// new data range for the copied table (A11:B15)
dstChart.setChartDataRange("A11:B15", true);
If you are using a ListObject (table) as the source, you can also bind the chart to the table name:
Save the workbook – the chart now reflects the values you wrote to the copied cells (300, 400, 500, 600).
What to check
Verify the Aspose.Cells for Node.js version you are using (new AsposeCells.Workbook().getVersion() or check package.json). The behaviour is the same in all released versions up to the latest, but testing with the most recent build is always recommended.
Ensure that the copied table indeed has a new index (tableIndex + 1). If you add more tables before the copy, adjust the index accordingly.
If you need the chart to be automatically re‑bound
At the moment there is no built‑in flag that updates chart references during a range copy. The only supported approach is to re‑assign the data range programmatically as shown above. We will log this as a feature request internally.
Please try the snippet and let us know:
Aspose.Cells for Node.js version you are using.
Whether the chart updates correctly after applying setChartDataRange to the copied chart.
If the issue persists, attach the generated Result.xlsx so we can reproduce it with the exact version.
Thank you, is there any better way to identify the chart that belongs to the copied area besides by index? The copied area could contain multiple charts, and there is no way to control the naming of the duplicated charts within the area
@max00000
Thank you for your feedback. Copying a range in Aspose.Cells is exactly the same as copying a range in Excel. If you manually copy a range in Excel, the copied chart data still points to the original location. Because the chart names included in the copied range are automatically generated, the copied charts can only be accessed via index.
Additionally, would you like to support automatically updating the chart data to the new range after copying?
John, thank you for your reply, that makes sense. Support for automatically updating the chart data to the new range after copying would be very helpful, as identifying the charts to update and manually updating the ranges requires quite a bit of code.
We will asses the possibility of adding the feature/enhancement that automatically refreshes/updates the chart data to the new range after it has been copied. We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.
Issue ID(s): CELLSNODEJSJAVA-85
You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.