batoolset 0.1.0__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.
Files changed (162) hide show
  1. batoolset/GUI/__init__.py +0 -0
  2. batoolset/GUI/list_gui.py +513 -0
  3. batoolset/GUI/multi_image_display.py +989 -0
  4. batoolset/GUI/open.py +325 -0
  5. batoolset/GUI/overlay_hints.py +45 -0
  6. batoolset/GUI/paint2.py +1345 -0
  7. batoolset/GUI/scrollablepaint.py +1152 -0
  8. batoolset/IJ_ROIs/__init__.py +0 -0
  9. batoolset/IJ_ROIs/tools.py +40 -0
  10. batoolset/PATH/__init__.py +0 -0
  11. batoolset/PATH/tools.py +79 -0
  12. batoolset/SQLite_tools/__init__.py +0 -0
  13. batoolset/SQLite_tools/tools.py +840 -0
  14. batoolset/__init__.py +0 -0
  15. batoolset/binary/__init__.py +0 -0
  16. batoolset/binary/tools.py +123 -0
  17. batoolset/binarytools/__init__.py +0 -0
  18. batoolset/binarytools/cell_center_detector.py +290 -0
  19. batoolset/clipboard_tools/__init__.py +0 -0
  20. batoolset/clipboard_tools/tools.py +7 -0
  21. batoolset/colors/__init__.py +0 -0
  22. batoolset/colors/colorgen.py +193 -0
  23. batoolset/colors/tools.py +22 -0
  24. batoolset/command_line/__init__.py +0 -0
  25. batoolset/command_line/tools.py +18 -0
  26. batoolset/dialogs/__init__.py +0 -0
  27. batoolset/dialogs/opensave.py +228 -0
  28. batoolset/dicts/__init__.py +0 -0
  29. batoolset/dicts/tools.py +299 -0
  30. batoolset/dims/__init__.py +0 -0
  31. batoolset/dims/tools.py +83 -0
  32. batoolset/draw/__init__.py +0 -0
  33. batoolset/draw/shapes/Position.py +183 -0
  34. batoolset/draw/shapes/__init__.py +0 -0
  35. batoolset/draw/shapes/automated_alignment_drawing_refactored.py +346 -0
  36. batoolset/draw/shapes/circle2d.py +99 -0
  37. batoolset/draw/shapes/compute_optimal_size_all_merged.py +317 -0
  38. batoolset/draw/shapes/ellipse2d.py +336 -0
  39. batoolset/draw/shapes/freehand2d.py +235 -0
  40. batoolset/draw/shapes/group.py +1830 -0
  41. batoolset/draw/shapes/image2d.py +2469 -0
  42. batoolset/draw/shapes/line2d.py +575 -0
  43. batoolset/draw/shapes/point2d.py +257 -0
  44. batoolset/draw/shapes/polygon2d.py +357 -0
  45. batoolset/draw/shapes/polyline2d.py +235 -0
  46. batoolset/draw/shapes/rect2d.py +388 -0
  47. batoolset/draw/shapes/rectangle2d.py +601 -0
  48. batoolset/draw/shapes/scalebar.py +304 -0
  49. batoolset/draw/shapes/serializablefont.py +126 -0
  50. batoolset/draw/shapes/serializableguiparams.py +10 -0
  51. batoolset/draw/shapes/square2d.py +103 -0
  52. batoolset/draw/shapes/textorientation.py +45 -0
  53. batoolset/draw/shapes/tools.py +467 -0
  54. batoolset/draw/shapes/transform2D.py +350 -0
  55. batoolset/draw/shapes/txt2d.py +550 -0
  56. batoolset/draw/widgets/__init__.py +0 -0
  57. batoolset/draw/widgets/col.py +343 -0
  58. batoolset/draw/widgets/image_group.py +248 -0
  59. batoolset/draw/widgets/image_organizer.py +96 -0
  60. batoolset/draw/widgets/paint.py +184 -0
  61. batoolset/draw/widgets/vectorial.py +257 -0
  62. batoolset/figure/__init__.py +0 -0
  63. batoolset/figure/alignment.py +814 -0
  64. batoolset/figure/column.py +1117 -0
  65. batoolset/figure/fig_tools.py +285 -0
  66. batoolset/figure/minimal_debugger_scale_etc.py +139 -0
  67. batoolset/figure/panel.py +697 -0
  68. batoolset/figure/row.py +852 -0
  69. batoolset/figure/user_selection.py +287 -0
  70. batoolset/files/__init__.py +0 -0
  71. batoolset/files/tools.py +1321 -0
  72. batoolset/images/__init__.py +0 -0
  73. batoolset/images/tools.py +81 -0
  74. batoolset/img.py +5216 -0
  75. batoolset/linux/__init__.py +0 -0
  76. batoolset/linux/tools.py +72 -0
  77. batoolset/lists/__init__.py +0 -0
  78. batoolset/lists/tools.py +436 -0
  79. batoolset/luts/__init__.py +0 -0
  80. batoolset/luts/lut_minimal_test.py +1207 -0
  81. batoolset/matplolib/__init__.py +0 -0
  82. batoolset/matplolib/tools.py +44 -0
  83. batoolset/np_tools/__init__.py +0 -0
  84. batoolset/np_tools/tools.py +252 -0
  85. batoolset/np_tools/trash.py +15 -0
  86. batoolset/pandas_tools/__init__.py +0 -0
  87. batoolset/pandas_tools/tools.py +880 -0
  88. batoolset/partials/__init__.py +0 -0
  89. batoolset/partials/tools.py +83 -0
  90. batoolset/plot_tools/__init__.py +0 -0
  91. batoolset/plot_tools/tools.py +70 -0
  92. batoolset/pyqt/__init__.py +0 -0
  93. batoolset/pyqt/tools.py +691 -0
  94. batoolset/re_tools/__init__.py +0 -0
  95. batoolset/re_tools/tools.py +35 -0
  96. batoolset/serialization/__init__.py +0 -0
  97. batoolset/serialization/tools.py +1192 -0
  98. batoolset/sets/__init__.py +0 -0
  99. batoolset/sets/tools.py +109 -0
  100. batoolset/settings/__init__.py +0 -0
  101. batoolset/settings/global_settings.py +134 -0
  102. batoolset/strings/__init__.py +0 -0
  103. batoolset/strings/tools.py +225 -0
  104. batoolset/ta/__init__.py +0 -0
  105. batoolset/ta/database/__init__.py +0 -0
  106. batoolset/ta/database/advanced_sql_plotter.py +1170 -0
  107. batoolset/ta/database/my_qt_table.py +79 -0
  108. batoolset/ta/database/preview_and_edit_sqlite_db.py +405 -0
  109. batoolset/ta/database/sql.py +2141 -0
  110. batoolset/ta/database/sql_column_name_dialog.py +122 -0
  111. batoolset/ta/measurements/TAmeasures.py +2226 -0
  112. batoolset/ta/measurements/__init__.py +0 -0
  113. batoolset/ta/measurements/measurements3D/__init__.py +0 -0
  114. batoolset/ta/measurements/measurements3D/get_point_on_surface_if_centroid_is_bad.py +175 -0
  115. batoolset/ta/measurements/measurements3D/height_map_to_projection.py +82 -0
  116. batoolset/ta/measurements/measurements3D/measures3D.py +208 -0
  117. batoolset/ta/measurements/measurements3D/triangulate.py +331 -0
  118. batoolset/ta/measurements/nematic.py +562 -0
  119. batoolset/ta/measurements/nematic_measurements.py +107 -0
  120. batoolset/ta/segmentation/__init__.py +0 -0
  121. batoolset/ta/segmentation/neo_wshed.py +314 -0
  122. batoolset/ta/selections/__init__.py +0 -0
  123. batoolset/ta/selections/selection.py +329 -0
  124. batoolset/ta/tracking/__init__.py +0 -0
  125. batoolset/ta/tracking/last_tracking_based_on_matching_or_on_translation_from_mermaid_warp.py +653 -0
  126. batoolset/ta/tracking/local_to_track_correspondance.py +138 -0
  127. batoolset/ta/tracking/rapid_detection_of_vertices.py +517 -0
  128. batoolset/ta/tracking/registration.py +108 -0
  129. batoolset/ta/tracking/swap_detector_and_fixer.py +296 -0
  130. batoolset/ta/tracking/track_correction.py +238 -0
  131. batoolset/ta/tracking/tracking_error_detector_and_fixer.py +3099 -0
  132. batoolset/ta/tracking/tracking_yet_another_approach_pyramidal_registration_n_neo_swapping_correction.py +725 -0
  133. batoolset/ta/utils/TA_tools.py +43 -0
  134. batoolset/ta/utils/__init__.py +0 -0
  135. batoolset/ta/utils/rps_tools.py +1783 -0
  136. batoolset/tests/__init__.py +0 -0
  137. batoolset/tests/rps_tools.py +51 -0
  138. batoolset/tests/tools.py +10 -0
  139. batoolset/tools/__init__.py +0 -0
  140. batoolset/tools/early_stopper_class.py +9 -0
  141. batoolset/tools/guided_data_recoverer.py +110 -0
  142. batoolset/tools/logger.py +100 -0
  143. batoolset/tools/mytimer.py +31 -0
  144. batoolset/tools/prompt_color.py +160 -0
  145. batoolset/tools/qthandler.py +118 -0
  146. batoolset/uitools/__init__.py +0 -0
  147. batoolset/uitools/blinker.py +56 -0
  148. batoolset/unsafe/__init__.py +0 -0
  149. batoolset/unsafe/tools.py +115 -0
  150. batoolset/utils/__init__.py +0 -0
  151. batoolset/utils/commontools.py +158 -0
  152. batoolset/utils/loadlist.py +728 -0
  153. batoolset/version.py +10 -0
  154. batoolset/xml/__init__.py +0 -0
  155. batoolset/xml/tools.py +65 -0
  156. batoolset/zip_tools/__init__.py +0 -0
  157. batoolset/zip_tools/tools.py +76 -0
  158. batoolset-0.1.0.dist-info/LICENSE +24 -0
  159. batoolset-0.1.0.dist-info/METADATA +45 -0
  160. batoolset-0.1.0.dist-info/RECORD +162 -0
  161. batoolset-0.1.0.dist-info/WHEEL +5 -0
  162. batoolset-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1192 @@
