spacr 0.2.56__py3-none-any.whl → 0.2.65__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/gui_elements.py CHANGED
@@ -2,6 +2,7 @@ import os, threading, time, sqlite3, webbrowser, pyautogui
2
2
  import tkinter as tk
3
3
  from tkinter import ttk
4
4
  import tkinter.font as tkFont
5
+ from tkinter import filedialog
5
6
  from tkinter import font
6
7
  from queue import Queue
7
8
  from tkinter import Label, Frame, Button
@@ -16,6 +17,7 @@ from skimage.draw import polygon, line
16
17
  from skimage.transform import resize
17
18
  from scipy.ndimage import binary_fill_holes, label
18
19
  from tkinter import ttk, scrolledtext
20
+ fig = None
19
21
 
20
22
  def set_element_size():
21
23
 
@@ -516,6 +518,7 @@ class spacrDropdownMenu(tk.Frame):
516
518
  self.inactive_color = color_settings['inactive_color']
517
519
  self.active_color = color_settings['active_color']
518
520
  self.fg_color = color_settings['fg_color']
521
+ self.bg_color = style_out['bg_color']
519
522
 
520
523
  # Create the button with rounded edges
521
524
  self.button_bg = self.create_rounded_rectangle(2, 2, self.button_width + 2, self.size + 2, radius=20, fill=self.inactive_color, outline=self.inactive_color)
@@ -536,8 +539,8 @@ class spacrDropdownMenu(tk.Frame):
536
539
  self.canvas.bind("<Leave>", self.on_leave)
537
540
  self.canvas.bind("<Button-1>", self.on_click)
538
541
 
539
- # Create a popup menu
540
- self.menu = tk.Menu(self, tearoff=0)
542
+ # Create a popup menu with the desired background color
543
+ self.menu = tk.Menu(self, tearoff=0, bg=self.bg_color, fg=self.fg_color)
541
544
  for option in self.options:
542
545
  self.menu.add_command(label=option, command=lambda opt=option: self.on_select(opt))
543
546
 
@@ -591,7 +594,6 @@ class spacrDropdownMenu(tk.Frame):
591
594
  else:
592
595
  self.menu.entryconfig(idx, background=style_out['bg_color'], foreground=style_out['fg_color'])
593
596
 
594
-
595
597
  class spacrCheckbutton(ttk.Checkbutton):
596
598
  def __init__(self, parent, text="", variable=None, command=None, *args, **kwargs):
597
599
  super().__init__(parent, *args, **kwargs)
@@ -613,17 +615,26 @@ class spacrProgressBar(ttk.Progressbar):
613
615
  self.bg_color = style_out['bg_color']
614
616
  self.active_color = style_out['active_color']
615
617
  self.inactive_color = style_out['inactive_color']
618
+ self.font_size = style_out['font_size']
619
+ self.font_loader = style_out['font_loader']
616
620
 
617
621
  # Configure the style for the progress bar
618
622
  self.style = ttk.Style()
623
+
624
+ # Remove any borders and ensure the active color fills the entire space
619
625
  self.style.configure(
620
626
  "spacr.Horizontal.TProgressbar",
621
- troughcolor=self.bg_color,
622
- background=self.active_color,
623
- thickness=20,
624
- troughrelief='flat',
625
- borderwidth=0
627
+ troughcolor=self.inactive_color, # Set the trough to bg color
628
+ background=self.active_color, # Active part is the active color
629
+ borderwidth=0, # Remove border width
630
+ pbarrelief="flat", # Flat relief for the progress bar
631
+ troughrelief="flat", # Flat relief for the trough
632
+ thickness=20, # Set the thickness of the progress bar
633
+ darkcolor=self.active_color, # Ensure darkcolor matches the active color
634
+ lightcolor=self.active_color, # Ensure lightcolor matches the active color
635
+ bordercolor=self.bg_color # Set the border color to the background color to hide it
626
636
  )
637
+
627
638
  self.configure(style="spacr.Horizontal.TProgressbar")
628
639
 
629
640
  # Set initial value to 0
@@ -641,15 +652,14 @@ class spacrProgressBar(ttk.Progressbar):
641
652
  justify='left',
