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.
- batoolset/GUI/__init__.py +0 -0
- batoolset/GUI/list_gui.py +513 -0
- batoolset/GUI/multi_image_display.py +989 -0
- batoolset/GUI/open.py +325 -0
- batoolset/GUI/overlay_hints.py +45 -0
- batoolset/GUI/paint2.py +1345 -0
- batoolset/GUI/scrollablepaint.py +1152 -0
- batoolset/IJ_ROIs/__init__.py +0 -0
- batoolset/IJ_ROIs/tools.py +40 -0
- batoolset/PATH/__init__.py +0 -0
- batoolset/PATH/tools.py +79 -0
- batoolset/SQLite_tools/__init__.py +0 -0
- batoolset/SQLite_tools/tools.py +840 -0
- batoolset/__init__.py +0 -0
- batoolset/binary/__init__.py +0 -0
- batoolset/binary/tools.py +123 -0
- batoolset/binarytools/__init__.py +0 -0
- batoolset/binarytools/cell_center_detector.py +290 -0
- batoolset/clipboard_tools/__init__.py +0 -0
- batoolset/clipboard_tools/tools.py +7 -0
- batoolset/colors/__init__.py +0 -0
- batoolset/colors/colorgen.py +193 -0
- batoolset/colors/tools.py +22 -0
- batoolset/command_line/__init__.py +0 -0
- batoolset/command_line/tools.py +18 -0
- batoolset/dialogs/__init__.py +0 -0
- batoolset/dialogs/opensave.py +228 -0
- batoolset/dicts/__init__.py +0 -0
- batoolset/dicts/tools.py +299 -0
- batoolset/dims/__init__.py +0 -0
- batoolset/dims/tools.py +83 -0
- batoolset/draw/__init__.py +0 -0
- batoolset/draw/shapes/Position.py +183 -0
- batoolset/draw/shapes/__init__.py +0 -0
- batoolset/draw/shapes/automated_alignment_drawing_refactored.py +346 -0
- batoolset/draw/shapes/circle2d.py +99 -0
- batoolset/draw/shapes/compute_optimal_size_all_merged.py +317 -0
- batoolset/draw/shapes/ellipse2d.py +336 -0
- batoolset/draw/shapes/freehand2d.py +235 -0
- batoolset/draw/shapes/group.py +1830 -0
- batoolset/draw/shapes/image2d.py +2469 -0
- batoolset/draw/shapes/line2d.py +575 -0
- batoolset/draw/shapes/point2d.py +257 -0
- batoolset/draw/shapes/polygon2d.py +357 -0
- batoolset/draw/shapes/polyline2d.py +235 -0
- batoolset/draw/shapes/rect2d.py +388 -0
- batoolset/draw/shapes/rectangle2d.py +601 -0
- batoolset/draw/shapes/scalebar.py +304 -0
- batoolset/draw/shapes/serializablefont.py +126 -0
- batoolset/draw/shapes/serializableguiparams.py +10 -0
- batoolset/draw/shapes/square2d.py +103 -0
- batoolset/draw/shapes/textorientation.py +45 -0
- batoolset/draw/shapes/tools.py +467 -0
- batoolset/draw/shapes/transform2D.py +350 -0
- batoolset/draw/shapes/txt2d.py +550 -0
- batoolset/draw/widgets/__init__.py +0 -0
- batoolset/draw/widgets/col.py +343 -0
- batoolset/draw/widgets/image_group.py +248 -0
- batoolset/draw/widgets/image_organizer.py +96 -0
- batoolset/draw/widgets/paint.py +184 -0
- batoolset/draw/widgets/vectorial.py +257 -0
- batoolset/figure/__init__.py +0 -0
- batoolset/figure/alignment.py +814 -0
- batoolset/figure/column.py +1117 -0
- batoolset/figure/fig_tools.py +285 -0
- batoolset/figure/minimal_debugger_scale_etc.py +139 -0
- batoolset/figure/panel.py +697 -0
- batoolset/figure/row.py +852 -0
- batoolset/figure/user_selection.py +287 -0
- batoolset/files/__init__.py +0 -0
- batoolset/files/tools.py +1321 -0
- batoolset/images/__init__.py +0 -0
- batoolset/images/tools.py +81 -0
- batoolset/img.py +5216 -0
- batoolset/linux/__init__.py +0 -0
- batoolset/linux/tools.py +72 -0
- batoolset/lists/__init__.py +0 -0
- batoolset/lists/tools.py +436 -0
- batoolset/luts/__init__.py +0 -0
- batoolset/luts/lut_minimal_test.py +1207 -0
- batoolset/matplolib/__init__.py +0 -0
- batoolset/matplolib/tools.py +44 -0
- batoolset/np_tools/__init__.py +0 -0
- batoolset/np_tools/tools.py +252 -0
- batoolset/np_tools/trash.py +15 -0
- batoolset/pandas_tools/__init__.py +0 -0
- batoolset/pandas_tools/tools.py +880 -0
- batoolset/partials/__init__.py +0 -0
- batoolset/partials/tools.py +83 -0
- batoolset/plot_tools/__init__.py +0 -0
- batoolset/plot_tools/tools.py +70 -0
- batoolset/pyqt/__init__.py +0 -0
- batoolset/pyqt/tools.py +691 -0
- batoolset/re_tools/__init__.py +0 -0
- batoolset/re_tools/tools.py +35 -0
- batoolset/serialization/__init__.py +0 -0
- batoolset/serialization/tools.py +1192 -0
- batoolset/sets/__init__.py +0 -0
- batoolset/sets/tools.py +109 -0
- batoolset/settings/__init__.py +0 -0
- batoolset/settings/global_settings.py +134 -0
- batoolset/strings/__init__.py +0 -0
- batoolset/strings/tools.py +225 -0
- batoolset/ta/__init__.py +0 -0
- batoolset/ta/database/__init__.py +0 -0
- batoolset/ta/database/advanced_sql_plotter.py +1170 -0
- batoolset/ta/database/my_qt_table.py +79 -0
- batoolset/ta/database/preview_and_edit_sqlite_db.py +405 -0
- batoolset/ta/database/sql.py +2141 -0
- batoolset/ta/database/sql_column_name_dialog.py +122 -0
- batoolset/ta/measurements/TAmeasures.py +2226 -0
- batoolset/ta/measurements/__init__.py +0 -0
- batoolset/ta/measurements/measurements3D/__init__.py +0 -0
- batoolset/ta/measurements/measurements3D/get_point_on_surface_if_centroid_is_bad.py +175 -0
- batoolset/ta/measurements/measurements3D/height_map_to_projection.py +82 -0
- batoolset/ta/measurements/measurements3D/measures3D.py +208 -0
- batoolset/ta/measurements/measurements3D/triangulate.py +331 -0
- batoolset/ta/measurements/nematic.py +562 -0
- batoolset/ta/measurements/nematic_measurements.py +107 -0
- batoolset/ta/segmentation/__init__.py +0 -0
- batoolset/ta/segmentation/neo_wshed.py +314 -0
- batoolset/ta/selections/__init__.py +0 -0
- batoolset/ta/selections/selection.py +329 -0
- batoolset/ta/tracking/__init__.py +0 -0
- batoolset/ta/tracking/last_tracking_based_on_matching_or_on_translation_from_mermaid_warp.py +653 -0
- batoolset/ta/tracking/local_to_track_correspondance.py +138 -0
- batoolset/ta/tracking/rapid_detection_of_vertices.py +517 -0
- batoolset/ta/tracking/registration.py +108 -0
- batoolset/ta/tracking/swap_detector_and_fixer.py +296 -0
- batoolset/ta/tracking/track_correction.py +238 -0
- batoolset/ta/tracking/tracking_error_detector_and_fixer.py +3099 -0
- batoolset/ta/tracking/tracking_yet_another_approach_pyramidal_registration_n_neo_swapping_correction.py +725 -0
- batoolset/ta/utils/TA_tools.py +43 -0
- batoolset/ta/utils/__init__.py +0 -0
- batoolset/ta/utils/rps_tools.py +1783 -0
- batoolset/tests/__init__.py +0 -0
- batoolset/tests/rps_tools.py +51 -0
- batoolset/tests/tools.py +10 -0
- batoolset/tools/__init__.py +0 -0
- batoolset/tools/early_stopper_class.py +9 -0
- batoolset/tools/guided_data_recoverer.py +110 -0
- batoolset/tools/logger.py +100 -0
- batoolset/tools/mytimer.py +31 -0
- batoolset/tools/prompt_color.py +160 -0
- batoolset/tools/qthandler.py +118 -0
- batoolset/uitools/__init__.py +0 -0
- batoolset/uitools/blinker.py +56 -0
- batoolset/unsafe/__init__.py +0 -0
- batoolset/unsafe/tools.py +115 -0
- batoolset/utils/__init__.py +0 -0
- batoolset/utils/commontools.py +158 -0
- batoolset/utils/loadlist.py +728 -0
- batoolset/version.py +10 -0
- batoolset/xml/__init__.py +0 -0
- batoolset/xml/tools.py +65 -0
- batoolset/zip_tools/__init__.py +0 -0
- batoolset/zip_tools/tools.py +76 -0
- batoolset-0.1.0.dist-info/LICENSE +24 -0
- batoolset-0.1.0.dist-info/METADATA +45 -0
- batoolset-0.1.0.dist-info/RECORD +162 -0
- batoolset-0.1.0.dist-info/WHEEL +5 -0
- batoolset-0.1.0.dist-info/top_level.txt +1 -0
|
File without changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from ctypes import pointer
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from batoolset.ta.measurements.TAmeasures import distance_between_points
|
|
6
|
+
from batoolset.ta.utils.rps_tools import get_feret_from_points, extreme_points
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
if __name__ == '__main__':
|
|
12
|
+
|
|
13
|
+
test = np.asarray([1,10,10,1])
|
|
14
|
+
print('test where', np.where(test == test.max())) # see why with cdist I can't find the two ???
|
|
15
|
+
|
|
16
|
+
# Bug somehow (but not really because there are several solutions, the only thing is that the solution may not be optimal for bonds) --> it should have returned the other extreme
|
|
17
|
+
|
|
18
|
+
coords = ((612, 457), (612, 458), (612, 459), (612, 460), (612, 461), (612, 462), (612, 463), (612, 464), (613, 441), (613, 442), (613, 443), (613, 444), (613, 445), (613, 446), (613, 447), (613, 448), (613, 449), (613, 450), (613, 451), (613, 452), (613, 453), (613, 454), (613, 455), (613, 456), (614, 426), (614, 427), (614, 428), (614, 429), (614, 430), (614, 431), (614, 432), (614, 433), (614, 434), (614, 435), (614, 436), (614, 437), (614, 438), (614, 439), (614, 440), (615, 411), (615, 412), (615, 413), (615, 414), (615, 415), (615, 416), (615, 417), (615, 418), (615, 419), (615, 420), (615, 421), (615, 422), (615, 423), (615, 424), (615, 425), (616, 395), (616, 396), (616, 397), (616, 398), (616, 399), (616, 400), (616, 401), (616, 402), (616, 403), (616, 404), (616, 405), (616, 406), (616, 407), (616, 408), (616, 409), (616, 410), (617, 380), (617, 381), (617, 382), (617, 383), (617, 384), (617, 385), (617, 386), (617, 387), (617, 388), (617, 389), (617, 390), (617, 391), (617, 392), (617, 393), (617, 394), (617, 499), (617, 500), (617, 501), (617, 502), (617, 503), (617, 504), (617, 505), (617, 506), (617, 507), (617, 508), (617, 509), (617, 510), (617, 511), (617, 512), (617, 513), (617, 514), (617, 515), (617, 516), (618, 372), (618, 373), (618, 374), (618, 375), (618, 376), (618, 377), (618, 378), (618, 379), (618, 473), (618, 474), (618, 475), (618, 476), (618, 477), (618, 478), (618, 479), (618, 480), (618, 481), (618, 482), (618, 483), (618, 484), (618, 485), (618, 486), (618, 487), (618, 488), (618, 489), (618, 490), (618, 491), (618, 492), (618, 493), (618, 494), (618, 495), (618, 496), (618, 497), (618, 498), (618, 517), (618, 518), (618, 519), (618, 520), (618, 521), (618, 522), (618, 523), (618, 524), (618, 525), (618, 526), (619, 374), (619, 375), (619, 447), (619, 448), (619, 449), (619, 450), (619, 451), (619, 452), (619, 453), (619, 454), (619, 455), (619, 456), (619, 457), (619, 458), (619, 459), (619, 460), (619, 461), (619, 462), (619, 463), (619, 464), (619, 465), (619, 466), (619, 467), (619, 468), (619, 469), (619, 470), (619, 471), (619, 472), (619, 527), (619, 528), (619, 529), (619, 530), (619, 531), (619, 532), (619, 533), (619, 534), (619, 535), (619, 536), (620, 376), (620, 377), (620, 378), (620, 421), (620, 422), (620, 423), (620, 424), (620, 425), (620, 426), (620, 427), (620, 428), (620, 429), (620, 430), (620, 431), (620, 432), (620, 433), (620, 434), (620, 435), (620, 436), (620, 437), (620, 438), (620, 439), (620, 440), (620, 441), (620, 442), (620, 443), (620, 444), (620, 445), (620, 446), (620, 537), (620, 538), (620, 539), (620, 540), (620, 541), (620, 542), (620, 543), (620, 544), (620, 545), (620, 546), (621, 379), (621, 380), (621, 395), (621, 396), (621, 397), (621, 398), (621, 399), (621, 400), (621, 401), (621, 402), (621, 403), (621, 404), (621, 405), (621, 406), (621, 407), (621, 408), (621, 409), (621, 410), (621, 411), (621, 412), (621, 413), (621, 414), (621, 415), (621, 416), (621, 417), (621, 418), (621, 419), (621, 420), (621, 547), (621, 548), (621, 549), (621, 550), (621, 551), (621, 552), (621, 553), (621, 554), (621, 555), (621, 556), (622, 381), (622, 382), (622, 383), (622, 384), (622, 385), (622, 386), (622, 387), (622, 388), (622, 389), (622, 390), (622, 391), (622, 392), (622, 393), (622, 394), (622, 557), (622, 558), (622, 559), (622, 560), (622, 561), (622, 562), (622, 563), (622, 564), (622, 565), (622, 566), (623, 567), (623, 568), (623, 569), (623, 570), (623, 571), (623, 572), (623, 573), (623, 574), (623, 575), (623, 576), (624, 577), (624, 578), (624, 579), (624, 580), (624, 581), (624, 582), (624, 583), (624, 584), (624, 585), (624, 586), (625, 587), (625, 588), (625, 589), (625, 590), (625, 591), (625, 592), (625, 593), (625, 594), (625, 595), (625, 596), (626, 597), (626, 598), (626, 599), (626, 600), (626, 601), (626, 602), (626, 603), (626, 604), (626, 605), (626, 606), (627, 607), (627, 608), (627, 609), (627, 610), (627, 611), (627, 612), (627, 613), (627, 614), (627, 615), (627, 616), (628, 617), (628, 618), (628, 619), (628, 620), (628, 621), (628, 622), (629, 623), (629, 624), (629, 625), (630, 626), (630, 627), (630, 628), (631, 629), (631, 630), (631, 631), (632, 632), (632, 633), (632, 634), (633, 635), (633, 636), (633, 637), (634, 638), (634, 639), (634, 640), (635, 641), (635, 642), (635, 643), (636, 644), (636, 645), (636, 646), (637, 647), (637, 648), (637, 649), (638, 650), (638, 651), (638, 652), (639, 653), (639, 654), (639, 655), (640, 656), (640, 657), (640, 658), (641, 659), (641, 660), (641, 661), (642, 662), (642, 663), (643, 664), (643, 665), (643, 666), (644, 667), (644, 668), (644, 669), (645, 670), (645, 671), (645, 672), (645, 819), (645, 820), (645, 821), (645, 822), (645, 823), (645, 824), (645, 825), (645, 826), (645, 827), (645, 828), (645, 829), (645, 830), (645, 831), (645, 832), (645, 833), (645, 834), (645, 835), (645, 836), (645, 837), (645, 838), (645, 839), (645, 840), (645, 841), (645, 842), (645, 843), (645, 844), (645, 845), (645, 846), (645, 847), (645, 848), (645, 849), (645, 850), (645, 851), (645, 852), (645, 853), (645, 854), (645, 855), (645, 856), (645, 857), (645, 858), (645, 859), (645, 860), (645, 861), (645, 862), (645, 863), (645, 864), (645, 865), (645, 866), (645, 867), (645, 868), (645, 869), (645, 870), (645, 871), (645, 872), (645, 873), (645, 874), (645, 875), (645, 876), (645, 877), (645, 878), (645, 879), (645, 880), (645, 881), (646, 673), (646, 674), (646, 675), (646, 750), (646, 751), (646, 752), (646, 753), (646, 754), (646, 755), (646, 756), (646, 757), (646, 758), (646, 759), (646, 760), (646, 761), (646, 762), (646, 763), (646, 764), (646, 765), (646, 766), (646, 767), (646, 768), (646, 769), (646, 770), (646, 771), (646, 772), (646, 773), (646, 774), (646, 775), (646, 776), (646, 777), (646, 778), (646, 779), (646, 780), (646, 781), (646, 782), (646, 783), (646, 784), (646, 785), (646, 786), (646, 787), (646, 788), (646, 789), (646, 790), (646, 791), (646, 792), (646, 793), (646, 794), (646, 795), (646, 796), (646, 797), (646, 798), (646, 799), (646, 800), (646, 801), (646, 802), (646, 803), (646, 804), (646, 805), (646, 806), (646, 807), (646, 808), (646, 809), (646, 810), (646, 811), (646, 812), (646, 813), (646, 814), (646, 815), (646, 816), (646, 817), (646, 818), (647, 676), (647, 677), (647, 678), (647, 745), (647, 746), (647, 747), (647, 748), (647, 749), (648, 679), (648, 680), (648, 681), (648, 740), (648, 741), (648, 742), (648, 743), (648, 744), (649, 682), (649, 683), (649, 684), (649, 736), (649, 737), (649, 738), (649, 739), (650, 685), (650, 686), (650, 687), (650, 731), (650, 732), (650, 733), (650, 734), (650, 735), (651, 688), (651, 689), (651, 690), (651, 726), (651, 727), (651, 728), (651, 729), (651, 730), (652, 691), (652, 692), (652, 693), (652, 721), (652, 722), (652, 723), (652, 724), (652, 725), (653, 694), (653, 695), (653, 696), (653, 716), (653, 717), (653, 718), (653, 719), (653, 720), (654, 697), (654, 698), (654, 699), (654, 712), (654, 713), (654, 714), (654, 715), (655, 700), (655, 701), (655, 702), (655, 707), (655, 708), (655, 709), (655, 710), (655, 711), (656, 703), (656, 704), (656, 705), (656, 706))
|
|
19
|
+
point1, point2= get_feret_from_points(coords) # -->((618, 372), (645, 881)) but this is incorrect !!!!
|
|
20
|
+
print(point1, point2)
|
|
21
|
+
found_dist = distance_between_points(point1, point2)
|
|
22
|
+
print(distance_between_points(point1, point2))
|
|
23
|
+
print(distance_between_points((618,372), (645,881))) #these are the real feret points --> in fact the distance is 100% equal but the second solution would have been better --> how can I do that
|
|
24
|
+
# indeed the pb is that the distance is equal --> so if there are many equal distances I shall maybe take the extreme most points
|
|
25
|
+
coords = extreme_points(np.asarray(coords), return_array=True )
|
|
26
|
+
print(coords)
|
|
27
|
+
# below does not work --> I just want the other pair --> take it and check if pixels exist and if one is more extreme --> take it
|
|
28
|
+
for coord1 in coords:
|
|
29
|
+
for coord2 in coords:
|
|
30
|
+
if coord1 == coord2:
|
|
31
|
+
continue
|
|
32
|
+
if distance_between_points(coord1, coord2) >= found_dist:
|
|
33
|
+
# if tuple(coord1) != tuple(point1):
|
|
34
|
+
print('as_good or better', coord1, coord2)
|
|
35
|
+
# si un des deux points differe -> le prendre
|
|
36
|
+
print((tuple(coord1)!=tuple(point1) or tuple(coord1)!=tuple(point2)) , ((tuple(coord2)!=tuple(point1) or tuple(coord2)!=tuple(point2))))
|
|
37
|
+
print(tuple(coord1)!=tuple(point1) , tuple(coord1)!=tuple(point2) , tuple(coord2)!=tuple(point1) , tuple(coord2)!=tuple(point2))
|
|
38
|
+
if (tuple(coord1)!=tuple(point1) or tuple(coord1)!=tuple(point2)):
|
|
39
|
+
if tuple(coord2) == tuple(point1) or tuple(coord2) == tuple(point2):
|
|
40
|
+
print('other possibility',coord1, coord2)
|
|
41
|
+
if (tuple(coord2)!=tuple(point1) or tuple(coord2)!=tuple(point2)):
|
|
42
|
+
if tuple(coord1)==tuple(point1) or tuple(coord1)==tuple(point2):
|
|
43
|
+
print('other possibility',coord1, coord2)
|
|
44
|
+
|
|
45
|
+
# TODO I should return the other pair
|
|
46
|
+
|
|
47
|
+
# or ((tuple(coord2)!=tuple(point1) and tuple(coord2)!=tuple(point2)))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
batoolset/tests/tools.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
|
|
2
|
+
def are_ratios_almost_equal(val1, val2, epsilon=0.0001):
|
|
3
|
+
# checks if two values are almost equal (due to rounding errors for example)
|
|
4
|
+
# epsilon is the tolerance
|
|
5
|
+
return abs(val1 - val2) < epsilon
|
|
6
|
+
|
|
7
|
+
if __name__ == '__main__':
|
|
8
|
+
print(are_ratios_almost_equal(1.6666666666666666,1.6666666666666667)) # True
|
|
9
|
+
print(are_ratios_almost_equal(1.6667,1.6666)) # True
|
|
10
|
+
print(are_ratios_almost_equal(1.667,1.666)) # False
|
|
File without changes
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import random
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
from batoolset.img import apply_2D_gradient, create_random_intensity_graded_perturbation, Img
|
|
4
|
+
|
|
5
|
+
def GuidedDataRecoverer(input_data, indices_to_recover, auto_unpack_if_single=True):
|
|
6
|
+
"""
|
|
7
|
+
Recovers specific elements from input_data based on indices_to_recover.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
input_data (list or tuple): The input data.
|
|
11
|
+
indices_to_recover (int or list): The indices to recover.
|
|
12
|
+
auto_unpack_if_single (bool, optional): Whether to automatically unpack the result if only one element is recovered.
|
|
13
|
+
Defaults to True.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
Recovered data based on the provided indices.
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
>>> input_data = ['crap', 'important', 'crap2']
|
|
20
|
+
>>> GuidedDataRecoverer(input_data, 1)
|
|
21
|
+
'important'
|
|
22
|
+
|
|
23
|
+
>>> GuidedDataRecoverer(input_data, -2)
|
|
24
|
+
'important'
|
|
25
|
+
|
|
26
|
+
>>> GuidedDataRecoverer(input_data, -2, auto_unpack_if_single=False)
|
|
27
|
+
['important']
|
|
28
|
+
|
|
29
|
+
>>> GuidedDataRecoverer(input_data, [0, 1])
|
|
30
|
+
['crap', 'important']
|
|
31
|
+
"""
|
|
32
|
+
if input_data is None:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
assert isinstance(input_data, (list, tuple)), "input_data should be a list or a tuple"
|
|
36
|
+
|
|
37
|
+
# create a list/tuple with all the values
|
|
38
|
+
if isinstance(indices_to_recover, int):
|
|
39
|
+
indices_to_recover = [indices_to_recover]
|
|
40
|
+
|
|
41
|
+
for val in indices_to_recover:
|
|
42
|
+
assert isinstance(val, int), 'indices must be integers'
|
|
43
|
+
|
|
44
|
+
data_to_be_recovered = [input_data[idx] for idx in indices_to_recover]
|
|
45
|
+
|
|
46
|
+
if auto_unpack_if_single and len(indices_to_recover) == 1:
|
|
47
|
+
return data_to_be_recovered[0]
|
|
48
|
+
else:
|
|
49
|
+
return data_to_be_recovered
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def graded_intensity_modification(orig, parameters, is_mask):
|
|
53
|
+
"""
|
|
54
|
+
Applies graded intensity modification to an image.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
orig (ndarray): The input image.
|
|
58
|
+
parameters: Additional parameters (not used in the function).
|
|
59
|
+
is_mask (bool): Indicates whether the input is a mask.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
The modified image.
|
|
63
|
+
|
|
64
|
+
# Examples:
|
|
65
|
+
# >>> orig = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012.png')[...,1]
|
|
66
|
+
# >>> out = graded_intensity_modification(orig, None, False)
|
|
67
|
+
# >>> plt.imshow(out)
|
|
68
|
+
# >>> plt.show()
|
|
69
|
+
"""
|
|
70
|
+
out = orig
|
|
71
|
+
if not is_mask:
|
|
72
|
+
# Apply 2D gradient and create random intensity graded perturbation
|
|
73
|
+
out = apply_2D_gradient(orig, create_random_intensity_graded_perturbation(orig, off_centered=True))
|
|
74
|
+
return [], out
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if __name__ == '__main__':
|
|
78
|
+
# this is a test
|
|
79
|
+
|
|
80
|
+
input_data = ['crap', 'important', 'crap2']
|
|
81
|
+
assert GuidedDataRecoverer(input_data, 1) == 'important'
|
|
82
|
+
assert GuidedDataRecoverer(input_data, -2) == 'important'
|
|
83
|
+
assert GuidedDataRecoverer(input_data, -2, auto_unpack_if_single=False) == ['important']
|
|
84
|
+
assert GuidedDataRecoverer(input_data, [0, 1]) == ['crap', 'important']
|
|
85
|
+
|
|
86
|
+
# try pipes to get the stuff done
|
|
87
|
+
# so easy with random to apply the same the only difficulty is that the nb of random calls should be the same --> inportant to keep in mind when doing this
|
|
88
|
+
|
|
89
|
+
from datetime import datetime
|
|
90
|
+
seed = datetime.now()
|
|
91
|
+
random.seed(seed)
|
|
92
|
+
|
|
93
|
+
orig = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012.png')[...,1]
|
|
94
|
+
out = GuidedDataRecoverer(graded_intensity_modification(orig, None,False),-1)
|
|
95
|
+
plt.imshow(out)
|
|
96
|
+
plt.show()
|
|
97
|
+
|
|
98
|
+
random.seed(seed)
|
|
99
|
+
random.randint(0,12)# any extra random call messes it up but that makes sense
|
|
100
|
+
|
|
101
|
+
# whatever happens the nb of random calls should be the same --> could add a fake option that calls random the exact same nb of times --> TODO
|
|
102
|
+
# if I have that parameters become useless --> ok most likely
|
|
103
|
+
|
|
104
|
+
orig = Img('/E/Sample_images/sample_images_PA/mini/focused_Series012.png')[..., 1]
|
|
105
|
+
out = GuidedDataRecoverer(graded_intensity_modification(orig, None, False), -1)
|
|
106
|
+
plt.imshow(out)
|
|
107
|
+
plt.show()
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
class TA_logger(object):
|
|
4
|
+
"""
|
|
5
|
+
A logger class for TA (Tracking and Analysis) module.
|
|
6
|
+
|
|
7
|
+
Attributes:
|
|
8
|
+
default_format (str): Default log format.
|
|
9
|
+
master_logger_name (str): Master logger name.
|
|
10
|
+
DEBUG (int): Debug logging level.
|
|
11
|
+
INFO (int): Info logging level.
|
|
12
|
+
WARNING (int): Warning logging level.
|
|
13
|
+
ERROR (int): Error logging level.
|
|
14
|
+
CRITICAL (int): Critical logging level.
|
|
15
|
+
DEFAULT (int): Default logging level.
|
|
16
|
+
|
|
17
|
+
Examples:
|
|
18
|
+
>>> logger = TA_logger()
|
|
19
|
+
>>> logger.debug("test")
|
|
20
|
+
>>> logger.info("test")
|
|
21
|
+
>>> logger.warning("test")
|
|
22
|
+
>>> logger.error("test")
|
|
23
|
+
>>> logger.critical("test")
|
|
24
|
+
>>> formatter = logging.Formatter(TA_logger.default_format)
|
|
25
|
+
>>> handler = logging.StreamHandler()
|
|
26
|
+
>>> handler.setFormatter(formatter)
|
|
27
|
+
>>> TA_logger.setHandler(handler)
|
|
28
|
+
>>> logger.debug("test")
|
|
29
|
+
>>> logger.info("test")
|
|
30
|
+
>>> logger.warning("test")
|
|
31
|
+
>>> logger.error("test")
|
|
32
|
+
>>> logger.critical("test")
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
default_format = '%(levelname)s - %(asctime)s - %(filename)s - %(funcName)s - line %(lineno)d - %(message)s\n'
|
|
36
|
+
master_logger_name = 'master'
|
|
37
|
+
DEBUG = logging.DEBUG
|
|
38
|
+
INFO = logging.INFO
|
|
39
|
+
WARNING = logging.WARNING
|
|
40
|
+
ERROR = logging.ERROR
|
|
41
|
+
CRITICAL = logging.CRITICAL
|
|
42
|
+
DEFAULT = INFO
|
|
43
|
+
|
|
44
|
+
loggers = {}
|
|
45
|
+
|
|
46
|
+
def __new__(cls, name=master_logger_name, logging_level=DEFAULT, format=default_format, handler=None):
|
|
47
|
+
if name is not None:
|
|
48
|
+
if name in cls.loggers:
|
|
49
|
+
return cls.loggers.get(name)
|
|
50
|
+
|
|
51
|
+
logger = logging.getLogger(name)
|
|
52
|
+
|
|
53
|
+
if handler is None:
|
|
54
|
+
formatter = logging.Formatter(format)
|
|
55
|
+
handler = logging.StreamHandler()
|
|
56
|
+
handler.setFormatter(formatter)
|
|
57
|
+
|
|
58
|
+
logger.addHandler(handler)
|
|
59
|
+
cls.DEFAULT = logging_level
|
|
60
|
+
logger.setLevel(logging_level)
|
|
61
|
+
cls.loggers[name] = logger
|
|
62
|
+
|
|
63
|
+
return logger
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def setHandler(handler, name=master_logger_name):
|
|
67
|
+
"""
|
|
68
|
+
Set the handler for the logger.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
handler (logging.Handler): Handler object.
|
|
72
|
+
name (str): Logger name (default: master_logger_name).
|
|
73
|
+
"""
|
|
74
|
+
logger = logging.getLogger(name)
|
|
75
|
+
try:
|
|
76
|
+
for hndlr in logger.handlers:
|
|
77
|
+
logger.removeHandler(hndlr)
|
|
78
|
+
except:
|
|
79
|
+
pass
|
|
80
|
+
logger.addHandler(handler)
|
|
81
|
+
logger.setLevel(TA_logger.DEFAULT)
|
|
82
|
+
|
|
83
|
+
if __name__ == '__main__':
|
|
84
|
+
logger = TA_logger()
|
|
85
|
+
logger.debug("test")
|
|
86
|
+
logger.info("test")
|
|
87
|
+
logger.warning("test")
|
|
88
|
+
logger.error("test")
|
|
89
|
+
logger.critical("test")
|
|
90
|
+
|
|
91
|
+
formatter = logging.Formatter(TA_logger.default_format)
|
|
92
|
+
handler = logging.StreamHandler()
|
|
93
|
+
handler.setFormatter(formatter)
|
|
94
|
+
|
|
95
|
+
TA_logger.setHandler(handler)
|
|
96
|
+
logger.debug("test")
|
|
97
|
+
logger.info("test")
|
|
98
|
+
logger.warning("test")
|
|
99
|
+
logger.error("test")
|
|
100
|
+
logger.critical("test")
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
# use this class to wrap and time any function without modifying it
|
|
5
|
+
|
|
6
|
+
def timer(func):
|
|
7
|
+
"""Decorator to time functions"""
|
|
8
|
+
|
|
9
|
+
@wraps(func)
|
|
10
|
+
def wrapper(*args, **kwargs):
|
|
11
|
+
"""Inner wrapper function"""
|
|
12
|
+
start = time.time()
|
|
13
|
+
result = func(*args, **kwargs)
|
|
14
|
+
end = time.time()
|
|
15
|
+
print(end-start)
|
|
16
|
+
return result
|
|
17
|
+
return wrapper
|
|
18
|
+
|
|
19
|
+
@timer
|
|
20
|
+
def func():
|
|
21
|
+
print('bob')
|
|
22
|
+
|
|
23
|
+
@timer
|
|
24
|
+
def addition(a,b):
|
|
25
|
+
return a+b
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == '__main__':
|
|
29
|
+
func()
|
|
30
|
+
|
|
31
|
+
res = addition(10,12)
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import traceback
|
|
2
|
+
|
|
3
|
+
# have nice colored command line outputs (can be very useful when using command line tools)
|
|
4
|
+
# http://en.wikipedia.org/wiki/ANSI_escape_code
|
|
5
|
+
|
|
6
|
+
STRING_TO_ANSI = {
|
|
7
|
+
'black': 30,
|
|
8
|
+
'red': 31,
|
|
9
|
+
'green': 32,
|
|
10
|
+
'yellow': 33,
|
|
11
|
+
'blue': 34,
|
|
12
|
+
'magenta': 35,
|
|
13
|
+
'cyan': 36,
|
|
14
|
+
'white': 37,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
__ANSI_STYLEs = {
|
|
18
|
+
'Bold':1,
|
|
19
|
+
'Faint':2,
|
|
20
|
+
'Italic':3,
|
|
21
|
+
'Underline':4,
|
|
22
|
+
'B': 1,
|
|
23
|
+
'F': 2,
|
|
24
|
+
'I': 3,
|
|
25
|
+
'U': 4,
|
|
26
|
+
'<B>': 1, # check if this is html
|
|
27
|
+
'<I>': 3,
|
|
28
|
+
'<U>': 4,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# add string to bg
|
|
32
|
+
# adds the letter values of ANSI
|
|
33
|
+
# adds bright colors to ANSI
|
|
34
|
+
__tmp = {}
|
|
35
|
+
for color, value in STRING_TO_ANSI.items():
|
|
36
|
+
__tmp[color[0]]=value
|
|
37
|
+
__tmp['l'+color[0]] = value + 60
|
|
38
|
+
__tmp['b'+color[0]] = value + 60
|
|
39
|
+
__tmp['bg' + color[0]] = value + 10
|
|
40
|
+
__tmp['lbg' + color[0]] = value + 60 + 10
|
|
41
|
+
__tmp['bbg' + color[0]] = value + 60 + 10
|
|
42
|
+
|
|
43
|
+
# add light or bright colors
|
|
44
|
+
for color, value in STRING_TO_ANSI.items():
|
|
45
|
+
__tmp['light_'+color]=value + 60
|
|
46
|
+
__tmp['bright_'+color]=value + 60
|
|
47
|
+
__tmp['foreground_' + color] = value
|
|
48
|
+
__tmp['fg' + color] = value
|
|
49
|
+
__tmp['background_' + color] = value + 10
|
|
50
|
+
__tmp['bg' + color] = value + 10
|
|
51
|
+
__tmp['light_background_' + color] = value + 60 + 10
|
|
52
|
+
__tmp['bright_background_' + color] = value + 60 + 10
|
|
53
|
+
__tmp['bg' + color] = value + 10
|
|
54
|
+
__tmp['lbg' + color] = value + 60 + 10
|
|
55
|
+
__tmp['bbg' + color] = value + 60 + 10
|
|
56
|
+
|
|
57
|
+
STRING_TO_ANSI.update(__tmp)
|
|
58
|
+
del __tmp
|
|
59
|
+
STRING_TO_ANSI.update(__ANSI_STYLEs)
|
|
60
|
+
|
|
61
|
+
def demo_all_ansi():
|
|
62
|
+
"""
|
|
63
|
+
Demonstrates ANSI color codes by printing each color code with its corresponding number.
|
|
64
|
+
|
|
65
|
+
This function iterates through ANSI color codes (0-108) and prints each code along with its number
|
|
66
|
+
to demonstrate how different colors can be displayed using ANSI escape sequences.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
None
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
None
|
|
73
|
+
...
|
|
74
|
+
"""
|
|
75
|
+
import sys
|
|
76
|
+
for i in range(11):
|
|
77
|
+
for j in range(10):
|
|
78
|
+
n = 10 * i + j
|
|
79
|
+
if n > 108:
|
|
80
|
+
break
|
|
81
|
+
sys.stdout.write(f"\x1b[{n}m {n:3d}\x1b[0m")
|
|
82
|
+
print()
|
|
83
|
+
|
|
84
|
+
def create_ansi(ansi_value, text=''):
|
|
85
|
+
"""
|
|
86
|
+
Create ANSI-formatted text by applying ANSI color codes to the input text.
|
|
87
|
+
|
|
88
|
+
This function takes an ANSI color code or a list of codes and applies them to the input text.
|
|
89
|
+
It returns the text with the specified color codes applied.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
ansi_value (int, str, or list): ANSI color code(s) to apply. Can be an integer, a string
|
|
93
|
+
representing a color name, or a list of integers/strings.
|
|
94
|
+
text (str, optional): The input text to which ANSI codes will be applied. Defaults to an empty string.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
str: The input text with ANSI color codes applied.
|
|
98
|
+
|
|
99
|
+
"""
|
|
100
|
+
if isinstance(ansi_value, (int,str)):
|
|
101
|
+
ansi_value = [ansi_value]
|
|
102
|
+
output=""
|
|
103
|
+
for ansi in ansi_value:
|
|
104
|
+
if isinstance(ansi, str):
|
|
105
|
+
try:
|
|
106
|
+
ansi = STRING_TO_ANSI[ansi]
|
|
107
|
+
except:
|
|
108
|
+
print('unsupported ANSI',ansi)
|
|
109
|
+
traceback.print_exc()
|
|
110
|
+
continue
|
|
111
|
+
output+=f'\x1b[{ansi}m'
|
|
112
|
+
output+=text
|
|
113
|
+
output+="\x1b[0m"
|
|
114
|
+
return output
|
|
115
|
+
|
|
116
|
+
def print_raw(text):
|
|
117
|
+
"""
|
|
118
|
+
Print text raw without special characters interpreted.
|
|
119
|
+
|
|
120
|
+
This function prints the input text without interpreting special characters or ANSI escape sequences.
|
|
121
|
+
It allows viewing the ANSI text as a raw string rather than as colored text.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
text (str): The input text to print.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
None
|
|
128
|
+
|
|
129
|
+
"""
|
|
130
|
+
print(repr(text))
|
|
131
|
+
|
|
132
|
+
if __name__ == '__main__':
|
|
133
|
+
# prompt = input(create_ansi('g', '>>>You:\n'))
|
|
134
|
+
# print(create_ansi('br', "\n>>>ChatGPT:\n" + prompt))
|
|
135
|
+
|
|
136
|
+
print("Hello\x1b[K") # Clear line
|
|
137
|
+
print("\x1b[2J\x1b[HCleared screen") # Clear screen
|
|
138
|
+
|
|
139
|
+
# VERY GOOD −−> MAKE USE OF THAT CAUSE VERY USEFUL WITH THE COMMANDE LINE
|
|
140
|
+
|
|
141
|
+
print(create_ansi(9, 'test')) # --> barre le texte
|
|
142
|
+
print_raw(create_ansi(9, 'test')) # '\x1b[9mtest\x1b[0m'
|
|
143
|
+
|
|
144
|
+
print(create_ansi(37, 'test')) # --> en gris
|
|
145
|
+
print_raw(create_ansi(37, 'test')) # --> '\x1b[37mtest\x1b[0m'
|
|
146
|
+
|
|
147
|
+
# combinaison des deux
|
|
148
|
+
print('\x1b[37m\x1b[9mtest\x1b[0m') #very good so it's fairly easy to combine
|
|
149
|
+
|
|
150
|
+
print(create_ansi([9,37,52], 'test')) # cree un text encadré # peut etre faire pareil avec des strings et aussi du html to be faster
|
|
151
|
+
# I could convert html to ansi --> would be cool too
|
|
152
|
+
# print(create_ansi([9, 'bright_yellow', 52],'test')) # cree un text encadré # peut etre faire pareil avec des strings et aussi du html to be faster
|
|
153
|
+
print(create_ansi([9, 'ly', 52],'test')) # cree un text encadré # peut etre faire pareil avec des strings et aussi du html to be faster
|
|
154
|
+
print(create_ansi([9, 'lbgr','ly', 52],'test')) # cree un text encadré jaune surligné en rouge
|
|
155
|
+
print(create_ansi(['B','lbgr','ly'],'test')) # cree un text encadré jaune surligné en rouge
|
|
156
|
+
print(create_ansi([9, 'B'],'test')) # cree un text encadré jaune surligné en rouge
|
|
157
|
+
print(create_ansi([9, 'I'],'test')) # cree un text encadré jaune surligné en rouge
|
|
158
|
+
print(create_ansi([9, 'I','B'],'test')) # bold italic barre
|
|
159
|
+
|
|
160
|
+
demo_all_ansi()
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# modified from https://stackoverflow.com/questions/24469662/how-to-redirect-logger-output-into-pyqt-text-widget
|
|
2
|
+
from batoolset.settings.global_settings import set_UI
|
|
3
|
+
set_UI()
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from qtpy import QtCore
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class QtHandler(logging.Handler):
|
|
11
|
+
"""
|
|
12
|
+
Custom logging handler for Qt application.
|
|
13
|
+
It emits log records to either stdout or stderr based on the log level.
|
|
14
|
+
|
|
15
|
+
Attributes:
|
|
16
|
+
messageWritten (QtCore.Signal): Signal emitted when a log message is written.
|
|
17
|
+
|
|
18
|
+
Methods:
|
|
19
|
+
emit(record): Formats and emits the log record.
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
logging.Handler.__init__(self)
|
|
25
|
+
|
|
26
|
+
def emit(self, record):
|
|
27
|
+
"""
|
|
28
|
+
Formats and emits the log record.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
record (logging.LogRecord): The log record to be emitted.
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
record = self.format(record)
|
|
35
|
+
if record:
|
|
36
|
+
if record.startswith('ERROR') or record.startswith('CRITICAL') or record.startswith('WARNING'):
|
|
37
|
+
XStream.stderr().write('%s' % record)
|
|
38
|
+
else:
|
|
39
|
+
XStream.stdout().write('%s' % record)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class XStream(QtCore.QObject):
|
|
43
|
+
"""
|
|
44
|
+
Custom QObject class for capturing stdout and stderr.
|
|
45
|
+
|
|
46
|
+
Attributes:
|
|
47
|
+
_stdout (XStream): The singleton instance for stdout.
|
|
48
|
+
_stderr (XStream): The singleton instance for stderr.
|
|
49
|
+
messageWritten (QtCore.Signal): Signal emitted when a log message is written.
|
|
50
|
+
|
|
51
|
+
Methods:
|
|
52
|
+
flush(): Flushes the output.
|
|
53
|
+
fileno(): Returns the file number.
|
|
54
|
+
write(msg): Writes the message to the output stream.
|
|
55
|
+
stdout(): Returns the singleton instance for stdout.
|
|
56
|
+
stderr(): Returns the singleton instance for stderr.
|
|
57
|
+
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
_stdout = None
|
|
61
|
+
_stderr = None
|
|
62
|
+
messageWritten = QtCore.Signal(str)
|
|
63
|
+
|
|
64
|
+
def flush(self):
|
|
65
|
+
"""
|
|
66
|
+
Flushes the output.
|
|
67
|
+
|
|
68
|
+
"""
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
def fileno(self):
|
|
72
|
+
"""
|
|
73
|
+
Returns the file number.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
int: The file number (-1).
|
|
77
|
+
|
|
78
|
+
"""
|
|
79
|
+
return -1
|
|
80
|
+
|
|
81
|
+
def write(self, msg):
|
|
82
|
+
"""
|
|
83
|
+
Writes the message to the output stream.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
msg (str): The message to be written.
|
|
87
|
+
|
|
88
|
+
"""
|
|
89
|
+
if not self.signalsBlocked():
|
|
90
|
+
self.messageWritten.emit(msg)
|
|
91
|
+
|
|
92
|
+
@staticmethod
|
|
93
|
+
def stdout():
|
|
94
|
+
"""
|
|
95
|
+
Returns the singleton instance for stdout.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
XStream: The singleton instance for stdout.
|
|
99
|
+
|
|
100
|
+
"""
|
|
101
|
+
if not XStream._stdout:
|
|
102
|
+
XStream._stdout = XStream()
|
|
103
|
+
sys.stdout = XStream._stdout
|
|
104
|
+
return XStream._stdout
|
|
105
|
+
|
|
106
|
+
@staticmethod
|
|
107
|
+
def stderr():
|
|
108
|
+
"""
|
|
109
|
+
Returns the singleton instance for stderr.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
XStream: The singleton instance for stderr.
|
|
113
|
+
|
|
114
|
+
"""
|
|
115
|
+
if not XStream._stderr:
|
|
116
|
+
XStream._stderr = XStream()
|
|
117
|
+
sys.stderr = XStream._stderr
|
|
118
|
+
return XStream._stderr
|
|
File without changes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from batoolset.settings.global_settings import set_UI
|
|
2
|
+
set_UI()
|
|
3
|
+
import os
|
|
4
|
+
from qtpy.QtCore import QTimer
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Blinker:
|
|
8
|
+
"""
|
|
9
|
+
Utility class for blinking components by changing their background color to red temporarily.
|
|
10
|
+
|
|
11
|
+
Methods:
|
|
12
|
+
blink(component): Blinks the given component or a list of components.
|
|
13
|
+
reset_stylesheet(component): Resets the stylesheet of the given component or a list of components.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
def blink(self, component):
|
|
21
|
+
"""
|
|
22
|
+
Blinks the given component or a list of components by changing their background color to red temporarily.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
component (QWidget or list[QWidget]): The component or list of components to be blinked.
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
if isinstance(component, list):
|
|
29
|
+
for comp in component:
|
|
30
|
+
comp.setStyleSheet("background-color: red;")
|
|
31
|
+
else:
|
|
32
|
+
component.setStyleSheet("background-color: red;")
|
|
33
|
+
|
|
34
|
+
self.current_timer = QTimer()
|
|
35
|
+
self.current_timer.timeout.connect(lambda: self.reset_stylesheet(component))
|
|
36
|
+
self.current_timer.setSingleShot(True)
|
|
37
|
+
self.current_timer.start(3000)
|
|
38
|
+
|
|
39
|
+
def reset_stylesheet(self, component):
|
|
40
|
+
"""
|
|
41
|
+
Resets the stylesheet of the given component or a list of components, restoring the original appearance.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
component (QWidget or list[QWidget]): The component or list of components to reset the stylesheet.
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
if isinstance(component, list):
|
|
48
|
+
for comp in component:
|
|
49
|
+
comp.setStyleSheet('background-color: none;')
|
|
50
|
+
else:
|
|
51
|
+
component.setStyleSheet('background-color: none;')
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
if __name__ == '__main__':
|
|
55
|
+
blinker = Blinker()
|
|
56
|
+
# blinker.blink()
|
|
File without changes
|