Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: trisurf_plot aka mesh3d #392

Closed
krcools opened this issue Jul 18, 2016 · 31 comments
Closed

Feature Request: trisurf_plot aka mesh3d #392

krcools opened this issue Jul 18, 2016 · 31 comments

Comments

@krcools
Copy link

krcools commented Jul 18, 2016

I really like the idea of this package and I am more and more relying upon it. These is one type of plots however that I encounter very frequently in my work and that does not seem to be supported by plots.jl: an interface for the plotting of triangular meshes in 3d. At least the PyPlot and PlotsJS backends provide support through their trisurf_plot and mesh3d API's, respectively. This leaves me with a mix of Plots calls and direct backend invocations.

Is this somehow already supported or are there any plans to support this API in the future?

@tbreloff
Copy link
Member

For pyplot and gr you can pass 3 vectors with seriestype surface and it
will do a trisurf.

On Monday, July 18, 2016, krcools notifications@github.com wrote:

I really like the idea of this package and I am more and more relying upon
it. These is one type of plots however that I encounter very frequently in
my work and that does not seem to be supported by plots.jl: an interface
for the plotting of triangular meshes in 3d. At least the PyPlot and
PlotsJS backends provide support through their trisurf_plot and mesh3d
API's, respectively. This leaves me with a mix of Plots calls and direct
backend invocations.

Is this somehow already supported or are there any plans to support this
API in the future?


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#392, or mute the thread
https://github.com/notifications/unsubscribe-auth/AA492gsX-iyBI-kvqMVw1kz1WdfmiNNnks5qW1TYgaJpZM4JOlTf
.

@krcools
Copy link
Author

krcools commented Jul 18, 2016

Thanks for the quick reply. If IIUC these trisurfs are always structured in the sense that they derive from a rectangular grid, correct? I am looking for functionality that allows me to create unstructured triangular meshes. Typical APIs expect x,y,z values, but in addition also i,j,k integer indices defining the grid. I know that PyPlot, PlotlyJS, and Matlab can do this.

Matlab example

@tbreloff
Copy link
Member

The whole point of a trisurf is that it's not necessarily a grid.

On Monday, July 18, 2016, krcools notifications@github.com wrote:

Thanks for the quick reply. If IIUC these trisurfs are always structured
in the sense that they derive from a rectangular grid, correct? I am
looking for functionality that allows me to create unstructured triangular
meshes. Typical APIs expect x,y,z values, but in addition also i,j,k
integer indices defining the grid. I know that PyPlot, PlotlyJS, and Matlab
can do this.

[image: Matlab example]
https://cloud.githubusercontent.com/assets/10086147/16913689/324d42ca-4ce4-11e6-81db-540d0707d8cb.png


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#392 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AA492qOSktM3mlGY8xrSVg8TgPYrKxToks5qW2W0gaJpZM4JOlTf
.

@krcools
Copy link
Author

krcools commented Jul 18, 2016

Thanks again. Possibly I am missing something obvious here, but I can't see how a three argument invocation of surface can produce a general trisurf. Issues #24 and #387 also seem to imply Plots.jl is not exposing this functionality for now.

@tbreloff
Copy link
Member

While I agree there's no way to specify arbitrary 3D meshes at this point, the "trisurf" functionality works fine:

using Plots; gr(); surface(rand(100),rand(100),rand(100))

tmp

As you can see from the example, there's no need for the data to be on a grid, or even ordered in any way. The "trisurf" creates a surface, not a mesh, and this might be your point of confusion?

@krcools
Copy link
Author

krcools commented Jul 18, 2016

Yes, I imagine our communication issues can be traced back to us using slightly different definitions. I'd like to partially shift blame for that to matplotlib though. The plot_trisurf API can accommodate a triangles kwarg that takes an Nx3 index buffer allowing for the description of any 3D unstructured mesh:

http://matplotlib.org/mpl_examples/mplot3d/trisurf3d_demo2.py

Also the Plotly documentation does not seem to distinguish the two: both are traces of type mesh3d.

https://plot.ly/javascript/trisurf/

What you refer to as trisurf they simply call surface.

@tbreloff
Copy link
Member

What you refer to as trisurf they simply call surface

So do I ;)

I'd like to partially shift blame for that to matplotlib

Always happy to shift the blame! Yeah I think a "surface" might be on a grid, or not, and I support both types. There is not currently support for 3D meshes, though I'm hopeful @SimonDanisch will help change that.

@krcools
Copy link
Author

krcools commented Jul 18, 2016

OK, let's consider the blame shifted then ;). The feature request stands though, maybe under a different description. Happy to hear it is on the radar! Many thanks!

@SimonDanisch
Copy link
Member

That sounds like the most basic primitive of 3D graphics to me :)
This will definitely be part of the GLVisualize backend!

@ChrisRackauckas
Copy link
Member

Yes, I showed in #286 how triangles are necessary to make the plotted structure "not fill in". Let me repost the example here with a bit more detail since I don't know if this is getting across.

using JLD, DifferentialEquations, Plots
mesh = meshExample_lakemesh()
plot(mesh)

trianglemesh

vs

using DifferentialEquations, JLD, PyPlot
mesh = meshExample_lakemesh()
PyPlot.plot_trisurf(mesh.node[:,1],mesh.node[:,2],ones(mesh.node[:,2]),triangles=mesh.elem-1)

c4f8b5aa-256b-11e6-8095-b22ea9d9ad63

In that example, you can clearly see the lake, but only when the triangles are specified. However, if you can't specify triangles, it "completes the outside of the structure" to just make a blob (couldn't color the edge lines in GR, but you get the point)