642
653
  bg=self.inactive_color,
643
654
  fg=self.fg_color,
644
- wraplength=300 # Adjust the wraplength as needed
655
+ wraplength=300,
656
+ font=self.font_loader.get_font(size=self.font_size)
645
657
  )
646
- self.progress_label.grid_forget() # Temporarily hide it
658
+ self.progress_label.grid_forget()
647
659
 
648
660
  # Initialize attributes for time and operation
649
661
  self.operation_type = None
650
- self.time_image = None
651
- self.time_batch = None
652
- self.time_left = None
662
+ self.additional_info = None
653
663
 
654
664
  def set_label_position(self):
655
665
  if self.label and self.progress_label:
@@ -664,74 +674,19 @@ class spacrProgressBar(ttk.Progressbar):
664
674
  label_text = f"Processing: {self['value']}/{self['maximum']}"
665
675
  if self.operation_type:
666
676
  label_text += f", {self.operation_type}"
667
- if self.time_image:
668
- label_text += f", Time/image: {self.time_image:.3f} sec"
669
- if self.time_batch:
670
- label_text += f", Time/batch: {self.time_batch:.3f} sec"
671
- if self.time_left:
672
- label_text += f", Time_left: {self.time_left:.3f} min"
673
- self.progress_label.config(text=label_text)
674
-
675
- class spacrProgressBar_v1(ttk.Progressbar):
676
- def __init__(self, parent, label=True, *args, **kwargs):
677
- super().__init__(parent, *args, **kwargs)
678
-
679
- # Get the style colors
680
- style_out = set_dark_style(ttk.Style())
681
-
682
- self.fg_color = style_out['fg_color']
683
- self.bg_color = style_out['bg_color']
684
- self.active_color = style_out['active_color']
685
- self.inactive_color = style_out['inactive_color']
686
-
687
- # Configure the style for the progress bar
688
- self.style = ttk.Style()
689
- self.style.configure(
690
- "spacr.Horizontal.TProgressbar",
691
- troughcolor=self.bg_color,
692
- background=self.active_color,
693
- thickness=20,
694
- troughrelief='flat',
695
- borderwidth=0
696
- )
697
- self.configure(style="spacr.Horizontal.TProgressbar")
698
-
699
- # Set initial value to 0
700
- self['value'] = 0
701
-
702
- # Track whether to show the progress label
703
- self.label = label
704
-
705
- # Create the progress label (defer placement)
706
- if self.label:
707
- self.progress_label = tk.Label(parent, text="Processing: 0/0", anchor='w', justify='left', bg=self.inactive_color, fg=self.fg_color)
708
- self.progress_label.grid_forget() # Temporarily hide it
709
-
710
- # Initialize attributes for time and operation
711
- self.operation_type = None
712
- self.time_image = None
713
- self.time_batch = None
714
- self.time_left = None
715
-
716
- def set_label_position(self):
717
- if self.label and self.progress_label:
718
- row_info = self.grid_info().get('row', 0)
719
- col_info = self.grid_info().get('column', 0)
720
- col_span = self.grid_info().get('columnspan', 1)
721
- self.progress_label.grid(row=row_info + 1, column=col_info, columnspan=col_span, pady=5, padx=5, sticky='ew')
722
-
723
- def update_label(self):
724
- if self.label and self.progress_label:
725
- # Update the progress label with current progress and additional info
726
- label_text = f"Processing: {self['value']}/{self['maximum']}"
727
- if self.operation_type:
728
- label_text += f", {self.operation_type}"
729
- if self.time_image:
730
- label_text += f", Time/image: {self.time_image:.3f} sec"
731
- if self.time_batch:
732
- label_text += f", Time/batch: {self.time_batch:.3f} sec"
733
- if self.time_left:
734
- label_text += f", Time_left: {self.time_left:.3f} min"
677
+ if hasattr(self, 'additional_info') and self.additional_info:
678
+ # Add a space between progress information and additional information
679
+ label_text += "\n\n"
680
+ # Split the additional_info into a list of items
681
+ items = self.additional_info.split(", ")
682
+ formatted_additional_info = ""
683
+ # Group the items in pairs, adding them to formatted_additional_info
684
+ for i in range(0, len(items), 2):
685
+ if i + 1 < len(items):
686
+ formatted_additional_info += f"{items[i]}, {items[i + 1]}\n\n"
687
+ else:
688
+ formatted_additional_info += f"{items[i]}\n\n" # If there's an odd item out, add it alone
689
+ label_text += formatted_additional_info.strip()
735
690
  self.progress_label.config(text=label_text)
