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

Configure more than 8 axes? #184

Open
forgemo opened this issue Mar 15, 2024 · 6 comments
Open

Configure more than 8 axes? #184

forgemo opened this issue Mar 15, 2024 · 6 comments
Assignees

Comments

@forgemo
Copy link

forgemo commented Mar 15, 2024

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?

@yasuomaidana
Copy link

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?

@andrei-ng
Copy link
Collaborator

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

@yasuomaidana
Copy link

yasuomaidana commented Jul 30, 2024

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

Btw, where are the PR guidelines?

@andrei-ng
Copy link
Collaborator

andrei-ng commented Jul 30, 2024

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.

@yasuomaidana
Copy link

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?

@yasuomaidana
Copy link

yasuomaidana commented Aug 11, 2024

@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.

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

No branches or pull requests

3 participants