Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 7, 2025

Summary: Add subplot_titles, title, and titles_as_subtitles to make_subplots

This PR implements three new parameters for deephaven-plotly-express make_subplots function to provide better control over subplot titles, similar to plotly's API.

Changes:

  1. Added subplot_titles parameter: Accepts a list or tuple of titles for subplots, ordered from left to right, top to bottom
  2. Added titles_as_subtitles parameter: Boolean flag to automatically extract and use titles from input figures as subplot titles
  3. Added title parameter: Sets an overall title for the combined subplot figure

Implementation Details:

  • Created helper functions:
    • extract_title_from_figure: Extracts titles from Figure or DeephavenFigure objects (always returns string)
    • map_user_index_to_grid_position: Maps user indices to internal reversed grid positions
    • create_subplot_annotations: Generates plotly annotations for subplot titles
    • get_subplot_titles: Consolidates title extraction logic based on parameters
  • Updated atomic_layer to accept subplot_annotations and overall_title parameters
  • Updated layer to accept title parameter (passes as overall_title to atomic_layer)
  • Annotations and title are applied directly in atomic_layer instead of through unsafe_update_figure
  • Updated both atomic_make_subplots and make_subplots function signatures
  • Added validation to prevent using both subplot_titles and titles_as_subtitles together
  • Properly handles grid reversal (plotly uses bottom-to-top coordinate system)
  • Handles empty strings and whitespace-only strings correctly
  • Automatically truncates excess titles if too many are provided
  • Works for both list of figures and grid layouts

Tests:

Added 8 comprehensive test cases covering:

  • Basic subplot_titles functionality
  • Empty and whitespace title handling
  • Automatic title extraction with titles_as_subtitles
  • Overall title functionality
  • Combining subplot titles with overall title
  • Grid layout support
  • Error handling for conflicting options
  • Title truncation behavior

Documentation:

Updated sub-plots.md with 4 new examples demonstrating:

  • Adding subplot titles
  • Using existing titles as subtitles
  • Adding an overall title
  • Combining features

All code is formatted with black and passes ruff linting.

Original prompt

Add the subplot_titles argument to make_subplots in deephaven-plotly-express. It should be similar to plotly's. It should take a list or tuple or similar and apply the subtitles to the subcharts. Note that it should work either for a list of figures or the grid. Additionally, add a way to maintain the existing titles as subplot titles instead of having to pass in titles again, perhaps a boolean option. Also add a new title argument for the overall chart title. Make sure to add tests and documentation.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI changed the title [WIP] Add subplot_titles argument to make_subplots Add subplot_titles, use_existing_titles, and title parameters to make_subplots Nov 7, 2025
Copilot AI requested a review from jnumainville November 7, 2025 21:21
Copilot finished work on behalf of jnumainville November 7, 2025 21:21
'b' is a float that adds bottom padding
'rowspan' is an int to make this figure span multiple rows
'colspan' is an int to make this figure span multiple columns
subplot_titles: (Default value = None)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to provide defaults like this in the docs. Any existing form of this can be considered incorrect.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed default value annotations from docstrings in commit eaed59c.

is desired in that space. Cannot be used with use_existing_titles.
use_existing_titles: (Default value = False)
If True, automatically extracts and uses titles from the input figures
as subplot titles. Cannot be used with subplot_titles.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want a more specific name for use_existing_titles that makes what the parameter does clear. How about titles_as_subtitles.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to titles_as_subtitles for better clarity in commit eaed59c.


### Adding Subplot Titles

You can add titles to individual subplots using the `subplot_titles` parameter. Provide a list or tuple of titles in row-major order.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"row-major" is a bit too jargony. Use simpler language for this term.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to use simpler language: "ordered from left to right, top to bottom" in commit eaed59c.

Comment on lines 412 to 439
if use_existing_titles:
# Extract titles from existing figures
# Since grid is already reversed, we need to extract in reversed order
# to get titles in natural top-to-bottom order
for fig_row in reversed(grid):
for fig in fig_row:
if fig is None:
final_subplot_titles.append("")
else:
extracted_title = extract_title_from_figure(fig)
# Explicitly check for None to handle empty strings correctly
final_subplot_titles.append(
extracted_title if extracted_title is not None else ""
)
elif subplot_titles is not None:
# Convert to list if tuple
final_subplot_titles = list(subplot_titles)