1
+ from batoolset.settings.global_settings import set_UI # set the UI to qtpy
2
+ set_UI()
3
+ from builtins import int
4
+ from batoolset.files.tools import read_string_from_file
5
+ import xml.etree.ElementTree as ET
6
+ import xml.dom.minidom
7
+ from batoolset.draw.shapes.txt2d import TAText2D
8
+ from batoolset.draw.shapes.Position import Position
9
+ # from batoolset.serialization.tools import deserialize_to_dict
10
+
11
+
12
+ # see key=='coords_as_list' and not key=='range': # excetptions that should not be written as texts even though they are texts for exceptions
13
+ def object_to_xml(obj, element=None, keys_to_ignore=['img','renderer','doc','qimage'], is_list=False):
14
+ obj_dict = None
15
+ if element is None:
16
+ # if is_list:
17
+ # element = ET.Element("list")
18
+ # else:
19
+ element = ET.Element(type(obj).__name__)
20
+
21
+ if hasattr(obj, 'to_dict'):
22
+ obj_dict = obj.to_dict()
23
+ elif isinstance(obj, (list, tuple)):
24
+ if is_list:
25
+ for item in obj:
26
+ child = ET.SubElement(element, type(item).__name__)
27
+ object_to_xml(item, child)
28
+ else:
29
+ obj_dict = [object_to_xml(item) for item in obj]
30
+ elif isinstance(obj, dict):
31
+ obj_dict = {k: object_to_xml(v) for k, v in obj.items()}
32
+ elif isinstance(obj, (str, int, float, bool)):
33
+ obj_dict = obj
34
+ else:
35
+ obj_dict = obj.__dict__
36
+ if isinstance(obj_dict, dict):
37
+ for key, value in obj_dict.items():
38
+ if keys_to_ignore and key in keys_to_ignore:
39
+ continue
40
+
41
+ child = ET.SubElement(element, key)
42
+
43
+ if isinstance(value, TAText2D):
44
+ child.text = value.getHtmlText()
45
+ elif isinstance(value, Position): # force serialization of Position as a string because it is much better
46
+ child.text = str(value)
47
+ elif isinstance(value, (list, tuple)):
48
+ for item in value:
49
+ grandchild = ET.SubElement(child, type(item).__name__)
50
+ object_to_xml(item, grandchild) # --> this makes an infinite loop but just with the Image2D with annotation = []
51
+ # elif hasattr(value, '__dict__'):
52
+ # object_to_xml(value, child)
53
+ else:
54
+ if isinstance(value, str) and not key=='coords_as_list' and not key=='range' and not key=='LUTs': # excetptions that should not be written as texts even though they are texts
55
+ child.text = f'""{str(value)}""'
56
+ else:
57
+ child.text = str(value)
58
+ else:
59
+ if obj_dict:
60
+ element.text = str(obj_dict)
61
+ else:
62
+ element.text = None
63
+
64
+ rough_string = ET.tostring(element, encoding='unicode', method='xml', xml_declaration=False)
65
+ reparsed = xml.dom.minidom.parseString(rough_string)
66
+ return reparsed.toprettyxml(indent=" ")
67
+
68
+ def create_objects_from_dict(objects_dict):
69
+ annotations = []
70
+
71
+ if isinstance(objects_dict, dict):
72
+
73
+ for obj_type, parameters in objects_dict.items(): # big pb it does not save and store the right index of the object in the list -−> see how I can do that and preserve it to sort them back
74
+ try:
75
+ if isinstance(parameters, list): # if there are many objects then one deserializes then all
76
+ for parameter in parameters:
77
+ annotations.append(create_object(obj_type, parameter))
78
+ else:
79
+ annotations.append(create_object(obj_type, parameters))
80
+ except:
81
+ print(f'ERROR deserialization: {obj_type} with parameters {parameters}') # ok that is my error when there are many objects of the same type
82
+ else:
83
+ # dirty hack to recover annotations in the right order
84
+ for dct in objects_dict: # big pb it does not save and store the right index of the object in the list -−> see how I can do that and preserve it to sort them back
85
+ obj_type, parameters = list(dct.items())[0]
86
+ try:
87
+ if isinstance(parameters, list): # if there are many objects then one deserializes then all
88
+ for parameter in parameters:
89
+ annotations.append(create_object(obj_type, parameter))
90
+ else:
91
+ annotations.append(create_object(obj_type, parameters))
92
+ except:
93
+ print(f'ERROR deserialization: {obj_type} with parameters {parameters}') # ok that is my error when there are many objects of the same type
94
+ return annotations
95
+
96
+ def clone_object(objects, auto_unpack_if_single=True, overrides=None): # overrides offers the possibility to mutate one of the parameters of the clone!
97
+ from batoolset.draw.shapes.image2d import Image2D
98
+ clones = []
99
+ if isinstance(objects, list) and not objects:
100
+ return clones
101
+ if not isinstance(objects, (Image2D, TAText2D)) and not objects:
102
+ return clones
103
+ # if objects is None:
104
+ # return clones
105
+ # if not objects: # why is this shit considered to be empty
106
+ # print('Error nothing to clone', objects, not objects)
107
+ # return clones
108
+ if not isinstance(objects,list):
109
+ objects=[objects]
110
+ for object in objects:
111
+ xml_string = object_to_xml(object)
112
+ # get the class of the instance
113
+ instance_class = type(object)
114
+ # get the name of the class
115
+ class_name = instance_class.__name__
116
+ # print('in there', class_name, 'oubsi')
117
+ original_dict = deserialize_to_dict(xml_string)
118
+ if isinstance(overrides, dict):
119
+ original_dict.update(overrides)
120
+ clones.append(create_object(class_name, original_dict))
121
+ if auto_unpack_if_single and len(clones) == 1:
122
+ return clones[0]
123
+ return clones
124
+
125
+ def create_object(object_type,properties):
126
+ from batoolset.draw.shapes.circle2d import Circle2D
127
+ from batoolset.draw.shapes.image2d import Image2D
128
+ from batoolset.draw.shapes.ellipse2d import Ellipse2D
129
+ from batoolset.draw.shapes.freehand2d import Freehand2D
130
+ from batoolset.draw.shapes.rectangle2d import Rectangle2D
131
+ from batoolset.draw.shapes.line2d import Line2D
132
+ from batoolset.draw.shapes.point2d import Point2D
133
+ from batoolset.draw.shapes.polygon2d import Polygon2D
134
+ from batoolset.draw.shapes.polyline2d import PolyLine2D
135
+ from batoolset.draw.shapes.scalebar import ScaleBar
136
+ from batoolset.draw.shapes.square2d import Square2D
137
+ from batoolset.draw.shapes.group import Group
138
+ from batoolset.draw.shapes.serializablefont import SerializableQFont
139
+ from batoolset.draw.shapes.serializableguiparams import SerializableGUIparameters
140
+
141
+ # print(object_type)
142
+
143
+ if object_type == list.__name__:
144
+ return create_objects_from_dict(properties)
145
+ elif object_type == Image2D.__name__:
146
+ # I can code custom shit in there
147
+ # if not 'args' in properties and 'filename' in properties:
148
+ # properties['args']=properties['filename']
149
+ # print('trying to create an image', properties)
150
+ return Image2D(**properties)
151
+ elif object_type == Line2D.__name__:
152
+ return Line2D(**properties)
153
+ elif object_type == TAText2D.__name__:
154
+ return TAText2D(**properties)
155
+ elif object_type == Point2D.__name__:
156
+ return Point2D(**properties)
157
+ elif object_type == Ellipse2D.__name__:
158
+ return Ellipse2D(**properties)
159
+ elif object_type == Circle2D.__name__:
160
+ return Circle2D(**properties)
161
+ elif object_type == Freehand2D.__name__:
162
+ return Freehand2D(**properties)
163
+ elif object_type == Polygon2D.__name__:
164
+ return Polygon2D(**properties)
165
+ elif object_type == PolyLine2D.__name__:
166
+ return PolyLine2D(**properties)
167
+ elif object_type == Rectangle2D.__name__:
168
+ return Rectangle2D(**properties)
169
+ elif object_type == Square2D.__name__:
170
+ return Square2D(**properties)
171
+ elif object_type == ScaleBar.__name__:
172
+ return ScaleBar(**properties)
173
+ elif object_type == Group.__name__:
174
+ return Group(**properties)
175
+ elif object_type == SerializableQFont.__name__:
176
+ # print('I am in there,', properties)
177
+ return SerializableQFont.from_dict(properties)
178
+ elif object_type == SerializableGUIparameters.__name__:
179
+ return SerializableGUIparameters(**properties)
180
+ else:
181
+ print(f'unknown type for deserialization {object_type}')
182
+
183
+
184
+ def is_float(str):
185
+ try:
186
+ float(str)
187
+ return True
188
+ except:
189
+ return False
190
+
191
+
192
+ def deserialize_to_dict(xml_string):
193
+ root = ET.fromstring(xml_string)
194
+ return element_to_dict(root)
195
+
196
+
197
+ def process_value(value):
198
+ if value in ['None', 'True', 'False']:
199
+ if value == 'None':
200
+ value = None
201
+ elif value == 'True':
202
+ value = True
203
+ elif value == 'False':
204
+ value = False
205
+ elif isinstance(value, str) and value.startswith('""') and value.endswith('""'):
206
+ value = value[2:-2]
207
+ elif isinstance(value, str) and value.startswith('[') and value.endswith(']'):
208
+ value = eval(value)
209
+ elif value.isdigit():
210
+ value = int(value)
211
+ elif is_float(value):
212
+ value = float(value)
213
+ return value
214
+
215
+
216
+ def element_to_dict_neo(element):
217
+ properties = {}
218
+
219
+ for child in element:
220
+ tag = child.tag
221
+ value = None
222
+
223
+ if list(child): # check if current element has any sub-elements
224
+ # If the tag is 'annotations', we want to store a list of dictionaries
225
+ if tag == 'annotations':
226
+ value = []
227
+ for grandchild in child:
228
+ grandchild_dict = element_to_dict(grandchild)
229
+ value.append(grandchild_dict)
230
+ # For other tags with sub-elements, we store a single dictionary
231
+ else:
232
+ value = {}
233
+ for grandchild in child:
234
+ if grandchild.tag == 'metadata' or grandchild.tag == 'positions' or grandchild.tag == 'annotations':
235
+ continue
236
+ else:
237
+ grandchild_dict = element_to_dict(grandchild)
238
+ value.update(grandchild_dict)
239
+ else:
240
+ value = child.text
241
+
242
+ # Process the value
243
+ value = process_value(value)
244
+
245
+ # If tag already exists in properties, append the new value to the list
246
+ if tag in properties:
247
+ if not isinstance(properties[tag], list):
248
+ properties[tag] = [properties[tag]]
249
+ properties[tag].append(value)
250
+ # If tag does not exist, add it with the new value
251
+ else:
252
+ properties[tag] = value
253
+
254
+ return properties
255
+
256
+ def element_to_dict(element):
257
+ properties = {}
258
+
259
+ for child in element:
260
+ tag = child.tag
261
+
262
+ # print('tag',tag)
263
+
264
+ if list(child): # check if current element has any sub-elements
265
+
266
+ if tag == 'annotations':
267
+ value = []
268
+ for grandchild in child:
269
+ grandchild_dict = element_to_dict(grandchild)
270
+ value.append({grandchild.tag:grandchild_dict})
271
+ else:
272
+ # Recursively parse sub-elements and store the resulting dictionary
273
+ # print('tag2',tag)
274
+ value = element_to_dict(child) # the second entrance create the pb
275
+ #
276
+ # if tag == 'annotations':
277
+ # print('babidi', value) #
278
+ else:
279
+ value = child.text
280
+
281
+ if value is None:
282
+ value = {}
283
+ for grandchild in child:
284
+ if grandchild.tag == 'metadata':
285
+ value = eval(grandchild.text)
286
+ elif grandchild.tag == 'positions':
287
+ # print('INSIDE POSITIONS', grandchild.text)
288
+ value[grandchild.tag] = eval(grandchild.text)
289
+ elif grandchild.tag == 'annotations':
290
+ # print('inside annotations', grandchild)
291
+ pass
292
+ else:
293
+ value[grandchild.tag] = element_to_dict(grandchild)
294
+ else:
295
+ if isinstance(value, dict):
296
+ # If value is a dictionary, leave it as is
297
+ # print('ignored', tag, value)
298
+ # --> the annotations are ignored and they should not
299
+ # print('value ignored', tag, len(value)) # this is the dict of the values of the annotations --> somehow I need to take them
300
+ pass
301
+ elif value in ['None', 'True', 'False']:
302
+ if value == 'None':
303
+ value = None
304
+ elif value == 'True':
305
+ value = True
306
+ elif value == 'False':
307
+ value = False
308
+ elif isinstance(value, str) and value.startswith('""') and value.endswith('""'):
309
+ value = value[2:-2]
310
+ elif isinstance(value, str) and value.startswith('[') and value.endswith(']'):
311
+ value = eval(value) # recreate the dict from string
312
+ elif isinstance(value, list):
313
+ pass
314
+ elif value.isdigit():
315
+ value = int(value)
316
+ elif is_float(value):
317
+ value = float(value)
318
+
319
+ # if tag == 'annotations':
320
+ # print('annotations--> ',tag, value)
321
+ # properties[tag] = value # if it contains it already it will override it --> that is the error
322
+ # Check if tag already exists in properties
323
+ if tag in properties:
324
+ # If tag already exists, check if the value is a list
325
+ if not isinstance(properties[tag], list):
326
+ # If the value is not a list, convert it to a list
327
+ properties[tag] = [properties[tag]]
328
+ # Append the new value to the list
329
+ properties[tag].append(value)
330
+ else:
331
+ # If tag does not exist, add it with the new value
332
+ properties[tag] = value
333
+
334
+ return properties
335
+
336
+
337
+ def has_custom_script(xml_string):
338
+ root = ET.fromstring(xml_string)
339
+
340
+ # Find the custom_loading_script element anywhere in the XML
341
+ custom_script_tags = root.findall(".//custom_loading_script")
342
+
343
+ for custom_script_tag in custom_script_tags:
344
+ custom_script = custom_script_tag.text
345
+ if custom_script is not None and custom_script.strip() != 'None' and custom_script.strip():
346
+ return True
347
+
348
+ return False
349
+
350
+ if __name__ == '__main__':
351
+ # from batoolset.serialization.tools import object_to_xml, create_object
352
+ from batoolset.settings.global_settings import set_UI # set the UI to qtpy
353
+
354
+ set_UI()
355
+ from batoolset.draw.shapes.image2d import Rectangle2D
356
+ from qtpy.QtCore import QRect, Qt, QRectF
357
+ from batoolset.draw.shapes.image2d import Image2D
358
+ import numpy as np
359
+ import sys
360
+ from qtpy.QtWidgets import QApplication
361
+ from qtpy.QtGui import QFont
362
+ from batoolset.draw.shapes.group import Group
363
+ from batoolset.draw.shapes.serializablefont import SerializableQFont
364
+
365
+ app = QApplication(sys.argv) # IMPORTANT KEEP !!!!!!!!!!!
366
+
367
+ if True:
368
+ img = Image2D('/E/Sample_images/sample_images_FIJI/first-instar-brain.tif')
369
+ # img.dimensions = {'order': 'tdhw', 'values': [15, 35]}
370
+ # img.LUTs = [None,'GREEN']
371
+ img.normalization = {
372
+ "min_range": 'toto',
373
+ "min_value": 0,
374
+ "max_range": 'tutu',
375
+ "max_value": 255,
376
+ "per_channel": True
377
+ }
378
+
379
+ print(img.normalization)
380
+
381
+ print(img.to_dict()['normalization'])
382
+ print(type(img.to_dict()['normalization']))
383
+
384
+ clone = clone_object(img)
385
+
386
+ print(clone.normalization)
387
+ print(type(clone.normalization))
388
+ print(clone.normalization == img.normalization)
389
+
390
+ print(clone.normalization['min_value']+1) # ça marche
391
+
392
+
393
+ sys.exit(0)
394
+
395
+ if True:
396
+ img = Image2D('/E/Sample_images/sample_images_FIJI/first-instar-brain.tif')
397
+ # img.dimensions = {'order': 'tdhw', 'values': [15, 35]}
398
+ # img.LUTs = [None,'GREEN']
399
+ img.projection = 'max'
400
+
401
+ print(img.projection)
402
+
403
+
404
+ print(img.to_dict()['projection'])
405
+ print(type(img.to_dict()['projection']))
406
+
407
+ clone = clone_object(img)
408
+
409
+ print(clone.projection)
410
+ print(clone.projection == img.projection)
411
+
412
+
413
+ sys.exit(0)
414
+
415
+ if True:
416
+ img = Image2D('/E/Sample_images/sample_images_FIJI/first-instar-brain.tif')
417
+ # img.dimensions = {'order': 'tdhw', 'values': [15, 35]}
418
+ # img.LUTs = [None,'GREEN']
419
+ img.channels = [True, False]
420
+
421
+ print(img.channels)
422
+
423
+
424
+ print(img.to_dict()['channels'])
425
+ print(type(img.to_dict()['channels']))
426
+
427
+ clone = clone_object(img)
428
+
429
+ print(clone.channels)
430
+ print(clone.channels == img.channels)
431
+
432
+
433
+ sys.exit(0)
434
+
435
+
436
+ if False:
437
+ img = Image2D('/E/Sample_images/sample_images_FIJI/confocal-series.tif')
438
+ # img.dimensions = {'order': 'tdhw', 'values': [15, 35]}
439
+ img.LUTs = [None,'GREEN']
440
+
441
+
442
+ print(img.LUTs)
443
+
444
+
445
+ print(img.to_dict()['LUTs'])
446
+ print(type(img.to_dict()['LUTs']))
447
+
448
+ clone = clone_object(img)
449
+
450
+ print(clone.LUTs)
451
+ print(clone.LUTs == img.LUTs)
452
+
453
+
454
+ sys.exit(0)
455
+
456
+
457
+ if True:
458
+
459
+ img = Image2D('/E/Sample_images/sample_images_denoise_manue/29-1_lif/ON 290119.lif - Series003.tif')
460
+ img.dimensions = {'order': 'tdhw', 'values': [15, 35]}
461
+
462
+
463
+
464
+ # print(img.to_dict()['dimensions'])
465
+ print(img.dimensions)
466
+
467
+
468
+ clone = clone_object(img)
469
+ print(clone.dimensions)
470
+
471
+ print(clone.dimensions == img.dimensions)
472
+ print(type(clone.dimensions), type(img.dimensions))
473
+
474
+ # very good -−> I need do some crazy stuff in qimage if not that
475
+
476
+
477
+
478
+
479
+
480
+
481
+ sys.exit(0)
482
+
483
+
484
+ if False:
485
+ script = """
486
+ t = np.arange(0.0, 2.0, 0.01)
487
+ s = 1 + np.sin(2 * np.pi * t)
488
+ fig, ax = plt.subplots()
489
+ print(type(fig))
490
+ ax.plot(t, s)
491
+ ax.set(xlabel='time (s)', ylabel='voltage (mV)', title=None)
492
+ ax.grid()
493
+ self.img = fig
494
+ """
495
+
496
+ # IF INDENT OF SCRIPT IS INCORRECT THE THETA IS SET PROPERLY OTHERWISE IT'S NOT
497
+ # matplotlib_figure = Image2D(fig)
498
+
499
+ matplotlib_figure = Image2D(custom_loading_script=script, theta=-45) # if theta is set from there then it is not ok # the theta from there does not reach to the end --> due to super override
500
+ # without rotation they are all ok --> so I need to do the translation of the rotation - the non rotated
501
+ # matplotlib_figure.set_rotation(-45)
502
+
503
+ print('qsdsqdqsdqsdqssqd', matplotlib_figure.theta) # this is reset but where # --> not set if from there
504
+ print(matplotlib_figure.to_dict()['theta']) # why is this 0 ???
505
+ print(clone_object(matplotlib_figure).to_dict()['theta']) # after cloning it is lost but why is that
506
+
507
+ sys.exit(0)
508
+
509
+
510
+ if False:
511
+ # very good --> I can also clone it --> see how I can add it to the stuff and then reload it
512
+
513
+ font = SerializableQFont()
514
+ font.setFamily('Arial')
515
+ font.setFamily('Comic Sans MS')
516
+ font.setPointSize(12)
517
+ font.setWeight(QFont.Normal)
518
+ font.setItalic(True)
519
+ font.background = 0xFF0000
520
+ font.foreground = 0x0000FF
521
+ font.placement = Position('top-right')
522
+
523
+ # Convert the SerializableQFont object to a dictionary
524
+ font_dict = font.to_dict()
525
+
526
+ xml_of_object =object_to_xml(font)
527
+ print(xml_of_object) # seems good
528
+
529
+ deser = deserialize_to_dict(xml_of_object) # this is also ok
530
+ print('deser',deser)
531
+
532
+ print(type(font).__name__)
533
+
534
+
535
+
536
+ clone = clone_object(font)
537
+
538
+ print(font_dict)
539
+ print(clone.to_dict())
540
+ print(clone.to_dict() == font_dict)
541
+
542
+
543
+
544
+ sys.exit(0)
545
+
546
+ if False:
547
+ txt = TAText2D('',placement=Position('center_h center_v'), range=[0,1])
548
+ print(object_to_xml(txt))
549
+ clone = clone_object(txt)
550
+ print(txt, clone) # -−> bingo this stuff is not clone properly if text is empty then it is deserialized as a list [] , also true for empty spaces but as soon as it is containing any non white space the n it gest cloned properly --> how can I fix that ???
551
+
552
+
553
+
554
+
555
+ sys.exit(0)
556
+
557
+
558
+
559
+ if False:
560
+
561
+ txt = TAText2D('this is a test',placement=Position('center_h center_v'), range=[0,1])
562
+
563
+ print(txt.range)
564
+
565
+ print('dabu',type(txt.to_dict()['range']))
566
+
567
+
568
+ print(object_to_xml(txt))
569
+
570
+ clone = clone_object(txt)
571
+
572
+ print(clone.range, type(clone.range)) # there is an error
573
+
574
+
575
+ print(clone.to_dict() == txt.to_dict()) # they are not the same but why --> is it because of placement ???
576
+
577
+ sys.exit(0)
578
+
579
+
580
+
581
+
582
+
583
+ if False:
584
+ xml_with_custom_script = """
585
+ <root>
586
+ <custom_loading_script>&quot;&quot;
587
+ import pandas as pd
588
+ import matplotlib.pyplot as plt
589
+ import numpy as np
590
+
591
+ # Read data using pandas
592
+ file_path = '/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_SF/sample_test_ScientFig/sample_data.txt'
593
+ data = pd.read_csv(file_path, sep=' ')
594
+
595
+ # Replace comma with dot in 'Percentages' and 'Errors' columns
596
+ data['Percentages'] = data['Percentages'].str.replace(',', '.').astype(float)
597
+ data['Errors'] = data['Errors'].str.replace(',', '.').astype(float)
598
+
599
+ # Plotting
600
+ fig, ax = plt.subplots()
601
+
602
+ for genotype, group in data.groupby('Genotype'):
603
+ ax.errorbar(group['Polygon Class'], group['Percentages'], yerr=group['Errors'], label=genotype, marker='o')
604
+
605
+ ax.set_xlabel('Polygon Class')
606
+ ax.set_ylabel('Percentages')
607
+ ax.set_title('Polygon Class vs Percentages')
608
+ ax.legend()
609
+ plt.grid(True)
610
+
611
+ self.img=fig
612
+ &quot;&quot;</custom_loading_script>
613
+ </root>
614
+ """
615
+
616
+ xml_without_custom_script_1 = """
617
+ <root>
618
+ <custom_loading_script>None</custom_loading_script>
619
+ </root>
620
+ """
621
+
622
+ xml_without_custom_script_2 = """
623
+ <root>
624
+ <custom_loading_script/>
625
+ <custom_loading_script>None</custom_loading_script>
626
+ <custom_loading_script>None</custom_loading_script>
627
+ <custom_loading_script>None</custom_loading_script>
628
+ </root>
629
+ """
630
+
631
+ print(has_custom_script(xml_with_custom_script)) # Output: True
632
+ print(has_custom_script(xml_without_custom_script_1)) # Output: False
633
+ print(has_custom_script(xml_without_custom_script_2)) # Output: False
634
+
635
+ print(has_custom_script(read_string_from_file('/tmp/tmpppa9xdax/state_0.xml')))
636
+ print(has_custom_script(read_string_from_file('/tmp/tmpppa9xdax/state_1.xml')))
637
+ print(has_custom_script(read_string_from_file('/home/aigouy/Bureau/test.pyf')))
638
+ print(has_custom_script(read_string_from_file('/home/aigouy/Bureau/test_with_custom_script.pyf')))
639
+
640
+ img = Image2D(width=512, height=512)
641
+ img3 = Image2D(width=512, height=512)
642
+ print(has_custom_script(object_to_xml(img)))
643
+
644
+ img2 = Image2D(custom_loading_script='bqlsqjdqksdjlqskdlkqsj')
645
+ print(has_custom_script(object_to_xml(img2)))
646
+
647
+
648
+
649
+
650
+ grp = Group(img, img2)
651
+
652
+ # print(object_to_xml(grp))
653
+
654
+ print(has_custom_script(object_to_xml(grp))) # still does not work
655
+
656
+ grp = Group(img, img3, Group(img, img3))
657
+ print(has_custom_script(object_to_xml(grp))) # still does not work
658
+
659
+ grp = Group(img, img3, Group(img, Group(img2)))
660
+ print(has_custom_script(object_to_xml(grp))) # still does not work
661
+ sys.exit(0)
662
+
663
+
664
+ if True:
665
+ # img0 = Image2D(width=512, height=512, annotations=TAText2D('this is a test of your system', placement='center_h center_v'))
666
+ # img0 = Image2D(width=512, height=512,
667
+ # annotations=[TAText2D('second', placement='center_h center_v', text_orientation='-Y')],
668
+ # isText=True)
669
+
670
+ tmp2 = Image2D(width=512, height=512,
671
+ annotations=[TAText2D('second', placement='center_h center_v', text_orientation='-Y'), Rectangle2D(0,0,120,150), TAText2D('third', placement='center_h center_v', text_orientation='-Y')],
672
+ isText=True)
673
+ print(object_to_xml(tmp2))
674
+
675
+ copy = clone_object(tmp2)
676
+
677
+
678
+
679
+
680
+
681
+ print(type(copy.annotations), copy.annotations) # BUG HERE --> THE ORDER IS CHANGED -−> I NEED A PLAN B!!!
682
+ print(type(copy.img))
683
+ print(type(copy))
684
+ print(copy.isText)
685
+
686
+
687
+
688
+
689
+
690
+ sys.exit(0)
691
+
692
+
693
+ if True:
694
+ img0 = Image2D('/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_svg/test_asym_size.png')
695
+ img1 = Image2D('/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_svg/test.png')
696
+
697
+ img3 = Image2D('/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_svg/test.png')
698
+ img4 = Image2D('/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_svg/test.png')
699
+
700
+ grp = Group(img3, img4)
701
+
702
+ lst = [img0, img1, grp]
703
+
704
+ # try to serialize this stuff --> this can be seen as an image --> TODO
705
+ xml_string = object_to_xml(lst, is_list=True)
706
+
707
+ # print(xml_string)
708
+
709
+ properties = deserialize_to_dict(xml_string)
710
+ # print(properties)
711
+ clone = create_object(list.__name__, properties)
712
+
713
+ print(clone)
714
+
715
+ # now try to deserialize it
716
+
717
+ sys.exit(0)
718
+
719
+ if True:
720
+
721
+ if False:
722
+ rect = Rectangle2D(10, 16, 200, 512)
723
+ obj_type = Rectangle2D.__name__
724
+
725
+ if False:
726
+ rect = Ellipse2D(10, 16, 200, 512)
727
+ obj_type = Ellipse2D.__name__
728
+
729
+ if False:
730
+ rect = Circle2D(10, 16, 200)
731
+ obj_type = Circle2D.__name__
732
+
733
+ if False:
734
+ rect = Point2D(10, 16)
735
+ obj_type = Point2D.__name__
736
+
737
+ if False:
738
+ rect = Line2D(10, 16, 200, 512)
739
+ obj_type = Line2D.__name__
740
+
741
+ if False:
742
+ rect = Polygon2D(100, 100, 110, 100, 110, 120, 10, 120, 100, 100)
743
+ obj_type = Polygon2D.__name__
744
+
745
+ if False:
746
+ rect = PolyLine2D(100, 100, 110, 100, 110, 120, 10, 120, 100, 100)
747
+ obj_type = PolyLine2D.__name__
748
+
749
+ if False: # no clue why they are ot equal because they seem to be...
750
+ rect = Square2D(10, 16, 200)
751
+ obj_type = Square2D.__name__
752
+
753
+ if False:
754
+ rect = Freehand2D(100, 100, 110, 100, 110, 120, 10, 120, 100, 100)
755
+ obj_type = Freehand2D.__name__
756
+
757
+ if False:
758
+ rect = TAText2D(
759
+ 'this is a test of your system') # they are nbot equal because of the doc --> no big deal and expected
760
+ obj_type = TAText2D.__name__
761
+
762
+ if False:
763
+ rect = TAText2D('this is a test of your system',
764
+ placement='top-left') # they are nbot equal because of the doc --> no big deal and expected
765
+ obj_type = TAText2D.__name__
766
+
767
+ if False:
768
+ rect = ScaleBar(10, legend='10µm',
769
+ placement='top-left') # they are nbot equal because of the doc --> no big deal and expected
770
+ obj_type = ScaleBar.__name__
771
+
772
+ if False:
773
+ rect = Image2D('/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_svg/test.png')
774
+ obj_type = Image2D.__name__
775
+
776
+ test_text = '''
777
+ </head><body style=" font-family:'Comic Sans MS'; font-size:22pt; font-weight:400; font-style:normal;">
778
+ <p style="color:#00ff00;"><span style=" color:#ff0000;">toto</span><br />tu<span style=" vertical-align:super;">tu</span></p>
779
+ '''
780
+ test_text2 = '''
781
+ </head><body style=" font-family:'Comic Sans MS'; font-size:22pt; font-weight:400; font-style:normal;">
782
+ <p style="color:#00ff00;"><span style=" color:#0000ff;">tititi</span>
783
+ '''
784
+ test_text3 = '''
785
+ </head><body style=" font-family:'Comic Sans MS'; font-size:22pt; font-weight:400; font-style:normal;">
786
+ <p style="color:#00ff00;"><span style=" color:#00ffff;">tata</span>
787
+ '''
788
+
789
+ if False:
790
+ img0 = Image2D('/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_svg/test_asym_size.png')
791
+ img1 = Image2D('/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_svg/test.png')
792
+ rect = img1
793
+ obj_type = Image2D.__name__
794
+
795
+ if True:
796
+ if True:
797
+ img1.border_size = 3 # make sure it displays an edge
798
+ # img1.annotations = []
799
+ img1.annotations.append(img0) # add an inset
800
+
801
+ if True:
802
+ # img1.setLettering(TAText2D(text=test_text))
803
+ img1.annotations.append(TAText2D(text=test_text, placement='top-left'))
804
+ img1.annotations.append(TAText2D(text=test_text2, placement='top-left'))
805
+ img1.annotations.append(Line2D(0, 0, img1.width() / 2, img1.height() / 2, stroke=3, color=0xFF00FF))
806
+ img1.annotations.append(Rectangle2D(128, 128, 64, 128, stroke=3, color=0xFF00FF))
807
+ img1.annotations.append(Point2D(img1.width() / 2, img1.height() / 2, stroke=6, color=0xFF00FF))
808
+ img1.annotations.append(
809
+ Ellipse2D(img1.width() / 2 - img1.width() / 8, img1.height() / 2 - img1.height() / 12,
810
+ img1.width() / 4, img1.height() / 6, stroke=3, color=0xFF00FF))
811
+ img1.annotations.append(
812
+ Circle2D(img1.width() / 2 - img1.width() / 10, img1.height() / 2 - img1.height() / 10,
813
+ img1.width() / 5, stroke=3, color=0xFF00FF))
814
+ img1.annotations.append(
815
+ Polygon2D(100, 100, 110, 100, 110, 120, 10, 120, 100, 100, color=0x0000FF, fill_color=0x00FFFF,
816
+ stroke=2))
817
+ img1.annotations.append(PolyLine2D(10, 16, 20, 10, 20, 30, 40, 30, color=0xFF0000, stroke=2))
818
+ img1.annotations.append(PolyLine2D(10, 16, 20, 10, 20, 30, 40, 30, color=0xFF0000, stroke=2))
819
+ img1.annotations.append(Square2D(72.5, 151.5, 30, stroke=3))
820
+ # img1.annotations.append(Freehand2D(10, 10, 20, 10, 20, 30, 288, 30, color=0xFFFF00, stroke=3))
821
+ img1.annotations.append(
822
+ Freehand2D(75, 25, 116.50, 50, 116.50, 100, 75, 125, 33.50, 100, 33.50, 50, color=0xFFFF00,
823
+ stroke=3)) # a beautiful hexagon !!!
824
+ # try a floating text
825
+ img1.annotations.append(TAText2D(x=img1.width() / 2, y=img1.height() / 2,
826
+ text='<font color="#FFFF00">free floating text</font>'))
827
+ img1.annotations.append(ScaleBar(30, '<font color="#FF00FF">right µm</font>',
828
+ placement='top-right')) # here I specify the bar to be top right specifically
829
+
830
+ if False:
831
+ img0 = Image2D('/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_svg/test_asym_size.png')
832
+ img1 = Image2D('/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_svg/test.png')
833
+ img1.annotations.append(TAText2D(text=test_text, placement='top-left'))
834
+ img1.annotations.append(TAText2D(text=test_text2, placement='top-left'))
835
+ img1.annotations.append(Line2D(0, 0, img1.width() / 2, img1.height() / 2, stroke=3, color=0xFF00FF))
836
+ img1.annotations.append(Rectangle2D(128, 128, 64, 128, stroke=3, color=0xFF00FF))
837
+ rect = Group(img0, img1)
838
+ obj_type = Group.__name__
839
+
840
+ rect.translate(120, 160)
841
+ if isinstance(rect, Image2D):
842
+ print('init Image', rect.img.shape)
843
+
844
+ print('to_dict orig', rect.to_dict())
845
+
846
+ # if True:
847
+ # print(type(rect.to_dict()['coords_as_list']), rect.to_dict()['coords_as_list'], rect.to_dict()['coords_as_list'][0])
848
+ # all is ok --> error is somewhere else then
849
+
850
+ print('orig', rect)
851
+
852
+ print('orig rect', rect.getRect())
853
+
854
+ xml_string = object_to_xml(rect)
855
+
856
+ if False:
857
+ print('#' * 20)
858
+ print(xml_string)
859
+ print('#' * 20)
860
+
861
+ properties = deserialize_to_dict(xml_string)
862
+ if False:
863
+ print(properties)
864
+ print(len(properties['annotations'])) # only 12 --> that is not the pb
865
+ print(properties['annotations'])
866
+ for elm, value in properties['annotations'].items():
867
+ if elm == 'TAText2D':
868
+ print(elm, len(value), type(value), type(value[
869
+ 1])) # value is a list of dict --> bingo I wil manage soon # ok so there are 14 stored in there and that is what I missed --> try to fix it -> this is a list so that is why I failed
870
+ # print(value)
871
+ for txt in value: # why is first value None ???
872
+ print(txt)
873
+ print(value)
874
+ sys.exit(0)
875
+
876
+ clone = create_object(obj_type, properties)
877
+
878
+ if isinstance(clone, Image2D):
879
+ print('copy Image', clone.img)
880
+
881
+ print('clone', clone)
882
+
883
+ print('to_dict clone', clone.to_dict())
884
+ print('clone rect', clone.getRect())
885
+
886
+ print('equal', rect == clone)
887
+
888
+ print('types', type(rect), type(clone))
889
+
890
+ try:
891
+ print('initial', rect.x(), rect.y(), rect.width(), rect.height()) # all ok
892
+ print('clone', clone.x(), clone.y(), clone.width(), clone.height()) # all 0
893
+ except:
894
+ pass # no big deal if fails
895
+
896
+ success = False
897
+ try:
898
+ print('equal dict', rect.__dict__ == clone.__dict__)
899
+ success = rect.__dict__ == clone.__dict__
900
+ except:
901
+ print('skipping equal dict')
902
+
903
+ if not success:
904
+ for k1, v1 in rect.__dict__.items():
905
+ for k2, v2 in clone.__dict__.items():
906
+ if k1 == k2:
907
+ if k1 in ['doc', 'img']:
908
+ continue
909
+ try:
910
+ if v1 != v2:
911
+ if isinstance(v2, Position):
912
+ if str(v2) == str(v1):
913
+ continue
914
+ print('not same values for', k1, v1, 'vs', v2, type(v1), type(v2))
915
+ except:
916
+ print(v1, 'vs', v2)
917
+
918
+ xml_of_clone = object_to_xml(clone)
919
+ print('serialization equality', xml_string == xml_of_clone)
920
+
921
+ if False:
922
+ if xml_string != xml_of_clone:
923
+ print('#' * 30)
924
+ print(xml_of_clone)
925
+ print('#' * 30)
926
+
927
+ import difflib
928
+
929
+ # string1 = "This is the first string."
930
+ # string2 = "This is the second string."
931
+
932
+ diff = difflib.ndiff(xml_string.splitlines(), xml_of_clone.splitlines())
933
+
934
+ print('difference:')
935
+ print(" vs ".join(diff))
936
+ # for dif in diff:
937
+ # print(dif)
938
+ # print(diff)
939
+
940
+ if isinstance(rect, Image2D):
941
+ print('annitations nb', len(rect.annotations),
942
+ len(clone.annotations)) # 15 texts are missing --> the error is in deserialization because serilaization is ok
943
+
944
+ sys.exit(0)
945
+
946
+ if False: # old
947
+ # if this is a string --> make it save as '''value''' -−> unpack it --> maybe need an extra check for a count of the values or maybe use """ or maybe use something unique so that it does not compete with python such as two '' or two "" at beginning and at the end
948
+
949
+ img1 = Image2D('/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_svg/test.png')
950
+ img0 = Image2D('/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_svg/test_asym_size.png')
951
+ test_text = '''
952
+ </head><body style=" font-family:'Comic Sans MS'; font-size:22pt; font-weight:400; font-style:normal;">
953
+ <p style="color:#00ff00;"><span style=" color:#ff0000;">toto</span><br />tu<span style=" vertical-align:super;">tu</span></p>
954
+ '''
955
+ test_text2 = '''
956
+ </head><body style=" font-family:'Comic Sans MS'; font-size:22pt; font-weight:400; font-style:normal;">
957
+ <p style="color:#00ff00;"><span style=" color:#0000ff;">tititi</span>
958
+ '''
959
+ test_text3 = '''
960
+ </head><body style=" font-family:'Comic Sans MS'; font-size:22pt; font-weight:400; font-style:normal;">
961
+ <p style="color:#00ff00;"><span style=" color:#00ffff;">tata</span>
962
+ '''
963
+
964
+ if True:
965
+ if True:
966
+ img1.border_size = 3 # make sure it displays an edge
967
+ # img1.annotations = []
968
+ img1.annotations.append(img0) # add an inset
969
+
970
+ if True:
971
+ # img1.setLettering(TAText2D(text=test_text))
972
+ img1.annotations.append(TAText2D(text=test_text, placement='top-left'))
973
+ img1.annotations.append(TAText2D(text=test_text2, placement='top-left'))
974
+ img1.annotations.append(TAText2D(text=test_text3, placement='top-left'))
975
+
976
+ img1.annotations.append(TAText2D(text=test_text, placement='bottom-right'))
977
+ img1.annotations.append(TAText2D(text=test_text2, placement='bottom-right'))
978
+ img1.annotations.append(TAText2D(text=test_text3, placement='bottom-right'))
979
+
980
+ img1.annotations.append(TAText2D(text=test_text, placement='bottom-left'))
981
+ img1.annotations.append(TAText2D(text=test_text2, placement='bottom-left'))
982
+
983
+ img1.annotations.append(TAText2D(text=test_text, placement='top-right'))
984
+ img1.annotations.append(TAText2D(text=test_text2, placement='top-right'))
985
+
986
+ img1.annotations.append(TAText2D(text=test_text, placement='center_h-center_v'))
987
+ img1.annotations.append(TAText2D(text=test_text2, placement='center_h-center_v'))
988
+
989
+ # print('TADAM',img1.width()/2., img1.height()/2.)
990
+ img1.annotations.append(Line2D(0, 0, img1.width() / 2, img1.height() / 2, stroke=3, color=0xFF00FF))
991
+ img1.annotations.append(Rectangle2D(128, 128, 64, 128, stroke=3, color=0xFF00FF))
992
+ img1.annotations.append(Point2D(img1.width() / 2, img1.height() / 2, stroke=6, color=0xFF00FF))
993
+ img1.annotations.append(
994
+ Ellipse2D(img1.width() / 2 - img1.width() / 8, img1.height() / 2 - img1.height() / 12,
995
+ img1.width() / 4, img1.height() / 6, stroke=3, color=0xFF00FF))
996
+ img1.annotations.append(
997
+ Circle2D(img1.width() / 2 - img1.width() / 10, img1.height() / 2 - img1.height() / 10,
998
+ img1.width() / 5, stroke=3, color=0xFF00FF))
999
+ img1.annotations.append(
1000
+ Polygon2D(100, 100, 110, 100, 110, 120, 10, 120, 100, 100, color=0x0000FF, fill_color=0x00FFFF,
1001
+ stroke=2))
1002
+ img1.annotations.append(PolyLine2D(10, 16, 20, 10, 20, 30, 40, 30, color=0xFF0000, stroke=2))
1003
+ img1.annotations.append(PolyLine2D(10, 16, 20, 10, 20, 30, 40, 30, color=0xFF0000, stroke=2))
1004
+ img1.annotations.append(Square2D(72.5, 151.5, 30, stroke=3))
1005
+ # img1.annotations.append(Freehand2D(10, 10, 20, 10, 20, 30, 288, 30, color=0xFFFF00, stroke=3))
1006
+ img1.annotations.append(
1007
+ Freehand2D(75, 25, 116.50, 50, 116.50, 100, 75, 125, 33.50, 100, 33.50, 50, color=0xFFFF00,
1008
+ stroke=3)) # a beautiful hexagon !!!
1009
+
1010
+ # try a floating text
1011
+ img1.annotations.append(TAText2D(text='<font color="#FF0000">top left by coords</font>'))
1012
+ img1.annotations.append(TAText2D(x=img1.width() / 2, y=img1.height() / 2,
1013
+ text='<font color="#FFFF00">free floating text</font>'))
1014
+ img1.annotations.append(
1015
+ ScaleBar(30, '<font color="#FF00FF">10µm</font>')) # default scale bar placement is bottom right
1016
+ img1.annotations.append(ScaleBar(30, '<font color="#FF00FF">right µm</font>',
1017
+ placement='top-right')) # here I specify the bar to be top right specifically
1018
+ # very good now try
1019
+
1020
+ img1.scale = 0.5
1021
+
1022
+ # print(img1.width())
1023
+ # print(img1.height())
1024
+
1025
+ # print(same_img.__dict__)
1026
+ xml_string = object_to_xml(img1)
1027
+
1028
+ print(xml_string)
1029
+ print('#' * 40)
1030
+
1031
+ # xml_string = '''<?xml version="1.0" ?>
1032
+ # <Rectangle2D>
1033
+ # <color>""16776960""</color>
1034
+ # <fill_color>None</fill_color>
1035
+ # <stroke>0.65</stroke>
1036
+ # <opacity>1.0</opacity>
1037
+ # <isSet>False</isSet>
1038
+ # <scale>1</scale>
1039
+ # <line_style>None</line_style>
1040
+ # <theta>0</theta>
1041
+ # <incompressible_width>0</incompressible_width>
1042
+ # <incompressible_height>0</incompressible_height>
1043
+ # <immutable>False</immutable>
1044
+ # <__init_called__>True</__init_called__>
1045
+ # </Rectangle2D>'''
1046
+
1047
+ # test ='16776960'
1048
+
1049
+ # print(test.isdigit())
1050
+ # print(int(test)+1)
1051
+
1052
+ properties = deserialize_to_dict(xml_string)
1053
+ if 'filename' in properties:
1054
+ properties['args'] = properties['filename']
1055
+ print('#' * 2000)
1056
+ print(properties)
1057
+ print('#-' * 2000)
1058
+
1059
+ # rect = xml_to_object(xml_string)
1060
+ # print(rect.__dict__)
1061
+
1062
+ # print(rect.__dict__ == same_img.__dict__)
1063
+
1064
+ # plt.imshow(rect.img)
1065
+ # plt.show()
1066
+
1067
+ rect = Image2D(**properties)
1068
+ print('testing keys', rect.__dict__.keys() == img1.__dict__.keys())
1069
+
1070
+ # removing the image is required for that
1071
+ # rect.__dict__['img']=None
1072
+ # same_img.__dict__['img']=None
1073
+
1074
+ try:
1075
+ print(rect.__dict__ == img1.__dict__)
1076
+ except:
1077
+ # Check all pairwise comparisons between the dictionaries
1078
+ for k1, v1 in rect.__dict__.items():
1079
+ for k2, v2 in img1.__dict__.items():
1080
+ if k1 == k2:
1081
+ try:
1082
+ if v1 != v2 or abs(v1 - v2) > 1e-9:
1083
+ if isinstance(v2, Position):
1084
+ if str(v2) == str(v1):
1085
+ continue
1086
+
1087
+ print('not same values for', k1, v1, 'vs', v2, type(v1), type(v2))
1088
+ if k1 == 'annotations':
1089
+ # print(type(v1))
1090
+ # k1 = eval(v1)
1091
+ # print(type(k1))
1092
+ if v1:
1093
+ for key, val in v1.items():
1094
+ print(key, '-->', val)
1095
+ try:
1096
+ print(create_object(key, val))
1097
+ except:
1098
+ traceback.print_exc()
1099
+ # bingo -−> can be easy TODO too -−> do deserialize that too!!
1100
+ # else:
1101
+
1102
+ except:
1103
+ if not np.array_equal(v1, v2):
1104
+ print('images', k1, 'not the same')
1105
+ # if not np.array_equal(v1, v2):
1106
+ # print(f"Error: The '{k1}' arrays are not equal.")
1107
+ # print(f"Array 1: {v1}")
1108
+ # print(f"Array 2: {v2}")
1109
+ # print()
1110
+ # pass
1111
+ # else:
1112
+ # print(f"Error: The dictionaries have different keys: '{k1}' and '{k2}'.")
1113
+
1114
+ '''
1115
+ there is a minor bug due to:
1116
+
1117
+ 'placement':<pyfigures.gui.Position.Position object at 0x7fded71d1480>
1118
+ <placement>
1119
+ <positions>{'top': True, 'bottom': False, 'left': False, 'right': True, 'center_h': False, 'center_v': False}</positions>
1120
+ </placement>
1121
+
1122
+ # see how I can fix that
1123
+ '''
1124
+
1125
+ print(rect, img1) # -> that rougly seems to work
1126
+ # --> see how to handle the things that need to be duplicated
1127
+
1128
+ if False:
1129
+ test2 = Rectangle2D(
1130
+ QRectF(10, 0, 100, 256)) # the serialization is great but now I need to see how to reload the shit
1131
+
1132
+ print(test2)
1133
+
1134
+ if True:
1135
+ xml_string = object_to_xml(test2)
1136
+
1137
+ rect = deserialize_rectangle2d(xml_string)
1138
+ print(rect.__dict__)
1139
+
1140
+ print(rect)
1141
+
1142
+ print(
1143
+ rect == test2) # very good --> that works and that is cool --> these are really two objects but they are interchangeable
1144
+ print(test2.__dict__)
1145
+
1146
+ print(test2.__dict__ == rect.__dict__)
1147
+
1148
+ # print
1149
+
1150
+ #
1151
+ #
1152
+ # if __name__ == '__main__':
1153
+ # from batoolset.settings.global_settings import set_UI # set the UI to qtpy
1154
+ #
1155
+ # set_UI()
1156
+ # from batoolset.draw.shapes.image2d import Rectangle2D
1157
+ # from qtpy.QtCore import QRect, Qt, QRectF
1158
+ #
1159
+ # test2 = Rectangle2D(QRectF(10, 0, 100, 256)) # the serialization is great but now I need to see how to reload the shit
1160
+ # xml_version =object_to_xml(test2)
1161
+ # print(xml_version)
1162
+ #
1163
+ # print('Deserialization')
1164
+ #
1165
+ # # print(xml_to_object(xml_version))
1166
+ #
1167
+ #
1168
+ # if False:
1169
+ # from batoolset.draw.shapes.image2d import Image2D
1170
+ #
1171
+ #
1172
+ # same_img = Image2D('/E/Sample_images/EZF_SF_scientifig_EZFig/sample_images_svg/test.png')
1173
+ # same_img.scale = 0.5
1174
+ #
1175
+ # print(same_img.width())
1176
+ # print(same_img.height())
1177
+ #
1178
+ #
1179
+ # # when it loops into position it should just get the position as a string
1180
+ #
1181
+ #
1182
+ # # see also how to handle the embedded images -> shall I store them separately or not
1183
+ # # can I use magic unique names to avoid repetitions ???
1184
+ #
1185
+ #
1186
+ #
1187
+ # print(object_to_xml(same_img))
1188
+ #
1189
+ #
1190
+ # # try to reload it maybe
1191
+
1192
+