spacr 0.2.61__tar.gz → 0.2.65__tar.gz

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.
Files changed (122) hide show
  1. {spacr-0.2.61/spacr.egg-info → spacr-0.2.65}/PKG-INFO +1 -1
  2. {spacr-0.2.61 → spacr-0.2.65}/setup.py +1 -1
  3. {spacr-0.2.61 → spacr-0.2.65}/spacr/__init__.py +1 -3
  4. {spacr-0.2.61 → spacr-0.2.65}/spacr/gui_core.py +136 -137
  5. {spacr-0.2.61 → spacr-0.2.65}/spacr/gui_elements.py +301 -1
  6. {spacr-0.2.61 → spacr-0.2.65}/spacr/gui_utils.py +39 -2
  7. {spacr-0.2.61 → spacr-0.2.65}/spacr/plot.py +4 -4
  8. {spacr-0.2.61 → spacr-0.2.65}/spacr/sequencing.py +4 -8
  9. {spacr-0.2.61 → spacr-0.2.65}/spacr/utils.py +1 -1
  10. {spacr-0.2.61 → spacr-0.2.65/spacr.egg-info}/PKG-INFO +1 -1
  11. {spacr-0.2.61 → spacr-0.2.65}/spacr.egg-info/SOURCES.txt +0 -1
  12. spacr-0.2.61/spacr/chris.py +0 -50
  13. {spacr-0.2.61 → spacr-0.2.65}/LICENSE +0 -0
  14. {spacr-0.2.61 → spacr-0.2.65}/MANIFEST.in +0 -0
  15. {spacr-0.2.61 → spacr-0.2.65}/README.rst +0 -0
  16. {spacr-0.2.61 → spacr-0.2.65}/setup.cfg +0 -0
  17. {spacr-0.2.61 → spacr-0.2.65}/spacr/__main__.py +0 -0
  18. {spacr-0.2.61 → spacr-0.2.65}/spacr/app_annotate.py +0 -0
  19. {spacr-0.2.61 → spacr-0.2.65}/spacr/app_classify.py +0 -0
  20. {spacr-0.2.61 → spacr-0.2.65}/spacr/app_make_masks.py +0 -0
  21. {spacr-0.2.61 → spacr-0.2.65}/spacr/app_mask.py +0 -0
  22. {spacr-0.2.61 → spacr-0.2.65}/spacr/app_measure.py +0 -0
  23. {spacr-0.2.61 → spacr-0.2.65}/spacr/app_sequencing.py +0 -0
  24. {spacr-0.2.61 → spacr-0.2.65}/spacr/app_umap.py +0 -0
  25. {spacr-0.2.61 → spacr-0.2.65}/spacr/core.py +0 -0
  26. {spacr-0.2.61 → spacr-0.2.65}/spacr/deep_spacr.py +0 -0
  27. {spacr-0.2.61 → spacr-0.2.65}/spacr/graph_learning.py +0 -0
  28. {spacr-0.2.61 → spacr-0.2.65}/spacr/gui.py +0 -0
  29. {spacr-0.2.61 → spacr-0.2.65}/spacr/io.py +0 -0
  30. {spacr-0.2.61 → spacr-0.2.65}/spacr/logger.py +0 -0
  31. {spacr-0.2.61 → spacr-0.2.65}/spacr/measure.py +0 -0
  32. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/OFL.txt +0 -0
  33. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
  34. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
  35. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/README.txt +0 -0
  36. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans-Bold.ttf +0 -0
  37. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans-BoldItalic.ttf +0 -0
  38. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans-ExtraBold.ttf +0 -0
  39. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans-ExtraBoldItalic.ttf +0 -0
  40. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans-Italic.ttf +0 -0
  41. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans-Light.ttf +0 -0
  42. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans-LightItalic.ttf +0 -0
  43. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans-Medium.ttf +0 -0
  44. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans-MediumItalic.ttf +0 -0
  45. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans-Regular.ttf +0 -0
  46. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans-SemiBold.ttf +0 -0
  47. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans-SemiBoldItalic.ttf +0 -0
  48. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_Condensed-Bold.ttf +0 -0
  49. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_Condensed-BoldItalic.ttf +0 -0
  50. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_Condensed-ExtraBold.ttf +0 -0
  51. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_Condensed-ExtraBoldItalic.ttf +0 -0
  52. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_Condensed-Italic.ttf +0 -0
  53. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_Condensed-Light.ttf +0 -0
  54. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_Condensed-LightItalic.ttf +0 -0
  55. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_Condensed-Medium.ttf +0 -0
  56. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_Condensed-MediumItalic.ttf +0 -0
  57. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_Condensed-Regular.ttf +0 -0
  58. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_Condensed-SemiBold.ttf +0 -0
  59. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_Condensed-SemiBoldItalic.ttf +0 -0
  60. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Bold.ttf +0 -0
  61. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-BoldItalic.ttf +0 -0
  62. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-ExtraBold.ttf +0 -0
  63. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-ExtraBoldItalic.ttf +0 -0
  64. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Italic.ttf +0 -0
  65. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Light.ttf +0 -0
  66. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-LightItalic.ttf +0 -0
  67. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Medium.ttf +0 -0
  68. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-MediumItalic.ttf +0 -0
  69. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Regular.ttf +0 -0
  70. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-SemiBold.ttf +0 -0
  71. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-SemiBoldItalic.ttf +0 -0
  72. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/abort.png +0 -0
  73. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/annotate.png +0 -0
  74. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/cellpose_all.png +0 -0
  75. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/cellpose_masks.png +0 -0
  76. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/classify.png +0 -0
  77. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/default.png +0 -0
  78. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/download.png +0 -0
  79. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/logo.pdf +0 -0
  80. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/logo_spacr.png +0 -0
  81. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/logo_spacr_1.png +0 -0
  82. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/make_masks.png +0 -0
  83. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/map_barcodes.png +0 -0
  84. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/mask.png +0 -0
  85. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/measure.png +0 -0
  86. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/ml_analyze.png +0 -0
  87. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/recruitment.png +0 -0
  88. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/regression.png +0 -0
  89. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/run.png +0 -0
  90. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/sequencing.png +0 -0
  91. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/settings.png +0 -0
  92. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/spacr_logo_rotation.gif +0 -0
  93. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/train_cellpose.png +0 -0
  94. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/icons/umap.png +0 -0
  95. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model +0 -0
  96. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model_settings.csv +0 -0
  97. {spacr-0.2.61 → spacr-0.2.65}/spacr/resources/models/cp/toxo_pv_lumen.CP_model +0 -0
  98. {spacr-0.2.61 → spacr-0.2.65}/spacr/settings.py +0 -0
  99. {spacr-0.2.61 → spacr-0.2.65}/spacr/sim.py +0 -0
  100. {spacr-0.2.61 → spacr-0.2.65}/spacr/sim_app.py +0 -0
  101. {spacr-0.2.61 → spacr-0.2.65}/spacr/timelapse.py +0 -0
  102. {spacr-0.2.61 → spacr-0.2.65}/spacr/version.py +0 -0
  103. {spacr-0.2.61 → spacr-0.2.65}/spacr.egg-info/dependency_links.txt +0 -0
  104. {spacr-0.2.61 → spacr-0.2.65}/spacr.egg-info/entry_points.txt +0 -0
  105. {spacr-0.2.61 → spacr-0.2.65}/spacr.egg-info/requires.txt +0 -0
  106. {spacr-0.2.61 → spacr-0.2.65}/spacr.egg-info/top_level.txt +0 -0
  107. {spacr-0.2.61 → spacr-0.2.65}/tests/test_annotate_app.py +0 -0
  108. {spacr-0.2.61 → spacr-0.2.65}/tests/test_core.py +0 -0
  109. {spacr-0.2.61 → spacr-0.2.65}/tests/test_gui_classify_app.py +0 -0
  110. {spacr-0.2.61 → spacr-0.2.65}/tests/test_gui_mask_app.py +0 -0
  111. {spacr-0.2.61 → spacr-0.2.65}/tests/test_gui_measure_app.py +0 -0
  112. {spacr-0.2.61 → spacr-0.2.65}/tests/test_gui_sim_app.py +0 -0
  113. {spacr-0.2.61 → spacr-0.2.65}/tests/test_gui_utils.py +0 -0
  114. {spacr-0.2.61 → spacr-0.2.65}/tests/test_io.py +0 -0
  115. {spacr-0.2.61 → spacr-0.2.65}/tests/test_mask_app.py +0 -0
  116. {spacr-0.2.61 → spacr-0.2.65}/tests/test_measure.py +0 -0
  117. {spacr-0.2.61 → spacr-0.2.65}/tests/test_plot.py +0 -0
  118. {spacr-0.2.61 → spacr-0.2.65}/tests/test_sim.py +0 -0
  119. {spacr-0.2.61 → spacr-0.2.65}/tests/test_timelapse.py +0 -0
  120. {spacr-0.2.61 → spacr-0.2.65}/tests/test_train.py +0 -0
  121. {spacr-0.2.61 → spacr-0.2.65}/tests/test_umap.py +0 -0
  122. {spacr-0.2.61 → spacr-0.2.65}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spacr
