This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
scene updating every second
i am trying to animate a series of png images computed with pythonista. I would like to display 1 image every second, and record the film with the ipad record, so i try to customize the scene example of the doc. But nothing works, i keep getting stupid errors, probably my bad.
Can anyone help? Thanks.
here is a code with no error, but the view_update is never called
# coding: utf-8 from scene import * import ui import photos from PIL import Image import io as io def pil2ui(pil_img): with io.BytesIO() as buffer: pil_img.save(buffer, format='PNG') return ui.Image.from_data(buffer.getvalue()) def view_update(): azim -= 10 file = 'CieLuv_'+str(azim)+'.png' print(file) im = Image.open(file) ui_image = pil2ui(im) class MyScene (Scene): global ui_image,t0,azim def setup(self): self.background_color = 'ligtgray' img = ui.Button(name='image') img.frame = (25, 50, 1476/1.5, 1024/1.5) #1476 1024 img.background_image = ui_image img.enable = False img.hidden = False self.view.add_subview(img) # trying to update 1 per second self.view.update_interval = 1 self.view.update = view_update def disp_photo(self,sender): img = sender.superview['image'] img.hidden = not img.hidden if __name__ == '__main__': global ui_image, azim im = Image.open("CieLuv_-10.png") ui_image = pil2ui(im) azim = 190 run(MyScene())
cvp last edited by cvp
@jmv38 the refresh method of a scene is update. You have mixed with view.update of an ui.View.
See animation sub-folder of examples
Perhaps it could be better that instead of a Scene, you use a ui.View.
In this cases, setup becomes the init, and the code of your view_update can be put in def update of the custom view class.
@cvp thanks, i’ll have a look.
The problem is that with Scene or ui.View some fair amount a background is needed to get it work smoothly. I wish i could just tweek a couple lines in an example and get what i need. The built in example are a bit too complex for that.
Thanks anyway. And happy new year!
also searching in the forum with keywords really leads me nowhere. The search engine does not seem very smart, cause i am fairly sure i saw that kind of problems disucussed in the past, but i dont get any usefull link...
with scene + update, how can i trigger something once per second? When i try to use globals to keep track of a global state t, i keep getting some ‘local variable t used before being assigned’ , although it is global and assigned in the main... I pbly dont get fully how python namespaces work or in which order things are called, so i am stuck.
btw, for anyone interested, here is the kind of video i want to make
this one i made by assembling the images manually with Splice, i am trying to make it more automatic.
mikael last edited by
@jmv38, if you use a View, you can set its
update_intervalto 1 (second), and its
updatemethod gets automatically called once per second.
Also, for better results, use Google to search instead of the forum search.
JonB last edited by JonB
you want to avoid globals in Scenes -- make those variables methods of your scene. The way threads work in scene, I think as written you could have issues.
by the way, most scene examples use run(amyScene()), but you are allowed to do:
s=MyScene(someparams,that,your,init,accepts) s.someattrib=value run(s)
JonB last edited by
Also, take a look at the scene docs.
You need to implement either a draw method, which is called once per frame (and you would use scene_drawing.image method, using a set of images where you prefiously called load_pil_image to precache inages), or else you would use update to set spritenode texture. the scene.run method takes a frame_interval parameter to set fps.
you may define a custom init that sets scene attributes etc based on globals -- but setup might not have access to globals (not sure if this is still true -- but it does run in a separate thread). Use setup just to handle actual display stuff,
Depending in how many images you have, it might be worth creating all your SpriteNodes up front.
thanks for your advices. I chose to go for the ui.view. It worked nicely https://youtu.be/Li5gV2tUj5M
(make sure to set 1080p when you watch the video, otherwise the quality is bad)
here is the code
import ui from console import clear from PIL import Image import io as io def pil2ui(pil_img): with io.BytesIO() as buffer: pil_img.save(buffer, format='PNG') return ui.Image.from_data(buffer.getvalue()) class MyView (ui.View): def __init__(self): # global view settings self.name = 'Viewing where colors lie in the CIE L*u*v* color space' self.background_color = 'gray' # trying to update 1 per second self.update_interval = 1 # image settings img = ui.Button(name='image') img.width = 1476/1.5 img.height = 1024/1.5 img.enable = False img.hidden = False self.add_subview(img) self.img = img # add a copyright txt = ui.Label() txt.text = 'copyright JMV38 2019' txt.text_color = (0.5, 0.5, 0.5, 0.2) txt.width = 600 txt.height = 100 txt.alignment = ui.ALIGN_CENTER fontName, fontSize = txt.font txt.font = (fontName,30) self.add_subview(txt) self.txt = txt def update(self): self.img.center = (self.width * 0.5, self.height * 0.5) self.txt.center = (self.width * 0.5, self.height * 0.5) try: self.azim -= 10 except: self.azim = 180 file = 'CieLuv_'+str(self.azim)+'.png' try: print(file) im = Image.open(file) ui_image = pil2ui(im) self.img.background_image = ui_image except: exit() if __name__ == '__main__': clear() view = MyView() view.present('full_screen')
mikael last edited by
@jmv38, nice! Have you tried updating every 1/30 or even 1/60 sec and making it completely smooth?
1/ i have not computed enough intermediate frames (each take 30s on my ipad air)
2/ i use the video to view it frame by frame from the ipad photo roll, to turn around as i wish, so it is enough for my usage
3/ i have tried 0.5s once but it skipped 1 frame in the middle, so i thought i would remain at 1 Hz.
still in trouble.
I am trying to save my numpy structured array with np.save, here is the code for details
# differents tests avec Luv from labColor import * import numpy as np from console import clear # compute all colors def getAllColors(step): dtype = [('L', float), ('u', float), ('v', float), ('c', tuple), ('d', float)] data =  for r in np.arange(0, 256, step): print(r) for g in np.arange(0, 256, step): for b in np.arange(0, 256, step): L, u, v = rgb_to_sLuv(r, g, b) data.append((L, u, v, (r/255,g/255,b/255), 0.0)) ar = np.array(data,dtype=dtype) return ar clear() ar = getAllColors(50) print(len(ar)) print(ar.dtype) np.save('rgb.npy',ar) a = np.load('rgb.npy') print(len(a)) print(a.dtype)
but i get this error
Traceback (most recent call last): File "/private/var/mobile/Containers/Shared/AppGroup/..../Pythonista3/Documents/couleurs/labColor6.py", line 24, in <module> np.save('rgb.npy',ar) File "/var/containers/Bundle/Application/..../Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/numpy/lib/npyio.py", line 451, in save format.write_array(fid, arr) File "/var/containers/Bundle/Application/.../Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/numpy/lib/format.py", line 407, in write_array pickle.dump(array, fp, protocol=2) _pickle.PicklingError: Can't pickle <built-in function _reconstruct>: import of module 'multiarray' failed
what am i doing wrong?
ok i got it. numpy.save cannot decode tuples by itself...
surprising that there is no simple way to save a structured array, and that i must flatten the structure to save it. Extra work and risk of errors... Anyway...
here is another video, technically more useful