736
691
 
737
692
  def spacrScrollbarStyle(style, inactive_color, active_color):
@@ -2128,6 +2083,7 @@ class AnnotateApp:
2128
2083
  print(f"median threshold measurement: {np.median(df[self.measurement])}")
2129
2084
  df = df[df[f'threshold_measurement_{idx}'] > thd]
2130
2085
  after = len(df)
2086
+
2131
2087
  elif isinstance(self.measurement, list):
2132
2088
  df['threshold_measurement'] = df[self.measurement[0]]/df[self.measurement[1]]
2133
2089
  print(f"mean threshold measurement: {np.mean(df['threshold_measurement'])}")
@@ -2136,6 +2092,7 @@ class AnnotateApp:
2136
2092
  after = len(df)
2137
2093
  self.measurement = 'threshold_measurement'
2138
2094
  print(f'Removed: {before-after} rows, retained {after}')
2095
+
2139
2096
  else:
2140
2097
  print(f"mean threshold measurement: {np.mean(df[self.measurement])}")
2141
2098
  print(f"median threshold measurement: {np.median(df[self.measurement])}")
@@ -2417,4 +2374,300 @@ def create_menu_bar(root):
2417
2374
  app_menu.add_command(label="Exit", command=root.quit)
2418
2375
 
2419
2376
  # Configure the menu for the root window
