Skip to content

Configure more than 8 axes? #184

Description

@forgemo

I do have one plot with 15 sub-plots.

I would like all of them to "match" the first one.

Layout::new()
            .x_axis2(Axis::new().matches(true))
            .x_axis3(Axis::new().matches(true))
            .x_axis4(Axis::new().matches(true))
            .x_axis5(Axis::new().matches(true))
            .x_axis6(Axis::new().matches(true))
            .x_axis7(Axis::new().matches(true))
            .x_axis8(Axis::new().matches(true))

How can I configure the remaining ones?
e.g. There is no .x_axis9(...) or .x_axis10(...) setter.
Is there a more generic way to do it for an arbitrary axes count?

Activity

  1. yasuomaidana commented on Jul 30, 2024

    @yasuomaidana

    I've been reviewing the code, and this problem relates to how the Layout struct is defined.

    After reviewing other implementations, I found this:

    • In the python documentation, I found that they are using a function called make_subplots to generate the plots. Then, they add traces by referring to which position in the grid they will be shown.
    • I've been reviewing the javascript documentation, and the API uses the layout using names.

    We could modify this structure Layout by replacing each axis with an axis array and generating a custom serializing function.

    Here is an example of the possible implementation:

    // Custom layout example
    #[serde_with::skip_serializing_none]
    #[derive(Serialize, Debug, Clone, FieldSetter)]
    #[field_setter(kind = "layout")]
    struct Example {
        // Other fields
        #[serde(rename = "hoverlabel")]
        hover_label: Option<Label>,
    
        #[serde(flatten, serialize_with= "serialize_axes")]
        xaxis:Option<Vec<Option<Box<Axis>>>>,
        // Other fields
    }
    
    impl Example {
        pub fn new() -> Self {
            Default::default()
        }
    }
    // other tests
        #[test]
        fn test_custom_serialize(){
            let layout = Example::new()
                .hover_label(Label::new())
                .xaxis(vec![
                    Some(Box::new(Axis::new())),
                    Some(Box::new(Axis::new()))
                ]);
            let json = serde_json::to_string(&layout).unwrap();
            println!("{}", json);
    // ...

    Output:

    {"hoverlabel":{},"xaxis":{},"xaxis2":{}}
    

    As you can appreciate, we can keep the previous serialized logic. However, we must carefully check all the tests to ensure we are not breaking anything else.

    Can I take this issue?

  2. andrei-ng commented on Jul 30, 2024

    @andrei-ng
    Collaborator

    Nice that you looked into it. Yes, would be awesome if you can work on the issue

  3. yasuomaidana commented on Jul 30, 2024

    @yasuomaidana

    Thank you. Could you assign it to me? Please?

    Btw, where are the PR guidelines?

  4. andrei-ng commented on Jul 30, 2024

    @andrei-ng
    Collaborator

    You can find them here. They are quite lightweight. Btw, I noticed that at the end , the former maintainer's contact is mentioned. That needs to be updated, as Ioannis is no longer involved. I will fix that.

  5. yasuomaidana commented on Jul 31, 2024

    @yasuomaidana

    I've been checking the code, and I have the following concerns:

    • This could be a breaking change because it changes at least two structures.
      • LayoutTemplate, which lives in layout\mod.rs
      • Layout, which lives in layout\mod.rs

    My concerns come from the fact that I was thinking of removing the

    #[serde_with::skip_serializing_none]
    #[derive(Serialize, Debug, Clone, FieldSetter)]
    #[field_setter(kind = "layout")]
    struct Layout{ \\LayoutTemplate
        // Other fields
        
          //////////////////////////////////////////////////////////////////////// 
         //I am thinking of removing this which will change several function signatures
        ////////////////////////////////////////////////////////////////////////
         // #[serde(rename = "xaxis")]
        // x_axis: Option<Box<Axis>>,
        // #[serde(rename = "yaxis")]
        // y_axis: Option<Box<Axis>>,
        // #[serde(rename = "zaxis")]
        // z_axis: Option<Box<Axis>>,
    
        // #[serde(rename = "xaxis2")]
        // x_axis2: Option<Box<Axis>>,
        // #[serde(rename = "yaxis2")]
        // y_axis2: Option<Box<Axis>>,
        // #[serde(rename = "zaxis2")]
        // z_axis2: Option<Box<Axis>>,
        // #[serde(rename = "xaxis3")]
        // x_axis3: Option<Box<Axis>>,
        // #[serde(rename = "yaxis3")]
        // y_axis3: Option<Box<Axis>>,
        // #[serde(rename = "zaxis3")]
        // z_axis3: Option<Box<Axis>>,
        // #[serde(rename = "xaxis4")]
        // x_axis4: Option<Box<Axis>>,
        // #[serde(rename = "yaxis4")]
        // y_axis4: Option<Box<Axis>>,
        // #[serde(rename = "zaxis4")]
        // z_axis4: Option<Box<Axis>>,
        // #[serde(rename = "xaxis5")]
        // x_axis5: Option<Box<Axis>>,
        // #[serde(rename = "yaxis5")]
        // y_axis5: Option<Box<Axis>>,
        // #[serde(rename = "zaxis5")]
        // z_axis5: Option<Box<Axis>>,
        // #[serde(rename = "xaxis6")]
        // x_axis6: Option<Box<Axis>>,
        // #[serde(rename = "yaxis6")]
        // y_axis6: Option<Box<Axis>>,
        // #[serde(rename = "zaxis6")]
        // z_axis6: Option<Box<Axis>>,
        // #[serde(rename = "xaxis7")]
        // x_axis7: Option<Box<Axis>>,
        // #[serde(rename = "yaxis7")]
        // y_axis7: Option<Box<Axis>>,
        // #[serde(rename = "zaxis7")]
        // z_axis7: Option<Box<Axis>>,
        // #[serde(rename = "xaxis8")]
        // x_axis8: Option<Box<Axis>>,
        // #[serde(rename = "yaxis8")]
        // y_axis8: Option<Box<Axis>>,
        // #[serde(rename = "zaxis8")]
        // z_axis8: Option<Box<Axis>>,
    
        //////////////////////////////////////////////////////////////////////// 
       //Deleting up to here, from here I will put my changes
      ////////////////////////////////////////////////////////////////////////
    
        #[serde(flatten, serialize_with= "serialize_axes")]
        xaxis:Option<Vec<Option<Box<Axis>>>>,
        #[serde(flatten, serialize_with= "serialize_axes")]
        yaxis:Option<Vec<Option<Box<Axis>>>>,
        #[serde(flatten, serialize_with= "serialize_axes")]
        zaxis:Option<Vec<Option<Box<Axis>>>>,
        // Other fields
    }

    I prefer the vector format; it is less hardcoded and cleaner.

    This could sound dumb, but it has been a while since I contributed to a repo. I can't see the button to create a branch for this issue. Is there any branch naming convention? Or could I name it as I want?

    I need to prepare my thesis presentation, so I'll be busy up to next week, sorry :( But I will be expecting feedback. What do you think?

  6. yasuomaidana commented on Aug 11, 2024

    @yasuomaidana

    @forgemo, you can find some examples, examples/subplots/src/main.rs; in that example, they use another workflow to generate plots with more than nine axes.

    Check this function many_subplots_with_titles.

  7. andrei-ng commented on Jul 7, 2025

    @andrei-ng
    Collaborator

    @yasuomaidana, do you have time by any chance to get back working on this and PR #218 ?

  8. yasuomaidana commented on Jul 30, 2025

    @yasuomaidana

    I'm sorry, I finished my master's and then suffered a layoff; fortunately, life is getting back on track. I want to start working again on this this week.

  9. andrei-ng commented on Aug 1, 2025

    @andrei-ng
    Collaborator

    I'm sorry, I finished my master's and then suffered a layoff; fortunately, life is getting back on track. I want to start working again on this this week.

    Congrats on your master's thesis!

    I have some ideas, so when you have time to get back to this, let me know so we cn discuss. If you don't have time is also fine, just let me know so I can allocate some time to work on it myself.

  10. yasuomaidana commented on Aug 8, 2025

    @yasuomaidana

    Thank you, I'll have some time next week, what about you?

  11. andrei-ng commented on Aug 11, 2025

    @andrei-ng
    Collaborator

    Thank you, I'll have some time next week, what about you?

    Should have some time towards the end of the week.

  12. yasuomaidana commented on Aug 12, 2025

    @yasuomaidana

    Yeah, what time?

  13. andrei-ng commented on Aug 16, 2025

    @andrei-ng
    Collaborator

    So, I have been thinking about this for some time. My current idea is that we should actually introduce make_subplots API similar to plotly.py and hide in there the number of axes needed. This would be nicer for the user to use and align nicely with Python implementation.

    We should keep the current hardcorded axes as there is no harm having those as well.

  14. yasuomaidana commented on Sep 3, 2025

    @yasuomaidana

    I deleted my branch and am starting again. There were too many changes, and I got confused. I want to review the current strategy.
    Should I implement my previous approach of using the serializer, then ensure it initializes with the current configuration (values), to ensure this change won't break the current project, and then implement make_subplots? To fully address all the features?

  15. andrei-ng commented on Sep 3, 2025

    @andrei-ng
    Collaborator

    I don't think there is a need to revisit the previous approach. IMO you should go straight into make_subplots . It is also a rather different approach than what you tried the first time. If you don't know how to start or are stuck at any point, let me know .

  16. yasuomaidana commented on Sep 7, 2025

    @yasuomaidana

    Can you help me from the start? How do you think we could implement this? My original idea was to modify to convert axes to vectors and modify their serializers...

  17. andrei-ng commented on Sep 9, 2025

    @andrei-ng
    Collaborator

    I will do a draft at the end of the week

  18. yasuomaidana commented on Sep 14, 2025

    @yasuomaidana

    You may have been busy, but can you give me a hint or a method to look at the Python implementation to get an idea?

  19. andrei-ng commented on Sep 14, 2025

    @andrei-ng
    Collaborator

    You may have been busy, but can you give me a hint or a method to look at the Python implementation to get an idea?

    I am still on time, based on UTC european time 😁

    So my idea is basically as outlined in #361 . Which already does the heavy lifting, I think.

    Where I have copied the basic structure from https://plotly.com/python/subplots/ , it is yet not fully on par/complete.

    Feel free to improve, make suggestions , the main function evaluate_subplots_layout which should do the calculation and distribution of the subplot in the appropriate domain, is ghastly at this moment. It should be split and improved, or a better approach found.

    @yasuomaidana, let me know if you can pick #361 up or you need more help

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions