Skip to content

Secondary y-axis subplot support #1564

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

Merged
merged 18 commits into from
May 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions codegen/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,11 +491,16 @@ def add_docstring(buffer, node, header, prepend_extras=(), append_extras=()):

# Write any append extras
for p, v in append_extras:
v_wrapped = '\n'.join(textwrap.wrap(
v,
width=79-12,
initial_indent=' ' * 12,
subsequent_indent=' ' * 12))
if '\n' in v:
# If v contains newlines then assume it's already wrapped as
# desired
v_wrapped = v
else:
v_wrapped = '\n'.join(textwrap.wrap(
v,
width=79-12,
initial_indent=' ' * 12,
subsequent_indent=' ' * 12))
buffer.write(f"""
{p}
{v_wrapped}""")
Expand Down
125 changes: 102 additions & 23 deletions codegen/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,28 +107,72 @@ def __init__(self, data=None, layout=None,
# ### add_trace methods for each trace type ###
for trace_node in trace_nodes:

include_secondary_y = bool([
d for d in trace_node.child_datatypes
if d.name_property == 'yaxis'
])
if include_secondary_y:
secondary_y_1 = ', secondary_y=None'
secondary_y_2 = ', secondary_y=secondary_y'
secondary_y_docstring = f"""
secondary_y: boolean or None (default None)
* If True, only select yaxis objects associated with the secondary
y-axis of the subplot.
* If False, only select yaxis objects associated with the primary
y-axis of the subplot.
* If None (the default), do not filter yaxis objects based on
a secondary y-axis condition.

To select yaxis objects by secondary y-axis, the Figure must
have been created using plotly.subplots.make_subplots. See
the docstring for the specs argument to make_subplots for more
info on creating subplots with secondary y-axes."""
else:
secondary_y_1 = ''
secondary_y_2 = ''
secondary_y_docstring = ''

# #### Function signature ####
buffer.write(f"""
def add_{trace_node.plotly_name}(self""")

# #### Function params####
param_extras = ['row', 'col']
if include_secondary_y:
param_extras.append('secondary_y')
add_constructor_params(buffer,
trace_node.child_datatypes,
append_extras=['row', 'col'])
append_extras=param_extras)

# #### Docstring ####
header = f"Add a new {trace_node.name_datatype_class} trace"

extras = (('row : int or None (default)',
'Subplot row index (starting from 1) for the trace to be '
'added. Only valid if figure was created using '
'`plotly.tools.make_subplots`'),
('col : int or None (default)',
'Subplot col index (starting from 1) for the trace to be '
'added. Only valid if figure was created using '
'`plotly.tools.make_subplots`'))

add_docstring(buffer, trace_node, header, append_extras=extras)
doc_extras = [(
'row : int or None (default)',
'Subplot row index (starting from 1) for the trace to be '
'added. Only valid if figure was created using '
'`plotly.tools.make_subplots`'),
('col : int or None (default)',
'Subplot col index (starting from 1) for the trace to be '
'added. Only valid if figure was created using '
'`plotly.tools.make_subplots`')]

if include_secondary_y:
doc_extras.append(
('secondary_y: boolean or None (default None)', """\
If True, associate this trace with the secondary y-axis of the
subplot at the specified row and col. Only valid if all of the
following conditions are satisfied:
* The figure was created using `plotly.subplots.make_subplots`.
* The row and col arguments are not None
* The subplot at the specified row and col has type xy
(which is the default) and secondary_y True. These
properties are specified in the specs argument to
make_subplots. See the make_subplots docstring for more info.\
""")
)

add_docstring(buffer, trace_node, header, append_extras=doc_extras)

# #### Function body ####
buffer.write(f"""
Expand All @@ -143,18 +187,47 @@ def add_{trace_node.plotly_name}(self""")
buffer.write(f"""
**kwargs)""")

if include_secondary_y:
secondary_y_kwarg = ', secondary_y=secondary_y'
else:
secondary_y_kwarg = ''

