MakieOrg / Makie.jl

Interactive data visualizations and plotting in Julia
https://docs.makie.org/stable
MIT License
2.38k stars 302 forks source link

Mesh does not interpolate using full spectrum of colormap #1368

Open MathieuMorlighem opened 2 years ago

MathieuMorlighem commented 2 years ago

Hello

first, thanks so much for maintaining this package, it is the best! This is more of a feature request I guess. If I use a jet colormap and use mesh to create a plot, I get this:

using GLMakie
import ColorSchemes.jet
Makie.mesh( [0.0 0.0; 1.0 0.0; 1.0 1.0; 0.0 1.0;], [ 1 2 3], shading = false, color = [1;2;3;3], colormap=jet)

Screen Shot 2021-10-06 at 3 51 32 PM

But I would expect something like this (interpolate using the full spectrum of the colormap instead of the between the colors of each vertex):

Screen Shot 2021-10-06 at 3 53 28 PM

which would be consistent with MATLAB's patch function:

patch('Vertices',[0.0 0.0; 1.0 0.0; 1.0 1.0; 0.0 1.0;],'Faces',[ 1 2 3],'FaceVertexCData',[1;2;3;3],'FaceColor','interp');
colormap jet

As a side note, I am not sure why this does not work:

using GLMakie
import ColorSchemes.jet
Makie.mesh( [0.0 0.0; 1.0 0.0; 1.0 1.0], [ 1 2 3], shading = false, color = [1;2;3;3], colormap=jet)

Thank you for considering this request! Mathieu

jkrumbiegel commented 2 years ago

Hm I don't know why GLMakie does it like this (I would have assumed the behavior you want was the one implemented) but I wanted to add that this is one of the unresolvable differences between GLMakie and CairoMakie. Vector graphics meshes only support one color per vertex as far as I know, so you always get linear interpolation between the corners and it only kind of works if you have many small triangles.

ffreyer commented 2 years ago

I think what GLMakie does is use the values in color to index the colormap and than interpolate those colors. If you generate a mesh with uv coordinates and use the colormap as a texture you get what you want:

using GLMakie, GeometryBasics
import ColorSchemes.jet

ps = [Point2f(0), Point2f(1, 0), Point2f(1)]
faces = [GLTriangleFace(1,2,3)]
uvs = [Point2f(0), Point2f0(0.5, 0), Point2f0(1, 0)]
m = GeometryBasics.Mesh(meta(ps; uv = uvs), faces)

texture = reshape(get(jet, 0:0.01:1), 1, 101)

Makie.mesh(m, color = texture, shading = false)

Screenshot from 2021-10-07 16-03-25

MathieuMorlighem commented 2 years ago

Thanks @ffreyer, that looks great. Is there an "easy" way to extend that to a mesh that has more than one triangle (and different values at each vertex)?

ffreyer commented 2 years ago

You can have however many vertices and faces you want, The uv's are always per vertex and they get interpolated for each face. The interpolated values are used to sample a color from the texture. Whether it's easy to extend depends on what you want the end result to be. If you want to have colors change in y direction you could probably just do

ys = map(p -> p[2], ps)
ymin, ymax = extrema(ys)
uvs = [Point2f0((y - ymin)/(ymax - ymin), 0) for y in ys]