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

Problem with viewer variable with multiple viewers and consolas #40

Open
Czaki opened this issue Dec 5, 2024 · 16 comments · May be fixed by #42
Open

Problem with viewer variable with multiple viewers and consolas #40

Czaki opened this issue Dec 5, 2024 · 16 comments · May be fixed by #42

Comments

@Czaki
Copy link
Contributor

Czaki commented Dec 5, 2024

We inject viewer variable into the console to allow a user to interact with the viewer.

However, if we have multiple viewers in a single process, the viewer variable will point to last viewer where we try to open the console (even if the second console do not show napari/napari#7413, that will be fixed in #39)

The variable is defined here:

user_variables = {'viewer': self.viewer}

It will be nice to find that there is already viewer variable defined in console and add viewer1 etc.

@dalthviz could you take a look?

@psobolewskiPhD
Copy link
Member

psobolewskiPhD commented Dec 7, 2024

I'm confused by the concepts here.
I tested a simple script:

import napari
v1 = napari.Viewer()
v2 = napari.Viewer()
napari.run()

and I was quite shocked when neither v1 nor v2 worked in either console.
But viewer worked in both and used the proper viewer, that associated with each console I was using--which I didn't expect based on this issue.
So to me the issue isn't how viewer works, but rather that the v1 and v2 I put in my script arn't pushed to the console(s) -- obviously I couldn't use viewer twice!

Other than a script the other way to get in a 2 viewer shared state is to launch napari from the terminal, which has a console, and use that console to make another viewer.
I did this with v2 = napari.Viewer() and got a second viewer with a console working. Surprisingly, v2 worked correctly there! But so did viewer -- in the 2nd viewer, either variable worked!
I made a data array and it was available in both consoles.
But viewer.add_image added it only to the 2nd viewer, regardless which viewer I used. So is this the nature of this issue??

@Czaki
Copy link
Contributor Author

Czaki commented Dec 7, 2024

After you open console in second viewer, did you try to interact with first viewer via console?

@jni
Copy link
Member

jni commented Dec 7, 2024

Yeah like @psobolewskiPhD, I don't understand why #18 didn't result in v1 and v2 being injected into the namespace... I think fixing that is more important than the workaround in #41 (though thank you @dalthviz!), and indeed I would remove the special-casing around the viewer — the viewer should have whatever variable name the script gave it.

@psobolewskiPhD
Copy link
Member

psobolewskiPhD commented Dec 7, 2024

After you open console in second viewer, did you try to interact with first viewer via console?

OK i retested this and indeed and it's quite strange!
If I start using v1 console, i can add and interact with that viewer no problem.
If I switch to v2 console, viewer.add_image adds to v2. OK. But after this, everything in the v1 console returns v2 info, e.g. v1.title.
If from the beginning I use viewer in the v2 console, then the v1 console always interacts with v2.

So yeah, the main thing is we need v1 and v2 pushed. Then I expect either console can interact with either viewer.

@Czaki
Copy link
Contributor Author

Czaki commented Dec 7, 2024

@dalthviz Maybe it will be possible to overwrite viewer variable when gain focus to console?

@dalthviz
Copy link
Member

dalthviz commented Dec 9, 2024

@dalthviz Maybe it will be possible to overwrite viewer variable when gain focus to console?

Will give that a try 👍 (maybe doing a focusInEvent method overide to add a call for shell.push 🤔)

If from the beginning I use viewer in the v2 console, then the v1 console always interacts with v2.

Also, to sumarize the expected behavior, the idea is for the corresponding variables defined in the script to point to their respective viewer while ensuring that the viewer variable points to the current viewer you are interacting with, right? If that is the case probably #41 should be closed, right?

@psobolewskiPhD
Copy link
Member

psobolewskiPhD commented Dec 9, 2024

If I did v1 = napari.Viewer() I wouldn't expect viewer to also work.
Using a simple case:

import napari
v1 = napari.Viewer()
napari.run()

When I open the console of that viewer, v1 doesn't work with NameError: name 'v1' is not defined but viewer does.
I think this is very unintuitive and I consider this a bug.

Edit: if the user doesn't provide a name, then defaulting to viewer makes sense.

@dalthviz
Copy link
Member

dalthviz commented Dec 9, 2024

When I open the console of that viewer, v1 doesn't work with NameError: name 'v1' is not defined

Oh so for you the variable in the script is not working? Checking the simple case with only one viewer I'm able to access the viewer via v1 and viewer when running the console from main, in fact if I do v1 == viewer I get True:

imagen

Maybe the variable is working for my due to the way I'm running the script (from a cmd running python script.py)? 🤔 Are you running the script in a somehow different way @psobolewskiPhD ?

@psobolewskiPhD
Copy link
Member

I'm also using python test.py
I have:

Name: napari-console
Version: 0.1.1

and napari from main.

@dalthviz
Copy link
Member

dalthviz commented Dec 9, 2024

I'm being unable to reproduce that behavior :/ (for me the variables over the script work) From what I understand #18 should have enabled the use of script variables in the console, right? Maybe there are some setups/cases where the implementation done there doesn't work? 🤔 Could it be worthy to open a new issue for that then?

@psobolewskiPhD
Copy link
Member

I just did a fresh env, pip install "napari[all]"
I got napari-console 0.1.2 and I tested

import napari
my_var = "tada!"
v1 = napari.Viewer()
napari.run()

This works, I can access v1 and my_var from the console. viewer as well.

@psobolewskiPhD
Copy link
Member

psobolewskiPhD commented Dec 9, 2024

I just retested in the new env with

import napari
my_var = "tada!"
v1 = napari.Viewer(title="v1")
v2 = napari.Viewer(title="v2")
napari.run()

I can access v1 and v2 in either console and both work just fine.
SO it's just viewer that is odd: here is the v2 console:

In [3]: viewer.title        # v2 console
Out[3]: 'v2'

Then jump to v1 console:

In [4]: viewer.title          # switched to v1 console
Out[4]: 'v1'

Back to v2 console:

viewer.add_image(data2)
Out[5]: <Image layer 'data2' at 0x16e3cbfe0>
viewer.title
Out[6]: 'v1'

The image opened in v1 viewer, despite typing in v2.

@dalthviz
Copy link
Member

I can access v1 and v2 in either console and both work just fine.

Awesome! 🎉

SO it's just viewer that is odd

I opened PR #42 which should take care of that. There the viewer variable gets updated to point to the viewer of the current console being used (idea pointed out at #40 (comment)). Let me know if that approach and if the interaction with the variables previewed there makes sense!

@psobolewskiPhD
Copy link
Member

psobolewskiPhD commented Dec 10, 2024

I made a fresh dev env:
pip install -e .[dev, pyqt6]
and v1 and v2 don't work...

but with pip install napari[all] it works.
with pip install -e .[all] it also works!
edit: pip install -e .[dev, pyqt] also works!
with pip install -e .[pyqt6] it doesnt work. So looks like some pyqt6 compatibility? or am I going crazy?

napari --info for the one that doesn't work:

napari: 0.5.4rc4.dev56+gfe19b7eb6
Platform: macOS-14.5-arm64-arm-64bit
System: MacOS 14.5
Python: 3.12.8 | packaged by conda-forge | (main, Dec  5 2024, 14:19:53) [Clang 18.1.8 ]
Qt: 6.7.1
PyQt6: 
NumPy: 2.2.0
SciPy: 1.14.1
Dask: 2024.12.0
VisPy: 0.14.3
magicgui: 0.9.1
superqt: 0.6.7
in-n-out: 0.2.1
app-model: 0.3.1
psygnal: 0.11.1
npe2: 0.7.7
pydantic: 2.10.3

OpenGL:
  - GL version:  2.1 Metal - 88.1
  - MAX_TEXTURE_SIZE: 16384
  - GL_MAX_3D_TEXTURE_SIZE: 2048

Screens:
  - screen 1: resolution 1680x1050, scale 2.0

Optional:
  - numba not installed
  - triangle not installed
  - napari-plugin-manager not installed

Settings path:
  - /Users/piotrsobolewski/Library/Application Support/napari/nap-pip_ff87c3a6a7e4231e9f8a045782cc90c38d85a77f/settings.yaml
Plugins:
  - napari: 0.5.4rc4.dev56+gfe19b7eb6 (81 contributions)
  - napari-console: 0.1.2 (0 contributions)
  - napari-svg: 0.2.0 (2 contributions)

@dalthviz
Copy link
Member

I was able to reproduce the missing variables when using PyQt6! From a quick check, seems like adding qtpy. to the _PREF_LIST constant (which is used over the _in_napari method and the logic to capture variables) helps. Will add a commit with the change over #42

@psobolewskiPhD
Copy link
Member

Crosslinking: napari/napari#1530 : clobbering viewer with multiple consoles.
Also this comment from Talley: napari/napari#787 (comment) check if viewer is in globals and don't clobber.

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