Hi,
When calling say Makie.mesh(args...;kwargs...)
for some arguments with user defined-type, one can define an argument conversion for the positional arguments args
using function Makie.convert_arguments
.
But how to convert the keyword arguments kwargs
? I also have some user-defined types in the keyword arguments that can be mapped to the usual keyword arguments.
As a fallback, I am trying to define method
funciton Makie.plot!(p::Makie.Mesh{<:Tuple{<:MyType}})
## ... Some conversions ...
Makie.mesh!(p,converted_args...;converted_kwargs...)
end
which gives access to the keyword arguments as well, But it does not work for Makie.Mesh
.
Any clue on how to convert keyword arguments?
Thanks!
cc @sdanisch @jules
You can overload convert_attribute(value::YourType, ::Makie.key"attribute", ::Makie.key"mesh")
.
See: Makie.jl/Makie/src/conversions.jl at master · MakieOrg/Makie.jl · GitHub for some examples.
Note, these will only get applied automatically for core Makie plots, not for user recipes, since it’s a bit hard to foresee what people want to do with e.g. a color
attribute.
1 Like
Hi @sdanisch
thanks for the quick reply.
To convert the attribute, I need both the attribute and the passed argument. I guess you only have the attribute in convert_attribute
.
This is my actual setting (after simplifying a bit): I have a custom type that contains a mesh plus a dict with arrays of data associated with the nodes of the mesh:
struct MeshWithData
mesh::SomeMeshType
node_data::Dict{String,Vector{Float64}}
end
struct NodeColor
name::String
end
I want this API:
foo = MeshWithData(...)
Makie.mesh(foo;color=NodeColor("dataname"))
Which should colorate foo according to the data in key “dataname”.
Any ideas how to achieve this? I was hopping to dispatch on NodeColor
somewhere.
BTW, I cannot pass directly the array of data like this
Makie.mesh(foo;color=foo.node_data["dataname"])
since the conversion of foo.mesh
will possibly create and destroy nodes and foo.node_data["dataname"]
will become out of sync.
You can add whatever vertex data you want to a mesh and it’ll expand like positions, normals, etc:
using GeometryBasics
m = normal_mesh(Rect3f(0,0,0,1,1,1), facetype = QuadFace{Int})
# Mesh{3, Float32, QuadFace{Int64}}
# faces: 6
# vertex position: 8
# vertex normal: 6
m2 = GeometryBasics.mesh(
m,
color = [RGBf(x, y, z) for x in 0:1 for y in 0:1 for z in 0:1],
vertex_name = string.(1:8),
face_name = per_face(string.(1:6), m)
)
# Mesh{3, Float32, NgonFace{3, OffsetInteger{-1, UInt32}}}
# faces: 12
# vertex position: 8
# vertex normal: 6
# vertex color: 8
# vertex vertex_name: 8
# vertex face_name: 6
expand_faceviews(m2)
# Mesh{3, Float32, NgonFace{3, OffsetInteger{-1, UInt32}}}
# faces: 12
# vertex position: 24
# vertex normal: 24
# vertex color: 24
# vertex vertex_name: 24
# vertex face_name: 24
If you need to do further processing with the data before plotting you can run expand_faceviews()
like this and pass the result to Makie.mesh
with the processed data as attributes.
1 Like
Hi @ffreyer,
Thanks for the hint. In a more complex example, I would like pass a function-like object in the color attribute and interpolate it on the mesh nodes, and use the resulting vector as color. So, I need a way of converting an attribute while having access to the positional arguments.
I provably will define a new recipe (which gives grater control) instead of trying to extend Makie.mesh
.
But it would be cool to use a function that already exists (Makie.mesh) instead of creating a new one, if the difference is mainly conversions of arguments/attributes.
Yea convert_attribute()
only considers the attribute itself, so you’d need something else. Maybe it’s useful to note that Makie.mesh
can extract colors from a mesh and that the positions don’t change in convert_arguments
/expand_faceviews
. They just get duplicated. So you can figure out your vertex colors without worrying about what the plot function does to the mesh.
function build_mesh(N)
ps = [Point2f(x, y) for x in 1:N for y in 1:2]
fs = [QuadFace(2x-1, 2x, 2x+2, 2x+1) for x in 1:N-1]
cs = per_face([x % 2 for x in 1:N-1], fs)
return GeometryBasics.mesh(ps, fs, color = cs)
end
fig = Figure()
sl = Slider(fig[1,1], range = 2:20, startvalue = 20)
Makie.mesh(fig[2,1], map(build_mesh, sl.value))
fig
1 Like