Skip to content

layout subplots has implicit magic, needs a better API #1436

Closed
@jthornbrue

Description

@jthornbrue

This issue refers to the example "Stacked Subplots with a Shared X-Axis".

import plotly.plotly as py
import plotly.graph_objs as go

trace1 = go.Scatter(
    x=[0, 1, 2],
    y=[10, 11, 12]
)
trace2 = go.Scatter(
    x=[2, 3, 4],
    y=[100, 110, 120],
    yaxis='y2'
)
trace3 = go.Scatter(
    x=[3, 4, 5],
    y=[1000, 1100, 1200],
    yaxis='y3'
)
data = [trace1, trace2, trace3]
layout = go.Layout(
    yaxis=dict(
        domain=[0, 0.33]
    ),
    legend=dict(
        traceorder='reversed'
    ),
    yaxis2=dict(
        domain=[0.33, 0.66]
    ),
    yaxis3=dict(
        domain=[0.66, 1]
    )
)
fig = go.Figure(data=data, layout=layout)
py.iplot(fig, filename='stacked-subplots-shared-x-axis')

First of all, I know that make_subplots abstracts a lot of this magic away, but the second I want finer control of my plot (e.g., more than just a grid or some shared axes), I need to use the layout object.

The implicit mapping of a trace from yaxis='y2' to the axis yaxis2 is a bit too magical for me. The name of the axis that you give a trace doesn't match the name of the axis in the layout (x vs xaxis, y2 vs yaxis2, etc.). Also, the name of the first axis doesn't have a number, e.g., x, x2, ... and xaxis, xaxis2, ... . As far as I can tell, this is only documented by example. I had to reverse engineer it from the example and by examining the layout object after much trial and error.

Ideally, an axis would be a first-class object with a unique identifier. A default name like xaxis1, yaxis3 is fine (as long as the naming convention is consistent for all), but it would also be nice to allow custom names that are even more meaningful.

The top-level separation between a list of traces and a layout that define a figure is confusing once subplots are involved. There is a natural relationship between a trace, axes, and axis. An axes should have x and y (or z) axis. An axes should have one or more trace children.

I'd like to see the API look more like this:

fig = go.Figure(...)
ax = fig.add_axes(...) . # create a custom subplot
ax.add_trace(go.Trace(...))  # add a trace to an axes

There could be some convenience functions:

ax = fig.axes  # default axes
fig.add_trace(go.Trace(...))  # equivalent to fig.axes.add_trace()

ax00, ax01, ax10, ax11 = fig.make_subplots(rows=2, cols=2)

Once the API is more object-oriented, you can do cool things like add a trace to more than one axes, and share axis objects between axes. In the JSON representation, these would be defined once and referenced elsewhere by unique name.

These are just suggestions. Obviously there are many corner cases and backward compatibility that would have to be addressed.

The bottom line is that the current API is not intuitive and not well documented, therefore hard to use.

Metadata

Metadata

Assignees

No one assigned

    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