plotly / plotly.js

Open-source JavaScript charting library behind Plotly and Dash
https://plotly.com/javascript/
MIT License
17.12k stars 1.87k forks source link

Volume on non-uniform grid does not appear #6673

Open Liozou opened 1 year ago

Liozou commented 1 year ago

Plotting a 3D volume with a non-uniform grid yields a blank canvas with only the axes and the side bar.

Non-uniform means that the x, y, and z parameters are not simply obtained from a call to mgrid. For my application, they correspond to an affine transformation of such a regular grid, exactly like in https://community.plotly.com/t/3d-volume-plotting-with-non-orthogonal-grid/51662. There is also a StackOverflow answer pointing to this problem: https://stackoverflow.com/questions/66141821/plotting-a-3d-volume-plot-in-r-using-discrete-3d-points#answers.

This is either a bug or simply a documentation mistake, since the reference explicitly states that the coordinates should come from a "uniform or non-uniform 3-D grid" (see https://plotly.com/javascript/reference/volume/#volume).

Reproducer: https://codepen.io/Liozou/pen/OJaQMzK. On the left, the expected behavior, working on a uniform grid. On the right, the issue, on an affine-transformed grid. Black dots are used to visualize the grid itself.

28raining commented 1 year ago

Hey @archmoj this issue is in one of your repo's https://github.com/gl-vis/gl-plot3d/tree/master

I'd like to help debug it but I cannot figure out how to run your examples...

I've tried browserify surface.js > bundle.js, but that fails because of missing module exports

and I tried npm init --y npm install but that doesn't create a dist folder

28raining commented 1 year ago

I think we can reproduce it by trying to draw a simple 3x3x3 cube, with one-point being non uniform

gurki commented 1 year ago

Second this. The minimal example as described by the linked stackoverflow post reproduces the issue.

import plotly.graph_objects as go
import numpy as np
X, Y, Z = np.mgrid[-8:8:40j, -8:8:40j, -8:8:40j]
values = np.sin(X*Y*Z) / (X*Y*Z)

X[0, 0, 0] += 1 # this makes the grid non-uniform, and results in a blank canvas

fig = go.Figure(data=go.Volume(
    x=X.flatten(),
    y=Y.flatten(),
    z=Z.flatten(),
    value=values.flatten(),
    isomin=0.1,
    isomax=0.8,
    opacity=0.1, 
    surface_count=17,
    ))
fig.show()

A workaround for the time being is to use some regular grid interpolation to make it make it uniform, e.g. using scipy .

yyyxam commented 4 months ago

I am facing the same issue and wanted to bring up the idea of allowing more axis configuration for figures. In my use case, I'm transforming volumetric data on a regular/uniform cartesian grid to a monoclinic crystal structure grid using three base vectors. If I could just assign these basis vectors to the Figure, I could both skip the point transformation and use Volume/Isosurface. I currently use Scatter3d as a substitute, but that has its own limitations.

I also noticed that It is possible to render a Mesh3d with my transformed dataset. I segmented it by some scalar-intervalls to create rough Isosurfaces by hand. This only works if I set alphahull to a positive value though, so by using the alpha-shape algorithm for tesselation. But this also takes a considerable time to render (~2min 30s for 70k point), making it not viable for my interactive Dash-board. Leads me to the assumption that Isosurface/Volume just use the standard Delaunay-Algo, which, I assume, only supports certesian grid data.

I'm using plotly.py btw, but I think the problem lies "under the hood" in plotly.js.