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

Version 4 make_subplots #1528

Merged
merged 5 commits into from
Apr 19, 2019
Merged

Version 4 make_subplots #1528

merged 5 commits into from
Apr 19, 2019

Conversation

jonmmease
Copy link
Contributor

@jonmmease jonmmease commented Apr 19, 2019

Overview

This PR contains the initial implementation of a version 4 rewrite of the make_subplots function.

This new function is located in a new plotly.subplots module, and to use it the new v4_subplots future flag must be enabled. When v4_subplots is enabled, the legacy plotly.tools.make_subplots function will delegate to `plotly.subplots.make_subplots, but otherwise the legacy function will operate unchanged for the remainder of plotly.py version 3.

cc: @chriddyp @nicolaskruchten

Notable changes

The new implementation has the following notable changes.

trace types

All subplot/trace types are now supported 🎉 To accomplish this, a new 'type' property has been added to elements of the specs argument. For example

make_subplots(3, 2, specs=[
    [{}, {'type': 'polar'}],
    [{'colspan': 2,
      'rowspan': 2,
      'type': 'parcoords'}, None],
     [None, None]],
    print_grid=True
)

The value of type may be 'xy' (the default, for 2D Cartesian subplots), 'scene' (for 3D Cartesian subplots), 'polar', 'ternary', 'geo', or 'domain' (for self positioning traces that don't have shared subplots). In addition, the name of any trace can be used and the subplot type for that trace will be used.

For backward compatibility, the is_3d specs flag is still accepted. It is treated as 'type': 'scene'.

Shared axes using matching

Unlike the legacy implementation, this implementation always creates xaxis/yaxis pairs for each 2D cartesian subplot. Axis sharing (shared_xaxes and shared_yaxes) is implemented not by actually sharing the same, for example, xaxis among multiple yaxes. Instead, sharing is accomplished using the matches property introduced in plotly.js version 1.45. This significantly simplifies the subplot construction logic, and it makes it possible to support more flexible axis "sharing". Now, the shared_xaxes/shared_yaxes arguments may be set to 'rows', 'columns', or 'all'. Setting these values to True will maintain the legacy behavior of sharing xaxes across columns and sharing yaxes across rows.

Row and column titles

New row_titles and column_titles arguments have been added for giving titles to subplot columns and rows. These are alternatives to the existing subplot_titles argument for giving titles to each individual subplot. Column titles are place at the top of each column, while row titles are placed to the right of each row and rotated vertically.

These are added to support faceted subplots

newplot (17)

x_title and y_title

New arguments x_title and y_title have been added to allow for the placement for a centered titles across all rows and columns. See image above for example.

print_grid cleamup

The print_grid argument is now False by default and when it is printed is uses unicode characters to display spanned subplots in a more readable way.

Before:
Screenshot_20190417_190547

After:
Screenshot_20190417_190311

row/column width/height cleanup

For API consistency, column_width has been renamed column_widths and row_width has been renamed row_heights (The old args still accepted for compatibility, but they don't show up in the function signature of the docstring.

In addition the behavior of row_heights has changed slightly for row_width. Now, the height specification followings the ordering specified in start_cell. So when start_cell='top-left' the row heights are specified from top to bottom, and when start_cell='bottom-left' they are specified from bottom to top. The old behavior was to always treat the row_width argument as specifying heights from bottom to top.

See #1275 for the confusion this has caused.

figure.get_subplot method

A new figure method, get_subplot has been added for retrieving a subplot object from a figure by row/column index. Here's the docstring

        Return an object representing the subplot at the specified row
        and column.  May only be used on Figures created using
        plotly.tools.make_subplots

        Parameters
        ----------
        row: int
            1-based index of subplot row
        col: int
            1-based index of subplot column

        Returns
        -------
        subplot
            * None: if subplot is empty
            * plotly.graph_objs.layout.Scene: if subplot type is 'scene'
            * plotly.graph_objs.layout.Polar: if subplot type is 'polar'
            * plotly.graph_objs.layout.Ternary: if subplot type is 'ternary'
            * plotly.graph_objs.layout.Mapbox: if subplot type is 'ternary'
            * SubplotDomain namedtuple with `x` and `y` fields:
              if subplot type is 'domain'.
                - x: length 2 list of the subplot start and stop width
                - y: length 2 list of the subplot start and stop height
            * SubplotXY namedtuple with `xaxis` and `yaxis` fields:
              if subplot type is 'xy'.
                - xaxis: plotly.graph_objs.layout.XAxis instance for subplot
                - yaxis: plotly.graph_objs.layout.YAxis instance for subplot

Among other uses, this will make it possible for folks to construct a faceted plot with plotly_express and then customize the subplot properties in the resulting figure.

Future flag

To activate this functionality, the v4_subplots (or v4) future flag must be enabled before import plotly.

Examples

Faceted subplots with all xaxes and yaxes shared, so all 6 subplots pans/zoom together.

from _plotly_future_ import v4
from plotly.subplots import make_subplots
import plotly.graph_objs as go

fig0 = make_subplots(
    start_cell='bottom-left',
    rows=3,
    cols=2,
    shared_xaxes='all',
    shared_yaxes='all',
    vertical_spacing=0.02,
    horizontal_spacing=0.01,
    column_titles=('First', 'Second'),
    row_titles=['X', 'Y', 'Z'],
    x_title='Dimension A',
    y_title='Dimension B'
)
t = go.Scatter(y=[2, 3, 1])
fig0.add_traces([t]*6, rows=[1, 1, 2, 2, 3, 3], cols=[1, 2, 1, 2, 1, 2])
fig0.layout.margin.r = 0
fig0.layout.title.text = 'MAIN TITLE'
fig0

newplot (17)

Mixed type subplots with spanning, and print_grid=True to show how the spanned grid is now represented

from _plotly_future_ import v4
from plotly.subplots import make_subplots
import plotly.graph_objs as go

fig2 = make_subplots(rows=4, cols=3,
                    start_cell='top-left',
                    shared_yaxes=False,
                    column_width=[0.5, 1, 1],
                    insets=None,
                    horizontal_spacing=0.1,
                    column_titles=['One', 'Two', 'Three', 'Four'],
                    row_width=[2, 0.5, 0.5, 2],
                    specs=[
                        [{'type': 'polar'}, {}, {'type': 'scene'}],
                        [{'colspan': 3,
                          'rowspan': 2}, None, None],
                        [None, None, None],
                        [{'type': 'domain', 'colspan': 3, 't': 0.1}, None, None]],
                     print_grid=True
                    ).update(layout={'height': 900})
fig2.add_scatter3d(x=[1, 1, 1], y=[2, 1, 3], z=[2, 4, 8],  row=1, col=3)
fig2.add_scatter(y=[2, 1, 3], row=1, col=2)
fig2.add_scatter(y=[2, 1, 3], row=2, col=1)
fig2.add_scatterpolar(r=[2, 3, 1], theta=[0, 45, 90], row=1, col=1)
fig2.add_parcats(
    dimensions=[{'values': ['A', 'A', 'B'], 'label': 'One'},
                {'values': [1, 2, 1], 'label': 'Two'},
                {'values': ['X', 'Y', 'X'], 'label': 'Three'}],
    row=4, col=1
)
fig2
This is the format of your plot grid:
[ (1,1) polar1        ]  [ (1,2) xaxis1,yaxis1 ]  [ (1,3) scene2        ]
⎡ (2,1) xaxis2,yaxis2           -                        -              ⎤
⎣      :                        :                        :              ⎦
[ (4,1)                         -                        -              ]

newplot-1

Added plotly.subplots.make_subplots for use with v4_subplots future
flag.

Added figure.get_subplot() method to retrieve subplot objects
The subplot type is then chosen automatically to be the one that
is compatible with that trace type
@jonmmease jonmmease changed the title [WIP] Version 4 make_subplots Version 4 make_subplots Apr 19, 2019
@jonmmease
Copy link
Contributor Author

Merging for v3.8.1 so that folks can start trying this out, and since this doesn't change legacy behavior. This API/design will not be considered stable until the release of version 4.

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

Successfully merging this pull request may close these issues.

1 participant