This is because surface seems to pair every node together, and get rid of the overlap. However, the whole reason for using trisurf instead of surface is because we know the triangles (big example is FEM codes), and thus without supplying them it's adding "extra" parts to the plot which don't make sense. I can't truly cutoff DifferentialEquations.jl from PyPlot until there is a way to specify the triangles via Plots.jl (and into something like GR or Plotly).

@tbreloff
Copy link
Member

the whole reason for using trisurf instead of surface is because we know the triangles

For you maybe. Not everyone has your perspective and use-case.

To be clear... I very much want support for "triangle meshes", but this is different than a "triangle surface". PyPlot makes a mess out of terminology here by combining "surface" and "mesh" into the same function, where you distinguish them by passing in triangles. I would prefer to keep these as separate types.

To summarize... please don't ask for surface to be changed... we need a new series type "mesh", and the inputs for that could likely be the triangles you would pass into PyPlot's trisurf.

@ChrisRackauckas
Copy link
Member

ChrisRackauckas commented Jul 22, 2016

I wasn't asking for this to be part of :surface, just that there be a :trisurf series type which allows for the passing of triangles, but if no triangles are supplied, defaulting to the :surface implementation.

This is pretty common in Finite Element Method (FEM) codes. I know there are a few packages for it on Julia already, and once this is implemented you may wish to start an issue on JuliaFEM for implementing plot recipes for their types.

I may get around to this soon.

@mkborregaard
Copy link
Member

Was this solved in #479 ?

@ChrisRackauckas
Copy link
Member

no

@SimonDanisch
Copy link
Member

I call the function mesh in MakiE and it works like this:

using FileIO, MakiE, GeometryTypes, MakiE
lakemesh = load(Pkg.dir("DiffEqProblemLibrary", "src", "premade_meshes.jld"))["lakemesh"]
scene = Scene()
# reconstructed type from JLD - not sure were SimpleMesh lives
function MakiE.to_mesh(b, m::typeof(lakemesh)) 
    vertices = map(1:size(m.node, 1)) do i
        Point3f0(ntuple(j-> m.node[i, j], Val{2})..., 0)
    end
    triangles = map(1:size(m.elem, 1)) do i
        GLTriangle(Int.(ntuple(j-> m.elem[i, j], Val{3})))
    end
    GLNormalMesh(vertices, triangles)
end

wireframe(lakemesh)
m = mesh(lakemesh)
center!(scene)

result:

image

@mkborregaard
Copy link
Member

Beautiful!
Now we just need the syntax to be

using FileIO, MakiE
lakemesh = load(Pkg.dir("DiffEqProblemLibrary", "src", "premade_meshes.jld"))["lakemesh"]
plot(lakemesh) #or mesh

:-)

@SimonDanisch
Copy link
Member

well, the overloading of MakiE.to_mesh(b, m::typeof(lakemesh)) is a light version of a recipe.
Once to_mesh lives in the abstractplots package, it can be overloaded by any package :)

@mkborregaard
Copy link
Member

awesome. And I'm guessing the Scene-related calls will become optional at some point?

@mkborregaard
Copy link
Member

Why is it a "light" version of a recipe? As a user recipe (given that there weren't one already) I'm guessing it would look like this:

Typ = typeof(lakemesh)
@recipe function f(m::Typ) 
    vertices = map(1:size(m.node, 1)) do i
        Point3f0(ntuple(j-> m.node[i, j], Val{2})..., 0)
    end
    triangles = map(1:size(m.elem, 1)) do i
        GLTriangle(Int.(ntuple(j-> m.elem[i, j], Val{3})))
    end
    GLNormalMesh(vertices, triangles)
end

@SimonDanisch
Copy link
Member

Because it just overloads a conversion function and basically works orthogonal to any plotting command (though every plotting command using to_mesh, e.g. wireframe, automatically will get this as well)...
While for a full recipe, I was thinking more of a collection of atomic drawing functions...

@mkborregaard
Copy link
Member

mkborregaard commented Nov 6, 2017

I'm not sure what you mean with the atomic function recipe? It sounds interesting, though.

I just wanted to highlight that recipes are generally a lot simpler than people tend to make them out to be, in particular it's a really easy way to define plotting for a type to define a simple conversion recipe like the above that changes it into a type that does have a recipe.

@SimonDanisch
Copy link
Member

SimonDanisch commented Nov 6, 2017

Well, this example would proof the point quite nicely, since a macro seems unnecessary here ;) I find it really confusing that this needs a macro, since I don't really know what magic this hides.

@SimonDanisch
Copy link
Member

And I'm guessing the Scene-related calls will become optional at some point?

Well, they're like the current gr()/pyplot() calls... You can leave them out already, but then things become more opaque and magic :D

@mkborregaard
Copy link
Member

... and efficient, once your focus is on data analysis and your plot is just a visualization that supports your thought process rather than the end point. That's the beauty of Plots - you have control when you need it, but for all the other plots you do during a workday you just need a ten-char one-liner.

@mkborregaard
Copy link
Member

To me, the@recipe macro just signals to me that this is a recipe, and I can trust it to Just Work(TM).

@Evizero
Copy link
Member

Evizero commented Nov 6, 2017

for what its worth, the way scene = Scene() seems to affect global state already seems very magical to me. then again i suppose Plots does the same thing

@JMmontilla
Copy link

Has this feature already been implemented in Plots.jl?

@BeastyBlacksmith
Copy link
Member

Both GR and PyPlot have a trisurf call in the backend code.
See here.
But it could be better documented

@t-bltg
Copy link
Member

t-bltg commented Jul 6, 2021

@krcools, would #3612 fix this (at least partially, connections are supported) or not ?

@BeastyBlacksmith
Copy link
Member

Closed by #3835

@simonbyrne
Copy link

Is there a 2D analog of this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants