Skip to content

Convert Plotly to VTK.js and remove dist folder#64

Closed
sridhar-mani wants to merge 24 commits intomainfrom
vtkjs
Closed

Convert Plotly to VTK.js and remove dist folder#64
sridhar-mani wants to merge 24 commits intomainfrom
vtkjs

Conversation

@sridhar-mani
Copy link
Collaborator

This pull request updates FEAScript’s visualization functionality to use vtk.js for scientific rendering instead of Plotly, and reorganizes the visualization exports. It also updates the documentation and dependencies to reflect this change.

Visualization library migration:

  • Replaced Plotly with vtk.js for interactive scientific rendering in both the documentation (README.md) and the package dependencies (package.json). [1] [2]
  • Updated the installation instructions and peer dependencies to use @kitware/vtk.js instead of plotly.js. [1] [2]

Codebase reorganization:

  • Changed visualization-related exports in src/index.js to use the new vtkSolutionScript.js module, adding new exports for color scales, contour line options, and various data transformation utilities for vtk.js.

Copilot AI review requested due to automatic review settings March 9, 2026 10:20
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates FEAScript’s visualization layer from Plotly-based plotting to vtk.js-based scientific rendering, while also reorganizing and expanding the public visualization exports and removing committed build artifacts from dist/.

Changes:

  • Replaced the Plotly visualization implementation with a vtk.js-based renderer and added VTK/ML/VTP transformation utilities.
  • Updated public exports to expose the new visualization/utility API from vtkSolutionScript.js.
  • Updated documentation and package metadata to reflect vtk.js usage and removed committed dist/ outputs from the repository.

Reviewed changes

Copilot reviewed 5 out of 12 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/visualization/vtkSolutionScript.js New vtk.js rendering + data transformation utilities (VTK polydata, VTP XML, ML buffers), replacing Plotly plotting logic.
src/visualization/plotSolutionScript.js Removed old Plotly-based plotting implementation.
src/index.js Re-exports visualization API from the new vtk.js module (and adds new exported helpers).
package.json Swaps Plotly peer dep for @kitware/vtk.js and adds vtk.js to devDependencies.
README.md Updates visualization description and install instructions to use vtk.js.
dist/feascript.umd.js Deleted committed build artifact.
dist/feascript.esm.js Deleted committed build artifact.
dist/feascript.cjs.js Deleted committed build artifact.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +10 to +14
import "@kitware/vtk.js/Rendering/Profiles/Geometry";
import vtkActor from "@kitware/vtk.js/Rendering/Core/Actor";
import vtkColorTransferFunction from "@kitware/vtk.js/Rendering/Core/ColorTransferFunction";
import vtkColorMaps from "@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps";
import vtkDataArray from "@kitware/vtk.js/Common/Core/DataArray";
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vtkSolutionScript.js imports vtk.js rendering modules at the top level, and src/index.js re-exports from this file. That makes vtk.js (and any browser/WebGL side effects it has) load whenever consumers import FEAScript, even if they only need the solvers (e.g., Node examples / workers). Consider splitting visualization into a separate entrypoint or lazy-loading vtk.js inside the rendering functions so non-browser consumers don’t pay the dependency/side-effect cost.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Comment on lines +433 to +436
const minX = Math.min(...nodesXCoordinates);
const maxX = Math.max(...nodesXCoordinates);
const minY = Math.min(...nodesYCoordinates);
const maxY = Math.max(...nodesYCoordinates);
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Math.min(...nodesXCoordinates) / Math.max(...nodesXCoordinates) (and the same for Y) will throw or become very slow for large meshes because it spreads the entire coordinate array into function arguments. Use a simple loop to compute bounds (or a typed-array reduction) to avoid RangeError: too many arguments and reduce memory churn.

