Convert Plotly to VTK.js and remove dist folder#64
Convert Plotly to VTK.js and remove dist folder#64sridhar-mani wants to merge 24 commits intomainfrom
Conversation
There was a problem hiding this comment.
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.
| 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"; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
| const minX = Math.min(...nodesXCoordinates); | ||
| const maxX = Math.max(...nodesXCoordinates); | ||
| const minY = Math.min(...nodesYCoordinates); | ||
| const maxY = Math.max(...nodesYCoordinates); |
There was a problem hiding this comment.
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.
| "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", |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
src/index.js
Outdated
| export { | ||
| plotSolution, | ||
| plotInterpolatedSolution, | ||
| createColorScale, | ||
| createContourLineOptions, | ||
| transformSolverOutputToVtkData, |
There was a problem hiding this comment.
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.
|
@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. |
There was a problem hiding this comment.
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.
| 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"; | ||
|
|
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
|
@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. |
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>
|
@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>
|
@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. |
This reverts commit 888a7f08b9da7f4081af7b441fcf71a65fd561f5.
|
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. |
|
Okay i will see how we can proceed with that. |
|
Have completed the integration of the visualization with both vtk js and plotly. |
There was a problem hiding this comment.
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.
| 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; |
There was a problem hiding this comment.
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.
| 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; |
There was a problem hiding this comment.
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").
| 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); | |
| } |
| 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"; | ||
|
|
There was a problem hiding this comment.
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").
There was a problem hiding this comment.
check the package json for the plotly
@copilot
| 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}>`, |
There was a problem hiding this comment.
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.
| ```bash | ||
| npm install feascript mathjs plotly.js | ||
| npm install feascript mathjs @kitware/vtk.js | ||
| ``` |
There was a problem hiding this comment.
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.
| "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 } | ||
| }, |
There was a problem hiding this comment.
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.
|
@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. |
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 |
|
I will look into it. |
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>
|
Have added the examples. |
- 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
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 |
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:
README.md) and the package dependencies (package.json). [1] [2]@kitware/vtk.jsinstead ofplotly.js. [1] [2]Codebase reorganization:
src/index.jsto use the newvtkSolutionScript.jsmodule, adding new exports for color scales, contour line options, and various data transformation utilities for vtk.js.