spacr 0.1.0__py3-none-any.whl → 0.1.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spacr/__init__.py +19 -12
- spacr/annotate_app.py +258 -99
- spacr/annotate_app_v2.py +163 -4
- spacr/app_annotate.py +538 -0
- spacr/app_classify.py +8 -0
- spacr/app_make_masks.py +925 -0
- spacr/app_make_masks_v2.py +686 -0
- spacr/app_mask.py +8 -0
- spacr/app_measure.py +8 -0
- spacr/app_sequencing.py +8 -0
- spacr/app_umap.py +8 -0
- spacr/classify_app.py +201 -0
- spacr/core.py +8 -6
- spacr/deep_spacr.py +3 -1
- spacr/gui.py +50 -31
- spacr/gui_2.py +106 -36
- spacr/gui_annotate.py +145 -0
- spacr/gui_classify_app.py +22 -8
- spacr/gui_core.py +608 -0
- spacr/gui_elements.py +322 -0
- spacr/gui_make_masks_app.py +927 -0
- spacr/gui_make_masks_app_v2.py +688 -0
- spacr/gui_mask_app.py +42 -15
- spacr/gui_measure_app.py +46 -21
- spacr/gui_run.py +58 -0
- spacr/gui_utils.py +78 -967
- spacr/gui_wrappers.py +137 -0
- spacr/make_masks_app.py +929 -0
- spacr/make_masks_app_v2.py +688 -0
- spacr/mask_app.py +239 -915
- spacr/measure.py +24 -3
- spacr/measure_app.py +246 -0
- spacr/sequencing.py +1 -17
- spacr/settings.py +441 -6
- spacr/sim_app.py +0 -0
- spacr/utils.py +60 -7
- {spacr-0.1.0.dist-info → spacr-0.1.6.dist-info}/METADATA +13 -22
- spacr-0.1.6.dist-info/RECORD +60 -0
- spacr-0.1.6.dist-info/entry_points.txt +8 -0
- spacr-0.1.0.dist-info/RECORD +0 -40
- spacr-0.1.0.dist-info/entry_points.txt +0 -9
- {spacr-0.1.0.dist-info → spacr-0.1.6.dist-info}/LICENSE +0 -0
- {spacr-0.1.0.dist-info → spacr-0.1.6.dist-info}/WHEEL +0 -0
- {spacr-0.1.0.dist-info → spacr-0.1.6.dist-info}/top_level.txt +0 -0
spacr/annotate_app_v2.py
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
+
import sqlite3
|
1
2
|
from queue import Queue
|
2
|
-
from tkinter import Label
|
3
|
+
from tkinter import Label
|
3
4
|
import tkinter as tk
|
5
|
+
from tkinter import ttk
|
4
6
|
import os, threading, time, sqlite3
|
5
7
|
import numpy as np
|
6
8
|
from PIL import Image, ImageOps
|
7
9
|
from concurrent.futures import ThreadPoolExecutor
|
8
10
|
from PIL import ImageTk
|
9
|
-
import pandas as pd
|
10
11
|
from skimage.exposure import rescale_intensity
|
11
|
-
import cv2
|
12
|
-
import matplotlib.pyplot as plt
|
13
12
|
from IPython.display import display, HTML
|
13
|
+
from tkinter import font as tkFont
|
14
|
+
|
15
|
+
from .gui_utils import ScrollableFrame, CustomButton, set_dark_style, set_default_font, style_text_boxes, create_menu_bar
|
14
16
|
|
15
17
|
class ImageApp:
|
16
18
|
def __init__(self, root, db_path, src, image_type=None, channels=None, grid_rows=None, grid_cols=None, image_size=(200, 200), annotation_column='annotate', normalize=False, percentiles=(1,99), measurement=None, threshold=None):
|
@@ -509,3 +511,160 @@ def annotate(settings):
|
|
509
511
|
|
510
512
|
app.load_images()
|
511
513
|
root.mainloop()
|
514
|
+
|
515
|
+
# Global list to keep references to PhotoImage objects
|
516
|
+
global_image_refs = []
|
517
|
+
|
518
|
+
def initiate_annotation_app_root(parent_frame):
|
519
|
+
style = ttk.Style(parent_frame)
|
520
|
+
set_dark_style(style)
|
521
|
+
style_text_boxes(style)
|
522
|
+
set_default_font(parent_frame, font_name="Arial", size=8)
|
523
|
+
|
524
|
+
parent_frame.configure(bg='black')
|
525
|
+
|
526
|
+
container = tk.PanedWindow(parent_frame, orient=tk.HORIZONTAL, bg='black')
|
527
|
+
container.pack(fill=tk.BOTH, expand=True)
|
528
|
+
|
529
|
+
scrollable_frame = ScrollableFrame(container, bg='black')
|
530
|
+
container.add(scrollable_frame, stretch="always")
|
531
|
+
|
532
|
+
# Setup input fields
|
533
|
+
vars_dict = {
|
534
|
+
'src': ttk.Entry(scrollable_frame.scrollable_frame),
|
535
|
+
'image_type': ttk.Entry(scrollable_frame.scrollable_frame),
|
536
|
+
'channels': ttk.Entry(scrollable_frame.scrollable_frame),
|
537
|
+
'geom': ttk.Entry(scrollable_frame.scrollable_frame),
|
538
|
+
'img_size': ttk.Entry(scrollable_frame.scrollable_frame),
|
539
|
+
'rows': ttk.Entry(scrollable_frame.scrollable_frame),
|
540
|
+
'columns': ttk.Entry(scrollable_frame.scrollable_frame),
|
541
|
+
'annotation_column': ttk.Entry(scrollable_frame.scrollable_frame),
|
542
|
+
'normalize': ttk.Entry(scrollable_frame.scrollable_frame),
|
543
|
+
'percentiles': ttk.Entry(scrollable_frame.scrollable_frame),
|
544
|
+
'measurement': ttk.Entry(scrollable_frame.scrollable_frame),
|
545
|
+
'threshold': ttk.Entry(scrollable_frame.scrollable_frame),
|
546
|
+
}
|
547
|
+
|
548
|
+
default_settings = {
|
549
|
+
'src': 'path',
|
550
|
+
'image_type': 'cell_png',
|
551
|
+
'channels': 'r,g,b',
|
552
|
+
'geom': "3200x2000",
|
553
|
+
'img_size': '(200, 200)',
|
554
|
+
'rows': '10',
|
555
|
+
'columns': '18',
|
556
|
+
'annotation_column': 'recruited_test',
|
557
|
+
'normalize': 'False',
|
558
|
+
'percentiles': '(2,98)',
|
559
|
+
'measurement': 'None',
|
560
|
+
'threshold': 'None'
|
561
|
+
}
|
562
|
+
|
563
|
+
# Arrange input fields and labels
|
564
|
+
row = 0
|
565
|
+
for name, entry in vars_dict.items():
|
566
|
+
ttk.Label(scrollable_frame.scrollable_frame, text=f"{name.replace('_', ' ').capitalize()}:",
|
567
|
+
background="black", foreground="white").grid(row=row, column=0)
|
568
|
+
entry.insert(0, default_settings[name])
|
569
|
+
entry.grid(row=row, column=1)
|
570
|
+
row += 1
|
571
|
+
|
572
|
+
# Function to be called when "Run" button is clicked
|
573
|
+
def run_app():
|
574
|
+
settings = {key: entry.get() for key, entry in vars_dict.items()}
|
575
|
+
settings['channels'] = settings['channels'].split(',')
|
576
|
+
settings['img_size'] = tuple(map(int, settings['img_size'][1:-1].split(',')))
|
577
|
+
settings['percentiles'] = tuple(map(int, settings['percentiles'][1:-1].split(',')))
|
578
|
+
settings['normalize'] = settings['normalize'].lower() == 'true'
|
579
|
+
settings['rows'] = int(settings['rows'])
|
580
|
+
settings['columns'] = int(settings['columns'])
|
581
|
+
if settings['measurement'].lower() == 'none':
|
582
|
+
settings['measurement'] = None
|
583
|
+
if settings['threshold'].lower() == 'none':
|
584
|
+
settings['threshold'] = None
|
585
|
+
|
586
|
+
# Clear previous content instead of destroying the root
|
587
|
+
if hasattr(parent_frame, 'winfo_children'):
|
588
|
+
for widget in parent_frame.winfo_children():
|
589
|
+
widget.destroy()
|
590
|
+
|
591
|
+
# Start the annotate application in the same root window
|
592
|
+
annotate_app(parent_frame, settings)
|
593
|
+
|
594
|
+
run_button = CustomButton(scrollable_frame.scrollable_frame, text="Run", command=run_app,
|
595
|
+
font=tkFont.Font(family="Arial", size=12, weight=tkFont.NORMAL))
|
596
|
+
run_button.grid(row=row, column=0, columnspan=2, pady=10, padx=10)
|
597
|
+
|
598
|
+
return parent_frame
|
599
|
+
|
600
|
+
def annotate_app(parent_frame, settings):
|
601
|
+
global global_image_refs
|
602
|
+
global_image_refs.clear()
|
603
|
+
root = parent_frame.winfo_toplevel()
|
604
|
+
annotate_with_image_refs(settings, root, lambda: load_next_app(root))
|
605
|
+
|
606
|
+
def annotate_with_image_refs(settings, root, shutdown_callback):
|
607
|
+
settings = get_annotate_default_settings(settings)
|
608
|
+
src = settings['src']
|
609
|
+
|
610
|
+
db = os.path.join(src, 'measurements/measurements.db')
|
611
|
+
conn = sqlite3.connect(db)
|
612
|
+
c = conn.cursor()
|
613
|
+
c.execute('PRAGMA table_info(png_list)')
|
614
|
+
cols = c.fetchall()
|
615
|
+
if settings['annotation_column'] not in [col[1] for col in cols]:
|
616
|
+
c.execute(f"ALTER TABLE png_list ADD COLUMN {settings['annotation_column']} integer")
|
617
|
+
conn.commit()
|
618
|
+
conn.close()
|
619
|
+
|
620
|
+
app = ImageApp(root, db, src, image_type=settings['image_type'], channels=settings['channels'], image_size=settings['img_size'], grid_rows=settings['rows'], grid_cols=settings['columns'], annotation_column=settings['annotation_column'], normalize=settings['normalize'], percentiles=settings['percentiles'], measurement=settings['measurement'], threshold=settings['threshold'])
|
621
|
+
|
622
|
+
# Set the canvas background to black
|
623
|
+
root.configure(bg='black')
|
624
|
+
|
625
|
+
next_button = tk.Button(root, text="Next", command=app.next_page, background='black', foreground='white')
|
626
|
+
next_button.grid(row=app.grid_rows, column=app.grid_cols - 1)
|
627
|
+
back_button = tk.Button(root, text="Back", command=app.previous_page, background='black', foreground='white')
|
628
|
+
back_button.grid(row=app.grid_rows, column=app.grid_cols - 2)
|
629
|
+
exit_button = tk.Button(root, text="Exit", command=lambda: [app.shutdown(), shutdown_callback()], background='black', foreground='white')
|
630
|
+
exit_button.grid(row=app.grid_rows, column=app.grid_cols - 3)
|
631
|
+
|
632
|
+
app.load_images()
|
633
|
+
|
634
|
+
# Store the shutdown function and next app details in the root
|
635
|
+
root.current_app_exit_func = app.shutdown
|
636
|
+
root.next_app_func = None
|
637
|
+
root.next_app_args = ()
|
638
|
+
|
639
|
+
def load_next_app(root):
|
640
|
+
# Get the next app function and arguments
|
641
|
+
next_app_func = root.next_app_func
|
642
|
+
next_app_args = root.next_app_args
|
643
|
+
|
644
|
+
if next_app_func:
|
645
|
+
next_app_func(*next_app_args)
|
646
|
+
|
647
|
+
def gui_annotate():
|
648
|
+
root = tk.Tk()
|
649
|
+
width = root.winfo_screenwidth()
|
650
|
+
height = root.winfo_screenheight()
|
651
|
+
root.geometry(f"{width}x{height}")
|
652
|
+
root.title("Annotate Application")
|
653
|
+
|
654
|
+
# Clear previous content if any
|
655
|
+
if hasattr(root, 'content_frame'):
|
656
|
+
for widget in root.content_frame.winfo_children():
|
657
|
+
widget.destroy()
|
658
|
+
root.content_frame.grid_forget()
|
659
|
+
else:
|
660
|
+
root.content_frame = tk.Frame(root)
|
661
|
+
root.content_frame.grid(row=1, column=0, sticky="nsew")
|
662
|
+
root.grid_rowconfigure(1, weight=1)
|
663
|
+
root.grid_columnconfigure(0, weight=1)
|
664
|
+
|
665
|
+
initiate_annotation_app_root(root.content_frame)
|
666
|
+
create_menu_bar(root)
|
667
|
+
root.mainloop()
|
668
|
+
|
669
|
+
if __name__ == "__main__":
|
670
|
+
gui_annotate()
|