Updating bqplot image widget - python-3.x

I'm working on a project that uses ipywidgets and bqplot to display and interact with an image.
Using ipywidgets and open cv I can modify an image, save it and update the value of the widget. But I also need the on_click_element aspect of bqplot, so I use the widget from the last one. I still have problems figuring out how to do the same thing with the widget in bqplot.
I would like to avoid to redraw the hole thing, but if needed it would have to close and redraw only the widget image since this is part of a bigger set of widgets. For example I would like to binarize the image using an arbitrary treshold.
From here I got the information on how to use the bqplot image widget: https://github.com/bqplot/bqplot/blob/master/examples/Marks/Object%20Model/Image.ipynb
I use something very similar to this to create the widget that I display.
from IPython.display import display
import ipywidgets as widgets
import bqplot as bq
with open('chelsea.png', 'rb') as f:
raw_image = f.read()
ipyimage = widgets.Image(value=raw_image, format='png')
x_sc = bq.LinearScale()
y_sc = bq.LinearScale()
bq_image = bq.Image(image=ipyimage, scales={'x':x_sc, 'y':y_sc})
img_ani = bq.Figure(marks=[bq_image], animation_duration=400)
display(img_ani)
After this I can't update the figure without redrawing the hole thing.
Any ideas?
jupyter 5.7.8,
ipython 7.5.0,
ipywidgets 7.5.1,
bqplot 0.12.10

Update the bqplot image mark by assigning a new image....
with open("chelsea2.png", 'rb') as f:
raw_image2 = f.read()
# ipyimage.value = raw_image2 # This doesn't seems to sync with widget display. Would require a redisplay of bqplot figure
# create new ipywidgets image and assign it to bqplot image
ipyimage2 = widgets.Image(value=raw_image2, format='png')
bq_image.image = ipyimage2

Related

Embedding Images and matplotlib Plots together on on tk canvas