buffer.write(f"""
return self.add_trace(new_trace, row=row, col=col)""")
return self.add_trace(
new_trace, row=row, col=col{secondary_y_kwarg})""")

# update layout subplots
# ----------------------
inflect_eng = inflect.engine()
for subplot_node in subplot_nodes:
singular_name = subplot_node.name_property
plural_name = inflect_eng.plural_noun(singular_name)

if singular_name == 'yaxis':
secondary_y_1 = ', secondary_y=None'
secondary_y_2 = ', secondary_y=secondary_y'
secondary_y_docstring = f"""
secondary_y: boolean or None (default None)
* If True, only select yaxis objects associated with the secondary
y-axis of the subplot.
* If False, only select yaxis objects associated with the primary
y-axis of the subplot.
* If None (the default), do not filter yaxis objects based on
a secondary y-axis condition.

To select yaxis objects by secondary y-axis, the Figure must
have been created using plotly.subplots.make_subplots. See
the docstring for the specs argument to make_subplots for more
info on creating subplots with secondary y-axes."""
else:
secondary_y_1 = ''
secondary_y_2 = ''
secondary_y_docstring = ''

buffer.write(f"""

def select_{plural_name}(self, selector=None, row=None, col=None):
def select_{plural_name}(
self, selector=None, row=None, col=None{secondary_y_1}):
\"\"\"
Select {singular_name} subplot objects from a particular subplot cell
and/or {singular_name} subplot objects that satisfy custom selection
Expand All @@ -172,8 +245,8 @@ def select_{plural_name}(self, selector=None, row=None, col=None):
Subplot row and column index of {singular_name} objects to select.
To select {singular_name} objects by row and column, the Figure
must have been created using plotly.subplots.make_subplots.
If None (the default), all {singular_name} objects are selected.

If None (the default), all {singular_name} objects are selected.\
{secondary_y_docstring}
Returns
-------
generator
Expand All @@ -184,9 +257,10 @@ def select_{plural_name}(self, selector=None, row=None, col=None):
_validate_v4_subplots('select_{plural_name}')

return self._select_layout_subplots_by_prefix(
'{singular_name}', selector, row, col)
'{singular_name}', selector, row, col{secondary_y_2})

def for_each_{singular_name}(self, fn, selector=None, row=None, col=None):
def for_each_{singular_name}(
self, fn, selector=None, row=None, col=None{secondary_y_1}):
\"\"\"
Apply a function to all {singular_name} objects that satisfy the
specified selection criteria
Expand All @@ -205,21 +279,25 @@ def for_each_{singular_name}(self, fn, selector=None, row=None, col=None):
Subplot row and column index of {singular_name} objects to select.
To select {singular_name} objects by row and column, the Figure
must have been created using plotly.subplots.make_subplots.
If None (the default), all {singular_name} objects are selected.
If None (the default), all {singular_name} objects are selected.\
{secondary_y_docstring}
Returns
-------
self
Returns the Figure object that the method was called on
\"\"\"
for obj in self.select_{plural_name}(
selector=selector, row=row, col=col):
selector=selector, row=row, col=col{secondary_y_2}):
fn(obj)

return self

def update_{plural_name}(
self, patch=None, selector=None, row=None, col=None, **kwargs):
self,
patch=None,
selector=None,
row=None, col=None{secondary_y_1},
**kwargs):
\"\"\"
Perform a property update operation on all {singular_name} objects
that satisfy the specified selection criteria
Expand All @@ -239,7 +317,8 @@ def update_{plural_name}(
Subplot row and column index of {singular_name} objects to select.
To select {singular_name} objects by row and column, the Figure
must have been created using plotly.subplots.make_subplots.
If None (the default), all {singular_name} objects are selected.
If None (the default), all {singular_name} objects are selected.\
{secondary_y_docstring}
**kwargs
Additional property updates to apply to each selected
{singular_name} object. If a property is specified in
Expand All @@ -251,7 +330,7 @@ def update_{plural_name}(
Returns the Figure object that the method was called on
\"\"\"
for obj in self.select_{plural_name}(
selector=selector, row=row, col=col):
selector=selector, row=row, col=col{secondary_y_2}):
obj.update(patch, **kwargs)

return self""")
Expand Down
Loading