Copilot uses AI. Check for mistakes.
Comment on lines 65 to 71
"peerDependencies": {
"mathjs": "^11.12.0",
"plotly.js": "^2.35.3"
"@kitware/vtk.js": "^32.12.0"
},
"devDependencies": {
"@kitware/vtk.js": "^32.12.0",
"@rollup/plugin-commonjs": "^28.0.3",
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR removes the committed dist/ artifacts, but main/module/exports still point at ./dist/* and the test script runs the Node examples without building first. With dist/ absent, npm test (and local dev installs from Git) will fail unless a build is run beforehand. Consider adding a prepare (and/or pretest) script to run rollup -c, or adjusting dev-time exports so the repo works without committed build output.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

src/index.js Outdated
Comment on lines +13 to +18
export {
plotSolution,
plotInterpolatedSolution,
createColorScale,
createContourLineOptions,
transformSolverOutputToVtkData,
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new export block uses tab indentation, while the rest of the file (and most JS in this repo) uses spaces. This can create noisy diffs and may fail formatting/linting if enforced; consider converting these lines to the repository’s standard indentation.

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI commented Mar 9, 2026

@sridhar-mani I've opened a new pull request, #65, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 12 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +10 to +21
import "@kitware/vtk.js/Rendering/Profiles/Geometry";
import vtkActor from "@kitware/vtk.js/Rendering/Core/Actor";
import vtkColorTransferFunction from "@kitware/vtk.js/Rendering/Core/ColorTransferFunction";
import vtkColorMaps from "@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps";
import vtkDataArray from "@kitware/vtk.js/Common/Core/DataArray";
import vtkImageData from "@kitware/vtk.js/Common/DataModel/ImageData";
import vtkImageMarchingSquares from "@kitware/vtk.js/Filters/General/ImageMarchingSquares";
import vtkGenericRenderWindow from "@kitware/vtk.js/Rendering/Misc/GenericRenderWindow";
import vtkMapper from "@kitware/vtk.js/Rendering/Core/Mapper";
import vtkPolyData from "@kitware/vtk.js/Common/DataModel/PolyData";
import vtkScalarBarActor from "@kitware/vtk.js/Rendering/Core/ScalarBarActor";

Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Top-level imports from vtk.js Rendering modules (Profiles/Geometry, Actor, Mapper, GenericRenderWindow, ScalarBarActor) will be executed whenever consumers import the main package (because src/index.js re-exports from this module). This is likely to break Node.js usage (including the repo’s npm test examples) if vtk.js touches DOM/WebGL globals at import time. Consider moving rendering-only imports behind a browser-only code path (dynamic import inside renderVtkScene), and/or splitting this file into a pure data-transform module (no Rendering imports) plus a browser-render module so Node can still import FEAScript safely.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sridhar-mani <165501918+sridhar-mani@users.noreply.github.com>
Copy link

Copilot AI commented Mar 9, 2026

@sridhar-mani I've opened a new pull request, #66, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 3 commits March 9, 2026 16:15
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link

Copilot AI commented Mar 9, 2026

@sridhar-mani I've opened a new pull request, #67, to work on those changes. Once the pull request is ready, I'll request review from you.

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Copy link

Copilot AI commented Mar 9, 2026

@sridhar-mani I've opened a new pull request, #68, to work on those changes. Once the pull request is ready, I'll request review from you.

@nikoscham nikoscham linked an issue Mar 10, 2026 that may be closed by this pull request
@nikoscham
Copy link
Member

Thanks for the input @sridhar-mani. I think it's better to also keep the previous visualization module (with Plotly.js) in case users want only basic visualization, and also for compatibility reasons. For example in 'FEAScript-core/src/visualization', rename plotSolutionScript.js to plotSolutionPlotlyScript and create also the plotSolutionVtkScript (based on vtkSolutionScript.js). Also, I've added some HTML examples in the 'FEAScript-core/examples' directory (see e.g. https://core.feascript.com/examples/frontPropagationScript/solidificationFront2D/solidificationFront2D.html) so we can test the VTK visualization before merging with the main branch.
I would also suggest that the visualization library be part of the arguments of the plotting functions (i.e., plotSolution, plotInterpolatedSolution), so that the user can choose what he wants.

@nikoscham nikoscham self-assigned this Mar 10, 2026
@nikoscham nikoscham added the enhancement New feature or request label Mar 10, 2026
@sridhar-mani
Copy link
Collaborator Author

Okay i will see how we can proceed with that.

@sridhar-mani
Copy link
Collaborator Author

Have completed the integration of the visualization with both vtk js and plotly.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 13 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +92 to +108
export async function plotInterpolatedSolution(model, result, plotType, plotDivId, renderOptions = {}) {
console.time("plottingTime");
const backend = renderOptions.backend ?? "vtk";

if (backend === "plotly") {
if (model.meshConfig.meshDimension === "2D" && plotType === "contour") {
const meshData = prepareMesh(model.meshConfig);
const grid = await buildInterpolatedGridValues(model, result, meshData);
await renderPlotlyScene(model, result, plotType, plotDivId, true, renderOptions, grid);
} else {
await renderPlotlyScene(model, result, plotType, plotDivId, false, renderOptions);
}
} else {
if (model.meshConfig.meshDimension !== "2D" || plotType !== "contour") {
await plotSolution(model, result, plotType, plotDivId, renderOptions);
console.timeEnd("plottingTime");
return;
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plotInterpolatedSolution starts a console.time("plottingTime") timer and, for non-2D/contour cases, calls plotSolution, which starts/ends a timer with the same label. This leads to nested timer label collisions and typically logs warnings (or produces incorrect timings). Consider either removing the timer from the delegating branch, using distinct labels, or refactoring to share a single timing block.

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +43
await import("@kitware/vtk.js/Rendering/Profiles/Geometry");
const [
{ default: vtkActor },
{ default: vtkColorTransferFunction },
{ default: vtkColorMaps },
{ default: vtkDataArray },
{ default: vtkImageData },
{ default: vtkImageMarchingSquares },
{ default: vtkGenericRenderWindow },
{ default: vtkMapper },
{ default: vtkPolyData },
{ default: vtkScalarBarActor },
] = await Promise.all([
import("@kitware/vtk.js/Rendering/Core/Actor"),
import("@kitware/vtk.js/Rendering/Core/ColorTransferFunction"),
import("@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps"),
import("@kitware/vtk.js/Common/Core/DataArray"),
import("@kitware/vtk.js/Common/DataModel/ImageData"),
import("@kitware/vtk.js/Filters/General/ImageMarchingSquares"),
import("@kitware/vtk.js/Rendering/Misc/GenericRenderWindow"),
import("@kitware/vtk.js/Rendering/Core/Mapper"),
import("@kitware/vtk.js/Common/DataModel/PolyData"),
import("@kitware/vtk.js/Rendering/Core/ScalarBarActor"),
]);
_vtkModules = {
vtkActor, vtkColorTransferFunction, vtkColorMaps, vtkDataArray,
vtkImageData, vtkImageMarchingSquares, vtkGenericRenderWindow,
vtkMapper, vtkPolyData, vtkScalarBarActor,
};
return _vtkModules;
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadVtkModules() dynamically imports optional peer dependencies (@kitware/vtk.js/...) but doesn’t handle the case where vtk.js isn’t installed or fails to load. In that scenario the promise rejects and callers will see a low-level module resolution error. Consider wrapping the imports in try/catch and surfacing a clear message (e.g., instructing users to install @kitware/vtk.js or to set renderOptions.backend = "plotly").

Suggested change
await import("@kitware/vtk.js/Rendering/Profiles/Geometry");
const [
{ default: vtkActor },
{ default: vtkColorTransferFunction },
{ default: vtkColorMaps },
{ default: vtkDataArray },
{ default: vtkImageData },
{ default: vtkImageMarchingSquares },
{ default: vtkGenericRenderWindow },
{ default: vtkMapper },
{ default: vtkPolyData },
{ default: vtkScalarBarActor },
] = await Promise.all([
import("@kitware/vtk.js/Rendering/Core/Actor"),
import("@kitware/vtk.js/Rendering/Core/ColorTransferFunction"),
import("@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps"),
import("@kitware/vtk.js/Common/Core/DataArray"),
import("@kitware/vtk.js/Common/DataModel/ImageData"),
import("@kitware/vtk.js/Filters/General/ImageMarchingSquares"),
import("@kitware/vtk.js/Rendering/Misc/GenericRenderWindow"),
import("@kitware/vtk.js/Rendering/Core/Mapper"),
import("@kitware/vtk.js/Common/DataModel/PolyData"),
import("@kitware/vtk.js/Rendering/Core/ScalarBarActor"),
]);
_vtkModules = {
vtkActor, vtkColorTransferFunction, vtkColorMaps, vtkDataArray,
vtkImageData, vtkImageMarchingSquares, vtkGenericRenderWindow,
vtkMapper, vtkPolyData, vtkScalarBarActor,
};
return _vtkModules;
try {
await import("@kitware/vtk.js/Rendering/Profiles/Geometry");
const [
{ default: vtkActor },
{ default: vtkColorTransferFunction },
{ default: vtkColorMaps },
{ default: vtkDataArray },
{ default: vtkImageData },
{ default: vtkImageMarchingSquares },
{ default: vtkGenericRenderWindow },
{ default: vtkMapper },
{ default: vtkPolyData },
{ default: vtkScalarBarActor },
] = await Promise.all([
import("@kitware/vtk.js/Rendering/Core/Actor"),
import("@kitware/vtk.js/Rendering/Core/ColorTransferFunction"),
import("@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps"),
import("@kitware/vtk.js/Common/Core/DataArray"),
import("@kitware/vtk.js/Common/DataModel/ImageData"),
import("@kitware/vtk.js/Filters/General/ImageMarchingSquares"),
import("@kitware/vtk.js/Rendering/Misc/GenericRenderWindow"),
import("@kitware/vtk.js/Rendering/Core/Mapper"),
import("@kitware/vtk.js/Common/DataModel/PolyData"),
import("@kitware/vtk.js/Rendering/Core/ScalarBarActor"),
]);
_vtkModules = {
vtkActor,
vtkColorTransferFunction,
vtkColorMaps,
vtkDataArray,
vtkImageData,
vtkImageMarchingSquares,
vtkGenericRenderWindow,
vtkMapper,
vtkPolyData,
vtkScalarBarActor,
};
return _vtkModules;
} catch (err) {
const message =
'Failed to load optional visualization backend "@kitware/vtk.js". ' +
'To use the VTK renderer, install @kitware/vtk.js (e.g. with "npm install @kitware/vtk.js") ' +
'or configure renderOptions.backend = "plotly". ' +
`Original error: ${err && err.message ? err.message : String(err)}`;
// Log a clearer message if logging is available, but do not depend on it.
try {
if (typeof errorLog === "function") {
errorLog(message, err);
}
} catch {
// Ignore logging failures.
}
throw new Error(message);
}

Copilot uses AI. Check for mistakes.
Comment on lines +291 to +303
async function renderPlotlyScene(model, result, plotType, plotDivId, interpolated, renderOptions = {}, prebuiltGrid = null) {
if (typeof document === "undefined") {
errorLog("Plotly visualization requires a browser environment");
return;
}
const { default: Plotly } = await import("plotly.js");
const { nodesXCoordinates, nodesYCoordinates } = result.nodesCoordinates;
const meshDimension = model.meshConfig.meshDimension;
const plotWidth = typeof window !== "undefined" ? Math.min(window.innerWidth, 600) : 600;
const colorScale = renderOptions.colorScale ?? {};
const plotlyColorscale = colorScale.reverse ? "RdBu" : "RdBu_r";
const scalarBarTitle = colorScale.scalarBarTitle ?? "Solution";

Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renderPlotlyScene dynamically imports plotly.js (an optional peer dependency) without error handling. If Plotly isn’t installed, this will throw a module resolution error rather than producing a user-friendly message. Consider try/catch around the import and an errorLog that explains how to enable the Plotly backend (install plotly.js and set renderOptions.backend = "plotly").

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check the package json for the plotly
@copilot

Comment on lines +525 to +544
function buildVTPString(vtkData) {
const { connectivity, offsets } = packedCellsToConnectivityAndOffsets(vtkData.cells);
const numberOfPoints = vtkData.points.length / 3;
const isLine = vtkData.mode === "line";
const topologyTag = isLine ? "Lines" : "Polys";
return [
'<?xml version="1.0"?>',
'<VTKFile type="PolyData" version="0.1" byte_order="LittleEndian">',
" <PolyData>",
` <Piece NumberOfPoints="${numberOfPoints}" NumberOfVerts="0" NumberOfLines="${isLine ? offsets.length : 0}" NumberOfStrips="0" NumberOfPolys="${isLine ? 0 : offsets.length}">`,
' <PointData Scalars="solution">',
` <DataArray type="Float32" Name="solution" NumberOfComponents="1" format="ascii">${Array.from(vtkData.scalars).join(" ")}</DataArray>`,
" </PointData>",
" <Points>",
` <DataArray type="Float32" NumberOfComponents="3" format="ascii">${Array.from(vtkData.points).join(" ")}</DataArray>`,
" </Points>",
` <${topologyTag}>`,
` <DataArray type="Int32" Name="connectivity" format="ascii">${connectivity.join(" ")}</DataArray>`,
` <DataArray type="Int32" Name="offsets" format="ascii">${offsets.join(" ")}</DataArray>`,
` </${topologyTag}>`,
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildVTPString uses Array.from(vtkData.scalars) / Array.from(vtkData.points) before joining. Since these are already typed arrays, Array.from needlessly copies the full buffers (extra memory + time) and can be very expensive for large meshes. Consider using the typed array’s native .join(" ") or a chunked string builder to avoid duplicating data.

Copilot uses AI. Check for mistakes.
Comment on lines 83 to 85
```bash
npm install feascript mathjs plotly.js
npm install feascript mathjs @kitware/vtk.js
```
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

README now instructs users to install only @kitware/vtk.js, but the codebase still supports a Plotly backend (renderOptions.backend === "plotly") and plotly.js remains an (optional) peer dependency. Consider either documenting Plotly as an optional install (and how to select the backend) or removing Plotly support/dependencies to match the migration messaging.

Copilot uses AI. Check for mistakes.
Comment on lines 67 to +75
"peerDependencies": {
"mathjs": "^11.12.0",
"@kitware/vtk.js": "^32.12.0",
"plotly.js": "^2.35.3"
},
"peerDependenciesMeta": {
"@kitware/vtk.js": { "optional": true },
"plotly.js": { "optional": true }
},
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plotly.js is still listed in peerDependencies (albeit optional) even though the README migration messaging/installation snippet implies Plotly is no longer needed. If Plotly support is intended to remain (via renderOptions.backend = "plotly"), consider clarifying this in docs and/or keeping it optional without implying a full removal; otherwise, remove Plotly from peer deps and code paths to avoid confusion for consumers.

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI commented Mar 11, 2026

@sridhar-mani I've opened a new pull request, #70, to work on those changes. Once the pull request is ready, I'll request review from you.

@nikoscham
Copy link
Member

nikoscham commented Mar 11, 2026

Have completed the integration of the visualization with both vtk js and plotly.

Thanks @sridhar-mani. Would it be possible also to test the vtk.js plotting in the HTML examples here? https://github.com/FEAScript/FEAScript-core/tree/main/examples

@sridhar-mani
Copy link
Collaborator Author

I will look into it.

Copilot AI and others added 3 commits March 11, 2026 21:58
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sridhar-mani <165501918+sridhar-mani@users.noreply.github.com>
@sridhar-mani
Copy link
Collaborator Author

Have added the examples.

nikoscham and others added 7 commits March 16, 2026 15:05
- Added support for contour lines and color scales in visualizations.
- Introduced interpolation methods for 2D solutions.
- Enhanced data transformation functions for VTK compatibility.
- Included utility functions for mesh preparation and scalar extraction.

`plotSolutionScript.js` filename is kept for backward continuity
@nikoscham
Copy link
Member

Have added the examples.

Thank you @sridhar-mani. I am locally testing a tutorial with vtk plotting, on FEAScript website (FEAScript-website/tutorials/heat-conduction-2d-fin-vtkjs.html), and seem to work! I will make some more tests and merge with main soon.

@sridhar-mani sridhar-mani deleted the vtkjs branch March 17, 2026 17:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use vtk.js for visualization

4 participants