A few years ago I wrote a script in python2 that would pull images and generate plots and show them together in one gui, following this old documentation. However, I'm trying to update this to python3, and I've run into an issue with the way that plots are put on tk windows in the latest version of matplotlib. There are updated guides for how to embed matplotlib graphs in tk windows, of course, but these don't seem to be exactly what I want, since I want to plot various images and graphs together.
Currently:
# Start by creating the GUI as root
root=Tk()
root.wm_title("JADESView")
# Create the canvas
canvas=Canvas(root, height=canvasheight, width=canvaswidth)
# Plot the EAZY SED
#image = Image.open(EAZY_files+str(current_id)+"_EAZY_SED.png")
image = getEAZYimage(current_id)
# Crop out the thumbnails
image = cropEAZY(image)
photo = resizeimage(image)
item4 = canvas.create_image(eazy_positionx, eazy_positiony, image=photo)
Label(root, text="EAZY FIT", font=('helvetica', int(textsizevalue*1.5))).place(x=eazytext_positionx, y = eazytext_positiony)
# Plot the BEAGLE SED
#new_image = Image.open(BEAGLE_files+str(current_id)+"_BEAGLE_SED.png")
new_image = getBEAGLEimage(current_id)
new_photo = resizeimage(new_image)
item5 = canvas.create_image(beagle_positionx, beagle_positiony, image=new_photo)
Label(root, text="BEAGLE FIT", font=('helvetica', int(textsizevalue*1.5))).place(x=beagletext_positionx, y = beagletext_positiony)
canvas.pack(side = TOP, expand=True, fill=BOTH)
# Plot the thumbnails
fig_photo_objects = np.empty(0, dtype = 'object')
fig_photo_objects = create_thumbnails(canvas, fig_photo_objects, current_id, current_index, defaultstretch)
I create a tk.canvas object, and then use canvas.create_image to place two PIL photo objects, with labels (the "EAZY SED" and BEAGLE SED"), and this still works with python3. However, the create_thumbnails function I've written creates individual figure objects and then calls a function "draw_figure" to embed them, which I'll post below, but it's from the tk example I linked above:
def draw_figure(canvas, figure, loc=(0, 0)):
""" Draw a matplotlib figure onto a Tk canvas
loc: location of top-left corner of figure on canvas in pixels.
Inspired by matplotlib source: lib/matplotlib/backends/backend_tkagg.py
"""
figure_canvas_agg = FigureCanvasAgg(figure)
figure_canvas_agg.draw()
figure_x, figure_y, figure_w, figure_h = figure.bbox.bounds
figure_w, figure_h = int(figure_w), int(figure_h)
photo = PhotoImage(master=canvas, width=figure_w, height=figure_h)
# Position: convert from top-left anchor to center anchor
canvas.create_image(loc[0] + figure_w/2, loc[1] + figure_h/2, image=photo)
# Unfortunately, there's no accessor for the pointer to the native renderer
tkagg.blit(photo, figure_canvas_agg.get_renderer()._renderer, colormode=2)
# Return a handle which contains a reference to the photo object
# which must be kept live or else the picture disappears
return photo
And this breaks in all sorts of ways.
I'm open to overhauling how everything is done, but I don't see examples that show how this sort of thing might work. The examples for the latest version of matplotlib all explain that you should use FigureCanvasTkAgg, but I don't exactly know how to use this if I already have an existing canvas with photos embedded.
Any help would be appreciated, and I can also explain more if necessary!

How to add background image to an tkinter application?

I recently made a Python watch application. But it looks very boring because of the one-color background and just nothing except of the time and the date. So I wanted to add background to the application. And I ran into a problem: If I just pack the image into a label, the other labels won't be transparent and will have their own background. I tried to use tkinter.Canvas, but it doesn't work with labels. Any suggestions?
That's the code for the first version of the app:
from tkinter import *
from time import sleep
from random import choice
import datetime
root=Tk()
BGCOLOR='#000000'
FGCOLOR='#FFFFFF'
root.overrideredirect(True)
w = root.winfo_screenwidth()
h = root.winfo_screenheight()
root.geometry(str(w)+'x'+str(h)+'+0+0')
root.configure(bg=BGCOLOR)
date=str(datetime.datetime.now()).split()[0].split('-')
tl=Label(root,text=str(datetime.datetime.now()).split()[1].split('.')[0],font=['URW Gothic L',300], fg=FGCOLOR, bg=BGCOLOR)
dl=Label(root,text=date[2]+'.'+date[1]+'.'+date[0],font=['URW Gothic L',100],bg=BGCOLOR,fg=FGCOLOR)
tl.pack(expand=True, fill=BOTH)
dl.pack(expand=True,fill=BOTH)
Button(master=root,text='X',bg=BGCOLOR,fg=FGCOLOR,command=root.destroy).pack(side=RIGHT)
while True:
tl.config(text=str(datetime.datetime.now()).split()[1].split('.')[0])
if date!=str(datetime.datetime.now()).split()[0].split('-'):
date=str(datetime.datetime.now()).split()[0].split('-')
dl.config(text=date[2]+'.'+date[1]+'.'+date[0])
dl.update()
tl.update()
sleep(1)
Ok, so the solution itself is, to create a Canvas object and use create_text() function with "fill" and "font" arguments. The best thing about this is that you can change the position of the text

Rendering a gltf/glb file in jupyter notebook using vtk and k3d

I have explored the available methods of how to render a gltf/glb file inline in a jupyter notebook to keep the viewer callback interactivity intact. I have eventually ended up using vtk and k3d to achieve this. The two hurdles I have are:
How to use the vtkGLTFReader() to get vtkPolyData objects from the
glb and render these in k3d? SOLUTION: See method posted in the comments.
How to display colors/textures embedded in the gltf/glb to show them in
k3d?
Here is the code to get vtkPolyData and pass it to k3d.
import k3d
import vtk
import ipywidgets as widgets
reader = vtk.vtkGLTFReader()
reader.SetFileName('sample_glb/GroundVehicle.glb')
reader.Update()
plot = k3d.plot()
mb = reader.GetOutput()
iterator = mb.NewIterator()
vtk_polyobjects = []
while not iterator.IsDoneWithTraversal():
item = iterator.GetCurrentDataObject()
vtk_polyobjects.append(item)
iterator.GoToNextItem()
for obj in vtk_polyobjects:
plot += k3d.vtk_poly_data(obj, color=0x222222)
plot.display()
debug_info = widgets.HTML()

Python Pillow ImageChops.difference always None

I'm trying to compare screenshots of 2 interactive maps. The screenshots are taken with Selenium and using Pillow to compare.
...
from selenium.webdriver.common.by import By
from selenium import webdriver
from io import BytesIO
from PIL import ImageChops, Image
...
png_bytes1 = driver.find_element(By.CSS_SELECTOR, "body").screenshot_as_png
png_bytes2 = driver2.find_element(By.CSS_SELECTOR, "body").screenshot_as_png
img1 = Image.open(BytesIO(png_bytes1))
img2 = Image.open(BytesIO(png_bytes2))
diff = ImageChops.difference(img1, img2)
print(diff.getbbox())
But diff is always blank. I manually used img1.show() and img2.show() to obtain the images below. diff.show() is always blank and diff.getbbox() prints None. What am I doing wrong and is there a better way of doing it?
Update: It works if I first save these images as jpg. Anyone have ideas why?
It seems ImageChops.difference() will only work if the image parameters are Image objects. PNG files are PngImageFile objects, with an RGBA mode for an extra alpha layer and need to be converted using converted_img1 = img1.convert('RGB').

Tkinter Background Image

I am not able to display an image as the background of my GUI window with the below code, any ideas? I have changed files extension types many times.
from tkinter import *
from PIL import ImageTk, Image
window = Tk()
window.title("My Application")
lbl = Label(window, text="Hello", font=("arial italic", 25))
lbl.grid(column=0, row=0)
backgroundImage = PhotoImage(file = "C:\\Users\\User
Person\\Desktop\\months.gif")
label = Label(master=window,
image = backgroundImage,
text='This is a test for stackflow',
height = 2
)
label.place(x=0, y=0, relwidth=1, relheight=1)
window.mainloop()
I am able to display an image with your code but I used a raw string to define the path for the gif image. You should use it like this:
backgroundImage = PhotoImage(file = r"C:\Users\User Person\Desktop\months.gif")
Notice the r" " which makes the image path a raw string, so you don't need to escape the \.
I also defined a window geometry:
window.title("My Application")
window.geometry("320x240")
Update:
As per comment, you can also use the PIL library to open the image first to fix the error Tkinter error: Couldn't recognize data in image file:
from PIL import ImageTk, Image
backgroundImage = ImageTk.PhotoImage(Image.open(r"C:\Users\User Person\Desktop\months.gif"))
Note:
You must also verify that this is a valid gif file. Try opening the file in Windows Picture viewer or similar software. Also, you mentioned that you have changed the file extension, this could make the file unstable and render it invalid. Therefore, make sure you use the original file extension. If you'd like to convert the file to a different format, use specialized software for that or write a simple Python script(although I've never tried this option) that could perform this conversion without breaking the file.

Resources