3
- Version: 0.2.61
3
+ Version: 0.2.65
4
4
  Summary: Spatial phenotype analysis of crisp screens (SpaCr)
5
5
  Home-page: https://github.com/EinarOlafsson/spacr
6
6
  Author: Einar Birnir Olafsson
@@ -56,7 +56,7 @@ dependencies = [
56
56
 
57
57
  setup(
58
58
  name="spacr",
59
- version="0.2.61",
59
+ version="0.2.65",
60
60
  author="Einar Birnir Olafsson",
61
61
  author_email="olafsson@med.umich.com",
62
62
  description="Spatial phenotype analysis of crisp screens (SpaCr)",
@@ -17,7 +17,6 @@ from . import gui_utils
17
17
  from . import gui_elements
18
18
  from . import gui_core
19
19
  from . import gui
20
- from . import gui
21
20
  from . import app_make_masks
22
21
  from . import app_mask
23
22
  from . import app_measure
@@ -35,7 +34,7 @@ __all__ = [
35
34
  "plot",
36
35
  "measure",
37
36
  "sim",
38
- "sequencing"
37
+ "sequencing",
39
38
  "timelapse",
40
39
  "deep_spacr",
41
40
  "app_annotate",
@@ -43,7 +42,6 @@ __all__ = [
43
42
  "gui_elements",
44
43
  "gui_core",
45
44
  "gui",
46
- "gui",
47
45
  "app_make_masks",
48
46
  "app_mask",
49
47
  "app_measure",
@@ -83,12 +83,22 @@ def toggle_settings(button_scrollable_frame):
83
83
  def process_fig_queue():
84
84
  global canvas, fig_queue, canvas_widget, parent_frame, uppdate_frequency, figures, figure_index
85
85
 
86
+ from .gui_elements import standardize_figure
86
87
  try:
87
88
  while not fig_queue.empty():
88
89
  fig = fig_queue.get_nowait()
90
+
91
+ if fig is None:
92
+ print("Warning: Retrieved a None figure from fig_queue.")
93
+ continue # Skip processing if the figure is None
94
+
95
+ # Standardize the figure appearance before adding it to the list
96
+ standardize_figure(fig)
97
+
89
98
  figures.append(fig)
90
- figure_index = len(figures) - 1
91
- display_figure(fig)
99
+ if figure_index == len(figures) - 2:
100
+ figure_index += 1
101
+ display_figure(fig)
92
102
  except Exception as e:
93
103
  traceback.print_exc()
94
104
  finally:
@@ -98,8 +108,23 @@ def process_fig_queue():
98
108
  def display_figure(fig):
99
109
  global canvas, canvas_widget
100
110
 
111
+ from .gui_elements import modify_figure_properties, save_figure_as_format, modify_figure
112
+
113
+ # Apply the dark style to the context menu
114
+ style_out = set_dark_style(ttk.Style())
115
+ bg_color = style_out['bg_color']
116
+ fg_color = style_out['fg_color']
117
+
118
+ # Initialize the scale factor for zooming
119
+ scale_factor = 1.0
120
+
121
+ # Save the original x and y limits of the first axis (assuming all axes have the same limits)
122
+ original_xlim = [ax.get_xlim() for ax in fig.get_axes()]
123
+ original_ylim = [ax.get_ylim() for ax in fig.get_axes()]
124
+
101
125
  # Clear previous canvas content
102
- canvas.get_tk_widget().destroy()
126
+ if canvas:
127
+ canvas.get_tk_widget().destroy()
103
128
 
104
129
  # Create a new canvas for the figure
105
130
  new_canvas = FigureCanvasTkAgg(fig, master=canvas_widget.master)
@@ -109,154 +134,141 @@ def display_figure(fig):
109
134
  # Update the global canvas and canvas_widget references
110
135
  canvas = new_canvas
111
136
  canvas_widget = new_canvas.get_tk_widget()
112
-
113
- # Apply the dark style to the context menu
114
- style_out = set_dark_style(ttk.Style())
115
- bg_color = style_out['bg_color']
116
- fg_color = style_out['fg_color']
117
-
118
- # Define the save functions for the context menu
119
- def save_figure_as_format(format):
120
- file_path = filedialog.asksaveasfilename(defaultextension=f".{format}", filetypes=[(f"{format.upper()} files", f"*.{format}"), ("All files", "*.*")])
121
- if file_path:
122
- fig.savefig(file_path, format=format)
123
-
124
- def modify_figure():
125
- def apply_modifications():
126
- try:
127
- x_width = float(x_width_var.get())
128
- y_height = float(y_height_var.get())
129
- line_width = float(line_width_var.get())
130
- font_size = int(font_size_var.get())
131
- modify_figure_properties(fig, x_width=x_width, y_height=y_height, line_width=line_width)
132
- for ax in fig.get_axes():
133
- for label in ax.get_xticklabels() + ax.get_yticklabels():
134
- label.set_fontsize(font_size)
135
- ax.title.set_fontsize(font_size)
136
- ax.xaxis.label.set_fontsize(font_size)
137
- ax.yaxis.label.set_fontsize(font_size)
138
- canvas.draw_idle() # Redraw the canvas after modifications
139
- except ValueError:
140
- print("Invalid input; please enter numeric values.")
141
-
142
- # Create a new window for user input
143
- modify_window = tk.Toplevel()
144
- modify_window.title("Modify Figure Properties")
145
-
146
- # Apply dark style to the popup window
147
- modify_window.configure(bg=bg_color)
148
-
149
- # Create and style the input fields
150
- tk.Label(modify_window, text="X Axis Width:", bg=bg_color, fg=fg_color).grid(row=0, column=0, padx=10, pady=5)
151
- x_width_var = tk.StringVar()
152
- tk.Entry(modify_window, textvariable=x_width_var, bg=bg_color, fg=fg_color).grid(row=0, column=1, padx=10, pady=5)
153
-
154
- tk.Label(modify_window, text="Y Axis Height:", bg=bg_color, fg=fg_color).grid(row=1, column=0, padx=10, pady=5)
155
- y_height_var = tk.StringVar()
156
- tk.Entry(modify_window, textvariable=y_height_var, bg=bg_color, fg=fg_color).grid(row=1, column=1, padx=10, pady=5)
157
-
158
- tk.Label(modify_window, text="Line Width:", bg=bg_color, fg=fg_color).grid(row=2, column=0, padx=10, pady=5)
159
- line_width_var = tk.StringVar()
160
- tk.Entry(modify_window, textvariable=line_width_var, bg=bg_color, fg=fg_color).grid(row=2, column=1, padx=10, pady=5)
161
-
162
- tk.Label(modify_window, text="Font Size:", bg=bg_color, fg=fg_color).grid(row=3, column=0, padx=10, pady=5)
163
- font_size_var = tk.StringVar()
164
- tk.Entry(modify_window, textvariable=font_size_var, bg=bg_color, fg=fg_color).grid(row=3, column=1, padx=10, pady=5)
165
-
166
- # Apply button
167
- apply_button = tk.Button(modify_window, text="Apply", command=apply_modifications, bg=bg_color, fg=fg_color)
168
- apply_button.grid(row=4, column=0, columnspan=2, pady=10)
137
+ canvas_widget.configure(bg=bg_color)
169
138
 
170
139
  # Create the context menu
171
140
  context_menu = tk.Menu(canvas_widget, tearoff=0, bg=bg_color, fg=fg_color)
172
- context_menu.add_command(label="Save Figure as PDF", command=lambda: save_figure_as_format('pdf'))
173
- context_menu.add_command(label="Save Figure as PNG", command=lambda: save_figure_as_format('png'))
174
- context_menu.add_command(label="Modify Figure", command=modify_figure)
141
+ context_menu.add_command(label="Save Figure as PDF", command=lambda: save_figure_as_format(fig, 'pdf'))
142
+ context_menu.add_command(label="Save Figure as PNG", command=lambda: save_figure_as_format(fig, 'png'))
143
+ context_menu.add_command(label="Modify Figure", command=lambda: modify_figure(fig))
144
+ context_menu.add_command(label="Reset Zoom", command=lambda: reset_zoom(fig)) # Add Reset Zoom option
145
+
146
+ def reset_zoom(fig):
147
+ global scale_factor
148
+ scale_factor = 1.0 # Reset the scale factor
149
+
150
+ for i, ax in enumerate(fig.get_axes()):
151
+ ax.set_xlim(original_xlim[i])
152
+ ax.set_ylim(original_ylim[i])
153
+ fig.canvas.draw_idle()
175
154
 
176
155
  def on_right_click(event):
177
156
  context_menu.post(event.x_root, event.y_root)
178
157
 
179
- new_canvas.get_tk_widget().bind("<Button-3>", on_right_click)
158
+ def on_hover(event):
159
+ widget_width = event.widget.winfo_width()
160
+ x_position = event.x
161
+
162
+ if x_position < widget_width / 2:
163
+ canvas_widget.config(cursor="hand2")
164
+ else:
165
+ canvas_widget.config(cursor="hand2")
166
+
167
+ def on_leave(event):
168
+ canvas_widget.config(cursor="arrow")
169
+
170
+ def flash_feedback(side):
171
+ flash = tk.Toplevel(canvas_widget.master)
172
+ flash.overrideredirect(True)
173
+ flash_width = int(canvas_widget.winfo_width() / 2)
174
+ flash_height = canvas_widget.winfo_height()
175
+ flash.configure(bg='white')
176
+ flash.attributes('-alpha', 0.9)
177
+
178
+ if side == "left":
179
+ flash.geometry(f"{flash_width}x{flash_height}+{canvas_widget.winfo_rootx()}+{canvas_widget.winfo_rooty()}")
180
+ else:
181
+ flash.geometry(f"{flash_width}x{flash_height}+{canvas_widget.winfo_rootx() + flash_width}+{canvas_widget.winfo_rooty()}")
182
+
183
+ flash.lift()
184
+
185
+ # Ensure the flash covers the correct area only
186
+ flash.update_idletasks()
187
+ flash.after(100, flash.destroy)
188
+
189
+ def on_click(event):
190
+ widget_width = event.widget.winfo_width()
191
+ x_position = event.x
192
+
193
+ if x_position < widget_width / 2:
194
+ #flash_feedback("left")
195
+ show_previous_figure()
196
+ else:
197
+ #flash_feedback("right")
198
+ show_next_figure()
199
+
200
+ def zoom(event):
201
+ nonlocal scale_factor
202
+
203
+ zoom_speed = 0.1 # Adjust the zoom speed for smoother experience
204
+
205
+ # Adjust zoom factor based on the operating system and mouse event
206
+ if event.num == 4 or event.delta > 0: # Scroll up
207
+ scale_factor *= (1 + zoom_speed)
208
+ elif event.num == 5 or event.delta < 0: # Scroll down
209
+ scale_factor /= (1 + zoom_speed)
210
+
211
+ # Get mouse position relative to the figure
212
+ x_mouse, y_mouse = event.x, event.y
213
+ x_ratio = x_mouse / canvas_widget.winfo_width()
214
+ y_ratio = y_mouse / canvas_widget.winfo_height()
215
+
216
+ for ax in fig.get_axes():
217
+ xlim = ax.get_xlim()
218
+ ylim = ax.get_ylim()
219
+
220
+ # Calculate the new limits
221
+ x_center = xlim[0] + x_ratio * (xlim[1] - xlim[0])
222
+ y_center = ylim[0] + (1 - y_ratio) * (ylim[1] - ylim[0])
223
+
224
+ x_range = (xlim[1] - xlim[0]) * scale_factor
225
+ y_range = (ylim[1] - ylim[0]) * scale_factor
226
+
227
+ ax.set_xlim([x_center - x_range * x_ratio, x_center + x_range * (1 - x_ratio)])
228
+ ax.set_ylim([y_center - y_range * (1 - y_ratio), y_center + y_range * y_ratio])
229
+
230
+ # Redraw the figure
231
+ fig.canvas.draw_idle()
232
+
233
+ # Bind events for hover, click interactions, and zoom
234
+ canvas_widget.bind("<Motion>", on_hover)
235
+ canvas_widget.bind("<Leave>", on_leave)
236
+ canvas_widget.bind("<Button-1>", on_click)
237
+ canvas_widget.bind("<Button-3>", on_right_click)
238
+
239
+ # Bind mouse wheel for zooming (cross-platform)
240
+ canvas_widget.bind("<MouseWheel>", zoom) # Windows
241
+ canvas_widget.bind("<Button-4>", zoom) # Linux/macOS Scroll Up
242
+ canvas_widget.bind("<Button-5>", zoom) # Linux/macOS Scroll Down
180
243
 
181
244
  def clear_unused_figures():
182
245
  global figures, figure_index
183
246
 
184
247
  lower_bound = max(0, figure_index - 20)
185
248
  upper_bound = min(len(figures), figure_index + 20)
186
-
187
249
  # Clear figures outside of the +/- 20 range
188
250
  figures = deque([fig for i, fig in enumerate(figures) if lower_bound <= i <= upper_bound])
189
-
190
251
  # Update the figure index after clearing
191
252
  figure_index = min(max(figure_index, 0), len(figures) - 1)
192
253
 
193
254
  def show_previous_figure():
194
- global figure_index, figures
255
+ global figure_index, figures, fig_queue
195
256
  if figure_index is not None and figure_index > 0:
196
257
  figure_index -= 1
197
258
  display_figure(figures[figure_index])
198
259
  clear_unused_figures()
199
260
 
200
261
  def show_next_figure():
201
- global figure_index, figures
262
+ global figure_index, figures, fig_queue
202
263
  if figure_index is not None and figure_index < len(figures) - 1:
203
264
  figure_index += 1
204
265
  display_figure(figures[figure_index])
205
266
  clear_unused_figures()
206
-
207
- def save_figure_as_format(fig, file_format):
208
- file_path = filedialog.asksaveasfilename(defaultextension=f".{file_format}", filetypes=[(f"{file_format.upper()} files", f"*.{file_format}"), ("All files", "*.*")])
209
- if file_path:
210
- try:
211
- fig.savefig(file_path, format=file_format)
212
- print(f"Figure saved as {file_format.upper()} at {file_path}")
213
- except Exception as e:
214
- print(f"Error saving figure: {e}")
215
-
216
- def modify_figure_properties(fig, x_width=None, y_height=None, line_width=None):
217
- """
218
- Modifies the properties of the figure, including axis dimensions and line widths.
219
-
220
- Parameters:
221
- - fig: The matplotlib figure object to modify.
222
- - x_width: Desired width for the x-axis (optional).
223
- - y_height: Desired height for the y-axis (optional).
224
- - line_width: Desired line width for all lines (optional).
225
- """
226
- for ax in fig.get_axes():
227
- # Scaling the figure
228
- if x_width is not None or y_height is not None:
229
- # Get the current axis limits
230
- current_xlim = ax.get_xlim()
231
- current_ylim = ax.get_ylim()
232
-
233
- # Set new limits
234
- if x_width is not None:
235
- scale_factor_x = x_width / (current_xlim[1] - current_xlim[0])
236
- else:
237
- scale_factor_x = 1
238
-
239
- if y_height is not None:
240
- scale_factor_y = y_height / (current_ylim[1] - current_ylim[0])
241
- else:
242
- scale_factor_y = 1
243
-
244
- # Adjust the figure size and elements proportionally
245
- fig.set_size_inches(fig.get_size_inches() * scale_factor_x * scale_factor_y, forward=True)
246
- ax.set_xlim(left=current_xlim[0] * scale_factor_x, right=current_xlim[1] * scale_factor_x)
247
- ax.set_ylim(bottom=current_ylim[0] * scale_factor_y, top=current_ylim[1] * scale_factor_y)
248
-
249
- # Adjust line width and other elements if specified
250
- if line_width is not None:
251
- for line in ax.get_lines():
252
- line.set_linewidth(line_width)
253
- for spine in ax.spines.values(): # Modify width of spines (e.g., scale bars)
254
- spine.set_linewidth(line_width)
255
- ax.tick_params(width=line_width) # Modify width of ticks
256
- for text in ax.get_xticklabels() + ax.get_yticklabels():
257
- text.set_fontsize(ax.get_xticklabels()[0].get_fontsize())
258
-
259
- fig.canvas.draw_idle()
267
+ elif figure_index == len(figures) - 1 and not fig_queue.empty():
268
+ fig = fig_queue.get_nowait()
269
+ figures.append(fig)
270
+ figure_index += 1
271
+ display_figure(fig)
260
272
 
261
273
  def set_globals(thread_control_var, q_var, console_output_var, parent_frame_var, vars_dict_var, canvas_var, canvas_widget_var, scrollable_frame_var, fig_queue_var, figures_var, figure_index_var, progress_bar_var, usage_bars_var, fig_memory_limit_var, figure_current_memory_usage_var):
262
274
  global thread_control, q, console_output, parent_frame, vars_dict, canvas, canvas_widget, scrollable_frame, fig_queue, figures, figure_index, progress_bar, usage_bars, fig_memory_limit, figure_current_memory_usage
@@ -416,7 +428,7 @@ def setup_plot_section(vertical_container):
416
428
  plot_frame.grid_columnconfigure(0, weight=1)
417
429
 
418
430
  canvas.draw()
419
- canvas.figure = figure
431
+ canvas.figure = figure # Ensure that the figure is linked to the canvas
420
432
  style_out = set_dark_style(ttk.Style())
421
433
 
422
434
  figure.patch.set_facecolor(style_out['bg_color'])
@@ -425,19 +437,6 @@ def setup_plot_section(vertical_container):
425
437
  widgets = [canvas_widget]
426
438
  style = ttk.Style(vertical_container)
427
439
  _ = set_dark_style(style, containers=containers, widgets=widgets)
428
-
429
- # Add navigation buttons using spacrButton
430
- button_frame = tk.Frame(plot_frame, bg=style_out['bg_color'])
431
- button_frame.grid(row=1, column=0, sticky='ew', pady=5)
432
-
433
- size_dict = set_element_size()
434
-
435
- btn_size = int(size_dict['btn_size']*0.75)
436
- prev_button = spacrButton(button_frame, text="Previous", command=show_previous_figure, bg=style_out['bg_color'], show_text=False, size=btn_size, animation=False)
437
- prev_button.pack(side='left', padx=5)
438
-
439
- next_button = spacrButton(button_frame, text="Next", command=show_next_figure, bg=style_out['bg_color'], show_text=False, size=btn_size, animation=False)
440
- next_button.pack(side='right', padx=5)
441
440
 
442
441
  return canvas, canvas_widget
443
442
 
@@ -842,7 +841,7 @@ def initiate_root(parent, settings_type='mask'):
842
841
  from .gui_utils import setup_frame
843
842
  from .settings import descriptions
844
843
 
845
- uppdate_frequency = 1000
844
+ uppdate_frequency = 100
846
845
 
847
846
  # Start tracemalloc and initialize global variables
848
847
  tracemalloc.start()