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

Subplots with individual titles #387

Closed
edugca opened this issue May 5, 2023 · 4 comments · Fixed by #453
Closed

Subplots with individual titles #387

edugca opened this issue May 5, 2023 · 4 comments · Fixed by #453
Labels
Area: Core API Area: MissingAbstraction Plotly.js functionality that has to be implemented Type: Enhancement

Comments

@edugca
Copy link

edugca commented May 5, 2023

Description

I code in C#. I'm trying to plot a grid of subplots in which each subplot has its own title displayed on top of it. When I run the code below, the title of the last graph is displayed on top of the first graph and all other titles are missing. "stepCharts" is an array of GenericCharts.

GenericChart.GenericChart allCharts = Plotly.NET.CSharp.Chart.Grid(stepCharts, nRows, nCols);

I noted that my variable "allCharts" has a single layout while each chart in "stepCharts" has its own layout with the right title.

How can I solve this? Also, is there a Plotly.NET equivalent to Python's Plotly function "make_subplots"?

Related information

  • Windows
  • .NET 6.0
@kMutagene
Copy link
Member

The Title attribute in plotly.js always refers to the title on top of the whole plot. The reason you see the first title is the logic we use to combine the layouts of the subplots.

To set titles for individual subplots, you have to use Annotations. That is also what is used internally by python's make_subplots.

However, make_subplots has the subplot_titles argument to calculate the annotation positions for the titles. Chart.Grid does not have this logic yet, so currently you have to set this yourself. An additional "problem" is that Annotation has no native binding for Plotly.NET.CSharp yet, so you'll have to use Annotation.init from the base lib, which needs lots of type annotations.

I ended up with this code, which is a bit awkward but should be a good workaround for now (ideally, you would create the annotations with positional logic in some kind of function beforehand instead of manually):

using Plotly.NET;
using Plotly.NET.LayoutObjects;
using Plotly.NET.CSharp;

Plotly.NET.CSharp.Chart.Grid(
    new [] {
        Plotly.NET.CSharp.Chart.Point<int,int,string>(x: new [] { 1 }, y: new [] { 1 }),
        Plotly.NET.CSharp.Chart.Point<int,int,string>(x: new [] { 1 }, y: new [] { 1 }),
        Plotly.NET.CSharp.Chart.Point<int,int,string>(x: new [] { 1 }, y: new [] { 1 }),
        Plotly.NET.CSharp.Chart.Point<int,int,string>(x: new [] { 1 }, y: new [] { 1 })
    },
    2,
    2
).WithAnnotations(
    new Annotation [] {
        Annotation.init<double,double,string,string,string,string,string,string,string,string>(
            X: 0.225,
            Y : 1,
            XAnchor: StyleParam.XAnchorPosition.Center,
            ShowArrow : false,
            YAnchor : StyleParam.YAnchorPosition.Bottom,
            Text : "plot1",
            XRef : "paper",
            YRef : "paper"
        ),
        Annotation.init<double,double,string,string,string,string,string,string,string,string>(
            X: 0.775,
            Y : 1,
            XAnchor: StyleParam.XAnchorPosition.Center,
            ShowArrow : false,
            YAnchor : StyleParam.YAnchorPosition.Bottom,
            Text : "plot2",
            XRef : "paper",
            YRef : "paper"
        ),
        Annotation.init<double,double,string,string,string,string,string,string,string,string>(
            X: 0.225,
            Y : 0.4125,
            XAnchor: StyleParam.XAnchorPosition.Center,
            ShowArrow : false,
            YAnchor : StyleParam.YAnchorPosition.Bottom,
            Text : "plot3",
            XRef : "paper",
            YRef : "paper"
        ),
        Annotation.init<double,double,string,string,string,string,string,string,string,string>(
            X: 0.775,
            Y : 0.4125,
            XAnchor: StyleParam.XAnchorPosition.Center,
            ShowArrow : false,
            YAnchor : StyleParam.YAnchorPosition.Bottom,
            Text : "plot4",
            XRef : "paper",
            YRef : "paper"
        )
    }
)

image

@kMutagene
Copy link
Member

I noted that my variable "allCharts" has a single layout while each chart in "stepCharts" has its own layout with the right title.

How can I solve this?

Also maybe to add some context for this, this is by design. You always only have one layout for a chart.

Chart.Grid creates a MultiChart that has multiple Traces (your subplots in this case) and a single Layout, which is combined from the individual subplot inputs. "combined" in this case means for example that x and y axes are preserved for the individual subplots etc.

This also means that there can always be only one Title, which is the title on top of the chart's layout (this is not only how Plotly.NET abstracts things btw, this is just how plotly works).

So for individual subplot titles, you always have to set annotations. We should also provide an abstraction for that, ideally with an SubplotTitles argument for Chart.Grid.

@edugca
Copy link
Author

edugca commented May 5, 2023

Thanks a lot for the quick and thorough answer! I tried to implement it and it works I still have to manually set X and Y properties for each annotation. Is there an easy formula to calculate these coordinates, say at the top-center of each subplot?

@kMutagene kMutagene added Type: Enhancement Area: MissingAbstraction Plotly.js functionality that has to be implemented Area: Core API labels Feb 5, 2024
@kMutagene kMutagene added this to the Plotly.NET 5.0 milestone Feb 5, 2024
@kMutagene
Copy link
Member

kMutagene commented May 22, 2024

Revisiting this for finally releasing v5. Found this 6(!) year old issue plotly/plotly.js#2746 in plotly.js that basically says that we have to use a workaround, since plotly.js does not support this out of the box (and without a sponsor most likely never will) as it has no complete "subplot" concept.

This means that Chart.Grid must implement a custom, annotation-based solution. Other language implementation seem to implement everything based on domain ranges, but i really want to keep using layout.grid. The linked issue contains a workaround adding annotations anchored to layout grid cells, so i will give implementing that a shot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Core API Area: MissingAbstraction Plotly.js functionality that has to be implemented Type: Enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants