pypulseq icon indicating copy to clipboard operation
pypulseq copied to clipboard

PyQt5 requirement for Ubuntu/Linux systems

Open sairamgeethanath opened this issue 8 months ago • 3 comments

Describe the bug seq.plot() does not display graphs

To Reproduce On Ubuntu 22.04. LTS run write_gre.py with plot=True

Expected behavior No plot shows

Screenshots NA

Desktop (please complete the following information):

  • OS: Ubuntu
  • OS Version: 22.04. LTS
  • pypulseq version: 1.4.2

Additional context Adding PyQt5 package solves the issue.

sairamgeethanath avatar Apr 01 '25 15:04 sairamgeethanath

This is more relevant to Matplotlib rather than PyPulseq. Matplotlib supports many "backends", PyQt5 is just one of them. Users should be able to pick whichever backend they want. Most Python installations come with Tkinter, so plots should be able to shown without installing any additional dependency using Tkinter.

Documentation showing how to configure backends: https://matplotlib.org/stable/users/explain/figure/backends.html

If you configure matplotlib to use TkAgg using any of the recommended configuration options, you should be able to see the plots without installing PyQt.

btasdelen avatar Apr 01 '25 16:04 btasdelen

That sounds like a good idea. If you don't want to make the env heavy then it is best to introduce an argument for the mpl_backend in the seq.plot() definition.

def plot( self, label: str = str(), show_blocks: bool = False, save: bool = False, time_range=(0, np.inf), time_disp: str = 's', grad_disp: str = 'kHz/m', plot_now: bool = True, mpl_backend = 'default_method', ) -> None:

Implement using matplotlib.use()

The consequence of not handling via a package or the mpl_backend argument is code breaking (read as no plots displayed when plot=True). Any other alternate is fine too, just want to make sure that the code does not break for these different scenarios.

sairamgeethanath avatar Apr 02 '25 11:04 sairamgeethanath

I looked into this some time ago. I checked projects that are dealing with matplotlib as well. I could not see a nice way of handling this, without forcing a specific backend.

I don't think calling use() inside plot() is a good solution. If the user or calls a plot with a different backend then default_method before calling our plot() function, it will also cause an error. Automatically setting a sane backend is already being done by matplotlib, and it usually fails when there is no available one, so I don't see how we can improve on that.

These are the two potential solutions I can think of:

  1. We can provide an optional dependency on PySide6 on pyproject.toml, then someone can install via pip install pypulseq[Qt], for example, it will ensure an interactive backend is available.
  2. We can check if the active backend is non-interactive and print a warning (I believe matplotlib already should print such a warning, but in case it is not clear):
import matplotlib

current_backend = matplotlib.get_backend()
print(f"Current Matplotlib backend: {current_backend}")

non_interactive_backends = ['agg', 'pdf', 'ps', 'svg', 'cairo']

if current_backend.lower() in non_interactive_backends:
    print("A non-interactive backend is currently selected.")
else:
    print("An interactive backend is currently selected.")

#323 might be a good PR to add this check.

I feel like this is a more common problem nowadays because distros are dropping Tkinter from their Python distributions.

btasdelen avatar Nov 10 '25 19:11 btasdelen