Button support and FieldSetter derive macro#99
Merged
mfreeborn merged 4 commits intoplotly:devfrom Sep 6, 2022
Merged
Conversation
Contributor
|
Thank you for this effort! It was something that I was thinking about implementing, but I have no experience with writing macros. I'll review these changes fully as soon as I can, which will be early next week at the latest. |
cohen990
pushed a commit
to cohen990/plotly.rs
that referenced
this pull request
Dec 12, 2025
* FieldSetter proc macro * Unit Tests * Remove unused trait * Fix compilation with all features turned on
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Thank you for this wonderful crate. I have personally found it much easier to make a plotly chart using this crate aided by the Rust type system as opposed to other options. Excited to contribute to this repository.
This PR introduces two changes:
Change 1: FieldSetter derive marco
There are a number of structs defined in this crate that have private fields and public functions to set the value for each of these fields. The
FieldSetterprocedural marco, when applied on a struct, auto-derives the public setter functions for each of the fields in the struct. The setter functions have a small number of distinct signatures based on the type of the field. Types such asDim, String, Color, NumOrStringget a special syntax. The procedural macro is defined in theplotly_derivecrate. I have updated thetracesandlayoutmodules to use the procedural macro (resulting in a lot of code deletions). The macro also proved two attributes#[field_setter(box_self)]- The setter functions returnBox<Self>instead ofSelfif applied to the struct#[field_setter(skip)]- To skip generating setter function for a specific fieldThe procedural macro is not fully general to cover type aliasing etc, but works in practice for this crate.
Pros
Cons
Change 2: Support for Buttons (update menu)
I have defined the structs required to support buttons in a plotly chart (https://plotly.com/javascript/reference/layout/updatemenus/) in a new module
layout/update_menu.rs.Using these structs we can add buttons with this crate. However the button API (https://plotly.com/python/dropdowns/) is not strongly-typed and needs lots of "stringy" arguments. Instead, I have added a new approach to help create buttons. There are three button methods that I have focused on:
restyle: modify tracesrelayout: modify layoutupdatemodify traces and layoutRestyles
First I have defined a
Restylemarker trait. TheFieldSettermacro defines a new enum for each struct if it is marked as#[field_setter(kind = "trace")]. As an example, say we are deriving FieldSetter on the (simplified)SimpleBarstructThe derived enum would look like
i.e it contains one enum variant for modifying each of the struct fields. The reason each field is wrapped with a
Dimis that plotly provide option to modify all the traces in the plot using a scalar argument or control what to modify in each trace using a list argument. This enum implements theRestyletrait.Additionally we also define helper functions for SimpleBar
Coupled with this we have a
ButtonBuilderstruct that has apush_restyle()function which accepts any struct that implementsRestyletrait. On invoking theButtonBuilder::build()function, the builder sets up the Button correctly with the arguments in the right form.So for example, if we have two bar plots and we want a button to alternate between them, we can create the button using
Relayout
Similar to
Restylewe have aRelayouttrait. We derive a new enum which implementsRelayoutif the struct is annotated with#[field_setter(kind = "layout")]. Since you only have a single layout per plot, we don't do theDimwrapping here. TheButtonBuilderalso has apush_relayoutfunction.Examples
Three plots that demonstrate the use of
UpdateMenuto create buttons:Dropdown to alternate between two bar plots (restyle)

Heatmap with buttons to choose colorscale (restyle)

Button to change barmode (relayout)
