Create a napari widget that can display an image - python-napari

I want a napari widget that can display an image, e.g. for permanent display of a fixed colormap.
The goal is to have a widget that can read an image file e.g. .png or .jpg from a file and display it in one of the docking areas to the right or left inside the napari viewer.

A simple widget can be implemented using PyQt5:
import sys
from PyQt5.QtWidgets import QApplication, QLabel
from PyQt5.QtGui import QPixmap
class ImageWidget(QLabel):
"""
A QLabel widget that displays an image from a file
"""
def __init__(self, parent=None):
"""
Initialize the ImageWidget
"""
super().__init__(parent)
def set_image(self, file_path):
"""
Set the image of the widget from a file path
Parameters:
file_path (str): path to the image file
"""
pixmap = QPixmap(file_path)
self.setPixmap(pixmap)
# Create an instance of the ImageWidget
image_widget = ImageWidget()
# Set the image to be displayed in the widget
image_widget.set_image('colormap_white.png')
This widget can be used by adding it to the dock area of the napari viewer:
viewer.window.add_dock_widget(image_widget,area="left")
The result can look like this:

Related

Monitor Changing file in python

How to create a program that monitors a file (for example, text, and when you wrote something new to this file, the program should output that something was added to the file, and when, on the contrary, part of the text was deleted from it, it should write that something was deleted
And it should print to the console exactly which words were deleted or added?
Explanation
I use watchdog to follow the file.
On instantiation of the handler, I read the file's size.
When the file is modified, watchdog calls the on_modified function.
When this method is called, I compare the file's current size to its previous size to determine if the change was additive or subtractive.
You have a few other options when it comes to tracking the file. For example, you could also compare:
the number of lines
the number of words
the number of characters
the exact contents of the file
import os
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class EventHandler(FileSystemEventHandler):
def __init__(self, file_path_to_watch):
self.file_path_to_watch = file_path_to_watch
self._file_size = self._read_file_size()
def _read_file_size(self):
return os.path.getsize(self.file_path_to_watch)
def _print_change(self, new_file_size):
if new_file_size > self._file_size:
print('File modified with additions')
elif new_file_size < self._file_size:
print('File modified with deletions')
def on_modified(self, event):
if event.src_path != self.file_path_to_watch:
return
new_file_size = self._read_file_size()
self._print_change(new_file_size)
self._file_size = new_file_size
if __name__ == "__main__":
file_to_watch = '/path/to/watch.txt'
event_handler = EventHandler(file_to_watch)
observer = Observer()
observer.schedule(event_handler, path=file_to_watch, recursive=False)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()

remove_widget kivy do not remove by name

I have this code, and I can’t remove the widget when I use the name of this widget: MainApp(). m.remove_widget (Butt()).
I understand that I am accessing this widget incorrectly, but I do not understand how to do it correctly.
Tell me how to remove a widget using its name?
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.colorpicker import ColorPicker
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
class Butt(Button):
def add_wid1(self):
MainApp.m.add_widget(Box())
MainApp.m.add_widget(Butt1())
class Butt1(Button):
def on_press(self):
print('111')
MainApp().m.remove_widget(MainApp().m.children[1]) #this code works
MainApp().m.remove_widget(Butt()) #this code not working
class Box (ColorPicker):
size_hint=.50, .25
class Pict (Widget):
pass
class MainApp (App):
m = FloatLayout()
def build (self):
pic = Pict()
MainApp.m.add_widget(pic)
MainApp.m.add_widget(Butt())
return MainApp.m
if __name__ == '__main__':
MainApp().run()
You must use the instance of the Butt that you want to remove. An easy way to do it is to save a reference to that Butt in your build method:
self.butt = Butt()
MainApp.m.add_widget(self.butt)
and then remove it with:
app = App.get_running_app()
MainApp.m.remove_widget(app.butt)

best tool for rendering short items of text in wxPython and Kivi

I have a multi-platform app running on desktop (wxPython) and mobile (kivy). In it I want to render small areas of variable text in a window in the app. The text will depend on the state of the app. I am happy to use rtf, html or reStructuredText. I need to use the same source for the text on each platform.
A typical example of a text snippet would be:
Heading
=======
1. With 24 widgets pull a **long** one;
2. with fewer, push a **wide** one.
Which would render as:
Heading
With 24 widgets pull a long one;
with fewer, push a wide one.
My question is: which format should I use?
My preference would be reStructuredText. There appears to be a kivy widget to support this but nothing in wxPython
One solution is to use the docutils package.
This will take reStructuredText and output it as html. I can then use the wxPython wx.html control to display the output.
import wx
import wx.html as wxhtml
from docutils.core import publish_string
class MainFrame(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = MainPanel(self)
sizer = wx.BoxSizer()
sizer.Add(self.panel)
self.SetSizerAndFit(sizer)
self.Show()
input_string = ("Heading\n"
"=======\n"
"\n"
"1. With 24 widgets pull a **long** one;\n"
"2. with fewer, push a **wide** one.\n")
self.display_rst(input_string)
def display_rst(self, rst):
html = publish_string(rst, writer_name='html')
self.panel.html.SetPage(html)
class MainPanel(wx.Panel):
def __init__(self, parent, *args, **kwargs):
wx.Panel.__init__(self, parent, *args, **kwargs)
display_style = wx.VSCROLL|wx.HSCROLL|wx.TE_READONLY|wx.BORDER_SIMPLE
self.html = wxhtml.HtmlWindow(self, -1, size=(300, 200),
style=display_style)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.html)
self.SetSizer(sizer)
if __name__ == "__main__":
SCREEN_APP = wx.App()
MAIN_FRAME = MainFrame(None, title="Display HTML")
SCREEN_APP.MainLoop()

GeoDjango PointField admin visualization

I was wondering how I could change the default PointField visualization (the Openstreetmap) in admin so that I could enter simple latitude/longitude instead of select a point on the map?
I looked at this one Latitude/longitude widget for pointfield? but could not get it working in any way in Django 1.6b4
Thanks
As Bibhas says you can override the widget used for the field, but the simple text input may not be usefull. So here is an example with a full widget that can be used for PointField of geodjango:
class LatLongWidget(forms.MultiWidget):
"""
A Widget that splits Point input into latitude/longitude text inputs.
"""
def __init__(self, attrs=None, date_format=None, time_format=None):
widgets = (forms.TextInput(attrs=attrs),
forms.TextInput(attrs=attrs))
super(LatLongWidget, self).__init__(widgets, attrs)
def decompress(self, value):
if value:
return tuple(value.coords)
return (None, None)
def value_from_datadict(self, data, files, name):
mylat = data[name + '_0']
mylong = data[name + '_1']
try:
point = Point(float(mylat), float(mylong))
except ValueError:
return ''
return point
And now you can override your model Admin:
from django.contrib.gis.db import models as geomodels
class CompanyAdmin(admin.ModelAdmin):
list_display = ('name', 'approval', 'company_view',)
list_filter = ('approval',)
formfield_overrides = {
geomodels.PointField: {'widget': LatLongWidget},
}
You can override a widget with another in Django admin. From the documentation -
from django.db import models
from django.contrib import admin
# Import our custom widget and our model from where they're defined
from myapp.widgets import RichTextEditorWidget
from myapp.models import MyModel
class MyModelAdmin(admin.ModelAdmin):
formfield_overrides = {
models.TextField: {'widget': RichTextEditorWidget},
}
This overrides TextField with RichTextEditorWidget. Just find the field type for point field and override it with TextField.
In case you are new to gis, and you don't know where point is defined, the LatLongWidget above needs to know what Point is. You can import it like this:
from django.contrib.gis.geos.point import Point
In this post I approach this issue by using two extra "Decimal Fields" in the ModelForm. This way, the Latitude and Longitude fields appear in the admin for the user's convenience without affecting the database, whatsoever.
They always reflect the relevant values if a PointField exists while they can update them or create them if the PointField does not exist.

Creating composite image from two source png in Groovy

I've seen some Groovy code that lets you combing images and text, but not images and images ...
Essentially, I need to overlay symbols at certain coordinates on maps: I have some maps and symbols as .png files. I can do the coordinate calcs no problem, so the issue is more a case of, given two transparent pngs how do I combine them without losing transparency? (Both the map and the symbol may need to retain their transparency).
Ideally I need a function, something like
combinePngImage(background_src, foreground_src, foreground_x, foreground_y)
that would return a png combination of the two, given the top left, top right coordinates of the foreground image.
[Background: I have some maps and symbols as .png files stored in container fields in FileMaker that I need to combine within a FileMaker solution. I've tried looking in to doing it using ImageMagick and the command line, but it suddenly struck me that this may be something that could be done using ScriptMaster, which uses Groovy to create external functions. ]
Any pointers gratefully received!
Okay, for what it's worth - here's some cobbled together cookbook snippets that seem to do the job - any comments on the (poor) coding style greatfully received.
Given a ScriptMaster call to
combineImage ( backgroundImg ; foregroundImg ; x ; y )
the required code is:
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.URL;
// get container data
InputStream bgImgContainer
try{
bgImgContainer = fmpro.getContainerStream(backgroundImg)
}catch(e){
throw new Exception('Could not get data from background image container (make sure container field name is passed as text)')
}
// test if container field is empty
if( bgImgContainer == null ) {
throw new Exception('Background image container field is empty')
}
bgImgName = fmpro.getContainerFileName(backgroundImg);
InputStream fgImgContainer
try{
fgImgContainer = fmpro.getContainerStream(foregroundImg)
}catch(e){
throw new Exception('Could not get data from foreground image container (make sure container field name is passed as text)')
}
// test if container field is empty
if( fgImgContainer == null ) {
throw new Exception('Foreground image container field is empty')
}
fgImgName = fmpro.getContainerFileName(foregroundImg);
int xCoord = Integer.parseInt(x);
int yCoord = Integer.parseInt(y);
// load image from container data
BufferedImage result = ImageIO.read(bgImgContainer);
BufferedImage overlay = ImageIO.read(fgImgContainer);
int fgWidth = overlay.getWidth(null);
int fgHeight = overlay.getHeight(null);
Graphics2D graphics = result.createGraphics();
// overlay the foreground at given coordinates and actual size
graphics.drawImage(overlay, xCoord, yCoord, fgWidth, fgHeight, null);
graphics.dispose();
File output = File.createTempFile(bgImgName, ".png");
ImageIO.write(result, "png", output);
return output;
Rather than using the ImageMagick command-line, you could try using Im4java, a pure Java ImageMagick API.

Resources