nglviewer / nglview

Jupyter widget to interactively view molecular structures and trajectories
http://nglviewer.org/nglview/latest/
Other
788 stars 132 forks source link

follow up problem on rendering data and saving it to file ( based on FAQ: How to make nglview view object write PNG file?) #1087

Closed luhtzia closed 5 months ago

luhtzia commented 7 months ago

first cell

view_a = nv.show_mdanalysis(prot, default_representation=False) #structure
for item in ALL_BTB:
    view_a.add_cartoon(item.residues,color="green") #coordinates  
for item in ALL_PEI2:
    view_a.add_surface(item.residues, color="lightgrey",opacity=0.5,depthWrite=True)
view_a.add_unitcell()
view_a.center()

examples of the second cell

example A (working)

works

def generate_images(v=view_a):
    v.clear()
    v.frame=10
    for item in ALL_BTB:
        v.add_cartoon(item.residues,color="green") #coordinates
    for item in ALL_PEI2:
        v.add_surface(item.residues, color="lightgrey",opacity=0.5,depthWrite=True)
    v.add_unitcell()
    v.center()
    im0 = v.render_image()
    v.clear()
    v.frame=20
    for item in ALL_BTB:
        v.add_cartoon(item.residues,color="green") #coordinates
    for item in ALL_PEI2:
        v.add_surface(item.residues, color="lightgrey",opacity=0.5,depthWrite=True)
    v.add_unitcell()
    v.center()
    im1 = v.render_image()
    for im in [im0, im1]:
        while not im.value:
            time.sleep(0.1)
    print('hehe')
    for n, im in zip('GH', [im0, im1]):
        with open(f'figure_{n}.png', 'wb') as fh:
            fh.write(im.value)
import threading
thread = threading.Thread(
    target=generate_images,
)
thread.daemon = True
thread.start()

example B (not working)

doesn't work with above

def generate_images(v=view_a):
    l=[]
    for n in np.arange(0,6,2):
        print(n)
        v.clear()
        v.frame=int(n)
        for item in ALL_BTB:
            v.add_cartoon(item.residues,color="green") #coordinates
        for item in ALL_PEI2:
            v.add_surface(item.residues, color="lightgrey",opacity=0.5,depthWrite=True)
        v.add_unitcell()
        v.center()
        im0 = v.render_image()
        l.append(im0)
        im0=None
        v.clear()
    for im in l:
        while not im.value:
            time.sleep(0.1)
    for n, im in zip('FOU', l):
        with open(f'figure_{n}.png', 'wb') as fh:
            fh.write(im.value)

import threading
thread = threading.Thread(
    target=generate_images,
)
thread.daemon = True
thread.start()
hainm commented 7 months ago

@luhtzia Please try to sleep after calling v.frame=int(n) (this is non-blocking)

luhtzia commented 7 months ago

@hainm that doesn't make a difference, unfortunately - still identical images are being saved

hainm commented 7 months ago

@hainm that doesn't make a difference, unfortunately - still identical images are being saved

@luhtzia Can you please provide a full example (with input files if needed) so I can reproduce and play with it? thanks

luhtzia commented 7 months ago

@hainm thank you - I uploaded everything as an example here: https://seafile.rlp.net/d/56a4a0caa4764ba9a146/

def generate_images(v=view_b): 
    l=[]
    for n in np.arange(0,20,5):
        print(n)
        v.clear()
        v.frame=int(n)
        time.sleep(5)
        for item in ALL_BTB:
            view_b.add_cartoon(item.residues,color="green") #coordinates

        for item in ALL_BACK:
            view_b.add_cartoon(item.residues,color="orange") #coordinates

        for item in ALL_PEI1:
            view_b.add_surface(item.residues, color="lightblue",opacity=0.1,depthWrite=True)

        for item in ALL_PEI2:
            view_b.add_surface(item.residues, color="lightgrey",opacity=0.1,depthWrite=True)
        v.add_unitcell()
        v.center()
        im0 = v.render_image()
        time.sleep(5)
        l.append(im0)
        im0=None
        v.clear()
    for im in l:
        while not im.value:
            time.sleep(0.1)
    for n, im in zip('ABCD', l):
        with open(f'figure_{n}.png', 'wb') as fh:
            fh.write(im.value)

import threading
thread = threading.Thread(
    target=generate_images,
)
thread.daemon = True
thread.start()
hainm commented 7 months ago

however if I let this run while moving to a different tab the files are saved only once I return to the tap and I get the issue with identical figures: W,X,Y,Z (see example folder). Is there a solution such that I can execute this in the background?

What does "moving to a different tab" mean? does this mean your execute another Python code in another tab. This won't work for python. Basically, we are using thread for run the rendering code. This code has sleep period, and when you run code in another tab, this will block the code execution from the generate_images, so nothing will be actually done. So you will end up get the same image as the first one. There is no currently solution for this and I don't know (yet) how to run thing in background. Working with asynchronous code is hard and I am not good at that.

in all cases the view is a little different in every image saved - how can I define and fix this?

I think it's because you call center multiple times. May be try to only call one right after creating the view?

Basically add center here

image

And remove it from here:

image

PS: try to sleep less first, instead of 5s.

luhtzia commented 7 months ago

@hainm no with moving to a different tab I meant moving away from the tab where I run the jupyter lab to e.g. writing an email in a different tab, not executing any other python code. I figured out this is related to Firefox though and I can do that when using Chromium, also the rendering of the same image over and over again seems to be related to Firefox. Im using Chromium now and I run a test case with a more realistic example (see test_rendering.jpynb in the provided folder), but unlike in example_rendering.ipynb it is not saving any files. I like nglview very much - but I've been spending a vast amount of time trying to get a rendering in order to create a movie out of my views. Is what you're saying that I need to make sure that there is no other python process running on my machine at the same time?

hainm commented 7 months ago

Is what you're saying that I need to make sure that there is no other python process running on my machine at the same time?

I mean about try not to run another python code in the same notebook you are using while rendering.

I figured out this is related to Firefox

I see. I am using Chrome.

but I've been spending a vast amount of time trying to get a rendering in order to create a movie out of my views.

Good luck with this. If you have a good idea, feel free to share. thanks.

luhtzia commented 7 months ago

@hainm thank you - I will have a look, are you seeing an obvious difference between test_rendering.jpynb and example_rendering.ipynb here: https://seafile.rlp.net/d/56a4a0caa4764ba9a146/ ? what is the current status of the movie maker ansatz?

hainm commented 7 months ago

@luhtzia it's due to your Python code, IMO. lab=str(int(n)) doesn't work. I think this is a limitation of using thread to execute the function. The error won't be raised if having a code error.

Good luck with debugging.