# Validate and adjust length if needed
total_subplots = rows * cols
if len(final_subplot_titles) > total_subplots:
# Truncate if too many titles provided
final_subplot_titles = final_subplot_titles[:total_subplots]
elif len(final_subplot_titles) < total_subplots:
# Pad with empty strings if too few titles provided
final_subplot_titles.extend(
[""] * (total_subplots - len(final_subplot_titles))
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic seems overly complex. It could be combined into a generator, and at the very least it should be put into a function so it matches the level of abstraction as the existing function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracted into get_subplot_titles helper function for better abstraction in commit eaed59c.

Comment on lines 441 to 467
# Create the custom update function to add annotations and title
def custom_update_figure(fig: Figure) -> Figure:
# Add subplot title annotations if any
if final_subplot_titles:
annotations = create_subplot_annotations(
final_subplot_titles,
col_starts,
col_ends,
row_starts,
row_ends,
rows,
cols,
)

# Get existing annotations if any
existing_annotations = (
list(fig.layout.annotations) if fig.layout.annotations else []
)
fig.update_layout(annotations=existing_annotations + annotations)

# Add overall title if provided
if title:
fig.update_layout(title=title)

# Apply user's unsafe_update_figure if provided
result = unsafe_update_figure(fig)
return result if result is not None else fig
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be structured this way. The functionality should be within atomic_layer itself rather than trying to use the unsafe update in this way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved annotation and title logic directly into atomic_layer via new subplot_annotations and overall_title parameters in commit eaed59c.


# Add overall title if provided
if title:
fig.update_layout(title=title)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should also be an argument to layer

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added overall_title parameter to both atomic_layer and layer functions in commit eaed59c.

@jnumainville
Copy link
Collaborator

@copilot address comments

- Rename use_existing_titles to titles_as_subtitles for clarity
- Remove default value annotations from docstrings
- Extract title handling logic into get_subplot_titles helper function
- Move annotation and title application from unsafe_update_figure to atomic_layer
- Add subplot_annotations and overall_title parameters to atomic_layer and layer
- Update documentation to use simpler language (left to right, top to bottom instead of row-major)
- Update all tests to use titles_as_subtitles
- Simplify extract_title_from_figure to always return string

Co-authored-by: jnumainville <[email protected]>
Copilot AI changed the title Add subplot_titles, use_existing_titles, and title parameters to make_subplots Add subplot_titles, titles_as_subtitles, and title parameters to make_subplots Nov 7, 2025
Copilot AI requested a review from jnumainville November 7, 2025 22:02
Copilot finished work on behalf of jnumainville November 7, 2025 22:02
Used to add any custom changes to the underlying plotly figure. Note that
the existing data traces should not be removed. This may lead to unexpected
behavior if traces are modified in a way that break data mappings.
overall_title:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should just be title

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to title in commit 10b6052.

Comment on lines 360 to 361
elif len(titles) < total_subplots:
titles.extend([""] * (total_subplots - len(titles)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to pad the list. If there is less than expected, there will just be no annotations there anyways, which get skipped later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed padding logic - annotations are skipped for missing titles in commit 10b6052.

cols,
)

return atomic_layer([""] * (total_subplots - len(final_subplot_titles)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this call of atomic_layer seems like it shouldn't be here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed erroneous duplicate return statement in commit 10b6052.

@jnumainville
Copy link
Collaborator

@copilot address comments

- Rename 'overall_title' parameter to 'title' in layer function
- Remove unnecessary padding logic from get_subplot_titles (annotations are skipped for missing titles anyway)
- Remove erroneous duplicate return statement in atomic_make_subplots

Co-authored-by: jnumainville <[email protected]>
Copilot AI requested a review from jnumainville November 7, 2025 22:24
Copilot finished work on behalf of jnumainville November 7, 2025 22:24
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.

2 participants