2420
- root.config(menu=menu_bar)
2377
+ root.config(menu=menu_bar)
2378
+
2379
+ def standardize_figure(fig):
2380
+ from .gui_elements import set_dark_style
2381
+ from matplotlib.font_manager import FontProperties
2382
+
2383
+ style_out = set_dark_style(ttk.Style())
2384
+ bg_color = style_out['bg_color']
2385
+ fg_color = style_out['fg_color']
2386
+ font_size = style_out['font_size']
2387
+ font_loader = style_out['font_loader']
2388
+
2389
+ # Get the custom font path from the font loader
2390
+ font_path = font_loader.font_path
2391
+ font_prop = FontProperties(fname=font_path, size=font_size)
2392
+
2393
+ """
2394
+ Standardizes the appearance of the figure:
2395
+ - Font size: from style
2396
+ - Font color: from style
2397
+ - Font family: custom OpenSans from font_loader
2398
+ - Removes top and right spines
2399
+ - Figure and subplot background: from style
2400
+ - Line width: 1
2401
+ - Line color: from style
2402
+ """
2403
+
2404
+ for ax in fig.get_axes():
2405
+ # Set font properties for title and labels
2406
+ ax.title.set_fontsize(font_size)
2407
+ ax.title.set_color(fg_color)
2408
+ ax.title.set_fontproperties(font_prop)
2409
+
2410
+ ax.xaxis.label.set_fontsize(font_size)
2411
+ ax.xaxis.label.set_color(fg_color)
2412
+ ax.xaxis.label.set_fontproperties(font_prop)
2413
+
2414
+ ax.yaxis.label.set_fontsize(font_size)
2415
+ ax.yaxis.label.set_color(fg_color)
2416
+ ax.yaxis.label.set_fontproperties(font_prop)
2417
+
2418
+ # Set font properties for tick labels
2419
+ for label in ax.get_xticklabels() + ax.get_yticklabels():
2420
+ label.set_fontsize(font_size)
2421
+ label.set_color(fg_color)
2422
+ label.set_fontproperties(font_prop)
2423
+
2424
+ # Remove top and right spines
2425
+ ax.spines['top'].set_visible(False)
2426
+ ax.spines['right'].set_visible(False)
2427
+ ax.spines['left'].set_visible(True)
2428
+ ax.spines['bottom'].set_visible(True)
2429
+
2430
+ # Set spine line width and color
2431
+ for spine in ax.spines.values():
2432
+ spine.set_linewidth(1)
2433
+ spine.set_edgecolor(fg_color)
2434
+
2435
+ # Set line width and color
2436
+ for line in ax.get_lines():
2437
+ line.set_linewidth(1)
2438
+ line.set_color(fg_color)
2439
+
2440
+ # Set subplot background color
2441
+ ax.set_facecolor(bg_color)
2442
+
2443
+ # Adjust the grid if needed
2444
+ ax.grid(True, color='gray', linestyle='--', linewidth=0.5)
2445
+
2446
+ # Set figure background color
2447
+ fig.patch.set_facecolor(bg_color)
2448
+
2449
+ fig.canvas.draw_idle()
2450
+
2451
+ def modify_figure_properties(fig, scale_x=None, scale_y=None, line_width=None, font_size=None, x_lim=None, y_lim=None, grid=False, legend=None, title=None, x_label_rotation=None, remove_axes=False, bg_color=None, text_color=None, line_color=None):
2452
+ """
2453
+ Modifies the properties of the figure, including scaling, line widths, font sizes, axis limits, x-axis label rotation, background color, text color, line color, and other common options.
2454
+
2455
+ Parameters:
2456
+ - fig: The Matplotlib figure object to modify.
2457
+ - scale_x: Scaling factor for the width of subplots (optional).
2458
+ - scale_y: Scaling factor for the height of subplots (optional).
2459
+ - line_width: Desired line width for all lines (optional).
2460
+ - font_size: Desired font size for all text (optional).
2461
+ - x_lim: Tuple specifying the x-axis limits (min, max) (optional).
2462
+ - y_lim: Tuple specifying the y-axis limits (min, max) (optional).
2463
+ - grid: Boolean to add grid lines to the plot (optional).
2464
+ - legend: Boolean to show/hide the legend (optional).
2465
+ - title: String to set as the title of the plot (optional).
2466
+ - x_label_rotation: Angle to rotate the x-axis labels (optional).
2467
+ - remove_axes: Boolean to remove or show the axes labels (optional).
2468
+ - bg_color: Color for the figure and subplot background (optional).
2469
+ - text_color: Color for all text in the figure (optional).
2470
+ - line_color: Color for all lines in the figure (optional).
2471
+ """
2472
+ if fig is None:
2473
+ print("Error: The figure provided is None.")
2474
+ return
2475
+
2476
+ for ax in fig.get_axes():
2477
+ # Rescale subplots if scaling factors are provided
2478
+ if scale_x is not None or scale_y is not None:
2479
+ bbox = ax.get_position()
2480
+ width = bbox.width * (scale_x if scale_x else 1)
2481
+ height = bbox.height * (scale_y if scale_y else 1)
2482
+ new_bbox = [bbox.x0, bbox.y0, width, height]
2483
+ ax.set_position(new_bbox)
2484
+
2485
+ # Set axis limits if provided
2486
+ if x_lim is not None:
2487
+ ax.set_xlim(x_lim)
2488
+ if y_lim is not None:
2489
+ ax.set_ylim(y_lim)
2490
+
2491
+ # Set grid visibility only
2492
+ ax.grid(grid)
2493
+
2494
+ # Adjust line width and color if specified
2495
+ if line_width is not None or line_color is not None:
2496
+ for line in ax.get_lines():
2497
+ if line_width is not None:
2498
+ line.set_linewidth(line_width)
2499
+ if line_color is not None:
2500
+ line.set_color(line_color)
2501
+ for spine in ax.spines.values(): # Modify width and color of spines (e.g., scale bars)
2502
+ if line_width is not None:
2503
+ spine.set_linewidth(line_width)
2504
+ if line_color is not None:
2505
+ spine.set_edgecolor(line_color)
2506
+ ax.tick_params(width=line_width, colors=text_color if text_color else 'black')
2507
+
2508
+ # Adjust font size if specified
2509
+ if font_size is not None:
2510
+ for label in ax.get_xticklabels() + ax.get_yticklabels():
2511
+ label.set_fontsize(font_size)
2512
+ ax.title.set_fontsize(font_size)
2513
+ ax.xaxis.label.set_fontsize(font_size)
2514
+ ax.yaxis.label.set_fontsize(font_size)
2515
+ if ax.legend_:
2516
+ for text in ax.legend_.get_texts():
2517
+ text.set_fontsize(font_size)
2518
+
2519
+ # Rotate x-axis labels if rotation is specified
2520
+ if x_label_rotation is not None:
2521
+ for label in ax.get_xticklabels():
2522
+ label.set_rotation(x_label_rotation)
2523
+ if 0 <= x_label_rotation <= 90:
2524
+ label.set_ha('center')
2525
+
2526
+ # Toggle axes labels visibility without affecting the grid or spines
2527
+ if remove_axes:
2528
+ ax.xaxis.set_visible(False)
2529
+ ax.yaxis.set_visible(False)
2530
+ else:
2531
+ ax.xaxis.set_visible(True)
2532
+ ax.yaxis.set_visible(True)
2533
+
2534
+ # Set text color if specified
2535
+ if text_color:
2536
+ ax.title.set_color(text_color)
2537
+ ax.xaxis.label.set_color(text_color)
2538
+ ax.yaxis.label.set_color(text_color)
2539
+ ax.tick_params(colors=text_color)
2540
+ for label in ax.get_xticklabels() + ax.get_yticklabels():
2541
+ label.set_color(text_color)
2542
+
2543
+ # Set background color for subplots if specified
2544
+ if bg_color:
2545
+ ax.set_facecolor(bg_color)
2546
+
2547
+ # Set figure background color if specified
2548
+ if bg_color:
2549
+ fig.patch.set_facecolor(bg_color)
2550
+
2551
+ fig.canvas.draw_idle()
2552
+
2553
+ def save_figure_as_format(fig, file_format):
2554
+ file_path = filedialog.asksaveasfilename(defaultextension=f".{file_format}", filetypes=[(f"{file_format.upper()} files", f"*.{file_format}"), ("All files", "*.*")])
2555
+ if file_path:
2556
+ try:
2557
+ fig.savefig(file_path, format=file_format)
2558
+ print(f"Figure saved as {file_format.upper()} at {file_path}")
2559
+ except Exception as e:
2560
+ print(f"Error saving figure: {e}")
2561
+
2562
+ def modify_figure(fig):
2563
+ from .gui_core import display_figure
2564
+ def apply_modifications():
2565
+ try:
2566
+ # Only apply changes if the fields are filled
2567
+ scale_x = float(scale_x_var.get()) if scale_x_var.get() else None
2568
+ scale_y = float(scale_y_var.get()) if scale_y_var.get() else None
2569
+ line_width = float(line_width_var.get()) if line_width_var.get() else None
2570
+ font_size = int(font_size_var.get()) if font_size_var.get() else None
2571
+ x_lim = eval(x_lim_var.get()) if x_lim_var.get() else None
2572
+ y_lim = eval(y_lim_var.get()) if y_lim_var.get() else None
2573
+ title = title_var.get() if title_var.get() else None
2574
+ bg_color = bg_color_var.get() if bg_color_var.get() else None
2575
+ text_color = text_color_var.get() if text_color_var.get() else None
2576
+ line_color = line_color_var.get() if line_color_var.get() else None
2577
+ x_label_rotation = int(x_label_rotation_var.get()) if x_label_rotation_var.get() else None
2578
+
2579
+ modify_figure_properties(
2580
+ fig,
2581
+ scale_x=scale_x,
2582
+ scale_y=scale_y,
2583
+ line_width=line_width,
2584
+ font_size=font_size,
2585
+ x_lim=x_lim,
2586
+ y_lim=y_lim,
2587
+ grid=grid_var.get(),
2588
+ legend=legend_var.get(),
2589
+ title=title,
2590
+ x_label_rotation=x_label_rotation,
2591
+ remove_axes=remove_axes_var.get(),
2592
+ bg_color=bg_color,
2593
+ text_color=text_color,
2594
+ line_color=line_color
2595
+ )
2596
+ display_figure(fig)
2597
+ except ValueError:
2598
+ print("Invalid input; please enter numeric values.")
2599
+
2600
+ def toggle_spleens():
2601
+ for ax in fig.get_axes():
2602
+ if spleens_var.get():
2603
+ ax.spines['top'].set_visible(False)
2604
+ ax.spines['right'].set_visible(False)
2605
+ ax.spines['left'].set_visible(True)
2606
+ ax.spines['bottom'].set_visible(True)
2607
+ ax.spines['top'].set_linewidth(2)
2608
+ ax.spines['right'].set_linewidth(2)
2609
+ else:
2610
+ ax.spines['top'].set_visible(True)
2611
+ ax.spines['right'].set_visible(True)
2612
+ display_figure(fig)
2613
+
2614
+ # Create a new window for user input
2615
+ modify_window = tk.Toplevel()
2616
+ modify_window.title("Modify Figure Properties")
2617
+
2618
+ # Apply dark style to the popup window
2619
+ style = ttk.Style()
2620
+ style.configure("TCheckbutton", background="#2E2E2E", foreground="white", selectcolor="blue")
2621
+
2622
+ modify_window.configure(bg="#2E2E2E")
2623
+
2624
+ # Create and style the input fields
2625
+ scale_x_var = tk.StringVar()
2626
+ scale_y_var = tk.StringVar()
2627
+ line_width_var = tk.StringVar()
2628
+ font_size_var = tk.StringVar()
2629
+ x_lim_var = tk.StringVar()
2630
+ y_lim_var = tk.StringVar()
2631
+ title_var = tk.StringVar()
2632
+ bg_color_var = tk.StringVar()
2633
+ text_color_var = tk.StringVar()
2634
+ line_color_var = tk.StringVar()
2635
+ x_label_rotation_var = tk.StringVar()
2636
+ remove_axes_var = tk.BooleanVar()
2637
+ grid_var = tk.BooleanVar()
2638
+ legend_var = tk.BooleanVar()
2639
+ spleens_var = tk.BooleanVar()
2640
+
2641
+ options = [
2642
+ ("Rescale X:", scale_x_var),
2643
+ ("Rescale Y:", scale_y_var),
2644
+ ("Line Width:", line_width_var),
2645
+ ("Font Size:", font_size_var),
2646
+ ("X Axis Limits (tuple):", x_lim_var),
2647
+ ("Y Axis Limits (tuple):", y_lim_var),
2648
+ ("Title:", title_var),
2649
+ ("X Label Rotation (degrees):", x_label_rotation_var),
2650
+ ("Background Color:", bg_color_var),
2651
+ ("Text Color:", text_color_var),
2652
+ ("Line Color:", line_color_var)
2653
+ ]
2654
+
2655
+ for i, (label_text, var) in enumerate(options):
2656
+ tk.Label(modify_window, text=label_text, bg="#2E2E2E", fg="white").grid(row=i, column=0, padx=10, pady=5)
2657
+ tk.Entry(modify_window, textvariable=var, bg="#2E2E2E", fg="white").grid(row=i, column=1, padx=10, pady=5)
2658
+
2659
+ checkboxes = [
2660
+ ("Grid", grid_var),
2661
+ ("Legend", legend_var),
2662
+ ("Spleens", spleens_var),
2663
+ ("Remove Axes", remove_axes_var)
2664
+ ]
2665
+
2666
+ for i, (label_text, var) in enumerate(checkboxes, start=len(options)):
2667
+ ttk.Checkbutton(modify_window, text=label_text, variable=var, style="TCheckbutton").grid(row=i, column=0, padx=10, pady=5, columnspan=2, sticky='w')
2668
+
2669
+ spleens_var.trace_add("write", lambda *args: toggle_spleens())
2670
+
2671
+ # Apply button
2672
+ apply_button = tk.Button(modify_window, text="Apply", command=apply_modifications, bg="#2E2E2E", fg="white")
2673
+ apply_button.grid(row=len(options) + len(checkboxes), column=0, columnspan=2, pady=10)