Skip to content

[Bug]: canvas.manager.set_window_title does not work to figure with WebAgg backend #29256

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

Closed
YongcaiHuang opened this issue Dec 8, 2024 · 4 comments · Fixed by #29338
Closed

Comments

@YongcaiHuang
Copy link

Bug summary

canvas.manager.set_window_title does not work to figure with WebAgg backend (but MacOSX). the title is still Figure 1 by default.

Code for reproduction

import matplotlib.pyplot as plt
import numpy as np
import matplotlib
matplotlib.use("WebAgg")

fig = plt.figure(figsize=(7, 5))
fig.canvas.manager.set_window_title("My figure")
ax = fig.add_subplot(111)

dx, dy = 0.05, 0.05
y, x = np.mgrid[slice(1, 5 + dy, dy),
slice(1, 5 + dx, dx)]
z = np.sin(x)**10 + np.cos(10 + y*x) * np.cos(x)

cf = ax.contourf(x + dx/2., y + dy/2., z)
fig.colorbar(cf, ax=ax)

plt.show()

Actual outcome

image

Expected outcome

image

Additional information

it works in MacOSX backends

image

Operating system

macOS Sequoia 15.1.1

Matplotlib Version

3.9.3

Matplotlib Backend

WebAgg

Python version

3.12.7

Jupyter version

No response

Installation

pip

@ianthomas23
Copy link
Member

Thanks for the report, it is an interesting bug!

When using the webagg backend the set_window_title initially does what you want which is to update the figure_label in the browser:

def set_window_title(self, title):
self._send_event('figure_label', label=title)
self._window_title = title

However on the next render, which is essentially immediate, the figure_label is reset to the contents of figure.get_label():

def handle_refresh(self, event):
figure_label = self.figure.get_label()
if not figure_label:
figure_label = f"Figure {self.manager.num}"
self.send_event('figure_label', label=figure_label)

For other backends such as qtagg the use of set_window_title does indeed set the title in the title bar of the window displaying the figure, and figure.set_label() (inherited from the Artist class) is used to uniquely identify the figure and is the default filename used when saving the figure, it is not used as a visual title anywhere.

I expect there has been some historical confusion here as webagg is different from most backends in that a figure is displayed in a browser tab and there are two possible titles here, one in the title bar of the tab and the other rendered at the top of the canvas in the page displaying the figure.

For consistency with other backends like qtagg I think the correct behaviour is to keep the set_window_title implementation as it is and change the handle_refresh to read self._window_title rather than self.figure.get_label(). But this will change the behaviour for anyone currently using figure.set_label to change the title.

An alternative fix is to keep the text above the figure in the web page as the figure label, and use set_window_title to set the text in the browser tab. This won't break anyone's current use of figure.set_label. AFAICT from an implementation point of view this would need another message type to be handled by lib/matplotlib/backends/web_backend/js/mpl.js which would set the document.title.

@QuLogic
Copy link
Member

QuLogic commented Dec 10, 2024

An alternative fix is to keep the text above the figure in the web page as the figure label, and use set_window_title to set the text in the browser tab. This won't break anyone's current use of figure.set_label. AFAICT from an implementation point of view this would need another message type to be handled by lib/matplotlib/backends/web_backend/js/mpl.js which would set the document.title.

WebAgg supports multiple figures in a single webpage; we can't map a single figure's title to the entire document.

@timhoffm
Copy link
Member

For consistency with other backends like qtagg I think the correct behaviour is to keep the set_window_title implementation as it is and change the handle_refresh to read self._window_title rather than self.figure.get_label(). But this will change the behaviour for anyone currently using figure.set_label to change the title.

I agree, this is the way to go.

AFAICS, the meaning of Figure.set_label is not documented anywhere. Technically it's inherited from Artist.set_label, which refers to legend labels. We have some internal code that repurposes it for figure, but that's not documented. More generally, label is a heavily overloaded term and we should try to use it less. Semi-related: #28584, where we disallowed Axis.set_label as that was also causing confusion.

@ianthomas23
Copy link
Member

Thanks @QuLogic and @timhoffm for the clarification. I should be able to come up a PR for this soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants