From e65eb6bff57af79512b2a59b323d156a85ca5e1c Mon Sep 17 00:00:00 2001 From: <> Date: Sat, 23 Nov 2024 21:41:38 +0000 Subject: [PATCH] Deployed 25a2a73 with MkDocs version: 1.6.1 --- .../applications/callable/index.html | 2 +- .../applications/callable_codeobj.pickle | Bin 4943 -> 4931 bytes .../applications/chaining_codeobj.pickle | Bin 13613 -> 13598 bytes .../applications/hotdog/index.html | 2 +- .../applications/hotdog_codeobj.pickle | Bin 3699 -> 3699 bytes .../mg_execution_times/index.html | 10 +++---- .../applications/pint_quantity/index.html | 2 +- .../applications/pint_quantity_codeobj.pickle | Bin 4561 -> 4555 bytes .../applications/snells_law/index.html | 2 +- .../applications/snells_law_codeobj.pickle | Bin 2911 -> 2911 bytes generated_examples/basic_example/index.html | 2 +- .../basic_example_codeobj.pickle | Bin 2469 -> 2469 bytes .../basic_widgets_demo/index.html | 4 +-- .../basic_widgets_demo_codeobj.pickle | Bin 3945 -> 3945 bytes .../demo_widgets/change_label/index.html | 2 +- .../demo_widgets/change_label_codeobj.pickle | Bin 2469 -> 2469 bytes .../demo_widgets/choices_codeobj.pickle | Bin 5253 -> 5280 bytes .../demo_widgets/directory_dialog/index.html | 2 +- .../directory_dialog_codeobj.pickle | Bin 2892 -> 2892 bytes .../demo_widgets/file_dialog/index.html | 2 +- .../demo_widgets/file_dialog_codeobj.pickle | Bin 2881 -> 2881 bytes .../demo_widgets/files_dialog/index.html | 2 +- .../demo_widgets/files_dialog_codeobj.pickle | Bin 3563 -> 3563 bytes .../demo_widgets/image/index.html | 2 +- .../demo_widgets/image_codeobj.pickle | Bin 3433 -> 3433 bytes .../demo_widgets/log_slider/index.html | 2 +- .../demo_widgets/log_slider_codeobj.pickle | Bin 2370 -> 2370 bytes .../demo_widgets/login/index.html | 2 +- .../demo_widgets/login_codeobj.pickle | Bin 2321 -> 2321 bytes .../mg_execution_times/index.html | 26 +++++++++--------- .../demo_widgets/optional/index.html | 2 +- .../demo_widgets/optional_codeobj.pickle | Bin 2406 -> 2406 bytes .../demo_widgets/range_slider/index.html | 2 +- .../demo_widgets/range_slider_codeobj.pickle | Bin 2320 -> 2320 bytes .../demo_widgets/selection/index.html | 2 +- .../demo_widgets/table/index.html | 4 +-- .../demo_widgets/table_codeobj.pickle | Bin 18732 -> 18750 bytes .../generated_examples_jupyter.zip | Bin 85019 -> 85019 bytes .../generated_examples_python.zip | Bin 50440 -> 50440 bytes .../images/mkd_glr_basic_widgets_demo_001.png | Bin 31520 -> 31375 bytes .../mkd_glr_basic_widgets_demo_thumb.png | Bin 25565 -> 25507 bytes .../matplotlib/mg_execution_times/index.html | 6 ++-- .../matplotlib/mpl_figure/index.html | 2 +- .../matplotlib/mpl_figure_codeobj.pickle | Bin 9300 -> 9303 bytes .../matplotlib/waveform/index.html | 2 +- .../matplotlib/waveform_codeobj.pickle | Bin 9667 -> 9676 bytes .../mg_execution_times/index.html | 6 ++-- .../images/mkd_glr_napari_img_math_001.png | Bin 47494 -> 47465 bytes .../thumb/mkd_glr_napari_img_math_thumb.png | Bin 29164 -> 29299 bytes .../napari/mg_execution_times/index.html | 10 +++---- .../napari/napari_combine_qt/index.html | 2 +- .../napari/napari_combine_qt_codeobj.pickle | Bin 8732 -> 8738 bytes .../napari/napari_forward_refs/index.html | 2 +- .../napari/napari_img_math/index.html | 2 +- .../napari/napari_img_math_codeobj.pickle | Bin 8154 -> 8151 bytes .../napari/napari_parameter_sweep/index.html | 2 +- .../napari_parameter_sweep_codeobj.pickle | Bin 7556 -> 7565 bytes .../mg_execution_times/index.html | 10 +++---- .../progress_bars/progress/index.html | 2 +- .../progress_bars/progress_codeobj.pickle | Bin 2529 -> 2529 bytes .../progress_indeterminate/index.html | 2 +- .../progress_indeterminate_codeobj.pickle | Bin 2850 -> 2850 bytes .../progress_bars/progress_manual/index.html | 4 +-- .../progress_manual_codeobj.pickle | Bin 4115 -> 4115 bytes .../progress_bars/progress_nested/index.html | 2 +- .../progress_nested_codeobj.pickle | Bin 3926 -> 3926 bytes .../under_the_hood/class_method/index.html | 2 +- .../class_method_codeobj.pickle | Bin 4809 -> 4812 bytes .../mg_execution_times/index.html | 6 ++-- .../under_the_hood/self_reference/index.html | 2 +- scripts/__pycache__/_hooks.cpython-313.pyc | Bin 10613 -> 10613 bytes search/search_index.json | 2 +- type_map/index.html | 2 +- 73 files changed, 71 insertions(+), 71 deletions(-) diff --git a/generated_examples/applications/callable/index.html b/generated_examples/applications/callable/index.html index 22a506fa5..a1d0dfe8b 100644 --- a/generated_examples/applications/callable/index.html +++ b/generated_examples/applications/callable/index.html @@ -2953,7 +2953,7 @@

Callable functions demoexample.func.changed.connect(update) example.show(run=True) -

Total running time of the script: ( 0 minutes 0.050 seconds)

+

Total running time of the script: ( 0 minutes 0.037 seconds)

Download Python source code: callable.py

diff --git a/generated_examples/applications/callable_codeobj.pickle b/generated_examples/applications/callable_codeobj.pickle index 10469d234077c2ba440ce5ae44771341e07edcf7..339560e64e5ec5dff105da4c9bae0ef14e945f08 100644 GIT binary patch delta 973 zcmYk4U1-x#7>3t5zDmp0~KwgoGogDm8_xL3dPY1cF2Y^l+=ZW z8!oBE^JPPq3rZ$ClBr}<?6x=A9HaC;jHEg{+HHVF^FO66t+SSYOj!?X9*#)B_PWD5Z@peH~#pw#(ugdEpxg$m3EDj=`IB2L>JZ(ht zv~cP}8coNU!So_Rmp93&RfH4XZcd#G91xq{0+t>&F^UWgMz|M2W-x+>7bv2ya#>v;_DBML|hcGE}2{IuB zutD7uE;)I0au&-HtYrvism0;{<$1-RDTc4^++34L?!o zwb8vg|xLvI(m?)2!ASj;*>` zsbS3BYC4ABR;rECVujF1>}D9GK_LPf}JrqFL*c50b_z$? z4st5gL!Sn9xW_pI3#bn<`xMe)k#h#_qi%+>@PKOiRj`>yWoAf1AYo#1r2^7 zpCK98N4-tbaDci-juNxQ)6#;xL;8scF6Wdkn)9_2Q~v9*=5zVFGDu9-haXiP_;YdzXBz&VSzT3#w*}d;Ec{%pXt<3Aq3O diff --git a/generated_examples/applications/chaining_codeobj.pickle b/generated_examples/applications/chaining_codeobj.pickle index ee8e0f8b1217b61c7dee4e8372b5528aa5db2949..6d86d99ed52ba2bcba95be9e24b216b6ce764d9d 100644 GIT binary patch delta 1129 zcmY+DYe-Z<7>4^kj%C)Gn=7?#?XH(~x83#Vt}B5MC`KTqA_Y-VCSq-eNC>2`k|Hbv zyV%=}B1yVZgj!MbBdmTDU9|N_P)JfCMP)akD1vHcw&UWTndkjx=DhD2zPVy_7}}1c zBk4WboMcodZ>1&_OwPpT%qpj#jabt&d5xUZv3DB*1bQE{3IieQhXs1H8 z^DG9YI&g4i7Dq2AjLn$E(M$L?GoPbZM8!wlsJ6Q}dJPVXmu}#A>VE1SGkugW?HgzM zT$v6gOy4F<-zQ8*5~g3`rlZRAd))M=GX0G*%l_$xMiVAPEqfd5+a|7U+*nsri%!=~ zvf^s`19GCt)~b2Mj{ngfCmCT=mDnv>kratr*`8#S$ck-nnq zSa?0(B9s@d=R1V!h4uV^;E2?4KVe&B9Y2%PEc}fGk?CsSH^Ro#!XF8Lay?k-twMjU z9TjsOc$JnVSmz&dDXjgHcBj2wv1gDpguH&d@LOmS8hpi+BF0?Ad}(C4_S#28v(e-C zVTwPST#AY!ng{q6pp#E!XD>3Q;kt zf-bc_Ur;`kpgTAlC&hZ1pdc;8%V31c#pp(HAdMF@4!Q30a>i|EA+KhPI&-;}vBJGa zGg$mh{E>*JXf%~a6qMBm2B(o{nO(C1&Fv#N+Zzh|LDN>DbLZNDmQvw5g zno(uXqBE%W__g!$ydzn+8J7jgCa!HujW@Br1qW@LwCi%mSjt{g$&~k`7?-k7R#eKE mBs1lpDP+o_v6Qb9DTfm&->H-z;weALlvBQn^Xh>$>i+;Ub6>>( delta 1028 zcmYL`X-HI27>4`4u4p#5W^}AsoPC@bCrw8&BQc6-p=g012&AcC;5va7t&~&{tT4F?P+aa-pSx? z%~OD$s#w0U-O!J0TL*tZEA2foA%L!eS9BEFNz>^VsK$>+iI;4gQrMQTuyGoXr-qTO ze8a|Ng=+OGE?C@H<_NNJL*bmsE;eo{%-Tw*Lr{!5@!IC6dl<4s={_7q88)8bdeKuh zdQq%r=%X2+Uj_I+7U1VtfM25ldNrbP<3=Osq@mg|m-5BvMb_b_!V$9BIj!T1V;Wgu zafYZE)y_Cg!KUID6v9mVVXDAm`w-QOF^sl^PP5QEB_w{ko8}9u))twTY-O*u(kx`> zDy3YVQ#Oq$lS;W>DN|B8!4O}{t4?9Ks+Be?X=_fpHzz%+q{mE;l%6sRDLt*EXLHgE zW73OCdPPaENh!Az=EZBdgRnCm(K_WhvjbbXi?F-=Irk9G#}Cn4mF06T%hz0%L6v35 z)XOY?%tB`QC$lgy5)O~Nbk;`EW*?u>DkHE3$-^ ziZO;v#7!%3Ez(FURc(#RH}XbnX|))A_z<;H6YfO===T+KIw>$g>*0?DFfnGQl%NC| zI2iMdG;9!9MJ>1+s}>J75UbF(O7-NRNABmPcbJtpn0GOnoO`tWa&4~5i@(lpEn^k~ zE?qk=i=;a!c9x^d?LgAiDCSB&!x(fY_#DGux<$Jz+xkjNaHI4ccQV#^gSh0`!w*Jq zp|^w|O0421j5cqIyBWW{&HRS3&ezQE8LxaP{=}&DC%K<7?04a&e<}ZvxPZ4!{|_u{ BLWuwX diff --git a/generated_examples/applications/hotdog/index.html b/generated_examples/applications/hotdog/index.html index d7bd1f0a0..41a1f346b 100644 --- a/generated_examples/applications/hotdog/index.html +++ b/generated_examples/applications/hotdog/index.html @@ -2960,7 +2960,7 @@

Hotdog or not appif __name__ == "__main__": is_hotdog.show(run=True) -

Total running time of the script: ( 0 minutes 0.039 seconds)

+

Total running time of the script: ( 0 minutes 0.040 seconds)

Download Python source code: hotdog.py

diff --git a/generated_examples/applications/hotdog_codeobj.pickle b/generated_examples/applications/hotdog_codeobj.pickle index 656b6385d6b8df38611606a9f29d04a12d462d9e..caa0cb2231185a51893e4c4cedf74f5557d4485f 100644 GIT binary patch delta 216 zcmew?^I2wso+gWHUTN->*eM#dQ#5*5@)C1Xr}RL?df0OFQ%Z9{{8XTtiLtT@9i>23 z8SGF68JrNADH+@u{24r*rKuBZEf_^6PhgT^6rXrGkx^l?DPts~`s9AbFh;$}3QW?I zeHb+-Yca_(nojm$k~gscYwF>Mj|bTs9}jc}#C+!BlAd|qO1YJB{Z*eSJBGOi4&(-FbYmQE5j%<@l_(D>|`ItNJf>(%NWBLwI}~&Ok^~g9M2>#V4A_x zS(@6z;+j{Q3p8G1;zbEYE1)hmTd>6BZ%jIjPLq|HRoGl10-KoZ*t|f@#Ld3UYTN)g CdN`K= diff --git a/generated_examples/applications/mg_execution_times/index.html b/generated_examples/applications/mg_execution_times/index.html index e06dd0b5d..3e7ed3453 100644 --- a/generated_examples/applications/mg_execution_times/index.html +++ b/generated_examples/applications/mg_execution_times/index.html @@ -2885,17 +2885,17 @@

Computation times#

-

00:00.367 total execution time for generated_examples_applications files:

+

00:00.342 total execution time for generated_examples_applications files:

+-----------------------------------------------------------------------------------+-----------+--------+ -| pint_quantity (docs/examples/applications/pint_quantity.py) | 00:00.196 | 0.0 MB | +| pint_quantity (docs/examples/applications/pint_quantity.py) | 00:00.162 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ | chaining (docs/examples/applications/chaining.py) | 00:00.054 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ -| callable (docs/examples/applications/callable.py) | 00:00.050 | 0.0 MB | +| snells_law (docs/examples/applications/snells_law.py) | 00:00.049 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ -| hotdog (docs/examples/applications/hotdog.py) | 00:00.039 | 0.0 MB | +| hotdog (docs/examples/applications/hotdog.py) | 00:00.040 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ -| snells_law (docs/examples/applications/snells_law.py) | 00:00.029 | 0.0 MB | +| callable (docs/examples/applications/callable.py) | 00:00.037 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ | values_dialog (docs/examples/applications/values_dialog.py) | 00:00.000 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+

diff --git a/generated_examples/applications/pint_quantity/index.html b/generated_examples/applications/pint_quantity/index.html index 8321bf1db..31405c526 100644 --- a/generated_examples/applications/pint_quantity/index.html +++ b/generated_examples/applications/pint_quantity/index.html @@ -2941,7 +2941,7 @@

Quantities with pintwidget.show(run=True) -

Total running time of the script: ( 0 minutes 0.196 seconds)

+

Total running time of the script: ( 0 minutes 0.162 seconds)

Download Python source code: pint_quantity.py

diff --git a/generated_examples/applications/pint_quantity_codeobj.pickle b/generated_examples/applications/pint_quantity_codeobj.pickle index 458053fab0bb43b23f81b1ce411bc69bb14ee723..e2fc66cb9c49759b787e7b7062da28a9fba035ea 100644 GIT binary patch delta 651 zcmYk&O=#0#7zgk@X__Wo)1*)@uC3iNwQjXc4^|4IpeT58ih>|IN?V$g^@AqaEIL#a zM99JNkBEvOejo~p!tgSbdD%rpy$p(8^dfi_#Si>=lL~ry_&xvUd0$@M*V;3UKN-BR z*yYDI4bB?nYQ@T#dUMu2>}KZNjKepI^@{7LJMBivGMbHDw$YzELcLkGrzIAj0td4WK z2_cr{^cm!18BXu`kM~xO`+5{pIQ;~^iyP<+veM|*v$}lFt~laeyV$S{tMm73_0WHj zE;(|`Xjr*+rD~W~yW{GE4(}x{dSaT+gDBZuYSKjyxEE0Avag?cVTgLdWiSjD9xiANI(nJX@MzAPyF87dWskP2n2qKo->WpOFRx{FdV!>%S@Z8 z=l3Z=qPJKO64)W!pbx&h(;smyl)zZ%I(_!#Wnb|rG)zCRTTB3=hW+BoV2z`J0kp(w SuqJuxiK`;D2$TOkcJ2?h_|~NW delta 625 zcmYL_U1-x#7>4`BByEGm30J$3gRCMyHk)VC>xboTxlBCb~Gt<=v2Is zK@hq(dgFzEH;Q=W5WJTS6&d2~aBQdu17RWvL&1|&@#gS6@5?zK=XJJv=3<|iJOv&P5A;H3aqARbQIT=0XmLb>TWD4i*%Avj!xlfG>dihE}dm`fW`t} zjY?F&m00JU?${kF2jzV3Yv*gOH%4E6Z7;GIaf1B;CU3emNw_8!1ru01RXfL0k2Pm_T zAEP`y#ystzr|9Q&tk4H~5s=KQ^z!){#}U248aD_(SVErHahUI+H;neuI~0Tj?(v^! z1yON;P0?vJpiwTtnd=M>(&r$ki7I`?Gcg%l-(WOM-=Kz57!UW*CL@D>p#Il?GBRij x%i(0u|7MgEtPq7l_!S-&tZg0IiPvIGuteYd|BQ#X3zqcHSf^MDvtTbx;}4ii#p3_~ diff --git a/generated_examples/applications/snells_law/index.html b/generated_examples/applications/snells_law/index.html index ccbd296fa..d888fd1f1 100644 --- a/generated_examples/applications/snells_law/index.html +++ b/generated_examples/applications/snells_law/index.html @@ -2955,7 +2955,7 @@

Snell's law demonstration using snells_law.show(run=True) -

Total running time of the script: ( 0 minutes 0.029 seconds)

+

Total running time of the script: ( 0 minutes 0.049 seconds)

Download Python source code: snells_law.py

diff --git a/generated_examples/applications/snells_law_codeobj.pickle b/generated_examples/applications/snells_law_codeobj.pickle index 013defd983e3623f3f865e88e7d5120a846a2d43..0c94f2554fd646ec93e315fc507e594d933e1991 100644 GIT binary patch delta 435 zcmXAkziSh57{+;$+~sn)Vuqt?ny4{R3&zue;19Yuh$z%{a|+jMb8tuVLvwd1LO^J# z7LICo4&xwX5kx40;L=SI`acweICOIB(xpTF=IiqCc|Om(yyNNd^thD5%h^jjR;yT%^gdlod9J{_@TB;Wox&PVvL$XS zCOU%Zct%@0Mq^)r~>` delta 452 zcmY+A+eZX(6vv%uc5b^-Y$@GryWQBPi*EFg9x6*kM8sOd4zp<{wx+8}lrAP3-w~yk zi1ZRA(ZA4J^j6eMe?Tuiu4aBkdO1Gld(QVbzHjAkPUkt*LRc}kv-ct8KT1vS+?mJvcu~P!ba4H z?Ay8%F|`Fl&1>15X3gVW?uk_fgCCdpt21M;=ow+7+PzCr%q`SW0=4u?9T?zhP{B=5 zA7;2l>W9mH(Xe0R7#E5ug-yN*??o>($tcjK@X7bmv|r;G4V6$D=}>`Y5fdA*6sp9j zpwJxa9)&8(GYX4kWc$=f%a|0~X$?DKk~VPbD_i&wRocdgREv}xrCpy?I>4gTPKUUZ zl5~V;sg(duZlPoLaj}RUm8VQwHf8t4cN9;7J}z S-2Y`%G@rBn<@3NU+3GhVy_8A- diff --git a/generated_examples/basic_example/index.html b/generated_examples/basic_example/index.html index 0b852e96e..c5ec5547a 100644 --- a/generated_examples/basic_example/index.html +++ b/generated_examples/basic_example/index.html @@ -2936,7 +2936,7 @@

Basic exampleexample.changed.connect(print) example.show(run=True) -

Total running time of the script: ( 0 minutes 0.895 seconds)

+

Total running time of the script: ( 0 minutes 0.766 seconds)

Download Python source code: basic_example.py

diff --git a/generated_examples/basic_example_codeobj.pickle b/generated_examples/basic_example_codeobj.pickle index 488a5f5265dac868ad7875d1b2176cb4a4091b86..376c976ebba576125ae2af943981c378bcd7d65d 100644 GIT binary patch delta 535 zcmXw$%SyvQ6oyGpn+rN1w2Bz3)N8FZq9}q;=*GHJ5ClQA#wK(kObUkKz`ScVokkPGXO7jh1D{8#~V*hfAqB`}dc%COkk5?+QTa#!uv zj)a%NMZT*;BG(aK0w4LU&cZ2jK%0gOWL2AoOF^AIXno5!l-!4Qr2b!i@`zNy$Fc+3 lwm8)y^)Pf=f#dm{_Rw2Op03B>4)I#YQ-UgXVCt+9!ujhF@tq96#OL}|D< zxar{Hb|xpqFQs_y67h?%sR%-s9loU`s7XwQ|*{R2{?L_OmB`*5&Kv zn&!JgO>5}ZZUEMbCF7|6bA7t;2?|_qdW_7b|Ajwtf7P#-UG_G1^_^ zWUP13#N)br>1eL3HOsXFQ&XwyC^*ggN#avvz-vam&tXpXzQ?@xY@kz+p$+!AB+f_3 zAj(3HoLg=ZW=LPTD!H#*8asRvOI@R3)P^BgWcf78d@tmQ3y{GNZiOleu*KF426d}p zE~r~4PVsZF!8DC;LJT&Ei;+0q^YhddP={ATYJ-An5rst=C{bmN4gMI1cdouI&V$TX7FV*lW%e`ubTn*aa+ diff --git a/generated_examples/basic_widgets_demo/index.html b/generated_examples/basic_widgets_demo/index.html index ddab78792..1e74af958 100644 --- a/generated_examples/basic_widgets_demo/index.html +++ b/generated_examples/basic_widgets_demo/index.html @@ -2923,7 +2923,7 @@

Basic widgets demo

Out:

-
<MainFunctionGui widget_demo(boolean=True, integer=1, spin_float=3.14, slider_float=43.5, slider_int=550, string='Text goes here', dropdown=<Medium.Glass: 1.52>, radio_option=2, date=datetime.date(1999, 12, 31), time=datetime.time(1, 30, 20), datetime=datetime.datetime(2024, 11, 23, 21, 27, 53, 136000), filename=PosixPath('/Users/runner'))>
+
<MainFunctionGui widget_demo(boolean=True, integer=1, spin_float=3.14, slider_float=43.5, slider_int=550, string='Text goes here', dropdown=<Medium.Glass: 1.52>, radio_option=2, date=datetime.date(1999, 12, 31), time=datetime.time(1, 30, 20), datetime=datetime.datetime(2024, 11, 23, 21, 41, 22, 999000), filename=PosixPath('/Users/runner'))>
 


-

Total running time of the script: ( 0 minutes 0.124 seconds)

+

Total running time of the script: ( 0 minutes 0.122 seconds)

Download Python source code: basic_widgets_demo.py

diff --git a/generated_examples/basic_widgets_demo_codeobj.pickle b/generated_examples/basic_widgets_demo_codeobj.pickle index 9c934fbc0723bfac9e39d92832e6104d77325efc..94ab8b86dc20766ea2546601ec5ea9778feefb77 100644 GIT binary patch delta 546 zcmYk2OK1~O7=<~LbS96PY1BwfNXMy(ZNzrc6rr2?SahQZQ4zY5FpY&NOpQ9tMhLnQ zs}9z1M!{Vdf)EgO;X)A=Q4o|uK@hBh-~$3~3dNNaZ$=R}hwq&8|Mzll$LJW>t?Bp? zd)~2}`rJ%#A}BV4q8~kF3*-M+`0`x+WWyDqep*bsv(r}9t=DWf@YO#})pP1+=L28) z+XsGZ)~nWB+w%f$XgiSNfL=o%FX|;^`A{#SpQ&Dx8~P@gf`*aj-rfQRIiVfHZZ2v? zSlpGoA&)!S<;DyvY6%lOubSA;t?C|mvK!lcnJnQT*OMj=^P5`6QTAyC`FOa~8p*Vt z=a^PDw=U@Pu$>w*t&dZ%xh%}T{1RLqkPNn!G7m`u@OWS958Y$Q#5t}?gJ|+sq`+oR zg>NHSE=F7|h@_0Gw4y(8Q)r%MRKqRiZC4U$bVBOR|KO53)U)Pj3k}{=x5d`O-)mUE E0YA*PZvX%Q delta 543 zcmXYuUr1A77{+f}rRoC}mD}=!`Zu+?Ip>KoC@N zg01Hy1VXpnNZoWJ1QFCl6hQ`g;;qs-+>mV00A@jF_noUa!xmwWV1E-In0qwhLd@nOE^@_^PE zbbN(scD9(SR$V?(8tCFRHO_`|f^XGszE?8h9YmbJ)C!WE*5)w6H7$uT{`Mx==UvCR zpbU=li*HEiGyLxB<%;hzPDy7YXy7y>fnk}w@H;p!)sBCGtAQbY3Uy&h&|yro9r%kf ze+ExtUd)5MsP9Kz(z4!-hNM2#z*TPQW4OV+MjAJH#fZt4TY^m7=EwhfQILsyJQj+| zyeTLR(h7}Wi3}aWL$Oi6%$6nT;RqhF((yohY#Vp$7MDDuSmA5W0G@Kvb3}W#W9JwY z_A1AP{ha;bVfCeL+^I7i-iKHG>dD{@dzA#Custom text labels for widgetsexample.changed.connect(print) example.show(run=True)
-

Total running time of the script: ( 0 minutes 0.037 seconds)

+

Total running time of the script: ( 0 minutes 0.049 seconds)

Download Python source code: change_label.py

diff --git a/generated_examples/demo_widgets/change_label_codeobj.pickle b/generated_examples/demo_widgets/change_label_codeobj.pickle index 488a5f5265dac868ad7875d1b2176cb4a4091b86..376c976ebba576125ae2af943981c378bcd7d65d 100644 GIT binary patch delta 535 zcmXw$%SyvQ6oyGpn+rN1w2Bz3)N8FZq9}q;=*GHJ5ClQA#wK(kObUkKz`ScVokkPGXO7jh1D{8#~V*hfAqB`}dc%COkk5?+QTa#!uv zj)a%NMZT*;BG(aK0w4LU&cZ2jK%0gOWL2AoOF^AIXno5!l-!4Qr2b!i@`zNy$Fc+3 lwm8)y^)Pf=f#dm{_Rw2Op03B>4)I#YQ-UgXVCt+9!ujhF@tq96#OL}|D< zxar{Hb|xpqFQs_y67h?%sR%-s9loU`s7XwQ|*{R2{?L_OmB`*5&Kv zn&!JgO>5}ZZUEMbCF7|6bA7t;2?|_qdW_7b|Ajwtf7P#-UG_G1^_^ zWUP13#N)br>1eL3HOsXFQ&XwyC^*ggN#avvz-vam&tXpXzQ?@xY@kz+p$+!AB+f_3 zAj(3HoLg=ZW=LPTD!H#*8asRvOI@R3)P^BgWcf78d@tmQ3y{GNZiOleu*KF426d}p zE~r~4PVsZF!8DC;LJT&Ei;+0q^YhddP={ATYJ-An5rst=C{bmN4gMI1cdouI&V$TX7FV*lW%e`ubTn*aa+ diff --git a/generated_examples/demo_widgets/choices_codeobj.pickle b/generated_examples/demo_widgets/choices_codeobj.pickle index 9316d32808a83f9efc197cdaf7a18a483357397c..4edbd7d0e752a52dc1d3c18e0f784602a217ecf1 100644 GIT binary patch literal 5280 zcmdT|&ubGw6t2*wNz*hILlr?$1c@LKDng+kVzlC+R9d7bT{fGsGt2Hqv%6Lbg5DJN zAh<;kym|BH&6_v>0k7T#?}8xco89b8W-|LDDFw|fyYGA7yl=jF^O9#X`}>Wl=o3_p zo@F7!BR$6rgX%`Vi~6X0gBV`;I=rwMHiKE+)sW-c;k~f=6uwV8x{V-o&37W$EuVxz z$?kQ13m%`g^&MjD_@uQVQ^HA4}&ssHN( zA)Xbva76*aRn@~P1G!L1?1VDgA+SNY;}gpxU|iV6%M_&trFGOL%&f41$pad%X|_%r zO{4KExb|XTuj!lA-ViVy`5a!Z(w8WRU&OwLRHJd%vXZppIx4Um%bx!bP6x{*93CM4 zr(Ja?u46t{wzaK$sLwVeP2Rilb}S}cpxtvk&^|)aHUe^1_%o28@JUE^O@s^Q;6C4$ zIwRSR`VrmcW^(#jkLu_yf=*>5i`3#}gHM7bb#RzXk&2o$p-LW1vKJv}V)58x*P-0Q z*CmbSK-#1wRqC^wU$dam9*?iD`<~vh&=z{+Bga70H}#>rvZZ$nYLC%ptgWb02-ht% zn&+Ic#0@&y4h9D0wp7&1h=(#|Xk9RaB20bPCg*a9T@d#bFLhDd=o17DfsP&P+yL@b>~`3p)MafD?-O;jpyI z!Y=}MT5qB&GDn8%Bv1r1ILs9G{* zu+kM)Gf(AUB%7IMg!nq2GBR1t<)UPs^CE)J37I?>a#1qRMFCMuri@IMOF0;sV_Arw zi>8cBf-6}7Is1wbthn-2+rF9yl3A_}04U&=V}EIsY~&F+@I%zVF}-}g5=`5RQ7So;mci=LS`?!q%b_^ZU^h{BK%Ba_3zi=#lmwy#dVIo0$~Oc= zwo_}svi217Ow6nsO{YNsU$^#O=VeE_0Tl3kOUeYGf6p&_@HWIeKkEYM4pDb`ha01{kz z*`>;DXw0wi+(po53l^e8-Qt3h6J= z{g_^N#X6RY#WB4BrWo6b=`Ejrh=~%t!~Yf@iV|C5V{!`Jh3YCLgXw(`qe_CkRa8tL zx@IG$vmhQRTQGg%io~=E*Lw>3uo`ELDny^V1`c=uVnoei`VzzgHI3;j5HL3H$k(pP z68eT;A+NT93? zsvW{=b|thAC|AEjabhaVl~zF`X4OBRC1#DMM+JV)Ghsb3>pZd`>;SSLRI`?_Ow6=L z4~97%52uN_*(0-I-Z>kt@^Z}{)go;`bCINAw!6fi(nN&+$>T^$F!wC;?Lj_atKl!m CY!9vg diff --git a/generated_examples/demo_widgets/directory_dialog/index.html b/generated_examples/demo_widgets/directory_dialog/index.html index 0282bca52..429431e46 100644 --- a/generated_examples/demo_widgets/directory_dialog/index.html +++ b/generated_examples/demo_widgets/directory_dialog/index.html @@ -2940,7 +2940,7 @@

Directory dialog widgetdirectorypicker.directory.changed.connect(print) directorypicker.show(run=True) -

Total running time of the script: ( 0 minutes 0.042 seconds)

+

Total running time of the script: ( 0 minutes 0.054 seconds)

Download Python source code: directory_dialog.py

diff --git a/generated_examples/demo_widgets/directory_dialog_codeobj.pickle b/generated_examples/demo_widgets/directory_dialog_codeobj.pickle index 6764e9ad01a242de33ccb5defa5dfdbbd56dfde2..232a82c6e9738a7f2a16ac44e31f14f3c0a93c61 100644 GIT binary patch delta 74 zcmV-Q0JZGll=-ClimtO0iBa2 g3m*ZXlVJ%l0i~0Z2_ylilf4L|2(f4liFIXlF8K=@g#Z8m delta 66 zcmV-I0KNar7R(l~!w8e73Y`InlS&FP0gaP<3M2uLlf4L80hyCc2^W(t2|@v&lW_@F Y0jHD531I=QlPU@y2(f4liFIXlE*W$duK)l5 diff --git a/generated_examples/demo_widgets/file_dialog/index.html b/generated_examples/demo_widgets/file_dialog/index.html index 37dca6eab..ec9684f2b 100644 --- a/generated_examples/demo_widgets/file_dialog/index.html +++ b/generated_examples/demo_widgets/file_dialog/index.html @@ -2921,7 +2921,7 @@

File dialog widgetfilepicker.filename.changed.connect(print) filepicker.show(run=True) -

Total running time of the script: ( 0 minutes 0.042 seconds)

+

Total running time of the script: ( 0 minutes 0.035 seconds)

Download Python source code: file_dialog.py

diff --git a/generated_examples/demo_widgets/file_dialog_codeobj.pickle b/generated_examples/demo_widgets/file_dialog_codeobj.pickle index 532f3fdabfa3f9a12fbbb5f519084106f08aa1b0..9e9c8c2dc8196b485bc1d81997517364e3bbdede 100644 GIT binary patch delta 60 zcmV-C0K@;m7Qq&oc2I0X4CmyRT-uDilSR2z7$-~)?*IS* diff --git a/generated_examples/demo_widgets/files_dialog/index.html b/generated_examples/demo_widgets/files_dialog/index.html index 522308a38..5967fa3b7 100644 --- a/generated_examples/demo_widgets/files_dialog/index.html +++ b/generated_examples/demo_widgets/files_dialog/index.html @@ -2943,7 +2943,7 @@

File dialog widgetfilespicker.filenames.changed.connect(print) filespicker.show(run=True) -

Total running time of the script: ( 0 minutes 0.053 seconds)

+

Total running time of the script: ( 0 minutes 0.032 seconds)

Download Python source code: files_dialog.py

diff --git a/generated_examples/demo_widgets/files_dialog_codeobj.pickle b/generated_examples/demo_widgets/files_dialog_codeobj.pickle index eace182f7813f5976f9aca1a4e88576ce6e26916..9323fc236fb33273f1fee268231997b04d6ff3c0 100644 GIT binary patch delta 727 zcmXw1OK1~87-sV~`(B7PDs8M`tJ}sHBNdBLDF($JJlIkwl!}&ZvdwOrZ9+F`5PVfH zRTgZWMeraBoGsnK~cQw#p1rl&_e%x1g)eN$iT7jQ(&6-oGwVh(e zsn)EP7x<#%%~a~9=LPHycZt)m_OW?EqqMCtJ#i6^p2)Df35_yv))GhP5HL$R`<@s@ zG)t4wsM~{1s_Z5tdvaCNW_Pz47{Jb zB5M!Yn9vq{g$+@jjq=@S(!-arPV)whAx#wyvktfSv5;gRc$Fq%>kpry$%vO|D)z#; zu7bZ7dZXR0M?6m^P!SJCUNzzcssY{Dn~!*bT;Nx6x3(GaJbA#s;xSqV=A=Qo0Ss@< zmC|%G=Fg=R-2s0mox#DgN*}F4sq(O)t;X|-<7UggV0u?;< o|9>j}jd&~GwOV$g8crh4ww-#*S@gnDe%jjl?SAoBRM;;519C*v!vFvP delta 676 zcmXw%O=uHA7>3z=`;+WWYS4tFjfJK)%@S%F#e#|UBuHy9)T4(|V-hn9Nfx?UfA9wc zL9Hva&R%+|2gO@J@MJITNl$v~O~i8#J@+8^ZnB=<=XvLwnPu3c>``{Bv>NT!+g79P zTK<}EKJ`sc?$x_3-&4D-KDV0z*iE;CCVJPkI(@6>_#PW|>khX!`aajasO79TI(5hK z#X)?UPH`rVSyy6WEk3ViID753w$G1?h?Ef@DOJt;dXKqk$h*^$oCJaS)Zduzz@A*gK2OeIUsjAMXF}VJBt=b0h8CP~2h*$S zj2I|0)ChSwG9mMOp;VQm%&no6StocByf)XoxG2kcva#?*Ez$<^k6I>om}f;xbRL9UGTnCYz>1*iCj7w#jCdU!1*i#cjQ!27ioO F`Ui^N!Po!* diff --git a/generated_examples/demo_widgets/image/index.html b/generated_examples/demo_widgets/image/index.html index 542a99c8e..0529cb57f 100644 --- a/generated_examples/demo_widgets/image/index.html +++ b/generated_examples/demo_widgets/image/index.html @@ -2931,7 +2931,7 @@

Image widgetimage.scale_widget_to_image_size() image.show(run=True) -

Total running time of the script: ( 0 minutes 0.044 seconds)

+

Total running time of the script: ( 0 minutes 0.040 seconds)

Download Python source code: image.py

diff --git a/generated_examples/demo_widgets/image_codeobj.pickle b/generated_examples/demo_widgets/image_codeobj.pickle index fd50f35542f208b3ed878febeb358d9d6a27752a..e9f1b654deb26c293dfa308f7c0c8259146b47db 100644 GIT binary patch delta 379 zcmaDU^-^kro+@i*Zen`sl-Ma6wNo^DSn?8cQ>XN>dV&Re*mCnzN^?@DOfKXQo>*Wy zc_NFrm_P<^XK88=7g(QOaYlYQNb|(`qLWuK8%|s*!zejlj5R$1>Rh zX)Q(-pr{U``s4{r%0RjEj7DJA8zx>x)5#Z^r6!9oKVfv4{F7Op(S5QciyEWXWEqZ~ zjKPyHa+*%|<UU5c#`IOix8nsh2dRX!jb5p1EaCyRICVB=<=3|s$6qtOM zQGT))<8el55Q~oks3J2ty)<)526u+sWP7GhjG91F8C61OvK5QeLog slider widgetslider.show(run=True) -

Total running time of the script: ( 0 minutes 0.037 seconds)

+

Total running time of the script: ( 0 minutes 0.031 seconds)

Download Python source code: log_slider.py

diff --git a/generated_examples/demo_widgets/log_slider_codeobj.pickle b/generated_examples/demo_widgets/log_slider_codeobj.pickle index b983f01a9196ac48ffad23fd186c941eba7d6705..6848f662c3a5f155a6b2f916bbcafa6b3e3bbf2e 100644 GIT binary patch delta 251 zcmX>kbVz7I!{k>S+Khse#W+>iL^60fOH(J-UuIOCJe^T?asgu?qsHVzjB1S9lLMKQ zC-X2}W;6q{tXX&&EjJ4?Gchu{OcrETp9~UkpWMizJUNF&gwYGgGG_Fh+`}q0`8>-L z#+b==Y^sxQvMMvigIOg^QcM|1K&BOADp+718!uzVkbVz7I!^G>C7$qmaW0ak|i%n$m1y9I?oy^1fk1=HO1vb^m25icV;b2xJ zn>1q-n6-;dlra{_GGa`a%*<}Um^|5pU57Dkaw5ACV5pH#pI0~l9T5E<*I=!O~yK~>p^N8!K_mp0&FcAJe{Sf6YF&t OJ14GD;phQ#OZ5P_7)@ya diff --git a/generated_examples/demo_widgets/login/index.html b/generated_examples/demo_widgets/login/index.html index 55106173c..ed742894e 100644 --- a/generated_examples/demo_widgets/login/index.html +++ b/generated_examples/demo_widgets/login/index.html @@ -2940,7 +2940,7 @@

Password loginlogin.show(run=True) -

Total running time of the script: ( 0 minutes 0.048 seconds)

+

Total running time of the script: ( 0 minutes 0.040 seconds)

Download Python source code: login.py

diff --git a/generated_examples/demo_widgets/login_codeobj.pickle b/generated_examples/demo_widgets/login_codeobj.pickle index ce86a091168aebdbd344fc1a5eac8b0368188545..bccb812cb3471b13f0e4f00a3ebda2d8ef3c9453 100644 GIT binary patch delta 480 zcmXYt&r8B!9LAa7*KNqukY%NIFfBx75mW>ng2eD7b%-!9Gc`BZTsT)j6a;|;J2c*% zJ9i5FLxk@A0iFB$w}^{>JO_lLZXmSC7S0doJ3Ww06BD&%fklhB$TD!+!4lZfM*R}zYwsBs;Q{qeD8UocC3f{^Jf(W@8 z|6gBrb|#%P8%7K6G5LMu{r2T$zTNpf*toU)$$%7T3Pi9X=Sl{%GKLc3=ZpyTOYP6q zL~f=_zGNO&tlpP{tca@=_x7?VVI;wgGZrTx_%!^m zLWj7jS&34vJhv zEQhkL@Lvoa8Xda_#%}8n(29}PY#=U9Sf1!p?HSm(J=N=Fx-ERtl+nh%h&W*Qq$wk; z{|^+DJ8rP*;j@-{Bh~9ofMxIZI8G~nOYo|*D@!db}xXN(@fN9?>AwK!Q`j;9F()3dOA%dR-gA4>MVujabxTshv WRu|*D(Kjp&YTi73dwwistLY!(c5Oib diff --git a/generated_examples/demo_widgets/mg_execution_times/index.html b/generated_examples/demo_widgets/mg_execution_times/index.html index aa7467672..1f0701d8c 100644 --- a/generated_examples/demo_widgets/mg_execution_times/index.html +++ b/generated_examples/demo_widgets/mg_execution_times/index.html @@ -2885,31 +2885,31 @@

Computation times#

-

00:00.531 total execution time for generated_examples_demo_widgets files:

+

00:00.498 total execution time for generated_examples_demo_widgets files:

+--------------------------------------------------------------------------------------------+-----------+--------+ -| range_slider (docs/examples/demo_widgets/range_slider.py) | 00:00.061 | 0.0 MB | +| directory_dialog (docs/examples/demo_widgets/directory_dialog.py) | 00:00.054 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ -| files_dialog (docs/examples/demo_widgets/files_dialog.py) | 00:00.053 | 0.0 MB | +| change_label (docs/examples/demo_widgets/change_label.py) | 00:00.049 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ -| login (docs/examples/demo_widgets/login.py) | 00:00.048 | 0.0 MB | +| selection (docs/examples/demo_widgets/selection.py) | 00:00.048 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ -| image (docs/examples/demo_widgets/image.py) | 00:00.044 | 0.0 MB | +| range_slider (docs/examples/demo_widgets/range_slider.py) | 00:00.048 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ -| optional (docs/examples/demo_widgets/optional.py) | 00:00.043 | 0.0 MB | -+--------------------------------------------------------------------------------------------+-----------+--------+ -| table (docs/examples/demo_widgets/table.py) | 00:00.042 | 0.0 MB | +| table (docs/examples/demo_widgets/table.py) | 00:00.045 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | choices (docs/examples/demo_widgets/choices.py) | 00:00.042 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ -| file_dialog (docs/examples/demo_widgets/file_dialog.py) | 00:00.042 | 0.0 MB | +| login (docs/examples/demo_widgets/login.py) | 00:00.040 | 0.0 MB | ++--------------------------------------------------------------------------------------------+-----------+--------+ +| image (docs/examples/demo_widgets/image.py) | 00:00.040 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ -| directory_dialog (docs/examples/demo_widgets/directory_dialog.py) | 00:00.042 | 0.0 MB | +| file_dialog (docs/examples/demo_widgets/file_dialog.py) | 00:00.035 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ -| selection (docs/examples/demo_widgets/selection.py) | 00:00.040 | 0.0 MB | +| optional (docs/examples/demo_widgets/optional.py) | 00:00.034 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ -| change_label (docs/examples/demo_widgets/change_label.py) | 00:00.037 | 0.0 MB | +| files_dialog (docs/examples/demo_widgets/files_dialog.py) | 00:00.032 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ -| log_slider (docs/examples/demo_widgets/log_slider.py) | 00:00.037 | 0.0 MB | +| log_slider (docs/examples/demo_widgets/log_slider.py) | 00:00.031 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+

diff --git a/generated_examples/demo_widgets/optional/index.html b/generated_examples/demo_widgets/optional/index.html index 9a07605f1..837141599 100644 --- a/generated_examples/demo_widgets/optional/index.html +++ b/generated_examples/demo_widgets/optional/index.html @@ -2938,7 +2938,7 @@

Optional user choicef.show(run=True) -

Total running time of the script: ( 0 minutes 0.043 seconds)

+

Total running time of the script: ( 0 minutes 0.034 seconds)

Download Python source code: optional.py

diff --git a/generated_examples/demo_widgets/optional_codeobj.pickle b/generated_examples/demo_widgets/optional_codeobj.pickle index 7b2559c879eddc9439e288095fb1d35dae948a17..75b5dff7bc4e8407b687a2456230b4ae2398ea53 100644 GIT binary patch delta 238 zcmaDR^h{{N%1Ml88D%CLa>`DA%^1k2JlU2>jZtm#87Ae)?M#;$4Z*BBW?n{<$^9(q zKr#QxF)Xr^?SUdDj82pPuqaP{&LYC-3S=2GdQ3K8{l^$SS)a{=F$zekPM*sq z%@_-2-D4AFOaQYa*?Ae0Cr7Z$fOVz;SvriFlXtMof%!Q=mL6mNWGM~^zX-_EV=SFq z#Q{-Y0c7bgR!?5eq03k|`6`DdV2$2PFBOoM;R3uwI@GgRAbbe%**tR z(Go~1PmX8dWwe>RkXe1Q0h9ma)yzGN?qD8B+-q_!i#ek&kW`*5%PzneFnI&3)a1`B zPZ;ATE3&Ch{>!S&m;_`wFs6d}ovb2E85v;aDOO&_?8%JmGLt8;h%n{>Svrh`lM~tH zCi}39FqQyWdW_|hC$JkaRsl)5$tPF@7;7hgVmDxHn5@j9!`M7IfJ2wD4M<9Y;bcY>N)x|csff{OZ5PJCrFb3 diff --git a/generated_examples/demo_widgets/range_slider/index.html b/generated_examples/demo_widgets/range_slider/index.html index 9ef05d3b1..0908719cd 100644 --- a/generated_examples/demo_widgets/range_slider/index.html +++ b/generated_examples/demo_widgets/range_slider/index.html @@ -2935,7 +2935,7 @@

Range slider widgetfunc.show(run=True) -

Total running time of the script: ( 0 minutes 0.061 seconds)

+

Total running time of the script: ( 0 minutes 0.048 seconds)

Download Python source code: range_slider.py

diff --git a/generated_examples/demo_widgets/range_slider_codeobj.pickle b/generated_examples/demo_widgets/range_slider_codeobj.pickle index fac01677ce0c66da59c6b4e40f949f8ea2925933..8673552c77e17b63dc846d333cc93f9a7b22c162 100644 GIT binary patch delta 527 zcmXw$OH0E*6opCdq={%CXhgAEsLxuoD6|L#!IiF55ClPd)HY@!O)Dl*1RoUyQL?Da zY`PJDNtc2v|3LqMD_3rdH|e-K-?``9WSD6VHV2!zeBWtME9X2~zv2fxbIUU!sg+!d zhsHVvzEiJl1Wqpx6K=f{R4xAcm0k=7dgcgMFMO=KCEF?6*u8Qpw&i;~)Ew`qTrGJX zXPeRldr>lyj+6zH>Z~m##iT7|Ac>Q2X&O?fhHPWckkhOs=LP-9!!RFbX?9F>SU~Q= z3_E~zY(&)ScA*F>B8z%O^kZ?b;$=(!GxabSp z*nUq;v92-&JAzyC7@@nuyeKB2d$Cy>*r)n)fR{+sP-hJ?1BVz8H47!wWpxQEv5vC_ z9>hjwI6FiAP#3^O{Z(^tjykJl!9#t}M%bBV!ez{JaE%&WT{OE9{7H<$ee`21)c#*V lJSLta;aWbeS2*npwUfZ9`cBQ`w4Xjw{q=5Adx{r>+#mM-qmlps delta 500 zcmXYuJxjw-6oyGolBSZXl!_m%LyWbhEs=tVxClyHHx(2?EVZT|38oD+2@0Yhh$3XD z-mJPh3I33RyIU8h4*mcKPj0i^=Q-~==iWg2@qWCo?u(sz+tAvs;aC0aji2?nZoSj= zJ)zTdbgL1F)o@Kr#B(y&-L`%5BQ9m8bm_@$deN5K z)l?k13@_Is-gFr=$FRB;*C20vGFA(Qf}n;ULH3wgMtc4%1;-+ZaxqBh5>c2PMj~w{ z3kp^*%rdMXWmYENOc^^edqhu}3}6O|VK3NTLm#pi*d4NIGUAe?%Fc&XFuO(jY5LMO z`T-}CO)dc?>P6T^p7L|#m0QQHz($-J+5i%y!Y62zhGU$Z6cqB#D{vC}FQ0@e^$j=+ zGgF9xhW;Te(3e`&b6_B2krd5L>IJZnR+#mu7r;e+MaH{V)N^o+{EOt_7MT+>aECk; QSK%J{Am+tK`afLtA6osAumAu6 diff --git a/generated_examples/demo_widgets/selection/index.html b/generated_examples/demo_widgets/selection/index.html index 53650e07a..948c11b2d 100644 --- a/generated_examples/demo_widgets/selection/index.html +++ b/generated_examples/demo_widgets/selection/index.html @@ -2940,7 +2940,7 @@

Multiple selection widgetmy_widget.show(run=True) -

Total running time of the script: ( 0 minutes 0.040 seconds)

+

Total running time of the script: ( 0 minutes 0.048 seconds)

Download Python source code: selection.py

diff --git a/generated_examples/demo_widgets/table/index.html b/generated_examples/demo_widgets/table/index.html index 2ab9fc609..bbe743f08 100644 --- a/generated_examples/demo_widgets/table/index.html +++ b/generated_examples/demo_widgets/table/index.html @@ -2921,7 +2921,7 @@

Table widgettable

Out:

-
Table(shape=(6, 3) at 0x113157cb0)
+
Table(shape=(6, 3) at 0x11793fe00)
 


-

Total running time of the script: ( 0 minutes 0.042 seconds)

+

Total running time of the script: ( 0 minutes 0.045 seconds)

Download Python source code: table.py

diff --git a/generated_examples/demo_widgets/table_codeobj.pickle b/generated_examples/demo_widgets/table_codeobj.pickle index 0dbf19a56864e446bb0e658529dc320907db9acc..3f94246448b95e9c29553e3559c5c1dd39f8464a 100644 GIT binary patch delta 2749 zcmYk8dvH|M9mhGpdvB6Wc9TuAn`E<(B>PBqv)N6ud6H!FAP`{akjCn0LxE)Eak&kU zK(Ra`kB+TIDK&f}2qSHjk)mb7w4(#IqP3$_Tf~ZDEm8&gP(lS^N^9#>={fhzHvQ}O z`TX|$e!p|?IoZvzz3ipEOx>wHRyVFz7FpH}#|JkIu3NowV(CQq{)zBzb=~0Fl@qvL z;vMfzAW&LNdJYccG^9Cn>)572EG--(-HR`466v~Mrfw8IM|w4CT|R`}VbT*Op7QY0 z2962Ro6XGQMOM;VanV(VlP*8$?HpT4??Op&1CFXzOuGuPwb+XHIbSF)gwKywCic1x=iEf*2Tb4t>FAm5f&!^Z34SzjP<4AK-)t}X^<2!!IPT)yaiUIZ;_A8U#RBh}v+)NZ>168rtO?rWX?6gV$ zA|HFxq%JC8XR%WW;G2qro#Rx;-ovmOSQt6GetI>i2DW<<}w!lrr5wO2S*vA^N6 z=EgR1;kd&>`gK#2DnHPhCZ5)u>=vgm`wW?BrR;M=(<;~($ZjgYp)?Ecl&=`G7_3c2 z+>10rVY6o8L|RNU(gb~!7SRlgpxpEt&9F-HVjw+7GjfEDq}OUjo+KY48qYh0y_0@k zGyH-&E#>IX3Ts9vWm8$jnh}=Pq8ZUtelo+V8F68|G9x%+bs<)lsn(_vW?6m8dTkEP zXp+{T87+cNX0~ZYQc?sZS$s2{!fLYa(2QU z#vk(zK{u^sd~1HqxJz2AX55p?o4uB#%|XpG^**;i;n zgfd)gx6yuvuGSzttpPeHu!9cC%#l_nO-h_@vC(0M8?DWBM1&v~x7q0#hJm(Q^qdGG zv)2iRQ%Ns=oOIC71;*$UJN!wK(Hjic+so*847nX)dYfUSqZCUz9Q3Zh8u|mn;f`v$ zz;Lc3N*^+?&IDZ+!H4&gcKQp$nd(A}c6#XJ6lRD|ELZ>cc;|9n)r`-?vwtJkj~DIy zl6{`C(R{c1MM@Uh`DK|!=E69?<$`wS&gZvWQV3$XB_-{7PJAzvjeWUpjON)Whww;V zE9Hq$flu@71M+wMWar(kyC>1BYtH(7>{~ri^S8>A{r%rZM=A^N>1G|qr3-wXGX>3 z@21qr9)c_8!-1%SJ;Eu@_FydL#mZQKjdN;d6Q=Vb?5pO77PCX_^&m>)emX?_{yFjW zcs@-Mzj#G>F`j`vaR(hvX%RbucjGne8KhNL(J_8@odwulogpUD@st*^pW%(_Qga*6 zbE;8KitF<21<%rJgwvhJ=xxH5uJiPP2p$a2vC$<$Uv~+9IALgN2YW ze}GkC&HPnVr{L`T)zqS(WkELru72n(gv9k zBQ`1M4ON(>n*}z}HU$rb7SeVR$|0(DNfZMgkSHo2I3p`s$2Wu(i>t{`&tDml8Jmt%6Sz3+RjpAuOwN z(_0cJ>zwqC#6Q;A)ZdH3ok}r!>n*U?-$NfL__DrSjHF8vI~(2fXMwHsk<5qz(+Y+g z*3%6Imm50i?;?01mi|*B-xd8^!FXdO{YSy6MnAiaOI%3hKlKfyiBN{hW;+9rz$!Ic<(tY)ci@vIubMj}7O`G+h{Q;`6JKlgs)Z>TYj$N7b1`4xrucsW8{Z>h delta 2791 zcmYL~dvH`&9mhGpyEn-u+3W^3k9}pcyV+!Slk6^8LI`;fNFcmPWpt<(Vt~NSZ5|X7 zDkCurQ)+maG<>7jR8-o*ktsuqR*~|m15-p(v7KQCgaK(qs?Z=>A5gWPb8fc%=YBum z-~Bz#J$v`uv-{c6{misO{kCt!6e-N??AX%V+Owfm=;-Rv{?X7rQ+Hce`{+KC2#u^w zz?y!RIq*bd9xi8?F_C_W6-~NaR)VZ1=l;wx7BRq#mP{8bPnzM(92QTSJyr`#Aj=ZK zqf9%S$tl6AF*4tU)t2AyH)Y_Z`Pm%Jcq+?+825*>rpnaCcqyxlEklph1#_kY=W@-Y zwMe@n!%5moiBDQ{*q1nk*pv9KwU9l9lhzW}irdx-($;eE;zX8>wWHtWlx;OmVbY$) zA8Z~O=;l;L+B3+`o=#dXmjYSxEVgA|Bkegnm|BefsUgz7De-qx`S3j)XOs3V8ChDL zN!kmTV-I6!nx8aClzHEg_-VGCv==#6lJ-5k$@7*vrjhmojlbdsb+Zxi|ge8v;IwNn&%D1pBFG$*XypqSC z^lfD42aP_LIL;t#9EQ0)5P$4$S-r61y-0Bvnf-=KDCeB-<__nOgg;I-ca?ga*JbB zfM1(Js=m%}vs8UUGCq)ESM`phJC>5E>Yc(dlMfw=U)6h(?wI0K_036lPvLcahAUU~ zuL+8qwyOGoAYJtv6L%)vIPvOTNhhZc8ZN5pdj*ZDyw8w9P8={O=+cyev097!>_oLj3&GQujI6_H}gjc67IH=<8nB+tJhA+OxT}tG!q2SwE_o_oYqV z-ZH9X=;M=}jLMYBRy<4X?(5pLO{84@Y?!^bZEa_J6gy^JqZ0UjHt+c$grxWhCXJvRue_M!A}1YSWk}` z&eg``g#Q|NquNDNh)0`95fX!#kV4o|S0XFT0;?#KaI$U@S%nlsR82Kd%*!!QROWN6 zFC`b@PxTd4Kyc2fCm-RHfPF!dTIyn7m~6TY=~sx`(;t4%ZTXQ1y)|cHt}nLtl9!w)Po)6 z0k&0=n6yojSkZP)5jKFDsGse`nrN8q!r7<~N1}E%$Z0y;3t!BQ%$S`GaVldYSRPBT zQGWFzHEv@Ea5q*c^T#;F%?D}n<;0OR{zAXZEz-;fRQ**!{QXt+V}hP#73um z>Hi}vZ}u~WXPP4>lfobAwlx>`o6R`eY&WHT9&k{)g6f5CJipLR7J+4CQ*hIki~fZk znwCT}PA#-it^#Xz9{$MhI1F?ya+utr-MG0<)qR4lq)kuPi#ZvetwWBJlu!_lIMC`! zL%;JP)hBHZ%~fza;)dIuhA~%wnm)H1Jx)b$PI?b5PGTBb-4W z*c+nl3Lbb1W$J*yIPFy6D~!=DAue0u9r~@1LUdMGOz(=6xs|y*WeK|qt@0!9UAgmvea5k=%$?ULPFAID?K*K{{sp}= zi`Ykaai(tiSQIx@+2N{M#6CfL)dnIH-l^J{YBq^qZxEgFT6p6>%5X~0Kdybz{{!D3 BL+$_o diff --git a/generated_examples/generated_examples_jupyter.zip b/generated_examples/generated_examples_jupyter.zip index d1adc46d125d65f27e05e5a36a24cdac1e1c6a0f..50428d35c9051eb8845a4ab7cd3273009f7e296f 100644 GIT binary patch delta 549 zcmXYsO(+Cm7{@)s?Ch*1`B)CLdqLV=vm%F8Xm@63W=B~U+QXKOiwg(Jx=2YVxi}2= z;On69wuec3al&;=q+ApSMHKCgDDU&m&gJ*~{{N?WX0qFScAIx6jPi>5GJO2xz|C`h zVpa3MRY-STEpuPfivwNo?g+@kHm`#V5bG*X6w&j&zXJMs{|S#w%O2J*#5Wj)kr_AU znbZaAdncM$o|rmj{ylvwVqeINGnW>-87G(589&z!8Mij8TX65_)aB$t#L8K^kCTY? zbN3~3L1KM84!XE5Vs*aGv{L5xsvzgYA>n~a5r>o)8dx&d4(~iB=^%iB!(d>BIl!^BQK*g4-m6Pw)3P63i>`e<(mw{$glzia#f-4 zqbw+(Asb`1r($-05`!4##gY%GcE6(1do;gMA&zX;>^l=0y%QqlnMUtO#Qf7}A0(!( l)9>mcrm53Al+PuX;&hMtQXEE+4<+v~?7dmT?yn6P`v)N5w8{Vg delta 549 zcmbO|gLU={R-OQFW)=|!5U5(ckcXA2YV~G5)<3);nnzd&%vX?j%EnZ^dNaHHOm>j? zA~kt1|FF&{PLTL^vp?)0daKkTD5X#s00;&V@8@w39K=chLU(*|+uGkwQf5e+H8~{4J$kYG; diff --git a/generated_examples/generated_examples_python.zip b/generated_examples/generated_examples_python.zip index bbcc0ef34f6eda3333736f4ca3146e8b75ae2ba1..de7cb1983d87cce0b21e1f86ba896f2f9adc0a70 100644 GIT binary patch delta 529 zcmeC^V(#c-<_Yj-W)Wck0j;$gdBhl*wAXG{VO+ooqK|Ri1M`>h9Ag6U^Z2JQ^J=dx zk9>7rR`xq11H<>p7r8_x8|)R>Y%I(OR$?Z4m=&b-x6}(}CY`mLpUQ1v1ktk<tDTN~~G^S>H3vx4NSEQ-PW_m;t6+QoVbn7(DR9!z)J zT@?qZOA6y;VbWi_IX5asnn`!<=F_FG!1}jWTe2}3tlj*najF87;o8lei+-?x=;q~Y ztRT93jWn3QV#9Yv5P#t&K4uWTaqCksf5vux7ACE=lUMGx0eWll^WBahN^6fNh$`LV z0-|>BaRX7zd%=Q!d%=QJ_BsLGHTedR2c+co`GBaLeI6ic+dfAS^>d#qh;rBu<~8pJ z%bnft3=$MN0OrLU0L#rk;06+We!v|>85{%~U2@O`=;O(|4*CE+JelJVST698C(yf- n=Nxhc`eO29AP-3C9rgiHHHU*i)I|tS{s>q}+7YnamLnkmfZfbG delta 529 zcmeC^V(#c-<_Yj-W)Wckfy&hzdBhl*s#b4SVO+ooqK|Ri1M`>h9Ag6U^Z2JQ^H!}c zk9>7rR`xq11H<>p7r8_x8|)R>Y%I*k#8ka{vzh2&RuKJL>IE~1ek!+x5k${ckORx_ zR+%V03=Vm$>+-?CZH$W*g> zbGO}9agaGlVVo>X4XZcjM#V^j#7~#LVg=FLt1a1>8dq=r)HqdvscH4*&P6|1Ky>qR zHdYYby+#_$U$NmkBZ$9n6CX2(-njKCm_K7XKMPak>d7m2+WjB2f;>{9CQKtc=E1;J|IDkLtweUL!LnI pPM&kf73hn}kAXZOrFYl|MAaM)22mFwJozJFC22>%a$Ams004$0;6MNX diff --git a/generated_examples/images/mkd_glr_basic_widgets_demo_001.png b/generated_examples/images/mkd_glr_basic_widgets_demo_001.png index f2deff8dd725dc8cee9c51b94234f709e8c38d07..156cad176ab9705bf02bcbb049fd675a8e8ef33a 100644 GIT binary patch delta 12118 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ℜ{f$Ax$yo@g|GRfrQNa-rL|zH!b34EXp>O{a;&9s*wk1E1 zbff!Um?c-O%!URDV?~h92O2;(gjpGwnVZJg`S=lEPY=<9q|K>`@_`wipBOX?V~(h5 zo+h+oHeRd9o8dA6fq`CoYm{CGLCCSFfx$#m(?WYR5AeEiP@FJT!cP|2ZUXQ1aDP7x zc0)wO$IE;9%9TF@A1-a2JuY^B=Q~!%2B(^wl!PZ@#GwVc2)HJ&R_JCh0r&Yn@~jR9 zJ2t;r&NzS%4*GqS> z+wh`}YAL6QUmrEJ95P-3%}XTh#dj?}wAsrmEih&IZ}<9tNhtmfWB%*c{Lj#x3R7+y TSPS@|!IBnN5X%*L`sP0XoBnh7 diff --git a/generated_examples/images/thumb/mkd_glr_basic_widgets_demo_thumb.png b/generated_examples/images/thumb/mkd_glr_basic_widgets_demo_thumb.png index 6a825d1992b0acc0792c65ecdb7b618ce1e566ec..2d360d27db67ba749f7a6d194fb2826ea302065b 100644 GIT binary patch literal 25507 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 literal 25565 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 diff --git a/generated_examples/matplotlib/mg_execution_times/index.html b/generated_examples/matplotlib/mg_execution_times/index.html index 8d4a3ce53..6a588feed 100644 --- a/generated_examples/matplotlib/mg_execution_times/index.html +++ b/generated_examples/matplotlib/mg_execution_times/index.html @@ -2885,11 +2885,11 @@

Computation times#

-

00:00.269 total execution time for generated_examples_matplotlib files:

+

00:00.252 total execution time for generated_examples_matplotlib files:

+------------------------------------------------------------------------+-----------+--------+ -| waveform (docs/examples/matplotlib/waveform.py) | 00:00.163 | 0.0 MB | +| waveform (docs/examples/matplotlib/waveform.py) | 00:00.155 | 0.0 MB | +------------------------------------------------------------------------+-----------+--------+ -| mpl_figure (docs/examples/matplotlib/mpl_figure.py) | 00:00.106 | 0.0 MB | +| mpl_figure (docs/examples/matplotlib/mpl_figure.py) | 00:00.097 | 0.0 MB | +------------------------------------------------------------------------+-----------+--------+

diff --git a/generated_examples/matplotlib/mpl_figure/index.html b/generated_examples/matplotlib/mpl_figure/index.html index d702f380a..683fc0ffb 100644 --- a/generated_examples/matplotlib/mpl_figure/index.html +++ b/generated_examples/matplotlib/mpl_figure/index.html @@ -2954,7 +2954,7 @@

matplotlib figure examplef.show(run=True)

-

Total running time of the script: ( 0 minutes 0.106 seconds)

+

Total running time of the script: ( 0 minutes 0.097 seconds)

Download Python source code: mpl_figure.py

diff --git a/generated_examples/matplotlib/mpl_figure_codeobj.pickle b/generated_examples/matplotlib/mpl_figure_codeobj.pickle index dd67b710ccf9058755158e4fccedfac4459f901e..06100b7b6b364a64fab41be67ffb69027143ef5c 100644 GIT binary patch delta 1178 zcmYL|U2GIp6vsKYJMB()r?cB`zxI1}Y1!@KZXxBfDG`IA6rpG&A*RrbvO1maw$rnIa-O$RAMFDn4V2naE>+0rP}QH z@j`~HvmQ+?IoH&1&KQ3xUx8NBI{h^jxljWtJxo-lz#--p+Gf0E;yd^5NT> z7zMFp>%b9d5Z7%!%-OOOx17&v6xz6$lI%p=kdopM#!iga?w~#%JMd+#i|$2togb^U zztSK!**8G3N9iF>_t9ZX&)b`^YIERtesQXl<*B5Cv^E;~o*7pQE4ZXpur ztTX;Hl-Yt_{-cvt&_;gx2UAV6B!N8J$WGG+uzKp$JZdW^A#$A{16BfmFCmo3Rw$Oj~#iVpOZA?FeWo>cs&q zM!WE)7R4)?i*|FmhwUNU&=PE~NCBsGsQ6%hEB`*`03j9G#14oQZTR0mB(_^tdN!Dc ztHtV$DCw7EB3$cI3=00f(|;jN@i(|H0*LVgv}SL z3(_T~PgidbKcH>*bXuIQJlKY>BEjVvAq5>1I%3O-PRpdeOl4OD5We<-#R1fkGUtM^XgKj-|u@1A=v z=RTIVoZn*GFU{RIYim|ne%#z;rl-tw$u^W9>^Doc&hh@DS*jQuer&AJZ^EyHHk4dz zYIji|eqz)tc?a{OBZcA7!oZ{1yjAWPDDK`<$QO$y?ol4H>$2{CZmb{YybbZNK)!)) zFO}~ZE}D8}Ng5g(9GNh6ryfP0XEUid;ZZ4tV@ey-n{Zy~!X~d#(QYj=n+eT+qF`AH zU|S>u2i4+!x{c=)ZN@oAf~yCq2X9cCw&Dn@$0{vjUxgEMEP|`djSo1Nm*1ktah){@ zhX&AL>!1RU^*G}2(J*e0{x916EH{d1mFtcE;HU&5E3z4Q%gJ-tY$G`oIL%*x|yt%d0; zxS?rG{}qij{6v38UrmDPSB_SGNPlCpGKmY7Ub=>-tKw)2bfc%LjsD?kgJhIZSsCW5 zOv$jXQ4D=fk7QH{HR3!d8Gb=IR}Gx5F3AW9wcWKtG7^GTToHWX>XeKIp(OVMl93TK z?T#Yi)?m6LlF=rd)9wNk-$Clcao;BD;;{}hKCi7?3`emIC56FG2+Xl} z2?N|wG?~38FvsQz-`2&gngxMbwn)fn5v%4Sfi3K;Xlx__8qFc@rMl1MR^ zv~6PhXgmM5hJ)c6FPsi~m{VYec^IClIm03hchz>VxJU`i)yhm|I8~cvDF$ySij(0Q P)+n&W+053v9?Sj*qTOga diff --git a/generated_examples/matplotlib/waveform/index.html b/generated_examples/matplotlib/waveform/index.html index 333bf1bc8..3c67a6640 100644 --- a/generated_examples/matplotlib/waveform/index.html +++ b/generated_examples/matplotlib/waveform/index.html @@ -3155,7 +3155,7 @@

Waveforms examplewaveform = WaveForm() waveform.show(run=True) -

Total running time of the script: ( 0 minutes 0.163 seconds)

+

Total running time of the script: ( 0 minutes 0.155 seconds)

Download Python source code: waveform.py

diff --git a/generated_examples/matplotlib/waveform_codeobj.pickle b/generated_examples/matplotlib/waveform_codeobj.pickle index ec6829643f4b025b387b4d3f100ff07d56764834..ff68d8aa8d672d9a1eb65b19601b33960031fbec 100644 GIT binary patch delta 1250 zcmY+DZA_b06vuaNdi&l|Xe%9k0ZJK^mlcLvGcuekEE3C*%_-U9GCF8?xzZMq4l#o* zCMLu5gXCZ1Vl>eYGnt8ug{X1K6kie(baNV$#l`7}$qXBD;fqf9LGM#uj9>2a`~S~5 zH#g@w=Zn}kG2LnY+Go?cI=}wO#89GtG=C&tJCU!=>C*93BA;7xr@NccV=L1a3G10` z0wdMcOt|o7wU>!fxGfRAPgtk2@#!0lR0$*bDFj#1921RrwWtEiMRq2d@K4cMCZg&S zz$J%rT5-jZXQEww{0?&}J~}*<866rtmKPS$f#u?Id{8{VL=1tF!%Q5&M9D!W4#Dp9 zVx^>=i9SS~-Ao+Er%oTnG`>0(AvlOk7gfNSATb z&`)2Y-FTe7#(8yqk783l{fO4kGfdnnJmIcspYAu+Hl%IpSqO;x|K7I#ZM%X znUR!gI(q%(2JuHBfT!J2CLZ8tpC1?8`-y=b`ipGp+=8PX8#(48rJTr%NNHWc2q5KY zRh>_Hw&1GAL7}-{JVexj#mzC=q0U-7RpzCgc&@CCb`|vXG8^s2W^Xy9*F}32MQATh zc`FOLQ&BU;aM8P+y46{U1)qcVW1nv||Dd7>^YZ6EMdqQ(gX34k@$FCm~uRwO${ru$Y-_elhkOG!>idiY1zhQRYE0Y{6<<)9Gz9WaCZ8|4Y7yY*#syStvbB`}^8P-VKlJ_bn zbxrG{E9lm>tcnIMcW89eaE!|~joOV#E;}?jZ%i^7!?mg;9Y8eHr#qy%+Vb8tb#d9Z suI{riO4!3(4r)#(+lhHsSU;kKuuh+fa5<)MdbY|cUo3cPPO@A71zaV2w*UYD delta 1318 zcmY+EZD?Cn7{_-`&uNl2NtY&RUT&J#rpvN6Z8mM4({_>7iJ2=~=R~oTyEgUYn3vL~ ztDCk=Ccez8=B)TZ5OFZw2k`}!VW}`F4n$F^9gcOg)K|obpq`W46!+!a-~a!d z^PF>@d!KtTc_B%T(HGw>k*Hrkr5;X==Et+;!SZxDQY1Mwn<^Le4+#5iVV9C|NQXNx zv%r~fsDas-@wv%VQI{Kw<#Q54>{6J=&7(%fWr>`0l_Gf!m&{N#*c z7Jz0~2(uQr+SE?jW@daA_IU2VECwe%LCoSX*V2Vq7ohO=Xzf5MlNv6Fb49e=RYPRg z4-IA2bZ%%!ZqN%$4n@cA64@qGu;Mw4SrRO|WpohsdBvs=!exCBI&}T8qIbesJx3!I zC+{_4_6V%{yfE+Ek68|U{_B`c!&tx%?SW~`o~qzNz=qi~6+B&ULMPyj`e9UpW5H3( zUV;_*n1w~-FnS#lra|-;%$ic@ycnG@+tLnYr4_Re;UmS3*~f6QsWZerl}FVsrOS<| zvlp8q_dzZ5evH} z%d8gl6Y5kUpD!@j84l{$YQ+WWjAQm2>~QXe4;((s{+1=9>>rt1Z*HsOHE6>IZR*eN z9;Anu(t_$?K=2^xYws6zRp(rK*CfZ~Z73PNaC{6UEsj;yQg z;izF|T{+wx=s4_lZ!tW*=B3~@b2sJB3kkl4X1HPAhhBht8~#FP#MlZRtBJfSg9*zf z7;ETU@;U9EW3bAq;p^~hwAuv b)hoRmZsSvHO6$EEG3%zj<44!xsma)XwOf*o diff --git a/generated_examples/mg_execution_times/index.html b/generated_examples/mg_execution_times/index.html index 3c7356766..971c4ae4c 100644 --- a/generated_examples/mg_execution_times/index.html +++ b/generated_examples/mg_execution_times/index.html @@ -2885,11 +2885,11 @@

Computation times#

-

00:01.019 total execution time for generated_examples files:

+

00:00.888 total execution time for generated_examples files:

+-------------------------------------------------------------------------------------+-----------+--------+ -| basic_example (docs/examples/basic_example.py) | 00:00.895 | 0.0 MB | +| basic_example (docs/examples/basic_example.py) | 00:00.766 | 0.0 MB | +-------------------------------------------------------------------------------------+-----------+--------+ -| basic_widgets_demo (docs/examples/basic_widgets_demo.py) | 00:00.124 | 0.0 MB | +| basic_widgets_demo (docs/examples/basic_widgets_demo.py) | 00:00.122 | 0.0 MB | +-------------------------------------------------------------------------------------+-----------+--------+

diff --git a/generated_examples/napari/images/mkd_glr_napari_img_math_001.png b/generated_examples/napari/images/mkd_glr_napari_img_math_001.png index bb768d7bd9d975c650cfa018d087de2316492efd..11eb355275a60d41f5512cf875566a262f122c55 100644 GIT binary patch literal 47465 zcmb5W1yq!8yFCn|qEaH#rJ^DtEhR9B(kUX{E!~}pgro=vk}4(A(m6CpjdTpd07Ewn z4a0ml;_p50|D5x#v%Xo&n(=w&e(t!geeJz3-oH?kBDzL%4F?B@NJd)xB@WI-2oBB# zk1LnKJCfs@Lf{WBX9*2w6+1I$H$z8L99u(sLr05SuBMJo7IwC`IN5pGd2YRScD8qV z!ohL=A-kQUIme+;dp{0NC0a&Y?3H`+D#FeCmFi^s7A*E|48yZ$55Ml~kt-(}xvjB3 z-%Wra0uU{xE z@3r1Dg-+D(6&&fWLB7Bv{reI%u~{Jw`THuRAcu&bzgq0Z;MI6{?s#R`X(5Jn zub=(*XxBV9=+}sHiwEL&%@0Wx zD_`1oSCH{Zww0ggg?N@LTs9^nR_qR(oT_j4TVA+uVR5*GKR2GkVx{1*_N(C6gw0>_ zN@t5A(ZN=ff1Ys+RYbrj;^~Y!K()PisitV~6lX+_C*tGB8>fd8VZp+DkM73C<*Mlww*Bg z&WvR<;!oA>Lz+-71L@{&e0fOsQF>0o03uqx=!6ennu6)#R$Ya3y>{;0d3Y@f{@it* zIP}^z>DA=7twy(njG1wMvFL6c)y|rk_J1`de4nCn<;se zbZ*z^=PStm@pJldVMZ*wb9h9vQQ3=FXxM6a3RRF8`1r<0Au=i|aSu%vp>o@{mEG&K zluF{SZi>AjeoH5Ill6X6ywP$LsKuRQO-2pfcQ$zRsaaChE3)xNpP` zY9YgUT9L37n-63IERn?Y#xlCl%VDk0Hcs(!etiE@ot4Ng;`#HQ3)7Hlobys&Osp+p zto~k|tw`jiG@p$I0VKdTAn2t=0<2(y?k!!TdtK^LQ@F@2oEk)LTUo9{jjr=rA3-yx zMvW!)?XQMAtMIfR%d(r)LZ{qt6npEIPz#5BjUP;M4dnoaGxrO6JJ9 z! z@ZLwhH&nMpNWVX+O+JEQ>+jrQVws2w&Ml|#2V=y!KERUNxy}8svkRxA>sOX}n(uCV zTzs6ewhG=;2?^@2UkzWWtF7;AT|>J~I}W9Y3UhyCvq;+Xta}w3udJyj>F$1)+%$7{ z&B{u5)Y`RrZ&6Is;;K-Et!m%%KWBA3uKA&NCBoM1)SN<4uJLcpR6o|HQ67Ip?ilKZc!ZN4T(%uXiAr{sqqnRLug|@z(xT{Gv zWg4{M>zuCUYh9`F7GUlMAfcZKVVF7cbA`C{O>L=wLIE-aYBKc=Z>0lb%*@LrOys0k>V}%m(V*^k;6|pe3i%DJyfY z)#LQ8)OBGJw*2wq*RRem8x6NL9!)t`jV6{`Y*>(RPNj4DQGPX?CS-tI182oThHK6= z6NC)KHpL@is_<5$R!x=GPlI&}@cnlbU6UjC0t0uJML$ep@T2P;beqF2aF^SBl}hs^ zr1y9fG|j|p%*;EadhwFra?+4Mu8i!`v+Q@`k1pR_*!Y%Zwy{Y5C+J3}r(}X$fluSc zai>P}kwMw`=Bb(3OYrsB#^=9&b!TK$7WFys)esf7!(SgamgE`W8jD(4Xyo&G*Jq^_ z`X+YcW{*5xOIAxFYF-fPc%1Sny57PiH&y>UTWD|iKBu*@iXmmZvle0a`}-p4b*her z+szL+Skp^0UPIgIZTr&MyV`v}9pMP%eUm~|5$k?`-6`mIe39mSe0$FVNutdhYjpDT zit~n~#Lg3%G+L7cAudiVEfmgnVFfN z6Ze}*L=zJ6f9I$$tDr9v)4jHwM4s;PtDx6w(TXbQ3EPSskJi@Kta*gzN`BUSPm0jU zVC^a9I0;-+W~DyBleznUXJWa)^CuxC-O_&O{WoogAYcC7V&dW_pZ@I$R~2li7{=a& zeE+Vt8X8inK9`yKDmJdvh5sBB&{%ATkdTXr&pzEj;{TZ-K`o0PVgCmh$o&*#qM74!7KU2H+Szb`~v|?Cb$fiBWO2t~**+EO_!|yo--)g^I zAWT=~KL2j57%KgL*&$lW{BjUyU)J<0=81mpw@u) zUK085N)3m~0qr0XhK5-g<`<~EIgAqYt|+wVSNphid2{EDzmNVJ;2@coO>DJ(vbQ$U zZb-{kwhpd}NRap&NL^Ry6$(>KF_K>kI3J7li|OYr7g?q$^irs#p~PxOE=AkR;^VGN(g1YfDDj*yG?io`U0d8%@B>(8$1R|9*_!t|G+i$qlAhq}PX$`92xzYO#B zPd2G9gN(CAt?7L*W_^0RweU(!)sQMEb?|(*`YKs@hm`)b!XKr*DY6$rP;9@3Bec)q zQXy+=E&uplrs-;T_k5uGWXsx?0oCQ!d#1J9M}D{j;FckqoFJ)hdHUq{|2+fc8DMVm ztu0ccPG}O+$|{ODMRRT8{k6j^e9jw*O{F=M4xR5&IQCTt5QALN?zQg13@@KBJ2t0f zIrdeVm&uBrui$v1IHv*V*v^5kU;v{g_DXA;(JZM%08Ha2Xkszb4{pBPJZ zUE*SXZeP20E$Q^#If{$k69)&D;uD=3f1oKC3b;#>b2qiFH659q>HK99&A1+Yw`S6t z@7{>HuCt%+rd1G+)fZJJ#Or%iocfrE3-Bs3v#YPjL;tKDDc9M#W_t}A(4KkrDExf| zZ`Gy){Dn|)BSmCHiR11CN^0_8{S#>!#i^4LrFPWb=7y#n<6a_tW8|%ZdZTN$6=D0L zn8XwBhzo!27rpmqzCZYcG2pC(d55o>)^Xsa?Tm&)!y@ z%%BC$W?#GwppV##k5hl4se0+DKO%C-(keyq{JbZKGeN|)IuKz9qO9s}*!H&V(IhYA zNK$iI%2T+kQ^9g+Qkgn_ubhXas(`pEcYJESRY6~;6f6lxeQFnDZ-TscHWm9pvqkN3 z-@>sC*a&y;jyAqSMa>;>rAx~p+X}5lVp3`da0*A-{X|dSp89wxztYjtzesBFg9LKW zu+zOXke!scKW!JN#9)1*3PjWduI9noEmV6_;({ZujkuMZ;7VSJe2>?3ASL*H{8U?` zd{@tM8SSs`PK#cf^F$-~1B4i9g3j-p34BOZtN=VKv3T66C8|UL`7;Gudk6_KoN}zW zNnf#W^+6l3> z8|k(-yT`=lCekXVbE`9HSYM)w_JASFOeNU5$->&V+S&{LtI5LK1fh#J;iUde-;5?t zr+9PPc3Xo?clK)G0F`Zj=g)_civA8)xCh~jJ4oE^7@vR0&IS@neUqlP zToF@<7~athDk}f3H8UT}CqafEKIb=`SJwy3`CGS*K89ZlU~$s1`B=va_1_mg{V19Y z`8?DAa#Ytzb8F=ZD6)Bb$N84x|7JXu>E{`rL29jB{W@<_#Y$^~KJ?yQae3TY@b=j$ zdftnuJTCUr7UCq0*duQQzD-aR`scy~F%@0$M3(y3`5v0BD>OE_IR)HoNKF+Rt-q;M zt{(&8Y1^+ z0y63Vn9cZ{7Zl7ehF${c+UAJ?70A&ldU}(5hv!jf%^$4z-`9TvCjSn-{?1QG$bVuV z{sZRuS>b{&?n~0t+$1fpm|@)hnlADdPI9kSXlN*a&0oL${2Af(;Lng|($3PZgj#MK z#K-GnZ0x&MBa0%A$B*Cr{(b$4o8lcIp`_A5wgc~azU7?rf%^eKl@X_ruNFkYC>y-^ zJ)pcq*z^>rwZGZ8_YqYhNXg=_7A3oWKzo&WcTQ zdz+oPcH3S3bHNkL{d6LpJDeiuA$5ITUc1ey#;kdOS3xuekux!ol7Ye2a?)oXVQx9u z!;iGKoU|&eGqX$`J448xW-cyeIUbby-o-f{qNfMxIUY#gSlXBw1pH@YFll&m9yS0`vP36O=%o5>sg`d{$P_g~L;Imoiy}7lJ z2QP{a!@4sdd$gY#8al)jNJvEO0sQfM)mW%aoWIH@YF)PqTj=&NwLb9s_wShU&yI~A zuT)3uTY33;j7F~)K##5s=V>dsxb%qazyGu52Y65hcxu9R*v?A9Ox(!i%<@vj^zLEh zo>DxXiwbEF5q*mfiAbBSpU;QlcKYV4#!;6HMn5!mr}9K~ojy+Cwc_WTYjVP=G#fWH zD7Np3sMzZ7=C3?W%nb<-ZqzGTedBE&p<9RPLh;=2+j5PZ@6DU+j<}7DEYx&HqtRNUPp{D`YXJsEYCNgfM z?u(1W7Jb0QtnB&h_PAAA>Yhx8t57}uF3J={f@`q(<I|-~Y*Dk-n1z(4GHD`P z*IdgqL;*1b2n#X4TD<^&fB%5>^OUwl>8pDnt$=Lu$Mum>lx;97w%?xJvX+%AM2b3` zYzfeby?b}jscF<$8u^nPl*m!Gx`&GcutV2%Z*K@=Yo;lVwX6cFG)Ae#vg~7QLIWBG zQEaiJFmi0wy9zxP>uYjy96r{2Sos`(E}5L4 z6vB3Em*};am2FK*rM=Ws#%-IF&o22C81`wisU!;R7bVhMO+M z+Su5r<1_S1R!&Z{%u_d}AiJ_MWM<|Y6O^le8ALn*v+nQBzCQtoSnci*m^qOlQ#2S0 zRehzVR&3cr(<`|0IMrkQ-qHTbb0Z^f%)*hu@t?I8KY6213Bjp9b!8}7@K!P~xK&nG zMzn|dX?;nl_khy1rmnGmU-Tqg3A;~j&^R|PwDzU;+gm7P^MRO{Sfvg-VS2#~mshWF z0#9K*!il54DXg%&3AKfDos>aRL4k;XVm)R4rHV>(rn;WKAMq9kd0d={xp_=-vbRRN zsp;GcO=TDHF(})Qy2D=l3G7IXyYW210bxMAS-rBT&&q!d5`?uc>xGL@HqSu;tF1~A z_qs_;LHm>=z59bd#tP+;@N9yD*A8fiG%f( zmG5@U*j;Ok<_hyP4q1O!epl1gZLZtLFw%b$dZDK_IfeEu`saX7xhWrvrcra$n#lJ4 zoXf4WK6EA*^bH2vEmti+%Pmb0cYG{hBM*})4Y+#%VtdJ!2}*(Rgn$D@=qG|yhYzLFxu9G#M)ptVfl4bi9F zeHF=fwE8y%M_glE3m>vHJ=px}91{8DwGcR)j*i@4ZyV-mm1*f4NTkvKx&5JTKMiBe zrAwE%91pJJybTBtTu)FAb~*7s^?AQ?6HcRR^+gGp8hkQST}a%gyt6)#yZhwsS`b9& z&(m*vIlrQWNJi20{%*w6UiE(S=8cZ;FNuht13c%D&{^0(;iWHfvfS$W9xSdk`M(w* z3wZ<7ypB}Aw=t7U!jHl;GBTPW?1F;Pn?*$w8&Rc<{~G_0vdEBW#~0jJs_G@4Yey7< zX-p47oM4auH_?NOg(F@Kt~nM-pIw{tgI(68(%j2WUF7z?qIz|OHY#2_J)j5+d=r4L zqNO(U4HLb`^zdQnSXxRfd&*dmp$hAc>^Z#KEpwkXUQIAQKpmQsk-?+OR`@n&SPPYv zmBBP~kLdf{L)2sy*+^aHfF50@rq+~Cef;L@bNm~Wv~oJx8WikDf!NwpKJ!#xZe|6# zU_&Zr1)1q$W^;Qqk-Bl&I2E@$j(%@ybM2w%_5y8z+3$waSoK%iND|0=aA4T`(9qd= z+Jdich3m2L>YPr)+IgB4Z>W_-E;MvgrkS>(IZAv{r_kx}9%r zn|z7v>bv(_98kLh2e6e5`?VeT)}gnK^W+%Lgd1!Pu;YU9`aWdPN4mW}`xC_eOadXe zn4|4gG>5~8KI7~`ar^HQFZKFF3_Y6S(QMe5ll$r~>Zb^MOr;{%#BMzP;r5E%5Tw!oK zULmQsKQ4C>S;&tQaCtXfyCU{J68Q%r*f=YcXDPu+u}*iPSf;~?b6iteMnS*T2i4c- zvz0YR1V!KoAFe`iLRN0dxoc4A_nZ=gG-A2ursLRmxEuDSKo|NZc|sV6&qg-eJc_}3 ztlSt%O+dl^?RzDa{~W7tE6UZW%_8Rg6#}M5k7EH|;V$`k*!(%$ambVsy^>f~dpy}L z<*aKpVwX`=l+e^(h~FE83w zWS{QdQ|Vp!(Z$ioN%+%^QW1xOL$_C-(LJ{F$HTL=IQ87O0Yic)HCt`3`_?X`t_a4e zBi)0+x(5Kdjp686BpDq%07~-;_)s3oKcK+k&gq7Ks8>Sg~mxjK-$+f{-F3 zBhzM7yqV3)ZrUla@G&MS7>=5LSKNNV9v}z@FX7#EVd9KoO*!lK1ibYPL^?hJC8h~f z0uk*c74F=JEn5J`&onDR7UtBE8Rk*8IF%FZ-~o%d=(VRTlO{L1II2QAJ0F_W9kT1g zKFbv%Fw}e|w^D@oF*3A)60JS!F#}5wXQnOf-tl?tY1p+S?0*gN$o}>!wF)7v! zDFSfXhm@Ky=2TyXW={8+rG*1@#E4@vuR4GPzsO+1P`8U$yrdLYk3F~g=O(c6LLQ47 zZs>+)rQwQERM!~Nv7K!|5WS-^TEtT3d)%9%IpG11&~g1G0hVOa{aECzc%xv~Y9fF^ zda)vV@|f6Uq#4%ru2jG&_3_3^z0^rLQn0GVeQ{&|g{EfU$O`K7g5JfcCMRq|TdDJ; z#muYZZu-yQa5C-<2og3MAgXy^sV(NPL)E7Z4e5ByUX?(Egm}2Ma@1#{j`la~Jk3l@ zGIBiJCOxuqJdE4Ixp+592NZdD3-zJCS@R+%o6Y~Q^b%ndpA-2#woO#Pq17<3WM~Ma z)O&5Ir>q>E*eofDP+VPA-8X4VcUQ7lBftc7EQ0YYM3DSujBYcaTH1mh?h=(e)@-JSxq^zPc z@LK=1^pzoA-iT||t~K;g?E~L^I67_{(#L%M ztgxI_+WbWFM9Ip}^{1Pyoni%zG_v$41a{kIB}NItC4%1W;^6013XJ;1>$<9;g68Jo zQRv~R*>pHs>Pb?B>zGkO7`#@wRL~74O;X<8wK*PUNEJU0@0*lKLN8rsTHa^Pf7U%% z9L`@tifM;}#HxQT;q>LOdr<{BG|aS31EM;4#bAXD)YTXY5gfom?`vzkUi*gsc)h}q ziYS!9tDL?7)ZMW+^V&veu6Tr_e`7@(aJ}Vf#yg+aKWXAp?t_zc8=(Vtp zU%i=sD1nDkwEwzDGBC;tKR8SMCOZAZ`fQR7JhV*UyepbbUdz-P8-^c(w;vf)(u=uCnlEcwMVUyFC|rR zUx`jBdo+PU2>C$_ZxIPq3QJKMkN5Y-S+B!n9qpqjPQ*=BU1;~D|BSB%JEo1E9bkvP z+d@S)zYS!hIPG4sgGz0rBB~C)p*=SHm~jQ>GTsB41l=aI!G+3^!bv!sDd~1UH7&P= z_bLn&nk{~LbCaALJWa!{69eEH&mbT3G+Q} z^U1fvC%li7dMr(sW6?4)iW%dYUD{a8hqp~e>j!9;oAI&H{esc@BY6v9g-|?@d5gp8 zMK0v_00tRm*i#*`vpg07>OQ=ro+c7ew&?}^PZe9LyvWl64sPzZ7Ajb2jn`K^4lmVi ztxHuR)-jXmVZA~z#LA>PK69c@?83SoA@VsQH zN39dCB7Z}X{k}J2kxohiF0N(li+W^P5W(9&%P`BkeY&X$T=2uOZ25TQ0utNbJ#OTOH zJv!mKUqiQ5mhNQ=f{_V#T8GTt-e zTxXz=eEIA`1;T}~WYRmnD_id!!WOmUcbc@is*`%U5azuN3rq z0|(28#sK%d!}tVO4BNZQLJ6FT!^W9?}7FsNv90fZqT2hwC6wbu(cPnA3wu8mF&( zGj_h&9!1?s#&g=^#L@H3e7^uk9tbshpLh9`dfh+AFh?*y;4C64{C-I6>;o(u++p$T z3t+paf3E}@2`$komci#>Ngb$V=w;fCHCwXq)(gNt1vu>5?eQA$3!eNqXT4;}UZ7}f z#WLoN*qe)^YtG@3Myp&*hwb5%9uD(K@`6|rjYkx#xVRTD4I<$FIJCr4h?SW8bg-_% zx@IUA&1aC{-u~yziboRX^UW~XsYBBI4vCDTgn~fD1u7j-afQ;D+r+@Q?4RnVx*vI1 zT3U`4am5iO^)HQ7@O#v3SD}WNRyD7h!1q$TPsZX283xn*gfYTHL%ewa>4gM)#fV;$rW*5)`@6vqrUSdzz z_8}%Mzi$6qDj*56#3H-ymt$PJrxEmu4)C#nE%ISsny?pfjgrW+eDI>GThUG1l ziq@0WME<30@XDzPo|S!5lewAQ!v_x@-2qq<0P5Az==X5c*Sx%BB}kgW)2BFB9a0iJ zw+?Yy+Qi8aw?ij%4{aPpr0zfpRMJ=QLZUWWC`%SD6nS*QTyRA5s=rWG>7mqziA;1+ zoCp1VEt{71qT6_9Xo!q~qOIWM?d4-@KKSGa1>BAVk)1+c=(eGsi2ukyMF++#9+7VrbjM`x#+Pm+i_&08=t?75sPPNi=7Y6pvbb+qvE4M13l-edD2C_uCZ z0%zaH8)P97OCbnb^U>d8yY2rVTo?U`mjnHR9^3AqJo+Vbm5}Op{NN57RZ!zcQ`Tj_ zmjirwMJ&7#1Bwt*z!khSx&RYB79gFT&d9Pco2f)O2)wlyc$*-w?*3ARpK+T8=sztC z1`Y!U2Lg{Y+%ft4nmg#1mR43<>+IoYB|IRfxK?`H4n2EyJa-o_Kg}=sG#cpz8v$JO z^sx@M&ur|+P)nQh>^eLP-R=aN@zd|cZ5V~czJJ?vXV_MHZc@nh>@yW*)vFEW`rgg? z{CYhi708b7q|KYFD#DgZAT;Rv@I>(_er`cjC}gX{Y)^Ka5HydEYou%|lDfO;Y-`s$ zFT?%d{iC{^XL3<5rg>>%Yhgt?JlCuGg|8SX?LdFk{@&8W;lj#+(Vj42^DUn)HP5}p zHgG@l!H};w03ZdC(6{JTOg3m{r*^=gdDd05=kTLnv2^@ZJUEO^8CRJ%_wxKyG+v2| z86xzXoY32v2k0B8n28uruY(dr+b?`Tv#Uu$&V72U{SexoIvuBJ=K!Pkn@<_hYg*gd zoWxHn;$cGjf95f->#1`){aj&I7t&*is*8eT0z%FXnxq6+QIFkBzY9gqW3u%rLVjsX z5kZBnep@G}!D*HAKe|HJueXNA<bzz3Wqt&bT9dkDo9y$+ibU*C{Ghg>g7*gVYMMRo{rJg7c(S{62TPS zN2bS{)#+jfze%NfG5~qKM+NJhQ{RJ$5+-W+ln+0I2Vfg4%lN2lb`I5%TSNRv6#8&E z>@Inns_?-m52&7|#up&a!*!{P7cWk2xi7=d#k!MJjXwo}-Se}8fc4hnyYGH1w?(ZI zUb_Y!4*W;jwG#Lmk>q7i4gjt<@uYR_>DpQiWvFnnGJZKi#cGc~@bYr%U6mC_-f_EP zjVr{iFLZSWUe^p&yDdimsjJ`R-rf7WRj_^yTSdMv$L@FcCYtenO;%w-c>4MCAu~?W z@T1unC3#rw$#$1QPYt?PNTG+8$1FU@BRj=45!6QQk-WSdJm?0$rxrv`3yC%L{Y%+N zLUpd&v%f&0v^Q#;HIJ*~J{<@IqjpC3+t^`)JrUhncc2B`yEm^`!p_dl$7}beXz2OO z(>_>hi%8t3-;vhwn2XCYm+e|c*u74-$v+a%Hh@ZyeAk9fJ@wU25YT`(3%WUFX|C4r zb({i8=on#3C7J%MJ$3CkRmCsx+(<%dA(CI-_K$&CT3cm0J!O;LX!bqb=zl}emb*FZ z{oI|MvhTygn=FMkQGS_RX(Mu)nid!@M0@i--0OiOry0z~Hmv)e+$Z4hiie)G{!`8I zS`CADHk(P365ZCT77`QPR*Tz#D0cn2f#qad1g%03p1@K@jC>D|S4s*sk6A*Z`5p}; z(q}&<$3q?1UvfMEU&F`C!Nt`#SUXwgm6XVQDhH~MrX}YY=lL=h{&5k6)SrA2jimhl zTYShS0o{;^OE5Z;J{<%#9FVJ69zML!%o-fp*~z#5^<2{|bpwX6B@mZ=j`r@duv`sm z?KjW|jOo{}x1HCM#a&(bEON9r54~*$|B|~F8=%5a(fq$e&}g$h8b+fZKw4$^xmf&f zl<0X_@l^;U;Zgw95Fk2&eRLch?|^DN|93hvevw#NBmWr7?Dr3iz4ke)x|FG}j~*B+ z8!U^dG19$zIPLBRka|K$yarSSVKl+nAJgn%;U1W<_TMiDj*e!GCmGMBXbg2(>1Ck>e~adThG z=GpjQ-z#$Lj6>HbwzGr?lS)f&d>$pz8mE$7WV*tarI@6s z>2V2oRiavr48ep7AD_s{*PK#33!s;$;-~Pp)qTR_{sMbnU(So&6KB-AXT$I5Q*_w< zwdk_<`wvG+yTL5ACvW%(8zdP^k}M3spiOJ8B_?CnfOBOLUNdt0zcf`2@0|^J5+J5O zB$j{vv1|!Bc67zm118ZF6Qq#rFm3{rOBs#V4*>6ubCaC1#BA+yXD4e%N2l4ZpK(9} z;P3~m(IpM(`~1xEddKVNl z2qhsJJ3jizvfwl{7Y~TXu_~f$a(Cg$%NsrrJe+1u8e6P_(8hXu!MX({HEAyzCM>zX z&T=#U6KI$qh|2beGTWt|e9r$Q)T6Fv0}5ZWZA_)ZcuUzA?wOWp6>B^qTCW?ix_OARTm;XH z-L5ACMsa)u^PdAh!*Sy4Fz|8a#=76Z)%!{`urIh6Ab)aHT3YIE{WltL*MDKu?L+Vu z+~?SO%Y8?i4KuF~f!)c%r60Muzk1-R$a%n-bDR9eQOnmG$*^K!Xa81N`CY~) zO7fi58#ELhYvm;D9~j8VJHXr&jT{8$zJz2YWKNX?`6uTIO0;*V87LEkCe%$@TGkDa?8?k57KG`k4(|= zL#OO+U^j}hm-X$&W83oG5cm!8`Y?+RE`5W!EBby1zZP~28GTPI-qI6W>au&+*A3`Q z9&f5lVi!v&s{7ORB~0&)jg0{@j&ayQQ&aGvCtc9gltDqgs`;?u{g#d_KKND-S*KDOwGlG zXn%6w4_NM>dT4qC@QM(Z|CQDm4}7Nara&m{^b=?JwI6^Q8=o5_z>F@Z^8v=cb&8U;a;J z(PG0_J&;7O`qeA7kDtn^AIF_Lu*9|ABSm}F&Wl)aU+BMaVE=)qvv5!meDrVRoP^f< ze`Swh-E#&^(CE`7CWuDCB4IF7+iG88{7q%0JGqE2zPBDnjq4o!FxQw+1*3!QQPz-@ zH?f8Gh@Mye(r0}?4Dh@lsy`oNN%(EXO@J3>-)U{UENkA>%nTreR&sT~{ra7H0}FWd z3cCs#bT`TO;JMF6O930qKz7tWtaGZ@Iu|c&Rdg1#C;=ZiDoQjlk>7dog$f#I(EwRI zc=YJ82vF|+P^<$XQLZM96=|e&bn?>D9b(vu%yIcAYqgR-FZxjXVo>uxkF-Upg*xv# z_-~f*f19w~8ch@vUltQ!v8^Y6=I7Vk>3?X=$4b#PJ;Y7a96YjOmC5i|@~J~AOdEGh zy&+_L62hE@QP*~p$WXl~^p;w$`nwc&4ht+}?ek8-tdwxeP9@0T-Kjo3`Js_UhH`v%-uCcsN0TkWP`2#+Mx z^W7!l=B5!<@>*`C+R>az%pDGo9$9KGHF1ig@e zzVslY#-{!`==Lwlk|ksXC18J0X&m*}8UVDQa+~0)6+lOn*A=;b`BD^8^x-=2vJj86 z3o%Cl@-W8p-k&Ji?>asg64mlfz_!+x2J3;LFG%qf0u(2p0crh@*Q-+WKd~=t=i1H0 zXLeO>q{30>tE{B5k{FgM5o-i^o^$Wl?$Yi!wSH!juyGVOI31bbtk02=t)0H3Ta;?gZ3OdCGO zcR)UmI+HO?R>5=tc?x%NIFly;f0uu$;4>2o*BkVyJxw7L1KAfndYoeP?fn%JyjvZl z()$H0wY$iugu`*6GvbAYqBC6y0uxQeP`1+xeFSc${tDY{C&xP}MnV@jEe{M{^4nQ- zby=#rnwTkTX}LCF&JFH-#Zu>x(k5G%0s_1tU2O_WXT~j{%cXkn>34ggb!VQm-T)kn zdI_|7&T(sKb>j*^#swQ(V>>8EM&J$OAcne?R4&Dk3Iy8Ky&xV>YgbmijY(9U z9tYp?r1tb)C2i@x2aTDBPyG=ZPyBxpM`Ons;XWnadU#1?x|4hN9iF7Tdnd4r#K#w+ zS>5*(-Yq=dUu$I>$R-7D3q$2*3rab)lg<#s0IJ{F{P1$~7ixNa)%5#3pz$EWLYvm7 zmp{v{u>`j9^js-GmUY=pCG`(b|Aum~u>1mK<*9RPrhL^RC=1Z`KOwlsNVb< zkeK52SQb$m*K*+A3qhMiQVWKIEqa6t&$`PT{W-2n9ocPs97#B_UUw-wAMSdcimD}W zA>|i1x`}-*P!&|(ZJ)Gu{%o5`$sS+HH|G_^L5XWsrG=RppB;9e>2#ys3z#`?3As@! z0TwjKaI<9qwzWW8I2UA9kWu^XBXg>U@5Yr6h<3kYgtw>jN@p$yhRi>+OKp2?;?N5( zJSYl}cT|YY0LgN}tK9B?FdYFX0)kNYIepl5s_Py7Y z@P!_1v~dGTw11FMbKOq57HH|nR%C!t>ibDqcz}iqSMI8s zZQKNGGmL1Qf;@h+Asu#|Zgq4+`rYQ{3tycbxq#?fjt2mD!>bAYMujW{1>}qEPHTN@ zgb)4e<9aR6`~Vtr6vqZ{ua>YaiC$qvqbGsa0sKyk=^Qy=JstLK_;0+fh)Jmkt8f#2 zc<^*jeW&uceCgu&TJ0C9(Q|gDgY@-CVAP&L8v#d|3#I)2+-jA#pclJZZdu=Ae3s`? zReX|9-ucexU|4f>P_bZ)%&`CZ?Jpxydhy@PPZmGqgt)f`ok%KSI6s76s7}8Lz4qms z>d_S169|I&j<$lH2YV$9=Z%iiUZ79MQ3LQ5yP2b~!&*J?H+c15u8!>)6J)kXAVo2` zw-)%0&%a+f=B$J1?=Jlho!oL(-lcz~N)crV`3m!56;MV03kO-#Z1pLAU%YM8YFR=` zO+7S>_-k|qo#f+J$we~QmeA)ge=QDJ;m=<)6{TkcOlbm7uR!xoH)xYiNQ_TTwzkwm z*83>*9PbP$DfD#x`UUiL@K=7`jhyUMZeF{tPi$H9Z2I*RgSFXdzT<sFJU1|S z8kSNhw{X|!iDbp-;ht%UW-)v%c-Oe3>==9Zd|n^_UWd;8^>HCK>Td_&JFYWo*-Ec~ zXd}21K7b=|Zs*bnOR2dhpUC-XG$ArSb)Z5?>3*6(!I0A)sF~U;�p+(Rf{NT;*ue z9*8e6$nLBRl$>JTIT%xq7P`qf=SLezai&WVPA5b^Puk%DN%5@$!}{M2i1Beyw&V*R zwUl`C9@mtwOX3+vQOmS165Ajm)JTympOl&QM1N+BEREFQi+DNn+{^v>BeX}`?Qs?6 zla0{#ydSo8#D9SuE>vS;(5TEF!>i8iFro3&(ebn33R{0aEyudcuUNF8LzBRSEq|I1 zSCXL9!WkFBHc)tvpCf9zIjG1LaoMcbGi>JLOF+M?>kGy?Fo%Dwt$n-0249BpVybh` z49TLH+IMGA&1%@zU}DR-qqhgu<2GroV)+CoTRyera3T3UaItMrJ~G+-f;-``fdQh{ z{9p|8)?{$n4EiwgfZ=2*l%>TbbWTZKryDrOid|9n3ufK zohA>eehcmLt>GHRm#VtWbCml2BMX`OX?j2qsBrR|TDaF$td+0hzD`X@%Y6kXEvLZ} z-P)Tf0TV#-ys>J(xm$t6vv0je35b;YYK8EpfX|87apz-6iRt)-Xsuy9jRMZ&w-@lL zRzISbklANyiucZ#x;3Ia0A$ItL2VNdfc4|ZS<*f;qb*%0|1~I@DrNBER+Okaho9dp zi!j3m?nWz~Usa02k~S5u_m#s-f!;^0{NNsV{v|Ns&&E=N5rdjPx78uo<*C-(GvZ|K zZOQwnFw><_{bH?0yT?H!)GgH6snUQ+VpT7k3s9;ihRE-*L#==-auNf`Ai`aTWkd z`>nu*{yJ^SRW({fjf>$lOs;Z0OX$kgtMl(r?KqrgBpESvhm9L1C797K=ndxhaR=bI zFDwt&0^7Nc6UxSVG`7>jJnib!5q1_GuHC3J7HML0p+-6+D!qB#;szJJ5T|9!?;|I= z98J4=Si#8!;A&!Us>kBi3`qjbNi9#Sr*2;~sMYAJU7B9)>E7|l+?)2RSFaiEe4oYv zy**@#LwOatRREm zy}N$%)ri>Sd^ZoVu4P{^5k~ggEf{gwEi4#=7oAnvIldF&%v(*;yMkQm*$F<%= zTI*g1GN2hnGJ>izGW^lx;gpK&YWFM$$tmg!=qBw5u@|=G-xt}rm{ehlnk8$;}8okJ5YNT%30)$24g7Y6egowg(vHrMgf zwx^6?A7T?a0B|2d!f<`OxKR4o>G#xFvz8*Ua2iO$CDGIF8B^AS({_nn@ZAXsk-}Uk zWViPk;^>*I+<5e72@8uc-2M32PsKbuH4;4MRdytWukr!-2?E~RW9k54ZJ*(2V%HDX zk((S7zz?D1?2HdQBJH4^1#szK{Gip(BxNk9yFL|u0~MTUmwKPo{;PMOwRsbh_rH_ZHZtm3y#OOu8`g^769z z2rb9OeJTdi378bZ<|#jb47_#dV%nlIrJ@R2TGw?+Ob$DFL2082!b}iuiqVsoFJHc8 z>S(-2nIZ)Qe2;|yC5M^`h0e%`_xB$?dgnnvp}gVr(NrK5 zzY7c+#?}L#P@~3{33ROjEjyZ>MW&~EFD?F2_VAq1VQ882nvPrKq(}`K{c#TH^ef zMkSgn(8UV}wfLuw8Y@38HLSTduA_3Teym7c0Y~E9>i+2P%$WH#z|cR~NBR(?#E?B; zXVRD6JFqlgjj#VTUgbWcjPTDa;^ma zPuhWUz5`*eIz7HDI}3Z*-`>0kFfZWevM?+BNb0peNifFg=>28$dma?XTkdryweHlS zY+BDWUQ^-j1#mcg{8S(K9u?Vs)<<*q9a*GkZFVTo{ob>u2=VOB5F~J}gLrN&i>WXA z{o=lYz;scs+k-N8{=PotKbV5_(dI8oBk( z?&FL;GKI4wHC9LP<_#{WwFb(Z5XQE^OYq&LO2E|_;hYEzI8FmD>bOOoYnSu*Smi$D z8=VqeYb8=y&}sOa|*pea=2$yV(-fuFtH++Soz8^9&>=`HW-dUo&%Y6Uw6J#oM6Vy5TX9PXJS-t;&rrgndz8C!Qla8Oq zqas***-*Jk>@;(Nu!V5I<(-9eCFs;Hfs`9AdP#97Ldh(d&_Rj^Mqv5qm1VgIF>i@^yTR>IWc59=cuNWx21|g|} zbQyH%YalJ%AT8ZpDgp`u0@9^)FSXMg*gz0cU^A7_kn80at- zPuwx%n%BH;*TvnznqquzkuNJt+GFFoz@(VYIlFY`1@O7{^X=!b+X2}};Ezyo?pRS4 z9)AdgQbzdM>3KOr`$t=6+ElVY4n|sDxsDN4rQ&8R40~$SjR+eX8;I`jYenU;vJDp; zO-naLOv43yXATbr7F9;erI=f#RCAs9@#9Use-oOk^41qQ^M!-2E?Yf6NoM z8_y41IR9Q;1yik8p!F3y_S)5J*WL{-aA(jq{&5CpocsI6Sza|r51mE@&5XlgQ-{apF-SV$-`A~YyS+i+wqdFiNXCv&Qv((OKyS=31u7>S>B z9ZCuwGrLDugC8+KmXBT!IPl&?* zo?Yl}z;JhPKqQnSBtv+?q|Fh>ONP2%0el{Ji38t8pF4~;@Ev@BFH_*^X2eA2kiyzk zP~hdpTp(V2=u)+P)O&aVN1T7j%z;n6skynasm&-Km0BC+5_>^=+j)N zHFr&7->l&|%dr*vm0f3hHQzlQVjOj5nv=+1>p~TSGnwz<-nZoaEq6(XX1&;({=zfH zY+fuh6pE$U`&5!KR$3N+9(NHiJ8M#f#2!ht-WMuqd)oj zS5cLJBF<()UdcsT28XmGHup}MMS)NhQR zm5HgPyWES?wXeI}peqUTS4f3nwP7-gB7h3e++8gc3dncms&q)Esz?0<|BEt!ktfn@ zavT>NWp-`q=8}PyCa>qlyY$LLS~?KY5B$-#1BzGB?DE-cDF&9sgTMYFt0=Y8hPZp6 zl(9+$XmdFDzkGlIBJBk1%hF4!pea&h*?v+xY0;jS4TajLSlL*wJJ7Q|FOobsI&=}6 zm+PXYrDj`vTR|{?1Zf|T`{GZj@GL4y9EH6=ug)uoGfvmU(2GVN1-#*hzMFfr%Q-5 z5V~Gt5DlBw_KPc5$LZ;q##`+Ke?n)_O-9DZ2|x1Mwhv5){A)H4Q)9jOKa>TEr6_5m z%*jHmN`v-=e zcqGrHr0!68_&X!}?gj(jP)_2}DzYgS~Z{s_b|EKutyvMiP>0$V(r@ zs`En{KHl7KrBphO-n9x23GOP>w=*r)Nj9kcgNRmZEKAGoZXk8ev<5m)puW}J~Qg?9iG9v|~P9SiC zg)~Y7gR0nZ*97>lDq>ZO46q)4GkiVZp-LkcZ%|W*UG+nevR~=SIUWD>BD6N8JXy>H z9s`sUniVpqD!pO>T-QRVZ_uNq1djZ0_2)#(f$L4Qc-ghc%q%l*hq7YmE!m#ULlrNV z-veK?F{7Mg$i6jlL<~(dKw-DC2V3i~oTCrRTL*fmu(qR(3M<@kY%AQYSnfs&p?KU-)a42H%*qz@Vk$o zegsgpEQq#1Q=sC(VGo8QTXzr-Ko~4YoHU%-y#@x91@^`nd1~uAZ!!e_gKR6MsMrDp zj=L#tM>tA=L~lA#c5>6d&y(Qw07C7@PsDBw7-Fu^tg&u)BBAyRjoiA>&%L{`aH-oR zRkhHW07TW8R4TpI`Ae}s{v#1Flp)zw`d^;`@(p zSd)`e_nA=ykDa1NDUjtRQ|q38i+7?U6OPO_k0eK236mgrK92D)_Um)WH{ zevR+A-ac4#^z_<$Z69{ekXD#Vx^Jq-79EO4wd=ni7RZn%n~N9m+)Q6 z_4XE_qfg&UKRQWt-sDNdw)}W_S~1u8cG(3IfsVSo_I1*-%tgEGnQcl!W<7LP=_aMi z?rn_Y#)}t60{afTvD=G#lwrI_$-N~H3^@GjYwGed0gNCTTx?H5V|2B5LvUh$cWAhE zB~c0d?gAtJY`XAz)%!wPx?xz=Pug5dtGORH=U=&f!Mk)`bANG;npT2X2=cHewMZ%J zKk!^Rxi|y_@Nfy$-7qeM2j!n&HIPL!A~ zuh4>D**3|k{@S;MsTB>iI?`C21VVG`X?(#(!5D|vDoGkOzG(3pV4W_7qn5U~UI8G9 zG!bC3N&?fMGUzgZgrE+h2f@4N8U^qLF`Lmxlsk;Cixc|*%J z+nyzL;9Uc(!;7l;t_z)(F4`L58-!a!EBYf23%7?T@RwYc&qEX0+(Q{6#}@b zilxT4<$9RcsC}Pq*=_Cp+kB$t4W%1MImm=@xiYChwDz+k*UBpVVAy%Fe9946dAf;+ zXjd5)6ecX2*V9wevg&5;g>CdYVI`Oi`wcFPh1W06WL5EhP>H|bccJ!n8G4OvK1uV$ zv~Tl@0y!Y^eu-eJXi@K?=xGSI(+kGdKYjf8!q714EZIUwg%J^`faqma?MQ%eNzH=7 zvgfe60*1S9`S698yK<;em81&b-DmkY=;+RcHup?!Twx*<4H~2Y@@VStHzXTav0q-a zQUe{8uV0~AZ{QIH&`r(%I3qP-&0)a%YS^@EJjwMI=gd#s&w5Kku0IaMLFI4ba_pml z-fYbpyx|m&#AMKT;?!-rCbQgfkIcC)r9?xblC4-bf?j(M3t!MG1hi;@`% znKjdj4SDFen{JKNcTCF90CES%KyQ+fGuemZ&awngOnvDB}w}7a&piT>AG(( zv*x(9Xkr*MxB&E4X6DxJ@`i?Iz;!u&8YWg;9F$~!e17;_oQv;OZth)~H3mjT@m5@1 z+0db2M{KvviyCR z|NWC@(x6suR)MB+ux5=X)-ncV1go=k;P;Pp_TC?VL~@^3$EP9N>@Oc{L9DgL(xUCz;NTT+28opM!@6w{pET*6$!P_ zgBcNHP!OR~a|Dwn*2>7p2y?mCF31TqCXCbgds-ku@9jeKkXY;9&P=R$t4dk#K7GMG zy%yNG)o;&3{}ChM8%fi*X=y>Z&6-EN)d_Ss|EAA&a_j#zvHYj< zYItdJDkv~#$uNPo@Wvq2OX*orY(*Euvf2cFfg>J zz4}deyV%O$te8m%IC6Hs@vpv|Anb!Zsprohn2uz*Q=n098m6UV%8+-YjP_PIab{JG zwYScBzS97G=g%tbBN^(I-}77EHPGFPkL!=9e4jE)TwPt0`i$3njEal;Q}(j?1>33c z-rqFu5c56{e+vFmi+u}iI(kN0wi~ZN`tGT)@cAR>#o9*{q=Z+Rn&i^MHwH%Pulze5 z>vL06I^?;&HJ8Qe!z6xdfj%pS`8WX%ZXvWxxOa7K+o8cI~D`T?Im{x8mZKi}`i*7eA+be)YYL9>^KF_iRsnjOrvn zwTqg{(~$GjeeC1*c=hUmi1&rYzDj}`HexPou3&DDYG9}57f!4B) z@u36^0dy#}UHUc+Rkd!ex#1$p=<%!l!I9z* zUi>M5@@G#EnOJkg4>Ks}&mJ_vqE5E{^7)4Un{ri<<2~_~ zM=K{j)|0mp2?cCs{NEOco=rsrqTP(drDW8^RsXtW8yVdhsFjw^pn{P;!NA2V;K7Op zTU(A=Zqd?)W@ob*LtrsAB`zSq$m=z@R2-_H?)dt{hYH*%KVpGTz#-#}%6hk*2m<7f zpV%eP2~z5di@Uo#IdjJP7x8IA+$TFb4~GA$!CF)%!rE~t=>`QSN^Rmg%_;rGAz+o< z36SbopA&pF^y?Q*Cicljwan*%iG=u*fWXELJ1fKZP~*)~=?v<)-Px|pus>Mi$FH^b z+de;jn0w=107dIKZDV717mqV##BBD&SQvE1sn2n_WH7wCPp$*UK1{*_*ian2g7k^F zwNE^B7W+KgF}LqCUBrrQ7k%*J2BFVXwh#Tu%}r93{PXywr=|!#g%*uO+_<&Swy0d4 zHDp}6wI~WBMnG_hk`?V@-Zw4m(B|6Sd~qj9r)(0B z+Lzray>kh6N3ZRNDZai?aU{Van1Y<-TXskNDrPm2Sb*8|1e9BN6nRbHu?}iLnKoU4 z2^-|<-}W@SeKRZ=J7|5A0D)L6`jLd5p8LX13HRj8G(euqj++!~m|P9KFr~06pXz-z zoBEllz}QgS2j8;zK*n3MK#4S}8CbTi8zM}E=`ph>Z@1uGkjZ=F)}`w>zTOnruU}sz z=O)n?zm$0U$sWJy=wGz~Q>174LcJ-DKixTk$RzUqv@KDr&7H3WB6OovtE#HuqiY{>2yd zxSj;GzdC^ZqUZejRJM}Ij~?ZZsI^x#s$IR@|E&pmV8l^>#zG^&5!pgG^m z?(y;CPn^La7JNuT3SYLxB$s0G9e(cuX`s?4?X1Ta%N5L2-kwD#6QL!_E`oRvkihP# zNA)MUP4PQ)+7q&>Jk-^di`;lP`4Z$mB)_PjKjDBEVzmDmKs%Ts)ER@sGcn;YF{Xy< z_V&dfk>|YT3&ILVc+E{sVy(F6&Os;?Z8vgAO=ysuM7|Q3^9{!kR-GR- zyuX4%r-+EC%Du(UkmB4SkI(7P7;@}lZ;9Gq;k|cnFhkIbih~BYa;2Xna?ZLr*6sSH zmhXC&$XOc*I&RIk_3K9sBoqRLY$n#_Y5am9%Wh&nP{}2Kt25k@NhcHt$=nZanr8q! zBzqoRP&{nHNpiFF(KQa0;YT2p`&Y@Fr$IT$b!Ci(4S*&mLXk6{(v>-9%SFe)@})T8 z4wu95=U!kXDdgpf27!n9;oDZ?+1cJoK=3P)=3Lh1BH<6HVkEy?J9Mt z?OaQf20GVzCkqIZB!H)p*Ul9j6*a^$o0?Aqa9V#rKqJiCChyeL3&=}z zbo!g9{%MHGq{g%-vu{Q@kN<%MvIP%eB?6A69H+qyT-W-igFwiE79~Ou65e)f+amVt zz~MJ)(aWikz7vnNZM%4CxcQ~9B`l>92a{fX7=LIR zJzr05rC1Lf+qrkRl#aip!Sg++7@XgFcyZWMl8`vQ3c2Jf=z1|;2v2*ajY;6ZvXCCv zvW`N> z3SR@7U&GaVaMDJ?TYIeBJh|I4A_v3u;{uM2HI z03lJ+-p+L##wj!&9C=aIs&^Ygz}nhGs9Iq^6ZtSRBp6k>XLCxaq=ZR5cmG*w2X)RJ zUm@pTM!*nz{P^w4fXdRCb#I}g+a@hb)>X7Rd$3;zIUPN-b}#8t;6~&eV?kMR>96qB zD}TPA709~E66#YOx4Dr(VxSTp-k&j?z4FYD8=xfd+g!?!gqcHx2#5J!!Fu+XK9?e%ujPydvB{JM0G$E|XV1XKfP zfTBpVZioVzWUHM-qOo%qv|vlAJMHl^Fffo7>}if^fp$h?*1j|J_`*Yhx>r=Wnoz4O zxq-%^{kMML!6WYlx~y%`W-RKP=c%AqF&xMJk2xfCxY%$Q)7x2Kq+e>CwP$1jiW5{` zXlBD=ZG9R+R!~@)&|K>^0YR%LqSj-dPyMpxv3_SPJ&179%XS>cCwK}hQJW-up9RsX z>;zET6AeX;*8&1lG>dJ6Tc-!yZ50*H@pvb6=@SO4`>jtvk5+~j28!mZ>1m_^z485f zlOe|6liBg>G9`ID?~hE;3o3;s$@v-O9fxtpVo$bCYL6vMhvSj~((FjqSY6TA2-lcK^L;-CZP|KIMlf$D=e$aAy(2{&%6dTMkB%i|or=a60L0VN=zJJA z^TZ3>ND7d``+iA5HxWe>;a(Z?vfQtDei4no=^$ zG4HsNx%B(oo?J>uXFwpK;xGpVi`Inqu5!K%b7pq-yQZ{xJxaID>&dI&rwqPPu*)mS zwYrVipM?mhc*0+|Wj4Tf08u%sk2U)&RFnlCV)Yj;YfwmKqTJr?LsVL6#OkW0vnT#5 zP<3ZuNFOLxIPtd3@k&O{lM78Vsi4cTI9!(Pu*LyZlg+_4t(-r*a;TuosW>v*^ofyD zg)KiRN0Q~Q*~?-iZhYiCkJ)$nU>Fp03@@dlOb`|9uq#WtaRL}5OtCvzbd{^^ zz%vQ{bd7AS^F^x*Z<(q=X85zj?Z_)`{DA0L%g;^wZG#nQMCU8}i+dQKCYi-qdrMK* zhc_AJGc~7BMq*2Ar5ll92g6%YuB-1=ZTf5Z_Nto^aoR3Pfy=KDCCn;R<+qu&@B!8p zsKCmpvYzP6>99SfU#)P5e=zqJRahhS%A(=tkSrekfar zPjBoh=2%{0RLInQaa0*~f9{V`>qRk$q|4pW>LQ+!a)lo!| ztvFvng`(HnkPr^XDbl=(;Yn$Ozes2w+g(v72nJQ*@DdwYJwPYAq9$5r%NB{2m(F6$xK;Wl9i%jc#_BYV>ysPW` zVH!+&d3*-lX&axq%DWh5KXUdc=*usdyMJ?q)l)MY7A?rBbpDNnY+wUd!Gf+KQXt3~ zwVtbzmy&86+QI!h`}x*_d>(~9BBF#_nzc}WrFEgyOpn=i`J^(54agLR3x#lthO-lAUN2-?X&TL5ao*VFjWJ`TdlfSGAl{~@!+V>7Q~ zI8tab2txJ(&JYU%>p2c+3S(nXROUb2o`7RQKx-L55vXuQC_H}-ZRX^5L%@kwyyMg)dgC+kxw5x*NSDs1jnXc|_*ukJ|)sd$!3CB5r{sJ`}9rR;4 zc;)BcH!WM>fTqnA#|kFJY|t+G%h{Qa-)WPYpFetQ#L555Bd@y_25*tmx_KzkmkvhYvtsy#VnbbogE&BJ!#k`#NVG7#r&k{SD>i zWTDL-a8$spTc^BgUN=vHuzgfi6d4pY?_4|`+b#rZv%qphlpsJPEIyc3<+0x&u#&n$Ej($xQ0y#IJhN z72q%eKnHp+3g&RlZrGYN@lZ^kSrV+BM+h)7Fc2?z)<9xf%2fFn#! ztmI=qRTy8<5T=^~0x_VF0Spy-I=UM$v*Y7h&{+Ha{rj8n7clu3Yd~Jv0;CVd;XI;j z&C}pke*Ad;)Q?P9O6oF5@mkORz)tQG*3qFJF14vyu$7UL`t}O@w4z?h-w%@$%7SrB z6b*%*l^HmMsV`R-7Z^}~oIQK>`t|ov4x**?g6bq3@$gJcjGB$@W7%S;sg#jM(eFF%C%}1?v)ck>}5! z2hh?T9t}1bRQV%Y<&UUCC;WKv!14JD9zKH%XC}spB|JPFCjJLXLlD+)7~BMxkm<(# z`=5XYb(NH~x!hq5B+hT#zI}%5AJFgdw7q+GuDYfsr{DPP+qc;^7ov8PXQ@cGyO1ie_0O}0`*va$k+ zXJAketobnvs%kn++fNf93;1@=R4EFKiSer$!-_ccV7ULI&MKL9qUNW!q%A0axTijf zx9DSX4p6SUD!4Enawo@mxjt)XTNkH)YH@lbee_a#qUopFv3&|<_g2HP0#UE!B9yd) zz7j{hE#_-cm(W^&1Yf7ET%p0}0RCyV;;pw5VzY!2(r=@aiKZwM7AlWU!ivsA_SEGS zIMM54OboJfcXoC%G^%32GJ!n|7jzSllamA42-x6Z>_&tg9UXkjUr)oXFo*i1C6Kzb zh;hI+>NbbK$q<5vd!t9vQc|zM9k8(Yk@MQZX>JXTjjzL!TvjgNWv`AaHR=SHIJ{8j zh!3o>pYKlCJ+Q0gF?Vv=H!boFDgU!lXX`{h}LT6J^$=AiiXt> z(ph^;%BxLACHj_hU0xXMS&FOGL}>r%xB6~0cRIgm>u>4W&pZoRVwz}^e*6anto&VCz?|lY^zG|Ygp~qJMpzHf9}lIJub2%EgLf5Y z+^;9!&Z{U6*_+Xu*ti}wz!)brD!D}de(YXYNyaODG~u1Kp{%z!F9(`$CbRz1cXEFG zr~lCx*7mm1CTep78Hkot?_9iinioe{>f1$e@5xTI!pd529FD`2-~zsNITBOJVSO#jSmIO0^74yx z276B3EUue}6oM)m)kOP7vk#dwAPnst2Mvm*9jHW52mOU z)So5(V}R+R@VT1>pFK(JhB>&2-A6~_%X3M1juv>C2+!f?uC0Y=(QMA0Bi_%=eAh`r zbk*_6+CrUk8}Xm@Lg|*o1Ke+lmv2z)@({#gyB%3xja-a1zd7?6ZqYBM!l%M*2&D^{ltGXe*S#^4FpSD8lp?Kcg$AGXzy+Y0P=J)2G@SgqdAWOfWc zY<;=z^Z^(5g@W!d59bX2hv|?U3#@$?>06Bf*k%45RVODltx!UQH)Pq&e36XnBY4KU zz=|MbRTl#v4dw(Sk;(AR!Z=yab$UPugo{Fpdf|~T+w<+ip-I_`({xTrru_v z{LA}|1p)QoRw1;Xp2O4gf+oyy*|{MZorbxhM#Rf*qnsko{4B}XjPT2Ps!0_t(pKe$ zL<%ZeeYLf`;k2~y#GPlgNLaZ1!02Y=s!_3-w6uGOg73S;++Lr>oa4}GI|xEGP+0!D zxiARyT^e@w;O=f&EiJ9SVhbwRMniU^E+0tPy+IPN&}`JNc}nZ&*VpzH>Ja&4P(#VSwB}TuoDq>^}zLN^+xMISDd3xba!X; z7ymLemr8jvnLCzK%(3?Z%#qz3tSf1MY)DO5QZ^88k3%KKpwT~N%YMbuth!%EP)@h11B}^drNK7#F(`S`7J+}liIpSPUxG2n2 z8(g5eQ)d}dVtx+)=!+nM1U|lNNx&OR+D7s>7(AW_V^k%N*cANcPJL~+^GA&yHlS1a z_&F;GvIeTUi(M{?pZlg+wAw&VUq&hAY|i4JRN4^0y^!A})(*jUQmO+)3Q5y8bDbc` zc0!{*K00#?svnSFAD74sqO5+GRLnZ!o+M4XZ1(FXP5V*`9{%uEets=4%<1x{Dd9el3<5X|9b>s*M zBKJ zso)*Tdcm$vr&BlA-!j~&*kTd?^Uq*8DQtyaU6a`X*Q`=ZX%A%+IAOH3#CM&!e@c?6RGxp z)=dO7shYZc{CJbX1{=;ve?cvGK>+k>dJ0WcfLj-bjN zTxe=+)9(XX`@85U)`0}X0Zb=;)$WwqnGvAXQ8p5iP1%Y;fLD$p4BD2u0xo&74$$;Dm zXebz1h+b_t)fr*+P9 zZWI6Nr%y^Lq9K0s1mEf3|tgEyVbQ~P=&7rJl z$kW-KHjNK38b{K4dP${rODv(yiD26a2niWDITc{#uWoHAV0trqvNaz;83|Z)7r+HT8qjW(baizNJK{V-n3Uoky5lr1*cw3+ZCRoUj<1NaPNje-5fA*=S?XO3^BTFh{U60Vk}fQs>>;7@}Q1BgVp!f8t$wC!OV zWdQb*CKdnGaix~XX2O?~fs0F#(q%mWN>cDV*C;7bA3y#H6Wutm@^Y#vSh>tL69=Cn z1B@O$ECLuR*-YgEYfw`Z#@;Y;96G+~&%4Obva(9*@08mIfiSatb5>r5n8}!O_u~+uQbu2?-4_%14I>Jod|zr!NPi$iyTj$+z+r#)AOnqUz{iX`sX^`O1|mz(6D*C(i`5^5w>Sk8+V| zG_0X`K;fQAB+D3~vwA?G;Zsyp1|;$6<>jih5>d}#`~YrC0utbpr%w%Me|!NQ4X%

O+2+QUh-rEqm-=mBj4+s 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

bQ_}uDT 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 E14DKW7ytkO literal 29164 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 JiLzDb{{d!~rK$h` diff --git a/generated_examples/napari/mg_execution_times/index.html b/generated_examples/napari/mg_execution_times/index.html index 9c17bc744..3207041bc 100644 --- a/generated_examples/napari/mg_execution_times/index.html +++ b/generated_examples/napari/mg_execution_times/index.html @@ -2885,15 +2885,15 @@

Computation times#

-

00:07.525 total execution time for generated_examples_napari files:

+

00:07.838 total execution time for generated_examples_napari files:

+--------------------------------------------------------------------------------------------------------+-----------+--------+ -| napari_combine_qt (docs/examples/napari/napari_combine_qt.py) | 00:04.805 | 0.0 MB | +| napari_combine_qt (docs/examples/napari/napari_combine_qt.py) | 00:04.907 | 0.0 MB | +--------------------------------------------------------------------------------------------------------+-----------+--------+ -| napari_parameter_sweep (docs/examples/napari/napari_parameter_sweep.py) | 00:01.863 | 0.0 MB | +| napari_parameter_sweep (docs/examples/napari/napari_parameter_sweep.py) | 00:01.766 | 0.0 MB | +--------------------------------------------------------------------------------------------------------+-----------+--------+ -| napari_img_math (docs/examples/napari/napari_img_math.py) | 00:00.824 | 0.0 MB | +| napari_img_math (docs/examples/napari/napari_img_math.py) | 00:01.133 | 0.0 MB | +--------------------------------------------------------------------------------------------------------+-----------+--------+ -| napari_forward_refs (docs/examples/napari/napari_forward_refs.py) | 00:00.033 | 0.0 MB | +| napari_forward_refs (docs/examples/napari/napari_forward_refs.py) | 00:00.032 | 0.0 MB | +--------------------------------------------------------------------------------------------------------+-----------+--------+

diff --git a/generated_examples/napari/napari_combine_qt/index.html b/generated_examples/napari/napari_combine_qt/index.html index 745b990f8..c3b2d6c6c 100644 --- a/generated_examples/napari/napari_combine_qt/index.html +++ b/generated_examples/napari/napari_combine_qt/index.html @@ -2960,7 +2960,7 @@

napari Qt demonapari.run() -

Total running time of the script: ( 0 minutes 4.805 seconds)

+

Total running time of the script: ( 0 minutes 4.907 seconds)

Download Python source code: napari_combine_qt.py

diff --git a/generated_examples/napari/napari_combine_qt_codeobj.pickle b/generated_examples/napari/napari_combine_qt_codeobj.pickle index 74d27c63d4e59ce83f1be7ab699c6031d5117d11..b4fc653325fe0eca60369c063b694273804d0361 100644 GIT binary patch delta 907 zcmX}qT}V@57zgm4*K?f5ZMyj}=eD!W%=wu*F+UQsVikoERD?HLlIih)B8p~UC}CM> z;QU(w$eV}XyXSvi#yS6~$jyi{q+ZF0 zD#NfRuQMYP4#!rD;WKQPdQU}1nkXmwah^&MOxLkMZB)sX%Z%+f$i`?Fp8?dSCo&^~ z7ja$${L`my-FXtV+!l5}SDU^cOa z`q7!>!g}H!8pNRUC^If#%I?LWeK%dkH@gc-wrUL6bQCAm(REDQ+G#o#oY@H8-w0l_ zS}|fvk>N#ta~*E0r|B8|@vrD5>MVH(TKx2ytD4@(b5nwq-eJyifZp?20H5Zh6)Ca# zjAAW>@q`e4ky=i0)0&jXedh|(51i1d=qI1qSkN5wTWU?S(_gG>wW`Tz(pin$(EfMHyTrDMNOuYf>OmED`jISb3cXn z%$J*dDX}TSFHa7RdqPwqHREwpnUuI;8&@e+p~zcFHGFPHkf)3CCBK(?q(r7qif7mv!cbNYmV?=BAV!{KgE8_bJ11Di&J!MH6|jqhw^?CjRJ_i5 zwLD~wbBU6joy;>VV{zTRos)((7T?+2)!f}aX;@8&=v?XwFOZ%dBIwET2>n=e`#*dSRbUMy;DZUv@bV|@`qmIdE(O`^2sWF_%eH_!6 zJRoj_c@b0U47!3ojTOnkYw0@rB`Z3EvuG5Pp?16v&c->74r#6&CXb`pRm|i`JPWC$ z=l_#a|C00$iLOmd{y3le!nJUHBiD_dS^`OSIo=$LGhF2ylofb4< z)>1Dj&2HqGqp6=$I$aR8;#`7rQ9S0%5?$uBnubNKIM+~MiQ$hahWTzN*lmfRTjI`Z zG4q)gSd!^B_F2;C9@iy!X))25AVZj*9v~`g4L#)Q7S3ZqquiOqc-Ro1d6(6L!SHE% z%gM{<{nT1WAGj_@!D2g23%VN_PM-wLMd;}>vLaUEmo=Wga>}FcqE<4qcoLCGzoCoV nzycWbkugdW7C4VQ!PN7}+ptiEP+J1iF{Ii&S|eN7XI;`?cn=@Q diff --git a/generated_examples/napari/napari_forward_refs/index.html b/generated_examples/napari/napari_forward_refs/index.html index 39f044bdb..e6e955021 100644 --- a/generated_examples/napari/napari_forward_refs/index.html +++ b/generated_examples/napari/napari_forward_refs/index.html @@ -2956,7 +2956,7 @@

napari forward reference demo# you could add this widget to a napari viewer with # viewer.window.add_dock_widget(subtract_background) -

Total running time of the script: ( 0 minutes 0.033 seconds)

+

Total running time of the script: ( 0 minutes 0.032 seconds)

Download Python source code: napari_forward_refs.py

diff --git a/generated_examples/napari/napari_img_math/index.html b/generated_examples/napari/napari_img_math/index.html index 48028d045..2f7df8c83 100644 --- a/generated_examples/napari/napari_img_math/index.html +++ b/generated_examples/napari/napari_img_math/index.html @@ -3413,7 +3413,7 @@

Code napari.run() -

Total running time of the script: ( 0 minutes 0.824 seconds)

+

Total running time of the script: ( 0 minutes 1.133 seconds)

Download Python source code: napari_img_math.py

diff --git a/generated_examples/napari/napari_img_math_codeobj.pickle b/generated_examples/napari/napari_img_math_codeobj.pickle index 49c9e16e0207da5df74364756b907cfa0ce100af..61d227eae19f44939397d816eeed7a224e5697fa 100644 GIT binary patch delta 1179 zcmYk4e`s4(6vumRbJHX*%S)T2X`8&Hrc1LQHKwI?V`VLKqGK>N++R~lj9Ki>U6O{T zac2J71fg|tvYqEd#nCbm+>efKD3vjB_?JPf{v`~dAc|taIZzAAzF}KuhrA#qr)@k+mYAI{h z?Zv61)q*tCakK8WjC6%fP0yIjRd?ho>1-iWshBv?86ix^JNgOe!fW2mSo2sOfec?sJpaFDP8{Iz`_VULJyE2_Yd!VfxJgpJ^(j{St~6k8l4z93s?>M$$TC`x@A7u^jwFV>LT zUdog+(|MC=>^+>{WWq=IlE;vjS1&B#@#qj?pW$M( zm$1+AjGlxq@RlBi+gJ!ZLs;WnAVt^;js$k&LeB}pe#G9;Ucy$z_7Kj6L~}n$eDDRo zV0U;ku7||Pe-k)N*qU-uhUoGSTnYE%<#3d+djiE&{!)$#uAhsumMc7R>1F`SKf!KvtGWD~e?Jet5iBb}ftN=CiVA!yhZfR+~g+tW{Z zk0e76jd4Q|bI(Od<*zr@n!SheH!QV-^4X@ZYMqwqmOUwQx;@4Gi}_MTwtdF3_fdYfd7uG)%FU)y z$?r;ayDe@#$S}(GEWuD*f zKl9Aq&2wes>WH?)R@Roa+Ydy>=ca4UVtKae6}{dgUazZFotbIRy=B7<&CDLGS7aD2 zm1dlBwN&z4J;+K6e73ge@u(XvFO;S#&ccF+;bfX|gX>S9J=97G#q=oU56H3^*^W-i_bHTLqkO+Y)p-E#br!IcPGhw*Lixi|$0&b9rRr=^p*lN> z;~DuArex_xF>6r%82-!*QC^lMA0!pbXJs-g%X(77wXE!_%d+0}I2`LP$`8wu3%ZWV zm)J@9arGeT=BIEmG)10AU(9^)Tjchn=FBNMZ5Bl-~e%BOgE?umm=b+J695`c`}a^U6-|^vh8edONfx?{Il8%((#YJ#KbE; z9c#XyiPr+U4Zk$YKk$0PCe4_(>PscQ1$*Oi0w)3+Wa91h-1vWj;-sJLH+t|_T+ZQi z!(NQbX}upT(tH7056?aSO5S3 diff --git a/generated_examples/napari/napari_parameter_sweep/index.html b/generated_examples/napari/napari_parameter_sweep/index.html index f5738c58a..7dcd827ad 100644 --- a/generated_examples/napari/napari_parameter_sweep/index.html +++ b/generated_examples/napari/napari_parameter_sweep/index.html @@ -3339,7 +3339,7 @@

Code napari.run() -

Total running time of the script: ( 0 minutes 1.863 seconds)

+

Total running time of the script: ( 0 minutes 1.766 seconds)

Download Python source code: napari_parameter_sweep.py

diff --git a/generated_examples/napari/napari_parameter_sweep_codeobj.pickle b/generated_examples/napari/napari_parameter_sweep_codeobj.pickle index e2f5600ad15875af85f2c1adb5215b68721eebe5..41485c620b05c28620bdc715d7de621d47a9f1c7 100644 GIT binary patch delta 1403 zcmYL{Z)h839LJmdF3+XCyX3N7lIG9NG;O*zZPPZcHf?l&trNv{!{NW;y4Xf9N7mM+ zU2!jD)uBvN+WKUJ$#fu!#W8Vg=$MH0g(B$0z1SPU7lN-g97B+S6YB4t=Z?I2zMt>+ z_lJ9q=VX34FP!k4eq&8Y(^u6Vu_{a#juvb5yc(9O-KWV$e0m@Cx`$p~X~Af9(C zr|1!)Ljvu3AS)Otgg*jN!RSQzGnNsIUW7>eA>4I>SQ~#OoiKvgeeyiI`y@#h#k5U- z5eY`IcF>!m_r$I6xXq7v1Mno{e%O!ti+3Bn;7!0m#yL1-XZ?*5Jd3>9*hVY94tT-l zi;XStqRrN>BaAaJiQ3;Z2rn~D(2S%)$>y({6euI_mQwU?QwU~kwtD6mXJNrm)_&dz z$I<#+))lWy)}^+|DR>*RF?kQX!}I}qSq{On&9`LB?g4-ts!0OI!A{vx9DGvS8fCayiycdz(8kwur@lW4zqlBN+c63}|V(EBF}J z2eiZNOk=+$nhmao2D`qgDFnE^70lS}7L9A$apYETFY(pOR(F8gtD!VqjcG)4><9^S z+z7YQL`y_nEKR*qoX6K~M(c%fEh?IN-LvmWI6gz#IR4(!gFD(tN8Pf?uDWNFJ&qqH zeH`PFA(C~ljm}0@GRW$sU-7Pfh z9>Ub3%W{xb#UOJ@(VXQyT@a&p+#{HFLAPiw*3)jGNi>ghzXaphu>?B(7gW()a#EeL zu9Mua2oZewDY__xv3o_>$Ib}7E8xsZy+`-p=J&Yo_6%cJ(PKT6_dWPsAMkv`Gm6QE qCl-=sUz;jS&zB}M#|Ert@UhbnqhmxC%}=?9&5miYC=@D_&8(STjyBDj zMl8&!W8$irYj{sVrxt{Ptiv(zpMiCM$ep52suX8V*bU{mdSz<9JX^6FWM;NhpJv|idU<-j zT&dX&O?by@=Iq?OZF(C@xpr)7x>&2(^k}5u(r8oO2O(3V-^hDV-SQP+Gb+_Tfa<-- zh+8{HKX)ZyJDRTOIGRsJM{spTBlJqtE17#RSdC7gwHh^OE~ZQ7UTzum*%;>gQJjn& z!Te+_A@W0Pma$DTA4A9+?6-L%N2jF#H`>5U#fHxdw`FZ4J=@2aOx{c@5VV1vx93yFZ zs$(m>>+o7f1m1UeQVPH_=Nx>5^>MNrF7cYAhh-f;7Oem894lx(Bll5N4#Ou7v*v4@ z2jEkzm$f`x$NHm|g3qvem8U^ltka!Jgq~JZxQX6vVJZ-Tj|3gA4!YoLT4{s*SqPGuN%V)ojYYKBa$yVcgR*&uoB47gg%NL zjNa1Ooo2MIhsaQ?WsnpECc1J?HzU!V=sG|~+cA5B!$RKg%FywiZZg)A50P(#8w+{X)7&;18B C=!&%f diff --git a/generated_examples/progress_bars/mg_execution_times/index.html b/generated_examples/progress_bars/mg_execution_times/index.html index e801f6586..dc08e2f54 100644 --- a/generated_examples/progress_bars/mg_execution_times/index.html +++ b/generated_examples/progress_bars/mg_execution_times/index.html @@ -2885,15 +2885,15 @@

Computation times#

-

00:00.191 total execution time for generated_examples_progress_bars files:

+

00:00.184 total execution time for generated_examples_progress_bars files:

+---------------------------------------------------------------------------------------------------------------+-----------+--------+ -| progress (docs/examples/progress_bars/progress.py) | 00:00.059 | 0.0 MB | +| progress_manual (docs/examples/progress_bars/progress_manual.py) | 00:00.052 | 0.0 MB | +---------------------------------------------------------------------------------------------------------------+-----------+--------+ -| progress_nested (docs/examples/progress_bars/progress_nested.py) | 00:00.048 | 0.0 MB | +| progress_nested (docs/examples/progress_bars/progress_nested.py) | 00:00.047 | 0.0 MB | +---------------------------------------------------------------------------------------------------------------+-----------+--------+ -| progress_manual (docs/examples/progress_bars/progress_manual.py) | 00:00.044 | 0.0 MB | +| progress_indeterminate (docs/examples/progress_bars/progress_indeterminate.py) | 00:00.045 | 0.0 MB | +---------------------------------------------------------------------------------------------------------------+-----------+--------+ -| progress_indeterminate (docs/examples/progress_bars/progress_indeterminate.py) | 00:00.039 | 0.0 MB | +| progress (docs/examples/progress_bars/progress.py) | 00:00.040 | 0.0 MB | +---------------------------------------------------------------------------------------------------------------+-----------+--------+

diff --git a/generated_examples/progress_bars/progress/index.html b/generated_examples/progress_bars/progress/index.html index a2bb79ef9..20bddd709 100644 --- a/generated_examples/progress_bars/progress/index.html +++ b/generated_examples/progress_bars/progress/index.html @@ -2945,7 +2945,7 @@

Simple progress barlong_running.show(run=True) -

Total running time of the script: ( 0 minutes 0.059 seconds)

+

Total running time of the script: ( 0 minutes 0.040 seconds)

Download Python source code: progress.py

diff --git a/generated_examples/progress_bars/progress_codeobj.pickle b/generated_examples/progress_bars/progress_codeobj.pickle index 04567d93d8c3648ec8bd14c7135ebd384d2564b3..d2ced26587a7ad90b6b4c8704ba6a41f21032afc 100644 GIT binary patch delta 342 zcmXYtK}!Nr6ot8yGxLU&1dT|r0<(-{2q8iWqBcP!*wRIW+T+#jTu?6D z;Ni9_PUWf>!M2J$k}>0g2tk>p_6wDb7*Zsu}-}5ov7SwW^M3TRzu3R&mV($Fz=pKFoa{?wsW% GSN{V5-EENo delta 361 zcmXYsO-lk%6oxtDeB3FeNQ1DuW3M9{8(5VdPx2rcR_wCXyxd)}9a_i+00e*8*L%kEK?nMP0va;+fei>zuJflu~5 zR&ysbxgV$Fb#(n%Wap3cKm_r8=) z(P+ox!(5k|4Z}DX*rIFkBix)r0X`s)ePFPPWnmH4@Kea(o$wB&kY2LEBF((a9@Ku=&bBmJ>ZOoHlKI5drIbM*V-{GWzkIy6zm-tPV;F`aX!h)KBn~;8# LadJC&-SG53f6aH) diff --git a/generated_examples/progress_bars/progress_indeterminate/index.html b/generated_examples/progress_bars/progress_indeterminate/index.html index 69768746d..fbea6bcbd 100644 --- a/generated_examples/progress_bars/progress_indeterminate/index.html +++ b/generated_examples/progress_bars/progress_indeterminate/index.html @@ -2951,7 +2951,7 @@

Indeterminate progress barlong_running.show(run=True) -

Total running time of the script: ( 0 minutes 0.039 seconds)

+

Total running time of the script: ( 0 minutes 0.045 seconds)

Download Python source code: progress_indeterminate.py

diff --git a/generated_examples/progress_bars/progress_indeterminate_codeobj.pickle b/generated_examples/progress_bars/progress_indeterminate_codeobj.pickle index 6b53dcceef847facc868c25ec6511d9ebadc7957..69a5f1d4085be71c308d672a41155c94d3b13bff 100644 GIT binary patch delta 373 zcmZ1^wn%J(o*HjSMp0^FN_=^KQFdz4l-Ma6wNo^DSn?8cQ>XNBq?P6+mt^MWO-#0& z_&J49baDiv3Zum2x18~eij#f0oESAGPv8n;)z9GRD4qO=(`a%%;~hqa$qSfdCs#5B zGP+Mb&7{WYHF*QG@?=rw%Z#C5)_OKx#)!!eSk!@H{*x!L^e`rac_8t$$z80$^;-wk8$$k6;S>(AWM&N=41{|8L<2uAWMgF{$x{5UB*R|lQ}gRmx5gn za={8P>kg-Y^y&Gd6<_DAfZ10U~`s delta 376 zcmXYs%}WAd5Qmvv-48$dz{OBB1pDxyTR~(+UIMQbL{Wr@)yBK1tF5~Tfe=K2u~0S} z)U7;4hoW=;L6-v0b?V%qd(hiUmmkkFGcYsVa5sFeMtqiD)zn5s)9P-)O|{&V<1tEA z&Ba$=yt6ioqCd3IPXcXQbAlEzwbE{}Su@L;`9DrXN7}QE9ZRnnE|DE++tw?VZZurt zCkhF4jw=xFe2+i^^V|nyknnMw5vS1P6EKa)k3klnJV|`#d$34p67sm@9jCsG8(s%i zm<5C&tYTEi!aB_)zDNVGi3Kr=H^L_n?3YIIUQ9xnQQi~fh(U24_F17O1;N4xDTX;g zfhMIi9AKY3jL)(HElMgJVx9UH^&?6uoZy=rWBoRzG&uMpXW)!xgss0|uUtzCTr&DQ e=?aIS2)8)Mh42(6;10haf<4H=BdyJGw)zVl2z9^! diff --git a/generated_examples/progress_bars/progress_manual/index.html b/generated_examples/progress_bars/progress_manual/index.html index 841bc53fe..bf0403658 100644 --- a/generated_examples/progress_bars/progress_manual/index.html +++ b/generated_examples/progress_bars/progress_manual/index.html @@ -2921,7 +2921,7 @@

Manual progress bar

Out:

-
<FunctionGui manual(pbar: magicgui.widgets.ProgressBar = ProgressBar(value=<function TypeMap.match_type.<locals>.<lambda> at 0x120e83740>, annotation=<class 'magicgui.widgets.ProgressBar'>, name='pbar'), increment: bool = 1)>
+
<FunctionGui manual(pbar: magicgui.widgets.ProgressBar = ProgressBar(value=<function TypeMap.match_type.<locals>.<lambda> at 0x1255b65c0>, annotation=<class 'magicgui.widgets.ProgressBar'>, name='pbar'), increment: bool = 1)>
 


-

Total running time of the script: ( 0 minutes 0.044 seconds)

+

Total running time of the script: ( 0 minutes 0.052 seconds)

Download Python source code: progress_manual.py

diff --git a/generated_examples/progress_bars/progress_manual_codeobj.pickle b/generated_examples/progress_bars/progress_manual_codeobj.pickle index 494fc43e8021f97fe9a7b7c90139f178eb1543f0..23ffb308c390da6c7682c72d371843e0d7316db8 100644 GIT binary patch delta 496 zcmY+APe>GT9L0I=zj3GEjG~tA;I@O^Nqdy>Z5+Nce_SDG^LG_!t?d9=#-|ss-9@9*3of@*us$;Gg z4Xbw3oA)y7UZxqYns&)!uhQ4ujM}wjXT^7+KCy7ssV-fw)T#?*r{b;|oKc4PP|0&n z89_f^1?~cpY%3>`VsG~$vQkI+@rXc<|Kj6ZjPIiukbj%vnp(tZsiS!R>JSqmj*EdiCz7}n(54u`oTLIS^Rt-56-KliOct~PmRZsal)0m&xU2W$nj`}@ z54B0Ga$L`$!C8F*H+Wai;#Sbu&)p8_kKThjoQ~yjkL$6qWA`nw;gp){OubgFml}<; zX5F92Z5`!UEX&oX;yxM17F$TVUti;qgbcR%4*Pg2HK{4KS*|R}tvpM$p7B%HHl9mO z^Fe3;FMR5ZyyQeU!C&EN7Q=PC@m*(NhxtfK2Hs-Nr_SdWev7p6ogbnJ{NT^%@le|m N?&CpOHrM4C{{a|_sA~WK delta 500 zcmY+=!D|yi6b5j9>c1ptnlE;z1A*6bgbUNDDv=uHp?#yl1p9ws}%X7hah9Ob2yb?`exTC{I&T=nmb0zv7V;vnHUSz|{ zh~Xt(wvvoncQ7H6)0kv2mf~CM8>TrQv*EHG>%(16={8670losEaRPJfQ*zwI29~4@ z)x^`+TZ#fKb4xkNPSEDKn&YUN#7m(eyyA^6o6prh_&`hR7q{fFDmA9qiuY0Q96rgQ zqM7)@6|G0Ee-+AOon|P*>!BnzgbMi1>i_Nested progress barslong_function.show(run=True)
-

Total running time of the script: ( 0 minutes 0.048 seconds)

+

Total running time of the script: ( 0 minutes 0.047 seconds)

Download Python source code: progress_nested.py

diff --git a/generated_examples/progress_bars/progress_nested_codeobj.pickle b/generated_examples/progress_bars/progress_nested_codeobj.pickle index 409bf15dd35764db6d8e7ac3ac168707761c7825..c61a4942c8bdf21833b8496775f6ed22d67e93f5 100644 GIT binary patch delta 877 zcmZvaOK1~O6oyI9Jd&B*5Ns97?WvcVluIv83iHT zh*)73(L1!qKjlU9h@0F9eIkv}CMQABpZB;p9Q4^+Qf9mtDyTs|0aK`1J`K~TmA|;%!l9}W= zjok1%@McR@FM2IFOUHA^&np_a`FLt#VJ9Tiw2odwGvo+Mic#<2KgpVoJq80sFi>X$ zDOf~3&9|_}3x1Z3d*~IJz%tfL!cnZ0ggEU91g>G_jxYf$s6{bJzYE9EEsFDOOw#q> zFi_vy6bal$-WD&QyDg^aDe;g`UhXdQ($ve{L#~FB^h9U~?lUgI15_HClm6~lriaBG zJtGa`N3zlkj!h{IPcb$skJIb?E*h12`c4YNbHDaWio;9B6PEP~cAaq!Hc%z9AHJYg$UgXr>K$2^48b>_ACYMJ whj%loBUpGB4b?sCX8NxsxL_MKOYa!$#hkbGmZck}cU4<>rORc(TV@x214We(^Z)<= delta 792 zcmZXSPiWI{6vs(lnxskE6>N2`TUc5vb;G*Rje*J-17#o#MPclqqqeobV4J!np$gNh ze~7aB%W)tGqM%d;13?g`f}%JSlzQpGo8X}*4<0=DlKyU(!wZFZ#$LNVZF7zmpjPt<8s^1s`sT`39If|*WdCMEs&UvrZYhKKOKJLB#+?OKQ%cd}${tqjN^GAv%fbVE;)a@`T_pn#88;Deocrate class methods with magicg assert a.method() == "a" assert b.method() == "b" -

Total running time of the script: ( 0 minutes 0.034 seconds)

+

Total running time of the script: ( 0 minutes 0.052 seconds)

Download Python source code: class_method.py

diff --git a/generated_examples/under_the_hood/class_method_codeobj.pickle b/generated_examples/under_the_hood/class_method_codeobj.pickle index 7d88aa0ff56cfebae238062af43464f349768a2c..d04b8e67ed5ef242fa71884a19c1823763340297 100644 GIT binary patch delta 473 zcmXZZ!Alfj7zS{k*_m->XLg)jMmET`#cd61cQX_^3V|?(YV8z+MccOS>|kq!LrSqE z85wwJee@7Pmrg4S1^of#9s z&oh?--b##dLeD9_gsv_&^o-;yJdr4LM@1H2&}?@UKY93eE&jzkeN+aOWt5uF2TXtH IxF`jM1IGrAF#rGn delta 454 zcmXZWZ%7ky7zc2_x4ZM)?%F0(g5?m$8m2pjBE3vV!d}R|5F#*wHHXKA73c;FQBj1A z{^0RtYH!qD^+H9#cR`CJh)_h?yCUjc80fpA7ZU!weDm=6ejj*v_7a~H^0ZQ^y7Dy% z8TWd>QO;+cYXe2=fs@OQbGflivBS1rq7vSb>=-S~B1u<@^ABq1@-(j)=-~%nQgjw~ zeJyComputation times#

-

00:00.075 total execution time for generated_examples_under_the_hood files:

+

00:00.090 total execution time for generated_examples_under_the_hood files:

+----------------------------------------------------------------------------------------+-----------+--------+ -| self_reference (docs/examples/under_the_hood/self_reference.py) | 00:00.041 | 0.0 MB | +| class_method (docs/examples/under_the_hood/class_method.py) | 00:00.052 | 0.0 MB | +----------------------------------------------------------------------------------------+-----------+--------+ -| class_method (docs/examples/under_the_hood/class_method.py) | 00:00.034 | 0.0 MB | +| self_reference (docs/examples/under_the_hood/self_reference.py) | 00:00.039 | 0.0 MB | +----------------------------------------------------------------------------------------+-----------+--------+

diff --git a/generated_examples/under_the_hood/self_reference/index.html b/generated_examples/under_the_hood/self_reference/index.html index 053a93eea..4eafa1112 100644 --- a/generated_examples/under_the_hood/self_reference/index.html +++ b/generated_examples/under_the_hood/self_reference/index.html @@ -2936,7 +2936,7 @@

Self reference magicgui widgetsfunction.show(run=True) -

Total running time of the script: ( 0 minutes 0.041 seconds)

+

Total running time of the script: ( 0 minutes 0.039 seconds)

Download Python source code: self_reference.py

diff --git a/scripts/__pycache__/_hooks.cpython-313.pyc b/scripts/__pycache__/_hooks.cpython-313.pyc index 2655758802b97a32e08c5fbc78aa4c91ac281478..be04b5bece9cbc2dfd46de57f995f18b22ab6f07 100644 GIT binary patch delta 19 Zcmeww^fid1OP--1)l%_ delta 19 Zcmeww^fidmagicgui is a python library for building graphical user interfaces (GUIs).

It aims to speed up data workflows by providing a simple, consistent API for creating GUIs to control various data types, that work across various environments.

GUIs may be built manually using a variety of widgets, or generated automatically from python type hints.

"},{"location":"#magicgui-organization","title":"magicgui organization","text":"

magicgui can be thought of as performing two distinct tasks:

  1. Providing an simplified abstraction layer for GUI frameworks, allowing you to use the same API to create UIs that can move between environments and frameworks (such as a desktop app, or a Jupyter notebook).
  2. Providing a mapping of python types to widgets, allowing you to autogenerate graphical user interfaces for functions and dataclasses by annotating with standard python type hints.

While there is some degree of customizeability, the emphasis is on rapid development of relatively simple GUIs, with minimal boilerplate. For highly customized GUIs with complex layouts, it may be more appropriate to use a lower-level GUI framework.

The API is organized into 2 main levels:

magicgui API layers"},{"location":"#python-type-mapping","title":"Python Type Mapping","text":"

At its highest level, magicgui provides a mapping of Python types to widgets. This API allows you to create graphical user interfaces for your functions and dataclasses simply by annotating them with standard python type hints.

Type hints??

Type hints are a way to annotate your code with information about the types of variables and function arguments. They are completely optional, but static type checkers and other libraries (like magicgui!) can use them to check your code and/or provide additional functionality.

Typically, they are provided after a colon following a variable name or function argument.

In the example below, param_a has been annotated as an int, param_b as a str, and the return value as a list.

def my_function(param_a: int, param_b: str) -> list:\n    ...\n

If you are new to type annotations in Python, here are a few resources to get you started:

  • PEP 484 - the Python Enhancement Proposal that introduced type hints to the language. (See also: PEP 483)
  • Python docs - the official Python documentation on type hints and the typing module.
  • The mypy documentation also has a lot of useful information, including this cheat sheet
"},{"location":"#create_widget","title":"create_widget","text":"

magicgui.widgets.create_widget is a general function, used throughout the library, that allows you to create a widget for a specific Python type or value:

from magicgui.widgets import create_widget\n\n# passing a type to create_widget\nwidget = create_widget(annotation=int)\nwidget.show()\n

# passing a value to create_widget\nwidget2 = create_widget(value=\"Hello World\")\nwidget2.show()\n

For more details on how magicgui maps types to widgets, see Type Mapping.

"},{"location":"#magicgui_1","title":"magicgui","text":"

The magicgui.magicgui function is one way to autogenerate a compound Widget based on the parameters of a function:

from typing import Annotated, Literal\n\nfrom magicgui import magicgui\n\n\n@magicgui\ndef my_function(\n    param_a: int,\n    param_b: Annotated[int, {'widget_type': \"Slider\", 'max': 100}] = 42,\n    param_c: Literal[\"First\", \"Second\", \"Third\"] = \"Second\"\n):\n    print(\"param_a:\", param_a)\n    print(\"param_b:\", param_b)\n    print(\"param_c:\", param_c)\n\n# my_function now IS a widget, in addition to being a callable function\nmy_function.show()\n

For more details on using magicgui and magic_factory, see the magicgui decorators page.

"},{"location":"#guiclass","title":"guiclass","text":"

magicgui.experimental.guiclass is a newer experimental feature that provides an object-oriented alternative to magicgui. It wraps dataclasses.dataclass and adds a gui attribute to the resulting class, which is a magicgui-generated widget that can be used to control the dataclass instance. (The widget is only created when the gui attribute is accessed for the first time.)

from magicgui.experimental import guiclass, button\n\n@guiclass\nclass MyDataclass:\n    a: int = 0\n    b: str = 'hello'\n    c: bool = True\n\n    @button\n    def compute(self):\n        print(self.a, self.b, self.c)\n\nobj = MyDataclass(a=10, b='foo')\nobj.gui.show()\n

For more details on using the guiclass decorator, see Dataclasses & guiclass.

"},{"location":"#widgets","title":"Widgets","text":"

At the lower level, magicgui is a library of widgets (the individual elements that make up a graphical user interface). Each widget is customized to display and interact with a specific type of data. In some cases, it makes more sense to create and arrange these widgets manually, rather than using the type-based autogeneration features described above.

Magicgui acts as an abstraction layer for a variety of different GUI toolkits, allowing you to use the same API to create UIs that can move between environments (such as a desktop app, or a Jupyter notebook).

Currently, magicgui supports the following backends:

  • Qt (via PySide2/PySide6 or PyQt5/PyQt6)
  • Jupyter Widgets (a.k.a. \"IPyWidgets\")

You can use magicgui.widgets to quickly build graphical user interfaces.

from magicgui import widgets\n\na = widgets.SpinBox(value=10, label=\"a\")\nb = widgets.Slider(value=20, min=0, max=100, label=\"b\")\nresult = widgets.LineEdit(value=a.value * b.value, label=\"result\")\nbutton = widgets.PushButton(text=\"multiply\")\n\n@button.clicked.connect\ndef on_button_click():\n    result.value = a.value * b.value\n\ncontainer = widgets.Container(widgets=[a, b, result, button])\ncontainer.show()\n

To learn more about the available widgets and how to use them, see the Widgets Overview.

...details

Behind the scenes, magicgui declares a set of WidgetProtocols that each backend must implement, and every magicgui Widget is a wrapper around a backend-specific widget. Most users will never need to worry about this, but it's good to know that it's there if you ever need to dig deeper.

"},{"location":"#events","title":"Events","text":"

All widgets (whether created directly or autogenerated based on type hints) emit events when their value changes or in response to interaction.

To learn about connecting custom functionality to these events, see Events.

"},{"location":"#installation","title":"Installation","text":"

See installing magicgui.

"},{"location":"CONTRIBUTING/","title":"Contributing","text":"

Contributions are welcome!

"},{"location":"CONTRIBUTING/#development","title":"Development","text":"

To install magicgui for development, first clone the repository:

git clone https://github.com/pyapp-kit/magicgui\ncd magicgui\n

Then install the package in editable mode with the dev extra:

pip install -e .[dev]\n

To run the tests:

pytest\n
"},{"location":"CONTRIBUTING/#code-quality","title":"Code Quality","text":"

magicgui attempts to adhere to strict coding rules and employs the following static analysis tools to prevent errors from being introduced into the codebase:

  • black - code formatting
  • ruff - linting
  • mypy - static type analysis
  • codecov - test coverage

To prevent continuous integration failures when contributing, please consider installing pre-commit in your environment to run all of these checks prior to checking in new code.

pre-commit install\n

To run the checks manually, you can use:

pre-commit run --all-files\n
"},{"location":"CONTRIBUTING/#adding-a-widget","title":"Adding a widget","text":"

These instructions may change in the future as the repo structures changes. If they appear outdated as you follow them, please open an issue.

To add a new widget, you will need to:

  1. Create a new class in magicgui/widgets/_concrete.py that inherits from the base class most appropriate for your widget (e.g. ValueWidget, or CategoricalWidget).

    In some (complex) cases, you may need to extend one of the base classes. If so, it is likely that you will also need to extend one of the Protocols found in magicgui.widgets.protocols. This is where all of protocols that backend classes need to implement to work with a given widget type. (Don't hesitate to open an issue if you're confused).

  2. Most likely, you will want to decorate the class with @backend_widget. Using this decorator implies that there is a class with the same name in any any backend modules that will support this widget type (e.g. magicgui.backends._qtpy.widgets for Qt support.).

  3. Make any changes necessary to your new concrete class. For example, you may need to change the value property and corresponding setter to handle a specific type. This part of the code should be backend agnostic.
  4. Export the new class in magicgui/widgets/__init__.py so that it can be imported from magicgui.widgets.
  5. Implement the backend widget class (using the same class name) in the appropriate backend module (e.g. magicgui.backends._qtpy.widgets for Qt support). Usually this will mean implementing the appropriate _mgui_get/set_... methods for the Protocol of the corresponding widget base class your chose to extend.
  6. Export the backend widget class in the __init__.py of the backend module (e.g. magicgui.backends._qtpy.__init__.py for Qt support). This is important, as that is where the @backend_widget decorator will look.
  7. Add a test for your new widget.

For an example of a minimal PR adding a new widget, see #483, which added a QuantityWidget to be used with pint.Quantity objects.

"},{"location":"CONTRIBUTING/#associating-a-widget-with-a-type","title":"Associating a widget with a type","text":"

To associate your new widget with a specific type such that it will be used when someone annotates a parameter with that type, you will need to update code in magicgui.type_map._type_map.

In the simplest of cases, this will mean adding a new entry to the magicgui.type_map._type_map._SIMPLE_TYPES dict. This is a mapping from a python type to a widget class. (Note that all subclasses of the type will also be matched.)

For more complex cases, you can add a new conditional to the body of the match_type function. That function should always return a tuple of widget type, and kwargs that will be passed to the widget constructor. For example: return widgets.MyNewWidget, {}.

"},{"location":"CONTRIBUTING/#building-the-documentation","title":"Building the documentation","text":"

To build the documentation locally, you will need to install the docs extra:

pip install -e .[docs]\n

Then, from the root of the repository, run:

mkdocs serve\n

This will start a local server at http://127.0.0.1:8000/ where you can view the documentation as you edit it.

"},{"location":"dataclasses/","title":"Dataclasses & guiclass","text":""},{"location":"dataclasses/#what-are-dataclasses","title":"What are dataclasses?","text":"

dataclasses are a feature added in Python 3.7 (PEP 557) that allow you to simply define classes that store a specific set of data. They encourage clear, type-annotated code, and are a great way to define data structures with minimal boilerplate.

New to dataclasses?

If you're totally new to dataclasses, you might want to start with the official documentation for the dataclasses module, or this Real Python post on dataclasses. The following is a very brief example of the key features:

Example dataclass
from dataclasses import dataclass\n\n@dataclass  # (1)!\nclass Person:\n    name: str # (2)!\n    age: int = 0  # (3)!\n\np = Person(name='John', age=30)  # (4)!\nprint(p) # (5)!\n
  1. The @dataclass decorator is used to mark a class as a dataclass. This will automatically generate an __init__ method with a parameter for each annotated class attribute.
  2. Attribute names are annotated with types. Note that, as with all Python type hints, these have no runtime effect (i.e. no validation is performed).
  3. Optional attributes can be defined with a default value. If no default value is specified, then the field is required when creating a new object.
  4. Creating a new object is as simple as passing in the required arguments.
  5. The __repr__ method is automatically generated and will print out the class name and all of the attributes and their current values.
"},{"location":"dataclasses/#dataclass-patterns-outside-the-standard-library","title":"dataclass patterns outside the standard library","text":"

The dataclasses module is not the only way to define data-focused classes in Python. There are other libraries that provide similar functionality, and some of them have additional features that are not available in the standard library.

  • attrs is a popular library that provides a number of additional features on top of the standard library dataclasses, including complex validation and type conversions.
  • pydantic is a library that provides runtime type enforcement and casting, serialization, and other features.
  • msgspec is a fast serialization library with a msgspec.Struct that is similar to a dataclass.
"},{"location":"dataclasses/#magicgui-guiclass","title":"magicgui guiclass","text":"

Experimental

This is an experimental feature. The API may change in the future without deprecations or warnings.

magicgui supports the dataclass API as a way to define the interface for compound widget, where each attribute of the dataclass is a separate widget. The magicgui.experimental.guiclass decorator can be used to mark a class as a \"GUI class\". A GUI class is a Python standard dataclass that has two additional features:

  1. A property (named \"gui\" by default) that returns a Container widget which contains a widget for each attribute of the dataclass.
  2. An property (named \"events\" by default) that returns a psygnal.SignalGroup object that allows you to connect callbacks to the change event of any of field in the dataclass. (Under the hood, this uses the @evented dataclass decorator from psygnal.)

Tip

You can still use all of the standard dataclass features, including field values, __post_init__ processing, and ClassVar.

Info

In the future, we may also support other dataclass-like objects, such as pydantic models, attrs classes, and traitlets classes.

from magicgui.experimental import guiclass\n\n@guiclass\nclass MyDataclass:\n    a: int = 0\n    b: str = 'hello'\n    c: bool = True\n\nobj = MyDataclass()\nobj.gui.show()\n

The individual widgets in the Container may be accessed by the same name as the corresponding attribute. For example, obj.gui.a will return the SpinBox widget that controls the value of the a attribute.

"},{"location":"dataclasses/#two-way-data-binding","title":"Two-way data binding","text":"

As you interact programmatically with the obj instance, the widgets in the obj.gui will update. Similarly, as you change the value of the widgets in the obj.gui, the values of the obj instance will be updated.

obj = MyDataclass(a=10)\nobj.b = 'world'\nobj.c = False\n\nobj.gui.show()\n

All magicgui-related stuff is in the gui attribute

The original dataclass instance (obj) is essentially untouched. Just as in a regular dataclass, obj.a returns the current value of a in the dataclass. The widget for the class will be at obj.gui (or whatever name you specified in the gui_name parameter) So, obj.gui.a.value, returns the current value of the widget. Unless you explicitly disconnect the gui from the underlying object/model, the two will always be in sync.

"},{"location":"dataclasses/#adding-buttons-and-callbacks","title":"Adding buttons and callbacks","text":"

Buttons are one of the few widget types that tend not to have an associated value, but simply trigger a callback when clicked. That is: it doesn't often make sense to add a field to a dataclass representing a button. To add a button to a guiclass, decorate a method with the magicgui.experimental.button decorator.

positioning buttons

Currently, all buttons are appended to the end of the widget. The ability to position the button in the layout will be added in the future.

Any additional keyword arguments to the button decorator will be passed to the magicgui.widgets.PushButton constructor (e.g. label, tooltip, etc.)

from magicgui.experimental import guiclass, button\n\n@guiclass\nclass Greeter:\n    first_name: str\n\n    @button\n    def say_hello(self):\n        print(f'Hello {self.first_name}')\n\ngreeter = Greeter('Talley')\ngreeter.gui.show()\n

clicking the \"say_hello\" button will print \"Hello Talley\" to the console

Tip

As your widget begins to manage more internal state, the guiclass pattern becomes much more useful than the magicgui decorator pattern -- which was designed with pure functions that take inputs and return outputs in mind.

"},{"location":"decorators/","title":"magicgui & magic_factory","text":""},{"location":"decorators/#from-object-to-gui","title":"From Object to GUI","text":"

The eponymous feature of magicgui is the magicgui.magicgui function, which converts an object into a widget.

Info

Currently, the only supported objects are functions, but in the future magicgui.magicgui may accept other objects, such as dataclass instances

When used to decorate a function, @magicgui will autogenerate a graphical user interface (GUI) by inspecting the function signature and adding an appropriate GUI widget for each parameter, as described in Type Hints to Widgets. Parameter types are taken from type hints, if provided, or inferred using the type of the default value otherwise.

import math\nfrom enum import Enum\nfrom magicgui import magicgui\n\n# dropdown boxes are best made by creating an enum\nclass Medium(Enum):\n    Glass = 1.520\n    Oil = 1.515\n    Water = 1.333\n    Air = 1.0003\n\n# decorate your function with the @magicgui decorator\n@magicgui(call_button=\"calculate\")\ndef snells_law(aoi=30.0, n1=Medium.Glass, n2=Medium.Water, degrees=True):\n    aoi = math.radians(aoi) if degrees else aoi\n    try:\n        result = math.asin(n1.value * math.sin(aoi) / n2.value)\n        return math.degrees(result) if degrees else result\n    except ValueError:\n        # beyond the critical angle\n        return \"Total internal reflection!\"\n\nsnells_law.show()\n

The object returned by the magicgui decorator is an instance of magicgui.widgets.FunctionGui. It can still be called like the original function, but it also knows how to present itself as a GUI.

"},{"location":"decorators/#two-way-data-binding","title":"Two-Way Data Binding","text":"

The modified snells_law object gains attributes named after each of the parameters in the function. Each attribute is an instance of a magicgui.widgets.Widget subclass (suitable for the data type represented by that parameter). As you make changes in your GUI, the attributes of the snells_law object will be kept in sync. For instance, change the first dropdown menu from \"Glass\" to \"Oil\", and the corresponding n1 object on snells_law will change its value to 1.515:

snells_law.n1.value  # 1.515\n

It goes both ways: set a parameter in the console and it will change in the GUI:

snells_law.aoi.value = 47\nsnells_law.show()\n

"},{"location":"decorators/#its-still-a-function","title":"It's still a function","text":"

magicgui tries very hard to make it so that the decorated object behaves as much like the original object as possible.

We can invoke the function in a few ways:

  • Because we provided the call_button argument to the magicgui decorator, a new button was created that will execute the function with the current gui parameters when clicked.

  • We can call the object just like the original function.

    snells_law()        # 34.7602\nsnells_law(aoi=12)  # 13.7142\n

    Now however, the current values from the GUI will be used as the default values for any arguments that are not explicitly provided to the function.

    snells_law.aoi.value = 12\nsnells_law()  # 13.7142\nsnells_law(aoi=30)  # 34.7602\n

    In essence, your original function now has a \"living\" signature whose defaults change as the user interacts with your GUI.

    import inspect\n\ninspect.signature(snells_law)\n# <MagicSignature(\n#   aoi=12.0, n1=<Medium.Glass: 1.52>, n2=<Medium.Water: 1.333>, degrees=True\n# )>\n# notice how the default `aoi` is now 12 ... because we changed it above\n
  • You can still override positional or keyword arguments in the original function, just as you would with a regular function.

    Note

    calling the function with values that differ from the GUI will not set the values in the GUI... It's just a one-time call.

    # in radians, overriding the value for the second medium (n2)\nsnells_law(0.8, n2=Medium.Air, degrees=False)  # 'Total internal reflection!'\n
"},{"location":"decorators/#connecting-events","title":"Connecting Events","text":""},{"location":"decorators/#function-calls","title":"Function Calls","text":"

With a GUI, you are usually looking for something to happen as a result of calling the function. The function will have a new called attribute that you can connect to an arbitrary callback function:

@snells_law.called.connect\ndef my_callback(value: str):\n    # The callback receives an `Event` object that has the result\n    # of the function call in the `value` attribute\n    print(f\"Your function was called! The result is: {value}\")\n\nresult = snells_law()\n

Now when you call snells_law(), or click the calculate button in the gui, my_callback will be called with the result of the calculation.

"},{"location":"decorators/#parameter-changes","title":"Parameter Changes","text":"

You can also listen for changes on individual function parameters by connecting to the <parameter_name>.changed signal:

# whenever the current value for n1 changes, print it to the console:\n@snells_law.n1.changed.connect\ndef _on_n1_changed(x: Medium):\n    print(f\"n1 was changed to {x}\")\n\nsnells_law.n1.value = Medium.Air\n

Note

This signal will be emitted regardless of whether the parameter was changed in the GUI or via by directly setting the paramaeter on the gui instance.

"},{"location":"decorators/#usage-as-a-decorator-is-optional","title":"Usage As a Decorator is Optional","text":"

Remember: the @decorator syntax is just syntactic sugar. You don't have to use @magicgui to decorate your function declaration. You can also just call it with your function as an argument:

This decorator usage:

@magicgui(auto_call=True)\ndef function():\n    pass\n

is equivalent to this:

def function():\n    pass\n\nfunction = magicgui(function, auto_call=True)\n

In many cases, it will actually be desirable not to use magicgui as a decorator if you don't need a widget immediately, but want to create one later (see also the magic_factory decorator.)

# some time later...\nwidget_instance = magicgui(function)\n
"},{"location":"decorators/#magic_factory","title":"magic_factory","text":"

The magicgui.magic_factory function/decorator acts very much like the magicgui decorator, with one important difference:

Unlike magicgui, magic_factory does not return a widget instance immediately. Instead, it returns a \"factory function\" that can be called to create a widget instance.

This is an important distinction to understand. In most cases, the @magicgui decorator is useful for interactive use or rapid prototyping. But if you are writing a library or package where someone else will be instantiating your widget (a napari plugin is a good example), you will likely want to use magic_factory instead, (or create your own Widget Container subclass).

it's just a partial

If you're familiar with functools.partial, you can think of magic_factory as a partial function application of the magicgui decorator (in fact, magic_factory is a subclass of partial). It is very roughly equivalent to:

def magic_factory(func, *args, **kwargs):\n    return partial(magicgui, func, *args, **kwargs)\n
"},{"location":"decorators/#widget_init","title":"widget_init","text":"

magic_factory gains one additional parameter: widget_init. This accepts a callable that will be called with the new widget instance each time the factory is called. This is a convenient place to add additional initialization or connect events.

from magicgui import magic_factory\n\ndef _on_init(widget):\n    print(\"widget created!\", widget)\n    widget.y.changed.connect(lambda x: print(\"y changed!\", x))\n\n@magic_factory(widget_init=_on_init)\ndef my_factory(x: int, y: str): ...\n\nnew_widget = my_factory()\n
"},{"location":"decorators/#the-lack-of-magic-in-magicgui","title":"The (lack of) \"magic\" in magicgui","text":"

Just to demystify the name a bit, there really isn't a whole lot of \"magic\" in the magicgui decorator. It's really just a thin wrapper around the magicgui.widgets.create_widget function, to create a Container with a sub-widget for each parameter in the function signature.

The widget creation is very roughly equivalent to something like this:

from inspect import signature, Parameter\nfrom magicgui.widgets import create_widget, Container\nfrom magicgui.types import Undefined\n\n\ndef pseudo_magicgui(func: 'Callable'):\n    return Container(\n        widgets=[\n            create_widget(p.default, annotation=p.annotation, name=p.name)\n            for p in signature(func).parameters.values()\n        ]\n    )\n\ndef some_func(x: int = 2, y: str = 'hello'):\n    return x, y\n\nmy_widget = pseudo_magicgui(some_func)\nmy_widget.show()\n

In the case of magicgui, a special subclass of Container (FunctionGui) is used, which additionally adds a __call__ method that allows the widget to behave like the original function.

"},{"location":"events/","title":"Events","text":"

All magicgui widgets emit events when certain properties change. For each event there is a corresponding signal attribute on the widget that can be connected to a callback function. For example, a PushButton emits an event when it is clicked, and all ValueWidget subclasses (like Slider or LineEdit) emit an event when their value changes.

"},{"location":"events/#connecting-to-events","title":"Connecting to events","text":"

To connect a callback to an event, use the connect method of the signal attribute. The exact signals available on each widget are mostly defined in the base classes, and are listed on the API page for each respective widget.

For example, to connect a callback to a LineEdit widget's changed event:

Widget APImagicgui decoratormagic_factory decorator
from magicgui import widgets\n\ntext = widgets.LineEdit(value='type something')\ntext.changed.connect(lambda val: print(f\"Text changed to: {val}\"))\n
from magicgui import magicgui\n\n@magicgui\ndef my_function(text: str):\n    ...\n\nmy_function.text.changed.connect(lambda val: print(f\"Text changed to: {val}\"))\n
from magicgui import magic_factory\n\ndef _on_init(widget):\n    widget.text.changed.connect(lambda val: print(f\"Text changed to: {val}\"))\n\n@magic_factory(widget_init=_on_init)\ndef my_function(text: str):\n    ...\n\nmy_widget = my_function()\n

It's all psygnal under the hood

magicgui uses psygnal for its event system. For greater detail on the connect method and its options, see the Usage section of psygnal's documentation, or the psygnal.SignalInstance.connect API reference.

Tip

Note that connect returns the callable that it was passed, so you can use it as a decorator if you prefer.

text = widgets.LineEdit(value='type something')\n\n# this works\ntext.changed.connect(lambda val: print(f\"Text changed to: {val}\"))\n\n# so does this\n@text.changed.connect\ndef on_text_changed(val):\n    print(f\"Text changed to: {val}\")\n
"},{"location":"installation/","title":"Installation","text":"

magicgui is a pure Python package, and can be installed with pip:

pip install magicgui\n

or with conda:

conda install -c conda-forge magicgui\n
"},{"location":"installation/#backends","title":"Backends","text":"

magicgui requires a backend to be installed in order to function, but it does not specify a particular backend by default. The following backends are available:

  • PyQt5: pip install magicgui[pyqt5]
  • PyQt6: pip install magicgui[pyqt6]
  • PySide2: pip install magicgui[pyside2]
  • PySide6: pip install magicgui[pyside6]
  • Jupyter Widgets: pip install magicgui[jupyter]

Important

Note not all widgets are necessarily implemented for all backends. Most widgets in the widget docs specify which backends are supported.

"},{"location":"installation/#extras","title":"Extras","text":"

The Image widget requires pillow. You may use the image extra:

pip install magicgui[image]\n

The magicgui.tqdm module requires tqdm. You may use the tqdm extra:

pip install magicgui[tqdm]\n

The QuantityEdit widget requires pint. You may use the quantity extra:

pip install magicgui[quantity]\n
"},{"location":"type_map/","title":"Type Hints to Widgets","text":"

One of the key offerings of magicgui is the ability to automatically generate Widgets from Python type hints. This page describes how type hints are mapped to Widgets, and how to customize that mapping.

"},{"location":"type_map/#default-type-mapping","title":"Default Type Mapping","text":"

By default, The following python Type Hint annotations are mapped to the corresponding Widget class, and parametrized with the corresponding kwargs (when applicable):

Type Hint Widget __init__ kwargs bool Slider int Slider float FloatSlider str LineEdit range RangeEdit slice SliceEdit list ListEdit tuple TupleEdit pathlib.Path FileEdit os.PathLike FileEdit Sequence[pathlib.Path] FileEdit {'mode': 'rm'} datetime.time TimeEdit datetime.timedelta TimeEdit datetime.date DateEdit datetime.datetime DateTimeEdit Literal['a', 'b'] ComboBox {'choices': ['a', 'b']} Set[Literal['a', 'b']] Select {'choices': ('a', 'b')} enum.Enum ComboBox {'choices': <enum 'Enum'>} magicgui.widgets.ProgressBar ProgressBar {'bind': <function TypeMap.match_type.<locals>.<lambda> at 0x11f1979c0>, 'visible': True} types.FunctionType FunctionGui {'function': ...} pint.Quantity QuantityEdit"},{"location":"type_map/#example","title":"Example","text":"

from magicgui import widgets\nimport pathlib\nimport os\nimport datetime\nfrom typing import Literal, Set, Sequence\nimport types\nimport pint\nimport enum\n\ntypes = [\n    bool, int, float, str, range, slice, list,\n    pathlib.Path, os.PathLike, Sequence[pathlib.Path],\n    datetime.time, datetime.timedelta, datetime.date, datetime.datetime,\n    Literal['a', 'b'], Set[Literal['a', 'b']], enum.Enum,\n    widgets.ProgressBar, pint.Quantity,\n]\n\nwdg = widgets.Container(\n    widgets=[\n        widgets.create_widget(annotation=t, label=str(t)) for t in types\n    ]\n)\nwdg.show()\n

"},{"location":"type_map/#customizing-widget-options-with-typingannotated","title":"Customizing Widget Options with typing.Annotated","text":"

Widget options and types may be embedded in the type hint itself using typing.Annotated.

Note

This is not the only way to customize the widget type or options in magicgui. Some functions (like magicgui.magicgui) also accept **param_options keyword arguments that map parameter names to dictionaries of widget options.

"},{"location":"type_map/#overriding-the-default-type","title":"Overriding the Default Type","text":"

To override the widget class used for a given object type, use the widget_type key in the Annotated kwargs. It can be either the string name of one of the built-in widgets, or any Widget subclass object.

Type Hint Widget __init__ kwargs Annotated[int, {'widget_type': 'Slider'}] Slider Annotated[float, {'widget_type': 'FloatSlider'}] FloatSlider"},{"location":"type_map/#overriding-the-default-options","title":"Overriding the Default Options","text":"

Any additional kwargs will be passed to the widget constructor (and must be valid for the corresponding widget type).

Type Hint Widget __init__ kwargs Annotated[int, {'step': 10, 'max': 50}] Slider {'step': 10, 'max': 50} Annotated[int, {'choices': [1, 2, 3]}] Slider {'choices': [1, 2, 3]}"},{"location":"type_map/#examples","title":"Examples","text":"

Create a widget using standard type map:

create_widgetmagicgui decoratorguiclass decorator
my_widget = widgets.create_widget(value=42, annotation=int)\n
from magicgui import magicgui\n\n@magicgui\ndef my_widget(x: int = 42):\n    return x\n
from magicgui.experimental import guiclass\n\n@guiclass\nclass MyObject:\n    x: int = 42\n\nobj = MyObject()\nmy_widget = obj.gui\n

Customize a widget using typing.Annotated:

create_widgetmagicgui decoratorguiclass decorator
from typing import Annotated\n\nInt10_50 = Annotated[int, (('widget_type', 'Slider'),('step', 10),('max', 50))]\nwdg2 = widgets.create_widget(value=42, annotation=Int10_50)\n
from magicgui import magicgui\nfrom typing import Annotated\n\nInt10_50 = Annotated[int, (('widget_type', 'Slider'),('step', 10),('max', 50))]\n\n@magicgui\ndef my_widget(x: Int10_50 = 42):\n    ...\n
from magicgui.experimental import guiclass\nfrom typing import Annotated\n\nInt10_50 = Annotated[int, (('widget_type', 'Slider'),('step', 10),('max', 50))]\n\n@guiclass\nclass MyObject:\n    x: Int10_50 = 42\n\nobj = MyObject()\nmy_widget = obj.gui\n

Note that you may also customize widget creation with kwargs to create_widget

from typing import Annotated\nfrom magicgui.widgets import Slider\n\noptions = {'step': 10, 'max': 50}\nwdg3 = widgets.create_widget(value=42, widget_type=Slider, options=options)\nwdg3.show()\n

... or to the magicgui decorator:

@magicgui(x={'widget_type': 'Slider', 'step': 10, 'max': 50})\ndef my_widget(x: int = 42):\n    ...\n\nmy_widget.show()\n

"},{"location":"type_map/#return-type-mapping","title":"Return Type Mapping","text":"

In some cases, magicgui may be able to create a widget for the return annotation of a function.

... more to come ...

"},{"location":"type_map/#postponed-annotations","title":"Postponed annotations","text":"

Using forward references and __future__.annotations with magicgui is possible, but requires some extra care. Read on for more details.

"},{"location":"type_map/#forward-references","title":"Forward References","text":"

When a type hint contains names that have not been defined yet, that definition may be expressed as a string literal, to be resolved later. This is called a Forward Reference (see PEP 484). This is useful when you want to use a type hint that refers to a type that has not yet been defined, or when you want to avoid importing a type that is only used in a type hint.

from typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from mymodule import MyType\n\ndef my_function(x: 'MyType') -> None:\n    ...\n
"},{"location":"type_map/#__future__annotations","title":"__future__.annotations","text":"

In Python 3.7, the __future__.annotations feature was introduced (PEP 563), which postpones the evaluation of type annotations. The effect of this is that no type annotations will be evaluated at definition time, and all type annotations will be treated as strings (regardless of whether they are enclosed in quotes or not).

from __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from mymodule import MyType\n\n# no longer necessary to use quotes around 'MyType'\ndef my_function(x: MyType) -> None:\n    ...\n

While this is a useful feature for developers, it does make it significantly more difficult to use those type annotations at runtime.

Magicgui does attempt to resolve forward references it encounters (see Resolving type hints at runtime for gory details), but this is an imperfect process, and may not always work.

"},{"location":"type_map/#if-you-must-use-postponed-annotations","title":"If You Must Use Postponed Annotations","text":"

As a general rule, if you must use forward references or __future__.annotations in a module that uses magicgui, you should:

  • don't use typing syntax that is not valid for ALL python versions you wish to support (e.g. str | int instead of Union[str, int] in python < 3.10), as these will raise an exception when magicgui attempts to evaluate them at runtime.
  • use fully qualified names for all type hints, as these will be easier for magicgui to resolve without user-supplied namespaces.

    from __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    import mymodule\n\n# this is easier for magicgui to resolve\ndef my_function(x: mymodule.MyType) -> None:\n    ...\n
"},{"location":"type_map/#registering-support-for-custom-types","title":"Registering Support for Custom Types","text":"

Any third-party library may use the magicgui.register_type function to register its types with magicgui. When a registered type is used as an annotation, the registered widget will be used.

"},{"location":"type_map/#known-third-party-support-for-magicgui","title":"Known Third-Party Support for magicgui","text":"

Hi developer!

Have a library that registers types with magicgui? Let us know and we'll add it to this list!

"},{"location":"type_map/#napari","title":"napari","text":"

napari has registered a number of its types to provide access to napari-specific objects using type annotations in magicgui. Details may be found in napari's documentation on using magicgui in napari.

"},{"location":"widgets/","title":"Widgets","text":"

Tip

If you're looking for an index of all available widgets, see the Widget Index.

All individual graphical elements in magicgui are \"widgets\", and all widgets are instances of magicgui.widgets.Widget. Widgets may be created directly:

from magicgui.widgets import LineEdit\n\nline_edit = LineEdit(value='hello!')\nline_edit.show()\n

Some widgets (such as magicgui.widgets.Container) are composite widgets that comprise other widgets:

from magicgui.widgets import LineEdit, SpinBox, Container\n\nline_edit = LineEdit(value='hello!')\nspin_box = SpinBox(value=400)\ncontainer = Container(widgets=[line_edit, spin_box])\ncontainer.show()\n

magicgui provides a way to automatically select a widget given a python value or type annotation using magicgui.widgets.create_widget. Here is an example that yields the same result as the one above:

from magicgui.widgets import create_widget\n\nx = 'hello!'\ny = 400\ncontainer = Container(widgets=[create_widget(i) for i in (x, y)])\ncontainer.show()\n

Tip

Because there are often multiple valid widget types for a given python object, you may sometimes wish to create widgets directly, or use the widget_type argument in create_widget()

"},{"location":"widgets/#the-widget-hierarchy","title":"The widget hierarchy","text":"
graph TB\n    A([Widget])-->B([ValueWidget])\n    A-->C([ContainerWidget])\n    B-->D([RangedWidget])\n    B-->E([ButtonWidget])\n    B-->F([CategoricalWidget])\n    C-->H([MainWindowWidget])\n    C-->G([FunctionGui])\n    D-->I([SliderWidget])\n    click A \"#widget\"\n    click B \"#valuewidget\"\n    click C \"#containerwidget\"\n    click D \"#rangedwidget\"\n    click E \"#buttonwidget\"\n    click F \"#categoricalwidget\"\n    click H \"#mainwindowwidget\"\n    click G \"#functiongui\"\n    click I \"#sliderwidget\"

Many widgets present similar types of information in different ways. magicgui tries to maintain a consistent API among all types of widgets that are designed to represent similar objects. The general class of widget you are working with will determine the properties and attributes it has.

Note

The categories shown below are sorted by their base class (such as ValueWidget and RangedWidget). The bases are not intended to be instantiated directly. Instead, you would create the widget type you wanted, such as LineEdit or SpinBox, respectively.

"},{"location":"widgets/#widget","title":"Widget","text":"

As mentioned above, all magicgui widgets derive from magicgui.widgets.Widget and have the following attributes (this list is not comprehensive, see the magicgui.widgets.Widget API):

Attribute Type Description name str The name or \"ID\" of this widget (such as a function parameter name to which this widget corresponds). annotation Any A type annotation for the value represented by the widget. label str A string to use for an associated Label widget (if this widget is being shown in a magicgui.widgets.Container widget, and container.labels is True). By default, name will be used. Note: name refers the name of the parameter, as might be used in a signature, whereas label is just the label for that widget in the GUI. tooltip str A tooltip to display when hovering over the widget. visible bool Whether the widget is visible."},{"location":"widgets/#valuewidget","title":"ValueWidget","text":"

In addition to the base Widget properties mentioned above, the following ValueWidgets track some value:

Widget Description Label A non-editable text display. LineEdit A one-line text editor. LiteralEvalLineEdit A one-line text editor that evaluates strings as python literals. Password A one-line text editor that obscures input. TextEdit A widget to edit and display both plain and rich text. FileEdit A LineEdit widget with a button that opens a FileDialog. RangeEdit A widget to represent a python range object, with start/stop/step. SliceEdit A widget to represent slice objects, with start/stop/step. DateTimeEdit A widget for editing dates and times. DateEdit A widget for editing dates. TimeEdit A widget for editing times. Table A widget to represent columnar or 2D data with headers. QuantityEdit A combined LineEdit and ComboBox to edit a pint.Quantity. Attribute Type Description value Any The current value of the widget. changed psygnal.SignalInstance A psygnal.SignalInstance that will emit an event when the value has changed. Connect callbacks to the change event using widget.changed.connect(callback) bind Any, optional A value or callback to bind this widget. If bound, whenever widget.value is accessed, the value provided here will be returned. The bound value can be a callable, in which case bound_value(self) will be returned (i.e. your callback must accept a single parameter, which is this widget instance.). see ValueWidget.bind for details.

Here is a demonstration of all these:

from magicgui import widgets\nimport datetime\n\nwdg_list = [\n    widgets.Label(value=\"label value\", label=\"Label:\"),\n    widgets.LineEdit(value=\"line edit value\", label=\"LineEdit:\"),\n    widgets.Password(value=\"super-secret!\", label=\"Password:\"),\n    widgets.TextEdit(value=\"text edit value...\", label=\"TextEdit:\"),\n    widgets.FileEdit(value=\"/home\", label=\"FileEdit:\"),\n    widgets.RangeEdit(value=range(0, 10, 2), label=\"RangeEdit:\"),\n    widgets.SliceEdit(value=slice(0, 10, 2), label=\"SliceEdit:\"),\n    widgets.DateTimeEdit(\n      value=datetime.datetime(1999, 12, 31, 11, 30), label=\"DateTimeEdit:\"\n    ),\n    widgets.DateEdit(value=datetime.date(81, 2, 18), label=\"DateEdit:\"),\n    widgets.TimeEdit(value=datetime.time(12, 20), label=\"TimeEdit:\"),\n    widgets.QuantityEdit(value='12 seconds', label=\"Quantity:\")\n]\ncontainer = widgets.Container(widgets=wdg_list)\ncontainer.max_height = 300\ncontainer.show()\n

"},{"location":"widgets/#rangedwidget","title":"RangedWidget","text":"

RangedWidgets are numerical ValueWidgets that have a restricted range of valid values, and a step size. RangedWidgets include:

Widget Description SpinBox A widget to edit an integer with clickable up/down arrows. FloatSpinBox A widget to edit a float with clickable up/down arrows.

In addition to all of the ValueWidget attributes, RangedWidget attributes include:

Attribute Type Description min float The minimum allowable value, by default 0 max float The maximum allowable value, by default 1000 step float The step size for incrementing the value, by default 1 range tuple of float A convenience attribute for getting/setting the (min, max) simultaneously

w1 = widgets.SpinBox(value=10, max=20, label='SpinBox:')\nw2 = widgets.FloatSpinBox(value=380, step=0.5, label='FloatSpinBox:')\ncontainer = widgets.Container(widgets=[w1, w2])\ncontainer.show()\n

"},{"location":"widgets/#sliderwidget","title":"SliderWidget","text":"

SliderWidgets are special RangedWidgets that additionally have an orientation, and a readout.

Widget Description Slider A slider widget to adjust an integer value within a range. FloatSlider A slider widget to adjust an integer value within a range. LogSlider A slider widget to adjust a numerical value logarithmically within a range. ProgressBar A progress bar widget.

In addition to all of the RangedWidget attributes, SliderWidget attributes include:

Attribute Type Description orientation str The orientation for the slider. Must be either 'horizontal' or 'vertical'. by default 'horizontal' readout bool Whether to show the value of the slider. By default, True.

w1 = widgets.Slider(value=10, max=25, label='Slider:')\nw2 = widgets.FloatSlider(value=10.5, max=18.5, label='FloatSlider:')\nw3 = widgets.ProgressBar(value=80, max=100, label='ProgressBar:')\ncontainer = widgets.Container(widgets=[w1, w2, w3])\ncontainer.show()\n

"},{"location":"widgets/#buttonwidget","title":"ButtonWidget","text":"

ButtonWidgets are boolean ValueWidgets that also have some text associated with them.

Widget Description PushButton A clickable command button. CheckBox A checkbox with a text label.

In addition to all of the ValueWidget attributes, ButtonWidget attributes include:

Attribute Type Description text str The text to display on the button. If not provided, will use name.

w1 = widgets.PushButton(value=True, text='PushButton Text')\nw2 = widgets.CheckBox(value=False, text='CheckBox Text')\ncontainer = widgets.Container(widgets=[w1, w2])\ncontainer.show()\n

"},{"location":"widgets/#categoricalwidget","title":"CategoricalWidget","text":"

CategoricalWidget are ValueWidgets that provide a set of valid choices. They can be created from:

  • an enum.Enum
  • an iterable of objects (or an iterable of 2-tuples (name, object))
  • a callable that returns an enum.Enum or an iterable
  • a typing.Literal annotation.
Widget Description ComboBox A dropdown menu, allowing selection between multiple choices. RadioButtons An exclusive group of radio buttons, providing a choice from multiple choices. Select A list of options, allowing selection between multiple choices.

In addition to all of the ValueWidget attributes, CategoricalWidget attributes include:

Attribute Type Description choices Enum, Iterable, or Callable Available choices displayed in the widget. value Any In the case of a CategoricalWidget the value is the data of the currently selected choice (see also: current_choice below). current_choice str The name associated with the current choice. For instance, if choices was provided as choices=[('one', 1), ('two', 2)], then an example value would be 1, and an example current_choice would be 'one'.

choices = ['one', 'two', 'three']\nw1 = widgets.ComboBox(choices=choices, value='two', label='ComboBox:')\nw2 = widgets.RadioButtons(choices=choices, label='RadioButtons:')\nw3 = widgets.Select(choices=choices, label='Select:')\ncontainer = widgets.Container(widgets=[w1, w2, w3])\ncontainer.max_height = 220\ncontainer.show()\n

"},{"location":"widgets/#containerwidget","title":"ContainerWidget","text":"

A ContainerWidget is a list-like Widget that can contain other widgets. Containers allow you to build more complex widgets from sub-widgets. A notable example of a Container is magicgui.widgets.FunctionGui) (the product of the @magicgui decorator).

Widget Description Container A Widget to contain other widgets. MainWindow A Widget to contain other widgets, includes a menu bar. FunctionGui Wrapper for a container of widgets representing a callable object. Attribute Type Description layout str The layout for the container. Must be either 'horizontal' or 'vertical'. widgets Sequence[Widget] The widgets that the container contains. labels bool Whether each widget should be shown with a corresponding Label widget to the left. Note: the text for each widget defaults to widget.name, but can be overridden by setting widget.label.

Container implements the full collections.abc.MutableSequence interface. You can add and remove widgets from it just as you would add or remove items from a list.

from magicgui.widgets import Container, Slider, FloatSlider, ProgressBar\n\ncontainer = widgets.Container()\ncontainer.append(widgets.LineEdit(value='Mookie', label='Your Name:'))\ncontainer.append(widgets.FloatSlider(value=10.5, label='FloatSlider:'))\ncontainer.show()\n

"},{"location":"widgets/#mainwindowwidget","title":"MainWindowWidget","text":"

A MainWindowWidget is a special type of ContainerWidget that also includes a menu bar.

"},{"location":"widgets/#functiongui","title":"FunctionGui","text":"

A FunctionGui is a special type of ContainerWidget that is created from a function. It is the product of the @magicgui decorator. It is a container that contains a widget for each of the parameters in the function. See magicgui.widgets.FunctionGui for details.

"},{"location":"widgets/#magicgui","title":"@magicgui","text":"

It's worth noting that @magicgui and @magic_factory decorators are just conveniences that build a special type of Container widget (a FunctionGui), with a widget representing each of the parameters in a decorated function.

from magicgui import magicgui\n\n@magicgui\ndef my_function(x='hello', y=400): ...\n\nmy_function.show()\n

In terms of simply building widgets, the following code performs a similar task to @magicgui.

from inspect import signature\n\ndef my_function(x='hello', y=400):\n  ...\n\nparams = signature(my_function).parameters.values()\ncontainer = Container(\n    widgets=[create_widget(p.default, name=p.name) for p in params]\n)\ncontainer.show()\n

Tip

Note that the FunctionGui widget produced by @magicgui is actually a callable object that behaves very much like the original function, except that it will use current values from the GUI as default parameters when calling the function.

"},{"location":"api/app/","title":"Application","text":""},{"location":"api/app/#magicgui.application.Application","title":"magicgui.application.Application","text":"

Magicgui Application, wrapping a native BaseApplicationBackend implementation.

"},{"location":"api/app/#magicgui.application.Application.backend_module","title":"backend_module: ModuleType property","text":"

Return module object that defines the backend.

"},{"location":"api/app/#magicgui.application.Application.backend_name","title":"backend_name: str property","text":"

Return name of the GUI backend that this app wraps.

"},{"location":"api/app/#magicgui.application.Application.native","title":"native: Any property","text":"

Return the native GUI application instance.

"},{"location":"api/app/#magicgui.application.Application.__enter__","title":"__enter__() -> Application","text":"

Context manager to start this application.

"},{"location":"api/app/#magicgui.application.Application.__exit__","title":"__exit__(*exc_details: Any) -> None","text":"

Exit context manager for this application.

"},{"location":"api/app/#magicgui.application.Application.__repr__","title":"__repr__() -> str","text":"

Return repr for this instance.

"},{"location":"api/app/#magicgui.application.Application.create","title":"create() -> None","text":"

Create the native application.

"},{"location":"api/app/#magicgui.application.Application.get_obj","title":"get_obj(name: str) -> Any","text":"

Get the backend object for the given name (such as a widget).

"},{"location":"api/app/#magicgui.application.Application.process_events","title":"process_events() -> None","text":"

Process all pending GUI events.

"},{"location":"api/app/#magicgui.application.Application.quit","title":"quit() -> None","text":"

Quit the native GUI event loop.

"},{"location":"api/app/#magicgui.application.Application.run","title":"run() -> None","text":"

Enter the native GUI event loop.

"},{"location":"api/app/#magicgui.application.Application.start_timer","title":"start_timer(interval: int = 1000, on_timeout: Callable[[], None] | None = None, single_shot: bool = False) -> None","text":"

Start a timer with a given interval, optional callback, and single_shot.

"},{"location":"api/app/#magicgui.application.use_app","title":"magicgui.application.use_app(app: AppRef | None = None) -> Application","text":"

Get/create the default Application object. See _use_app docstring.

"},{"location":"api/experimental/","title":"magicgui.experimental","text":"

Experimental

This module contains experimental features that are not yet ready for prime time. All of the features in this module are subject to change without warning or deprecation.

"},{"location":"api/experimental/#magicgui.experimental.guiclass","title":"magicgui.experimental.guiclass(cls: T | None = None, *, gui_name: str = 'gui', events_namespace: str = 'events', follow_changes: bool = True, **dataclass_kwargs: Any) -> T | Callable[[T], T]","text":"

Turn class into a dataclass with a property (gui_name) that returns a gui.

This decorator is similar to dataclasses.dataclass, but it will also add an events attribute to the class that is an instance of psygnal.SignalGroup (with a signal for each field in the dataclass; see https://psygnal.readthedocs.io/en/latest/dataclasses/ for details), and a gui property that returns a magicgui widget, bound to the values of the dataclass instance.

Note

This decorator is compatible with dataclasses using slots=True, however, there is a potential for a memory leak that the user should be aware of. If you create a guiclass instance, and then store a reference to its gui, and then delete the instance, the gui will still be bound to the instance, preventing it from being garbage collected. To avoid this, you can call unbind_gui_from_instance(gui, instance) before deleting the instance.

Parameters:

  • cls (type, default: None ) \u2013

    The class to turn into a dataclass.

  • gui_name (str, default: 'gui' ) \u2013

    The name of the property that will return a magicgui widget, by default \"gui\"

  • events_namespace (str, default: 'events' ) \u2013

    The name of the attribute that will be added to the class, by default \"events\". This attribute will be an instance of psygnal.SignalGroup that will be used to connect events to the class.

  • follow_changes (bool, default: True ) \u2013

    If True (default), changes to the dataclass instance will be reflected in the gui, and changes to the gui will be reflected in the dataclass instance.

  • dataclass_kwargs (dict, default: {} ) \u2013

    Additional keyword arguments to pass to dataclasses.dataclass.

Returns:

  • type \u2013

    The dataclass.

Examples:

>>> @guiclass\n... class MyData:\n...     x: int = 0\n...     y: str = \"hi\"\n...\n...     @button\n...     def reset(self):\n...         self.x = 0\n...         self.y = \"hi\"\n>>> data = MyData()\n>>> data.gui.show()\n
"},{"location":"api/experimental/#magicgui.experimental.button","title":"magicgui.experimental.button(func: F | None = None, **button_kwargs: Any) -> F | Callable[[F], F]","text":"

Add a method as a button to a guiclass, which calls the decorated method.

Parameters:

  • func (callable, default: None ) \u2013

    The method to decorate. If None, returns a decorator that can be applied to a method.

  • button_kwargs (dict, default: {} ) \u2013

    Additional keyword arguments to pass to magicgui.widgets.PushButton.

"},{"location":"api/experimental/#magicgui.experimental.is_guiclass","title":"magicgui.experimental.is_guiclass(obj: object) -> TypeGuard[GuiClassProtocol]","text":"

Return True if obj is a guiclass or an instance of a guiclass.

"},{"location":"api/magic_factory/","title":"magicgui.magic_factory","text":""},{"location":"api/magic_factory/#magicgui.magic_factory","title":"magicgui.magic_factory = TypeMap.global_instance().magic_factory module-attribute","text":""},{"location":"api/magic_factory/#magicgui.type_map._magicgui.MagicFactory","title":"magicgui.type_map._magicgui.MagicFactory","text":"

Bases: partial, Generic[_FGuiVar]

Factory function that returns a FunctionGui instance.

While this can be used directly, (see example below) the preferred usage is via the magicgui.magic_factory decorator.

Examples:

>>> def func(x: int, y: str):\n...     pass\n>>> factory = MagicFactory(function=func, labels=False)\n>>> # factory accepts all the same arguments as magicgui()\n>>> widget1 = factory(call_button=True)\n>>> # can also override magic_kwargs that were provided when creating the factory\n>>> widget2 = factory(auto_call=True, labels=True)\n
"},{"location":"api/magic_factory/#magicgui.type_map._magicgui.MagicFactory.__name__","title":"__name__: str property","text":"

Pass function name.

"},{"location":"api/magic_factory/#magicgui.type_map._magicgui.MagicFactory.__call__","title":"__call__(*args, **kwargs)","text":"

Call the wrapped _magicgui and return a FunctionGui.

"},{"location":"api/magic_factory/#magicgui.type_map._magicgui.MagicFactory.__getattr__","title":"__getattr__(name)","text":"

Allow accessing FunctionGui attributes without mypy error.

"},{"location":"api/magic_factory/#magicgui.type_map._magicgui.MagicFactory.__new__","title":"__new__(function, *args, magic_class=FunctionGui, widget_init=None, type_map=None, **keywords)","text":"

Create new MagicFactory.

"},{"location":"api/magic_factory/#magicgui.type_map._magicgui.MagicFactory.__repr__","title":"__repr__()","text":"

Return string repr.

"},{"location":"api/magicgui/","title":"magicgui.magicgui","text":""},{"location":"api/magicgui/#magicgui.magicgui","title":"magicgui.magicgui = TypeMap.global_instance().magicgui module-attribute","text":""},{"location":"api/migration/","title":"migration guide","text":""},{"location":"api/migration/#v030-migration-guide","title":"v0.3.0 migration guide","text":"

October, 2021

Version 0.3.0 of magicgui introduced some changes to the events and callbacks API. See https://github.com/pyapp-kit/magicgui/pull/253 for details

"},{"location":"api/migration/#callbacks-now-receive-the-value-directly-instead-of-an-event-object","title":"Callbacks now receive the value directly, instead of an Event object","text":"

magicgui 0.3.0 is now using psygnal as its event/callback handler.

Callbacks connected to widget.changed (and other event emitters) may now receive the value(s) directly, instead of an event object:

\ud83d\udc4e Old Method (< v0.3.0)
@widget.changed.connect\ndef my_callback(event):\n    # event was an `Event` object with a `value` attribute\n    new_value = event.value\n

Existing code using callbacks with a single positional argument will continue to receive a single Event object (and a warning will be shown, until v0.4.0 where it will become an error).

To silence the warning and opt in to the new pattern of receiving value directly, you can do one of two things:

  1. type hint your single positional argument as anything other than magicgui.events.Event
  2. provide a callback that takes no arguments
\ud83d\udc4d New Method (>= v0.3.0)
@widget.changed.connect\ndef my_callback(new_value: int):\n    ...  # use new_value directly\n\n# or, if you don't need to use new_value\n@widget.changed.connect\ndef my_callback():\n    # something that didn't need the value\n    ...\n
"},{"location":"api/migration/#event-emitters-take-no-keyword-arguments","title":"Event emitters take no keyword arguments","text":"

For the few packages who were manually emitting change events, you should no longer provide the value= keyword when emitting.

\ud83d\udc4e Old Method (< v0.3.0)
widget.changed(value='whatever')\n
\ud83d\udc4d New Method (>= v0.3.0)
widget.changed.emit('whatever')\n# OR (if you prefer the direct __call__ syntax)\nwidget.changed('whatever')\n
"},{"location":"api/migration/#v020-migration-guide","title":"v0.2.0 migration guide","text":"

December, 2020

Version 0.2.0 of magicgui was a complete rewrite that introduced a couple breaking API changes

"},{"location":"api/migration/#gui-attribute-removed","title":".Gui() attribute removed","text":"

Before v0.2.0, the magicgui.magicgui decorator added a Gui attribute to the decorated function that was to be called to instantiate a widget. In v0.2.0 the object returned from the magicgui.magicgui decorator is already an instantiated magicgui.widgets.Widget.

\ud83d\udc4e Old Method (< v0.2.0)
from magicgui import magicgui, event_loop\n\n@magicgui\ndef function(x, y):\n    ...\n\nwith event_loop():\n    gui = function.Gui(show=True)\n
\ud83d\udc4d New Method (>= v0.2.0)
from magicgui import magicgui\n\n@magicgui\ndef function(x, y):\n    ...\n\nfunction.show(run=True)\n
"},{"location":"api/migration/#new-base-widget-type","title":"New base widget type","text":"

Before v0.2.0, the Gui() object returned by the magicgui.magicgui decorator was a MagicGuiBase widget class, which in turn was a direct subclass of a backend widget, such as a QtWidgets.QWidget. In v0.2.0, all widgets derive from [magicgui.widgets.Widget``][magicgui.widgets.Widget], and the *backend* is available atwidget.native. If you are incorporating magicgui widgets into a larger Qt-based GUI, please note that you will want to usewidget.nativeinstead ofwidget`

from magicgui import magicgui, use_app\n\nuse_app('qt')\n\n@magicgui\ndef function(x, y):\n    ...\n
>>> print(type(function))\n<class 'magicgui.widgets.FunctionGui'>\n>>> print(type(function.native))\n<class 'PyQt5.QtWidgets.QWidget'>\n
"},{"location":"api/migration/#starting-the-application","title":"Starting the application","text":"

It is now easier to show a widget and start an application by calling widget.show(run=True). Calling show(run=True) will immediately block execution of your script and show the widget. If you wanted to (for instance) show multiple widgets next to each other, then you would still want to use the event_loop context manager:

from magicgui import magicgui, event_loop\n\n@magicgui\ndef function_a(x=1, y=3):\n    ...\n\n@magicgui\ndef function_b(z='asdf'):\n    ...\n\nwith event_loop():\n    function_a.show()\n    function_b.show()\n# both widgets will show (though b may be on top of a)\n
"},{"location":"api/migration/#getting-and-setting-values","title":"Getting and setting values","text":"

To get or set the value of a widget programmatically, you no longer set the corresponding widget attribute directly, but rather use the widget.value attribute:

Old Method \ud83d\udc4e

gui.x used to be a descriptor object to get/set the value, but the actual underlying widget was at gui.x_widget

gui = function.Gui()\ngui.x = 10\n

New Method \ud83d\udc4d

now function.x IS the widget, and you set its value with function.x.value

function.x.value = 10\n
"},{"location":"api/migration/#connecting-callbacks-to-events","title":"Connecting callbacks to events","text":"

When binding callbacks to change events, you no longer connect to gui.<name>_changed, you now connect to function.<name>.changed:

\ud83d\udc4e Old Method (< v0.2.0)
gui = function.Gui()\ngui.x_changed.connect(my_callback)\n
\ud83d\udc4d New Method (>= v0.2.0)
function.x.changed.connect(my_callback)\n
"},{"location":"api/migration/#renamed","title":"Renamed","text":"
  • Widget.refresh_choices has been renamed to Widget.reset_choices.

  • @magicgui(result=True) has been renamed to @magicgui(result_widget=True)

"},{"location":"api/protocols/","title":"Backend Protocols","text":"

Advanced Topic

Most users of magicgui will not need to worry about this section.

These Protocol classes declare the interface that backend adapters must implement in order to be used by magicgui. All magicgui Widget objects compose a backend widget implementing one of these protocols, and control it using the methods defined herein.

magicgui developers may be interested in this page, but end-users needn't worry about it.

"},{"location":"api/protocols/#summary","title":"Summary","text":"Widget Description WidgetProtocol Base Widget Protocol: specifies methods that all widgets must provide. ValueWidgetProtocol Widget that has a current value, with getter/setter and on_change callback. ButtonWidgetProtocol The \"value\" in a ButtonWidget is the current (checked) state. TableWidgetProtocol ValueWidget subclass intended for 2D tabular data, with row & column headers. RangedWidgetProtocol Value widget that supports numbers within a provided min/max range. CategoricalWidgetProtocol Categorical widget, that has a set of valid choices, and a current value. SliderWidgetProtocol Protocol for implementing a slider widget. ContainerProtocol Widget that can contain other widgets. BaseApplicationBackend Backend Application object. DialogProtocol Protocol for modal (blocking) containers. SupportsChoices Widget that has a set of valid choices. SupportsOrientation Widget that can be reoriented. SupportsText Widget that have text (in addition to value)... like buttons. SupportsReadOnly Widget that can be read_only."},{"location":"api/protocols/#protocol-inheritance","title":"Protocol Inheritance","text":"

The visual hierarchy of protocols looks like this:

graph LR\n    A([WidgetProtocol])-->B([ValueWidgetProtocol])\n    A-->C([ContainerProtocol])\n    M([SupportsText])-->E\n    B-->E([ButtonWidgetProtocol])\n    B-->D([RangedWidgetProtocol])\n    B-->F([CategoricalWidgetProtocol])\n    D-->I([SliderWidgetProtocol])\n    B-->J([TableWidgetProtocol])\n    K([SupportsReadOnly])-->J([TableWidgetProtocol])\n    L([SupportsChoices])-->F\n    N([SupportsOrientation])-->C\n    N-->I\n    C-->O([DialogProtocol])\n    C-->P([MainWindowProtocol])\n\n    click A \"#magicgui.widgets.protocols.WidgetProtocol\"\n    click B \"#magicgui.widgets.protocols.ValueWidgetProtocol\"\n    click C \"#magicgui.widgets.protocols.ContainerProtocol\"\n    click D \"#magicgui.widgets.protocols.RangedWidgetProtocol\"\n    click E \"#magicgui.widgets.protocols.ButtonWidgetProtocol\"\n    click F \"#magicgui.widgets.protocols.CategoricalWidgetProtocol\"\n    click I \"#magicgui.widgets.protocols.SliderWidgetProtocol\"\n    click J \"#magicgui.widgets.protocols.TableWidgetProtocol\"\n    click K \"#magicgui.widgets.protocols.SupportsReadOnly\"\n    click L \"#magicgui.widgets.protocols.SupportsChoices\"\n    click M \"#magicgui.widgets.protocols.SupportsText\"\n    click N \"#magicgui.widgets.protocols.SupportsOrientation\"\n    click O \"#magicgui.widgets.protocols.DialogProtocol\"\n    click P \"#magicgui.widgets.protocols.MainWindowProtocol\"
"},{"location":"api/protocols/#widget-protocols","title":"Widget Protocols","text":""},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol","title":"magicgui.widgets.protocols.WidgetProtocol","text":"

Bases: Protocol

Base Widget Protocol: specifies methods that all widgets must provide.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_bind_parent_change_callback","title":"_mgui_bind_parent_change_callback(callback: Callable[[Any], None]) -> None abstractmethod","text":"

Bind callback to parent change event.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_close_widget","title":"_mgui_close_widget() -> None abstractmethod","text":"

Close widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_enabled","title":"_mgui_get_enabled() -> bool abstractmethod","text":"

Get the enabled state of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_height","title":"_mgui_get_height() -> int abstractmethod","text":"

Get the height of the widget.

The intention is to get the height of the widget after it is shown, for the purpose of unifying widget height in a layout. Backends may do what they need to accomplish this. For example, Qt can use sizeHint().height(), since height() may return something large if the widget has not yet been painted on screen.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_max_height","title":"_mgui_get_max_height() -> int abstractmethod","text":"

Get the maximum height of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_max_width","title":"_mgui_get_max_width() -> int abstractmethod","text":"

Get the maximum width of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_min_height","title":"_mgui_get_min_height() -> int abstractmethod","text":"

Get the minimum height of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_min_width","title":"_mgui_get_min_width() -> int abstractmethod","text":"

Get the minimum width of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_native_widget","title":"_mgui_get_native_widget() -> Any abstractmethod","text":"

Return the native backend widget instance.

This is generally the widget that has the layout.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_parent","title":"_mgui_get_parent() -> Widget abstractmethod","text":"

Return the parent widget of this widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_root_native_widget","title":"_mgui_get_root_native_widget() -> Any abstractmethod","text":"

Return the root native backend widget.

In most cases, this is the same as _mgui_get_native_widget. However, in cases where the native widget is in a scroll layout, this might be different.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_tooltip","title":"_mgui_get_tooltip() -> str abstractmethod","text":"

Get the tooltip for this widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_visible","title":"_mgui_get_visible() -> bool abstractmethod","text":"

Get widget visibility.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_width","title":"_mgui_get_width() -> int abstractmethod","text":"

Get the width of the widget.

The intention is to get the width of the widget after it is shown, for the purpose of unifying widget width in a layout. Backends may do what they need to accomplish this. For example, Qt can use sizeHint().width(), since width() may return something large if the widget has not yet been painted on screen.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_render","title":"_mgui_render() -> np.ndarray abstractmethod","text":"

Return an RGBA (MxNx4) numpy array bitmap of the rendered widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_enabled","title":"_mgui_set_enabled(enabled: bool) -> None abstractmethod","text":"

Set the enabled state of the widget to enabled.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_height","title":"_mgui_set_height(value: int) -> None abstractmethod","text":"

Set the height of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_max_height","title":"_mgui_set_max_height(value: int) -> None abstractmethod","text":"

Set the maximum height of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_max_width","title":"_mgui_set_max_width(value: int) -> None abstractmethod","text":"

Set the maximum width of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_min_height","title":"_mgui_set_min_height(value: int) -> None abstractmethod","text":"

Set the minimum height of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_min_width","title":"_mgui_set_min_width(value: int) -> None abstractmethod","text":"

Set the minimum width of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_parent","title":"_mgui_set_parent(widget: Widget) -> None abstractmethod","text":"

Set the parent widget of this widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_tooltip","title":"_mgui_set_tooltip(value: str | None) -> None abstractmethod","text":"

Set a tooltip for this widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_visible","title":"_mgui_set_visible(value: bool) -> None abstractmethod","text":"

Set widget visibility.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_width","title":"_mgui_set_width(value: int) -> None abstractmethod","text":"

Set the width of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ValueWidgetProtocol","title":"magicgui.widgets.protocols.ValueWidgetProtocol","text":"

Bases: WidgetProtocol, Protocol

Widget that has a current value, with getter/setter and on_change callback.

It is worth noting that the widget is the thing that has a value. Magicgui does not maintain & synchronize an independent model.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ValueWidgetProtocol._mgui_bind_change_callback","title":"_mgui_bind_change_callback(callback: Callable[[Any], Any]) -> None abstractmethod","text":"

Bind callback to value change event.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ValueWidgetProtocol._mgui_get_value","title":"_mgui_get_value() -> Any abstractmethod","text":"

Get current value of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ValueWidgetProtocol._mgui_set_value","title":"_mgui_set_value(value: Any) -> None abstractmethod","text":"

Set current value of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ButtonWidgetProtocol","title":"magicgui.widgets.protocols.ButtonWidgetProtocol","text":"

Bases: ValueWidgetProtocol, SupportsText, SupportsIcon, Protocol

The \"value\" in a ButtonWidget is the current (checked) state.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol","title":"magicgui.widgets.protocols.TableWidgetProtocol","text":"

Bases: ValueWidgetProtocol, SupportsReadOnly, Protocol

ValueWidget subclass intended for 2D tabular data, with row & column headers.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_bind_change_callback","title":"_mgui_bind_change_callback(callback: Callable[[Any], Any]) -> None abstractmethod","text":"

Bind callback to value change event.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_bind_column_headers_change_callback","title":"_mgui_bind_column_headers_change_callback(callback: Callable[[Any], None]) -> None abstractmethod","text":"

Bind callback to column headers change event.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_bind_row_headers_change_callback","title":"_mgui_bind_row_headers_change_callback(callback: Callable[[Any], None]) -> None abstractmethod","text":"

Bind callback to row headers change event.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_get_cell","title":"_mgui_get_cell(row: int, col: int) -> Any abstractmethod","text":"

Get current value of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_get_column_count","title":"_mgui_get_column_count() -> int abstractmethod","text":"

Get the number of columns in the table.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_get_column_headers","title":"_mgui_get_column_headers() -> tuple abstractmethod","text":"

Get current column headers of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_get_row_count","title":"_mgui_get_row_count() -> int abstractmethod","text":"

Get the number of rows in the table.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_get_row_headers","title":"_mgui_get_row_headers() -> tuple abstractmethod","text":"

Get current row headers of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_remove_column","title":"_mgui_remove_column(column: int) -> None abstractmethod","text":"

Remove column at index column.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_remove_row","title":"_mgui_remove_row(row: int) -> None abstractmethod","text":"

Remove row at index row.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_set_cell","title":"_mgui_set_cell(row: int, col: int, value: Any) -> None abstractmethod","text":"

Set current value of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_set_column_count","title":"_mgui_set_column_count(ncols: int) -> None abstractmethod","text":"

Set the number of columns in the table. (Create/delete as needed).

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_set_column_headers","title":"_mgui_set_column_headers(headers: Sequence) -> None abstractmethod","text":"

Set current column headers of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_set_row_count","title":"_mgui_set_row_count(nrows: int) -> None abstractmethod","text":"

Set the number of rows in the table. (Create/delete as needed).

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_set_row_headers","title":"_mgui_set_row_headers(headers: Sequence) -> None abstractmethod","text":"

Set current row headers of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol","title":"magicgui.widgets.protocols.RangedWidgetProtocol","text":"

Bases: ValueWidgetProtocol, Protocol

Value widget that supports numbers within a provided min/max range.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_get_adaptive_step","title":"_mgui_get_adaptive_step() -> bool abstractmethod","text":"

Get adaptive step status.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_get_max","title":"_mgui_get_max() -> float abstractmethod","text":"

Get the maximum possible value.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_get_min","title":"_mgui_get_min() -> float abstractmethod","text":"

Get the minimum possible value.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_get_step","title":"_mgui_get_step() -> float abstractmethod","text":"

Get the step size.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_set_adaptive_step","title":"_mgui_set_adaptive_step(value: bool) -> None abstractmethod","text":"

Set adaptive step status.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_set_max","title":"_mgui_set_max(value: float) -> None abstractmethod","text":"

Set the maximum possible value.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_set_min","title":"_mgui_set_min(value: float) -> None abstractmethod","text":"

Set the minimum possible value.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_set_step","title":"_mgui_set_step(value: float) -> None abstractmethod","text":"

Set the step size.

"},{"location":"api/protocols/#magicgui.widgets.protocols.CategoricalWidgetProtocol","title":"magicgui.widgets.protocols.CategoricalWidgetProtocol","text":"

Bases: ValueWidgetProtocol, SupportsChoices, Protocol

Categorical widget, that has a set of valid choices, and a current value.

It adds no additional methods.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SliderWidgetProtocol","title":"magicgui.widgets.protocols.SliderWidgetProtocol","text":"

Bases: RangedWidgetProtocol, SupportsOrientation, Protocol

Protocol for implementing a slider widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SliderWidgetProtocol._mgui_get_tracking","title":"_mgui_get_tracking() -> bool","text":"

If tracking is False, changed is only emitted when released.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SliderWidgetProtocol._mgui_set_readout_visibility","title":"_mgui_set_readout_visibility(visible: bool) -> None","text":"

Set visibility of readout widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SliderWidgetProtocol._mgui_set_tracking","title":"_mgui_set_tracking(tracking: bool) -> None","text":"

If tracking is False, changed is only emitted when released.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ContainerProtocol","title":"magicgui.widgets.protocols.ContainerProtocol","text":"

Bases: WidgetProtocol, SupportsOrientation, Protocol

Widget that can contain other widgets.

This generally manages a backend Layout.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ContainerProtocol._mgui_get_margins","title":"_mgui_get_margins() -> tuple[int, int, int, int] abstractmethod","text":"

Get the margins of the container.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ContainerProtocol._mgui_insert_widget","title":"_mgui_insert_widget(position: int, widget: Widget) -> None abstractmethod","text":"

Insert widget at the given position in the layout.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ContainerProtocol._mgui_remove_widget","title":"_mgui_remove_widget(widget: Widget) -> None abstractmethod","text":"

Remove the specified widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ContainerProtocol._mgui_set_margins","title":"_mgui_set_margins(margins: tuple[int, int, int, int]) -> None abstractmethod","text":"

Set the margins of the container.

"},{"location":"api/protocols/#magicgui.widgets.protocols.DialogProtocol","title":"magicgui.widgets.protocols.DialogProtocol","text":"

Bases: ContainerProtocol, Protocol

Protocol for modal (blocking) containers.

"},{"location":"api/protocols/#magicgui.widgets.protocols.DialogProtocol._mgui_exec","title":"_mgui_exec() -> None abstractmethod","text":"

Show the dialog and block.

"},{"location":"api/protocols/#magicgui.widgets.protocols.MainWindowProtocol","title":"magicgui.widgets.protocols.MainWindowProtocol","text":"

Bases: ContainerProtocol, Protocol

Application main widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.MainWindowProtocol._mgui_create_menu_item","title":"_mgui_create_menu_item(menu_name: str, action_name: str, callback: Callable | None = None, shortcut: str | None = None) -> None abstractmethod","text":"

Create a new menu item.

Parameters:

  • menu_name (str) \u2013

    The name of the menu to add the item to.

  • action_name (str) \u2013

    The name of the action to add.

  • callback (Callable | None, default: None ) \u2013

    A callback to be called when the action is triggered, by default None.

  • shortcut (str | None, default: None ) \u2013

    A keyboard shortcut for the action, by default None.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices","title":"magicgui.widgets.protocols.SupportsChoices","text":"

Bases: Protocol

Widget that has a set of valid choices.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_del_choice","title":"_mgui_del_choice(choice_name: str) -> None abstractmethod","text":"

Delete the provided choice_name and associated data.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_get_choice","title":"_mgui_get_choice(choice_name: str) -> Any abstractmethod","text":"

Get data for a single choice.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_get_choices","title":"_mgui_get_choices() -> tuple[tuple[str, Any], ...] abstractmethod","text":"

Get available choices.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_get_count","title":"_mgui_get_count() -> int abstractmethod","text":"

Return number of choices.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_get_current_choice","title":"_mgui_get_current_choice() -> str abstractmethod","text":"

Return the text of the currently selected choice.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_set_choice","title":"_mgui_set_choice(choice_name: str, data: Any) -> None abstractmethod","text":"

Set data for choice_name, or add a new item if choice_name doesn't exist.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_set_choices","title":"_mgui_set_choices(choices: Iterable[tuple[str, Any]]) -> None abstractmethod","text":"

Set available choices.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsOrientation","title":"magicgui.widgets.protocols.SupportsOrientation","text":"

Bases: Protocol

Widget that can be reoriented.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsOrientation._mgui_get_orientation","title":"_mgui_get_orientation() -> str abstractmethod","text":"

Get orientation, return either 'horizontal' or 'vertical'.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsOrientation._mgui_set_orientation","title":"_mgui_set_orientation(value: str) -> None abstractmethod","text":"

Set orientation, value will be 'horizontal' or 'vertical'.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsText","title":"magicgui.widgets.protocols.SupportsText","text":"

Bases: Protocol

Widget that have text (in addition to value)... like buttons.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsText._mgui_get_text","title":"_mgui_get_text() -> str abstractmethod","text":"

Get text.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsText._mgui_set_text","title":"_mgui_set_text(value: str) -> None abstractmethod","text":"

Set text.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsReadOnly","title":"magicgui.widgets.protocols.SupportsReadOnly","text":"

Bases: Protocol

Widget that can be read_only.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsReadOnly._mgui_get_read_only","title":"_mgui_get_read_only() -> bool abstractmethod","text":"

Get read_only status.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsReadOnly._mgui_set_read_only","title":"_mgui_set_read_only(value: bool) -> None abstractmethod","text":"

Set read_only.

"},{"location":"api/protocols/#application-protocol","title":"Application Protocol","text":""},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend","title":"magicgui.widgets.protocols.BaseApplicationBackend","text":"

Bases: ABC

Backend Application object.

Abstract class that provides an interface between backends and Application. Each backend must implement a subclass of BaseApplicationBackend, and implement all of its _mgui_xxx methods.

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_get_backend_name","title":"_mgui_get_backend_name() -> str abstractmethod","text":"

Return the name of the backend.

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_get_native_app","title":"_mgui_get_native_app() -> Any abstractmethod","text":"

Return the native GUI application instance.

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_process_events","title":"_mgui_process_events() -> None abstractmethod","text":"

Process all pending GUI events.

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_quit","title":"_mgui_quit() -> None abstractmethod","text":"

Quit the native GUI event loop.

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_run","title":"_mgui_run() -> None abstractmethod","text":"

Start the application.

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_start_timer","title":"_mgui_start_timer(interval: int = 0, on_timeout: Callable[[], None] | None = None, single: bool = False) -> None abstractmethod","text":"

Create and start a timer.

Parameters:

  • interval (int, default: 0 ) \u2013

    Interval between timeouts, by default 0

  • on_timeout (Optional[Callable[[], None]], default: None ) \u2013

    Function to call when timer finishes, by default None

  • single (bool, default: False ) \u2013

    Whether the timer should only fire once, by default False

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_stop_timer","title":"_mgui_stop_timer() -> None abstractmethod","text":"

Stop timer. Should check for the existence of the timer.

"},{"location":"api/type_map/","title":"magicgui.type_map","text":"Widget Description get_widget_class Return a Widget subclass for the value/annotation. register_type Register a widget_type to be used for all parameters with type type_. type_registered Context manager that temporarily registers a widget type for a given type_. type2callback Return any callbacks that have been registered for type_. TypeMap Storage for mapping from types to widgets and callbacks."},{"location":"api/type_map/#magicgui.type_map.get_widget_class","title":"magicgui.type_map.get_widget_class = _GLOBAL_TYPE_MAP.get_widget_class module-attribute","text":""},{"location":"api/type_map/#magicgui.type_map.register_type","title":"magicgui.type_map.register_type = _GLOBAL_TYPE_MAP.register_type module-attribute","text":""},{"location":"api/type_map/#magicgui.type_map.type_registered","title":"magicgui.type_map.type_registered = _GLOBAL_TYPE_MAP.type_registered module-attribute","text":""},{"location":"api/type_map/#magicgui.type_map.type2callback","title":"magicgui.type_map.type2callback = _GLOBAL_TYPE_MAP.type2callback module-attribute","text":""},{"location":"api/type_map/#magicgui.type_map.TypeMap","title":"magicgui.type_map.TypeMap","text":"

Storage for mapping from types to widgets and callbacks.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.copy","title":"copy()","text":"

Return a copy of the type map.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.create_widget","title":"create_widget(value=Undefined, annotation=None, name='', param_kind='POSITIONAL_OR_KEYWORD', label=None, gui_only=False, app=None, widget_type=None, options=None, is_result=False, raise_on_unknown=True)","text":"

Create and return appropriate widget subclass.

This factory function can be used to create a widget appropriate for the provided value and/or annotation provided. See Type Mapping Docs for details on how the widget type is determined from type annotations.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget, by default None

  • annotation (Any, default: None ) \u2013

    The type annotation for the parameter represented by the widget, by default None.

  • name (str, default: '' ) \u2013

    The name of the parameter represented by this widget. by default \"\"

  • param_kind (str, default: 'POSITIONAL_OR_KEYWORD' ) \u2013

    The :attr:inspect.Parameter.kind represented by this widget. Used in building signatures from multiple widgets, by default \"POSITIONAL_OR_KEYWORD\"

  • label (str, default: None ) \u2013

    A string to use for an associated Label widget (if this widget is being shown in a Container widget, and labels are on). By default, name will be used. Note: name refers the name of the parameter, as might be used in a signature, whereas label is just the label for that widget in the GUI.

  • gui_only (bool, default: False ) \u2013

    Whether the widget should be considered \"only for the gui\", or if it should be included in any widget container signatures, by default False

  • app (str, default: None ) \u2013

    The backend to use, by default None

  • widget_type (str or Type[WidgetProtocol] or None, default: None ) \u2013

    A class implementing a widget protocol or a string with the name of a magicgui widget type (e.g. \"Label\", \"PushButton\", etc...). If provided, this widget type will be used instead of the type autodetermined from value and/or annotation above.

  • options (dict, default: None ) \u2013

    Dict of options to pass to the Widget constructor, by default dict()

  • is_result (boolean, default: False ) \u2013

    Whether the widget belongs to an input or an output. By default, an input is assumed.

  • raise_on_unknown (bool, default: True ) \u2013

    Raise exception if no widget is found for the given type, by default True

Returns:

  • Widget \u2013

    An instantiated widget subclass

Raises:

  • TypeError \u2013

    If the provided or autodetected widget_type does not implement any known widget protocols

Examples:

from magicgui.widgets import create_widget\n\n# create a widget from a string value\nwdg = create_widget(value=\"hello world\")\nassert wdg.value == \"hello world\"\n\n# create a widget from a string annotation\nwdg = create_widget(annotation=str)\nassert wdg.value == \"\"\n
"},{"location":"api/type_map/#magicgui.type_map.TypeMap.get_widget_class","title":"get_widget_class(value=Undefined, annotation=Undefined, options=None, is_result=False, raise_on_unknown=True)","text":"

Return a Widget subclass for the value/annotation.

Parameters:

  • value (Any, default: Undefined ) \u2013

    A python value. Will be used to determine the widget type if an annotation is not explicitly provided by default None

  • annotation (Optional[Type], default: Undefined ) \u2013

    A type annotation, by default None

  • options (dict, default: None ) \u2013

    Options to pass when constructing the widget, by default {}

  • is_result (bool, default: False ) \u2013

    Identifies whether the returned widget should be tailored to an input or to an output.

  • raise_on_unknown (bool, default: True ) \u2013

    Raise exception if no widget is found for the given type, by default True

Returns:

  • Tuple[WidgetClass, dict] \u2013

    The WidgetClass, and dict that can be used for params. dict may be different than the options passed in.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.global_instance","title":"global_instance() staticmethod","text":"

Get the global type map.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.magic_factory","title":"magic_factory(function=None, *, layout='vertical', scrollable=False, labels=True, tooltips=True, call_button=None, auto_call=False, result_widget=False, main_window=False, app=None, persist=False, widget_init=None, raise_on_unknown=False, **param_options)","text":"

Return a MagicFactory for function.

magic_factory is nearly identical to the magicgui decorator with the following differences:

  1. Whereas magicgui returns a FunctionGui instance, magic_factory returns a callable that returns a FunctionGui instance. (Technically, it returns an instance of MagicFactory which you behaves exactly like a functools.partial for a FunctionGui instance.)
  2. magic_factory adds a widget_init method: a callable that will be called immediately after the FunctionGui instance is created. This can be used to add additional widgets to the layout, or to connect signals to the widgets.

Important

Whereas decorating a function with magicgui will immediately create a widget instance, magic_factory will not create a widget instance until the decorated object is called. This is often what you want in a library, whereas magicgui is useful for rapid, interactive development.

Parameters:

  • function (Callable, default: None ) \u2013

    The function to decorate. Optional to allow bare decorator with optional arguments. by default None

  • layout (str, default: 'vertical' ) \u2013

    The type of layout to use. Must be horizontal or vertical by default \"vertical\".

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether labels are shown in the widget. by default True

  • tooltips (bool, default: True ) \u2013

    Whether tooltips are shown when hovering over widgets. by default True

  • call_button (bool or str, default: None ) \u2013

    If True, create an additional button that calls the original function when clicked. If a str, set the button text. If None (the default), it defaults to True when auto_call is False, and False otherwise.

  • auto_call (bool, default: False ) \u2013

    If True, changing any parameter in either the GUI or the widget attributes will call the original function with the current settings. by default False

  • result_widget (bool, default: False ) \u2013

    Whether to display a LineEdit widget the output of the function when called, by default False

  • main_window (bool, default: False ) \u2013

    Whether this widget should be treated as the main app window, with menu bar, by default False.

  • app (Application or str, default: None ) \u2013

    A backend to use, by default None (use the default backend.)

  • persist (bool, default: False ) \u2013

    If True, when parameter values change in the widget, they will be stored to disk and restored when the widget is loaded again with persist = True. Call magicgui._util.user_cache_dir() to get the default cache location. By default False.

  • widget_init (callable, default: None ) \u2013

    A function that will be called with the newly created widget instance as its only argument. This can be used to customize the widget after it is created. by default None.

  • raise_on_unknown (bool, default: False ) \u2013

    If True, raise an error if magicgui cannot determine widget for function argument or return type. If False, ignore unknown types. By default False.

  • param_options (dict of dict, default: {} ) \u2013

    Any additional keyword arguments will be used as parameter-specific widget options. Keywords must match the name of one of the arguments in the function signature, and the value must be a dict of keyword arguments to pass to the widget constructor.

Returns:

  • result ( MagicFactory or Callable[[F], MagicFactory] ) \u2013

    If function is not None (such as when this is used as a bare decorator), returns a MagicFactory instance. If function is None such as when arguments are provided like magic_factory(auto_call=True), then returns a function that can be used as a decorator.

Examples:

>>> @magic_factory\n... def my_function(a: int = 1, b: str = \"hello\"):\n...     pass\n>>> my_widget = my_function()\n>>> my_widget.show()\n>>> my_widget.a.value == 1  # True\n>>> my_widget.b.value = \"world\"\n
"},{"location":"api/type_map/#magicgui.type_map.TypeMap.magicgui","title":"magicgui(function=None, *, layout='vertical', scrollable=False, labels=True, tooltips=True, call_button=None, auto_call=False, result_widget=False, main_window=False, app=None, persist=False, raise_on_unknown=False, **param_options)","text":"

Return a FunctionGui for function.

Parameters:

  • function (Callable, default: None ) \u2013

    The function to decorate. Optional to allow bare decorator with optional arguments. by default None

  • layout (str, default: 'vertical' ) \u2013

    The type of layout to use. Must be horizontal or vertical by default \"vertical\".

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether labels are shown in the widget. by default True

  • tooltips (bool, default: True ) \u2013

    Whether tooltips are shown when hovering over widgets. by default True

  • call_button (bool or str, default: None ) \u2013

    If True, create an additional button that calls the original function when clicked. If a str, set the button text. If None (the default), it defaults to True when auto_call is False, and False otherwise.

  • auto_call (bool, default: False ) \u2013

    If True, changing any parameter in either the GUI or the widget attributes will call the original function with the current settings. by default False

  • result_widget (bool, default: False ) \u2013

    Whether to display a LineEdit widget the output of the function when called, by default False

  • main_window (bool, default: False ) \u2013

    Whether this widget should be treated as the main app window, with menu bar, by default False.

  • app (Application or str, default: None ) \u2013

    A backend to use, by default None (use the default backend.)

  • persist (bool, default: False ) \u2013

    If True, when parameter values change in the widget, they will be stored to disk and restored when the widget is loaded again with persist = True. Call magicgui._util.user_cache_dir() to get the default cache location. By default False.

  • raise_on_unknown (bool, default: False ) \u2013

    If True, raise an error if magicgui cannot determine widget for function argument or return type. If False, ignore unknown types. By default False.

  • param_options (dict[str, dict], default: {} ) \u2013

    Any additional keyword arguments will be used as parameter-specific options. Keywords must match the name of one of the arguments in the function signature, and the value must be a dict of keyword arguments to pass to the widget constructor.

Returns:

  • result ( FunctionGui or Callable[[F], FunctionGui] ) \u2013

    If function is not None (such as when this is used as a bare decorator), returns a FunctionGui instance, which is a list-like container of autogenerated widgets corresponding to each parameter in the function. If function is None such as when arguments are provided like magicgui(auto_call=True), then returns a function that can be used as a decorator.

Examples:

>>> @magicgui\n... def my_function(a: int = 1, b: str = \"hello\"):\n...     pass\n>>> my_function.show()\n>>> my_function.a.value == 1  # True\n>>> my_function.b.value = \"world\"\n
"},{"location":"api/type_map/#magicgui.type_map.TypeMap.match_return_type","title":"match_return_type(type_)","text":"

Check simple type mappings for result widgets.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.match_type","title":"match_type(type_, default=None)","text":"

Check simple type mappings.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.register_type","title":"register_type(type_=None, *, widget_type=None, return_callback=None, **options)","text":"

Register a widget_type to be used for all parameters with type type_.

Note: registering a Union (or Optional) type effectively registers all types in the union with the arguments.

Parameters:

  • type_ (type, default: None ) \u2013

    The type for which a widget class or return callback will be provided.

  • widget_type (WidgetRef, default: None ) \u2013

    A widget class from the current backend that should be used whenever type_ is used as the type annotation for an argument in a decorated function, by default None

  • return_callback (ReturnCallback | None, default: None ) \u2013

    If provided, whenever type_ is declared as the return type of a decorated function, return_callback(widget, value, return_type) will be called whenever the decorated function is called... where widget is the Widget instance, and value is the return value of the decorated function.

  • options (Any, default: {} ) \u2013

    key value pairs where the keys are valid dict

Raises:

  • ValueError \u2013

    If none of widget_type, return_callback, bind or choices are provided.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.type2callback","title":"type2callback(type_)","text":"

Return any callbacks that have been registered for type_.

Parameters:

  • type_ (type) \u2013

    The type_ to look up.

Returns:

  • list of callable \u2013

    Where a return callback accepts two arguments (gui, value) and does something.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.type_registered","title":"type_registered(type_, *, widget_type=None, return_callback=None, **options)","text":"

Context manager that temporarily registers a widget type for a given type_.

When the context is exited, the previous widget type associations for type_ is restored.

Parameters:

  • type_ (_T) \u2013

    The type for which a widget class or return callback will be provided.

  • widget_type (Optional[WidgetRef], default: None ) \u2013

    A widget class from the current backend that should be used whenever type_ is used as the type annotation for an argument in a decorated function, by default None

  • return_callback (ReturnCallback | None, default: None ) \u2013

    If provided, whenever type_ is declared as the return type of a decorated function, return_callback(widget, value, return_type) will be called whenever the decorated function is called... where widget is the Widget instance, and value is the return value of the decorated function.

  • options (Any, default: {} ) \u2013

    key value pairs where the keys are valid dict

"},{"location":"api/widgets/","title":"Widget Index","text":"

Here you will find a list of all the widgets that are available in magicgui. Each widget has a link to its own documentation page, where you can find more information about the widget, including its parameters and events.

Widget Description CheckBox A checkbox with a text label. ComboBox A dropdown menu, allowing selection between multiple choices. Container A Widget to contain other widgets. DateEdit A widget for editing dates. DateTimeEdit A widget for editing dates and times. Dialog A modal container. EmptyWidget A base widget with no value. FileEdit A LineEdit widget with a button that opens a FileDialog. FloatRangeSlider A slider widget to adjust a range defined by two float values within a range. FloatSlider A slider widget to adjust an integer value within a range. FloatSpinBox A widget to edit a float with clickable up/down arrows. FunctionGui Wrapper for a container of widgets representing a callable object. Image A non-editable image display. Label A non-editable text display. LineEdit A one-line text editor. ListEdit A widget to represent a list of values. LiteralEvalLineEdit A one-line text editor that evaluates strings as python literals. LogSlider A slider widget to adjust a numerical value logarithmically within a range. MainFunctionGui Container of widgets as a Main Application Window. MainWindow A Widget to contain other widgets, includes a menu bar. Password A one-line text editor that obscures input. ProgressBar A progress bar widget. PushButton A clickable command button. QuantityEdit A combined LineEdit and ComboBox to edit a pint.Quantity. RadioButton A radio button with a text label. RadioButtons An exclusive group of radio buttons, providing a choice from multiple choices. RangeEdit A widget to represent a python range object, with start/stop/step. RangeSlider A slider widget to adjust a range between two integer values within a range. Select A list of options, allowing selection between multiple choices. SliceEdit A widget to represent slice objects, with start/stop/step. Slider A slider widget to adjust an integer value within a range. SpinBox A widget to edit an integer with clickable up/down arrows. Table A widget to represent columnar or 2D data with headers. TextEdit A widget to edit and display both plain and rich text. TimeEdit A widget for editing times. ToolBar Toolbar that contains a set of controls. TupleEdit A widget to represent a tuple of values."},{"location":"api/widgets/CheckBox/","title":"CheckBox","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/CheckBox/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the button is clicked (may also be connected at the alias clicked).
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/CheckBox/#magicgui.widgets.CheckBox","title":"CheckBox","text":"

Bases: ButtonWidget

A checkbox with a text label.

Parameters:

  • value (bool, default: Undefined ) \u2013

    The starting state of the widget.

  • text (str, default: None ) \u2013

    The text to display on the button. If not provided, will use name.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/ComboBox/","title":"ComboBox","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/ComboBox/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/ComboBox/#magicgui.widgets.ComboBox","title":"ComboBox","text":"

Bases: CategoricalWidget

A dropdown menu, allowing selection between multiple choices.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The initially selected choice.

  • choices (Enum, Iterable, or Callable, default: () ) \u2013

    Available choices displayed in the combo box.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/Container/","title":"Container","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/Container/#signals","title":"Signals","text":"
  • changed(object) - Emitted with self when any sub-widget in the container changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Container/#magicgui.widgets.Container","title":"Container","text":"

Bases: ContainerWidget[WidgetVar]

A Widget to contain other widgets.

Note that Container implements the typing.MutableSequence interface, so you can use it like a list to add and remove widgets.

Parameters:

  • widgets (Sequence[Widget], default: () ) \u2013

    A sequence of widgets with which to initialize the container, by default None.

  • layout (str, default: 'vertical' ) \u2013

    The layout for the container. must be one of {'horizontal', 'vertical'}. by default \"vertical\"

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether each widget should be shown with a corresponding Label widget to the left, by default True. Note: the text for each widget defaults to widget.name, but can be overridden by setting widget.label.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/DateEdit/","title":"DateEdit","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/DateEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/DateEdit/#magicgui.widgets.DateEdit","title":"DateEdit","text":"

Bases: ValueWidget[date]

A widget for editing dates.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/DateTimeEdit/","title":"DateTimeEdit","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/DateTimeEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/DateTimeEdit/#magicgui.widgets.DateTimeEdit","title":"DateTimeEdit","text":"

Bases: ValueWidget[datetime]

A widget for editing dates and times.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/Dialog/","title":"Dialog","text":"

Available in backends: qt

"},{"location":"api/widgets/Dialog/#signals","title":"Signals","text":"
  • changed(object) - Emitted with self when any sub-widget in the container changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Dialog/#magicgui.widgets.Dialog","title":"Dialog","text":"

Bases: DialogWidget

A modal container.

Parameters:

  • widgets (Sequence[Widget], default: () ) \u2013

    A sequence of widgets with which to initialize the container, by default None.

  • layout (str, default: 'vertical' ) \u2013

    The layout for the container. must be one of {'horizontal', 'vertical'}. by default \"vertical\"

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether each widget should be shown with a corresponding Label widget to the left, by default True. Note: the text for each widget defaults to widget.name, but can be overridden by setting widget.label.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/EmptyWidget/","title":"EmptyWidget","text":"

Available in backends:

"},{"location":"api/widgets/EmptyWidget/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/EmptyWidget/#magicgui.widgets.EmptyWidget","title":"EmptyWidget","text":"

Bases: ValuedContainerWidget[Any]

A base widget with no value.

This widget is primarily here to serve as a \"hidden widget\" to which a value or callback can be bound.

"},{"location":"api/widgets/EmptyWidget/#magicgui.widgets.EmptyWidget.__repr__","title":"__repr__() -> str","text":"

Return string repr (avoid looking for value).

"},{"location":"api/widgets/EmptyWidget/#magicgui.widgets.EmptyWidget.get_value","title":"get_value() -> Any","text":"

Return value if one has been manually set... otherwise return Param.empty.

"},{"location":"api/widgets/FileEdit/","title":"FileEdit","text":"

Available in backends:

"},{"location":"api/widgets/FileEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/FileEdit/#magicgui.widgets.FileEdit","title":"FileEdit","text":"

Bases: ValuedContainerWidget[Union[Path, tuple[Path, ...], None]]

A LineEdit widget with a button that opens a FileDialog.

Parameters:

  • mode (FileDialogMode or str, default: EXISTING_FILE ) \u2013
    • 'r' returns one existing file.
    • 'rm' return one or more existing files.
    • 'w' return one file name that does not have to exist.
    • 'd' returns one existing directory.
  • filter (str, default: None ) \u2013

    The filter is used to specify the kind of files that should be shown. It should be a glob-style string, like '*.png' (this may be backend-specific)

"},{"location":"api/widgets/FileEdit/#magicgui.widgets.FileEdit.mode","title":"mode: FileDialogMode property writable","text":"

Mode for the FileDialog.

"},{"location":"api/widgets/FileEdit/#magicgui.widgets.FileEdit.__repr__","title":"__repr__() -> str","text":"

Return string representation.

"},{"location":"api/widgets/FileEdit/#magicgui.widgets.FileEdit.get_value","title":"get_value() -> tuple[Path, ...] | Path | None","text":"

Return current value.

"},{"location":"api/widgets/FileEdit/#magicgui.widgets.FileEdit.set_value","title":"set_value(value: Sequence[PathLike] | PathLike | None) -> None","text":"

Set current file path.

"},{"location":"api/widgets/FloatRangeSlider/","title":"FloatRangeSlider","text":"

Available in backends: qt

"},{"location":"api/widgets/FloatRangeSlider/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/FloatRangeSlider/#magicgui.widgets.FloatRangeSlider","title":"FloatRangeSlider","text":"

Bases: MultiValuedSliderWidget

A slider widget to adjust a range defined by two float values within a range.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • orientation ((str, {'horizontal', 'vertical'}), default: 'horizontal' ) \u2013

    The orientation for the slider, by default \"horizontal\"

  • readout (bool, default: True ) \u2013

    Whether to show the editable spinbox next to the slider

  • tracking (bool, default: True ) \u2013

    If tracking is enabled (the default), the slider emits the changed signal while the slider is being dragged. If tracking is disabled, the slider emits the changed signal only after the user releases the slider.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/FloatSlider/","title":"FloatSlider","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/FloatSlider/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/FloatSlider/#magicgui.widgets.FloatSlider","title":"FloatSlider","text":"

Bases: SliderWidget[float]

A slider widget to adjust an integer value within a range.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • orientation ((str, {'horizontal', 'vertical'}), default: 'horizontal' ) \u2013

    The orientation for the slider, by default \"horizontal\"

  • readout (bool, default: True ) \u2013

    Whether to show the editable spinbox next to the slider

  • tracking (bool, default: True ) \u2013

    If tracking is enabled (the default), the slider emits the changed signal while the slider is being dragged. If tracking is disabled, the slider emits the changed signal only after the user releases the slider.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/FloatSpinBox/","title":"FloatSpinBox","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/FloatSpinBox/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/FloatSpinBox/#magicgui.widgets.FloatSpinBox","title":"FloatSpinBox","text":"

Bases: RangedWidget[float]

A widget to edit a float with clickable up/down arrows.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/FunctionGui/","title":"FunctionGui","text":"

Available in backends:

"},{"location":"api/widgets/FunctionGui/#signals","title":"Signals","text":"
  • called(object) - Emitted with the result after the function is called.
  • changed(object) - Emitted with self when any sub-widget in the container changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui","title":"FunctionGui","text":"

Bases: Container, Generic[_P, _R]

Wrapper for a container of widgets representing a callable object.

Parameters:

  • function (Callable) \u2013

    A callable to turn into a GUI

  • call_button (bool | str | None, default: None ) \u2013

    If True, create an additional button that calls the original function when clicked. If a str, set the button text. by default False when auto_call is True, and True otherwise. The button can be accessed from the .call_button property.

  • layout (str, default: 'vertical' ) \u2013

    The type of layout to use. Must be horizontal or vertical by default \"horizontal\".

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether labels are shown in the widget. by default True

  • tooltips (bool, default: True ) \u2013

    Whether tooltips are shown when hovering over widgets. by default True

  • app (Application | str | None, default: None ) \u2013

    A backend to use, by default None (use the default backend.)

  • visible (bool, default: None ) \u2013

    Whether to immediately show the widget. If False, widget is explicitly hidden. If None, widget is not shown, but will be shown if a parent container is shown, by default None.

  • auto_call (bool, default: False ) \u2013

    If True, changing any parameter in either the GUI or the widget attributes will call the original function with the current settings. by default False

  • result_widget (bool, default: False ) \u2013

    Whether to display a LineEdit widget the output of the function when called, by default False

  • param_options (dict, default: None ) \u2013

    A dict of name: widget_options dict for each parameter in the function. Will be passed to magic_signature by default None

  • name (str, default: None ) \u2013

    A name to assign to the Container widget, by default function.__name__

  • persist (bool, default: False ) \u2013

    If True, when parameter values change in the widget, they will be stored to disk (in ~/.config/magicgui/cache) and restored when the widget is loaded again with persist = True. By default, False.

  • raise_on_unknown (bool, default: False ) \u2013

    If True, raise an error if a parameter annotation is not recognized.

Raises:

  • TypeError \u2013

    If unexpected keyword arguments are provided

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.__signature__","title":"__signature__: MagicSignature property","text":"

Return a MagicSignature object representing the current state of the gui.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.call_button","title":"call_button: PushButton | None property","text":"

Return the call button.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.call_count","title":"call_count: int property","text":"

Return the number of times the function has been called.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.result_name","title":"result_name: str property writable","text":"

Return a name that can be used for the result of this magicfunction.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.return_annotation","title":"return_annotation: Any property","text":"

Return annotation for inspect.Signature conversion.

ForwardRefs will be resolve when setting the annotation.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.__call__","title":"__call__(*args: _P.args, **kwargs: _P.kwargs) -> _R","text":"

Call the original function with the current parameter values from the Gui.

You may pass a update_widget=True keyword argument to update the widget values to match the current parameter values before calling the function.

It is also possible to override the current parameter values from the GUI by providing args/kwargs to the function call. Only those provided will override the ones from the gui. A called signal will also be emitted with the results.

Returns:

  • result ( Any ) \u2013

    whatever the return value of the original function would have been.

Examples:

gui = FunctionGui(func, show=True)\n\n# then change parameters in the gui, or by setting:  gui.param.value = something\n\ngui()  # calls the original function with the current parameters\n
"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.__get__","title":"__get__(obj: object, objtype: type | None = None) -> FunctionGui","text":"

Provide descriptor protocol.

This allows the @magicgui decorator to work on a function as well as a method. If a method on a class is decorated with @magicgui, then accessing the attribute on an instance of that class will return a version of the FunctionGui in which the first argument of the function is bound to the instance. (Just like what you'd expect with the @property decorator.)

Returns:

  • bound ( FunctionGui ) \u2013

    A new FunctionGui instance.

Examples:

>>> class MyClass:\n...     @magicgui\n...     def my_method(self, x=1):\n...         print(locals())\n...\n>>> c = MyClass()\n>>> c.my_method  # the FunctionGui that can be used as a widget\n\n# calling it works as usual, with `c` provided as `self`\n>>> c.my_method(x=34)\n{'self': <__main__.MyClass object at 0x7fb610e455e0>, 'x': 34}\n
"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.__repr__","title":"__repr__() -> str","text":"

Return string representation of instance.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.__set__","title":"__set__(obj: Any, value: Any) -> NoReturn","text":"

Prevent setting a magicgui attribute.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.copy","title":"copy() -> FunctionGui","text":"

Return a copy of this FunctionGui.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.reset_call_count","title":"reset_call_count() -> None","text":"

Reset the call count to 0.

"},{"location":"api/widgets/Image/","title":"Image","text":"

Available in backends: qt

"},{"location":"api/widgets/Image/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Image/#magicgui.widgets.Image","title":"Image","text":"

Bases: ValueWidget

A non-editable image display.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.image_data","title":"image_data: np.ndarray | None property","text":"

Return image data.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.image_rgba","title":"image_rgba: np.ndarray | None property","text":"

Return rendered numpy array.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.__repr__","title":"__repr__() -> str","text":"

Return representation of widget of instance.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.get_clim","title":"get_clim() -> tuple[float | None, float | None]","text":"

Get contrast limits (for monochromatic images).

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.get_value","title":"get_value()","text":"

Return current image array.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.scale_widget_to_image_size","title":"scale_widget_to_image_size()","text":"

Set the size of the widget to the size of the image.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.set_clim","title":"set_clim(vmin: float | None = None, vmax: float | None = None)","text":"

Set contrast limits (for monochromatic images).

Parameters:

  • vmin (float, default: None ) \u2013

    The min contrast limit to use when scaling monochromatic images

  • vmax (float, default: None ) \u2013

    The max contrast limit to use when scaling monochromatic images

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.set_cmap","title":"set_cmap(cmap: str | Colormap | matplotlib.colors.Colormap)","text":"

Set colormap (for monochromatic images).

Parameters:

  • cmap (str, magicgui.types.Colormap, or matplotlib.colors.Colormap) \u2013

    A colormap to use for monochromatic images. If a string, matplotlib must be installed and the colormap will be selected with cm.get_cmap(cmap).

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.set_data","title":"set_data(val: str | Path | np.ndarray | PIL.Image.Image, cmap: str | Colormap | matplotlib.colors.Colormap | None = None, norm: _mpl_image.Normalize | matplotlib.colors.Normalize | None = None, vmin: float | None = None, vmax: float | None = None, width: int | Literal['auto'] | None = None, height: int | Literal['auto'] | None = None, format: str | None = None)","text":"

Set image data with various optional display parameters.

Parameters:

  • val ((str, Path, ndarray or Image)) \u2013

    The image data or file to load. Data must be 2D (monochromatic), or 3D: MxNx3 (RGB) or MxNx4 (RGBA).

  • cmap (str, magicgui.types.Colormap, or matplotlib.colors.Colormap, default: None ) \u2013

    A colormap to use for monochromatic images. If a string, matplotlib must be installed and the colormap will be selected with cm.get_cmap(cmap).

  • norm (magicgui.types.Normalize, or matplotlib.colors.Normalize, default: None ) \u2013

    A normalization object to use for rendering images. Accepts matplotlib Normalize objects.

  • vmin (float, default: None ) \u2013

    The min contrast limit to use when scaling monochromatic images

  • vmax (float, default: None ) \u2013

    The max contrast limit to use when scaling monochromatic images

  • width (int or 'auto', default: None ) \u2013

    Set the width of the widget. If \"auto\", sets the widget size to the image size (1:1). If width is provided, height is auto-set based on aspect ratio.

  • height (int or 'auto', default: None ) \u2013

    Set the height of the widget. If \"auto\", sets the widget size to the image size (1:1). If width is provided, height is auto-set based on aspect ratio.

  • format (str, default: None ) \u2013

    Force image format type for imread when val is provided as a string, by default None

Raises:

  • TypeError \u2013

    If the provided data shape or type is invalid.

  • ImportError \u2013

    If a string is provided for val and PIL is not installed.

  • RuntimeError \u2013

    If a PIL.Image.Image instance is provided as data, with an unrecognized image mode.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.set_norm","title":"set_norm(norm: Normalize | matplotlib.colors.Normalize)","text":"

Set normalization method.

Parameters:

  • norm (magicgui.types.Normalize, or matplotlib.colors.Normalize) \u2013

    A normalization object to use for rendering images. Accepts matplotlib Normalize objects.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.set_value","title":"set_value(value)","text":"

Set current data. Alias for image.set_data(value).

"},{"location":"api/widgets/Label/","title":"Label","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/Label/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Label/#magicgui.widgets.Label","title":"Label","text":"

Bases: ValueWidget[str]

A non-editable text display.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/LineEdit/","title":"LineEdit","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/LineEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/LineEdit/#magicgui.widgets.LineEdit","title":"LineEdit","text":"

Bases: ValueWidget[str]

A one-line text editor.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/ListEdit/","title":"ListEdit","text":"

Available in backends:

"},{"location":"api/widgets/ListEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/ListEdit/#magicgui.widgets.ListEdit","title":"ListEdit","text":"

Bases: ValuedContainerWidget[list[_V]]

A widget to represent a list of values.

A ListEdit container can create a list with multiple objects of same type. It will contain many child widgets and their value is represented as a Python list object. If a list is given as the initial value, types of child widgets are determined from the contents. Number of contents can be adjusted with +/- buttons.

Parameters:

  • value (Iterable, default: Undefined ) \u2013

    The starting value for the widget.

  • nullable (bool) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • options (dict, default: None ) \u2013

    Widget options of child widgets.

"},{"location":"api/widgets/ListEdit/#magicgui.widgets.ListEdit.annotation","title":"annotation: Any property writable","text":"

Return type annotation for the parameter represented by the widget.

ForwardRefs will be resolve when setting the annotation. For ListEdit, annotation will be like 'list[str]'.

"},{"location":"api/widgets/ListEdit/#magicgui.widgets.ListEdit.data","title":"data: ListDataView[_V] property writable","text":"

Return a data view of current value.

"},{"location":"api/widgets/ListEdit/#magicgui.widgets.ListEdit.__delitem__","title":"__delitem__(key: int | slice) -> None","text":"

Delete child widget(s).

"},{"location":"api/widgets/ListEdit/#magicgui.widgets.ListEdit.get_value","title":"get_value() -> list[_V]","text":"

Return current value as a list object.

"},{"location":"api/widgets/LiteralEvalLineEdit/","title":"LiteralEvalLineEdit","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/LiteralEvalLineEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/LiteralEvalLineEdit/#magicgui.widgets.LiteralEvalLineEdit","title":"LiteralEvalLineEdit","text":"

Bases: ValueWidget[str]

A one-line text editor that evaluates strings as python literals.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/LogSlider/","title":"LogSlider","text":"

Available in backends:

"},{"location":"api/widgets/LogSlider/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/LogSlider/#magicgui.widgets.LogSlider","title":"LogSlider","text":"

Bases: TransformedRangedWidget

A slider widget to adjust a numerical value logarithmically within a range.

Parameters:

  • base (Enum, Iterable, or Callable, default: e ) \u2013

    The base to use for the log, by default math.e.

"},{"location":"api/widgets/LogSlider/#magicgui.widgets.LogSlider.base","title":"base: float property writable","text":"

Return base used for the log.

"},{"location":"api/widgets/LogSlider/#magicgui.widgets.LogSlider.tracking","title":"tracking: bool property writable","text":"

Return whether slider tracking is enabled.

If tracking is enabled (the default), the slider emits the changed() signal while the slider is being dragged. If tracking is disabled, the slider emits the changed() signal only when the user releases the slider.

"},{"location":"api/widgets/MainFunctionGui/","title":"MainFunctionGui","text":"

Available in backends:

"},{"location":"api/widgets/MainFunctionGui/#signals","title":"Signals","text":"
  • called(object) - Emitted with the result after the function is called.
  • changed(object) - Emitted with self when any sub-widget in the container changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/MainFunctionGui/#magicgui.widgets.MainFunctionGui","title":"MainFunctionGui","text":"

Bases: FunctionGui[_P, _R], MainWindow

Container of widgets as a Main Application Window.

"},{"location":"api/widgets/MainWindow/","title":"MainWindow","text":"

Available in backends: qt

"},{"location":"api/widgets/MainWindow/#signals","title":"Signals","text":"
  • changed(object) - Emitted with self when any sub-widget in the container changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/MainWindow/#magicgui.widgets.MainWindow","title":"MainWindow","text":"

Bases: MainWindowWidget

A Widget to contain other widgets, includes a menu bar.

Parameters:

  • widgets (Sequence[Widget], default: () ) \u2013

    A sequence of widgets with which to initialize the container, by default None.

  • layout (str, default: 'vertical' ) \u2013

    The layout for the container. must be one of {'horizontal', 'vertical'}. by default \"vertical\"

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether each widget should be shown with a corresponding Label widget to the left, by default True. Note: the text for each widget defaults to widget.name, but can be overridden by setting widget.label.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/Password/","title":"Password","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/Password/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Password/#magicgui.widgets.Password","title":"Password","text":"

Bases: ValueWidget[str]

A one-line text editor that obscures input.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/ProgressBar/","title":"ProgressBar","text":"

Available in backends: qt

"},{"location":"api/widgets/ProgressBar/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/ProgressBar/#magicgui.widgets.ProgressBar","title":"ProgressBar","text":"

Bases: SliderWidget[float]

A progress bar widget.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • orientation ((str, {'horizontal', 'vertical'}), default: 'horizontal' ) \u2013

    The orientation for the slider, by default \"horizontal\"

  • readout (bool, default: True ) \u2013

    Whether to show the editable spinbox next to the slider

  • tracking (bool, default: True ) \u2013

    If tracking is enabled (the default), the slider emits the changed signal while the slider is being dragged. If tracking is disabled, the slider emits the changed signal only after the user releases the slider.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/ProgressBar/#magicgui.widgets.ProgressBar.step","title":"step: float property writable","text":"

Step size for widget values.

"},{"location":"api/widgets/ProgressBar/#magicgui.widgets.ProgressBar.decrement","title":"decrement(val: float | None = None) -> None","text":"

Decrease current value by step size, or provided value.

"},{"location":"api/widgets/ProgressBar/#magicgui.widgets.ProgressBar.increment","title":"increment(val: float | None = None) -> None","text":"

Increase current value by step size, or provided value.

"},{"location":"api/widgets/PushButton/","title":"PushButton","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/PushButton/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the button is clicked (may also be connected at the alias clicked).
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/PushButton/#magicgui.widgets.PushButton","title":"PushButton","text":"

Bases: ButtonWidget

A clickable command button.

Parameters:

  • value (bool, default: Undefined ) \u2013

    The starting state of the widget.

  • text (str, default: None ) \u2013

    The text to display on the button. If not provided, will use name.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/QuantityEdit/","title":"QuantityEdit","text":"

Available in backends: qt

"},{"location":"api/widgets/QuantityEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/QuantityEdit/#magicgui.widgets.QuantityEdit","title":"QuantityEdit","text":"

Bases: ValueWidget

A combined LineEdit and ComboBox to edit a pint.Quantity.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/RadioButton/","title":"RadioButton","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/RadioButton/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the button is clicked (may also be connected at the alias clicked).
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/RadioButton/#magicgui.widgets.RadioButton","title":"RadioButton","text":"

Bases: ButtonWidget

A radio button with a text label.

Parameters:

  • value (bool, default: Undefined ) \u2013

    The starting state of the widget.

  • text (str, default: None ) \u2013

    The text to display on the button. If not provided, will use name.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/RadioButtons/","title":"RadioButtons","text":"

Available in backends: qt

"},{"location":"api/widgets/RadioButtons/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/RadioButtons/#magicgui.widgets.RadioButtons","title":"RadioButtons","text":"

Bases: CategoricalWidget, _OrientationMixin

An exclusive group of radio buttons, providing a choice from multiple choices.

Parameters:

  • value (Any) \u2013

    The initially selected choice.

  • choices (Enum, Iterable, or Callable, default: () ) \u2013

    Available choices displayed in the combo box.

  • bind (Callable[[ValueWidget], Any] | Any) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/RangeEdit/","title":"RangeEdit","text":"

Available in backends:

"},{"location":"api/widgets/RangeEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/RangeEdit/#magicgui.widgets.RangeEdit","title":"RangeEdit","text":"

Bases: _RangeOrSliceEdit[range]

A widget to represent a python range object, with start/stop/step.

A range object produces a sequence of integers from start (inclusive) to stop (exclusive) by step. range(i, j) produces i, i+1, i+2, ..., j-1. start defaults to 0, and stop is omitted! range(4) produces 0, 1, 2, 3. These are exactly the valid indices for a list of 4 elements. When step is given, it specifies the increment (or decrement).

Parameters:

  • start (int, default: 0 ) \u2013

    The range start value, by default 0

  • stop (int, default: 10 ) \u2013

    The range stop value, by default 10

  • step (int, default: 1 ) \u2013

    The range step value, by default 1

"},{"location":"api/widgets/RangeSlider/","title":"RangeSlider","text":"

Available in backends: qt

"},{"location":"api/widgets/RangeSlider/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/RangeSlider/#magicgui.widgets.RangeSlider","title":"RangeSlider","text":"

Bases: MultiValuedSliderWidget

A slider widget to adjust a range between two integer values within a range.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • orientation ((str, {'horizontal', 'vertical'}), default: 'horizontal' ) \u2013

    The orientation for the slider, by default \"horizontal\"

  • readout (bool, default: True ) \u2013

    Whether to show the editable spinbox next to the slider

  • tracking (bool, default: True ) \u2013

    If tracking is enabled (the default), the slider emits the changed signal while the slider is being dragged. If tracking is disabled, the slider emits the changed signal only after the user releases the slider.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/Select/","title":"Select","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/Select/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Select/#magicgui.widgets.Select","title":"Select","text":"

Bases: CategoricalWidget

A list of options, allowing selection between multiple choices.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The initially selected choice.

  • choices (Enum, Iterable, or Callable, default: () ) \u2013

    Available choices displayed in the combo box.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/SliceEdit/","title":"SliceEdit","text":"

Available in backends:

"},{"location":"api/widgets/SliceEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/SliceEdit/#magicgui.widgets.SliceEdit","title":"SliceEdit","text":"

Bases: _RangeOrSliceEdit[slice]

A widget to represent slice objects, with start/stop/step.

slice(stop) slice(start, stop[, step])

Slice objects may be used for extended slicing (e.g. a[0:10:2])

Parameters:

  • start (int, default: 0 ) \u2013

    The range start value, by default 0

  • stop (int, default: 10 ) \u2013

    The range stop value, by default 10

  • step (int, default: 1 ) \u2013

    The range step value, by default 1

"},{"location":"api/widgets/Slider/","title":"Slider","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/Slider/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Slider/#magicgui.widgets.Slider","title":"Slider","text":"

Bases: SliderWidget[int]

A slider widget to adjust an integer value within a range.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • orientation ((str, {'horizontal', 'vertical'}), default: 'horizontal' ) \u2013

    The orientation for the slider, by default \"horizontal\"

  • readout (bool, default: True ) \u2013

    Whether to show the editable spinbox next to the slider

  • tracking (bool, default: True ) \u2013

    If tracking is enabled (the default), the slider emits the changed signal while the slider is being dragged. If tracking is disabled, the slider emits the changed signal only after the user releases the slider.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/SpinBox/","title":"SpinBox","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/SpinBox/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/SpinBox/#magicgui.widgets.SpinBox","title":"SpinBox","text":"

Bases: RangedWidget[int]

A widget to edit an integer with clickable up/down arrows.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/Table/","title":"Table","text":"

Available in backends: qt

"},{"location":"api/widgets/Table/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Table/#magicgui.widgets.Table","title":"Table","text":"

Bases: ValueWidget[Mapping[TblKey, Collection]], _ReadOnlyMixin, MutableMapping[TblKey, list]

A widget to represent columnar or 2D data with headers.

Tables behave like plain dicts, where the keys are column headers and the (list-like) values are column data.

Parameters:

  • value ((dict, dataframe, list, array, tuple), default: None ) \u2013

    Table data (and/or header data), in one of the accepted formats:

    • list or list-of-lists : [column_values] or [[row_vals], ..., [row_vals]]
    • dict-of-dicts : {column_header -> {row_header -> value}}
    • dict-of-lists : {column_header -> [column_values]}
    • list-of-row-records : [{column_headers -> value}, ... , {column_headers -> value}]
    • split-dict-of-lists :
    • tuple-of-values : ([values], [row_headers], [column_headers])
    • dict-of-pandas-series : {column_header -> Series(values)}
  • index (Collection, default: None ) \u2013

    A sized iterable container of row headers. By default, row headers will be tuple(range(len(data))). Values provided here override any implied in value.

  • columns (Collection, default: None ) \u2013

    A sized iterable container of column headers. By default, column headers will be tuple(range(len(data[0]))). Values provided here override any implied in value.

  • **kwargs (Unpack[WidgetKwargs], default: {} ) \u2013

    Additional kwargs will be passed to the magicgui.widgets.Widget constructor.

Attributes:

  • value (dict) \u2013

    Returns a dict with the keys data, index, and columns ... representing the 2D (list of lists) tabular data, row headers, and column headers, respectively. If set, will clear and update the table using the new data.

  • data (DataView) \u2013

    A DataView instance that provides numpy-like indexing (with get/set/delete) onto the 2D data array, For example table.data[0,2] gets the data in the cell of the first row, 3rd column. Works with numpy slice syntax.

  • column_headers (tuple) \u2013

    The current column headers. Can be set with a new sequence to change

  • row_headers (tuple) \u2013

    The current row headers. Can be set with a new sequence to change

  • shape (tuple of int) \u2013

    The shape of the table in (rows, columns).

  • size (int) \u2013

    The number of cells in the table.

Methods:

  • keys \u2013

    Return a TableHeadersView, providing a view on this table's headers. Use axis='row' for row headers.

  • items \u2013

    Return a TableItemsView, providing a view on this table's items, as 2-tuples of (header, data). Use axis='row' for (row_header, row_data)

  • clear \u2013

    Clear all table data and headers.

  • to_dataframe \u2013

    Returns a pandas dataframe representation of this table. (requires pandas)

  • to_dict \u2013

    Return one of many different dict-like representations of table and header data. See docstring of :meth:to_dict for details.

Events

changed Emitted whenever a cell in the table changes. The value will have a dict of information regarding the cell that changed: {'data': x, 'row': int, 'column': int, 'column_header': str, 'row_header': str} CURRENTLY: only emitted on changes in the GUI. not programmatic changes.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.column_headers","title":"column_headers: tuple property writable","text":"

Return column headers.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.data","title":"data: DataView property writable","text":"

Return DataView object for this table.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.row_headers","title":"row_headers: tuple property writable","text":"

Return row headers.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.shape","title":"shape: tuple[int, int] property","text":"

Return shape of table widget (rows, cols).

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.size","title":"size: int property","text":"

Return shape of table widget (rows, cols).

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__delitem__","title":"__delitem__(key: TblKey) -> None","text":"

Delete a column from the table.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__getitem__","title":"__getitem__(key: TblKey) -> list","text":"

Get a column from the table.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__hash__","title":"__hash__() -> int","text":"

Make table hashable.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__iter__","title":"__iter__() -> Iterator","text":"

Yield column headers.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__len__","title":"__len__() -> int","text":"

Return number of columns.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__new__","title":"__new__(value: TableData | None = None, *, index: Collection | None = None, columns: Collection | None = None, **kwargs: Any) -> Table","text":"

Just for the signature.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__repr__","title":"__repr__() -> str","text":"

Return string repr.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__setitem__","title":"__setitem__(key: TblKey, v: Collection) -> None","text":"

Set a column in the table. If k doesn't exist, make a new column.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.clear","title":"clear() -> None","text":"

Clear the table.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.delete_row","title":"delete_row(*, index: int | Sequence[int] | None = None, header: Any | Sequence[Any] | None = None) -> None","text":"

Delete row(s) by index or header.

Parameters:

  • index (int or Sequence[int], default: None ) \u2013

    Index or indices of row(s) to delete.

  • header (Any or Sequence[Any], default: None ) \u2013

    Header or headers of row(s) to delete.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.get_value","title":"get_value() -> dict[TblKey, Collection]","text":"

Return dict with current data, index, and columns of the widget.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.items","title":"items(axis: str = 'column') -> TableItemsView[TblKey, list]","text":"

Return a set-like object providing a view on this table's items.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.keys","title":"keys(axis: str = 'column') -> HeadersView[TblKey]","text":"

Return a set-like object providing a view on this table's headers.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.set_value","title":"set_value(value: TableData) -> None","text":"

Set table data from dict, dataframe, list, or array.

Parameters:

  • value (Any) \u2013

    Complete table data in one of the forms described above. Partial table updates are not yet supported

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.to_dataframe","title":"to_dataframe() -> pandas.DataFrame","text":"

Convert TableData to dataframe.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.to_dict","title":"to_dict(orient: str = 'dict') -> list | dict","text":"

Convert the Table to a dictionary.

The type of the key-value pairs can be customized with the parameters (see below).

Parameters:

  • orient (str {'dict', 'list', 'series', 'split', 'records', 'index'}, default: 'dict' ) \u2013

    Determines the type of the values of the dictionary.

    • 'dict' (default) : dict like {column -> {index -> value}}
    • 'list' : dict like {column -> [values]}
    • 'split' : dict like
    • 'records' : list like [{column -> value}, ... , {column -> value}]
    • 'index' : dict like {index -> {column -> value}}
    • 'series' : dict like {column -> Series(values)}
"},{"location":"api/widgets/TextEdit/","title":"TextEdit","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/TextEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/TextEdit/#magicgui.widgets.TextEdit","title":"TextEdit","text":"

Bases: ValueWidget[str], _ReadOnlyMixin

A widget to edit and display both plain and rich text.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/TimeEdit/","title":"TimeEdit","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/TimeEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/TimeEdit/#magicgui.widgets.TimeEdit","title":"TimeEdit","text":"

Bases: ValueWidget[TV]

A widget for editing times.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/ToolBar/","title":"ToolBar","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/ToolBar/#signals","title":"Signals","text":"
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/ToolBar/#magicgui.widgets.ToolBar","title":"ToolBar","text":"

Bases: ToolBarWidget

Toolbar that contains a set of controls.

Parameters:

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/TupleEdit/","title":"TupleEdit","text":"

Available in backends:

"},{"location":"api/widgets/TupleEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/TupleEdit/#magicgui.widgets.TupleEdit","title":"TupleEdit","text":"

Bases: ValuedContainerWidget[tuple]

A widget to represent a tuple of values.

A TupleEdit container has several child widgets of different type. Their value is represented as a Python tuple object. If a tuple is given as the initial value, types of child widgets are determined one by one. Unlike ListEdit, number of contents is not editable.

Parameters:

  • value (Iterable, default: Undefined ) \u2013

    The starting value for the widget.

  • nullable (bool) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • options (dict, default: None ) \u2013

    Widget options of child widgets.

"},{"location":"api/widgets/TupleEdit/#magicgui.widgets.TupleEdit.annotation","title":"annotation: Any property writable","text":"

Return type annotation for the parameter represented by the widget.

ForwardRefs will be resolve when setting the annotation. For TupleEdit, annotation will be like 'tuple[str, int]'.

"},{"location":"api/widgets/TupleEdit/#magicgui.widgets.TupleEdit.get_value","title":"get_value() -> tuple","text":"

Return current value as a tuple.

"},{"location":"api/widgets/bases/","title":"magicgui.widgets.bases","text":"

The magicgui.widgets.bases module contains the base classes for all widgets.

While most users will never instantiate these classes directly, the methods and properties of these classes are inherited by all widgets, and define the common API for all widgets. Therefore, it is worth being aware of the type of widget you are working with.

"},{"location":"api/widgets/bases/#summary","title":"Summary","text":"Widget Description Widget Basic Widget, wrapping a class that implements WidgetProtocol. ButtonWidget Widget with a value, Wraps a widget implementing the ButtonWidgetProtocol. CategoricalWidget Widget with a value and choices. Wraps CategoricalWidgetProtocol. BaseContainerWidget Widget that can contain other widgets. ContainerWidget Container widget that can insert/remove child widgets. ValuedContainerWidget Container-type ValueWidget. DialogWidget Modal Container. MainWindowWidget Top level Application widget that can contain other widgets. RangedWidget Widget with a constrained value. Wraps RangedWidgetProtocol. SliderWidget Widget with a constrained value and orientation. Wraps SliderWidgetProtocol. ValueWidget Widget with a value, Wraps ValueWidgetProtocol. BaseValueWidget An abstract base class for widgets that have a value."},{"location":"api/widgets/bases/#class-hierarchy","title":"Class Hierarchy","text":"

In visual form, the widget class hierarchy looks like this:

classDiagram\n    Widget <|-- BaseValueWidget\n    BaseValueWidget <|-- ValueWidget\n    Widget <|-- BaseContainerWidget\n    BackendWidget ..|> WidgetProtocol : implements a\n    ValueWidget <|-- RangedWidget\n    ValueWidget <|-- ButtonWidget\n    ValueWidget <|-- CategoricalWidget\n    RangedWidget <|-- SliderWidget\n    BaseContainerWidget <|-- ContainerWidget\n    BaseContainerWidget <|-- ValuedContainerWidget\n    BaseValueWidget <|-- ValuedContainerWidget\n    Widget --* WidgetProtocol : controls a\n    <<Interface>> WidgetProtocol\n    class WidgetProtocol {\n        _mgui_get_X()\n        _mgui_set_X()\n    }\n    class Widget{\n        name: str\n        annotation: Any\n        label: str\n        tooltip: str\n        visible: bool\n        enabled: bool\n        native: Any\n        height: int\n        width: int\n        hide()\n        show()\n        close()\n        render()\n    }\n    class BaseValueWidget{\n        value: Any\n        changed: SignalInstance\n        bind(value, call) Any\n        unbind()\n    }\n    class ValueWidget{\n    }\n    class RangedWidget{\n        value: float | tuple\n        min: float\n        max: float\n        step: float\n        adaptive_step: bool\n        range: tuple[float, float]\n    }\n    class SliderWidget{\n        orientation: str\n    }\n    class ButtonWidget{\n        value: bool\n        clicked: SignalInstance\n        text: str\n    }\n    class CategoricalWidget{\n        choices: List[Any]\n    }\n    class BaseContainerWidget{\n        widgets: List[Widget]\n        labels: bool\n        layout: str\n        margins: tuple[int, int, int, int]\n        reset_choices()\n        asdict() Dict[str, Any]\n        update(mapping)\n    }\n\n    click Widget href \"#magicgui.widgets.bases.Widget\"\n    click BaseValueWidget href \"#magicgui.widgets.bases.BaseValueWidget\"\n    click ValueWidget href \"#magicgui.widgets.bases.ValueWidget\"\n    click RangedWidget href \"#magicgui.widgets.bases.RangedWidget\"\n    click SliderWidget href \"#magicgui.widgets.bases.SliderWidget\"\n    click ButtonWidget href \"#magicgui.widgets.bases.ButtonWidget\"\n    click CategoricalWidget href \"#magicgui.widgets.bases.CategoricalWidget\"\n    click BaseContainerWidget href \"#magicgui.widgets.bases.BaseContainerWidget\"\n
"},{"location":"api/widgets/bases/#base-widget-classes","title":"Base Widget Classes","text":""},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget","title":"magicgui.widgets.bases.Widget","text":"

Basic Widget, wrapping a class that implements WidgetProtocol.

Parameters:

  • widget_type (type[WidgetProtocol]) \u2013

    A class implementing a widget protocol. Will be instantiated during init.

  • name (str, default: '' ) \u2013

    The name of the parameter represented by this widget. by default \"\"

  • annotation (Any, default: None ) \u2013

    The type annotation for the parameter represented by the widget, by default None

  • label (str, default: None ) \u2013

    A string to use for an associated Label widget (if this widget is being shown in a Container widget, and labels are on). By default, name will be used. Note: name refers the name of the parameter, as might be used in a signature, whereas label is just the label for that widget in the GUI.

  • tooltip (str, default: None ) \u2013

    A tooltip to display when hovering over the widget.

  • visible (bool, default: None ) \u2013

    Whether the widget is visible, by default True.

  • enabled (bool, default: True ) \u2013

    Whether the widget is enabled, by default True.

  • gui_only (bool, default: False ) \u2013

    If True, widget is excluded from any function signature representation. by default False. (This will likely be deprecated.)

  • parent (Any, default: None ) \u2013

    Optional parent widget of this widget. CAREFUL: if a parent is set, and subsequently deleted, this widget will likely be deleted as well (depending on the backend), and will no longer be usable.

  • backend_kwargs (dict, default: None ) \u2013

    keyword argument to pass to the backend widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.annotation","title":"annotation: Any property writable","text":"

Return type annotation for the parameter represented by the widget.

ForwardRefs will be resolve when setting the annotation.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.enabled","title":"enabled: bool property writable","text":"

Whether widget is enabled (editable).

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.height","title":"height: int property writable","text":"

Return the current height of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.label","title":"label: str property writable","text":"

Return a label to use for this widget when present in Containers.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.max_height","title":"max_height: int property writable","text":"

Get the maximum height of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.max_width","title":"max_width: int property writable","text":"

Get the maximum width of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.min_height","title":"min_height: int property writable","text":"

Get the minimum height of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.min_width","title":"min_width: int property writable","text":"

Get the minimum width of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.native","title":"native: Any property","text":"

Return native backend widget.

Note this is the widget that contains the layout, and not any parent widgets of this (e.g. a parent widget that is used to enable scroll bars)

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.options","title":"options: dict property","text":"

Return options currently being used in this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.param_kind","title":"param_kind: inspect._ParameterKind property writable","text":"

Return :attr:inspect.Parameter.kind represented by this widget.

Used in building signatures from multiple widgets, by default :attr:~inspect.Parameter.POSITIONAL_OR_KEYWORD

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.parent","title":"parent: Widget property writable","text":"

Return the parent widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.parent_changed","title":"parent_changed: SignalInstance property","text":"

Signal emitted when the parent of the widget changes.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.root_native_widget","title":"root_native_widget: Any property","text":"

Return the root native backend widget.

This can be different from the .native widget if the layout is a child of some other widget, e.g. a widget used to enable scroll bars.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.tooltip","title":"tooltip: str | None property writable","text":"

Get the tooltip for this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.visible","title":"visible: bool property writable","text":"

Return whether widget is visible.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.widget_type","title":"widget_type: str property","text":"

Return type of widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.width","title":"width: int property writable","text":"

Return the current width of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.__repr__","title":"__repr__() -> str","text":"

Return representation of widget of instance.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.close","title":"close() -> None","text":"

Close widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.hide","title":"hide() -> None","text":"

Hide widget.

alias for widget.visible = False

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.render","title":"render() -> np.ndarray","text":"

Return an RGBA (MxNx4) numpy array bitmap of the rendered widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.show","title":"show(run: bool = False) -> Widget","text":"

Show widget.

alias for widget.visible = True

Parameters:

  • run (bool, default: False ) \u2013

    Whether to start the application event loop, by default False

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.shown","title":"shown() -> Iterator[Application]","text":"

Context manager to show the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ButtonWidget","title":"magicgui.widgets.bases.ButtonWidget","text":"

Bases: ValueWidget[bool]

Widget with a value, Wraps a widget implementing the ButtonWidgetProtocol.

see ButtonWidgetProtocol.

Parameters:

  • value (bool, default: Undefined ) \u2013

    The starting state of the widget.

  • text (str, default: None ) \u2013

    The text to display on the button. If not provided, will use name.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ButtonWidget.clicked","title":"clicked: SignalInstance property","text":"

Alias for changed event.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ButtonWidget.options","title":"options: dict property","text":"

Return options currently being used in this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ButtonWidget.text","title":"text: str property writable","text":"

Text of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget","title":"magicgui.widgets.bases.CategoricalWidget","text":"

Bases: ValueWidget[T]

Widget with a value and choices. Wraps CategoricalWidgetProtocol.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The initially selected choice.

  • choices (Enum, Iterable, or Callable, default: () ) \u2013

    Available choices displayed in the combo box.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.choices","title":"choices: tuple[T | None, ...] property writable","text":"

Available value choices for this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.current_choice","title":"current_choice: str property","text":"

Return the text of the currently selected choice.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.options","title":"options: dict property","text":"

Return options currently being used in this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.value","title":"value: T property writable","text":"

Return current value of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.__len__","title":"__len__() -> int","text":"

Return the number of choices.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.del_choice","title":"del_choice(choice_name: str) -> None","text":"

Delete the provided choice_name and associated data.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.get_choice","title":"get_choice(choice_name: str) -> T","text":"

Get data for the provided choice_name.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.reset_choices","title":"reset_choices(*_: Any) -> None","text":"

Reset choices to the default state.

If self._default_choices is a callable, this may NOT be the exact same set of choices as when the widget was instantiated, if the callable relies on external state.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.set_choice","title":"set_choice(choice_name: str, data: Any | None = None) -> None","text":"

Set data for the provided choice_name.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget","title":"magicgui.widgets.bases.BaseContainerWidget","text":"

Bases: Widget, _OrientationMixin, Sequence[WidgetVar]

Widget that can contain other widgets.

Wraps a widget that implements ContainerProtocol.

Parameters:

  • widgets (Sequence[Widget], default: () ) \u2013

    A sequence of widgets with which to initialize the container, by default None.

  • layout (str, default: 'vertical' ) \u2013

    The layout for the container. must be one of {'horizontal', 'vertical'}. by default \"vertical\"

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether each widget should be shown with a corresponding Label widget to the left, by default True. Note: the text for each widget defaults to widget.name, but can be overridden by setting widget.label.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.labels","title":"labels: bool property writable","text":"

Whether widgets are presented with labels.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.layout","title":"layout: str property writable","text":"

Return the layout of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.margins","title":"margins: tuple[int, int, int, int] property writable","text":"

Return margin between the content and edges of the container.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.__getattr__","title":"__getattr__(name: str) -> WidgetVar","text":"

Return attribute name. Will return a widget if present.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.__getitem__","title":"__getitem__(key: int | str | slice) -> WidgetVar | MutableSequence[WidgetVar]","text":"

Get item by integer, str, or slice.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.__len__","title":"__len__() -> int","text":"

Return the count of widgets.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.reset_choices","title":"reset_choices(*_: Any) -> None","text":"

Reset choices for all Categorical subWidgets to the default state.

If widget._default_choices is a callable, this may NOT be the exact same set of choices as when the widget was instantiated, if the callable relies on external state.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget","title":"magicgui.widgets.bases.ContainerWidget","text":"

Bases: BaseContainerWidget[WidgetVar], MutableSequence[WidgetVar]

Container widget that can insert/remove child widgets.

A ContainerWidget behaves like a python list of Widget objects. Subwidgets can be accessed using integer or slice-based indexing (container[0]), as well as by widget name (container.<widget_name>). Widgets can be added with append or insert, and removed with del or pop, etc...

There is a tight connection between a ContainerWidget and an inspect.Signature object, just as there is a tight connection between individual Widgetobjects an an :class:inspect.Parameter object. The signature representation of a ContainerWidget (with the current settings as default values) is accessible with the :meth:~ContainerWidget.__signature__ method (or by using :func:inspect.signature from the standard library)

For a ContainerWidget subclass that is tightly coupled to a specific function signature (as in the \"classic\" magicgui decorator), see magicgui.widgets.FunctionGui.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__signature__","title":"__signature__: MagicSignature property","text":"

Return a MagicSignature object representing the current state of the gui.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__delattr__","title":"__delattr__(name: str) -> None","text":"

Delete a widget by name.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__delitem__","title":"__delitem__(key: int | slice) -> None","text":"

Delete a widget by integer or slice index.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__dir__","title":"__dir__() -> list[str]","text":"

Add subwidget names to the dir() call for this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__repr__","title":"__repr__() -> str","text":"

Return a repr.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__setattr__","title":"__setattr__(name: str, value: Any) -> None","text":"

Set attribute name. Prevents changing widget if present, (use del).

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__setitem__","title":"__setitem__(key: Any, value: Any) -> NoReturn","text":"

Prevent assignment by index.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.asdict","title":"asdict() -> dict[str, Any]","text":"

Return state of widget as dict.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.from_callable","title":"from_callable(obj: Callable, gui_options: dict | None = None, **kwargs: Unpack[ContainerKwargs]) -> Container classmethod","text":"

Create a Container widget from a callable object.

In most cases, it will be preferable to create a FunctionGui instead.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.from_signature","title":"from_signature(sig: inspect.Signature, **kwargs: Unpack[ContainerKwargs]) -> Container classmethod","text":"

Create a Container widget from an inspect.Signature object.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.index","title":"index(value: Any, start: int = 0, stop: int = 9223372036854775807) -> int","text":"

Return index of a specific widget instance (or widget name).

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.insert","title":"insert(key: int, widget: WidgetVar) -> None","text":"

Insert widget at key.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.remove","title":"remove(value: Widget | str) -> None","text":"

Remove a widget instance (may also be string name of widget).

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.update","title":"update(mapping: Mapping | Iterable[tuple[str, Any]] | None = None, **kwargs: Any) -> None","text":"

Update the parameters in the widget from a mapping, iterable, or kwargs.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ValuedContainerWidget","title":"magicgui.widgets.bases.ValuedContainerWidget","text":"

Bases: BaseContainerWidget[Widget], BaseValueWidget[T], Generic[T]

Container-type ValueWidget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.DialogWidget","title":"magicgui.widgets.bases.DialogWidget","text":"

Bases: ContainerWidget

Modal Container.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.DialogWidget.exec","title":"exec() -> bool","text":"

Show the dialog, and block.

Return True if the dialog was accepted, False if rejected.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.MainWindowWidget","title":"magicgui.widgets.bases.MainWindowWidget","text":"

Bases: ContainerWidget

Top level Application widget that can contain other widgets.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.MainWindowWidget.create_menu_item","title":"create_menu_item(menu_name: str, item_name: str, callback: Callable | None = None, shortcut: str | None = None) -> None","text":"

Create a menu item item_name under menu menu_name.

menu_name will be created if it does not already exist.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget","title":"magicgui.widgets.bases.RangedWidget","text":"

Bases: ValueWidget[T]

Widget with a constrained value. Wraps RangedWidgetProtocol.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.adaptive_step","title":"adaptive_step: bool property writable","text":"

Whether the step size is adaptive.

Adaptive decimal step means that the step size will continuously be adjusted to one power of ten below the current value. So when the value is 1100, the step is set to 100, so stepping up once increases it to 1200. For 1200 stepping up takes it to 1300. For negative values, stepping down from -1100 goes to -1200.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.max","title":"max: float property writable","text":"

Maximum allowable value for the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.min","title":"min: float property writable","text":"

Minimum allowable value for the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.options","title":"options: dict property","text":"

Return options currently being used in this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.range","title":"range: tuple[float, float] property writable","text":"

Range of allowable values for the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.step","title":"step: float | None property writable","text":"

Step size for widget values (None if adaptive step is turned on).

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.set_value","title":"set_value(value: T) -> None","text":"

Set widget value, will raise Value error if not within min/max.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.SliderWidget","title":"magicgui.widgets.bases.SliderWidget","text":"

Bases: RangedWidget[T], _OrientationMixin

Widget with a constrained value and orientation. Wraps SliderWidgetProtocol.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • orientation ((str, {'horizontal', 'vertical'}), default: 'horizontal' ) \u2013

    The orientation for the slider, by default \"horizontal\"

  • readout (bool, default: True ) \u2013

    Whether to show the editable spinbox next to the slider

  • tracking (bool, default: True ) \u2013

    If tracking is enabled (the default), the slider emits the changed signal while the slider is being dragged. If tracking is disabled, the slider emits the changed signal only after the user releases the slider.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.SliderWidget.options","title":"options: dict property","text":"

Return options currently being used in this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.SliderWidget.readout","title":"readout: bool property writable","text":"

Get visibility state of readout widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.SliderWidget.tracking","title":"tracking: bool property writable","text":"

Return whether slider tracking is enabled.

If tracking is enabled (the default), the slider emits the changed() signal while the slider is being dragged. If tracking is disabled, the slider emits the changed() signal only when the user releases the slider.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ValueWidget","title":"magicgui.widgets.bases.ValueWidget","text":"

Bases: BaseValueWidget[T]

Widget with a value, Wraps ValueWidgetProtocol.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ValueWidget.get_value","title":"get_value() -> T","text":"

Callable version of self.value.

The main API is to use self.value, however, this is here in order to provide an escape hatch if trying to access the widget's value inside of a callback bound to self._bound_value.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget","title":"magicgui.widgets.bases.BaseValueWidget","text":"

Bases: Widget, ABC, Generic[T]

An abstract base class for widgets that have a value.

Subclasses must implement the get_value and set_value methods.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.annotation","title":"annotation: Any property writable","text":"

Return type annotation for the parameter represented by the widget.

ForwardRefs will be resolve when setting the annotation. If the widget is nullable (had a type annototation of Optional[Type]), annotation will return the first argument in the Optional clause.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.value","title":"value: T property writable","text":"

Return current value of the widget. This may be interpreted by backends.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.__repr__","title":"__repr__() -> str","text":"

Return representation of widget of instance.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.bind","title":"bind(value: T | Callable[[BaseValueWidget], T], call: bool = True) -> None","text":"

Binds value to self.value.

If a value is bound to this widget, then whenever widget.value is accessed, the value provided here will be returned. value can be a callable, in which case value(self) will be returned (i.e. your callback must accept a single parameter, which is this widget instance.).

If you provide a callable and you don't want it to be called (but rather just returned as a callable object, then use call=False when binding your value.

Note: if you need to access the \"original\" widget.value within your callback, please use widget.get_value() instead of the widget.value property, in order to avoid a RuntimeError.

Parameters:

  • value (Any) \u2013

    The value (or callback) to return when accessing this widget's value.

  • call (bool, default: True ) \u2013

    If value is a callable and call is True, the callback will be called as callback(self) when accessing self.value. If False, the callback will simply be returned as a callable object, by default, True.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.get_value","title":"get_value() -> T abstractmethod","text":"

Callable version of self.value.

The main API is to use self.value, however, this is here in order to provide an escape hatch if trying to access the widget's value inside of a callback bound to self._bound_value.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.set_value","title":"set_value(value: Any) -> None abstractmethod","text":"

Normalize and set the value of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.unbind","title":"unbind() -> None","text":"

Unbinds any bound values. (see ValueWidget.bind).

"},{"location":"api/widgets/create_widget/","title":"magicgui.widgets.create_widget","text":""},{"location":"api/widgets/create_widget/#magicgui.widgets.create_widget","title":"magicgui.widgets.create_widget(value=Undefined, annotation=None, name='', param_kind='POSITIONAL_OR_KEYWORD', label=None, gui_only=False, app=None, widget_type=None, options=None, is_result=False, raise_on_unknown=True)","text":"

Create and return appropriate widget subclass.

This factory function can be used to create a widget appropriate for the provided value and/or annotation provided. See Type Mapping Docs for details on how the widget type is determined from type annotations.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget, by default None

  • annotation (Any, default: None ) \u2013

    The type annotation for the parameter represented by the widget, by default None.

  • name (str, default: '' ) \u2013

    The name of the parameter represented by this widget. by default \"\"

  • param_kind (str, default: 'POSITIONAL_OR_KEYWORD' ) \u2013

    The :attr:inspect.Parameter.kind represented by this widget. Used in building signatures from multiple widgets, by default \"POSITIONAL_OR_KEYWORD\"

  • label (str, default: None ) \u2013

    A string to use for an associated Label widget (if this widget is being shown in a Container widget, and labels are on). By default, name will be used. Note: name refers the name of the parameter, as might be used in a signature, whereas label is just the label for that widget in the GUI.

  • gui_only (bool, default: False ) \u2013

    Whether the widget should be considered \"only for the gui\", or if it should be included in any widget container signatures, by default False

  • app (str, default: None ) \u2013

    The backend to use, by default None

  • widget_type (str or Type[WidgetProtocol] or None, default: None ) \u2013

    A class implementing a widget protocol or a string with the name of a magicgui widget type (e.g. \"Label\", \"PushButton\", etc...). If provided, this widget type will be used instead of the type autodetermined from value and/or annotation above.

  • options (dict, default: None ) \u2013

    Dict of options to pass to the Widget constructor, by default dict()

  • is_result (boolean, default: False ) \u2013

    Whether the widget belongs to an input or an output. By default, an input is assumed.

  • raise_on_unknown (bool, default: True ) \u2013

    Raise exception if no widget is found for the given type, by default True

Returns:

  • Widget \u2013

    An instantiated widget subclass

Raises:

  • TypeError \u2013

    If the provided or autodetected widget_type does not implement any known widget protocols

Examples:

from magicgui.widgets import create_widget\n\n# create a widget from a string value\nwdg = create_widget(value=\"hello world\")\nassert wdg.value == \"hello world\"\n\n# create a widget from a string annotation\nwdg = create_widget(annotation=str)\nassert wdg.value == \"\"\n
"},{"location":"generated_examples/","title":"Getting started","text":"

A gallery of examples for magicgui.

Basic example

Basic widgets demo

"},{"location":"generated_examples/#demo-applications","title":"Demo applications","text":"

Example applications built with magicgui.

Input values dialog

Quantities with pint

Callable functions demo

Snell's law demonstration using magicgui

Hotdog or not app

Chaining functions together

"},{"location":"generated_examples/#demo-widget-types","title":"Demo widget types","text":"

Example gallery demonstrating the available widget types in magicgui.

Image widget

Range slider widget

Custom text labels for widgets

Log slider widget

Optional user choice

Multiple selection widget

File dialog widget

Directory dialog widget

Password login

File dialog widget

Dropdown selection widget

Table widget

"},{"location":"generated_examples/#matplotlib-and-magicgui","title":"matplotlib and magicgui","text":"

Examples involving matplotlib graphs and magicgui.

matplotlib figure example

Waveforms example

"},{"location":"generated_examples/#napari-and-magicgui","title":"napari and magicgui","text":"

Examples integrating magicgui with napari.

napari forward reference demo

napari Qt demo

napari parameter sweeps

napari image arithmetic widget

"},{"location":"generated_examples/#jupyter-notebooks-and-magicgui","title":"Jupyter notebooks and magicgui","text":"

Examples using jupyter notebooks together with magicgui.

Jupyter notebooks and magicgui

"},{"location":"generated_examples/#progress-bar-examples","title":"Progress bar examples","text":"

Examples of progress bars in magicgui.

Manual progress bar

Simple progress bar

Indeterminate progress bar

Nested progress bars

"},{"location":"generated_examples/#under-the-hood","title":"Under the hood","text":"

Learn more advanced usage patterns for magicgui, including self referencing widgets and decorating class methods with magicgui.

Self reference magicgui widgets

Deocrate class methods with magicgui

Download all examples in Python source code: generated_examples_python.zip

Download all examples in Jupyter notebooks: generated_examples_jupyter.zip

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/basic_example/","title":"Basic example","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/basic_example/#basic-example","title":"Basic example","text":"

A basic example using magicgui.

Out:

<FunctionGui example(x: int = 0, y='hi')>\n

from magicgui import magicgui\n\n\n@magicgui\ndef example(x: int, y=\"hi\"):\n    \"\"\"Basic example function.\"\"\"\n    return x, y\n\n\nexample.changed.connect(print)\nexample.show(run=True)\n

Total running time of the script: ( 0 minutes 0.895 seconds)

Download Python source code: basic_example.py

Download Jupyter notebook: basic_example.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/basic_widgets_demo/","title":"Basic widgets demo","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/basic_widgets_demo/#basic-widgets-demo","title":"Basic widgets demo","text":"

Widget demonstration with magicgui.

This code demonstrates a few of the widget types that magicgui can create based on the parameter types in your function.

Out:

<MainFunctionGui widget_demo(boolean=True, integer=1, spin_float=3.14, slider_float=43.5, slider_int=550, string='Text goes here', dropdown=<Medium.Glass: 1.52>, radio_option=2, date=datetime.date(1999, 12, 31), time=datetime.time(1, 30, 20), datetime=datetime.datetime(2024, 11, 23, 21, 27, 53, 136000), filename=PosixPath('/Users/runner'))>\n

import datetime\nfrom enum import Enum\nfrom pathlib import Path\n\nfrom magicgui import magicgui\n\n\nclass Medium(Enum):\n    \"\"\"Enum for various media and their refractive indices.\"\"\"\n\n    Glass = 1.520\n    Oil = 1.515\n    Water = 1.333\n    Air = 1.0003\n\n\n@magicgui(\n    main_window=True,\n    call_button=\"Calculate\",\n    layout=\"vertical\",\n    result_widget=True,\n    slider_float={\"widget_type\": \"FloatSlider\", \"max\": 100},\n    slider_int={\"widget_type\": \"Slider\", \"readout\": False},\n    radio_option={\n        \"widget_type\": \"RadioButtons\",\n        \"orientation\": \"horizontal\",\n        \"choices\": [(\"first option\", 1), (\"second option\", 2)],\n    },\n    filename={\"label\": \"Pick a file:\"},\n)\ndef widget_demo(\n    boolean=True,\n    integer=1,\n    spin_float=3.14159,\n    slider_float=43.5,\n    slider_int=550,\n    string=\"Text goes here\",\n    dropdown=Medium.Glass,\n    radio_option=2,\n    date=datetime.date(1999, 12, 31),\n    time=datetime.time(1, 30, 20),\n    datetime=datetime.datetime.now(),\n    filename=Path.home(),\n):\n    \"\"\"We can use numpy docstrings to provide tooltips.\n\n    Parameters\n    ----------\n    boolean : bool, optional\n        A checkbox for booleans, by default True\n    integer : int, optional\n        Some integer, by default 1\n    spin_float : float, optional\n        This one is a float, by default \"pi\"\n    slider_float : float, optional\n        Hey look! I'm a slider, by default 43.5\n    slider_int : float, optional\n        I only take integers, and I've hidden my readout, by default 550\n    string : str, optional\n        We'll use this string carefully, by default \"Text goes here\"\n    dropdown : Enum, optional\n        Pick a medium, by default Medium.Glass\n    radio_option : int\n        A set of radio buttons.\n    date : datetime.date, optional\n        Your birthday, by default datetime.date(1999, 12, 31)\n    time : datetime.time, optional\n        Some time, by default datetime.time(1, 30, 20)\n    datetime : datetime.datetime, optional\n        A very specific time and date, by default ``datetime.datetime.now()``\n    filename : str, optional\n        Pick a path, by default Path.home()\n    \"\"\"\n    return locals().values()\n\n\nwidget_demo.changed.connect(print)\nwidget_demo.show(run=True)\n

Total running time of the script: ( 0 minutes 0.124 seconds)

Download Python source code: basic_widgets_demo.py

Download Jupyter notebook: basic_widgets_demo.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/mg_execution_times/","title":"Computation times","text":"

00:01.019 total execution time for generated_examples files:

+-------------------------------------------------------------------------------------+-----------+--------+ | basic_example (docs/examples/basic_example.py) | 00:00.895 | 0.0 MB | +-------------------------------------------------------------------------------------+-----------+--------+ | basic_widgets_demo (docs/examples/basic_widgets_demo.py) | 00:00.124 | 0.0 MB | +-------------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/applications/callable/","title":"Callable functions demo","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/applications/callable/#callable-functions-demo","title":"Callable functions demo","text":"

This example demonstrates handling callable functions with magicgui.

Out:

<FunctionGui example(func='f')>\n

from magicgui import magicgui\n\n\ndef f(x: int, y=\"a string\") -> str:\n    \"\"\"Example function F.\"\"\"\n    return f\"{y} {x}\"\n\n\ndef g(x: int = 6, y=\"another string\") -> str:\n    \"\"\"Example function G.\"\"\"\n    return f\"{y} asdfsdf {x}\"\n\n\n@magicgui(call_button=True, func={\"choices\": [\"f\", \"g\"]})\ndef example(func=\"f\"):\n    \"\"\"\u00cbxample function.\"\"\"\n    pass\n\n\ndef update(f: str):\n    \"\"\"Update function.\"\"\"\n    if len(example) > 2:\n        del example[1]\n    example.insert(1, magicgui(globals()[f]))\n\n\nexample.func.changed.connect(update)\nexample.show(run=True)\n

Total running time of the script: ( 0 minutes 0.050 seconds)

Download Python source code: callable.py

Download Jupyter notebook: callable.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/applications/chaining/","title":"Chaining functions together","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/applications/chaining/#chaining-functions-together","title":"Chaining functions together","text":"

This example demonstrates chaining multiple functions together.

Out:

calling func_a\ncalling func_b\ncalling func_c\n\n\n<Container (func_a: NoneType, func_b: NoneType, func_c: NoneType)>\n

from magicgui import magicgui, widgets\n\n\n@magicgui(auto_call=True)\ndef func_a(x: int = 64, y: int = 64):\n    \"\"\"Callable function A.\"\"\"\n    print(\"calling func_a\")\n    return x + y\n\n\n@magicgui(auto_call=True, input={\"visible\": False, \"label\": \" \", \"max\": 100000})\ndef func_b(input: int, mult=1.0):\n    \"\"\"Callable function B.\"\"\"\n    print(\"calling func_b\")\n    result = input * mult\n    # since these function defs live in globals(), you can update them directly\n    func_c.input.value = result\n    return result\n\n\n# alternatively, you can the `widget.called` signal to connect a callback function\n# where the result of the function being called is at `value`\n@func_a.called.connect\ndef _on_func_a(value: str):\n    func_b.input.value = value\n\n\n@magicgui(\n    auto_call=True,\n    input={\"visible\": False, \"max\": 100000},\n    result_widget=True,\n    labels=False,\n)\ndef func_c(input: int, format: str = \"({} + {}) * {} is {}\") -> str:\n    \"\"\"Callable function C.\"\"\"\n    print(\"calling func_c\\n\")\n    return format.format(func_a.x.value, func_a.y.value, func_b.mult.value, input)\n\n\ncontainer = widgets.Container(\n    widgets=[func_a, func_b, func_c], layout=\"vertical\", labels=False\n)\ncontainer.native.setMinimumWidth(500)\nfunc_a()\ncontainer.show(run=True)\n\n# notice which functions get called when you change each widget.\n

Total running time of the script: ( 0 minutes 0.054 seconds)

Download Python source code: chaining.py

Download Jupyter notebook: chaining.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/applications/hotdog/","title":"Hotdog or not app","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/applications/hotdog/#hotdog-or-not-app","title":"Hotdog or not app","text":"

Demo app to upload an image and classify if it's an hotdog or not.

import pathlib\nfrom enum import Enum\n\nfrom magicgui import magicgui\n\n\nclass HotdogOptions(Enum):\n    \"\"\"All hotdog possibilities.\"\"\"\n\n    Hotdog = 1\n    NotHotdog = 0\n\n\n@magicgui(main_window=True, layout=\"form\", call_button=\"Classify\", result_widget=True)\ndef is_hotdog(img: pathlib.Path) -> HotdogOptions:\n    \"\"\"Classify possible hotdog images.\n\n    Upload an image and check whether it's an hotdog. For example, this image\n    will be classified as one: <br><br>\n\n    <img src=\"resources/hotdog.jpg\">\n\n    Parameters\n    ----------\n    img : pathlib.Path\n        Path to a possible hotdog image\n\n    Returns\n    -------\n    HotdogOptions\n        True if image contains an hotdog in it\n    \"\"\"\n    if \"hotdog\" in img.stem:\n        return HotdogOptions.Hotdog\n    return HotdogOptions.NotHotdog\n\n\nif __name__ == \"__main__\":\n    is_hotdog.show(run=True)\n

Total running time of the script: ( 0 minutes 0.039 seconds)

Download Python source code: hotdog.py

Download Jupyter notebook: hotdog.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/applications/mg_execution_times/","title":"Computation times","text":"

00:00.367 total execution time for generated_examples_applications files:

+-----------------------------------------------------------------------------------+-----------+--------+ | pint_quantity (docs/examples/applications/pint_quantity.py) | 00:00.196 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ | chaining (docs/examples/applications/chaining.py) | 00:00.054 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ | callable (docs/examples/applications/callable.py) | 00:00.050 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ | hotdog (docs/examples/applications/hotdog.py) | 00:00.039 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ | snells_law (docs/examples/applications/snells_law.py) | 00:00.029 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ | values_dialog (docs/examples/applications/values_dialog.py) | 00:00.000 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/applications/pint_quantity/","title":"Quantities with pint","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/applications/pint_quantity/#quantities-with-pint","title":"Quantities with pint","text":"

Pint is a Python package to define, operate and manipulate physical quantities: the product of a numerical value and a unit of measurement. It allows arithmetic operations between them and conversions from and to different units. https://pint.readthedocs.io/en/stable/

Out:

<FunctionGui widget(q=<Quantity(1, 'millisecond')>)>\n

from pint import Quantity\n\nfrom magicgui import magicgui\n\n\n@magicgui\ndef widget(q=Quantity(\"1 ms\")):\n    \"\"\"Widget allowing users to input quantity measurements.\"\"\"\n    print(q)\n\n\nwidget.show(run=True)\n

Total running time of the script: ( 0 minutes 0.196 seconds)

Download Python source code: pint_quantity.py

Download Jupyter notebook: pint_quantity.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/applications/snells_law/","title":"Snell's law demonstration using magicgui","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/applications/snells_law/#snells-law-demonstration-using-magicgui","title":"Snell's law demonstration using magicgui","text":"

Demo app for calculating angles of refraction according to Snell's law.

Out:

<FunctionGui snells_law(aoi=1.0, n1=<Medium.Glass: 1.52>, n2=<Medium.Water: 1.333>, degrees=True)>\n

import math\nfrom enum import Enum\n\nfrom magicgui import magicgui\n\n\nclass Medium(Enum):\n    \"\"\"Enum for various media and their refractive indices.\"\"\"\n\n    Glass = 1.520\n    Oil = 1.515\n    Water = 1.333\n    Air = 1.0003\n\n\n@magicgui(call_button=\"calculate\", result_widget=True)\ndef snells_law(aoi=1.0, n1=Medium.Glass, n2=Medium.Water, degrees=True):\n    \"\"\"Calculate the angle of refraction given two media and an AOI.\"\"\"\n    if degrees:\n        aoi = math.radians(aoi)\n    try:\n        n1 = n1.value\n        n2 = n2.value\n        result = math.asin(n1 * math.sin(aoi) / n2)\n        return round(math.degrees(result) if degrees else result, 2)\n    except ValueError:  # math domain error\n        return \"TIR!\"\n\n\nsnells_law.show(run=True)\n

Total running time of the script: ( 0 minutes 0.029 seconds)

Download Python source code: snells_law.py

Download Jupyter notebook: snells_law.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/applications/values_dialog/","title":"Input values dialog","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/applications/values_dialog/#input-values-dialog","title":"Input values dialog","text":"

A basic example of a user input dialog.

This will pause code execution until the user responds.

"},{"location":"generated_examples/applications/values_dialog/#_1","title":"Input values dialog","text":"
from magicgui.widgets import request_values\n\nvals = request_values(\n    age=int,\n    name={\"annotation\": str, \"label\": \"Enter your name:\"},\n    title=\"Hi, who are you?\",\n)\nprint(repr(vals))\n

Total running time of the script: ( 0 minutes 0.000 seconds)

Download Python source code: values_dialog.py

Download Jupyter notebook: values_dialog.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/change_label/","title":"Custom text labels for widgets","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/change_label/#custom-text-labels-for-widgets","title":"Custom text labels for widgets","text":"

An example showing how to create custom text labels for your widgets.

Out:

<FunctionGui example(x=1, y='hi')>\n

from magicgui import magicgui\n\n\n# use a different label than the default (the parameter name) in the UI\n@magicgui(x={\"label\": \"widget to set x\"})\ndef example(x=1, y=\"hi\"):\n    \"\"\"Example function.\"\"\"\n    return x, y\n\n\nexample.changed.connect(print)\nexample.show(run=True)\n

Total running time of the script: ( 0 minutes 0.037 seconds)

Download Python source code: change_label.py

Download Jupyter notebook: change_label.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/choices/","title":"Dropdown selection widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/choices/#dropdown-selection-widget","title":"Dropdown selection widget","text":"

Choices for dropdowns can be provided in a few different ways.

Out:

<Container (as_list: NoneType, as_enum: NoneType, as_2tuple: NoneType, as_function: NoneType)>\n

from enum import Enum\n\nfrom magicgui import magicgui, widgets\n\n\nclass Medium(Enum):\n    \"\"\"Enum for various media and their refractive indices.\"\"\"\n\n    Oil = 1.515\n    Water = 1.333\n    Air = 1.0003\n\n\n@magicgui(ri={\"choices\": [\"Oil\", \"Water\", \"Air\"]}, auto_call=True)\ndef as_list(ri=\"Water\"):\n    \"\"\"Function decorated with magicgui list of choices.\"\"\"\n    print(\"refractive index is\", Medium[ri].value)\n\n\n@magicgui(auto_call=True)\ndef as_enum(ri: Medium = Medium.Water):\n    \"\"\"Function decorated with magicgui and enumeration.\"\"\"\n    print(\"refractive index is\", ri.value)\n\n\n@magicgui(\n    ri={\"choices\": [(\"Oil\", 1.515), (\"Water\", 1.33), (\"Air\", 1.0)]}, auto_call=True\n)\ndef as_2tuple(ri=1.33):\n    \"\"\"Function decorated with magicgui tuple of choices.\"\"\"\n    print(\"refractive index is\", ri)\n\n\ndef get_choices(gui):\n    \"\"\"Function returning tuple of material and refractive index value.\"\"\"\n    return [(\"Oil\", 1.515), (\"Water\", 1.33), (\"Air\", 1.0)]\n\n\n@magicgui(ri={\"choices\": get_choices}, auto_call=True)\ndef as_function(ri: float):\n    \"\"\"Function to calculate refractive index.\"\"\"\n    print(\"refractive index is\", ri)\n\n\ncontainer = widgets.Container(\n    widgets=[as_list, as_enum, as_2tuple, as_function], layout=\"vertical\"\n)\ncontainer.show(run=True)\n

Total running time of the script: ( 0 minutes 0.042 seconds)

Download Python source code: choices.py

Download Jupyter notebook: choices.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/directory_dialog/","title":"Directory dialog widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/directory_dialog/#directory-dialog-widget","title":"Directory dialog widget","text":"

A dialog to select a directory.

Out:

<FunctionGui directorypicker(directory=PosixPath('~'))>\n

from pathlib import Path\n\nfrom magicgui import magicgui\n\n\n# Select a directory, instead of file(s)\n@magicgui(directory={\"mode\": \"d\", \"label\": \"Choose a directory\"})\ndef directorypicker(directory=Path(\"~\")):\n    \"\"\"Take a directory name and do something with it.\"\"\"\n    print(\"The directory name is:\", directory)\n    return directory\n\n\ndirectorypicker.directory.changed.connect(print)\ndirectorypicker.show(run=True)\n

Total running time of the script: ( 0 minutes 0.042 seconds)

Download Python source code: directory_dialog.py

Download Jupyter notebook: directory_dialog.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/file_dialog/","title":"File dialog","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/file_dialog/#file-dialog-widget","title":"File dialog widget","text":"

A dialog to select a file.

Out:

<FunctionGui filepicker(filename=PosixPath('~')) -> pathlib._local.Path>\n

from pathlib import Path\n\nfrom magicgui import magicgui\n\n\n@magicgui(filename={\"mode\": \"r\"})\ndef filepicker(filename=Path(\"~\")) -> Path:\n    \"\"\"Take a filename and do something with it.\"\"\"\n    print(\"The filename is:\", filename)\n    return filename\n\n\nfilepicker.filename.changed.connect(print)\nfilepicker.show(run=True)\n

Total running time of the script: ( 0 minutes 0.042 seconds)

Download Python source code: file_dialog.py

Download Jupyter notebook: file_dialog.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/files_dialog/","title":"File dialog widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/files_dialog/#file-dialog-widget","title":"File dialog widget","text":"

A dialog to select multiple files.

Out:

<FunctionGui filespicker(filenames: collections.abc.Sequence[pathlib._local.Path] = ()) -> collections.abc.Sequence[pathlib._local.Path]>\n

from collections.abc import Sequence\nfrom pathlib import Path\n\nfrom magicgui import magicgui\n\n\n# Sequence of paths\n# We change the label using \"label\" for added clarity\n# the filter argument restricts file types\n@magicgui(filenames={\"label\": \"Choose Tiff files:\", \"filter\": \"*.tif\"})\ndef filespicker(filenames: Sequence[Path]) -> Sequence[Path]:\n    \"\"\"Take a filename and do something with it.\"\"\"\n    print(\"The filenames are:\", filenames)\n    return filenames\n\n\nfilespicker.filenames.changed.connect(print)\nfilespicker.show(run=True)\n

Total running time of the script: ( 0 minutes 0.053 seconds)

Download Python source code: files_dialog.py

Download Jupyter notebook: files_dialog.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/image/","title":"Image widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/image/#image-widget","title":"Image widget","text":"

Example of creating an Image Widget from a file.

(This requires pillow, or that magicgui was installed as magicgui[image])

Out:

Image(200x232x3, name='')\n

from magicgui.widgets import Image\n\nimage = Image(value=\"../../images/_test.jpg\")\nimage.scale_widget_to_image_size()\nimage.show(run=True)\n

Total running time of the script: ( 0 minutes 0.044 seconds)

Download Python source code: image.py

Download Jupyter notebook: image.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/log_slider/","title":"Log slider widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/log_slider/#log-slider-widget","title":"Log slider widget","text":"

A logarithmic scale range slider widget.

Out:

<FunctionGui slider(input=1.0)>\n

from magicgui import magicgui\n\n\n@magicgui(\n    auto_call=True,\n    result_widget=True,\n    input={\"widget_type\": \"LogSlider\", \"max\": 10000, \"min\": 1, \"tracking\": False},\n)\ndef slider(input=1):\n    \"\"\"Logarithmic scale slider.\"\"\"\n    return round(input, 4)\n\n\nslider.show(run=True)\n

Total running time of the script: ( 0 minutes 0.037 seconds)

Download Python source code: log_slider.py

Download Jupyter notebook: log_slider.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/login/","title":"Password login","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/login/#password-login","title":"Password login","text":"

A password login field widget.

Out:

<FunctionGui login(username: str = '', password: str = '', password2: str = '')>\n

from magicgui import magicgui\n\n\n# note that \"password\" is a special keyword argument\n# it will create a password field in the gui by default\n# (unless you override \"widget_type\")\n# whereas \"password2\" will be a normal text field\n# (unless you override \"widget_type\")\n@magicgui(password2={\"widget_type\": \"Password\"})\ndef login(username: str, password: str, password2: str):\n    \"\"\"User login credentials.\"\"\"\n    ...\n\n\nlogin.show(run=True)\n

Total running time of the script: ( 0 minutes 0.048 seconds)

Download Python source code: login.py

Download Jupyter notebook: login.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/mg_execution_times/","title":"Computation times","text":"

00:00.531 total execution time for generated_examples_demo_widgets files:

+--------------------------------------------------------------------------------------------+-----------+--------+ | range_slider (docs/examples/demo_widgets/range_slider.py) | 00:00.061 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | files_dialog (docs/examples/demo_widgets/files_dialog.py) | 00:00.053 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | login (docs/examples/demo_widgets/login.py) | 00:00.048 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | image (docs/examples/demo_widgets/image.py) | 00:00.044 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | optional (docs/examples/demo_widgets/optional.py) | 00:00.043 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | table (docs/examples/demo_widgets/table.py) | 00:00.042 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | choices (docs/examples/demo_widgets/choices.py) | 00:00.042 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | file_dialog (docs/examples/demo_widgets/file_dialog.py) | 00:00.042 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | directory_dialog (docs/examples/demo_widgets/directory_dialog.py) | 00:00.042 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | selection (docs/examples/demo_widgets/selection.py) | 00:00.040 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | change_label (docs/examples/demo_widgets/change_label.py) | 00:00.037 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | log_slider (docs/examples/demo_widgets/log_slider.py) | 00:00.037 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/demo_widgets/optional/","title":"Optional user choice","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/optional/#optional-user-choice","title":"Optional user choice","text":"

Optional user input using a dropdown selection widget.

Out:

<FunctionGui f(path: str = None)>\n

from typing import Optional\n\nfrom magicgui import magicgui\n\n\n# Using optional will add a '----' to the combobox, which returns \"None\"\n@magicgui(path={\"choices\": [\"a\", \"b\"]})\ndef f(path: Optional[str] = None):\n    \"\"\"\u00d6ptional user input function.\"\"\"\n    print(path, type(path))\n\n\nf.show(run=True)\n

Total running time of the script: ( 0 minutes 0.043 seconds)

Download Python source code: optional.py

Download Jupyter notebook: optional.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/range_slider/","title":"Range slider widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/range_slider/#range-slider-widget","title":"Range slider widget","text":"

A double ended range slider widget.

Out:

<FunctionGui func(range_value: tuple[int, int] = (20, 380))>\n

from magicgui import magicgui\n\n\n@magicgui(auto_call=True, range_value={\"widget_type\": \"RangeSlider\", \"max\": 500})\ndef func(range_value: tuple[int, int] = (20, 380)):\n    \"\"\"Double ended range slider.\"\"\"\n    print(range_value)\n\n\nfunc.show(run=True)\n

Total running time of the script: ( 0 minutes 0.061 seconds)

Download Python source code: range_slider.py

Download Jupyter notebook: range_slider.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/selection/","title":"Multiple selection widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/selection/#multiple-selection-widget","title":"Multiple selection widget","text":"

A selection widget allowing multiple selections by the user.

Out:

<FunctionGui my_widget(pick_some=['first'])>\n

from magicgui import magicgui\n\n\n@magicgui(\n    pick_some={\n        \"choices\": (\"first\", \"second\", \"third\", \"fourth\"),\n        \"allow_multiple\": True,\n    }\n)\ndef my_widget(pick_some=(\"first\")):\n    \"\"\"Dropdown selection function.\"\"\"\n    print(\"you selected\", pick_some)\n\n\nmy_widget.show(run=True)\n

Total running time of the script: ( 0 minutes 0.040 seconds)

Download Python source code: selection.py

Download Jupyter notebook: selection.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/table/","title":"Table widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/table/#table-widget","title":"Table widget","text":"

Demonstrating a few ways to input tables.

Out:

Table(shape=(6, 3) at 0x113157cb0)\n

import numpy as np\n\nfrom magicgui.widgets import Table\n\n# all of these are valid data types\ndict_of_lists = {\"col_1\": [1, 4], \"col_2\": [2, 5], \"col_3\": [3, 6]}\n# column-dict-of-row-dicts\ndict_of_dict = {\n    \"col_1\": {\"r1\": 1, \"r2\": 4},\n    \"col_2\": {\"r1\": 2, \"r2\": 5},\n    \"col_3\": {\"r1\": 3, \"r2\": 6},\n}\n# list-of-lists\nlist_of_list = [[1, 2, 3], [4, 5, 6]]\n# Records: List-of-column-dict\nlist_of_records = [\n    {\"col_1\": 1, \"col_2\": 2, \"col_3\": 3},\n    {\"col_1\": 4, \"col_2\": 5, \"col_3\": 6},\n]\n\n# 3-tuple of data, index, column\ndata_index_column_tuple = (([[1, 2, 3], [4, 5, 6]], (\"r1\", \"r2\"), (\"c1\", \"c2\", \"c3\")),)\n# split-dict\nsplit_dict = {\n    \"data\": [[1, 2, 3], [4, 5, 6]],\n    \"index\": (\"r1\", \"r2\"),\n    \"columns\": (\"c1\", \"c2\", \"c3\"),\n}\n\ntable = Table(value=dict_of_lists)\n\n# it behaves like a dict:\ntable[\"new_col\"] = [5, 5]\nassert table.pop(\"new_col\") == [5, 5]\n# keys and items have both regular (column) and \"row\" modes\ncol_item_view = table.items()  # iterate col_header/column\nrow_item_view = table.items(\"row\")  # iterate row_header/row\n\n# we can just call dict() to get back our dict of lists\nassert dict(table) == dict_of_lists\n# or use one of many other exports in `to_dict`\nassert table.to_dict(\"records\") == list_of_records\n\n# change headers\ntable.row_headers = (\"row1\", \"row2\")\ntable.column_headers = (\"a\", \"b\", \"c\")\n\n# setting value clears and resets the table:\ntable.value = np.arange(18).reshape(6, 3)\n# we can get/set/delete the 2D data table using numpy-style indexing:\n# get every other row\nassert table.data[::2] == [[0, 1, 2], [6, 7, 8], [12, 13, 14]]\n# set every other column in the 3rd row\ntable.data[2, ::2] = [99, 99]\n\n# export to numpy or pandas\n# table.data.to_numpy()\n# table.to_dataframe()\n\n# the table.changed event emits a dict of information on any cell change\n# e.g. {'data': 'sdfg', 'row': 1, 'column': 0, 'column_header': '1', 'row_header': '1'}\ntable.changed.connect(print)\ntable.show(run=True)\n

Total running time of the script: ( 0 minutes 0.042 seconds)

Download Python source code: table.py

Download Jupyter notebook: table.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/matplotlib/mg_execution_times/","title":"Computation times","text":"

00:00.269 total execution time for generated_examples_matplotlib files:

+------------------------------------------------------------------------+-----------+--------+ | waveform (docs/examples/matplotlib/waveform.py) | 00:00.163 | 0.0 MB | +------------------------------------------------------------------------+-----------+--------+ | mpl_figure (docs/examples/matplotlib/mpl_figure.py) | 00:00.106 | 0.0 MB | +------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/matplotlib/mpl_figure/","title":"matplotlib figure example","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/matplotlib/mpl_figure/#matplotlib-figure-example","title":"matplotlib figure example","text":"

Basic example of adding a generic QWidget to a container.

Main lesson: add your QWidget to container.native.layout() as shown on line 30

Out:

<FunctionGui f(position: int = 0)>\n

import matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.backends.backend_qt5agg import FigureCanvas\n\nfrom magicgui import magicgui\n\nx = np.linspace(0, 5, 256)\ny = np.linspace(0, 5, 256)[:, np.newaxis]\ndata = np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)\n\nmpl_fig = plt.figure()\nax = mpl_fig.add_subplot(111)\n(line,) = ax.plot(data[123])  # linescan through the middle of the image\n\n\n@magicgui(position={\"widget_type\": \"Slider\", \"max\": 255}, auto_call=True)\ndef f(position: int):\n    \"\"\"Function demonstrating magicgui combined with matplotlib.\"\"\"\n    line.set_ydata(data[position])\n    line.figure.canvas.draw()\n\n\n# rather than using the Container.append (`f.append`) ...\n# grab the native layout and add the QWidget to it\nf.native.layout().addWidget(FigureCanvas(mpl_fig))\n\nf.show(run=True)\n

Total running time of the script: ( 0 minutes 0.106 seconds)

Download Python source code: mpl_figure.py

Download Jupyter notebook: mpl_figure.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/matplotlib/waveform/","title":"Waveforms example","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/matplotlib/waveform/#waveforms-example","title":"Waveforms example","text":"

Simple waveform generator widget, with plotting.

Out:

<Container (signal_widget: NoneType, sine: NoneType)>\n

from dataclasses import dataclass, field\nfrom enum import Enum\nfrom functools import partial\nfrom typing import Annotated\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.backends.backend_qt5agg import FigureCanvas\nfrom scipy import signal\n\nfrom magicgui import magicgui, register_type, widgets\n\nregister_type(float, widget_type=\"FloatSlider\")\nregister_type(int, widget_type=\"Slider\")\n\nFreq = Annotated[float, {\"min\": 0.001, \"max\": 30.0}]\nPhase = Annotated[float, {\"min\": 0.0, \"max\": 360.0}]\nDuty = Annotated[float, {\"min\": 0.0, \"max\": 1.0}]\nTime = Annotated[float, {\"min\": 0.01, \"max\": 100.0}]\n\n\n@dataclass\nclass Signal:\n    \"\"\"Constructs a 1D signal.\n\n    As is, this class is not very useful, but one could add callbacks\n    or more functionality here\n\n    Parameters\n    ----------\n    func : callable\n        func must take a 'time' array as sole argument and return a 1D array with the\n        same size as the input\n    duration : float\n        the maximum of the input time array\n    size : int\n        the number of samples in the time array\n\n    \"\"\"\n\n    func: callable\n    duration: Time = 1.0\n    size: int = 500\n    time: np.ndarray = field(init=False)\n    data: np.ndarray = field(init=False)\n\n    def __post_init__(self):\n        \"\"\"Evaluate the function at instantiation time.\"\"\"\n        self.time = np.linspace(0, self.duration, self.size)\n        self.data = self.func(self.time)\n\n    def plot(self, ax=None, **kwargs):\n        \"\"\"Plots the data.\n\n        Parameters\n        ----------\n        ax: matplotlib.axes.Axes instance, default None\n           if provided the plot is done on this axes instance.\n           If None a new ax is created\n        **kwargs: Keyword arguments that are passed on to\n            the matplotib ax.plot method\n\n        Returns\n        -------\n        fig: a matplotlib.figure.Figure instance\n        ax: matplotlib.axes.Axes instance\n        \"\"\"\n        if ax is None:\n            fig, ax = plt.subplots()\n        else:\n            fig = ax.get_figure()\n        ax.plot(self.time, self.data, **kwargs)\n        return fig, ax\n\n\ndef sine(\n    duration: Time = 10.0, size: int = 500, freq: Freq = 0.5, phase: Phase = 0.0\n) -> Signal:\n    \"\"\"Returns a 1D sine wave.\n\n    Parameters\n    ----------\n    duration: float\n       the duration of the signal in seconds\n    size: int\n        the number of samples in the signal time array\n    freq: float\n       the frequency of the signal in Hz\n    phase: Phase\n       the phase of the signal (in degrees)\n    \"\"\"\n    sig = Signal(\n        duration=duration,\n        size=size,\n        func=lambda t: np.sin(t * (2 * np.pi * freq) + phase * np.pi / 180),\n    )\n    return sig\n\n\ndef chirp(\n    duration: Time = 10.0,\n    size: int = 500,\n    f0: float = 1.0,\n    t1: Time = 5.0,\n    f1: float = 2.0,\n    phase: Phase = 0.0,\n) -> Signal:\n    \"\"\"Frequency-swept cosine generator.\n\n    See scipy.signal.chirp\n    \"\"\"\n    sig = Signal(\n        duration=duration,\n        size=size,\n        func=partial(signal.chirp, f0=f0, t1=t1, f1=f1, phi=phase),\n    )\n    return sig\n\n\ndef sawtooth(\n    duration: Time = 10.0,\n    size: int = 500,\n    freq: Freq = 1.0,\n    width: Duty = 1.0,\n    phase: Phase = 0.0,\n) -> Signal:\n    \"\"\"Return a periodic sawtooth or triangle waveform.\n\n    See scipy.signal.sawtooth\n    \"\"\"\n    sig = Signal(\n        duration=duration,\n        size=size,\n        func=lambda t: signal.sawtooth(\n            2 * np.pi * freq * t + phase * np.pi / 180, width=width\n        ),\n    )\n    return sig\n\n\ndef square(\n    duration: Time = 10.0, size: int = 500, freq: Freq = 1.0, duty: Duty = 0.5\n) -> Signal:\n    \"\"\"Return a periodic sawtooth or triangle waveform.\n\n    See scipy.signal.square\n    \"\"\"\n    sig = Signal(\n        duration=duration,\n        size=size,\n        func=lambda t: signal.square(2 * np.pi * freq * t, duty=duty),\n    )\n    return sig\n\n\ndef on_off(\n    duration: Time = 10.0, size: int = 500, t_on: Time = 0.01, t_off: Time = 0.01\n) -> Signal:\n    \"\"\"On/Off signal function.\"\"\"\n    data = np.ones(size)\n    data[: int(size * t_on / duration)] = -1\n    if t_off > 0:\n        data[int(size * t_off / duration) :] = -1\n    sig = Signal(duration=duration, size=size, func=lambda t: data)\n    return sig\n\n\nWAVEFORMS = {\n    \"sine\": sine,\n    \"chirp\": chirp,\n    \"sawtooth\": sawtooth,\n    \"square\": square,\n    \"on_off\": on_off,\n}\n\n\nclass Select(Enum):\n    \"\"\"Enumeration to select signal type.\"\"\"\n\n    OnOff = \"on_off\"\n    Sine = \"sine\"\n    Chirp = \"chirp\"\n    Sawtooth = \"sawtooth\"\n    Square = \"square\"\n\n\nclass WaveForm(widgets.Container):\n    \"\"\"Simple waveform generator widget, with plotting.\"\"\"\n\n    def __init__(self):\n        \"\"\"Creates the widget.\"\"\"\n        super().__init__()\n        self.fig, self.ax = plt.subplots()\n        self.native.layout().addWidget(FigureCanvas(self.fig))\n        self.waveform = sine\n        self.controls = None\n        self.append(self.signal_widget)\n        self.update_controls()\n        self.update_graph(sine())\n\n    @magicgui(auto_call=True)\n    def signal_widget(self, select: Select = Select.Sine) -> widgets.Container:\n        \"\"\"Waveform selection, from the WAVEFORMS dict.\"\"\"\n        self.waveform = WAVEFORMS[select.value]\n        self.update_controls()\n        self.update_graph(self.waveform())\n\n    def update_controls(self):\n        \"\"\"Reset controls according to the new function.\"\"\"\n        if self.controls is not None:\n            self.remove(self.controls)\n        self.controls = magicgui(auto_call=True)(self.waveform)\n        self.append(self.controls)\n        self.controls.called.connect(self.update_graph)\n\n    def update_graph(self, sig: Signal):\n        \"\"\"Re-plot when a parameter changes.\n\n        Note\n        ----\n        For big data, this could be slow, maybe `auto_call` should\n        not be true in the method above...\n        \"\"\"\n        self.ax.cla()\n        sig.plot(ax=self.ax)\n        self.fig.canvas.draw()\n\n\nwaveform = WaveForm()\nwaveform.show(run=True)\n

Total running time of the script: ( 0 minutes 0.163 seconds)

Download Python source code: waveform.py

Download Jupyter notebook: waveform.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/napari/mg_execution_times/","title":"Computation times","text":"

00:07.525 total execution time for generated_examples_napari files:

+--------------------------------------------------------------------------------------------------------+-----------+--------+ | napari_combine_qt (docs/examples/napari/napari_combine_qt.py) | 00:04.805 | 0.0 MB | +--------------------------------------------------------------------------------------------------------+-----------+--------+ | napari_parameter_sweep (docs/examples/napari/napari_parameter_sweep.py) | 00:01.863 | 0.0 MB | +--------------------------------------------------------------------------------------------------------+-----------+--------+ | napari_img_math (docs/examples/napari/napari_img_math.py) | 00:00.824 | 0.0 MB | +--------------------------------------------------------------------------------------------------------+-----------+--------+ | napari_forward_refs (docs/examples/napari/napari_forward_refs.py) | 00:00.033 | 0.0 MB | +--------------------------------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/napari/napari_combine_qt/","title":"napari Qt demo","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/napari/napari_combine_qt/#napari-qt-demo","title":"napari Qt demo","text":"

Napari provides a few conveniences with magicgui, and one of the most commonly used is the layer combo box that gets created when a parameter is annotated as napari.layers.Layer.

The layer box will stay in sync with the viewer model, adding and removing layers as needed.

This example shows how to use just that widget in the context of a larger custom QWidget.

import napari\nfrom qtpy.QtWidgets import QVBoxLayout, QWidget\n\nfrom magicgui.widgets import create_widget\n\n\nclass CustomWidget(QWidget):\n    \"\"\"A custom widget class.\"\"\"\n\n    def __init__(self) -> None:\n        super().__init__()\n        self.setLayout(QVBoxLayout())\n        # change annotation to napari.layers.Image (e.g) to restrict to just Images\n        self._layer_combo = create_widget(annotation=napari.layers.Layer)\n        # magicgui widgets hold the Qt widget at `widget.native`\n        self.layout().addWidget(self._layer_combo.native)\n\n\nviewer = napari.Viewer()\nviewer.add_points()\nviewer.add_points()\n\nmy_widget = CustomWidget()\nviewer.window.add_dock_widget(my_widget)\n\n# when my_widget is a magicgui.Widget, it will detect that it has been added\n# to a viewer, and automatically update the choices.  Otherwise, you need to\n# trigger this yourself:\nmy_widget._layer_combo.reset_choices()\nviewer.layers.events.inserted.connect(my_widget._layer_combo.reset_choices)\nviewer.layers.events.removed.connect(my_widget._layer_combo.reset_choices)\n\nnapari.run()\n

Total running time of the script: ( 0 minutes 4.805 seconds)

Download Python source code: napari_combine_qt.py

Download Jupyter notebook: napari_combine_qt.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/napari/napari_forward_refs/","title":"napari forward reference demo","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/napari/napari_forward_refs/#napari-forward-reference-demo","title":"napari forward reference demo","text":"

Example of using a ForwardRef to avoid importing a module that provides a widget.

In this example, one might want to create a widget that takes as an argument a napari Image layer, and returns an Image. In order to avoid needing to import napari (and therefore depending directly on napari), it's possible to annotate those parameters with a string representation of the type (rather than the type itself). This is called a \"forward reference\": https://www.python.org/dev/peps/pep-0484/#forward-references

Out:

<FunctionGui subtract_background(data: napari.types.ImageData = None, background: int = 50) -> napari.types.ImageData>\n

# Note: if you'd like to avoid circular imports, or just want to avoid having your\n# linter yell at you for an undefined type annotation, you can place the import\n# inside of an `if typing.TYPE_CHECKING` conditional.  This is not evaluated at runtime,\n# only when something like mypy is doing type checking.\nfrom typing import TYPE_CHECKING\n\nfrom magicgui import magicgui\n\nif TYPE_CHECKING:\n    import napari\n\n\n@magicgui(call_button=\"execute\", background={\"max\": 200})\ndef subtract_background(\n    data: \"napari.types.ImageData\", background: int = 50\n) -> \"napari.types.ImageData\":\n    \"\"\"Subtract a constant from the data.\"\"\"\n    if data:\n        return data - background\n\n\nsubtract_background.show(run=True)\n# now, this example isn't all that interesting on its own (since there will be no Image\n# layer in the dropdown) ... but in another package, where you DO import napari,\n# you could add this widget to a napari viewer with\n# viewer.window.add_dock_widget(subtract_background)\n

Total running time of the script: ( 0 minutes 0.033 seconds)

Download Python source code: napari_forward_refs.py

Download Jupyter notebook: napari_forward_refs.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/napari/napari_img_math/","title":"napari image arithmetic widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/napari/napari_img_math/#napari-image-arithmetic-widget","title":"napari image arithmetic widget","text":"

napari is a fast, interactive, multi-dimensional image viewer for python. It uses Qt for the GUI, so it's easy to extend napari with small, composable widgets created with magicgui. Here we're going to build this simple image arithmetic widget with a few additional lines of code.

For napari-specific magicgui documentation, see the napari docs

"},{"location":"generated_examples/napari/napari_img_math/#outline","title":"outline","text":"

This example demonstrates how to:

  1. Create a magicgui widget that can be used in another program (napari)

  2. Use an Enum to create a dropdown menu

  3. Connect some event listeners to create interactivity.

"},{"location":"generated_examples/napari/napari_img_math/#code","title":"code","text":"

Code follows, with explanation below... You can also get this example at github.

from enum import Enum\n\nimport napari\nimport numpy\nfrom napari.types import ImageData\n\nfrom magicgui import magicgui\n\n\nclass Operation(Enum):\n    # A set of valid arithmetic operations for image_arithmetic.\n    #\n    # To create nice dropdown menus with magicgui, it's best\n    # (but not required) to use Enums.  Here we make an Enum\n    # class for all of the image math operations we want to\n    # allow.\n    add = numpy.add\n    subtract = numpy.subtract\n    multiply = numpy.multiply\n    divide = numpy.divide\n\n\n# here's the magicgui!  We also use the additional\n# `call_button` option\n@magicgui(call_button=\"execute\")\ndef image_arithmetic(\n    layerA: ImageData, operation: Operation, layerB: ImageData\n) -> ImageData:\n    # Add, subtracts, multiplies, or divides to image layers.\n    return operation.value(layerA, layerB)\n\n\n# create a viewer and add a couple image layers\nviewer = napari.Viewer()\nviewer.add_image(numpy.random.rand(20, 20), name=\"Layer 1\")\nviewer.add_image(numpy.random.rand(20, 20), name=\"Layer 2\")\n\n# add our new magicgui widget to the viewer\nviewer.window.add_dock_widget(image_arithmetic)\n\n# keep the dropdown menus in the gui in sync with the layer model\nviewer.layers.events.inserted.connect(image_arithmetic.reset_choices)\nviewer.layers.events.removed.connect(image_arithmetic.reset_choices)\n\nnapari.run()\n
"},{"location":"generated_examples/napari/napari_img_math/#walkthrough","title":"walkthrough","text":"

We're going to go a little out of order so that the other code makes more sense. Let's start with the actual function we'd like to write to do some image arithmetic.

"},{"location":"generated_examples/napari/napari_img_math/#the-function","title":"the function","text":"

Our function takes two numpy arrays (in this case, from Image layers), and some mathematical operation (we'll restrict the options using an enum.Enum). When called, ourfunction calls the selected operation on the data.

def image_arithmetic(array1, operation, array2):\n    return operation.value(array1, array2)\n
"},{"location":"generated_examples/napari/napari_img_math/#type-annotations","title":"type annotations","text":"

magicgui works particularly well with type annotations, and allows third-party libraries to register widgets and behavior for handling their custom types (using magicgui.type_map.register_type). napari provides support for magicgui by registering a dropdown menu whenever a function parameter is annotated as one of the basic napari Layer types, or, in this case, ImageData indicates we just the data attribute of the layer. Furthermore, it recognizes when a function has a napari.layers.Layer or LayerData return type annotation, and will add the result to the viewer. So we gain a lot by annotating the above function with the appropriate napari types.

from napari.types import ImageData\n\n\ndef image_arithmetic(\n    layerA: ImageData, operation: Operation, layerB: ImageData\n) -> ImageData:\n    return operation.value(layerA, layerB)\n
"},{"location":"generated_examples/napari/napari_img_math/#the-magic-part","title":"the magic part","text":"

Finally, we decorate the function with @magicgui and tell it we'd like to have a call_button that we can click to execute the function.

@magicgui(call_button=\"execute\")\ndef image_arithmetic(layerA: ImageData, operation: Operation, layerB: ImageData):\n    return operation.value(layerA, layerB)\n

That's it! The image_arithmetic function is now a FunctionGui that can be shown, or incorporated into other GUIs (such as the napari GUI shown in this example)

!!! note While type hints aren't always required in magicgui, they are recommended ... and they are required for certain things, like the Operation(Enum) used here for the dropdown and the napari.types.ImageData annotations that napari has registered with magicgui.

"},{"location":"generated_examples/napari/napari_img_math/#create-dropdowns-with-enums","title":"create dropdowns with Enums","text":"

We'd like the user to be able to select the operation (add, subtract, multiply, divide) using a dropdown menu. enum.Enum offers a convenient way to restrict values to a strict set of options, while providing name: value pairs for each of the options. Here, the value for each choice is the actual function we would like to have called when that option is selected.

class Operation(enum.Enum):\n    add = numpy.add\n    subtract = numpy.subtract\n    multiply = numpy.multiply\n    divide = numpy.divide\n
"},{"location":"generated_examples/napari/napari_img_math/#add-it-to-napari","title":"add it to napari","text":"

When we decorated the image_arithmetic function above, it became a FunctionGui. Napari recognizes this type, so we can simply add it to the napari viewer as follows:

viewer.window.add_dock_widget(image_arithmetic)\n
"},{"location":"generated_examples/napari/napari_img_math/#connect-event-listeners-for-interactivity","title":"connect event listeners for interactivity","text":"

What fun is a GUI without some interactivity? Let's make stuff happen.

We connect the image_arithmetic.reset_choices function to the viewer.layers.events.inserted/removed event from napari, to make sure that the dropdown menus stay in sync if a layer gets added or removed from the napari window:

viewer.layers.events.inserted.connect(image_arithmetic.reset_choices)\nviewer.layers.events.removed.connect(image_arithmetic.reset_choices)\n

Tip

An additional offering from magicgui here is that the decorated function also acquires a new attribute \"called\" that can be connected to callback functions of your choice. Then, whenever the gui widget or the original function are called, the result will be passed to your callback function:

@image_arithmetic.called.connect\ndef print_mean(value):\n    # Callback function that accepts an event\n    # the value attribute has the result of calling the function\n    print(np.mean(value))\n
>>> image_arithmetic()\n1.0060037881040373\n
"},{"location":"generated_examples/napari/napari_img_math/#code_1","title":"Code","text":"

Here's the full code example again.

from enum import Enum\n\nimport napari\nimport numpy\nfrom napari.types import ImageData\n\nfrom magicgui import magicgui\n\n\nclass Operation(Enum):\n    # A set of valid arithmetic operations for image_arithmetic.\n    #\n    # To create nice dropdown menus with magicgui, it's best\n    # (but not required) to use Enums.  Here we make an Enum\n    # class for all of the image math operations we want to\n    # allow.\n    add = numpy.add\n    subtract = numpy.subtract\n    multiply = numpy.multiply\n    divide = numpy.divide\n\n\n# here's the magicgui!  We also use the additional\n# `call_button` option\n@magicgui(call_button=\"execute\")\ndef image_arithmetic(\n    layerA: ImageData, operation: Operation, layerB: ImageData\n) -> ImageData:\n    # Add, subtracts, multiplies, or divides to image layers.\n    return operation.value(layerA, layerB)\n\n\n# create a viewer and add a couple image layers\nviewer = napari.Viewer()\nviewer.add_image(numpy.random.rand(20, 20), name=\"Layer 1\")\nviewer.add_image(numpy.random.rand(20, 20), name=\"Layer 2\")\n\n# add our new magicgui widget to the viewer\nviewer.window.add_dock_widget(image_arithmetic)\n\n# keep the dropdown menus in the gui in sync with the layer model\nviewer.layers.events.inserted.connect(image_arithmetic.reset_choices)\nviewer.layers.events.removed.connect(image_arithmetic.reset_choices)\n\nnapari.run()\n

Total running time of the script: ( 0 minutes 0.824 seconds)

Download Python source code: napari_img_math.py

Download Jupyter notebook: napari_img_math.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/napari/napari_parameter_sweep/","title":"napari parameter sweeps","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/napari/napari_parameter_sweep/#napari-parameter-sweeps","title":"napari parameter sweeps","text":"

napari is a fast, interactive, multi-dimensional image viewer for python. It uses Qt for the GUI, so it's easy to extend napari with small, composable widgets created with magicgui. Here, we demonstrate how to build a interactive widget that lets you immediately see the effect of changing one of the parameters of your function.

For napari-specific magicgui documentation, see the napari docs

See also: Some of this tutorial overlaps with topics covered in the napari image arithmetic example.

"},{"location":"generated_examples/napari/napari_parameter_sweep/#outline","title":"outline","text":"

This example demonstrates how to:

  1. Create a magicgui widget that can be used in another program (napari)

  2. Automatically call our function when a parameter changes

  3. Provide magicgui with a custom widget for a specific argument

  4. Use the choices option to create a dropdown

  5. Connect some event listeners to create interactivity.

"},{"location":"generated_examples/napari/napari_parameter_sweep/#code","title":"code","text":"

Code follows, with explanation below... You can also get this example at github.

import napari\nimport skimage.data\nimport skimage.filters\nfrom napari.types import ImageData\n\nfrom magicgui import magicgui\n\n\n# turn the gaussian blur function into a magicgui\n# - 'auto_call' tells magicgui to call the function when a parameter changes\n# - we use 'widget_type' to override the default \"float\" widget on sigma,\n#   and provide a maximum valid value.\n# - we contstrain the possible choices for 'mode'\n@magicgui(\n    auto_call=True,\n    sigma={\"widget_type\": \"FloatSlider\", \"max\": 6},\n    mode={\"choices\": [\"reflect\", \"constant\", \"nearest\", \"mirror\", \"wrap\"]},\n    layout=\"horizontal\",\n)\ndef gaussian_blur(layer: ImageData, sigma: float = 1.0, mode=\"nearest\") -> ImageData:\n    # Apply a gaussian blur to 'layer'.\n    if layer is not None:\n        return skimage.filters.gaussian(layer, sigma=sigma, mode=mode)\n\n\n# create a viewer and add some images\nviewer = napari.Viewer()\nviewer.add_image(skimage.data.astronaut().mean(-1), name=\"astronaut\")\nviewer.add_image(skimage.data.grass().astype(\"float\"), name=\"grass\")\n\n# Add it to the napari viewer\nviewer.window.add_dock_widget(gaussian_blur)\n# update the layer dropdown menu when the layer list changes\nviewer.layers.events.changed.connect(gaussian_blur.reset_choices)\n\nnapari.run()\n
"},{"location":"generated_examples/napari/napari_parameter_sweep/#walkthrough","title":"walkthrough","text":"

We're going to go a little out of order so that the other code makes more sense. Let's start with the actual function we'd like to write to apply a gaussian filter to an image.

"},{"location":"generated_examples/napari/napari_parameter_sweep/#the-function","title":"the function","text":"

Our function is a very thin wrapper around skimage.filters.gaussian. It takes a napari Image layer, a sigma to control the blur radius, and a mode that determines how edges are handled.

def gaussian_blur(layer: Image, sigma: float = 1, mode=\"nearest\") -> Image:\n    return filters.gaussian(layer.data, sigma=sigma, mode=mode)\n

The reasons we are wrapping it here are:

  1. filters.gaussian accepts a numpy array, but we want to work with napari layers that store the data in a layer.data attribute. So we need an adapter.
  2. We'd like to add some type annotations to the signature that were not provided by filters.gaussian
"},{"location":"generated_examples/napari/napari_parameter_sweep/#type-annotations","title":"type annotations","text":"

As described in the image arithmetic example, we take advantage of napari's built in support for magicgui by annotating our function parameters and return value as napari Layer types. napari will then tell magicgui what to do with them, creating a dropdown with a list of current layers for our layer parameter, and automatically adding the result of our function to the viewer when called.

For documentation on napari types with magicgui, see the napari docs

"},{"location":"generated_examples/napari/napari_parameter_sweep/#the-magic-part","title":"the magic part","text":"

Finally, we decorate the function with @magicgui and provide some options.

@magicgui(\n    auto_call=True,\n    sigma={\"widget_type\": \"FloatSlider\", \"max\": 6},\n    mode={\"choices\": [\"reflect\", \"constant\", \"nearest\", \"mirror\", \"wrap\"]},\n)\ndef gaussian_blur(layer: ImageData, sigma: float = 1.0, mode=\"nearest\") -> ImageData:\n    # Apply a gaussian blur to ``layer``.\n    if layer is not None:\n        return skimage.filters.gaussian(layer, sigma=sigma, mode=mode)\n
  • auto_call=True makes it so that the gaussian_blur function will be called whenever one of the parameters changes (with the current parameters set in the GUI).
  • We then provide keyword arguments to modify the look & behavior of sigma and mode:

    • \"widget_type\": \"FloatSlider\" tells magicgui not to use the standard (float) widget for the sigma widget, but rather to use a slider widget.
    • we then set an upper limit on the slider values for sigma.
  • finally, we specify valid choices for the mode argument. This turns that parameter into a categorical/dropdown type widget, and sets the options.

"},{"location":"generated_examples/napari/napari_parameter_sweep/#connecting-events","title":"connecting events","text":"

As described in the Events documentation, we can also connect any callback to the gaussian_blur.called signal that will receive the result of our decorated function anytime it is called.

def do_something_with_result(result): ...\n\n\ngaussian_blur.called.connect(do_something_with_result)\n
"},{"location":"generated_examples/napari/napari_parameter_sweep/#code_1","title":"Code","text":"

Here's the full code example again.

import napari\nimport skimage.data\nimport skimage.filters\nfrom napari.types import ImageData\n\nfrom magicgui import magicgui\n\n\n# turn the gaussian blur function into a magicgui\n# - 'auto_call' tells magicgui to call the function when a parameter changes\n# - we use 'widget_type' to override the default \"float\" widget on sigma,\n#   and provide a maximum valid value.\n# - we contstrain the possible choices for 'mode'\n@magicgui(\n    auto_call=True,\n    sigma={\"widget_type\": \"FloatSlider\", \"max\": 6},\n    mode={\"choices\": [\"reflect\", \"constant\", \"nearest\", \"mirror\", \"wrap\"]},\n    layout=\"horizontal\",\n)\ndef gaussian_blur(layer: ImageData, sigma: float = 1.0, mode=\"nearest\") -> ImageData:\n    # Apply a gaussian blur to 'layer'.\n    if layer is not None:\n        return skimage.filters.gaussian(layer, sigma=sigma, mode=mode)\n\n\n# create a viewer and add some images\nviewer = napari.Viewer()\nviewer.add_image(skimage.data.astronaut().mean(-1), name=\"astronaut\")\nviewer.add_image(skimage.data.grass().astype(\"float\"), name=\"grass\")\n\n# Add it to the napari viewer\nviewer.window.add_dock_widget(gaussian_blur)\n# update the layer dropdown menu when the layer list changes\nviewer.layers.events.changed.connect(gaussian_blur.reset_choices)\n\nnapari.run()\n

Total running time of the script: ( 0 minutes 1.863 seconds)

Download Python source code: napari_parameter_sweep.py

Download Jupyter notebook: napari_parameter_sweep.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/notebooks/magicgui_jupyter/","title":"Jupyter notebooks and magicgui","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/notebooks/magicgui_jupyter/#jupyter-notebooks-and-magicgui","title":"Jupyter notebooks and magicgui","text":"

This example shows magicgui widgets embedded in a jupyter notebook.

The key function here is use_app(\"ipynb\").

You can also get this example at github.

import math\nfrom enum import Enum\n\nfrom magicgui import magicgui, use_app\n\nuse_app(\"ipynb\")\n\n\nclass Medium(Enum):\n    # Various media and their refractive indices.\n    Glass = 1.520\n    Oil = 1.515\n    Water = 1.333\n    Air = 1.0003\n\n\n@magicgui(\n    call_button=\"calculate\", result_widget=True, layout=\"vertical\", auto_call=True\n)\ndef snells_law(aoi=1.0, n1=Medium.Glass, n2=Medium.Water, degrees=True):\n    # Calculate the angle of refraction given two media and an angle of incidence.\n    if degrees:\n        aoi = math.radians(aoi)\n    try:\n        n1 = n1.value\n        n2 = n2.value\n        result = math.asin(n1 * math.sin(aoi) / n2)\n        return round(math.degrees(result) if degrees else result, 2)\n    except ValueError:  # math domain error\n        return \"TIR!\"\n\n\nsnells_law\n

Total running time of the script: ( 0 minutes 0.000 seconds)

Download Python source code: magicgui_jupyter.py

Download Jupyter notebook: magicgui_jupyter.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/notebooks/mg_execution_times/","title":"Computation times","text":"

00:00.000 total execution time for generated_examples_notebooks files:

+-----------------------------------------------------------------------------------------+-----------+--------+ | magicgui_jupyter (docs/examples/notebooks/magicgui_jupyter.py) | 00:00.000 | 0.0 MB | +-----------------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/progress_bars/mg_execution_times/","title":"Computation times","text":"

00:00.191 total execution time for generated_examples_progress_bars files:

+---------------------------------------------------------------------------------------------------------------+-----------+--------+ | progress (docs/examples/progress_bars/progress.py) | 00:00.059 | 0.0 MB | +---------------------------------------------------------------------------------------------------------------+-----------+--------+ | progress_nested (docs/examples/progress_bars/progress_nested.py) | 00:00.048 | 0.0 MB | +---------------------------------------------------------------------------------------------------------------+-----------+--------+ | progress_manual (docs/examples/progress_bars/progress_manual.py) | 00:00.044 | 0.0 MB | +---------------------------------------------------------------------------------------------------------------+-----------+--------+ | progress_indeterminate (docs/examples/progress_bars/progress_indeterminate.py) | 00:00.039 | 0.0 MB | +---------------------------------------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/progress_bars/progress/","title":"Simple progress bar","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/progress_bars/progress/#simple-progress-bar","title":"Simple progress bar","text":"

A simple progress bar demo with magicgui.

Out:

<FunctionGui long_running(steps=10, delay=0.1)>\n

from time import sleep\n\nfrom magicgui import magicgui\nfrom magicgui.tqdm import trange\n\n# if magicui.tqdm.tqdm or trange are used outside of a @magicgui function, (such as in\n# interactive use in IPython), then they fall back to the standard terminal output\n\n\n# If use inside of a magicgui-decorated function\n# a progress bar widget will be added to the magicgui container\n@magicgui(call_button=True, layout=\"horizontal\")\ndef long_running(steps=10, delay=0.1):\n    \"\"\"Long running computation with range iterator.\"\"\"\n    # trange(steps) is a shortcut for `tqdm(range(steps))`\n    for _i in trange(steps):\n        sleep(delay)\n\n\nlong_running.show(run=True)\n

Total running time of the script: ( 0 minutes 0.059 seconds)

Download Python source code: progress.py

Download Jupyter notebook: progress.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/progress_bars/progress_indeterminate/","title":"Indeterminate progress bar","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/progress_bars/progress_indeterminate/#indeterminate-progress-bar","title":"Indeterminate progress bar","text":"

Example of an indeterminate progress bar for a long running computation of unknown time.

Out:

<FunctionGui long_running(sleep_time=5)>\n

import time\n\nfrom superqt.utils import thread_worker\n\nfrom magicgui import magicgui\nfrom magicgui.tqdm import tqdm\n\n\n@magicgui(call_button=True, layout=\"horizontal\")\ndef long_running(sleep_time=5):\n    \"\"\"Long running computation with an indeterminate progress bar.\"\"\"\n    # Here tqdm is not provided an iterable argument, or the 'total' kwarg\n    # so it cannot calculate the expected number of iterations\n    # which means it will create an indeterminate progress bar\n    with tqdm() as pbar:\n        # It is best practice to use a separate thread for long running computations\n        # This makes the function non-blocking, you can still interact with the widget\n        @thread_worker(connect={\"finished\": lambda: pbar.progressbar.hide()})\n        def sleep(secs):\n            time.sleep(secs)\n\n        sleep(sleep_time)\n\n\nlong_running.show(run=True)\n

Total running time of the script: ( 0 minutes 0.039 seconds)

Download Python source code: progress_indeterminate.py

Download Jupyter notebook: progress_indeterminate.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/progress_bars/progress_manual/","title":"Manual progress bar","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/progress_bars/progress_manual/#manual-progress-bar","title":"Manual progress bar","text":"

Example of a progress bar being updated manually.

Out:

<FunctionGui manual(pbar: magicgui.widgets.ProgressBar = ProgressBar(value=<function TypeMap.match_type.<locals>.<lambda> at 0x120e83740>, annotation=<class 'magicgui.widgets.ProgressBar'>, name='pbar'), increment: bool = 1)>\n

from magicgui import magicgui\nfrom magicgui.widgets import ProgressBar\n\n\n@magicgui(call_button=\"tick\", pbar={\"min\": 0, \"step\": 2, \"max\": 20, \"value\": 0})\ndef manual(pbar: ProgressBar, increment: bool = True):\n    \"\"\"Example of manual progress bar control.\"\"\"\n    if increment:\n        pbar.increment()\n    else:\n        pbar.decrement()\n\n\nmanual.show(run=True)\n

Total running time of the script: ( 0 minutes 0.044 seconds)

Download Python source code: progress_manual.py

Download Jupyter notebook: progress_manual.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/progress_bars/progress_nested/","title":"Nested progress bars","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/progress_bars/progress_nested/#nested-progress-bars","title":"Nested progress bars","text":"

Example using nested progress bars in magicgui.

Out:

<FunctionGui long_function(steps=10, repeats=4, choices='ABCDEFGHIJKLMNOP12345679', char='', delay=0.05)>\n

import random\nfrom time import sleep\n\nfrom magicgui import magicgui\nfrom magicgui.tqdm import tqdm, trange\n\n# if magicui.tqdm.tqdm or trange are used outside of a @magicgui function, (such as in\n# interactive use in IPython), then they fall back to the standard terminal output\n\n\n# If use inside of a magicgui-decorated function\n# a progress bar widget will be added to the magicgui container\n@magicgui(call_button=True, layout=\"vertical\")\ndef long_function(\n    steps=10, repeats=4, choices=\"ABCDEFGHIJKLMNOP12345679\", char=\"\", delay=0.05\n):\n    \"\"\"Long running computation with nested iterators.\"\"\"\n    # trange and tqdm accept all the kwargs from tqdm itself, as well as any\n    # valid kwargs for magicgui.widgets.ProgressBar, (such as \"label\")\n    for _r in trange(repeats, label=\"repeats\"):\n        letters = [random.choice(choices) for _ in range(steps)]\n        # `tqdm`, like `tqdm`, accepts any iterable\n        # this progress bar is nested and will be run & reset multiple times\n        for letter in tqdm(letters, label=\"steps\"):\n            long_function.char.value = letter\n            sleep(delay)\n\n\nlong_function.show(run=True)\n

Total running time of the script: ( 0 minutes 0.048 seconds)

Download Python source code: progress_nested.py

Download Jupyter notebook: progress_nested.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/under_the_hood/class_method/","title":"Deocrate class methods with magicgui","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/under_the_hood/class_method/#deocrate-class-methods-with-magicgui","title":"Deocrate class methods with magicgui","text":"

Demonstrates decorating a class method with magicgui.

Once the class is instantiated, instance.method_name will return a FunctionGui in which the instance will always be provided as the first argument (i.e. \"self\") when the FunctionGui or method is called.

Out:

instance: a, counter: 0.0, sigma: 0.0\ninstance: b, counter: 0.0, sigma: 0.0\n

from magicgui import event_loop, magicgui\nfrom magicgui.widgets import Container\n\n\nclass MyObject:\n    \"\"\"Example object class.\"\"\"\n\n    def __init__(self, name):\n        self.name = name\n        self.counter = 0.0\n\n    @magicgui(auto_call=True)\n    def method(self, sigma: float = 0):\n        \"\"\"Example class method.\"\"\"\n        print(f\"instance: {self.name}, counter: {self.counter}, sigma: {sigma}\")\n        self.counter = self.counter + sigma\n        return self.name\n\n\nwith event_loop():\n    a = MyObject(\"a\")\n    b = MyObject(\"b\")\n    container = Container(widgets=[a.method, b.method])\n    container.show()\n    assert a.method() == \"a\"\n    assert b.method() == \"b\"\n

Total running time of the script: ( 0 minutes 0.034 seconds)

Download Python source code: class_method.py

Download Jupyter notebook: class_method.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/under_the_hood/mg_execution_times/","title":"Computation times","text":"

00:00.075 total execution time for generated_examples_under_the_hood files:

+----------------------------------------------------------------------------------------+-----------+--------+ | self_reference (docs/examples/under_the_hood/self_reference.py) | 00:00.041 | 0.0 MB | +----------------------------------------------------------------------------------------+-----------+--------+ | class_method (docs/examples/under_the_hood/class_method.py) | 00:00.034 | 0.0 MB | +----------------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/under_the_hood/self_reference/","title":"Self reference magicgui widgets","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/under_the_hood/self_reference/#self-reference-magicgui-widgets","title":"Self reference magicgui widgets","text":"

Widgets created with magicgui can reference themselves, and use the widget API.

Out:

<FunctionGui function(width=400, x: int = 50)>\n

from magicgui import magicgui\n\n\n@magicgui(auto_call=True, width={\"max\": 800, \"min\": 100}, x={\"widget_type\": \"Slider\"})\ndef function(width=400, x: int = 50):\n    \"\"\"Example function.\"\"\"\n    # the widget can reference itself, and use the widget API\n    function.x.width = width\n\n\nfunction.show(run=True)\n

Total running time of the script: ( 0 minutes 0.041 seconds)

Download Python source code: self_reference.py

Download Jupyter notebook: self_reference.ipynb

Gallery generated by mkdocs-gallery

"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"magicgui \ud83e\uddd9","text":"

magicgui is a python library for building graphical user interfaces (GUIs).

It aims to speed up data workflows by providing a simple, consistent API for creating GUIs to control various data types, that work across various environments.

GUIs may be built manually using a variety of widgets, or generated automatically from python type hints.

"},{"location":"#magicgui-organization","title":"magicgui organization","text":"

magicgui can be thought of as performing two distinct tasks:

  1. Providing an simplified abstraction layer for GUI frameworks, allowing you to use the same API to create UIs that can move between environments and frameworks (such as a desktop app, or a Jupyter notebook).
  2. Providing a mapping of python types to widgets, allowing you to autogenerate graphical user interfaces for functions and dataclasses by annotating with standard python type hints.

While there is some degree of customizeability, the emphasis is on rapid development of relatively simple GUIs, with minimal boilerplate. For highly customized GUIs with complex layouts, it may be more appropriate to use a lower-level GUI framework.

The API is organized into 2 main levels:

magicgui API layers"},{"location":"#python-type-mapping","title":"Python Type Mapping","text":"

At its highest level, magicgui provides a mapping of Python types to widgets. This API allows you to create graphical user interfaces for your functions and dataclasses simply by annotating them with standard python type hints.

Type hints??

Type hints are a way to annotate your code with information about the types of variables and function arguments. They are completely optional, but static type checkers and other libraries (like magicgui!) can use them to check your code and/or provide additional functionality.

Typically, they are provided after a colon following a variable name or function argument.

In the example below, param_a has been annotated as an int, param_b as a str, and the return value as a list.

def my_function(param_a: int, param_b: str) -> list:\n    ...\n

If you are new to type annotations in Python, here are a few resources to get you started:

  • PEP 484 - the Python Enhancement Proposal that introduced type hints to the language. (See also: PEP 483)
  • Python docs - the official Python documentation on type hints and the typing module.
  • The mypy documentation also has a lot of useful information, including this cheat sheet
"},{"location":"#create_widget","title":"create_widget","text":"

magicgui.widgets.create_widget is a general function, used throughout the library, that allows you to create a widget for a specific Python type or value:

from magicgui.widgets import create_widget\n\n# passing a type to create_widget\nwidget = create_widget(annotation=int)\nwidget.show()\n

# passing a value to create_widget\nwidget2 = create_widget(value=\"Hello World\")\nwidget2.show()\n

For more details on how magicgui maps types to widgets, see Type Mapping.

"},{"location":"#magicgui_1","title":"magicgui","text":"

The magicgui.magicgui function is one way to autogenerate a compound Widget based on the parameters of a function:

from typing import Annotated, Literal\n\nfrom magicgui import magicgui\n\n\n@magicgui\ndef my_function(\n    param_a: int,\n    param_b: Annotated[int, {'widget_type': \"Slider\", 'max': 100}] = 42,\n    param_c: Literal[\"First\", \"Second\", \"Third\"] = \"Second\"\n):\n    print(\"param_a:\", param_a)\n    print(\"param_b:\", param_b)\n    print(\"param_c:\", param_c)\n\n# my_function now IS a widget, in addition to being a callable function\nmy_function.show()\n

For more details on using magicgui and magic_factory, see the magicgui decorators page.

"},{"location":"#guiclass","title":"guiclass","text":"

magicgui.experimental.guiclass is a newer experimental feature that provides an object-oriented alternative to magicgui. It wraps dataclasses.dataclass and adds a gui attribute to the resulting class, which is a magicgui-generated widget that can be used to control the dataclass instance. (The widget is only created when the gui attribute is accessed for the first time.)

from magicgui.experimental import guiclass, button\n\n@guiclass\nclass MyDataclass:\n    a: int = 0\n    b: str = 'hello'\n    c: bool = True\n\n    @button\n    def compute(self):\n        print(self.a, self.b, self.c)\n\nobj = MyDataclass(a=10, b='foo')\nobj.gui.show()\n

For more details on using the guiclass decorator, see Dataclasses & guiclass.

"},{"location":"#widgets","title":"Widgets","text":"

At the lower level, magicgui is a library of widgets (the individual elements that make up a graphical user interface). Each widget is customized to display and interact with a specific type of data. In some cases, it makes more sense to create and arrange these widgets manually, rather than using the type-based autogeneration features described above.

Magicgui acts as an abstraction layer for a variety of different GUI toolkits, allowing you to use the same API to create UIs that can move between environments (such as a desktop app, or a Jupyter notebook).

Currently, magicgui supports the following backends:

  • Qt (via PySide2/PySide6 or PyQt5/PyQt6)
  • Jupyter Widgets (a.k.a. \"IPyWidgets\")

You can use magicgui.widgets to quickly build graphical user interfaces.

from magicgui import widgets\n\na = widgets.SpinBox(value=10, label=\"a\")\nb = widgets.Slider(value=20, min=0, max=100, label=\"b\")\nresult = widgets.LineEdit(value=a.value * b.value, label=\"result\")\nbutton = widgets.PushButton(text=\"multiply\")\n\n@button.clicked.connect\ndef on_button_click():\n    result.value = a.value * b.value\n\ncontainer = widgets.Container(widgets=[a, b, result, button])\ncontainer.show()\n

To learn more about the available widgets and how to use them, see the Widgets Overview.

...details

Behind the scenes, magicgui declares a set of WidgetProtocols that each backend must implement, and every magicgui Widget is a wrapper around a backend-specific widget. Most users will never need to worry about this, but it's good to know that it's there if you ever need to dig deeper.

"},{"location":"#events","title":"Events","text":"

All widgets (whether created directly or autogenerated based on type hints) emit events when their value changes or in response to interaction.

To learn about connecting custom functionality to these events, see Events.

"},{"location":"#installation","title":"Installation","text":"

See installing magicgui.

"},{"location":"CONTRIBUTING/","title":"Contributing","text":"

Contributions are welcome!

"},{"location":"CONTRIBUTING/#development","title":"Development","text":"

To install magicgui for development, first clone the repository:

git clone https://github.com/pyapp-kit/magicgui\ncd magicgui\n

Then install the package in editable mode with the dev extra:

pip install -e .[dev]\n

To run the tests:

pytest\n
"},{"location":"CONTRIBUTING/#code-quality","title":"Code Quality","text":"

magicgui attempts to adhere to strict coding rules and employs the following static analysis tools to prevent errors from being introduced into the codebase:

  • black - code formatting
  • ruff - linting
  • mypy - static type analysis
  • codecov - test coverage

To prevent continuous integration failures when contributing, please consider installing pre-commit in your environment to run all of these checks prior to checking in new code.

pre-commit install\n

To run the checks manually, you can use:

pre-commit run --all-files\n
"},{"location":"CONTRIBUTING/#adding-a-widget","title":"Adding a widget","text":"

These instructions may change in the future as the repo structures changes. If they appear outdated as you follow them, please open an issue.

To add a new widget, you will need to:

  1. Create a new class in magicgui/widgets/_concrete.py that inherits from the base class most appropriate for your widget (e.g. ValueWidget, or CategoricalWidget).

    In some (complex) cases, you may need to extend one of the base classes. If so, it is likely that you will also need to extend one of the Protocols found in magicgui.widgets.protocols. This is where all of protocols that backend classes need to implement to work with a given widget type. (Don't hesitate to open an issue if you're confused).

  2. Most likely, you will want to decorate the class with @backend_widget. Using this decorator implies that there is a class with the same name in any any backend modules that will support this widget type (e.g. magicgui.backends._qtpy.widgets for Qt support.).

  3. Make any changes necessary to your new concrete class. For example, you may need to change the value property and corresponding setter to handle a specific type. This part of the code should be backend agnostic.
  4. Export the new class in magicgui/widgets/__init__.py so that it can be imported from magicgui.widgets.
  5. Implement the backend widget class (using the same class name) in the appropriate backend module (e.g. magicgui.backends._qtpy.widgets for Qt support). Usually this will mean implementing the appropriate _mgui_get/set_... methods for the Protocol of the corresponding widget base class your chose to extend.
  6. Export the backend widget class in the __init__.py of the backend module (e.g. magicgui.backends._qtpy.__init__.py for Qt support). This is important, as that is where the @backend_widget decorator will look.
  7. Add a test for your new widget.

For an example of a minimal PR adding a new widget, see #483, which added a QuantityWidget to be used with pint.Quantity objects.

"},{"location":"CONTRIBUTING/#associating-a-widget-with-a-type","title":"Associating a widget with a type","text":"

To associate your new widget with a specific type such that it will be used when someone annotates a parameter with that type, you will need to update code in magicgui.type_map._type_map.

In the simplest of cases, this will mean adding a new entry to the magicgui.type_map._type_map._SIMPLE_TYPES dict. This is a mapping from a python type to a widget class. (Note that all subclasses of the type will also be matched.)

For more complex cases, you can add a new conditional to the body of the match_type function. That function should always return a tuple of widget type, and kwargs that will be passed to the widget constructor. For example: return widgets.MyNewWidget, {}.

"},{"location":"CONTRIBUTING/#building-the-documentation","title":"Building the documentation","text":"

To build the documentation locally, you will need to install the docs extra:

pip install -e .[docs]\n

Then, from the root of the repository, run:

mkdocs serve\n

This will start a local server at http://127.0.0.1:8000/ where you can view the documentation as you edit it.

"},{"location":"dataclasses/","title":"Dataclasses & guiclass","text":""},{"location":"dataclasses/#what-are-dataclasses","title":"What are dataclasses?","text":"

dataclasses are a feature added in Python 3.7 (PEP 557) that allow you to simply define classes that store a specific set of data. They encourage clear, type-annotated code, and are a great way to define data structures with minimal boilerplate.

New to dataclasses?

If you're totally new to dataclasses, you might want to start with the official documentation for the dataclasses module, or this Real Python post on dataclasses. The following is a very brief example of the key features:

Example dataclass
from dataclasses import dataclass\n\n@dataclass  # (1)!\nclass Person:\n    name: str # (2)!\n    age: int = 0  # (3)!\n\np = Person(name='John', age=30)  # (4)!\nprint(p) # (5)!\n
  1. The @dataclass decorator is used to mark a class as a dataclass. This will automatically generate an __init__ method with a parameter for each annotated class attribute.
  2. Attribute names are annotated with types. Note that, as with all Python type hints, these have no runtime effect (i.e. no validation is performed).
  3. Optional attributes can be defined with a default value. If no default value is specified, then the field is required when creating a new object.
  4. Creating a new object is as simple as passing in the required arguments.
  5. The __repr__ method is automatically generated and will print out the class name and all of the attributes and their current values.
"},{"location":"dataclasses/#dataclass-patterns-outside-the-standard-library","title":"dataclass patterns outside the standard library","text":"

The dataclasses module is not the only way to define data-focused classes in Python. There are other libraries that provide similar functionality, and some of them have additional features that are not available in the standard library.

  • attrs is a popular library that provides a number of additional features on top of the standard library dataclasses, including complex validation and type conversions.
  • pydantic is a library that provides runtime type enforcement and casting, serialization, and other features.
  • msgspec is a fast serialization library with a msgspec.Struct that is similar to a dataclass.
"},{"location":"dataclasses/#magicgui-guiclass","title":"magicgui guiclass","text":"

Experimental

This is an experimental feature. The API may change in the future without deprecations or warnings.

magicgui supports the dataclass API as a way to define the interface for compound widget, where each attribute of the dataclass is a separate widget. The magicgui.experimental.guiclass decorator can be used to mark a class as a \"GUI class\". A GUI class is a Python standard dataclass that has two additional features:

  1. A property (named \"gui\" by default) that returns a Container widget which contains a widget for each attribute of the dataclass.
  2. An property (named \"events\" by default) that returns a psygnal.SignalGroup object that allows you to connect callbacks to the change event of any of field in the dataclass. (Under the hood, this uses the @evented dataclass decorator from psygnal.)

Tip

You can still use all of the standard dataclass features, including field values, __post_init__ processing, and ClassVar.

Info

In the future, we may also support other dataclass-like objects, such as pydantic models, attrs classes, and traitlets classes.

from magicgui.experimental import guiclass\n\n@guiclass\nclass MyDataclass:\n    a: int = 0\n    b: str = 'hello'\n    c: bool = True\n\nobj = MyDataclass()\nobj.gui.show()\n

The individual widgets in the Container may be accessed by the same name as the corresponding attribute. For example, obj.gui.a will return the SpinBox widget that controls the value of the a attribute.

"},{"location":"dataclasses/#two-way-data-binding","title":"Two-way data binding","text":"

As you interact programmatically with the obj instance, the widgets in the obj.gui will update. Similarly, as you change the value of the widgets in the obj.gui, the values of the obj instance will be updated.

obj = MyDataclass(a=10)\nobj.b = 'world'\nobj.c = False\n\nobj.gui.show()\n

All magicgui-related stuff is in the gui attribute

The original dataclass instance (obj) is essentially untouched. Just as in a regular dataclass, obj.a returns the current value of a in the dataclass. The widget for the class will be at obj.gui (or whatever name you specified in the gui_name parameter) So, obj.gui.a.value, returns the current value of the widget. Unless you explicitly disconnect the gui from the underlying object/model, the two will always be in sync.

"},{"location":"dataclasses/#adding-buttons-and-callbacks","title":"Adding buttons and callbacks","text":"

Buttons are one of the few widget types that tend not to have an associated value, but simply trigger a callback when clicked. That is: it doesn't often make sense to add a field to a dataclass representing a button. To add a button to a guiclass, decorate a method with the magicgui.experimental.button decorator.

positioning buttons

Currently, all buttons are appended to the end of the widget. The ability to position the button in the layout will be added in the future.

Any additional keyword arguments to the button decorator will be passed to the magicgui.widgets.PushButton constructor (e.g. label, tooltip, etc.)

from magicgui.experimental import guiclass, button\n\n@guiclass\nclass Greeter:\n    first_name: str\n\n    @button\n    def say_hello(self):\n        print(f'Hello {self.first_name}')\n\ngreeter = Greeter('Talley')\ngreeter.gui.show()\n

clicking the \"say_hello\" button will print \"Hello Talley\" to the console

Tip

As your widget begins to manage more internal state, the guiclass pattern becomes much more useful than the magicgui decorator pattern -- which was designed with pure functions that take inputs and return outputs in mind.

"},{"location":"decorators/","title":"magicgui & magic_factory","text":""},{"location":"decorators/#from-object-to-gui","title":"From Object to GUI","text":"

The eponymous feature of magicgui is the magicgui.magicgui function, which converts an object into a widget.

Info

Currently, the only supported objects are functions, but in the future magicgui.magicgui may accept other objects, such as dataclass instances

When used to decorate a function, @magicgui will autogenerate a graphical user interface (GUI) by inspecting the function signature and adding an appropriate GUI widget for each parameter, as described in Type Hints to Widgets. Parameter types are taken from type hints, if provided, or inferred using the type of the default value otherwise.

import math\nfrom enum import Enum\nfrom magicgui import magicgui\n\n# dropdown boxes are best made by creating an enum\nclass Medium(Enum):\n    Glass = 1.520\n    Oil = 1.515\n    Water = 1.333\n    Air = 1.0003\n\n# decorate your function with the @magicgui decorator\n@magicgui(call_button=\"calculate\")\ndef snells_law(aoi=30.0, n1=Medium.Glass, n2=Medium.Water, degrees=True):\n    aoi = math.radians(aoi) if degrees else aoi\n    try:\n        result = math.asin(n1.value * math.sin(aoi) / n2.value)\n        return math.degrees(result) if degrees else result\n    except ValueError:\n        # beyond the critical angle\n        return \"Total internal reflection!\"\n\nsnells_law.show()\n

The object returned by the magicgui decorator is an instance of magicgui.widgets.FunctionGui. It can still be called like the original function, but it also knows how to present itself as a GUI.

"},{"location":"decorators/#two-way-data-binding","title":"Two-Way Data Binding","text":"

The modified snells_law object gains attributes named after each of the parameters in the function. Each attribute is an instance of a magicgui.widgets.Widget subclass (suitable for the data type represented by that parameter). As you make changes in your GUI, the attributes of the snells_law object will be kept in sync. For instance, change the first dropdown menu from \"Glass\" to \"Oil\", and the corresponding n1 object on snells_law will change its value to 1.515:

snells_law.n1.value  # 1.515\n

It goes both ways: set a parameter in the console and it will change in the GUI:

snells_law.aoi.value = 47\nsnells_law.show()\n

"},{"location":"decorators/#its-still-a-function","title":"It's still a function","text":"

magicgui tries very hard to make it so that the decorated object behaves as much like the original object as possible.

We can invoke the function in a few ways:

  • Because we provided the call_button argument to the magicgui decorator, a new button was created that will execute the function with the current gui parameters when clicked.

  • We can call the object just like the original function.

    snells_law()        # 34.7602\nsnells_law(aoi=12)  # 13.7142\n

    Now however, the current values from the GUI will be used as the default values for any arguments that are not explicitly provided to the function.

    snells_law.aoi.value = 12\nsnells_law()  # 13.7142\nsnells_law(aoi=30)  # 34.7602\n

    In essence, your original function now has a \"living\" signature whose defaults change as the user interacts with your GUI.

    import inspect\n\ninspect.signature(snells_law)\n# <MagicSignature(\n#   aoi=12.0, n1=<Medium.Glass: 1.52>, n2=<Medium.Water: 1.333>, degrees=True\n# )>\n# notice how the default `aoi` is now 12 ... because we changed it above\n
  • You can still override positional or keyword arguments in the original function, just as you would with a regular function.

    Note

    calling the function with values that differ from the GUI will not set the values in the GUI... It's just a one-time call.

    # in radians, overriding the value for the second medium (n2)\nsnells_law(0.8, n2=Medium.Air, degrees=False)  # 'Total internal reflection!'\n
"},{"location":"decorators/#connecting-events","title":"Connecting Events","text":""},{"location":"decorators/#function-calls","title":"Function Calls","text":"

With a GUI, you are usually looking for something to happen as a result of calling the function. The function will have a new called attribute that you can connect to an arbitrary callback function:

@snells_law.called.connect\ndef my_callback(value: str):\n    # The callback receives an `Event` object that has the result\n    # of the function call in the `value` attribute\n    print(f\"Your function was called! The result is: {value}\")\n\nresult = snells_law()\n

Now when you call snells_law(), or click the calculate button in the gui, my_callback will be called with the result of the calculation.

"},{"location":"decorators/#parameter-changes","title":"Parameter Changes","text":"

You can also listen for changes on individual function parameters by connecting to the <parameter_name>.changed signal:

# whenever the current value for n1 changes, print it to the console:\n@snells_law.n1.changed.connect\ndef _on_n1_changed(x: Medium):\n    print(f\"n1 was changed to {x}\")\n\nsnells_law.n1.value = Medium.Air\n

Note

This signal will be emitted regardless of whether the parameter was changed in the GUI or via by directly setting the paramaeter on the gui instance.

"},{"location":"decorators/#usage-as-a-decorator-is-optional","title":"Usage As a Decorator is Optional","text":"

Remember: the @decorator syntax is just syntactic sugar. You don't have to use @magicgui to decorate your function declaration. You can also just call it with your function as an argument:

This decorator usage:

@magicgui(auto_call=True)\ndef function():\n    pass\n

is equivalent to this:

def function():\n    pass\n\nfunction = magicgui(function, auto_call=True)\n

In many cases, it will actually be desirable not to use magicgui as a decorator if you don't need a widget immediately, but want to create one later (see also the magic_factory decorator.)

# some time later...\nwidget_instance = magicgui(function)\n
"},{"location":"decorators/#magic_factory","title":"magic_factory","text":"

The magicgui.magic_factory function/decorator acts very much like the magicgui decorator, with one important difference:

Unlike magicgui, magic_factory does not return a widget instance immediately. Instead, it returns a \"factory function\" that can be called to create a widget instance.

This is an important distinction to understand. In most cases, the @magicgui decorator is useful for interactive use or rapid prototyping. But if you are writing a library or package where someone else will be instantiating your widget (a napari plugin is a good example), you will likely want to use magic_factory instead, (or create your own Widget Container subclass).

it's just a partial

If you're familiar with functools.partial, you can think of magic_factory as a partial function application of the magicgui decorator (in fact, magic_factory is a subclass of partial). It is very roughly equivalent to:

def magic_factory(func, *args, **kwargs):\n    return partial(magicgui, func, *args, **kwargs)\n
"},{"location":"decorators/#widget_init","title":"widget_init","text":"

magic_factory gains one additional parameter: widget_init. This accepts a callable that will be called with the new widget instance each time the factory is called. This is a convenient place to add additional initialization or connect events.

from magicgui import magic_factory\n\ndef _on_init(widget):\n    print(\"widget created!\", widget)\n    widget.y.changed.connect(lambda x: print(\"y changed!\", x))\n\n@magic_factory(widget_init=_on_init)\ndef my_factory(x: int, y: str): ...\n\nnew_widget = my_factory()\n
"},{"location":"decorators/#the-lack-of-magic-in-magicgui","title":"The (lack of) \"magic\" in magicgui","text":"

Just to demystify the name a bit, there really isn't a whole lot of \"magic\" in the magicgui decorator. It's really just a thin wrapper around the magicgui.widgets.create_widget function, to create a Container with a sub-widget for each parameter in the function signature.

The widget creation is very roughly equivalent to something like this:

from inspect import signature, Parameter\nfrom magicgui.widgets import create_widget, Container\nfrom magicgui.types import Undefined\n\n\ndef pseudo_magicgui(func: 'Callable'):\n    return Container(\n        widgets=[\n            create_widget(p.default, annotation=p.annotation, name=p.name)\n            for p in signature(func).parameters.values()\n        ]\n    )\n\ndef some_func(x: int = 2, y: str = 'hello'):\n    return x, y\n\nmy_widget = pseudo_magicgui(some_func)\nmy_widget.show()\n

In the case of magicgui, a special subclass of Container (FunctionGui) is used, which additionally adds a __call__ method that allows the widget to behave like the original function.

"},{"location":"events/","title":"Events","text":"

All magicgui widgets emit events when certain properties change. For each event there is a corresponding signal attribute on the widget that can be connected to a callback function. For example, a PushButton emits an event when it is clicked, and all ValueWidget subclasses (like Slider or LineEdit) emit an event when their value changes.

"},{"location":"events/#connecting-to-events","title":"Connecting to events","text":"

To connect a callback to an event, use the connect method of the signal attribute. The exact signals available on each widget are mostly defined in the base classes, and are listed on the API page for each respective widget.

For example, to connect a callback to a LineEdit widget's changed event:

Widget APImagicgui decoratormagic_factory decorator
from magicgui import widgets\n\ntext = widgets.LineEdit(value='type something')\ntext.changed.connect(lambda val: print(f\"Text changed to: {val}\"))\n
from magicgui import magicgui\n\n@magicgui\ndef my_function(text: str):\n    ...\n\nmy_function.text.changed.connect(lambda val: print(f\"Text changed to: {val}\"))\n
from magicgui import magic_factory\n\ndef _on_init(widget):\n    widget.text.changed.connect(lambda val: print(f\"Text changed to: {val}\"))\n\n@magic_factory(widget_init=_on_init)\ndef my_function(text: str):\n    ...\n\nmy_widget = my_function()\n

It's all psygnal under the hood

magicgui uses psygnal for its event system. For greater detail on the connect method and its options, see the Usage section of psygnal's documentation, or the psygnal.SignalInstance.connect API reference.

Tip

Note that connect returns the callable that it was passed, so you can use it as a decorator if you prefer.

text = widgets.LineEdit(value='type something')\n\n# this works\ntext.changed.connect(lambda val: print(f\"Text changed to: {val}\"))\n\n# so does this\n@text.changed.connect\ndef on_text_changed(val):\n    print(f\"Text changed to: {val}\")\n
"},{"location":"installation/","title":"Installation","text":"

magicgui is a pure Python package, and can be installed with pip:

pip install magicgui\n

or with conda:

conda install -c conda-forge magicgui\n
"},{"location":"installation/#backends","title":"Backends","text":"

magicgui requires a backend to be installed in order to function, but it does not specify a particular backend by default. The following backends are available:

  • PyQt5: pip install magicgui[pyqt5]
  • PyQt6: pip install magicgui[pyqt6]
  • PySide2: pip install magicgui[pyside2]
  • PySide6: pip install magicgui[pyside6]
  • Jupyter Widgets: pip install magicgui[jupyter]

Important

Note not all widgets are necessarily implemented for all backends. Most widgets in the widget docs specify which backends are supported.

"},{"location":"installation/#extras","title":"Extras","text":"

The Image widget requires pillow. You may use the image extra:

pip install magicgui[image]\n

The magicgui.tqdm module requires tqdm. You may use the tqdm extra:

pip install magicgui[tqdm]\n

The QuantityEdit widget requires pint. You may use the quantity extra:

pip install magicgui[quantity]\n
"},{"location":"type_map/","title":"Type Hints to Widgets","text":"

One of the key offerings of magicgui is the ability to automatically generate Widgets from Python type hints. This page describes how type hints are mapped to Widgets, and how to customize that mapping.

"},{"location":"type_map/#default-type-mapping","title":"Default Type Mapping","text":"

By default, The following python Type Hint annotations are mapped to the corresponding Widget class, and parametrized with the corresponding kwargs (when applicable):

Type Hint Widget __init__ kwargs bool Slider int Slider float FloatSlider str LineEdit range RangeEdit slice SliceEdit list ListEdit tuple TupleEdit pathlib.Path FileEdit os.PathLike FileEdit Sequence[pathlib.Path] FileEdit {'mode': 'rm'} datetime.time TimeEdit datetime.timedelta TimeEdit datetime.date DateEdit datetime.datetime DateTimeEdit Literal['a', 'b'] ComboBox {'choices': ['a', 'b']} Set[Literal['a', 'b']] Select {'choices': ('a', 'b')} enum.Enum ComboBox {'choices': <enum 'Enum'>} magicgui.widgets.ProgressBar ProgressBar {'bind': <function TypeMap.match_type.<locals>.<lambda> at 0x123e8ec00>, 'visible': True} types.FunctionType FunctionGui {'function': ...} pint.Quantity QuantityEdit"},{"location":"type_map/#example","title":"Example","text":"

from magicgui import widgets\nimport pathlib\nimport os\nimport datetime\nfrom typing import Literal, Set, Sequence\nimport types\nimport pint\nimport enum\n\ntypes = [\n    bool, int, float, str, range, slice, list,\n    pathlib.Path, os.PathLike, Sequence[pathlib.Path],\n    datetime.time, datetime.timedelta, datetime.date, datetime.datetime,\n    Literal['a', 'b'], Set[Literal['a', 'b']], enum.Enum,\n    widgets.ProgressBar, pint.Quantity,\n]\n\nwdg = widgets.Container(\n    widgets=[\n        widgets.create_widget(annotation=t, label=str(t)) for t in types\n    ]\n)\nwdg.show()\n

"},{"location":"type_map/#customizing-widget-options-with-typingannotated","title":"Customizing Widget Options with typing.Annotated","text":"

Widget options and types may be embedded in the type hint itself using typing.Annotated.

Note

This is not the only way to customize the widget type or options in magicgui. Some functions (like magicgui.magicgui) also accept **param_options keyword arguments that map parameter names to dictionaries of widget options.

"},{"location":"type_map/#overriding-the-default-type","title":"Overriding the Default Type","text":"

To override the widget class used for a given object type, use the widget_type key in the Annotated kwargs. It can be either the string name of one of the built-in widgets, or any Widget subclass object.

Type Hint Widget __init__ kwargs Annotated[int, {'widget_type': 'Slider'}] Slider Annotated[float, {'widget_type': 'FloatSlider'}] FloatSlider"},{"location":"type_map/#overriding-the-default-options","title":"Overriding the Default Options","text":"

Any additional kwargs will be passed to the widget constructor (and must be valid for the corresponding widget type).

Type Hint Widget __init__ kwargs Annotated[int, {'step': 10, 'max': 50}] Slider {'step': 10, 'max': 50} Annotated[int, {'choices': [1, 2, 3]}] Slider {'choices': [1, 2, 3]}"},{"location":"type_map/#examples","title":"Examples","text":"

Create a widget using standard type map:

create_widgetmagicgui decoratorguiclass decorator
my_widget = widgets.create_widget(value=42, annotation=int)\n
from magicgui import magicgui\n\n@magicgui\ndef my_widget(x: int = 42):\n    return x\n
from magicgui.experimental import guiclass\n\n@guiclass\nclass MyObject:\n    x: int = 42\n\nobj = MyObject()\nmy_widget = obj.gui\n

Customize a widget using typing.Annotated:

create_widgetmagicgui decoratorguiclass decorator
from typing import Annotated\n\nInt10_50 = Annotated[int, (('widget_type', 'Slider'),('step', 10),('max', 50))]\nwdg2 = widgets.create_widget(value=42, annotation=Int10_50)\n
from magicgui import magicgui\nfrom typing import Annotated\n\nInt10_50 = Annotated[int, (('widget_type', 'Slider'),('step', 10),('max', 50))]\n\n@magicgui\ndef my_widget(x: Int10_50 = 42):\n    ...\n
from magicgui.experimental import guiclass\nfrom typing import Annotated\n\nInt10_50 = Annotated[int, (('widget_type', 'Slider'),('step', 10),('max', 50))]\n\n@guiclass\nclass MyObject:\n    x: Int10_50 = 42\n\nobj = MyObject()\nmy_widget = obj.gui\n

Note that you may also customize widget creation with kwargs to create_widget

from typing import Annotated\nfrom magicgui.widgets import Slider\n\noptions = {'step': 10, 'max': 50}\nwdg3 = widgets.create_widget(value=42, widget_type=Slider, options=options)\nwdg3.show()\n

... or to the magicgui decorator:

@magicgui(x={'widget_type': 'Slider', 'step': 10, 'max': 50})\ndef my_widget(x: int = 42):\n    ...\n\nmy_widget.show()\n

"},{"location":"type_map/#return-type-mapping","title":"Return Type Mapping","text":"

In some cases, magicgui may be able to create a widget for the return annotation of a function.

... more to come ...

"},{"location":"type_map/#postponed-annotations","title":"Postponed annotations","text":"

Using forward references and __future__.annotations with magicgui is possible, but requires some extra care. Read on for more details.

"},{"location":"type_map/#forward-references","title":"Forward References","text":"

When a type hint contains names that have not been defined yet, that definition may be expressed as a string literal, to be resolved later. This is called a Forward Reference (see PEP 484). This is useful when you want to use a type hint that refers to a type that has not yet been defined, or when you want to avoid importing a type that is only used in a type hint.

from typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from mymodule import MyType\n\ndef my_function(x: 'MyType') -> None:\n    ...\n
"},{"location":"type_map/#__future__annotations","title":"__future__.annotations","text":"

In Python 3.7, the __future__.annotations feature was introduced (PEP 563), which postpones the evaluation of type annotations. The effect of this is that no type annotations will be evaluated at definition time, and all type annotations will be treated as strings (regardless of whether they are enclosed in quotes or not).

from __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from mymodule import MyType\n\n# no longer necessary to use quotes around 'MyType'\ndef my_function(x: MyType) -> None:\n    ...\n

While this is a useful feature for developers, it does make it significantly more difficult to use those type annotations at runtime.

Magicgui does attempt to resolve forward references it encounters (see Resolving type hints at runtime for gory details), but this is an imperfect process, and may not always work.

"},{"location":"type_map/#if-you-must-use-postponed-annotations","title":"If You Must Use Postponed Annotations","text":"

As a general rule, if you must use forward references or __future__.annotations in a module that uses magicgui, you should:

  • don't use typing syntax that is not valid for ALL python versions you wish to support (e.g. str | int instead of Union[str, int] in python < 3.10), as these will raise an exception when magicgui attempts to evaluate them at runtime.
  • use fully qualified names for all type hints, as these will be easier for magicgui to resolve without user-supplied namespaces.

    from __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    import mymodule\n\n# this is easier for magicgui to resolve\ndef my_function(x: mymodule.MyType) -> None:\n    ...\n
"},{"location":"type_map/#registering-support-for-custom-types","title":"Registering Support for Custom Types","text":"

Any third-party library may use the magicgui.register_type function to register its types with magicgui. When a registered type is used as an annotation, the registered widget will be used.

"},{"location":"type_map/#known-third-party-support-for-magicgui","title":"Known Third-Party Support for magicgui","text":"

Hi developer!

Have a library that registers types with magicgui? Let us know and we'll add it to this list!

"},{"location":"type_map/#napari","title":"napari","text":"

napari has registered a number of its types to provide access to napari-specific objects using type annotations in magicgui. Details may be found in napari's documentation on using magicgui in napari.

"},{"location":"widgets/","title":"Widgets","text":"

Tip

If you're looking for an index of all available widgets, see the Widget Index.

All individual graphical elements in magicgui are \"widgets\", and all widgets are instances of magicgui.widgets.Widget. Widgets may be created directly:

from magicgui.widgets import LineEdit\n\nline_edit = LineEdit(value='hello!')\nline_edit.show()\n

Some widgets (such as magicgui.widgets.Container) are composite widgets that comprise other widgets:

from magicgui.widgets import LineEdit, SpinBox, Container\n\nline_edit = LineEdit(value='hello!')\nspin_box = SpinBox(value=400)\ncontainer = Container(widgets=[line_edit, spin_box])\ncontainer.show()\n

magicgui provides a way to automatically select a widget given a python value or type annotation using magicgui.widgets.create_widget. Here is an example that yields the same result as the one above:

from magicgui.widgets import create_widget\n\nx = 'hello!'\ny = 400\ncontainer = Container(widgets=[create_widget(i) for i in (x, y)])\ncontainer.show()\n

Tip

Because there are often multiple valid widget types for a given python object, you may sometimes wish to create widgets directly, or use the widget_type argument in create_widget()

"},{"location":"widgets/#the-widget-hierarchy","title":"The widget hierarchy","text":"
graph TB\n    A([Widget])-->B([ValueWidget])\n    A-->C([ContainerWidget])\n    B-->D([RangedWidget])\n    B-->E([ButtonWidget])\n    B-->F([CategoricalWidget])\n    C-->H([MainWindowWidget])\n    C-->G([FunctionGui])\n    D-->I([SliderWidget])\n    click A \"#widget\"\n    click B \"#valuewidget\"\n    click C \"#containerwidget\"\n    click D \"#rangedwidget\"\n    click E \"#buttonwidget\"\n    click F \"#categoricalwidget\"\n    click H \"#mainwindowwidget\"\n    click G \"#functiongui\"\n    click I \"#sliderwidget\"

Many widgets present similar types of information in different ways. magicgui tries to maintain a consistent API among all types of widgets that are designed to represent similar objects. The general class of widget you are working with will determine the properties and attributes it has.

Note

The categories shown below are sorted by their base class (such as ValueWidget and RangedWidget). The bases are not intended to be instantiated directly. Instead, you would create the widget type you wanted, such as LineEdit or SpinBox, respectively.

"},{"location":"widgets/#widget","title":"Widget","text":"

As mentioned above, all magicgui widgets derive from magicgui.widgets.Widget and have the following attributes (this list is not comprehensive, see the magicgui.widgets.Widget API):

Attribute Type Description name str The name or \"ID\" of this widget (such as a function parameter name to which this widget corresponds). annotation Any A type annotation for the value represented by the widget. label str A string to use for an associated Label widget (if this widget is being shown in a magicgui.widgets.Container widget, and container.labels is True). By default, name will be used. Note: name refers the name of the parameter, as might be used in a signature, whereas label is just the label for that widget in the GUI. tooltip str A tooltip to display when hovering over the widget. visible bool Whether the widget is visible."},{"location":"widgets/#valuewidget","title":"ValueWidget","text":"

In addition to the base Widget properties mentioned above, the following ValueWidgets track some value:

Widget Description Label A non-editable text display. LineEdit A one-line text editor. LiteralEvalLineEdit A one-line text editor that evaluates strings as python literals. Password A one-line text editor that obscures input. TextEdit A widget to edit and display both plain and rich text. FileEdit A LineEdit widget with a button that opens a FileDialog. RangeEdit A widget to represent a python range object, with start/stop/step. SliceEdit A widget to represent slice objects, with start/stop/step. DateTimeEdit A widget for editing dates and times. DateEdit A widget for editing dates. TimeEdit A widget for editing times. Table A widget to represent columnar or 2D data with headers. QuantityEdit A combined LineEdit and ComboBox to edit a pint.Quantity. Attribute Type Description value Any The current value of the widget. changed psygnal.SignalInstance A psygnal.SignalInstance that will emit an event when the value has changed. Connect callbacks to the change event using widget.changed.connect(callback) bind Any, optional A value or callback to bind this widget. If bound, whenever widget.value is accessed, the value provided here will be returned. The bound value can be a callable, in which case bound_value(self) will be returned (i.e. your callback must accept a single parameter, which is this widget instance.). see ValueWidget.bind for details.

Here is a demonstration of all these:

from magicgui import widgets\nimport datetime\n\nwdg_list = [\n    widgets.Label(value=\"label value\", label=\"Label:\"),\n    widgets.LineEdit(value=\"line edit value\", label=\"LineEdit:\"),\n    widgets.Password(value=\"super-secret!\", label=\"Password:\"),\n    widgets.TextEdit(value=\"text edit value...\", label=\"TextEdit:\"),\n    widgets.FileEdit(value=\"/home\", label=\"FileEdit:\"),\n    widgets.RangeEdit(value=range(0, 10, 2), label=\"RangeEdit:\"),\n    widgets.SliceEdit(value=slice(0, 10, 2), label=\"SliceEdit:\"),\n    widgets.DateTimeEdit(\n      value=datetime.datetime(1999, 12, 31, 11, 30), label=\"DateTimeEdit:\"\n    ),\n    widgets.DateEdit(value=datetime.date(81, 2, 18), label=\"DateEdit:\"),\n    widgets.TimeEdit(value=datetime.time(12, 20), label=\"TimeEdit:\"),\n    widgets.QuantityEdit(value='12 seconds', label=\"Quantity:\")\n]\ncontainer = widgets.Container(widgets=wdg_list)\ncontainer.max_height = 300\ncontainer.show()\n

"},{"location":"widgets/#rangedwidget","title":"RangedWidget","text":"

RangedWidgets are numerical ValueWidgets that have a restricted range of valid values, and a step size. RangedWidgets include:

Widget Description SpinBox A widget to edit an integer with clickable up/down arrows. FloatSpinBox A widget to edit a float with clickable up/down arrows.

In addition to all of the ValueWidget attributes, RangedWidget attributes include:

Attribute Type Description min float The minimum allowable value, by default 0 max float The maximum allowable value, by default 1000 step float The step size for incrementing the value, by default 1 range tuple of float A convenience attribute for getting/setting the (min, max) simultaneously

w1 = widgets.SpinBox(value=10, max=20, label='SpinBox:')\nw2 = widgets.FloatSpinBox(value=380, step=0.5, label='FloatSpinBox:')\ncontainer = widgets.Container(widgets=[w1, w2])\ncontainer.show()\n

"},{"location":"widgets/#sliderwidget","title":"SliderWidget","text":"

SliderWidgets are special RangedWidgets that additionally have an orientation, and a readout.

Widget Description Slider A slider widget to adjust an integer value within a range. FloatSlider A slider widget to adjust an integer value within a range. LogSlider A slider widget to adjust a numerical value logarithmically within a range. ProgressBar A progress bar widget.

In addition to all of the RangedWidget attributes, SliderWidget attributes include:

Attribute Type Description orientation str The orientation for the slider. Must be either 'horizontal' or 'vertical'. by default 'horizontal' readout bool Whether to show the value of the slider. By default, True.

w1 = widgets.Slider(value=10, max=25, label='Slider:')\nw2 = widgets.FloatSlider(value=10.5, max=18.5, label='FloatSlider:')\nw3 = widgets.ProgressBar(value=80, max=100, label='ProgressBar:')\ncontainer = widgets.Container(widgets=[w1, w2, w3])\ncontainer.show()\n

"},{"location":"widgets/#buttonwidget","title":"ButtonWidget","text":"

ButtonWidgets are boolean ValueWidgets that also have some text associated with them.

Widget Description PushButton A clickable command button. CheckBox A checkbox with a text label.

In addition to all of the ValueWidget attributes, ButtonWidget attributes include:

Attribute Type Description text str The text to display on the button. If not provided, will use name.

w1 = widgets.PushButton(value=True, text='PushButton Text')\nw2 = widgets.CheckBox(value=False, text='CheckBox Text')\ncontainer = widgets.Container(widgets=[w1, w2])\ncontainer.show()\n

"},{"location":"widgets/#categoricalwidget","title":"CategoricalWidget","text":"

CategoricalWidget are ValueWidgets that provide a set of valid choices. They can be created from:

  • an enum.Enum
  • an iterable of objects (or an iterable of 2-tuples (name, object))
  • a callable that returns an enum.Enum or an iterable
  • a typing.Literal annotation.
Widget Description ComboBox A dropdown menu, allowing selection between multiple choices. RadioButtons An exclusive group of radio buttons, providing a choice from multiple choices. Select A list of options, allowing selection between multiple choices.

In addition to all of the ValueWidget attributes, CategoricalWidget attributes include:

Attribute Type Description choices Enum, Iterable, or Callable Available choices displayed in the widget. value Any In the case of a CategoricalWidget the value is the data of the currently selected choice (see also: current_choice below). current_choice str The name associated with the current choice. For instance, if choices was provided as choices=[('one', 1), ('two', 2)], then an example value would be 1, and an example current_choice would be 'one'.

choices = ['one', 'two', 'three']\nw1 = widgets.ComboBox(choices=choices, value='two', label='ComboBox:')\nw2 = widgets.RadioButtons(choices=choices, label='RadioButtons:')\nw3 = widgets.Select(choices=choices, label='Select:')\ncontainer = widgets.Container(widgets=[w1, w2, w3])\ncontainer.max_height = 220\ncontainer.show()\n

"},{"location":"widgets/#containerwidget","title":"ContainerWidget","text":"

A ContainerWidget is a list-like Widget that can contain other widgets. Containers allow you to build more complex widgets from sub-widgets. A notable example of a Container is magicgui.widgets.FunctionGui) (the product of the @magicgui decorator).

Widget Description Container A Widget to contain other widgets. MainWindow A Widget to contain other widgets, includes a menu bar. FunctionGui Wrapper for a container of widgets representing a callable object. Attribute Type Description layout str The layout for the container. Must be either 'horizontal' or 'vertical'. widgets Sequence[Widget] The widgets that the container contains. labels bool Whether each widget should be shown with a corresponding Label widget to the left. Note: the text for each widget defaults to widget.name, but can be overridden by setting widget.label.

Container implements the full collections.abc.MutableSequence interface. You can add and remove widgets from it just as you would add or remove items from a list.

from magicgui.widgets import Container, Slider, FloatSlider, ProgressBar\n\ncontainer = widgets.Container()\ncontainer.append(widgets.LineEdit(value='Mookie', label='Your Name:'))\ncontainer.append(widgets.FloatSlider(value=10.5, label='FloatSlider:'))\ncontainer.show()\n

"},{"location":"widgets/#mainwindowwidget","title":"MainWindowWidget","text":"

A MainWindowWidget is a special type of ContainerWidget that also includes a menu bar.

"},{"location":"widgets/#functiongui","title":"FunctionGui","text":"

A FunctionGui is a special type of ContainerWidget that is created from a function. It is the product of the @magicgui decorator. It is a container that contains a widget for each of the parameters in the function. See magicgui.widgets.FunctionGui for details.

"},{"location":"widgets/#magicgui","title":"@magicgui","text":"

It's worth noting that @magicgui and @magic_factory decorators are just conveniences that build a special type of Container widget (a FunctionGui), with a widget representing each of the parameters in a decorated function.

from magicgui import magicgui\n\n@magicgui\ndef my_function(x='hello', y=400): ...\n\nmy_function.show()\n

In terms of simply building widgets, the following code performs a similar task to @magicgui.

from inspect import signature\n\ndef my_function(x='hello', y=400):\n  ...\n\nparams = signature(my_function).parameters.values()\ncontainer = Container(\n    widgets=[create_widget(p.default, name=p.name) for p in params]\n)\ncontainer.show()\n

Tip

Note that the FunctionGui widget produced by @magicgui is actually a callable object that behaves very much like the original function, except that it will use current values from the GUI as default parameters when calling the function.

"},{"location":"api/app/","title":"Application","text":""},{"location":"api/app/#magicgui.application.Application","title":"magicgui.application.Application","text":"

Magicgui Application, wrapping a native BaseApplicationBackend implementation.

"},{"location":"api/app/#magicgui.application.Application.backend_module","title":"backend_module: ModuleType property","text":"

Return module object that defines the backend.

"},{"location":"api/app/#magicgui.application.Application.backend_name","title":"backend_name: str property","text":"

Return name of the GUI backend that this app wraps.

"},{"location":"api/app/#magicgui.application.Application.native","title":"native: Any property","text":"

Return the native GUI application instance.

"},{"location":"api/app/#magicgui.application.Application.__enter__","title":"__enter__() -> Application","text":"

Context manager to start this application.

"},{"location":"api/app/#magicgui.application.Application.__exit__","title":"__exit__(*exc_details: Any) -> None","text":"

Exit context manager for this application.

"},{"location":"api/app/#magicgui.application.Application.__repr__","title":"__repr__() -> str","text":"

Return repr for this instance.

"},{"location":"api/app/#magicgui.application.Application.create","title":"create() -> None","text":"

Create the native application.

"},{"location":"api/app/#magicgui.application.Application.get_obj","title":"get_obj(name: str) -> Any","text":"

Get the backend object for the given name (such as a widget).

"},{"location":"api/app/#magicgui.application.Application.process_events","title":"process_events() -> None","text":"

Process all pending GUI events.

"},{"location":"api/app/#magicgui.application.Application.quit","title":"quit() -> None","text":"

Quit the native GUI event loop.

"},{"location":"api/app/#magicgui.application.Application.run","title":"run() -> None","text":"

Enter the native GUI event loop.

"},{"location":"api/app/#magicgui.application.Application.start_timer","title":"start_timer(interval: int = 1000, on_timeout: Callable[[], None] | None = None, single_shot: bool = False) -> None","text":"

Start a timer with a given interval, optional callback, and single_shot.

"},{"location":"api/app/#magicgui.application.use_app","title":"magicgui.application.use_app(app: AppRef | None = None) -> Application","text":"

Get/create the default Application object. See _use_app docstring.

"},{"location":"api/experimental/","title":"magicgui.experimental","text":"

Experimental

This module contains experimental features that are not yet ready for prime time. All of the features in this module are subject to change without warning or deprecation.

"},{"location":"api/experimental/#magicgui.experimental.guiclass","title":"magicgui.experimental.guiclass(cls: T | None = None, *, gui_name: str = 'gui', events_namespace: str = 'events', follow_changes: bool = True, **dataclass_kwargs: Any) -> T | Callable[[T], T]","text":"

Turn class into a dataclass with a property (gui_name) that returns a gui.

This decorator is similar to dataclasses.dataclass, but it will also add an events attribute to the class that is an instance of psygnal.SignalGroup (with a signal for each field in the dataclass; see https://psygnal.readthedocs.io/en/latest/dataclasses/ for details), and a gui property that returns a magicgui widget, bound to the values of the dataclass instance.

Note

This decorator is compatible with dataclasses using slots=True, however, there is a potential for a memory leak that the user should be aware of. If you create a guiclass instance, and then store a reference to its gui, and then delete the instance, the gui will still be bound to the instance, preventing it from being garbage collected. To avoid this, you can call unbind_gui_from_instance(gui, instance) before deleting the instance.

Parameters:

  • cls (type, default: None ) \u2013

    The class to turn into a dataclass.

  • gui_name (str, default: 'gui' ) \u2013

    The name of the property that will return a magicgui widget, by default \"gui\"

  • events_namespace (str, default: 'events' ) \u2013

    The name of the attribute that will be added to the class, by default \"events\". This attribute will be an instance of psygnal.SignalGroup that will be used to connect events to the class.

  • follow_changes (bool, default: True ) \u2013

    If True (default), changes to the dataclass instance will be reflected in the gui, and changes to the gui will be reflected in the dataclass instance.

  • dataclass_kwargs (dict, default: {} ) \u2013

    Additional keyword arguments to pass to dataclasses.dataclass.

Returns:

  • type \u2013

    The dataclass.

Examples:

>>> @guiclass\n... class MyData:\n...     x: int = 0\n...     y: str = \"hi\"\n...\n...     @button\n...     def reset(self):\n...         self.x = 0\n...         self.y = \"hi\"\n>>> data = MyData()\n>>> data.gui.show()\n
"},{"location":"api/experimental/#magicgui.experimental.button","title":"magicgui.experimental.button(func: F | None = None, **button_kwargs: Any) -> F | Callable[[F], F]","text":"

Add a method as a button to a guiclass, which calls the decorated method.

Parameters:

  • func (callable, default: None ) \u2013

    The method to decorate. If None, returns a decorator that can be applied to a method.

  • button_kwargs (dict, default: {} ) \u2013

    Additional keyword arguments to pass to magicgui.widgets.PushButton.

"},{"location":"api/experimental/#magicgui.experimental.is_guiclass","title":"magicgui.experimental.is_guiclass(obj: object) -> TypeGuard[GuiClassProtocol]","text":"

Return True if obj is a guiclass or an instance of a guiclass.

"},{"location":"api/magic_factory/","title":"magicgui.magic_factory","text":""},{"location":"api/magic_factory/#magicgui.magic_factory","title":"magicgui.magic_factory = TypeMap.global_instance().magic_factory module-attribute","text":""},{"location":"api/magic_factory/#magicgui.type_map._magicgui.MagicFactory","title":"magicgui.type_map._magicgui.MagicFactory","text":"

Bases: partial, Generic[_FGuiVar]

Factory function that returns a FunctionGui instance.

While this can be used directly, (see example below) the preferred usage is via the magicgui.magic_factory decorator.

Examples:

>>> def func(x: int, y: str):\n...     pass\n>>> factory = MagicFactory(function=func, labels=False)\n>>> # factory accepts all the same arguments as magicgui()\n>>> widget1 = factory(call_button=True)\n>>> # can also override magic_kwargs that were provided when creating the factory\n>>> widget2 = factory(auto_call=True, labels=True)\n
"},{"location":"api/magic_factory/#magicgui.type_map._magicgui.MagicFactory.__name__","title":"__name__: str property","text":"

Pass function name.

"},{"location":"api/magic_factory/#magicgui.type_map._magicgui.MagicFactory.__call__","title":"__call__(*args, **kwargs)","text":"

Call the wrapped _magicgui and return a FunctionGui.

"},{"location":"api/magic_factory/#magicgui.type_map._magicgui.MagicFactory.__getattr__","title":"__getattr__(name)","text":"

Allow accessing FunctionGui attributes without mypy error.

"},{"location":"api/magic_factory/#magicgui.type_map._magicgui.MagicFactory.__new__","title":"__new__(function, *args, magic_class=FunctionGui, widget_init=None, type_map=None, **keywords)","text":"

Create new MagicFactory.

"},{"location":"api/magic_factory/#magicgui.type_map._magicgui.MagicFactory.__repr__","title":"__repr__()","text":"

Return string repr.

"},{"location":"api/magicgui/","title":"magicgui.magicgui","text":""},{"location":"api/magicgui/#magicgui.magicgui","title":"magicgui.magicgui = TypeMap.global_instance().magicgui module-attribute","text":""},{"location":"api/migration/","title":"migration guide","text":""},{"location":"api/migration/#v030-migration-guide","title":"v0.3.0 migration guide","text":"

October, 2021

Version 0.3.0 of magicgui introduced some changes to the events and callbacks API. See https://github.com/pyapp-kit/magicgui/pull/253 for details

"},{"location":"api/migration/#callbacks-now-receive-the-value-directly-instead-of-an-event-object","title":"Callbacks now receive the value directly, instead of an Event object","text":"

magicgui 0.3.0 is now using psygnal as its event/callback handler.

Callbacks connected to widget.changed (and other event emitters) may now receive the value(s) directly, instead of an event object:

\ud83d\udc4e Old Method (< v0.3.0)
@widget.changed.connect\ndef my_callback(event):\n    # event was an `Event` object with a `value` attribute\n    new_value = event.value\n

Existing code using callbacks with a single positional argument will continue to receive a single Event object (and a warning will be shown, until v0.4.0 where it will become an error).

To silence the warning and opt in to the new pattern of receiving value directly, you can do one of two things:

  1. type hint your single positional argument as anything other than magicgui.events.Event
  2. provide a callback that takes no arguments
\ud83d\udc4d New Method (>= v0.3.0)
@widget.changed.connect\ndef my_callback(new_value: int):\n    ...  # use new_value directly\n\n# or, if you don't need to use new_value\n@widget.changed.connect\ndef my_callback():\n    # something that didn't need the value\n    ...\n
"},{"location":"api/migration/#event-emitters-take-no-keyword-arguments","title":"Event emitters take no keyword arguments","text":"

For the few packages who were manually emitting change events, you should no longer provide the value= keyword when emitting.

\ud83d\udc4e Old Method (< v0.3.0)
widget.changed(value='whatever')\n
\ud83d\udc4d New Method (>= v0.3.0)
widget.changed.emit('whatever')\n# OR (if you prefer the direct __call__ syntax)\nwidget.changed('whatever')\n
"},{"location":"api/migration/#v020-migration-guide","title":"v0.2.0 migration guide","text":"

December, 2020

Version 0.2.0 of magicgui was a complete rewrite that introduced a couple breaking API changes

"},{"location":"api/migration/#gui-attribute-removed","title":".Gui() attribute removed","text":"

Before v0.2.0, the magicgui.magicgui decorator added a Gui attribute to the decorated function that was to be called to instantiate a widget. In v0.2.0 the object returned from the magicgui.magicgui decorator is already an instantiated magicgui.widgets.Widget.

\ud83d\udc4e Old Method (< v0.2.0)
from magicgui import magicgui, event_loop\n\n@magicgui\ndef function(x, y):\n    ...\n\nwith event_loop():\n    gui = function.Gui(show=True)\n
\ud83d\udc4d New Method (>= v0.2.0)
from magicgui import magicgui\n\n@magicgui\ndef function(x, y):\n    ...\n\nfunction.show(run=True)\n
"},{"location":"api/migration/#new-base-widget-type","title":"New base widget type","text":"

Before v0.2.0, the Gui() object returned by the magicgui.magicgui decorator was a MagicGuiBase widget class, which in turn was a direct subclass of a backend widget, such as a QtWidgets.QWidget. In v0.2.0, all widgets derive from [magicgui.widgets.Widget``][magicgui.widgets.Widget], and the *backend* is available atwidget.native. If you are incorporating magicgui widgets into a larger Qt-based GUI, please note that you will want to usewidget.nativeinstead ofwidget`

from magicgui import magicgui, use_app\n\nuse_app('qt')\n\n@magicgui\ndef function(x, y):\n    ...\n
>>> print(type(function))\n<class 'magicgui.widgets.FunctionGui'>\n>>> print(type(function.native))\n<class 'PyQt5.QtWidgets.QWidget'>\n
"},{"location":"api/migration/#starting-the-application","title":"Starting the application","text":"

It is now easier to show a widget and start an application by calling widget.show(run=True). Calling show(run=True) will immediately block execution of your script and show the widget. If you wanted to (for instance) show multiple widgets next to each other, then you would still want to use the event_loop context manager:

from magicgui import magicgui, event_loop\n\n@magicgui\ndef function_a(x=1, y=3):\n    ...\n\n@magicgui\ndef function_b(z='asdf'):\n    ...\n\nwith event_loop():\n    function_a.show()\n    function_b.show()\n# both widgets will show (though b may be on top of a)\n
"},{"location":"api/migration/#getting-and-setting-values","title":"Getting and setting values","text":"

To get or set the value of a widget programmatically, you no longer set the corresponding widget attribute directly, but rather use the widget.value attribute:

Old Method \ud83d\udc4e

gui.x used to be a descriptor object to get/set the value, but the actual underlying widget was at gui.x_widget

gui = function.Gui()\ngui.x = 10\n

New Method \ud83d\udc4d

now function.x IS the widget, and you set its value with function.x.value

function.x.value = 10\n
"},{"location":"api/migration/#connecting-callbacks-to-events","title":"Connecting callbacks to events","text":"

When binding callbacks to change events, you no longer connect to gui.<name>_changed, you now connect to function.<name>.changed:

\ud83d\udc4e Old Method (< v0.2.0)
gui = function.Gui()\ngui.x_changed.connect(my_callback)\n
\ud83d\udc4d New Method (>= v0.2.0)
function.x.changed.connect(my_callback)\n
"},{"location":"api/migration/#renamed","title":"Renamed","text":"
  • Widget.refresh_choices has been renamed to Widget.reset_choices.

  • @magicgui(result=True) has been renamed to @magicgui(result_widget=True)

"},{"location":"api/protocols/","title":"Backend Protocols","text":"

Advanced Topic

Most users of magicgui will not need to worry about this section.

These Protocol classes declare the interface that backend adapters must implement in order to be used by magicgui. All magicgui Widget objects compose a backend widget implementing one of these protocols, and control it using the methods defined herein.

magicgui developers may be interested in this page, but end-users needn't worry about it.

"},{"location":"api/protocols/#summary","title":"Summary","text":"Widget Description WidgetProtocol Base Widget Protocol: specifies methods that all widgets must provide. ValueWidgetProtocol Widget that has a current value, with getter/setter and on_change callback. ButtonWidgetProtocol The \"value\" in a ButtonWidget is the current (checked) state. TableWidgetProtocol ValueWidget subclass intended for 2D tabular data, with row & column headers. RangedWidgetProtocol Value widget that supports numbers within a provided min/max range. CategoricalWidgetProtocol Categorical widget, that has a set of valid choices, and a current value. SliderWidgetProtocol Protocol for implementing a slider widget. ContainerProtocol Widget that can contain other widgets. BaseApplicationBackend Backend Application object. DialogProtocol Protocol for modal (blocking) containers. SupportsChoices Widget that has a set of valid choices. SupportsOrientation Widget that can be reoriented. SupportsText Widget that have text (in addition to value)... like buttons. SupportsReadOnly Widget that can be read_only."},{"location":"api/protocols/#protocol-inheritance","title":"Protocol Inheritance","text":"

The visual hierarchy of protocols looks like this:

graph LR\n    A([WidgetProtocol])-->B([ValueWidgetProtocol])\n    A-->C([ContainerProtocol])\n    M([SupportsText])-->E\n    B-->E([ButtonWidgetProtocol])\n    B-->D([RangedWidgetProtocol])\n    B-->F([CategoricalWidgetProtocol])\n    D-->I([SliderWidgetProtocol])\n    B-->J([TableWidgetProtocol])\n    K([SupportsReadOnly])-->J([TableWidgetProtocol])\n    L([SupportsChoices])-->F\n    N([SupportsOrientation])-->C\n    N-->I\n    C-->O([DialogProtocol])\n    C-->P([MainWindowProtocol])\n\n    click A \"#magicgui.widgets.protocols.WidgetProtocol\"\n    click B \"#magicgui.widgets.protocols.ValueWidgetProtocol\"\n    click C \"#magicgui.widgets.protocols.ContainerProtocol\"\n    click D \"#magicgui.widgets.protocols.RangedWidgetProtocol\"\n    click E \"#magicgui.widgets.protocols.ButtonWidgetProtocol\"\n    click F \"#magicgui.widgets.protocols.CategoricalWidgetProtocol\"\n    click I \"#magicgui.widgets.protocols.SliderWidgetProtocol\"\n    click J \"#magicgui.widgets.protocols.TableWidgetProtocol\"\n    click K \"#magicgui.widgets.protocols.SupportsReadOnly\"\n    click L \"#magicgui.widgets.protocols.SupportsChoices\"\n    click M \"#magicgui.widgets.protocols.SupportsText\"\n    click N \"#magicgui.widgets.protocols.SupportsOrientation\"\n    click O \"#magicgui.widgets.protocols.DialogProtocol\"\n    click P \"#magicgui.widgets.protocols.MainWindowProtocol\"
"},{"location":"api/protocols/#widget-protocols","title":"Widget Protocols","text":""},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol","title":"magicgui.widgets.protocols.WidgetProtocol","text":"

Bases: Protocol

Base Widget Protocol: specifies methods that all widgets must provide.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_bind_parent_change_callback","title":"_mgui_bind_parent_change_callback(callback: Callable[[Any], None]) -> None abstractmethod","text":"

Bind callback to parent change event.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_close_widget","title":"_mgui_close_widget() -> None abstractmethod","text":"

Close widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_enabled","title":"_mgui_get_enabled() -> bool abstractmethod","text":"

Get the enabled state of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_height","title":"_mgui_get_height() -> int abstractmethod","text":"

Get the height of the widget.

The intention is to get the height of the widget after it is shown, for the purpose of unifying widget height in a layout. Backends may do what they need to accomplish this. For example, Qt can use sizeHint().height(), since height() may return something large if the widget has not yet been painted on screen.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_max_height","title":"_mgui_get_max_height() -> int abstractmethod","text":"

Get the maximum height of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_max_width","title":"_mgui_get_max_width() -> int abstractmethod","text":"

Get the maximum width of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_min_height","title":"_mgui_get_min_height() -> int abstractmethod","text":"

Get the minimum height of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_min_width","title":"_mgui_get_min_width() -> int abstractmethod","text":"

Get the minimum width of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_native_widget","title":"_mgui_get_native_widget() -> Any abstractmethod","text":"

Return the native backend widget instance.

This is generally the widget that has the layout.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_parent","title":"_mgui_get_parent() -> Widget abstractmethod","text":"

Return the parent widget of this widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_root_native_widget","title":"_mgui_get_root_native_widget() -> Any abstractmethod","text":"

Return the root native backend widget.

In most cases, this is the same as _mgui_get_native_widget. However, in cases where the native widget is in a scroll layout, this might be different.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_tooltip","title":"_mgui_get_tooltip() -> str abstractmethod","text":"

Get the tooltip for this widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_visible","title":"_mgui_get_visible() -> bool abstractmethod","text":"

Get widget visibility.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_get_width","title":"_mgui_get_width() -> int abstractmethod","text":"

Get the width of the widget.

The intention is to get the width of the widget after it is shown, for the purpose of unifying widget width in a layout. Backends may do what they need to accomplish this. For example, Qt can use sizeHint().width(), since width() may return something large if the widget has not yet been painted on screen.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_render","title":"_mgui_render() -> np.ndarray abstractmethod","text":"

Return an RGBA (MxNx4) numpy array bitmap of the rendered widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_enabled","title":"_mgui_set_enabled(enabled: bool) -> None abstractmethod","text":"

Set the enabled state of the widget to enabled.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_height","title":"_mgui_set_height(value: int) -> None abstractmethod","text":"

Set the height of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_max_height","title":"_mgui_set_max_height(value: int) -> None abstractmethod","text":"

Set the maximum height of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_max_width","title":"_mgui_set_max_width(value: int) -> None abstractmethod","text":"

Set the maximum width of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_min_height","title":"_mgui_set_min_height(value: int) -> None abstractmethod","text":"

Set the minimum height of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_min_width","title":"_mgui_set_min_width(value: int) -> None abstractmethod","text":"

Set the minimum width of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_parent","title":"_mgui_set_parent(widget: Widget) -> None abstractmethod","text":"

Set the parent widget of this widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_tooltip","title":"_mgui_set_tooltip(value: str | None) -> None abstractmethod","text":"

Set a tooltip for this widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_visible","title":"_mgui_set_visible(value: bool) -> None abstractmethod","text":"

Set widget visibility.

"},{"location":"api/protocols/#magicgui.widgets.protocols.WidgetProtocol._mgui_set_width","title":"_mgui_set_width(value: int) -> None abstractmethod","text":"

Set the width of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ValueWidgetProtocol","title":"magicgui.widgets.protocols.ValueWidgetProtocol","text":"

Bases: WidgetProtocol, Protocol

Widget that has a current value, with getter/setter and on_change callback.

It is worth noting that the widget is the thing that has a value. Magicgui does not maintain & synchronize an independent model.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ValueWidgetProtocol._mgui_bind_change_callback","title":"_mgui_bind_change_callback(callback: Callable[[Any], Any]) -> None abstractmethod","text":"

Bind callback to value change event.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ValueWidgetProtocol._mgui_get_value","title":"_mgui_get_value() -> Any abstractmethod","text":"

Get current value of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ValueWidgetProtocol._mgui_set_value","title":"_mgui_set_value(value: Any) -> None abstractmethod","text":"

Set current value of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ButtonWidgetProtocol","title":"magicgui.widgets.protocols.ButtonWidgetProtocol","text":"

Bases: ValueWidgetProtocol, SupportsText, SupportsIcon, Protocol

The \"value\" in a ButtonWidget is the current (checked) state.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol","title":"magicgui.widgets.protocols.TableWidgetProtocol","text":"

Bases: ValueWidgetProtocol, SupportsReadOnly, Protocol

ValueWidget subclass intended for 2D tabular data, with row & column headers.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_bind_change_callback","title":"_mgui_bind_change_callback(callback: Callable[[Any], Any]) -> None abstractmethod","text":"

Bind callback to value change event.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_bind_column_headers_change_callback","title":"_mgui_bind_column_headers_change_callback(callback: Callable[[Any], None]) -> None abstractmethod","text":"

Bind callback to column headers change event.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_bind_row_headers_change_callback","title":"_mgui_bind_row_headers_change_callback(callback: Callable[[Any], None]) -> None abstractmethod","text":"

Bind callback to row headers change event.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_get_cell","title":"_mgui_get_cell(row: int, col: int) -> Any abstractmethod","text":"

Get current value of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_get_column_count","title":"_mgui_get_column_count() -> int abstractmethod","text":"

Get the number of columns in the table.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_get_column_headers","title":"_mgui_get_column_headers() -> tuple abstractmethod","text":"

Get current column headers of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_get_row_count","title":"_mgui_get_row_count() -> int abstractmethod","text":"

Get the number of rows in the table.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_get_row_headers","title":"_mgui_get_row_headers() -> tuple abstractmethod","text":"

Get current row headers of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_remove_column","title":"_mgui_remove_column(column: int) -> None abstractmethod","text":"

Remove column at index column.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_remove_row","title":"_mgui_remove_row(row: int) -> None abstractmethod","text":"

Remove row at index row.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_set_cell","title":"_mgui_set_cell(row: int, col: int, value: Any) -> None abstractmethod","text":"

Set current value of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_set_column_count","title":"_mgui_set_column_count(ncols: int) -> None abstractmethod","text":"

Set the number of columns in the table. (Create/delete as needed).

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_set_column_headers","title":"_mgui_set_column_headers(headers: Sequence) -> None abstractmethod","text":"

Set current column headers of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_set_row_count","title":"_mgui_set_row_count(nrows: int) -> None abstractmethod","text":"

Set the number of rows in the table. (Create/delete as needed).

"},{"location":"api/protocols/#magicgui.widgets.protocols.TableWidgetProtocol._mgui_set_row_headers","title":"_mgui_set_row_headers(headers: Sequence) -> None abstractmethod","text":"

Set current row headers of the widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol","title":"magicgui.widgets.protocols.RangedWidgetProtocol","text":"

Bases: ValueWidgetProtocol, Protocol

Value widget that supports numbers within a provided min/max range.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_get_adaptive_step","title":"_mgui_get_adaptive_step() -> bool abstractmethod","text":"

Get adaptive step status.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_get_max","title":"_mgui_get_max() -> float abstractmethod","text":"

Get the maximum possible value.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_get_min","title":"_mgui_get_min() -> float abstractmethod","text":"

Get the minimum possible value.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_get_step","title":"_mgui_get_step() -> float abstractmethod","text":"

Get the step size.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_set_adaptive_step","title":"_mgui_set_adaptive_step(value: bool) -> None abstractmethod","text":"

Set adaptive step status.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_set_max","title":"_mgui_set_max(value: float) -> None abstractmethod","text":"

Set the maximum possible value.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_set_min","title":"_mgui_set_min(value: float) -> None abstractmethod","text":"

Set the minimum possible value.

"},{"location":"api/protocols/#magicgui.widgets.protocols.RangedWidgetProtocol._mgui_set_step","title":"_mgui_set_step(value: float) -> None abstractmethod","text":"

Set the step size.

"},{"location":"api/protocols/#magicgui.widgets.protocols.CategoricalWidgetProtocol","title":"magicgui.widgets.protocols.CategoricalWidgetProtocol","text":"

Bases: ValueWidgetProtocol, SupportsChoices, Protocol

Categorical widget, that has a set of valid choices, and a current value.

It adds no additional methods.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SliderWidgetProtocol","title":"magicgui.widgets.protocols.SliderWidgetProtocol","text":"

Bases: RangedWidgetProtocol, SupportsOrientation, Protocol

Protocol for implementing a slider widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SliderWidgetProtocol._mgui_get_tracking","title":"_mgui_get_tracking() -> bool","text":"

If tracking is False, changed is only emitted when released.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SliderWidgetProtocol._mgui_set_readout_visibility","title":"_mgui_set_readout_visibility(visible: bool) -> None","text":"

Set visibility of readout widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SliderWidgetProtocol._mgui_set_tracking","title":"_mgui_set_tracking(tracking: bool) -> None","text":"

If tracking is False, changed is only emitted when released.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ContainerProtocol","title":"magicgui.widgets.protocols.ContainerProtocol","text":"

Bases: WidgetProtocol, SupportsOrientation, Protocol

Widget that can contain other widgets.

This generally manages a backend Layout.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ContainerProtocol._mgui_get_margins","title":"_mgui_get_margins() -> tuple[int, int, int, int] abstractmethod","text":"

Get the margins of the container.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ContainerProtocol._mgui_insert_widget","title":"_mgui_insert_widget(position: int, widget: Widget) -> None abstractmethod","text":"

Insert widget at the given position in the layout.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ContainerProtocol._mgui_remove_widget","title":"_mgui_remove_widget(widget: Widget) -> None abstractmethod","text":"

Remove the specified widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.ContainerProtocol._mgui_set_margins","title":"_mgui_set_margins(margins: tuple[int, int, int, int]) -> None abstractmethod","text":"

Set the margins of the container.

"},{"location":"api/protocols/#magicgui.widgets.protocols.DialogProtocol","title":"magicgui.widgets.protocols.DialogProtocol","text":"

Bases: ContainerProtocol, Protocol

Protocol for modal (blocking) containers.

"},{"location":"api/protocols/#magicgui.widgets.protocols.DialogProtocol._mgui_exec","title":"_mgui_exec() -> None abstractmethod","text":"

Show the dialog and block.

"},{"location":"api/protocols/#magicgui.widgets.protocols.MainWindowProtocol","title":"magicgui.widgets.protocols.MainWindowProtocol","text":"

Bases: ContainerProtocol, Protocol

Application main widget.

"},{"location":"api/protocols/#magicgui.widgets.protocols.MainWindowProtocol._mgui_create_menu_item","title":"_mgui_create_menu_item(menu_name: str, action_name: str, callback: Callable | None = None, shortcut: str | None = None) -> None abstractmethod","text":"

Create a new menu item.

Parameters:

  • menu_name (str) \u2013

    The name of the menu to add the item to.

  • action_name (str) \u2013

    The name of the action to add.

  • callback (Callable | None, default: None ) \u2013

    A callback to be called when the action is triggered, by default None.

  • shortcut (str | None, default: None ) \u2013

    A keyboard shortcut for the action, by default None.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices","title":"magicgui.widgets.protocols.SupportsChoices","text":"

Bases: Protocol

Widget that has a set of valid choices.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_del_choice","title":"_mgui_del_choice(choice_name: str) -> None abstractmethod","text":"

Delete the provided choice_name and associated data.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_get_choice","title":"_mgui_get_choice(choice_name: str) -> Any abstractmethod","text":"

Get data for a single choice.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_get_choices","title":"_mgui_get_choices() -> tuple[tuple[str, Any], ...] abstractmethod","text":"

Get available choices.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_get_count","title":"_mgui_get_count() -> int abstractmethod","text":"

Return number of choices.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_get_current_choice","title":"_mgui_get_current_choice() -> str abstractmethod","text":"

Return the text of the currently selected choice.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_set_choice","title":"_mgui_set_choice(choice_name: str, data: Any) -> None abstractmethod","text":"

Set data for choice_name, or add a new item if choice_name doesn't exist.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsChoices._mgui_set_choices","title":"_mgui_set_choices(choices: Iterable[tuple[str, Any]]) -> None abstractmethod","text":"

Set available choices.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsOrientation","title":"magicgui.widgets.protocols.SupportsOrientation","text":"

Bases: Protocol

Widget that can be reoriented.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsOrientation._mgui_get_orientation","title":"_mgui_get_orientation() -> str abstractmethod","text":"

Get orientation, return either 'horizontal' or 'vertical'.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsOrientation._mgui_set_orientation","title":"_mgui_set_orientation(value: str) -> None abstractmethod","text":"

Set orientation, value will be 'horizontal' or 'vertical'.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsText","title":"magicgui.widgets.protocols.SupportsText","text":"

Bases: Protocol

Widget that have text (in addition to value)... like buttons.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsText._mgui_get_text","title":"_mgui_get_text() -> str abstractmethod","text":"

Get text.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsText._mgui_set_text","title":"_mgui_set_text(value: str) -> None abstractmethod","text":"

Set text.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsReadOnly","title":"magicgui.widgets.protocols.SupportsReadOnly","text":"

Bases: Protocol

Widget that can be read_only.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsReadOnly._mgui_get_read_only","title":"_mgui_get_read_only() -> bool abstractmethod","text":"

Get read_only status.

"},{"location":"api/protocols/#magicgui.widgets.protocols.SupportsReadOnly._mgui_set_read_only","title":"_mgui_set_read_only(value: bool) -> None abstractmethod","text":"

Set read_only.

"},{"location":"api/protocols/#application-protocol","title":"Application Protocol","text":""},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend","title":"magicgui.widgets.protocols.BaseApplicationBackend","text":"

Bases: ABC

Backend Application object.

Abstract class that provides an interface between backends and Application. Each backend must implement a subclass of BaseApplicationBackend, and implement all of its _mgui_xxx methods.

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_get_backend_name","title":"_mgui_get_backend_name() -> str abstractmethod","text":"

Return the name of the backend.

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_get_native_app","title":"_mgui_get_native_app() -> Any abstractmethod","text":"

Return the native GUI application instance.

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_process_events","title":"_mgui_process_events() -> None abstractmethod","text":"

Process all pending GUI events.

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_quit","title":"_mgui_quit() -> None abstractmethod","text":"

Quit the native GUI event loop.

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_run","title":"_mgui_run() -> None abstractmethod","text":"

Start the application.

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_start_timer","title":"_mgui_start_timer(interval: int = 0, on_timeout: Callable[[], None] | None = None, single: bool = False) -> None abstractmethod","text":"

Create and start a timer.

Parameters:

  • interval (int, default: 0 ) \u2013

    Interval between timeouts, by default 0

  • on_timeout (Optional[Callable[[], None]], default: None ) \u2013

    Function to call when timer finishes, by default None

  • single (bool, default: False ) \u2013

    Whether the timer should only fire once, by default False

"},{"location":"api/protocols/#magicgui.widgets.protocols.BaseApplicationBackend._mgui_stop_timer","title":"_mgui_stop_timer() -> None abstractmethod","text":"

Stop timer. Should check for the existence of the timer.

"},{"location":"api/type_map/","title":"magicgui.type_map","text":"Widget Description get_widget_class Return a Widget subclass for the value/annotation. register_type Register a widget_type to be used for all parameters with type type_. type_registered Context manager that temporarily registers a widget type for a given type_. type2callback Return any callbacks that have been registered for type_. TypeMap Storage for mapping from types to widgets and callbacks."},{"location":"api/type_map/#magicgui.type_map.get_widget_class","title":"magicgui.type_map.get_widget_class = _GLOBAL_TYPE_MAP.get_widget_class module-attribute","text":""},{"location":"api/type_map/#magicgui.type_map.register_type","title":"magicgui.type_map.register_type = _GLOBAL_TYPE_MAP.register_type module-attribute","text":""},{"location":"api/type_map/#magicgui.type_map.type_registered","title":"magicgui.type_map.type_registered = _GLOBAL_TYPE_MAP.type_registered module-attribute","text":""},{"location":"api/type_map/#magicgui.type_map.type2callback","title":"magicgui.type_map.type2callback = _GLOBAL_TYPE_MAP.type2callback module-attribute","text":""},{"location":"api/type_map/#magicgui.type_map.TypeMap","title":"magicgui.type_map.TypeMap","text":"

Storage for mapping from types to widgets and callbacks.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.copy","title":"copy()","text":"

Return a copy of the type map.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.create_widget","title":"create_widget(value=Undefined, annotation=None, name='', param_kind='POSITIONAL_OR_KEYWORD', label=None, gui_only=False, app=None, widget_type=None, options=None, is_result=False, raise_on_unknown=True)","text":"

Create and return appropriate widget subclass.

This factory function can be used to create a widget appropriate for the provided value and/or annotation provided. See Type Mapping Docs for details on how the widget type is determined from type annotations.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget, by default None

  • annotation (Any, default: None ) \u2013

    The type annotation for the parameter represented by the widget, by default None.

  • name (str, default: '' ) \u2013

    The name of the parameter represented by this widget. by default \"\"

  • param_kind (str, default: 'POSITIONAL_OR_KEYWORD' ) \u2013

    The :attr:inspect.Parameter.kind represented by this widget. Used in building signatures from multiple widgets, by default \"POSITIONAL_OR_KEYWORD\"

  • label (str, default: None ) \u2013

    A string to use for an associated Label widget (if this widget is being shown in a Container widget, and labels are on). By default, name will be used. Note: name refers the name of the parameter, as might be used in a signature, whereas label is just the label for that widget in the GUI.

  • gui_only (bool, default: False ) \u2013

    Whether the widget should be considered \"only for the gui\", or if it should be included in any widget container signatures, by default False

  • app (str, default: None ) \u2013

    The backend to use, by default None

  • widget_type (str or Type[WidgetProtocol] or None, default: None ) \u2013

    A class implementing a widget protocol or a string with the name of a magicgui widget type (e.g. \"Label\", \"PushButton\", etc...). If provided, this widget type will be used instead of the type autodetermined from value and/or annotation above.

  • options (dict, default: None ) \u2013

    Dict of options to pass to the Widget constructor, by default dict()

  • is_result (boolean, default: False ) \u2013

    Whether the widget belongs to an input or an output. By default, an input is assumed.

  • raise_on_unknown (bool, default: True ) \u2013

    Raise exception if no widget is found for the given type, by default True

Returns:

  • Widget \u2013

    An instantiated widget subclass

Raises:

  • TypeError \u2013

    If the provided or autodetected widget_type does not implement any known widget protocols

Examples:

from magicgui.widgets import create_widget\n\n# create a widget from a string value\nwdg = create_widget(value=\"hello world\")\nassert wdg.value == \"hello world\"\n\n# create a widget from a string annotation\nwdg = create_widget(annotation=str)\nassert wdg.value == \"\"\n
"},{"location":"api/type_map/#magicgui.type_map.TypeMap.get_widget_class","title":"get_widget_class(value=Undefined, annotation=Undefined, options=None, is_result=False, raise_on_unknown=True)","text":"

Return a Widget subclass for the value/annotation.

Parameters:

  • value (Any, default: Undefined ) \u2013

    A python value. Will be used to determine the widget type if an annotation is not explicitly provided by default None

  • annotation (Optional[Type], default: Undefined ) \u2013

    A type annotation, by default None

  • options (dict, default: None ) \u2013

    Options to pass when constructing the widget, by default {}

  • is_result (bool, default: False ) \u2013

    Identifies whether the returned widget should be tailored to an input or to an output.

  • raise_on_unknown (bool, default: True ) \u2013

    Raise exception if no widget is found for the given type, by default True

Returns:

  • Tuple[WidgetClass, dict] \u2013

    The WidgetClass, and dict that can be used for params. dict may be different than the options passed in.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.global_instance","title":"global_instance() staticmethod","text":"

Get the global type map.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.magic_factory","title":"magic_factory(function=None, *, layout='vertical', scrollable=False, labels=True, tooltips=True, call_button=None, auto_call=False, result_widget=False, main_window=False, app=None, persist=False, widget_init=None, raise_on_unknown=False, **param_options)","text":"

Return a MagicFactory for function.

magic_factory is nearly identical to the magicgui decorator with the following differences:

  1. Whereas magicgui returns a FunctionGui instance, magic_factory returns a callable that returns a FunctionGui instance. (Technically, it returns an instance of MagicFactory which you behaves exactly like a functools.partial for a FunctionGui instance.)
  2. magic_factory adds a widget_init method: a callable that will be called immediately after the FunctionGui instance is created. This can be used to add additional widgets to the layout, or to connect signals to the widgets.

Important

Whereas decorating a function with magicgui will immediately create a widget instance, magic_factory will not create a widget instance until the decorated object is called. This is often what you want in a library, whereas magicgui is useful for rapid, interactive development.

Parameters:

  • function (Callable, default: None ) \u2013

    The function to decorate. Optional to allow bare decorator with optional arguments. by default None

  • layout (str, default: 'vertical' ) \u2013

    The type of layout to use. Must be horizontal or vertical by default \"vertical\".

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether labels are shown in the widget. by default True

  • tooltips (bool, default: True ) \u2013

    Whether tooltips are shown when hovering over widgets. by default True

  • call_button (bool or str, default: None ) \u2013

    If True, create an additional button that calls the original function when clicked. If a str, set the button text. If None (the default), it defaults to True when auto_call is False, and False otherwise.

  • auto_call (bool, default: False ) \u2013

    If True, changing any parameter in either the GUI or the widget attributes will call the original function with the current settings. by default False

  • result_widget (bool, default: False ) \u2013

    Whether to display a LineEdit widget the output of the function when called, by default False

  • main_window (bool, default: False ) \u2013

    Whether this widget should be treated as the main app window, with menu bar, by default False.

  • app (Application or str, default: None ) \u2013

    A backend to use, by default None (use the default backend.)

  • persist (bool, default: False ) \u2013

    If True, when parameter values change in the widget, they will be stored to disk and restored when the widget is loaded again with persist = True. Call magicgui._util.user_cache_dir() to get the default cache location. By default False.

  • widget_init (callable, default: None ) \u2013

    A function that will be called with the newly created widget instance as its only argument. This can be used to customize the widget after it is created. by default None.

  • raise_on_unknown (bool, default: False ) \u2013

    If True, raise an error if magicgui cannot determine widget for function argument or return type. If False, ignore unknown types. By default False.

  • param_options (dict of dict, default: {} ) \u2013

    Any additional keyword arguments will be used as parameter-specific widget options. Keywords must match the name of one of the arguments in the function signature, and the value must be a dict of keyword arguments to pass to the widget constructor.

Returns:

  • result ( MagicFactory or Callable[[F], MagicFactory] ) \u2013

    If function is not None (such as when this is used as a bare decorator), returns a MagicFactory instance. If function is None such as when arguments are provided like magic_factory(auto_call=True), then returns a function that can be used as a decorator.

Examples:

>>> @magic_factory\n... def my_function(a: int = 1, b: str = \"hello\"):\n...     pass\n>>> my_widget = my_function()\n>>> my_widget.show()\n>>> my_widget.a.value == 1  # True\n>>> my_widget.b.value = \"world\"\n
"},{"location":"api/type_map/#magicgui.type_map.TypeMap.magicgui","title":"magicgui(function=None, *, layout='vertical', scrollable=False, labels=True, tooltips=True, call_button=None, auto_call=False, result_widget=False, main_window=False, app=None, persist=False, raise_on_unknown=False, **param_options)","text":"

Return a FunctionGui for function.

Parameters:

  • function (Callable, default: None ) \u2013

    The function to decorate. Optional to allow bare decorator with optional arguments. by default None

  • layout (str, default: 'vertical' ) \u2013

    The type of layout to use. Must be horizontal or vertical by default \"vertical\".

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether labels are shown in the widget. by default True

  • tooltips (bool, default: True ) \u2013

    Whether tooltips are shown when hovering over widgets. by default True

  • call_button (bool or str, default: None ) \u2013

    If True, create an additional button that calls the original function when clicked. If a str, set the button text. If None (the default), it defaults to True when auto_call is False, and False otherwise.

  • auto_call (bool, default: False ) \u2013

    If True, changing any parameter in either the GUI or the widget attributes will call the original function with the current settings. by default False

  • result_widget (bool, default: False ) \u2013

    Whether to display a LineEdit widget the output of the function when called, by default False

  • main_window (bool, default: False ) \u2013

    Whether this widget should be treated as the main app window, with menu bar, by default False.

  • app (Application or str, default: None ) \u2013

    A backend to use, by default None (use the default backend.)

  • persist (bool, default: False ) \u2013

    If True, when parameter values change in the widget, they will be stored to disk and restored when the widget is loaded again with persist = True. Call magicgui._util.user_cache_dir() to get the default cache location. By default False.

  • raise_on_unknown (bool, default: False ) \u2013

    If True, raise an error if magicgui cannot determine widget for function argument or return type. If False, ignore unknown types. By default False.

  • param_options (dict[str, dict], default: {} ) \u2013

    Any additional keyword arguments will be used as parameter-specific options. Keywords must match the name of one of the arguments in the function signature, and the value must be a dict of keyword arguments to pass to the widget constructor.

Returns:

  • result ( FunctionGui or Callable[[F], FunctionGui] ) \u2013

    If function is not None (such as when this is used as a bare decorator), returns a FunctionGui instance, which is a list-like container of autogenerated widgets corresponding to each parameter in the function. If function is None such as when arguments are provided like magicgui(auto_call=True), then returns a function that can be used as a decorator.

Examples:

>>> @magicgui\n... def my_function(a: int = 1, b: str = \"hello\"):\n...     pass\n>>> my_function.show()\n>>> my_function.a.value == 1  # True\n>>> my_function.b.value = \"world\"\n
"},{"location":"api/type_map/#magicgui.type_map.TypeMap.match_return_type","title":"match_return_type(type_)","text":"

Check simple type mappings for result widgets.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.match_type","title":"match_type(type_, default=None)","text":"

Check simple type mappings.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.register_type","title":"register_type(type_=None, *, widget_type=None, return_callback=None, **options)","text":"

Register a widget_type to be used for all parameters with type type_.

Note: registering a Union (or Optional) type effectively registers all types in the union with the arguments.

Parameters:

  • type_ (type, default: None ) \u2013

    The type for which a widget class or return callback will be provided.

  • widget_type (WidgetRef, default: None ) \u2013

    A widget class from the current backend that should be used whenever type_ is used as the type annotation for an argument in a decorated function, by default None

  • return_callback (ReturnCallback | None, default: None ) \u2013

    If provided, whenever type_ is declared as the return type of a decorated function, return_callback(widget, value, return_type) will be called whenever the decorated function is called... where widget is the Widget instance, and value is the return value of the decorated function.

  • options (Any, default: {} ) \u2013

    key value pairs where the keys are valid dict

Raises:

  • ValueError \u2013

    If none of widget_type, return_callback, bind or choices are provided.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.type2callback","title":"type2callback(type_)","text":"

Return any callbacks that have been registered for type_.

Parameters:

  • type_ (type) \u2013

    The type_ to look up.

Returns:

  • list of callable \u2013

    Where a return callback accepts two arguments (gui, value) and does something.

"},{"location":"api/type_map/#magicgui.type_map.TypeMap.type_registered","title":"type_registered(type_, *, widget_type=None, return_callback=None, **options)","text":"

Context manager that temporarily registers a widget type for a given type_.

When the context is exited, the previous widget type associations for type_ is restored.

Parameters:

  • type_ (_T) \u2013

    The type for which a widget class or return callback will be provided.

  • widget_type (Optional[WidgetRef], default: None ) \u2013

    A widget class from the current backend that should be used whenever type_ is used as the type annotation for an argument in a decorated function, by default None

  • return_callback (ReturnCallback | None, default: None ) \u2013

    If provided, whenever type_ is declared as the return type of a decorated function, return_callback(widget, value, return_type) will be called whenever the decorated function is called... where widget is the Widget instance, and value is the return value of the decorated function.

  • options (Any, default: {} ) \u2013

    key value pairs where the keys are valid dict

"},{"location":"api/widgets/","title":"Widget Index","text":"

Here you will find a list of all the widgets that are available in magicgui. Each widget has a link to its own documentation page, where you can find more information about the widget, including its parameters and events.

Widget Description CheckBox A checkbox with a text label. ComboBox A dropdown menu, allowing selection between multiple choices. Container A Widget to contain other widgets. DateEdit A widget for editing dates. DateTimeEdit A widget for editing dates and times. Dialog A modal container. EmptyWidget A base widget with no value. FileEdit A LineEdit widget with a button that opens a FileDialog. FloatRangeSlider A slider widget to adjust a range defined by two float values within a range. FloatSlider A slider widget to adjust an integer value within a range. FloatSpinBox A widget to edit a float with clickable up/down arrows. FunctionGui Wrapper for a container of widgets representing a callable object. Image A non-editable image display. Label A non-editable text display. LineEdit A one-line text editor. ListEdit A widget to represent a list of values. LiteralEvalLineEdit A one-line text editor that evaluates strings as python literals. LogSlider A slider widget to adjust a numerical value logarithmically within a range. MainFunctionGui Container of widgets as a Main Application Window. MainWindow A Widget to contain other widgets, includes a menu bar. Password A one-line text editor that obscures input. ProgressBar A progress bar widget. PushButton A clickable command button. QuantityEdit A combined LineEdit and ComboBox to edit a pint.Quantity. RadioButton A radio button with a text label. RadioButtons An exclusive group of radio buttons, providing a choice from multiple choices. RangeEdit A widget to represent a python range object, with start/stop/step. RangeSlider A slider widget to adjust a range between two integer values within a range. Select A list of options, allowing selection between multiple choices. SliceEdit A widget to represent slice objects, with start/stop/step. Slider A slider widget to adjust an integer value within a range. SpinBox A widget to edit an integer with clickable up/down arrows. Table A widget to represent columnar or 2D data with headers. TextEdit A widget to edit and display both plain and rich text. TimeEdit A widget for editing times. ToolBar Toolbar that contains a set of controls. TupleEdit A widget to represent a tuple of values."},{"location":"api/widgets/CheckBox/","title":"CheckBox","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/CheckBox/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the button is clicked (may also be connected at the alias clicked).
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/CheckBox/#magicgui.widgets.CheckBox","title":"CheckBox","text":"

Bases: ButtonWidget

A checkbox with a text label.

Parameters:

  • value (bool, default: Undefined ) \u2013

    The starting state of the widget.

  • text (str, default: None ) \u2013

    The text to display on the button. If not provided, will use name.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/ComboBox/","title":"ComboBox","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/ComboBox/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/ComboBox/#magicgui.widgets.ComboBox","title":"ComboBox","text":"

Bases: CategoricalWidget

A dropdown menu, allowing selection between multiple choices.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The initially selected choice.

  • choices (Enum, Iterable, or Callable, default: () ) \u2013

    Available choices displayed in the combo box.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/Container/","title":"Container","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/Container/#signals","title":"Signals","text":"
  • changed(object) - Emitted with self when any sub-widget in the container changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Container/#magicgui.widgets.Container","title":"Container","text":"

Bases: ContainerWidget[WidgetVar]

A Widget to contain other widgets.

Note that Container implements the typing.MutableSequence interface, so you can use it like a list to add and remove widgets.

Parameters:

  • widgets (Sequence[Widget], default: () ) \u2013

    A sequence of widgets with which to initialize the container, by default None.

  • layout (str, default: 'vertical' ) \u2013

    The layout for the container. must be one of {'horizontal', 'vertical'}. by default \"vertical\"

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether each widget should be shown with a corresponding Label widget to the left, by default True. Note: the text for each widget defaults to widget.name, but can be overridden by setting widget.label.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/DateEdit/","title":"DateEdit","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/DateEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/DateEdit/#magicgui.widgets.DateEdit","title":"DateEdit","text":"

Bases: ValueWidget[date]

A widget for editing dates.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/DateTimeEdit/","title":"DateTimeEdit","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/DateTimeEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/DateTimeEdit/#magicgui.widgets.DateTimeEdit","title":"DateTimeEdit","text":"

Bases: ValueWidget[datetime]

A widget for editing dates and times.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/Dialog/","title":"Dialog","text":"

Available in backends: qt

"},{"location":"api/widgets/Dialog/#signals","title":"Signals","text":"
  • changed(object) - Emitted with self when any sub-widget in the container changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Dialog/#magicgui.widgets.Dialog","title":"Dialog","text":"

Bases: DialogWidget

A modal container.

Parameters:

  • widgets (Sequence[Widget], default: () ) \u2013

    A sequence of widgets with which to initialize the container, by default None.

  • layout (str, default: 'vertical' ) \u2013

    The layout for the container. must be one of {'horizontal', 'vertical'}. by default \"vertical\"

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether each widget should be shown with a corresponding Label widget to the left, by default True. Note: the text for each widget defaults to widget.name, but can be overridden by setting widget.label.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/EmptyWidget/","title":"EmptyWidget","text":"

Available in backends:

"},{"location":"api/widgets/EmptyWidget/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/EmptyWidget/#magicgui.widgets.EmptyWidget","title":"EmptyWidget","text":"

Bases: ValuedContainerWidget[Any]

A base widget with no value.

This widget is primarily here to serve as a \"hidden widget\" to which a value or callback can be bound.

"},{"location":"api/widgets/EmptyWidget/#magicgui.widgets.EmptyWidget.__repr__","title":"__repr__() -> str","text":"

Return string repr (avoid looking for value).

"},{"location":"api/widgets/EmptyWidget/#magicgui.widgets.EmptyWidget.get_value","title":"get_value() -> Any","text":"

Return value if one has been manually set... otherwise return Param.empty.

"},{"location":"api/widgets/FileEdit/","title":"FileEdit","text":"

Available in backends:

"},{"location":"api/widgets/FileEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/FileEdit/#magicgui.widgets.FileEdit","title":"FileEdit","text":"

Bases: ValuedContainerWidget[Union[Path, tuple[Path, ...], None]]

A LineEdit widget with a button that opens a FileDialog.

Parameters:

  • mode (FileDialogMode or str, default: EXISTING_FILE ) \u2013
    • 'r' returns one existing file.
    • 'rm' return one or more existing files.
    • 'w' return one file name that does not have to exist.
    • 'd' returns one existing directory.
  • filter (str, default: None ) \u2013

    The filter is used to specify the kind of files that should be shown. It should be a glob-style string, like '*.png' (this may be backend-specific)

"},{"location":"api/widgets/FileEdit/#magicgui.widgets.FileEdit.mode","title":"mode: FileDialogMode property writable","text":"

Mode for the FileDialog.

"},{"location":"api/widgets/FileEdit/#magicgui.widgets.FileEdit.__repr__","title":"__repr__() -> str","text":"

Return string representation.

"},{"location":"api/widgets/FileEdit/#magicgui.widgets.FileEdit.get_value","title":"get_value() -> tuple[Path, ...] | Path | None","text":"

Return current value.

"},{"location":"api/widgets/FileEdit/#magicgui.widgets.FileEdit.set_value","title":"set_value(value: Sequence[PathLike] | PathLike | None) -> None","text":"

Set current file path.

"},{"location":"api/widgets/FloatRangeSlider/","title":"FloatRangeSlider","text":"

Available in backends: qt

"},{"location":"api/widgets/FloatRangeSlider/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/FloatRangeSlider/#magicgui.widgets.FloatRangeSlider","title":"FloatRangeSlider","text":"

Bases: MultiValuedSliderWidget

A slider widget to adjust a range defined by two float values within a range.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • orientation ((str, {'horizontal', 'vertical'}), default: 'horizontal' ) \u2013

    The orientation for the slider, by default \"horizontal\"

  • readout (bool, default: True ) \u2013

    Whether to show the editable spinbox next to the slider

  • tracking (bool, default: True ) \u2013

    If tracking is enabled (the default), the slider emits the changed signal while the slider is being dragged. If tracking is disabled, the slider emits the changed signal only after the user releases the slider.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/FloatSlider/","title":"FloatSlider","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/FloatSlider/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/FloatSlider/#magicgui.widgets.FloatSlider","title":"FloatSlider","text":"

Bases: SliderWidget[float]

A slider widget to adjust an integer value within a range.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • orientation ((str, {'horizontal', 'vertical'}), default: 'horizontal' ) \u2013

    The orientation for the slider, by default \"horizontal\"

  • readout (bool, default: True ) \u2013

    Whether to show the editable spinbox next to the slider

  • tracking (bool, default: True ) \u2013

    If tracking is enabled (the default), the slider emits the changed signal while the slider is being dragged. If tracking is disabled, the slider emits the changed signal only after the user releases the slider.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/FloatSpinBox/","title":"FloatSpinBox","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/FloatSpinBox/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/FloatSpinBox/#magicgui.widgets.FloatSpinBox","title":"FloatSpinBox","text":"

Bases: RangedWidget[float]

A widget to edit a float with clickable up/down arrows.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/FunctionGui/","title":"FunctionGui","text":"

Available in backends:

"},{"location":"api/widgets/FunctionGui/#signals","title":"Signals","text":"
  • called(object) - Emitted with the result after the function is called.
  • changed(object) - Emitted with self when any sub-widget in the container changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui","title":"FunctionGui","text":"

Bases: Container, Generic[_P, _R]

Wrapper for a container of widgets representing a callable object.

Parameters:

  • function (Callable) \u2013

    A callable to turn into a GUI

  • call_button (bool | str | None, default: None ) \u2013

    If True, create an additional button that calls the original function when clicked. If a str, set the button text. by default False when auto_call is True, and True otherwise. The button can be accessed from the .call_button property.

  • layout (str, default: 'vertical' ) \u2013

    The type of layout to use. Must be horizontal or vertical by default \"horizontal\".

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether labels are shown in the widget. by default True

  • tooltips (bool, default: True ) \u2013

    Whether tooltips are shown when hovering over widgets. by default True

  • app (Application | str | None, default: None ) \u2013

    A backend to use, by default None (use the default backend.)

  • visible (bool, default: None ) \u2013

    Whether to immediately show the widget. If False, widget is explicitly hidden. If None, widget is not shown, but will be shown if a parent container is shown, by default None.

  • auto_call (bool, default: False ) \u2013

    If True, changing any parameter in either the GUI or the widget attributes will call the original function with the current settings. by default False

  • result_widget (bool, default: False ) \u2013

    Whether to display a LineEdit widget the output of the function when called, by default False

  • param_options (dict, default: None ) \u2013

    A dict of name: widget_options dict for each parameter in the function. Will be passed to magic_signature by default None

  • name (str, default: None ) \u2013

    A name to assign to the Container widget, by default function.__name__

  • persist (bool, default: False ) \u2013

    If True, when parameter values change in the widget, they will be stored to disk (in ~/.config/magicgui/cache) and restored when the widget is loaded again with persist = True. By default, False.

  • raise_on_unknown (bool, default: False ) \u2013

    If True, raise an error if a parameter annotation is not recognized.

Raises:

  • TypeError \u2013

    If unexpected keyword arguments are provided

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.__signature__","title":"__signature__: MagicSignature property","text":"

Return a MagicSignature object representing the current state of the gui.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.call_button","title":"call_button: PushButton | None property","text":"

Return the call button.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.call_count","title":"call_count: int property","text":"

Return the number of times the function has been called.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.result_name","title":"result_name: str property writable","text":"

Return a name that can be used for the result of this magicfunction.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.return_annotation","title":"return_annotation: Any property","text":"

Return annotation for inspect.Signature conversion.

ForwardRefs will be resolve when setting the annotation.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.__call__","title":"__call__(*args: _P.args, **kwargs: _P.kwargs) -> _R","text":"

Call the original function with the current parameter values from the Gui.

You may pass a update_widget=True keyword argument to update the widget values to match the current parameter values before calling the function.

It is also possible to override the current parameter values from the GUI by providing args/kwargs to the function call. Only those provided will override the ones from the gui. A called signal will also be emitted with the results.

Returns:

  • result ( Any ) \u2013

    whatever the return value of the original function would have been.

Examples:

gui = FunctionGui(func, show=True)\n\n# then change parameters in the gui, or by setting:  gui.param.value = something\n\ngui()  # calls the original function with the current parameters\n
"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.__get__","title":"__get__(obj: object, objtype: type | None = None) -> FunctionGui","text":"

Provide descriptor protocol.

This allows the @magicgui decorator to work on a function as well as a method. If a method on a class is decorated with @magicgui, then accessing the attribute on an instance of that class will return a version of the FunctionGui in which the first argument of the function is bound to the instance. (Just like what you'd expect with the @property decorator.)

Returns:

  • bound ( FunctionGui ) \u2013

    A new FunctionGui instance.

Examples:

>>> class MyClass:\n...     @magicgui\n...     def my_method(self, x=1):\n...         print(locals())\n...\n>>> c = MyClass()\n>>> c.my_method  # the FunctionGui that can be used as a widget\n\n# calling it works as usual, with `c` provided as `self`\n>>> c.my_method(x=34)\n{'self': <__main__.MyClass object at 0x7fb610e455e0>, 'x': 34}\n
"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.__repr__","title":"__repr__() -> str","text":"

Return string representation of instance.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.__set__","title":"__set__(obj: Any, value: Any) -> NoReturn","text":"

Prevent setting a magicgui attribute.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.copy","title":"copy() -> FunctionGui","text":"

Return a copy of this FunctionGui.

"},{"location":"api/widgets/FunctionGui/#magicgui.widgets.FunctionGui.reset_call_count","title":"reset_call_count() -> None","text":"

Reset the call count to 0.

"},{"location":"api/widgets/Image/","title":"Image","text":"

Available in backends: qt

"},{"location":"api/widgets/Image/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Image/#magicgui.widgets.Image","title":"Image","text":"

Bases: ValueWidget

A non-editable image display.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.image_data","title":"image_data: np.ndarray | None property","text":"

Return image data.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.image_rgba","title":"image_rgba: np.ndarray | None property","text":"

Return rendered numpy array.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.__repr__","title":"__repr__() -> str","text":"

Return representation of widget of instance.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.get_clim","title":"get_clim() -> tuple[float | None, float | None]","text":"

Get contrast limits (for monochromatic images).

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.get_value","title":"get_value()","text":"

Return current image array.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.scale_widget_to_image_size","title":"scale_widget_to_image_size()","text":"

Set the size of the widget to the size of the image.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.set_clim","title":"set_clim(vmin: float | None = None, vmax: float | None = None)","text":"

Set contrast limits (for monochromatic images).

Parameters:

  • vmin (float, default: None ) \u2013

    The min contrast limit to use when scaling monochromatic images

  • vmax (float, default: None ) \u2013

    The max contrast limit to use when scaling monochromatic images

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.set_cmap","title":"set_cmap(cmap: str | Colormap | matplotlib.colors.Colormap)","text":"

Set colormap (for monochromatic images).

Parameters:

  • cmap (str, magicgui.types.Colormap, or matplotlib.colors.Colormap) \u2013

    A colormap to use for monochromatic images. If a string, matplotlib must be installed and the colormap will be selected with cm.get_cmap(cmap).

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.set_data","title":"set_data(val: str | Path | np.ndarray | PIL.Image.Image, cmap: str | Colormap | matplotlib.colors.Colormap | None = None, norm: _mpl_image.Normalize | matplotlib.colors.Normalize | None = None, vmin: float | None = None, vmax: float | None = None, width: int | Literal['auto'] | None = None, height: int | Literal['auto'] | None = None, format: str | None = None)","text":"

Set image data with various optional display parameters.

Parameters:

  • val ((str, Path, ndarray or Image)) \u2013

    The image data or file to load. Data must be 2D (monochromatic), or 3D: MxNx3 (RGB) or MxNx4 (RGBA).

  • cmap (str, magicgui.types.Colormap, or matplotlib.colors.Colormap, default: None ) \u2013

    A colormap to use for monochromatic images. If a string, matplotlib must be installed and the colormap will be selected with cm.get_cmap(cmap).

  • norm (magicgui.types.Normalize, or matplotlib.colors.Normalize, default: None ) \u2013

    A normalization object to use for rendering images. Accepts matplotlib Normalize objects.

  • vmin (float, default: None ) \u2013

    The min contrast limit to use when scaling monochromatic images

  • vmax (float, default: None ) \u2013

    The max contrast limit to use when scaling monochromatic images

  • width (int or 'auto', default: None ) \u2013

    Set the width of the widget. If \"auto\", sets the widget size to the image size (1:1). If width is provided, height is auto-set based on aspect ratio.

  • height (int or 'auto', default: None ) \u2013

    Set the height of the widget. If \"auto\", sets the widget size to the image size (1:1). If width is provided, height is auto-set based on aspect ratio.

  • format (str, default: None ) \u2013

    Force image format type for imread when val is provided as a string, by default None

Raises:

  • TypeError \u2013

    If the provided data shape or type is invalid.

  • ImportError \u2013

    If a string is provided for val and PIL is not installed.

  • RuntimeError \u2013

    If a PIL.Image.Image instance is provided as data, with an unrecognized image mode.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.set_norm","title":"set_norm(norm: Normalize | matplotlib.colors.Normalize)","text":"

Set normalization method.

Parameters:

  • norm (magicgui.types.Normalize, or matplotlib.colors.Normalize) \u2013

    A normalization object to use for rendering images. Accepts matplotlib Normalize objects.

"},{"location":"api/widgets/Image/#magicgui.widgets.Image.set_value","title":"set_value(value)","text":"

Set current data. Alias for image.set_data(value).

"},{"location":"api/widgets/Label/","title":"Label","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/Label/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Label/#magicgui.widgets.Label","title":"Label","text":"

Bases: ValueWidget[str]

A non-editable text display.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/LineEdit/","title":"LineEdit","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/LineEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/LineEdit/#magicgui.widgets.LineEdit","title":"LineEdit","text":"

Bases: ValueWidget[str]

A one-line text editor.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/ListEdit/","title":"ListEdit","text":"

Available in backends:

"},{"location":"api/widgets/ListEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/ListEdit/#magicgui.widgets.ListEdit","title":"ListEdit","text":"

Bases: ValuedContainerWidget[list[_V]]

A widget to represent a list of values.

A ListEdit container can create a list with multiple objects of same type. It will contain many child widgets and their value is represented as a Python list object. If a list is given as the initial value, types of child widgets are determined from the contents. Number of contents can be adjusted with +/- buttons.

Parameters:

  • value (Iterable, default: Undefined ) \u2013

    The starting value for the widget.

  • nullable (bool) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • options (dict, default: None ) \u2013

    Widget options of child widgets.

"},{"location":"api/widgets/ListEdit/#magicgui.widgets.ListEdit.annotation","title":"annotation: Any property writable","text":"

Return type annotation for the parameter represented by the widget.

ForwardRefs will be resolve when setting the annotation. For ListEdit, annotation will be like 'list[str]'.

"},{"location":"api/widgets/ListEdit/#magicgui.widgets.ListEdit.data","title":"data: ListDataView[_V] property writable","text":"

Return a data view of current value.

"},{"location":"api/widgets/ListEdit/#magicgui.widgets.ListEdit.__delitem__","title":"__delitem__(key: int | slice) -> None","text":"

Delete child widget(s).

"},{"location":"api/widgets/ListEdit/#magicgui.widgets.ListEdit.get_value","title":"get_value() -> list[_V]","text":"

Return current value as a list object.

"},{"location":"api/widgets/LiteralEvalLineEdit/","title":"LiteralEvalLineEdit","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/LiteralEvalLineEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/LiteralEvalLineEdit/#magicgui.widgets.LiteralEvalLineEdit","title":"LiteralEvalLineEdit","text":"

Bases: ValueWidget[str]

A one-line text editor that evaluates strings as python literals.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/LogSlider/","title":"LogSlider","text":"

Available in backends:

"},{"location":"api/widgets/LogSlider/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/LogSlider/#magicgui.widgets.LogSlider","title":"LogSlider","text":"

Bases: TransformedRangedWidget

A slider widget to adjust a numerical value logarithmically within a range.

Parameters:

  • base (Enum, Iterable, or Callable, default: e ) \u2013

    The base to use for the log, by default math.e.

"},{"location":"api/widgets/LogSlider/#magicgui.widgets.LogSlider.base","title":"base: float property writable","text":"

Return base used for the log.

"},{"location":"api/widgets/LogSlider/#magicgui.widgets.LogSlider.tracking","title":"tracking: bool property writable","text":"

Return whether slider tracking is enabled.

If tracking is enabled (the default), the slider emits the changed() signal while the slider is being dragged. If tracking is disabled, the slider emits the changed() signal only when the user releases the slider.

"},{"location":"api/widgets/MainFunctionGui/","title":"MainFunctionGui","text":"

Available in backends:

"},{"location":"api/widgets/MainFunctionGui/#signals","title":"Signals","text":"
  • called(object) - Emitted with the result after the function is called.
  • changed(object) - Emitted with self when any sub-widget in the container changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/MainFunctionGui/#magicgui.widgets.MainFunctionGui","title":"MainFunctionGui","text":"

Bases: FunctionGui[_P, _R], MainWindow

Container of widgets as a Main Application Window.

"},{"location":"api/widgets/MainWindow/","title":"MainWindow","text":"

Available in backends: qt

"},{"location":"api/widgets/MainWindow/#signals","title":"Signals","text":"
  • changed(object) - Emitted with self when any sub-widget in the container changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/MainWindow/#magicgui.widgets.MainWindow","title":"MainWindow","text":"

Bases: MainWindowWidget

A Widget to contain other widgets, includes a menu bar.

Parameters:

  • widgets (Sequence[Widget], default: () ) \u2013

    A sequence of widgets with which to initialize the container, by default None.

  • layout (str, default: 'vertical' ) \u2013

    The layout for the container. must be one of {'horizontal', 'vertical'}. by default \"vertical\"

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether each widget should be shown with a corresponding Label widget to the left, by default True. Note: the text for each widget defaults to widget.name, but can be overridden by setting widget.label.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/Password/","title":"Password","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/Password/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Password/#magicgui.widgets.Password","title":"Password","text":"

Bases: ValueWidget[str]

A one-line text editor that obscures input.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/ProgressBar/","title":"ProgressBar","text":"

Available in backends: qt

"},{"location":"api/widgets/ProgressBar/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/ProgressBar/#magicgui.widgets.ProgressBar","title":"ProgressBar","text":"

Bases: SliderWidget[float]

A progress bar widget.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • orientation ((str, {'horizontal', 'vertical'}), default: 'horizontal' ) \u2013

    The orientation for the slider, by default \"horizontal\"

  • readout (bool, default: True ) \u2013

    Whether to show the editable spinbox next to the slider

  • tracking (bool, default: True ) \u2013

    If tracking is enabled (the default), the slider emits the changed signal while the slider is being dragged. If tracking is disabled, the slider emits the changed signal only after the user releases the slider.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/ProgressBar/#magicgui.widgets.ProgressBar.step","title":"step: float property writable","text":"

Step size for widget values.

"},{"location":"api/widgets/ProgressBar/#magicgui.widgets.ProgressBar.decrement","title":"decrement(val: float | None = None) -> None","text":"

Decrease current value by step size, or provided value.

"},{"location":"api/widgets/ProgressBar/#magicgui.widgets.ProgressBar.increment","title":"increment(val: float | None = None) -> None","text":"

Increase current value by step size, or provided value.

"},{"location":"api/widgets/PushButton/","title":"PushButton","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/PushButton/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the button is clicked (may also be connected at the alias clicked).
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/PushButton/#magicgui.widgets.PushButton","title":"PushButton","text":"

Bases: ButtonWidget

A clickable command button.

Parameters:

  • value (bool, default: Undefined ) \u2013

    The starting state of the widget.

  • text (str, default: None ) \u2013

    The text to display on the button. If not provided, will use name.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/QuantityEdit/","title":"QuantityEdit","text":"

Available in backends: qt

"},{"location":"api/widgets/QuantityEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/QuantityEdit/#magicgui.widgets.QuantityEdit","title":"QuantityEdit","text":"

Bases: ValueWidget

A combined LineEdit and ComboBox to edit a pint.Quantity.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/RadioButton/","title":"RadioButton","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/RadioButton/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the button is clicked (may also be connected at the alias clicked).
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/RadioButton/#magicgui.widgets.RadioButton","title":"RadioButton","text":"

Bases: ButtonWidget

A radio button with a text label.

Parameters:

  • value (bool, default: Undefined ) \u2013

    The starting state of the widget.

  • text (str, default: None ) \u2013

    The text to display on the button. If not provided, will use name.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/RadioButtons/","title":"RadioButtons","text":"

Available in backends: qt

"},{"location":"api/widgets/RadioButtons/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/RadioButtons/#magicgui.widgets.RadioButtons","title":"RadioButtons","text":"

Bases: CategoricalWidget, _OrientationMixin

An exclusive group of radio buttons, providing a choice from multiple choices.

Parameters:

  • value (Any) \u2013

    The initially selected choice.

  • choices (Enum, Iterable, or Callable, default: () ) \u2013

    Available choices displayed in the combo box.

  • bind (Callable[[ValueWidget], Any] | Any) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/RangeEdit/","title":"RangeEdit","text":"

Available in backends:

"},{"location":"api/widgets/RangeEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/RangeEdit/#magicgui.widgets.RangeEdit","title":"RangeEdit","text":"

Bases: _RangeOrSliceEdit[range]

A widget to represent a python range object, with start/stop/step.

A range object produces a sequence of integers from start (inclusive) to stop (exclusive) by step. range(i, j) produces i, i+1, i+2, ..., j-1. start defaults to 0, and stop is omitted! range(4) produces 0, 1, 2, 3. These are exactly the valid indices for a list of 4 elements. When step is given, it specifies the increment (or decrement).

Parameters:

  • start (int, default: 0 ) \u2013

    The range start value, by default 0

  • stop (int, default: 10 ) \u2013

    The range stop value, by default 10

  • step (int, default: 1 ) \u2013

    The range step value, by default 1

"},{"location":"api/widgets/RangeSlider/","title":"RangeSlider","text":"

Available in backends: qt

"},{"location":"api/widgets/RangeSlider/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/RangeSlider/#magicgui.widgets.RangeSlider","title":"RangeSlider","text":"

Bases: MultiValuedSliderWidget

A slider widget to adjust a range between two integer values within a range.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • orientation ((str, {'horizontal', 'vertical'}), default: 'horizontal' ) \u2013

    The orientation for the slider, by default \"horizontal\"

  • readout (bool, default: True ) \u2013

    Whether to show the editable spinbox next to the slider

  • tracking (bool, default: True ) \u2013

    If tracking is enabled (the default), the slider emits the changed signal while the slider is being dragged. If tracking is disabled, the slider emits the changed signal only after the user releases the slider.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/Select/","title":"Select","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/Select/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Select/#magicgui.widgets.Select","title":"Select","text":"

Bases: CategoricalWidget

A list of options, allowing selection between multiple choices.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The initially selected choice.

  • choices (Enum, Iterable, or Callable, default: () ) \u2013

    Available choices displayed in the combo box.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/SliceEdit/","title":"SliceEdit","text":"

Available in backends:

"},{"location":"api/widgets/SliceEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/SliceEdit/#magicgui.widgets.SliceEdit","title":"SliceEdit","text":"

Bases: _RangeOrSliceEdit[slice]

A widget to represent slice objects, with start/stop/step.

slice(stop) slice(start, stop[, step])

Slice objects may be used for extended slicing (e.g. a[0:10:2])

Parameters:

  • start (int, default: 0 ) \u2013

    The range start value, by default 0

  • stop (int, default: 10 ) \u2013

    The range stop value, by default 10

  • step (int, default: 1 ) \u2013

    The range step value, by default 1

"},{"location":"api/widgets/Slider/","title":"Slider","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/Slider/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Slider/#magicgui.widgets.Slider","title":"Slider","text":"

Bases: SliderWidget[int]

A slider widget to adjust an integer value within a range.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • orientation ((str, {'horizontal', 'vertical'}), default: 'horizontal' ) \u2013

    The orientation for the slider, by default \"horizontal\"

  • readout (bool, default: True ) \u2013

    Whether to show the editable spinbox next to the slider

  • tracking (bool, default: True ) \u2013

    If tracking is enabled (the default), the slider emits the changed signal while the slider is being dragged. If tracking is disabled, the slider emits the changed signal only after the user releases the slider.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/SpinBox/","title":"SpinBox","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/SpinBox/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/SpinBox/#magicgui.widgets.SpinBox","title":"SpinBox","text":"

Bases: RangedWidget[int]

A widget to edit an integer with clickable up/down arrows.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/Table/","title":"Table","text":"

Available in backends: qt

"},{"location":"api/widgets/Table/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/Table/#magicgui.widgets.Table","title":"Table","text":"

Bases: ValueWidget[Mapping[TblKey, Collection]], _ReadOnlyMixin, MutableMapping[TblKey, list]

A widget to represent columnar or 2D data with headers.

Tables behave like plain dicts, where the keys are column headers and the (list-like) values are column data.

Parameters:

  • value ((dict, dataframe, list, array, tuple), default: None ) \u2013

    Table data (and/or header data), in one of the accepted formats:

    • list or list-of-lists : [column_values] or [[row_vals], ..., [row_vals]]
    • dict-of-dicts : {column_header -> {row_header -> value}}
    • dict-of-lists : {column_header -> [column_values]}
    • list-of-row-records : [{column_headers -> value}, ... , {column_headers -> value}]
    • split-dict-of-lists :
    • tuple-of-values : ([values], [row_headers], [column_headers])
    • dict-of-pandas-series : {column_header -> Series(values)}
  • index (Collection, default: None ) \u2013

    A sized iterable container of row headers. By default, row headers will be tuple(range(len(data))). Values provided here override any implied in value.

  • columns (Collection, default: None ) \u2013

    A sized iterable container of column headers. By default, column headers will be tuple(range(len(data[0]))). Values provided here override any implied in value.

  • **kwargs (Unpack[WidgetKwargs], default: {} ) \u2013

    Additional kwargs will be passed to the magicgui.widgets.Widget constructor.

Attributes:

  • value (dict) \u2013

    Returns a dict with the keys data, index, and columns ... representing the 2D (list of lists) tabular data, row headers, and column headers, respectively. If set, will clear and update the table using the new data.

  • data (DataView) \u2013

    A DataView instance that provides numpy-like indexing (with get/set/delete) onto the 2D data array, For example table.data[0,2] gets the data in the cell of the first row, 3rd column. Works with numpy slice syntax.

  • column_headers (tuple) \u2013

    The current column headers. Can be set with a new sequence to change

  • row_headers (tuple) \u2013

    The current row headers. Can be set with a new sequence to change

  • shape (tuple of int) \u2013

    The shape of the table in (rows, columns).

  • size (int) \u2013

    The number of cells in the table.

Methods:

  • keys \u2013

    Return a TableHeadersView, providing a view on this table's headers. Use axis='row' for row headers.

  • items \u2013

    Return a TableItemsView, providing a view on this table's items, as 2-tuples of (header, data). Use axis='row' for (row_header, row_data)

  • clear \u2013

    Clear all table data and headers.

  • to_dataframe \u2013

    Returns a pandas dataframe representation of this table. (requires pandas)

  • to_dict \u2013

    Return one of many different dict-like representations of table and header data. See docstring of :meth:to_dict for details.

Events

changed Emitted whenever a cell in the table changes. The value will have a dict of information regarding the cell that changed: {'data': x, 'row': int, 'column': int, 'column_header': str, 'row_header': str} CURRENTLY: only emitted on changes in the GUI. not programmatic changes.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.column_headers","title":"column_headers: tuple property writable","text":"

Return column headers.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.data","title":"data: DataView property writable","text":"

Return DataView object for this table.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.row_headers","title":"row_headers: tuple property writable","text":"

Return row headers.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.shape","title":"shape: tuple[int, int] property","text":"

Return shape of table widget (rows, cols).

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.size","title":"size: int property","text":"

Return shape of table widget (rows, cols).

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__delitem__","title":"__delitem__(key: TblKey) -> None","text":"

Delete a column from the table.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__getitem__","title":"__getitem__(key: TblKey) -> list","text":"

Get a column from the table.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__hash__","title":"__hash__() -> int","text":"

Make table hashable.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__iter__","title":"__iter__() -> Iterator","text":"

Yield column headers.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__len__","title":"__len__() -> int","text":"

Return number of columns.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__new__","title":"__new__(value: TableData | None = None, *, index: Collection | None = None, columns: Collection | None = None, **kwargs: Any) -> Table","text":"

Just for the signature.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__repr__","title":"__repr__() -> str","text":"

Return string repr.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.__setitem__","title":"__setitem__(key: TblKey, v: Collection) -> None","text":"

Set a column in the table. If k doesn't exist, make a new column.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.clear","title":"clear() -> None","text":"

Clear the table.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.delete_row","title":"delete_row(*, index: int | Sequence[int] | None = None, header: Any | Sequence[Any] | None = None) -> None","text":"

Delete row(s) by index or header.

Parameters:

  • index (int or Sequence[int], default: None ) \u2013

    Index or indices of row(s) to delete.

  • header (Any or Sequence[Any], default: None ) \u2013

    Header or headers of row(s) to delete.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.get_value","title":"get_value() -> dict[TblKey, Collection]","text":"

Return dict with current data, index, and columns of the widget.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.items","title":"items(axis: str = 'column') -> TableItemsView[TblKey, list]","text":"

Return a set-like object providing a view on this table's items.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.keys","title":"keys(axis: str = 'column') -> HeadersView[TblKey]","text":"

Return a set-like object providing a view on this table's headers.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.set_value","title":"set_value(value: TableData) -> None","text":"

Set table data from dict, dataframe, list, or array.

Parameters:

  • value (Any) \u2013

    Complete table data in one of the forms described above. Partial table updates are not yet supported

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.to_dataframe","title":"to_dataframe() -> pandas.DataFrame","text":"

Convert TableData to dataframe.

"},{"location":"api/widgets/Table/#magicgui.widgets.Table.to_dict","title":"to_dict(orient: str = 'dict') -> list | dict","text":"

Convert the Table to a dictionary.

The type of the key-value pairs can be customized with the parameters (see below).

Parameters:

  • orient (str {'dict', 'list', 'series', 'split', 'records', 'index'}, default: 'dict' ) \u2013

    Determines the type of the values of the dictionary.

    • 'dict' (default) : dict like {column -> {index -> value}}
    • 'list' : dict like {column -> [values]}
    • 'split' : dict like
    • 'records' : list like [{column -> value}, ... , {column -> value}]
    • 'index' : dict like {index -> {column -> value}}
    • 'series' : dict like {column -> Series(values)}
"},{"location":"api/widgets/TextEdit/","title":"TextEdit","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/TextEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/TextEdit/#magicgui.widgets.TextEdit","title":"TextEdit","text":"

Bases: ValueWidget[str], _ReadOnlyMixin

A widget to edit and display both plain and rich text.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/TimeEdit/","title":"TimeEdit","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/TimeEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/TimeEdit/#magicgui.widgets.TimeEdit","title":"TimeEdit","text":"

Bases: ValueWidget[TV]

A widget for editing times.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/ToolBar/","title":"ToolBar","text":"

Available in backends: qt, ipynb

"},{"location":"api/widgets/ToolBar/#signals","title":"Signals","text":"
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/ToolBar/#magicgui.widgets.ToolBar","title":"ToolBar","text":"

Bases: ToolBarWidget

Toolbar that contains a set of controls.

Parameters:

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/TupleEdit/","title":"TupleEdit","text":"

Available in backends:

"},{"location":"api/widgets/TupleEdit/#signals","title":"Signals","text":"
  • changed(object) - Emitted when the widget value changes.
  • label_changed(str) - Emitted when the widget label changes.
  • native_parent_changed(object) - Emitted with the backend widget when the widget parent changes.
"},{"location":"api/widgets/TupleEdit/#magicgui.widgets.TupleEdit","title":"TupleEdit","text":"

Bases: ValuedContainerWidget[tuple]

A widget to represent a tuple of values.

A TupleEdit container has several child widgets of different type. Their value is represented as a Python tuple object. If a tuple is given as the initial value, types of child widgets are determined one by one. Unlike ListEdit, number of contents is not editable.

Parameters:

  • value (Iterable, default: Undefined ) \u2013

    The starting value for the widget.

  • nullable (bool) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • options (dict, default: None ) \u2013

    Widget options of child widgets.

"},{"location":"api/widgets/TupleEdit/#magicgui.widgets.TupleEdit.annotation","title":"annotation: Any property writable","text":"

Return type annotation for the parameter represented by the widget.

ForwardRefs will be resolve when setting the annotation. For TupleEdit, annotation will be like 'tuple[str, int]'.

"},{"location":"api/widgets/TupleEdit/#magicgui.widgets.TupleEdit.get_value","title":"get_value() -> tuple","text":"

Return current value as a tuple.

"},{"location":"api/widgets/bases/","title":"magicgui.widgets.bases","text":"

The magicgui.widgets.bases module contains the base classes for all widgets.

While most users will never instantiate these classes directly, the methods and properties of these classes are inherited by all widgets, and define the common API for all widgets. Therefore, it is worth being aware of the type of widget you are working with.

"},{"location":"api/widgets/bases/#summary","title":"Summary","text":"Widget Description Widget Basic Widget, wrapping a class that implements WidgetProtocol. ButtonWidget Widget with a value, Wraps a widget implementing the ButtonWidgetProtocol. CategoricalWidget Widget with a value and choices. Wraps CategoricalWidgetProtocol. BaseContainerWidget Widget that can contain other widgets. ContainerWidget Container widget that can insert/remove child widgets. ValuedContainerWidget Container-type ValueWidget. DialogWidget Modal Container. MainWindowWidget Top level Application widget that can contain other widgets. RangedWidget Widget with a constrained value. Wraps RangedWidgetProtocol. SliderWidget Widget with a constrained value and orientation. Wraps SliderWidgetProtocol. ValueWidget Widget with a value, Wraps ValueWidgetProtocol. BaseValueWidget An abstract base class for widgets that have a value."},{"location":"api/widgets/bases/#class-hierarchy","title":"Class Hierarchy","text":"

In visual form, the widget class hierarchy looks like this:

classDiagram\n    Widget <|-- BaseValueWidget\n    BaseValueWidget <|-- ValueWidget\n    Widget <|-- BaseContainerWidget\n    BackendWidget ..|> WidgetProtocol : implements a\n    ValueWidget <|-- RangedWidget\n    ValueWidget <|-- ButtonWidget\n    ValueWidget <|-- CategoricalWidget\n    RangedWidget <|-- SliderWidget\n    BaseContainerWidget <|-- ContainerWidget\n    BaseContainerWidget <|-- ValuedContainerWidget\n    BaseValueWidget <|-- ValuedContainerWidget\n    Widget --* WidgetProtocol : controls a\n    <<Interface>> WidgetProtocol\n    class WidgetProtocol {\n        _mgui_get_X()\n        _mgui_set_X()\n    }\n    class Widget{\n        name: str\n        annotation: Any\n        label: str\n        tooltip: str\n        visible: bool\n        enabled: bool\n        native: Any\n        height: int\n        width: int\n        hide()\n        show()\n        close()\n        render()\n    }\n    class BaseValueWidget{\n        value: Any\n        changed: SignalInstance\n        bind(value, call) Any\n        unbind()\n    }\n    class ValueWidget{\n    }\n    class RangedWidget{\n        value: float | tuple\n        min: float\n        max: float\n        step: float\n        adaptive_step: bool\n        range: tuple[float, float]\n    }\n    class SliderWidget{\n        orientation: str\n    }\n    class ButtonWidget{\n        value: bool\n        clicked: SignalInstance\n        text: str\n    }\n    class CategoricalWidget{\n        choices: List[Any]\n    }\n    class BaseContainerWidget{\n        widgets: List[Widget]\n        labels: bool\n        layout: str\n        margins: tuple[int, int, int, int]\n        reset_choices()\n        asdict() Dict[str, Any]\n        update(mapping)\n    }\n\n    click Widget href \"#magicgui.widgets.bases.Widget\"\n    click BaseValueWidget href \"#magicgui.widgets.bases.BaseValueWidget\"\n    click ValueWidget href \"#magicgui.widgets.bases.ValueWidget\"\n    click RangedWidget href \"#magicgui.widgets.bases.RangedWidget\"\n    click SliderWidget href \"#magicgui.widgets.bases.SliderWidget\"\n    click ButtonWidget href \"#magicgui.widgets.bases.ButtonWidget\"\n    click CategoricalWidget href \"#magicgui.widgets.bases.CategoricalWidget\"\n    click BaseContainerWidget href \"#magicgui.widgets.bases.BaseContainerWidget\"\n
"},{"location":"api/widgets/bases/#base-widget-classes","title":"Base Widget Classes","text":""},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget","title":"magicgui.widgets.bases.Widget","text":"

Basic Widget, wrapping a class that implements WidgetProtocol.

Parameters:

  • widget_type (type[WidgetProtocol]) \u2013

    A class implementing a widget protocol. Will be instantiated during init.

  • name (str, default: '' ) \u2013

    The name of the parameter represented by this widget. by default \"\"

  • annotation (Any, default: None ) \u2013

    The type annotation for the parameter represented by the widget, by default None

  • label (str, default: None ) \u2013

    A string to use for an associated Label widget (if this widget is being shown in a Container widget, and labels are on). By default, name will be used. Note: name refers the name of the parameter, as might be used in a signature, whereas label is just the label for that widget in the GUI.

  • tooltip (str, default: None ) \u2013

    A tooltip to display when hovering over the widget.

  • visible (bool, default: None ) \u2013

    Whether the widget is visible, by default True.

  • enabled (bool, default: True ) \u2013

    Whether the widget is enabled, by default True.

  • gui_only (bool, default: False ) \u2013

    If True, widget is excluded from any function signature representation. by default False. (This will likely be deprecated.)

  • parent (Any, default: None ) \u2013

    Optional parent widget of this widget. CAREFUL: if a parent is set, and subsequently deleted, this widget will likely be deleted as well (depending on the backend), and will no longer be usable.

  • backend_kwargs (dict, default: None ) \u2013

    keyword argument to pass to the backend widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.annotation","title":"annotation: Any property writable","text":"

Return type annotation for the parameter represented by the widget.

ForwardRefs will be resolve when setting the annotation.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.enabled","title":"enabled: bool property writable","text":"

Whether widget is enabled (editable).

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.height","title":"height: int property writable","text":"

Return the current height of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.label","title":"label: str property writable","text":"

Return a label to use for this widget when present in Containers.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.max_height","title":"max_height: int property writable","text":"

Get the maximum height of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.max_width","title":"max_width: int property writable","text":"

Get the maximum width of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.min_height","title":"min_height: int property writable","text":"

Get the minimum height of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.min_width","title":"min_width: int property writable","text":"

Get the minimum width of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.native","title":"native: Any property","text":"

Return native backend widget.

Note this is the widget that contains the layout, and not any parent widgets of this (e.g. a parent widget that is used to enable scroll bars)

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.options","title":"options: dict property","text":"

Return options currently being used in this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.param_kind","title":"param_kind: inspect._ParameterKind property writable","text":"

Return :attr:inspect.Parameter.kind represented by this widget.

Used in building signatures from multiple widgets, by default :attr:~inspect.Parameter.POSITIONAL_OR_KEYWORD

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.parent","title":"parent: Widget property writable","text":"

Return the parent widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.parent_changed","title":"parent_changed: SignalInstance property","text":"

Signal emitted when the parent of the widget changes.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.root_native_widget","title":"root_native_widget: Any property","text":"

Return the root native backend widget.

This can be different from the .native widget if the layout is a child of some other widget, e.g. a widget used to enable scroll bars.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.tooltip","title":"tooltip: str | None property writable","text":"

Get the tooltip for this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.visible","title":"visible: bool property writable","text":"

Return whether widget is visible.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.widget_type","title":"widget_type: str property","text":"

Return type of widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.width","title":"width: int property writable","text":"

Return the current width of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.__repr__","title":"__repr__() -> str","text":"

Return representation of widget of instance.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.close","title":"close() -> None","text":"

Close widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.hide","title":"hide() -> None","text":"

Hide widget.

alias for widget.visible = False

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.render","title":"render() -> np.ndarray","text":"

Return an RGBA (MxNx4) numpy array bitmap of the rendered widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.show","title":"show(run: bool = False) -> Widget","text":"

Show widget.

alias for widget.visible = True

Parameters:

  • run (bool, default: False ) \u2013

    Whether to start the application event loop, by default False

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.Widget.shown","title":"shown() -> Iterator[Application]","text":"

Context manager to show the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ButtonWidget","title":"magicgui.widgets.bases.ButtonWidget","text":"

Bases: ValueWidget[bool]

Widget with a value, Wraps a widget implementing the ButtonWidgetProtocol.

see ButtonWidgetProtocol.

Parameters:

  • value (bool, default: Undefined ) \u2013

    The starting state of the widget.

  • text (str, default: None ) \u2013

    The text to display on the button. If not provided, will use name.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ButtonWidget.clicked","title":"clicked: SignalInstance property","text":"

Alias for changed event.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ButtonWidget.options","title":"options: dict property","text":"

Return options currently being used in this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ButtonWidget.text","title":"text: str property writable","text":"

Text of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget","title":"magicgui.widgets.bases.CategoricalWidget","text":"

Bases: ValueWidget[T]

Widget with a value and choices. Wraps CategoricalWidgetProtocol.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The initially selected choice.

  • choices (Enum, Iterable, or Callable, default: () ) \u2013

    Available choices displayed in the combo box.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.choices","title":"choices: tuple[T | None, ...] property writable","text":"

Available value choices for this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.current_choice","title":"current_choice: str property","text":"

Return the text of the currently selected choice.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.options","title":"options: dict property","text":"

Return options currently being used in this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.value","title":"value: T property writable","text":"

Return current value of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.__len__","title":"__len__() -> int","text":"

Return the number of choices.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.del_choice","title":"del_choice(choice_name: str) -> None","text":"

Delete the provided choice_name and associated data.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.get_choice","title":"get_choice(choice_name: str) -> T","text":"

Get data for the provided choice_name.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.reset_choices","title":"reset_choices(*_: Any) -> None","text":"

Reset choices to the default state.

If self._default_choices is a callable, this may NOT be the exact same set of choices as when the widget was instantiated, if the callable relies on external state.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.CategoricalWidget.set_choice","title":"set_choice(choice_name: str, data: Any | None = None) -> None","text":"

Set data for the provided choice_name.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget","title":"magicgui.widgets.bases.BaseContainerWidget","text":"

Bases: Widget, _OrientationMixin, Sequence[WidgetVar]

Widget that can contain other widgets.

Wraps a widget that implements ContainerProtocol.

Parameters:

  • widgets (Sequence[Widget], default: () ) \u2013

    A sequence of widgets with which to initialize the container, by default None.

  • layout (str, default: 'vertical' ) \u2013

    The layout for the container. must be one of {'horizontal', 'vertical'}. by default \"vertical\"

  • scrollable (bool, default: False ) \u2013

    Whether to enable scroll bars or not. If enabled, scroll bars will only appear along the layout direction, not in both directions.

  • labels (bool, default: True ) \u2013

    Whether each widget should be shown with a corresponding Label widget to the left, by default True. Note: the text for each widget defaults to widget.name, but can be overridden by setting widget.label.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.labels","title":"labels: bool property writable","text":"

Whether widgets are presented with labels.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.layout","title":"layout: str property writable","text":"

Return the layout of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.margins","title":"margins: tuple[int, int, int, int] property writable","text":"

Return margin between the content and edges of the container.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.__getattr__","title":"__getattr__(name: str) -> WidgetVar","text":"

Return attribute name. Will return a widget if present.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.__getitem__","title":"__getitem__(key: int | str | slice) -> WidgetVar | MutableSequence[WidgetVar]","text":"

Get item by integer, str, or slice.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.__len__","title":"__len__() -> int","text":"

Return the count of widgets.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseContainerWidget.reset_choices","title":"reset_choices(*_: Any) -> None","text":"

Reset choices for all Categorical subWidgets to the default state.

If widget._default_choices is a callable, this may NOT be the exact same set of choices as when the widget was instantiated, if the callable relies on external state.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget","title":"magicgui.widgets.bases.ContainerWidget","text":"

Bases: BaseContainerWidget[WidgetVar], MutableSequence[WidgetVar]

Container widget that can insert/remove child widgets.

A ContainerWidget behaves like a python list of Widget objects. Subwidgets can be accessed using integer or slice-based indexing (container[0]), as well as by widget name (container.<widget_name>). Widgets can be added with append or insert, and removed with del or pop, etc...

There is a tight connection between a ContainerWidget and an inspect.Signature object, just as there is a tight connection between individual Widgetobjects an an :class:inspect.Parameter object. The signature representation of a ContainerWidget (with the current settings as default values) is accessible with the :meth:~ContainerWidget.__signature__ method (or by using :func:inspect.signature from the standard library)

For a ContainerWidget subclass that is tightly coupled to a specific function signature (as in the \"classic\" magicgui decorator), see magicgui.widgets.FunctionGui.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__signature__","title":"__signature__: MagicSignature property","text":"

Return a MagicSignature object representing the current state of the gui.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__delattr__","title":"__delattr__(name: str) -> None","text":"

Delete a widget by name.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__delitem__","title":"__delitem__(key: int | slice) -> None","text":"

Delete a widget by integer or slice index.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__dir__","title":"__dir__() -> list[str]","text":"

Add subwidget names to the dir() call for this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__repr__","title":"__repr__() -> str","text":"

Return a repr.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__setattr__","title":"__setattr__(name: str, value: Any) -> None","text":"

Set attribute name. Prevents changing widget if present, (use del).

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.__setitem__","title":"__setitem__(key: Any, value: Any) -> NoReturn","text":"

Prevent assignment by index.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.asdict","title":"asdict() -> dict[str, Any]","text":"

Return state of widget as dict.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.from_callable","title":"from_callable(obj: Callable, gui_options: dict | None = None, **kwargs: Unpack[ContainerKwargs]) -> Container classmethod","text":"

Create a Container widget from a callable object.

In most cases, it will be preferable to create a FunctionGui instead.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.from_signature","title":"from_signature(sig: inspect.Signature, **kwargs: Unpack[ContainerKwargs]) -> Container classmethod","text":"

Create a Container widget from an inspect.Signature object.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.index","title":"index(value: Any, start: int = 0, stop: int = 9223372036854775807) -> int","text":"

Return index of a specific widget instance (or widget name).

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.insert","title":"insert(key: int, widget: WidgetVar) -> None","text":"

Insert widget at key.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.remove","title":"remove(value: Widget | str) -> None","text":"

Remove a widget instance (may also be string name of widget).

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ContainerWidget.update","title":"update(mapping: Mapping | Iterable[tuple[str, Any]] | None = None, **kwargs: Any) -> None","text":"

Update the parameters in the widget from a mapping, iterable, or kwargs.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ValuedContainerWidget","title":"magicgui.widgets.bases.ValuedContainerWidget","text":"

Bases: BaseContainerWidget[Widget], BaseValueWidget[T], Generic[T]

Container-type ValueWidget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.DialogWidget","title":"magicgui.widgets.bases.DialogWidget","text":"

Bases: ContainerWidget

Modal Container.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.DialogWidget.exec","title":"exec() -> bool","text":"

Show the dialog, and block.

Return True if the dialog was accepted, False if rejected.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.MainWindowWidget","title":"magicgui.widgets.bases.MainWindowWidget","text":"

Bases: ContainerWidget

Top level Application widget that can contain other widgets.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.MainWindowWidget.create_menu_item","title":"create_menu_item(menu_name: str, item_name: str, callback: Callable | None = None, shortcut: str | None = None) -> None","text":"

Create a menu item item_name under menu menu_name.

menu_name will be created if it does not already exist.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget","title":"magicgui.widgets.bases.RangedWidget","text":"

Bases: ValueWidget[T]

Widget with a constrained value. Wraps RangedWidgetProtocol.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.adaptive_step","title":"adaptive_step: bool property writable","text":"

Whether the step size is adaptive.

Adaptive decimal step means that the step size will continuously be adjusted to one power of ten below the current value. So when the value is 1100, the step is set to 100, so stepping up once increases it to 1200. For 1200 stepping up takes it to 1300. For negative values, stepping down from -1100 goes to -1200.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.max","title":"max: float property writable","text":"

Maximum allowable value for the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.min","title":"min: float property writable","text":"

Minimum allowable value for the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.options","title":"options: dict property","text":"

Return options currently being used in this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.range","title":"range: tuple[float, float] property writable","text":"

Range of allowable values for the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.step","title":"step: float | None property writable","text":"

Step size for widget values (None if adaptive step is turned on).

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.RangedWidget.set_value","title":"set_value(value: T) -> None","text":"

Set widget value, will raise Value error if not within min/max.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.SliderWidget","title":"magicgui.widgets.bases.SliderWidget","text":"

Bases: RangedWidget[T], _OrientationMixin

Widget with a constrained value and orientation. Wraps SliderWidgetProtocol.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • min (float, default: Undefined ) \u2013

    The minimum allowable value, by default 0 (or value if value is less than 0)

  • max (float, default: Undefined ) \u2013

    The maximum allowable value, by default 999 (or value if value is greater than 999)

  • step (float, default: Undefined ) \u2013

    The step size for incrementing the value, by default adaptive step is used

  • orientation ((str, {'horizontal', 'vertical'}), default: 'horizontal' ) \u2013

    The orientation for the slider, by default \"horizontal\"

  • readout (bool, default: True ) \u2013

    Whether to show the editable spinbox next to the slider

  • tracking (bool, default: True ) \u2013

    If tracking is enabled (the default), the slider emits the changed signal while the slider is being dragged. If tracking is disabled, the slider emits the changed signal only after the user releases the slider.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.SliderWidget.options","title":"options: dict property","text":"

Return options currently being used in this widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.SliderWidget.readout","title":"readout: bool property writable","text":"

Get visibility state of readout widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.SliderWidget.tracking","title":"tracking: bool property writable","text":"

Return whether slider tracking is enabled.

If tracking is enabled (the default), the slider emits the changed() signal while the slider is being dragged. If tracking is disabled, the slider emits the changed() signal only when the user releases the slider.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ValueWidget","title":"magicgui.widgets.bases.ValueWidget","text":"

Bases: BaseValueWidget[T]

Widget with a value, Wraps ValueWidgetProtocol.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.ValueWidget.get_value","title":"get_value() -> T","text":"

Callable version of self.value.

The main API is to use self.value, however, this is here in order to provide an escape hatch if trying to access the widget's value inside of a callback bound to self._bound_value.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget","title":"magicgui.widgets.bases.BaseValueWidget","text":"

Bases: Widget, ABC, Generic[T]

An abstract base class for widgets that have a value.

Subclasses must implement the get_value and set_value methods.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget.

  • bind (Callable[[ValueWidget], Any] | Any, default: Undefined ) \u2013

    A value or callback to bind this widget. If provided, whenever widget.value is accessed, the value provided here will be returned instead. bind may be a callable, in which case bind(self) will be returned (i.e. your bound callback must accept a single parameter, which is this widget instance).

  • nullable (bool, default: False ) \u2013

    If True, the widget will accepts None as a valid value, by default False.

  • **base_widget_kwargs (Any, default: {} ) \u2013

    All additional keyword arguments are passed to the base magicgui.widgets.Widget constructor.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.annotation","title":"annotation: Any property writable","text":"

Return type annotation for the parameter represented by the widget.

ForwardRefs will be resolve when setting the annotation. If the widget is nullable (had a type annototation of Optional[Type]), annotation will return the first argument in the Optional clause.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.value","title":"value: T property writable","text":"

Return current value of the widget. This may be interpreted by backends.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.__repr__","title":"__repr__() -> str","text":"

Return representation of widget of instance.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.bind","title":"bind(value: T | Callable[[BaseValueWidget], T], call: bool = True) -> None","text":"

Binds value to self.value.

If a value is bound to this widget, then whenever widget.value is accessed, the value provided here will be returned. value can be a callable, in which case value(self) will be returned (i.e. your callback must accept a single parameter, which is this widget instance.).

If you provide a callable and you don't want it to be called (but rather just returned as a callable object, then use call=False when binding your value.

Note: if you need to access the \"original\" widget.value within your callback, please use widget.get_value() instead of the widget.value property, in order to avoid a RuntimeError.

Parameters:

  • value (Any) \u2013

    The value (or callback) to return when accessing this widget's value.

  • call (bool, default: True ) \u2013

    If value is a callable and call is True, the callback will be called as callback(self) when accessing self.value. If False, the callback will simply be returned as a callable object, by default, True.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.get_value","title":"get_value() -> T abstractmethod","text":"

Callable version of self.value.

The main API is to use self.value, however, this is here in order to provide an escape hatch if trying to access the widget's value inside of a callback bound to self._bound_value.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.set_value","title":"set_value(value: Any) -> None abstractmethod","text":"

Normalize and set the value of the widget.

"},{"location":"api/widgets/bases/#magicgui.widgets.bases.BaseValueWidget.unbind","title":"unbind() -> None","text":"

Unbinds any bound values. (see ValueWidget.bind).

"},{"location":"api/widgets/create_widget/","title":"magicgui.widgets.create_widget","text":""},{"location":"api/widgets/create_widget/#magicgui.widgets.create_widget","title":"magicgui.widgets.create_widget(value=Undefined, annotation=None, name='', param_kind='POSITIONAL_OR_KEYWORD', label=None, gui_only=False, app=None, widget_type=None, options=None, is_result=False, raise_on_unknown=True)","text":"

Create and return appropriate widget subclass.

This factory function can be used to create a widget appropriate for the provided value and/or annotation provided. See Type Mapping Docs for details on how the widget type is determined from type annotations.

Parameters:

  • value (Any, default: Undefined ) \u2013

    The starting value for the widget, by default None

  • annotation (Any, default: None ) \u2013

    The type annotation for the parameter represented by the widget, by default None.

  • name (str, default: '' ) \u2013

    The name of the parameter represented by this widget. by default \"\"

  • param_kind (str, default: 'POSITIONAL_OR_KEYWORD' ) \u2013

    The :attr:inspect.Parameter.kind represented by this widget. Used in building signatures from multiple widgets, by default \"POSITIONAL_OR_KEYWORD\"

  • label (str, default: None ) \u2013

    A string to use for an associated Label widget (if this widget is being shown in a Container widget, and labels are on). By default, name will be used. Note: name refers the name of the parameter, as might be used in a signature, whereas label is just the label for that widget in the GUI.

  • gui_only (bool, default: False ) \u2013

    Whether the widget should be considered \"only for the gui\", or if it should be included in any widget container signatures, by default False

  • app (str, default: None ) \u2013

    The backend to use, by default None

  • widget_type (str or Type[WidgetProtocol] or None, default: None ) \u2013

    A class implementing a widget protocol or a string with the name of a magicgui widget type (e.g. \"Label\", \"PushButton\", etc...). If provided, this widget type will be used instead of the type autodetermined from value and/or annotation above.

  • options (dict, default: None ) \u2013

    Dict of options to pass to the Widget constructor, by default dict()

  • is_result (boolean, default: False ) \u2013

    Whether the widget belongs to an input or an output. By default, an input is assumed.

  • raise_on_unknown (bool, default: True ) \u2013

    Raise exception if no widget is found for the given type, by default True

Returns:

  • Widget \u2013

    An instantiated widget subclass

Raises:

  • TypeError \u2013

    If the provided or autodetected widget_type does not implement any known widget protocols

Examples:

from magicgui.widgets import create_widget\n\n# create a widget from a string value\nwdg = create_widget(value=\"hello world\")\nassert wdg.value == \"hello world\"\n\n# create a widget from a string annotation\nwdg = create_widget(annotation=str)\nassert wdg.value == \"\"\n
"},{"location":"generated_examples/","title":"Getting started","text":"

A gallery of examples for magicgui.

Basic example

Basic widgets demo

"},{"location":"generated_examples/#demo-applications","title":"Demo applications","text":"

Example applications built with magicgui.

Input values dialog

Quantities with pint

Callable functions demo

Snell's law demonstration using magicgui

Hotdog or not app

Chaining functions together

"},{"location":"generated_examples/#demo-widget-types","title":"Demo widget types","text":"

Example gallery demonstrating the available widget types in magicgui.

Image widget

Range slider widget

Custom text labels for widgets

Log slider widget

Optional user choice

Multiple selection widget

File dialog widget

Directory dialog widget

Password login

File dialog widget

Dropdown selection widget

Table widget

"},{"location":"generated_examples/#matplotlib-and-magicgui","title":"matplotlib and magicgui","text":"

Examples involving matplotlib graphs and magicgui.

matplotlib figure example

Waveforms example

"},{"location":"generated_examples/#napari-and-magicgui","title":"napari and magicgui","text":"

Examples integrating magicgui with napari.

napari forward reference demo

napari Qt demo

napari parameter sweeps

napari image arithmetic widget

"},{"location":"generated_examples/#jupyter-notebooks-and-magicgui","title":"Jupyter notebooks and magicgui","text":"

Examples using jupyter notebooks together with magicgui.

Jupyter notebooks and magicgui

"},{"location":"generated_examples/#progress-bar-examples","title":"Progress bar examples","text":"

Examples of progress bars in magicgui.

Manual progress bar

Simple progress bar

Indeterminate progress bar

Nested progress bars

"},{"location":"generated_examples/#under-the-hood","title":"Under the hood","text":"

Learn more advanced usage patterns for magicgui, including self referencing widgets and decorating class methods with magicgui.

Self reference magicgui widgets

Deocrate class methods with magicgui

Download all examples in Python source code: generated_examples_python.zip

Download all examples in Jupyter notebooks: generated_examples_jupyter.zip

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/basic_example/","title":"Basic example","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/basic_example/#basic-example","title":"Basic example","text":"

A basic example using magicgui.

Out:

<FunctionGui example(x: int = 0, y='hi')>\n

from magicgui import magicgui\n\n\n@magicgui\ndef example(x: int, y=\"hi\"):\n    \"\"\"Basic example function.\"\"\"\n    return x, y\n\n\nexample.changed.connect(print)\nexample.show(run=True)\n

Total running time of the script: ( 0 minutes 0.766 seconds)

Download Python source code: basic_example.py

Download Jupyter notebook: basic_example.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/basic_widgets_demo/","title":"Basic widgets demo","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/basic_widgets_demo/#basic-widgets-demo","title":"Basic widgets demo","text":"

Widget demonstration with magicgui.

This code demonstrates a few of the widget types that magicgui can create based on the parameter types in your function.

Out:

<MainFunctionGui widget_demo(boolean=True, integer=1, spin_float=3.14, slider_float=43.5, slider_int=550, string='Text goes here', dropdown=<Medium.Glass: 1.52>, radio_option=2, date=datetime.date(1999, 12, 31), time=datetime.time(1, 30, 20), datetime=datetime.datetime(2024, 11, 23, 21, 41, 22, 999000), filename=PosixPath('/Users/runner'))>\n

import datetime\nfrom enum import Enum\nfrom pathlib import Path\n\nfrom magicgui import magicgui\n\n\nclass Medium(Enum):\n    \"\"\"Enum for various media and their refractive indices.\"\"\"\n\n    Glass = 1.520\n    Oil = 1.515\n    Water = 1.333\n    Air = 1.0003\n\n\n@magicgui(\n    main_window=True,\n    call_button=\"Calculate\",\n    layout=\"vertical\",\n    result_widget=True,\n    slider_float={\"widget_type\": \"FloatSlider\", \"max\": 100},\n    slider_int={\"widget_type\": \"Slider\", \"readout\": False},\n    radio_option={\n        \"widget_type\": \"RadioButtons\",\n        \"orientation\": \"horizontal\",\n        \"choices\": [(\"first option\", 1), (\"second option\", 2)],\n    },\n    filename={\"label\": \"Pick a file:\"},\n)\ndef widget_demo(\n    boolean=True,\n    integer=1,\n    spin_float=3.14159,\n    slider_float=43.5,\n    slider_int=550,\n    string=\"Text goes here\",\n    dropdown=Medium.Glass,\n    radio_option=2,\n    date=datetime.date(1999, 12, 31),\n    time=datetime.time(1, 30, 20),\n    datetime=datetime.datetime.now(),\n    filename=Path.home(),\n):\n    \"\"\"We can use numpy docstrings to provide tooltips.\n\n    Parameters\n    ----------\n    boolean : bool, optional\n        A checkbox for booleans, by default True\n    integer : int, optional\n        Some integer, by default 1\n    spin_float : float, optional\n        This one is a float, by default \"pi\"\n    slider_float : float, optional\n        Hey look! I'm a slider, by default 43.5\n    slider_int : float, optional\n        I only take integers, and I've hidden my readout, by default 550\n    string : str, optional\n        We'll use this string carefully, by default \"Text goes here\"\n    dropdown : Enum, optional\n        Pick a medium, by default Medium.Glass\n    radio_option : int\n        A set of radio buttons.\n    date : datetime.date, optional\n        Your birthday, by default datetime.date(1999, 12, 31)\n    time : datetime.time, optional\n        Some time, by default datetime.time(1, 30, 20)\n    datetime : datetime.datetime, optional\n        A very specific time and date, by default ``datetime.datetime.now()``\n    filename : str, optional\n        Pick a path, by default Path.home()\n    \"\"\"\n    return locals().values()\n\n\nwidget_demo.changed.connect(print)\nwidget_demo.show(run=True)\n

Total running time of the script: ( 0 minutes 0.122 seconds)

Download Python source code: basic_widgets_demo.py

Download Jupyter notebook: basic_widgets_demo.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/mg_execution_times/","title":"Computation times","text":"

00:00.888 total execution time for generated_examples files:

+-------------------------------------------------------------------------------------+-----------+--------+ | basic_example (docs/examples/basic_example.py) | 00:00.766 | 0.0 MB | +-------------------------------------------------------------------------------------+-----------+--------+ | basic_widgets_demo (docs/examples/basic_widgets_demo.py) | 00:00.122 | 0.0 MB | +-------------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/applications/callable/","title":"Callable functions demo","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/applications/callable/#callable-functions-demo","title":"Callable functions demo","text":"

This example demonstrates handling callable functions with magicgui.

Out:

<FunctionGui example(func='f')>\n

from magicgui import magicgui\n\n\ndef f(x: int, y=\"a string\") -> str:\n    \"\"\"Example function F.\"\"\"\n    return f\"{y} {x}\"\n\n\ndef g(x: int = 6, y=\"another string\") -> str:\n    \"\"\"Example function G.\"\"\"\n    return f\"{y} asdfsdf {x}\"\n\n\n@magicgui(call_button=True, func={\"choices\": [\"f\", \"g\"]})\ndef example(func=\"f\"):\n    \"\"\"\u00cbxample function.\"\"\"\n    pass\n\n\ndef update(f: str):\n    \"\"\"Update function.\"\"\"\n    if len(example) > 2:\n        del example[1]\n    example.insert(1, magicgui(globals()[f]))\n\n\nexample.func.changed.connect(update)\nexample.show(run=True)\n

Total running time of the script: ( 0 minutes 0.037 seconds)

Download Python source code: callable.py

Download Jupyter notebook: callable.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/applications/chaining/","title":"Chaining functions together","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/applications/chaining/#chaining-functions-together","title":"Chaining functions together","text":"

This example demonstrates chaining multiple functions together.

Out:

calling func_a\ncalling func_b\ncalling func_c\n\n\n<Container (func_a: NoneType, func_b: NoneType, func_c: NoneType)>\n

from magicgui import magicgui, widgets\n\n\n@magicgui(auto_call=True)\ndef func_a(x: int = 64, y: int = 64):\n    \"\"\"Callable function A.\"\"\"\n    print(\"calling func_a\")\n    return x + y\n\n\n@magicgui(auto_call=True, input={\"visible\": False, \"label\": \" \", \"max\": 100000})\ndef func_b(input: int, mult=1.0):\n    \"\"\"Callable function B.\"\"\"\n    print(\"calling func_b\")\n    result = input * mult\n    # since these function defs live in globals(), you can update them directly\n    func_c.input.value = result\n    return result\n\n\n# alternatively, you can the `widget.called` signal to connect a callback function\n# where the result of the function being called is at `value`\n@func_a.called.connect\ndef _on_func_a(value: str):\n    func_b.input.value = value\n\n\n@magicgui(\n    auto_call=True,\n    input={\"visible\": False, \"max\": 100000},\n    result_widget=True,\n    labels=False,\n)\ndef func_c(input: int, format: str = \"({} + {}) * {} is {}\") -> str:\n    \"\"\"Callable function C.\"\"\"\n    print(\"calling func_c\\n\")\n    return format.format(func_a.x.value, func_a.y.value, func_b.mult.value, input)\n\n\ncontainer = widgets.Container(\n    widgets=[func_a, func_b, func_c], layout=\"vertical\", labels=False\n)\ncontainer.native.setMinimumWidth(500)\nfunc_a()\ncontainer.show(run=True)\n\n# notice which functions get called when you change each widget.\n

Total running time of the script: ( 0 minutes 0.054 seconds)

Download Python source code: chaining.py

Download Jupyter notebook: chaining.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/applications/hotdog/","title":"Hotdog or not app","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/applications/hotdog/#hotdog-or-not-app","title":"Hotdog or not app","text":"

Demo app to upload an image and classify if it's an hotdog or not.

import pathlib\nfrom enum import Enum\n\nfrom magicgui import magicgui\n\n\nclass HotdogOptions(Enum):\n    \"\"\"All hotdog possibilities.\"\"\"\n\n    Hotdog = 1\n    NotHotdog = 0\n\n\n@magicgui(main_window=True, layout=\"form\", call_button=\"Classify\", result_widget=True)\ndef is_hotdog(img: pathlib.Path) -> HotdogOptions:\n    \"\"\"Classify possible hotdog images.\n\n    Upload an image and check whether it's an hotdog. For example, this image\n    will be classified as one: <br><br>\n\n    <img src=\"resources/hotdog.jpg\">\n\n    Parameters\n    ----------\n    img : pathlib.Path\n        Path to a possible hotdog image\n\n    Returns\n    -------\n    HotdogOptions\n        True if image contains an hotdog in it\n    \"\"\"\n    if \"hotdog\" in img.stem:\n        return HotdogOptions.Hotdog\n    return HotdogOptions.NotHotdog\n\n\nif __name__ == \"__main__\":\n    is_hotdog.show(run=True)\n

Total running time of the script: ( 0 minutes 0.040 seconds)

Download Python source code: hotdog.py

Download Jupyter notebook: hotdog.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/applications/mg_execution_times/","title":"Computation times","text":"

00:00.342 total execution time for generated_examples_applications files:

+-----------------------------------------------------------------------------------+-----------+--------+ | pint_quantity (docs/examples/applications/pint_quantity.py) | 00:00.162 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ | chaining (docs/examples/applications/chaining.py) | 00:00.054 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ | snells_law (docs/examples/applications/snells_law.py) | 00:00.049 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ | hotdog (docs/examples/applications/hotdog.py) | 00:00.040 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ | callable (docs/examples/applications/callable.py) | 00:00.037 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+ | values_dialog (docs/examples/applications/values_dialog.py) | 00:00.000 | 0.0 MB | +-----------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/applications/pint_quantity/","title":"Quantities with pint","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/applications/pint_quantity/#quantities-with-pint","title":"Quantities with pint","text":"

Pint is a Python package to define, operate and manipulate physical quantities: the product of a numerical value and a unit of measurement. It allows arithmetic operations between them and conversions from and to different units. https://pint.readthedocs.io/en/stable/

Out:

<FunctionGui widget(q=<Quantity(1, 'millisecond')>)>\n

from pint import Quantity\n\nfrom magicgui import magicgui\n\n\n@magicgui\ndef widget(q=Quantity(\"1 ms\")):\n    \"\"\"Widget allowing users to input quantity measurements.\"\"\"\n    print(q)\n\n\nwidget.show(run=True)\n

Total running time of the script: ( 0 minutes 0.162 seconds)

Download Python source code: pint_quantity.py

Download Jupyter notebook: pint_quantity.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/applications/snells_law/","title":"Snell's law demonstration using magicgui","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/applications/snells_law/#snells-law-demonstration-using-magicgui","title":"Snell's law demonstration using magicgui","text":"

Demo app for calculating angles of refraction according to Snell's law.

Out:

<FunctionGui snells_law(aoi=1.0, n1=<Medium.Glass: 1.52>, n2=<Medium.Water: 1.333>, degrees=True)>\n

import math\nfrom enum import Enum\n\nfrom magicgui import magicgui\n\n\nclass Medium(Enum):\n    \"\"\"Enum for various media and their refractive indices.\"\"\"\n\n    Glass = 1.520\n    Oil = 1.515\n    Water = 1.333\n    Air = 1.0003\n\n\n@magicgui(call_button=\"calculate\", result_widget=True)\ndef snells_law(aoi=1.0, n1=Medium.Glass, n2=Medium.Water, degrees=True):\n    \"\"\"Calculate the angle of refraction given two media and an AOI.\"\"\"\n    if degrees:\n        aoi = math.radians(aoi)\n    try:\n        n1 = n1.value\n        n2 = n2.value\n        result = math.asin(n1 * math.sin(aoi) / n2)\n        return round(math.degrees(result) if degrees else result, 2)\n    except ValueError:  # math domain error\n        return \"TIR!\"\n\n\nsnells_law.show(run=True)\n

Total running time of the script: ( 0 minutes 0.049 seconds)

Download Python source code: snells_law.py

Download Jupyter notebook: snells_law.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/applications/values_dialog/","title":"Input values dialog","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/applications/values_dialog/#input-values-dialog","title":"Input values dialog","text":"

A basic example of a user input dialog.

This will pause code execution until the user responds.

"},{"location":"generated_examples/applications/values_dialog/#_1","title":"Input values dialog","text":"
from magicgui.widgets import request_values\n\nvals = request_values(\n    age=int,\n    name={\"annotation\": str, \"label\": \"Enter your name:\"},\n    title=\"Hi, who are you?\",\n)\nprint(repr(vals))\n

Total running time of the script: ( 0 minutes 0.000 seconds)

Download Python source code: values_dialog.py

Download Jupyter notebook: values_dialog.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/change_label/","title":"Custom text labels for widgets","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/change_label/#custom-text-labels-for-widgets","title":"Custom text labels for widgets","text":"

An example showing how to create custom text labels for your widgets.

Out:

<FunctionGui example(x=1, y='hi')>\n

from magicgui import magicgui\n\n\n# use a different label than the default (the parameter name) in the UI\n@magicgui(x={\"label\": \"widget to set x\"})\ndef example(x=1, y=\"hi\"):\n    \"\"\"Example function.\"\"\"\n    return x, y\n\n\nexample.changed.connect(print)\nexample.show(run=True)\n

Total running time of the script: ( 0 minutes 0.049 seconds)

Download Python source code: change_label.py

Download Jupyter notebook: change_label.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/choices/","title":"Dropdown selection widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/choices/#dropdown-selection-widget","title":"Dropdown selection widget","text":"

Choices for dropdowns can be provided in a few different ways.

Out:

<Container (as_list: NoneType, as_enum: NoneType, as_2tuple: NoneType, as_function: NoneType)>\n

from enum import Enum\n\nfrom magicgui import magicgui, widgets\n\n\nclass Medium(Enum):\n    \"\"\"Enum for various media and their refractive indices.\"\"\"\n\n    Oil = 1.515\n    Water = 1.333\n    Air = 1.0003\n\n\n@magicgui(ri={\"choices\": [\"Oil\", \"Water\", \"Air\"]}, auto_call=True)\ndef as_list(ri=\"Water\"):\n    \"\"\"Function decorated with magicgui list of choices.\"\"\"\n    print(\"refractive index is\", Medium[ri].value)\n\n\n@magicgui(auto_call=True)\ndef as_enum(ri: Medium = Medium.Water):\n    \"\"\"Function decorated with magicgui and enumeration.\"\"\"\n    print(\"refractive index is\", ri.value)\n\n\n@magicgui(\n    ri={\"choices\": [(\"Oil\", 1.515), (\"Water\", 1.33), (\"Air\", 1.0)]}, auto_call=True\n)\ndef as_2tuple(ri=1.33):\n    \"\"\"Function decorated with magicgui tuple of choices.\"\"\"\n    print(\"refractive index is\", ri)\n\n\ndef get_choices(gui):\n    \"\"\"Function returning tuple of material and refractive index value.\"\"\"\n    return [(\"Oil\", 1.515), (\"Water\", 1.33), (\"Air\", 1.0)]\n\n\n@magicgui(ri={\"choices\": get_choices}, auto_call=True)\ndef as_function(ri: float):\n    \"\"\"Function to calculate refractive index.\"\"\"\n    print(\"refractive index is\", ri)\n\n\ncontainer = widgets.Container(\n    widgets=[as_list, as_enum, as_2tuple, as_function], layout=\"vertical\"\n)\ncontainer.show(run=True)\n

Total running time of the script: ( 0 minutes 0.042 seconds)

Download Python source code: choices.py

Download Jupyter notebook: choices.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/directory_dialog/","title":"Directory dialog widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/directory_dialog/#directory-dialog-widget","title":"Directory dialog widget","text":"

A dialog to select a directory.

Out:

<FunctionGui directorypicker(directory=PosixPath('~'))>\n

from pathlib import Path\n\nfrom magicgui import magicgui\n\n\n# Select a directory, instead of file(s)\n@magicgui(directory={\"mode\": \"d\", \"label\": \"Choose a directory\"})\ndef directorypicker(directory=Path(\"~\")):\n    \"\"\"Take a directory name and do something with it.\"\"\"\n    print(\"The directory name is:\", directory)\n    return directory\n\n\ndirectorypicker.directory.changed.connect(print)\ndirectorypicker.show(run=True)\n

Total running time of the script: ( 0 minutes 0.054 seconds)

Download Python source code: directory_dialog.py

Download Jupyter notebook: directory_dialog.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/file_dialog/","title":"File dialog","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/file_dialog/#file-dialog-widget","title":"File dialog widget","text":"

A dialog to select a file.

Out:

<FunctionGui filepicker(filename=PosixPath('~')) -> pathlib._local.Path>\n

from pathlib import Path\n\nfrom magicgui import magicgui\n\n\n@magicgui(filename={\"mode\": \"r\"})\ndef filepicker(filename=Path(\"~\")) -> Path:\n    \"\"\"Take a filename and do something with it.\"\"\"\n    print(\"The filename is:\", filename)\n    return filename\n\n\nfilepicker.filename.changed.connect(print)\nfilepicker.show(run=True)\n

Total running time of the script: ( 0 minutes 0.035 seconds)

Download Python source code: file_dialog.py

Download Jupyter notebook: file_dialog.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/files_dialog/","title":"File dialog widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/files_dialog/#file-dialog-widget","title":"File dialog widget","text":"

A dialog to select multiple files.

Out:

<FunctionGui filespicker(filenames: collections.abc.Sequence[pathlib._local.Path] = ()) -> collections.abc.Sequence[pathlib._local.Path]>\n

from collections.abc import Sequence\nfrom pathlib import Path\n\nfrom magicgui import magicgui\n\n\n# Sequence of paths\n# We change the label using \"label\" for added clarity\n# the filter argument restricts file types\n@magicgui(filenames={\"label\": \"Choose Tiff files:\", \"filter\": \"*.tif\"})\ndef filespicker(filenames: Sequence[Path]) -> Sequence[Path]:\n    \"\"\"Take a filename and do something with it.\"\"\"\n    print(\"The filenames are:\", filenames)\n    return filenames\n\n\nfilespicker.filenames.changed.connect(print)\nfilespicker.show(run=True)\n

Total running time of the script: ( 0 minutes 0.032 seconds)

Download Python source code: files_dialog.py

Download Jupyter notebook: files_dialog.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/image/","title":"Image widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/image/#image-widget","title":"Image widget","text":"

Example of creating an Image Widget from a file.

(This requires pillow, or that magicgui was installed as magicgui[image])

Out:

Image(200x232x3, name='')\n

from magicgui.widgets import Image\n\nimage = Image(value=\"../../images/_test.jpg\")\nimage.scale_widget_to_image_size()\nimage.show(run=True)\n

Total running time of the script: ( 0 minutes 0.040 seconds)

Download Python source code: image.py

Download Jupyter notebook: image.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/log_slider/","title":"Log slider widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/log_slider/#log-slider-widget","title":"Log slider widget","text":"

A logarithmic scale range slider widget.

Out:

<FunctionGui slider(input=1.0)>\n

from magicgui import magicgui\n\n\n@magicgui(\n    auto_call=True,\n    result_widget=True,\n    input={\"widget_type\": \"LogSlider\", \"max\": 10000, \"min\": 1, \"tracking\": False},\n)\ndef slider(input=1):\n    \"\"\"Logarithmic scale slider.\"\"\"\n    return round(input, 4)\n\n\nslider.show(run=True)\n

Total running time of the script: ( 0 minutes 0.031 seconds)

Download Python source code: log_slider.py

Download Jupyter notebook: log_slider.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/login/","title":"Password login","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/login/#password-login","title":"Password login","text":"

A password login field widget.

Out:

<FunctionGui login(username: str = '', password: str = '', password2: str = '')>\n

from magicgui import magicgui\n\n\n# note that \"password\" is a special keyword argument\n# it will create a password field in the gui by default\n# (unless you override \"widget_type\")\n# whereas \"password2\" will be a normal text field\n# (unless you override \"widget_type\")\n@magicgui(password2={\"widget_type\": \"Password\"})\ndef login(username: str, password: str, password2: str):\n    \"\"\"User login credentials.\"\"\"\n    ...\n\n\nlogin.show(run=True)\n

Total running time of the script: ( 0 minutes 0.040 seconds)

Download Python source code: login.py

Download Jupyter notebook: login.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/mg_execution_times/","title":"Computation times","text":"

00:00.498 total execution time for generated_examples_demo_widgets files:

+--------------------------------------------------------------------------------------------+-----------+--------+ | directory_dialog (docs/examples/demo_widgets/directory_dialog.py) | 00:00.054 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | change_label (docs/examples/demo_widgets/change_label.py) | 00:00.049 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | selection (docs/examples/demo_widgets/selection.py) | 00:00.048 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | range_slider (docs/examples/demo_widgets/range_slider.py) | 00:00.048 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | table (docs/examples/demo_widgets/table.py) | 00:00.045 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | choices (docs/examples/demo_widgets/choices.py) | 00:00.042 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | login (docs/examples/demo_widgets/login.py) | 00:00.040 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | image (docs/examples/demo_widgets/image.py) | 00:00.040 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | file_dialog (docs/examples/demo_widgets/file_dialog.py) | 00:00.035 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | optional (docs/examples/demo_widgets/optional.py) | 00:00.034 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | files_dialog (docs/examples/demo_widgets/files_dialog.py) | 00:00.032 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+ | log_slider (docs/examples/demo_widgets/log_slider.py) | 00:00.031 | 0.0 MB | +--------------------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/demo_widgets/optional/","title":"Optional user choice","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/optional/#optional-user-choice","title":"Optional user choice","text":"

Optional user input using a dropdown selection widget.

Out:

<FunctionGui f(path: str = None)>\n

from typing import Optional\n\nfrom magicgui import magicgui\n\n\n# Using optional will add a '----' to the combobox, which returns \"None\"\n@magicgui(path={\"choices\": [\"a\", \"b\"]})\ndef f(path: Optional[str] = None):\n    \"\"\"\u00d6ptional user input function.\"\"\"\n    print(path, type(path))\n\n\nf.show(run=True)\n

Total running time of the script: ( 0 minutes 0.034 seconds)

Download Python source code: optional.py

Download Jupyter notebook: optional.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/range_slider/","title":"Range slider widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/range_slider/#range-slider-widget","title":"Range slider widget","text":"

A double ended range slider widget.

Out:

<FunctionGui func(range_value: tuple[int, int] = (20, 380))>\n

from magicgui import magicgui\n\n\n@magicgui(auto_call=True, range_value={\"widget_type\": \"RangeSlider\", \"max\": 500})\ndef func(range_value: tuple[int, int] = (20, 380)):\n    \"\"\"Double ended range slider.\"\"\"\n    print(range_value)\n\n\nfunc.show(run=True)\n

Total running time of the script: ( 0 minutes 0.048 seconds)

Download Python source code: range_slider.py

Download Jupyter notebook: range_slider.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/selection/","title":"Multiple selection widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/selection/#multiple-selection-widget","title":"Multiple selection widget","text":"

A selection widget allowing multiple selections by the user.

Out:

<FunctionGui my_widget(pick_some=['first'])>\n

from magicgui import magicgui\n\n\n@magicgui(\n    pick_some={\n        \"choices\": (\"first\", \"second\", \"third\", \"fourth\"),\n        \"allow_multiple\": True,\n    }\n)\ndef my_widget(pick_some=(\"first\")):\n    \"\"\"Dropdown selection function.\"\"\"\n    print(\"you selected\", pick_some)\n\n\nmy_widget.show(run=True)\n

Total running time of the script: ( 0 minutes 0.048 seconds)

Download Python source code: selection.py

Download Jupyter notebook: selection.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/demo_widgets/table/","title":"Table widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/demo_widgets/table/#table-widget","title":"Table widget","text":"

Demonstrating a few ways to input tables.

Out:

Table(shape=(6, 3) at 0x11793fe00)\n

import numpy as np\n\nfrom magicgui.widgets import Table\n\n# all of these are valid data types\ndict_of_lists = {\"col_1\": [1, 4], \"col_2\": [2, 5], \"col_3\": [3, 6]}\n# column-dict-of-row-dicts\ndict_of_dict = {\n    \"col_1\": {\"r1\": 1, \"r2\": 4},\n    \"col_2\": {\"r1\": 2, \"r2\": 5},\n    \"col_3\": {\"r1\": 3, \"r2\": 6},\n}\n# list-of-lists\nlist_of_list = [[1, 2, 3], [4, 5, 6]]\n# Records: List-of-column-dict\nlist_of_records = [\n    {\"col_1\": 1, \"col_2\": 2, \"col_3\": 3},\n    {\"col_1\": 4, \"col_2\": 5, \"col_3\": 6},\n]\n\n# 3-tuple of data, index, column\ndata_index_column_tuple = (([[1, 2, 3], [4, 5, 6]], (\"r1\", \"r2\"), (\"c1\", \"c2\", \"c3\")),)\n# split-dict\nsplit_dict = {\n    \"data\": [[1, 2, 3], [4, 5, 6]],\n    \"index\": (\"r1\", \"r2\"),\n    \"columns\": (\"c1\", \"c2\", \"c3\"),\n}\n\ntable = Table(value=dict_of_lists)\n\n# it behaves like a dict:\ntable[\"new_col\"] = [5, 5]\nassert table.pop(\"new_col\") == [5, 5]\n# keys and items have both regular (column) and \"row\" modes\ncol_item_view = table.items()  # iterate col_header/column\nrow_item_view = table.items(\"row\")  # iterate row_header/row\n\n# we can just call dict() to get back our dict of lists\nassert dict(table) == dict_of_lists\n# or use one of many other exports in `to_dict`\nassert table.to_dict(\"records\") == list_of_records\n\n# change headers\ntable.row_headers = (\"row1\", \"row2\")\ntable.column_headers = (\"a\", \"b\", \"c\")\n\n# setting value clears and resets the table:\ntable.value = np.arange(18).reshape(6, 3)\n# we can get/set/delete the 2D data table using numpy-style indexing:\n# get every other row\nassert table.data[::2] == [[0, 1, 2], [6, 7, 8], [12, 13, 14]]\n# set every other column in the 3rd row\ntable.data[2, ::2] = [99, 99]\n\n# export to numpy or pandas\n# table.data.to_numpy()\n# table.to_dataframe()\n\n# the table.changed event emits a dict of information on any cell change\n# e.g. {'data': 'sdfg', 'row': 1, 'column': 0, 'column_header': '1', 'row_header': '1'}\ntable.changed.connect(print)\ntable.show(run=True)\n

Total running time of the script: ( 0 minutes 0.045 seconds)

Download Python source code: table.py

Download Jupyter notebook: table.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/matplotlib/mg_execution_times/","title":"Computation times","text":"

00:00.252 total execution time for generated_examples_matplotlib files:

+------------------------------------------------------------------------+-----------+--------+ | waveform (docs/examples/matplotlib/waveform.py) | 00:00.155 | 0.0 MB | +------------------------------------------------------------------------+-----------+--------+ | mpl_figure (docs/examples/matplotlib/mpl_figure.py) | 00:00.097 | 0.0 MB | +------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/matplotlib/mpl_figure/","title":"matplotlib figure example","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/matplotlib/mpl_figure/#matplotlib-figure-example","title":"matplotlib figure example","text":"

Basic example of adding a generic QWidget to a container.

Main lesson: add your QWidget to container.native.layout() as shown on line 30

Out:

<FunctionGui f(position: int = 0)>\n

import matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.backends.backend_qt5agg import FigureCanvas\n\nfrom magicgui import magicgui\n\nx = np.linspace(0, 5, 256)\ny = np.linspace(0, 5, 256)[:, np.newaxis]\ndata = np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)\n\nmpl_fig = plt.figure()\nax = mpl_fig.add_subplot(111)\n(line,) = ax.plot(data[123])  # linescan through the middle of the image\n\n\n@magicgui(position={\"widget_type\": \"Slider\", \"max\": 255}, auto_call=True)\ndef f(position: int):\n    \"\"\"Function demonstrating magicgui combined with matplotlib.\"\"\"\n    line.set_ydata(data[position])\n    line.figure.canvas.draw()\n\n\n# rather than using the Container.append (`f.append`) ...\n# grab the native layout and add the QWidget to it\nf.native.layout().addWidget(FigureCanvas(mpl_fig))\n\nf.show(run=True)\n

Total running time of the script: ( 0 minutes 0.097 seconds)

Download Python source code: mpl_figure.py

Download Jupyter notebook: mpl_figure.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/matplotlib/waveform/","title":"Waveforms example","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/matplotlib/waveform/#waveforms-example","title":"Waveforms example","text":"

Simple waveform generator widget, with plotting.

Out:

<Container (signal_widget: NoneType, sine: NoneType)>\n

from dataclasses import dataclass, field\nfrom enum import Enum\nfrom functools import partial\nfrom typing import Annotated\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.backends.backend_qt5agg import FigureCanvas\nfrom scipy import signal\n\nfrom magicgui import magicgui, register_type, widgets\n\nregister_type(float, widget_type=\"FloatSlider\")\nregister_type(int, widget_type=\"Slider\")\n\nFreq = Annotated[float, {\"min\": 0.001, \"max\": 30.0}]\nPhase = Annotated[float, {\"min\": 0.0, \"max\": 360.0}]\nDuty = Annotated[float, {\"min\": 0.0, \"max\": 1.0}]\nTime = Annotated[float, {\"min\": 0.01, \"max\": 100.0}]\n\n\n@dataclass\nclass Signal:\n    \"\"\"Constructs a 1D signal.\n\n    As is, this class is not very useful, but one could add callbacks\n    or more functionality here\n\n    Parameters\n    ----------\n    func : callable\n        func must take a 'time' array as sole argument and return a 1D array with the\n        same size as the input\n    duration : float\n        the maximum of the input time array\n    size : int\n        the number of samples in the time array\n\n    \"\"\"\n\n    func: callable\n    duration: Time = 1.0\n    size: int = 500\n    time: np.ndarray = field(init=False)\n    data: np.ndarray = field(init=False)\n\n    def __post_init__(self):\n        \"\"\"Evaluate the function at instantiation time.\"\"\"\n        self.time = np.linspace(0, self.duration, self.size)\n        self.data = self.func(self.time)\n\n    def plot(self, ax=None, **kwargs):\n        \"\"\"Plots the data.\n\n        Parameters\n        ----------\n        ax: matplotlib.axes.Axes instance, default None\n           if provided the plot is done on this axes instance.\n           If None a new ax is created\n        **kwargs: Keyword arguments that are passed on to\n            the matplotib ax.plot method\n\n        Returns\n        -------\n        fig: a matplotlib.figure.Figure instance\n        ax: matplotlib.axes.Axes instance\n        \"\"\"\n        if ax is None:\n            fig, ax = plt.subplots()\n        else:\n            fig = ax.get_figure()\n        ax.plot(self.time, self.data, **kwargs)\n        return fig, ax\n\n\ndef sine(\n    duration: Time = 10.0, size: int = 500, freq: Freq = 0.5, phase: Phase = 0.0\n) -> Signal:\n    \"\"\"Returns a 1D sine wave.\n\n    Parameters\n    ----------\n    duration: float\n       the duration of the signal in seconds\n    size: int\n        the number of samples in the signal time array\n    freq: float\n       the frequency of the signal in Hz\n    phase: Phase\n       the phase of the signal (in degrees)\n    \"\"\"\n    sig = Signal(\n        duration=duration,\n        size=size,\n        func=lambda t: np.sin(t * (2 * np.pi * freq) + phase * np.pi / 180),\n    )\n    return sig\n\n\ndef chirp(\n    duration: Time = 10.0,\n    size: int = 500,\n    f0: float = 1.0,\n    t1: Time = 5.0,\n    f1: float = 2.0,\n    phase: Phase = 0.0,\n) -> Signal:\n    \"\"\"Frequency-swept cosine generator.\n\n    See scipy.signal.chirp\n    \"\"\"\n    sig = Signal(\n        duration=duration,\n        size=size,\n        func=partial(signal.chirp, f0=f0, t1=t1, f1=f1, phi=phase),\n    )\n    return sig\n\n\ndef sawtooth(\n    duration: Time = 10.0,\n    size: int = 500,\n    freq: Freq = 1.0,\n    width: Duty = 1.0,\n    phase: Phase = 0.0,\n) -> Signal:\n    \"\"\"Return a periodic sawtooth or triangle waveform.\n\n    See scipy.signal.sawtooth\n    \"\"\"\n    sig = Signal(\n        duration=duration,\n        size=size,\n        func=lambda t: signal.sawtooth(\n            2 * np.pi * freq * t + phase * np.pi / 180, width=width\n        ),\n    )\n    return sig\n\n\ndef square(\n    duration: Time = 10.0, size: int = 500, freq: Freq = 1.0, duty: Duty = 0.5\n) -> Signal:\n    \"\"\"Return a periodic sawtooth or triangle waveform.\n\n    See scipy.signal.square\n    \"\"\"\n    sig = Signal(\n        duration=duration,\n        size=size,\n        func=lambda t: signal.square(2 * np.pi * freq * t, duty=duty),\n    )\n    return sig\n\n\ndef on_off(\n    duration: Time = 10.0, size: int = 500, t_on: Time = 0.01, t_off: Time = 0.01\n) -> Signal:\n    \"\"\"On/Off signal function.\"\"\"\n    data = np.ones(size)\n    data[: int(size * t_on / duration)] = -1\n    if t_off > 0:\n        data[int(size * t_off / duration) :] = -1\n    sig = Signal(duration=duration, size=size, func=lambda t: data)\n    return sig\n\n\nWAVEFORMS = {\n    \"sine\": sine,\n    \"chirp\": chirp,\n    \"sawtooth\": sawtooth,\n    \"square\": square,\n    \"on_off\": on_off,\n}\n\n\nclass Select(Enum):\n    \"\"\"Enumeration to select signal type.\"\"\"\n\n    OnOff = \"on_off\"\n    Sine = \"sine\"\n    Chirp = \"chirp\"\n    Sawtooth = \"sawtooth\"\n    Square = \"square\"\n\n\nclass WaveForm(widgets.Container):\n    \"\"\"Simple waveform generator widget, with plotting.\"\"\"\n\n    def __init__(self):\n        \"\"\"Creates the widget.\"\"\"\n        super().__init__()\n        self.fig, self.ax = plt.subplots()\n        self.native.layout().addWidget(FigureCanvas(self.fig))\n        self.waveform = sine\n        self.controls = None\n        self.append(self.signal_widget)\n        self.update_controls()\n        self.update_graph(sine())\n\n    @magicgui(auto_call=True)\n    def signal_widget(self, select: Select = Select.Sine) -> widgets.Container:\n        \"\"\"Waveform selection, from the WAVEFORMS dict.\"\"\"\n        self.waveform = WAVEFORMS[select.value]\n        self.update_controls()\n        self.update_graph(self.waveform())\n\n    def update_controls(self):\n        \"\"\"Reset controls according to the new function.\"\"\"\n        if self.controls is not None:\n            self.remove(self.controls)\n        self.controls = magicgui(auto_call=True)(self.waveform)\n        self.append(self.controls)\n        self.controls.called.connect(self.update_graph)\n\n    def update_graph(self, sig: Signal):\n        \"\"\"Re-plot when a parameter changes.\n\n        Note\n        ----\n        For big data, this could be slow, maybe `auto_call` should\n        not be true in the method above...\n        \"\"\"\n        self.ax.cla()\n        sig.plot(ax=self.ax)\n        self.fig.canvas.draw()\n\n\nwaveform = WaveForm()\nwaveform.show(run=True)\n

Total running time of the script: ( 0 minutes 0.155 seconds)

Download Python source code: waveform.py

Download Jupyter notebook: waveform.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/napari/mg_execution_times/","title":"Computation times","text":"

00:07.838 total execution time for generated_examples_napari files:

+--------------------------------------------------------------------------------------------------------+-----------+--------+ | napari_combine_qt (docs/examples/napari/napari_combine_qt.py) | 00:04.907 | 0.0 MB | +--------------------------------------------------------------------------------------------------------+-----------+--------+ | napari_parameter_sweep (docs/examples/napari/napari_parameter_sweep.py) | 00:01.766 | 0.0 MB | +--------------------------------------------------------------------------------------------------------+-----------+--------+ | napari_img_math (docs/examples/napari/napari_img_math.py) | 00:01.133 | 0.0 MB | +--------------------------------------------------------------------------------------------------------+-----------+--------+ | napari_forward_refs (docs/examples/napari/napari_forward_refs.py) | 00:00.032 | 0.0 MB | +--------------------------------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/napari/napari_combine_qt/","title":"napari Qt demo","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/napari/napari_combine_qt/#napari-qt-demo","title":"napari Qt demo","text":"

Napari provides a few conveniences with magicgui, and one of the most commonly used is the layer combo box that gets created when a parameter is annotated as napari.layers.Layer.

The layer box will stay in sync with the viewer model, adding and removing layers as needed.

This example shows how to use just that widget in the context of a larger custom QWidget.

import napari\nfrom qtpy.QtWidgets import QVBoxLayout, QWidget\n\nfrom magicgui.widgets import create_widget\n\n\nclass CustomWidget(QWidget):\n    \"\"\"A custom widget class.\"\"\"\n\n    def __init__(self) -> None:\n        super().__init__()\n        self.setLayout(QVBoxLayout())\n        # change annotation to napari.layers.Image (e.g) to restrict to just Images\n        self._layer_combo = create_widget(annotation=napari.layers.Layer)\n        # magicgui widgets hold the Qt widget at `widget.native`\n        self.layout().addWidget(self._layer_combo.native)\n\n\nviewer = napari.Viewer()\nviewer.add_points()\nviewer.add_points()\n\nmy_widget = CustomWidget()\nviewer.window.add_dock_widget(my_widget)\n\n# when my_widget is a magicgui.Widget, it will detect that it has been added\n# to a viewer, and automatically update the choices.  Otherwise, you need to\n# trigger this yourself:\nmy_widget._layer_combo.reset_choices()\nviewer.layers.events.inserted.connect(my_widget._layer_combo.reset_choices)\nviewer.layers.events.removed.connect(my_widget._layer_combo.reset_choices)\n\nnapari.run()\n

Total running time of the script: ( 0 minutes 4.907 seconds)

Download Python source code: napari_combine_qt.py

Download Jupyter notebook: napari_combine_qt.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/napari/napari_forward_refs/","title":"napari forward reference demo","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/napari/napari_forward_refs/#napari-forward-reference-demo","title":"napari forward reference demo","text":"

Example of using a ForwardRef to avoid importing a module that provides a widget.

In this example, one might want to create a widget that takes as an argument a napari Image layer, and returns an Image. In order to avoid needing to import napari (and therefore depending directly on napari), it's possible to annotate those parameters with a string representation of the type (rather than the type itself). This is called a \"forward reference\": https://www.python.org/dev/peps/pep-0484/#forward-references

Out:

<FunctionGui subtract_background(data: napari.types.ImageData = None, background: int = 50) -> napari.types.ImageData>\n

# Note: if you'd like to avoid circular imports, or just want to avoid having your\n# linter yell at you for an undefined type annotation, you can place the import\n# inside of an `if typing.TYPE_CHECKING` conditional.  This is not evaluated at runtime,\n# only when something like mypy is doing type checking.\nfrom typing import TYPE_CHECKING\n\nfrom magicgui import magicgui\n\nif TYPE_CHECKING:\n    import napari\n\n\n@magicgui(call_button=\"execute\", background={\"max\": 200})\ndef subtract_background(\n    data: \"napari.types.ImageData\", background: int = 50\n) -> \"napari.types.ImageData\":\n    \"\"\"Subtract a constant from the data.\"\"\"\n    if data:\n        return data - background\n\n\nsubtract_background.show(run=True)\n# now, this example isn't all that interesting on its own (since there will be no Image\n# layer in the dropdown) ... but in another package, where you DO import napari,\n# you could add this widget to a napari viewer with\n# viewer.window.add_dock_widget(subtract_background)\n

Total running time of the script: ( 0 minutes 0.032 seconds)

Download Python source code: napari_forward_refs.py

Download Jupyter notebook: napari_forward_refs.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/napari/napari_img_math/","title":"napari image arithmetic widget","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/napari/napari_img_math/#napari-image-arithmetic-widget","title":"napari image arithmetic widget","text":"

napari is a fast, interactive, multi-dimensional image viewer for python. It uses Qt for the GUI, so it's easy to extend napari with small, composable widgets created with magicgui. Here we're going to build this simple image arithmetic widget with a few additional lines of code.

For napari-specific magicgui documentation, see the napari docs

"},{"location":"generated_examples/napari/napari_img_math/#outline","title":"outline","text":"

This example demonstrates how to:

  1. Create a magicgui widget that can be used in another program (napari)

  2. Use an Enum to create a dropdown menu

  3. Connect some event listeners to create interactivity.

"},{"location":"generated_examples/napari/napari_img_math/#code","title":"code","text":"

Code follows, with explanation below... You can also get this example at github.

from enum import Enum\n\nimport napari\nimport numpy\nfrom napari.types import ImageData\n\nfrom magicgui import magicgui\n\n\nclass Operation(Enum):\n    # A set of valid arithmetic operations for image_arithmetic.\n    #\n    # To create nice dropdown menus with magicgui, it's best\n    # (but not required) to use Enums.  Here we make an Enum\n    # class for all of the image math operations we want to\n    # allow.\n    add = numpy.add\n    subtract = numpy.subtract\n    multiply = numpy.multiply\n    divide = numpy.divide\n\n\n# here's the magicgui!  We also use the additional\n# `call_button` option\n@magicgui(call_button=\"execute\")\ndef image_arithmetic(\n    layerA: ImageData, operation: Operation, layerB: ImageData\n) -> ImageData:\n    # Add, subtracts, multiplies, or divides to image layers.\n    return operation.value(layerA, layerB)\n\n\n# create a viewer and add a couple image layers\nviewer = napari.Viewer()\nviewer.add_image(numpy.random.rand(20, 20), name=\"Layer 1\")\nviewer.add_image(numpy.random.rand(20, 20), name=\"Layer 2\")\n\n# add our new magicgui widget to the viewer\nviewer.window.add_dock_widget(image_arithmetic)\n\n# keep the dropdown menus in the gui in sync with the layer model\nviewer.layers.events.inserted.connect(image_arithmetic.reset_choices)\nviewer.layers.events.removed.connect(image_arithmetic.reset_choices)\n\nnapari.run()\n
"},{"location":"generated_examples/napari/napari_img_math/#walkthrough","title":"walkthrough","text":"

We're going to go a little out of order so that the other code makes more sense. Let's start with the actual function we'd like to write to do some image arithmetic.

"},{"location":"generated_examples/napari/napari_img_math/#the-function","title":"the function","text":"

Our function takes two numpy arrays (in this case, from Image layers), and some mathematical operation (we'll restrict the options using an enum.Enum). When called, ourfunction calls the selected operation on the data.

def image_arithmetic(array1, operation, array2):\n    return operation.value(array1, array2)\n
"},{"location":"generated_examples/napari/napari_img_math/#type-annotations","title":"type annotations","text":"

magicgui works particularly well with type annotations, and allows third-party libraries to register widgets and behavior for handling their custom types (using magicgui.type_map.register_type). napari provides support for magicgui by registering a dropdown menu whenever a function parameter is annotated as one of the basic napari Layer types, or, in this case, ImageData indicates we just the data attribute of the layer. Furthermore, it recognizes when a function has a napari.layers.Layer or LayerData return type annotation, and will add the result to the viewer. So we gain a lot by annotating the above function with the appropriate napari types.

from napari.types import ImageData\n\n\ndef image_arithmetic(\n    layerA: ImageData, operation: Operation, layerB: ImageData\n) -> ImageData:\n    return operation.value(layerA, layerB)\n
"},{"location":"generated_examples/napari/napari_img_math/#the-magic-part","title":"the magic part","text":"

Finally, we decorate the function with @magicgui and tell it we'd like to have a call_button that we can click to execute the function.

@magicgui(call_button=\"execute\")\ndef image_arithmetic(layerA: ImageData, operation: Operation, layerB: ImageData):\n    return operation.value(layerA, layerB)\n

That's it! The image_arithmetic function is now a FunctionGui that can be shown, or incorporated into other GUIs (such as the napari GUI shown in this example)

!!! note While type hints aren't always required in magicgui, they are recommended ... and they are required for certain things, like the Operation(Enum) used here for the dropdown and the napari.types.ImageData annotations that napari has registered with magicgui.

"},{"location":"generated_examples/napari/napari_img_math/#create-dropdowns-with-enums","title":"create dropdowns with Enums","text":"

We'd like the user to be able to select the operation (add, subtract, multiply, divide) using a dropdown menu. enum.Enum offers a convenient way to restrict values to a strict set of options, while providing name: value pairs for each of the options. Here, the value for each choice is the actual function we would like to have called when that option is selected.

class Operation(enum.Enum):\n    add = numpy.add\n    subtract = numpy.subtract\n    multiply = numpy.multiply\n    divide = numpy.divide\n
"},{"location":"generated_examples/napari/napari_img_math/#add-it-to-napari","title":"add it to napari","text":"

When we decorated the image_arithmetic function above, it became a FunctionGui. Napari recognizes this type, so we can simply add it to the napari viewer as follows:

viewer.window.add_dock_widget(image_arithmetic)\n
"},{"location":"generated_examples/napari/napari_img_math/#connect-event-listeners-for-interactivity","title":"connect event listeners for interactivity","text":"

What fun is a GUI without some interactivity? Let's make stuff happen.

We connect the image_arithmetic.reset_choices function to the viewer.layers.events.inserted/removed event from napari, to make sure that the dropdown menus stay in sync if a layer gets added or removed from the napari window:

viewer.layers.events.inserted.connect(image_arithmetic.reset_choices)\nviewer.layers.events.removed.connect(image_arithmetic.reset_choices)\n

Tip

An additional offering from magicgui here is that the decorated function also acquires a new attribute \"called\" that can be connected to callback functions of your choice. Then, whenever the gui widget or the original function are called, the result will be passed to your callback function:

@image_arithmetic.called.connect\ndef print_mean(value):\n    # Callback function that accepts an event\n    # the value attribute has the result of calling the function\n    print(np.mean(value))\n
>>> image_arithmetic()\n1.0060037881040373\n
"},{"location":"generated_examples/napari/napari_img_math/#code_1","title":"Code","text":"

Here's the full code example again.

from enum import Enum\n\nimport napari\nimport numpy\nfrom napari.types import ImageData\n\nfrom magicgui import magicgui\n\n\nclass Operation(Enum):\n    # A set of valid arithmetic operations for image_arithmetic.\n    #\n    # To create nice dropdown menus with magicgui, it's best\n    # (but not required) to use Enums.  Here we make an Enum\n    # class for all of the image math operations we want to\n    # allow.\n    add = numpy.add\n    subtract = numpy.subtract\n    multiply = numpy.multiply\n    divide = numpy.divide\n\n\n# here's the magicgui!  We also use the additional\n# `call_button` option\n@magicgui(call_button=\"execute\")\ndef image_arithmetic(\n    layerA: ImageData, operation: Operation, layerB: ImageData\n) -> ImageData:\n    # Add, subtracts, multiplies, or divides to image layers.\n    return operation.value(layerA, layerB)\n\n\n# create a viewer and add a couple image layers\nviewer = napari.Viewer()\nviewer.add_image(numpy.random.rand(20, 20), name=\"Layer 1\")\nviewer.add_image(numpy.random.rand(20, 20), name=\"Layer 2\")\n\n# add our new magicgui widget to the viewer\nviewer.window.add_dock_widget(image_arithmetic)\n\n# keep the dropdown menus in the gui in sync with the layer model\nviewer.layers.events.inserted.connect(image_arithmetic.reset_choices)\nviewer.layers.events.removed.connect(image_arithmetic.reset_choices)\n\nnapari.run()\n

Total running time of the script: ( 0 minutes 1.133 seconds)

Download Python source code: napari_img_math.py

Download Jupyter notebook: napari_img_math.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/napari/napari_parameter_sweep/","title":"napari parameter sweeps","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/napari/napari_parameter_sweep/#napari-parameter-sweeps","title":"napari parameter sweeps","text":"

napari is a fast, interactive, multi-dimensional image viewer for python. It uses Qt for the GUI, so it's easy to extend napari with small, composable widgets created with magicgui. Here, we demonstrate how to build a interactive widget that lets you immediately see the effect of changing one of the parameters of your function.

For napari-specific magicgui documentation, see the napari docs

See also: Some of this tutorial overlaps with topics covered in the napari image arithmetic example.

"},{"location":"generated_examples/napari/napari_parameter_sweep/#outline","title":"outline","text":"

This example demonstrates how to:

  1. Create a magicgui widget that can be used in another program (napari)

  2. Automatically call our function when a parameter changes

  3. Provide magicgui with a custom widget for a specific argument

  4. Use the choices option to create a dropdown

  5. Connect some event listeners to create interactivity.

"},{"location":"generated_examples/napari/napari_parameter_sweep/#code","title":"code","text":"

Code follows, with explanation below... You can also get this example at github.

import napari\nimport skimage.data\nimport skimage.filters\nfrom napari.types import ImageData\n\nfrom magicgui import magicgui\n\n\n# turn the gaussian blur function into a magicgui\n# - 'auto_call' tells magicgui to call the function when a parameter changes\n# - we use 'widget_type' to override the default \"float\" widget on sigma,\n#   and provide a maximum valid value.\n# - we contstrain the possible choices for 'mode'\n@magicgui(\n    auto_call=True,\n    sigma={\"widget_type\": \"FloatSlider\", \"max\": 6},\n    mode={\"choices\": [\"reflect\", \"constant\", \"nearest\", \"mirror\", \"wrap\"]},\n    layout=\"horizontal\",\n)\ndef gaussian_blur(layer: ImageData, sigma: float = 1.0, mode=\"nearest\") -> ImageData:\n    # Apply a gaussian blur to 'layer'.\n    if layer is not None:\n        return skimage.filters.gaussian(layer, sigma=sigma, mode=mode)\n\n\n# create a viewer and add some images\nviewer = napari.Viewer()\nviewer.add_image(skimage.data.astronaut().mean(-1), name=\"astronaut\")\nviewer.add_image(skimage.data.grass().astype(\"float\"), name=\"grass\")\n\n# Add it to the napari viewer\nviewer.window.add_dock_widget(gaussian_blur)\n# update the layer dropdown menu when the layer list changes\nviewer.layers.events.changed.connect(gaussian_blur.reset_choices)\n\nnapari.run()\n
"},{"location":"generated_examples/napari/napari_parameter_sweep/#walkthrough","title":"walkthrough","text":"

We're going to go a little out of order so that the other code makes more sense. Let's start with the actual function we'd like to write to apply a gaussian filter to an image.

"},{"location":"generated_examples/napari/napari_parameter_sweep/#the-function","title":"the function","text":"

Our function is a very thin wrapper around skimage.filters.gaussian. It takes a napari Image layer, a sigma to control the blur radius, and a mode that determines how edges are handled.

def gaussian_blur(layer: Image, sigma: float = 1, mode=\"nearest\") -> Image:\n    return filters.gaussian(layer.data, sigma=sigma, mode=mode)\n

The reasons we are wrapping it here are:

  1. filters.gaussian accepts a numpy array, but we want to work with napari layers that store the data in a layer.data attribute. So we need an adapter.
  2. We'd like to add some type annotations to the signature that were not provided by filters.gaussian
"},{"location":"generated_examples/napari/napari_parameter_sweep/#type-annotations","title":"type annotations","text":"

As described in the image arithmetic example, we take advantage of napari's built in support for magicgui by annotating our function parameters and return value as napari Layer types. napari will then tell magicgui what to do with them, creating a dropdown with a list of current layers for our layer parameter, and automatically adding the result of our function to the viewer when called.

For documentation on napari types with magicgui, see the napari docs

"},{"location":"generated_examples/napari/napari_parameter_sweep/#the-magic-part","title":"the magic part","text":"

Finally, we decorate the function with @magicgui and provide some options.

@magicgui(\n    auto_call=True,\n    sigma={\"widget_type\": \"FloatSlider\", \"max\": 6},\n    mode={\"choices\": [\"reflect\", \"constant\", \"nearest\", \"mirror\", \"wrap\"]},\n)\ndef gaussian_blur(layer: ImageData, sigma: float = 1.0, mode=\"nearest\") -> ImageData:\n    # Apply a gaussian blur to ``layer``.\n    if layer is not None:\n        return skimage.filters.gaussian(layer, sigma=sigma, mode=mode)\n
  • auto_call=True makes it so that the gaussian_blur function will be called whenever one of the parameters changes (with the current parameters set in the GUI).
  • We then provide keyword arguments to modify the look & behavior of sigma and mode:

    • \"widget_type\": \"FloatSlider\" tells magicgui not to use the standard (float) widget for the sigma widget, but rather to use a slider widget.
    • we then set an upper limit on the slider values for sigma.
  • finally, we specify valid choices for the mode argument. This turns that parameter into a categorical/dropdown type widget, and sets the options.

"},{"location":"generated_examples/napari/napari_parameter_sweep/#connecting-events","title":"connecting events","text":"

As described in the Events documentation, we can also connect any callback to the gaussian_blur.called signal that will receive the result of our decorated function anytime it is called.

def do_something_with_result(result): ...\n\n\ngaussian_blur.called.connect(do_something_with_result)\n
"},{"location":"generated_examples/napari/napari_parameter_sweep/#code_1","title":"Code","text":"

Here's the full code example again.

import napari\nimport skimage.data\nimport skimage.filters\nfrom napari.types import ImageData\n\nfrom magicgui import magicgui\n\n\n# turn the gaussian blur function into a magicgui\n# - 'auto_call' tells magicgui to call the function when a parameter changes\n# - we use 'widget_type' to override the default \"float\" widget on sigma,\n#   and provide a maximum valid value.\n# - we contstrain the possible choices for 'mode'\n@magicgui(\n    auto_call=True,\n    sigma={\"widget_type\": \"FloatSlider\", \"max\": 6},\n    mode={\"choices\": [\"reflect\", \"constant\", \"nearest\", \"mirror\", \"wrap\"]},\n    layout=\"horizontal\",\n)\ndef gaussian_blur(layer: ImageData, sigma: float = 1.0, mode=\"nearest\") -> ImageData:\n    # Apply a gaussian blur to 'layer'.\n    if layer is not None:\n        return skimage.filters.gaussian(layer, sigma=sigma, mode=mode)\n\n\n# create a viewer and add some images\nviewer = napari.Viewer()\nviewer.add_image(skimage.data.astronaut().mean(-1), name=\"astronaut\")\nviewer.add_image(skimage.data.grass().astype(\"float\"), name=\"grass\")\n\n# Add it to the napari viewer\nviewer.window.add_dock_widget(gaussian_blur)\n# update the layer dropdown menu when the layer list changes\nviewer.layers.events.changed.connect(gaussian_blur.reset_choices)\n\nnapari.run()\n

Total running time of the script: ( 0 minutes 1.766 seconds)

Download Python source code: napari_parameter_sweep.py

Download Jupyter notebook: napari_parameter_sweep.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/notebooks/magicgui_jupyter/","title":"Jupyter notebooks and magicgui","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/notebooks/magicgui_jupyter/#jupyter-notebooks-and-magicgui","title":"Jupyter notebooks and magicgui","text":"

This example shows magicgui widgets embedded in a jupyter notebook.

The key function here is use_app(\"ipynb\").

You can also get this example at github.

import math\nfrom enum import Enum\n\nfrom magicgui import magicgui, use_app\n\nuse_app(\"ipynb\")\n\n\nclass Medium(Enum):\n    # Various media and their refractive indices.\n    Glass = 1.520\n    Oil = 1.515\n    Water = 1.333\n    Air = 1.0003\n\n\n@magicgui(\n    call_button=\"calculate\", result_widget=True, layout=\"vertical\", auto_call=True\n)\ndef snells_law(aoi=1.0, n1=Medium.Glass, n2=Medium.Water, degrees=True):\n    # Calculate the angle of refraction given two media and an angle of incidence.\n    if degrees:\n        aoi = math.radians(aoi)\n    try:\n        n1 = n1.value\n        n2 = n2.value\n        result = math.asin(n1 * math.sin(aoi) / n2)\n        return round(math.degrees(result) if degrees else result, 2)\n    except ValueError:  # math domain error\n        return \"TIR!\"\n\n\nsnells_law\n

Total running time of the script: ( 0 minutes 0.000 seconds)

Download Python source code: magicgui_jupyter.py

Download Jupyter notebook: magicgui_jupyter.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/notebooks/mg_execution_times/","title":"Computation times","text":"

00:00.000 total execution time for generated_examples_notebooks files:

+-----------------------------------------------------------------------------------------+-----------+--------+ | magicgui_jupyter (docs/examples/notebooks/magicgui_jupyter.py) | 00:00.000 | 0.0 MB | +-----------------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/progress_bars/mg_execution_times/","title":"Computation times","text":"

00:00.184 total execution time for generated_examples_progress_bars files:

+---------------------------------------------------------------------------------------------------------------+-----------+--------+ | progress_manual (docs/examples/progress_bars/progress_manual.py) | 00:00.052 | 0.0 MB | +---------------------------------------------------------------------------------------------------------------+-----------+--------+ | progress_nested (docs/examples/progress_bars/progress_nested.py) | 00:00.047 | 0.0 MB | +---------------------------------------------------------------------------------------------------------------+-----------+--------+ | progress_indeterminate (docs/examples/progress_bars/progress_indeterminate.py) | 00:00.045 | 0.0 MB | +---------------------------------------------------------------------------------------------------------------+-----------+--------+ | progress (docs/examples/progress_bars/progress.py) | 00:00.040 | 0.0 MB | +---------------------------------------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/progress_bars/progress/","title":"Simple progress bar","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/progress_bars/progress/#simple-progress-bar","title":"Simple progress bar","text":"

A simple progress bar demo with magicgui.

Out:

<FunctionGui long_running(steps=10, delay=0.1)>\n

from time import sleep\n\nfrom magicgui import magicgui\nfrom magicgui.tqdm import trange\n\n# if magicui.tqdm.tqdm or trange are used outside of a @magicgui function, (such as in\n# interactive use in IPython), then they fall back to the standard terminal output\n\n\n# If use inside of a magicgui-decorated function\n# a progress bar widget will be added to the magicgui container\n@magicgui(call_button=True, layout=\"horizontal\")\ndef long_running(steps=10, delay=0.1):\n    \"\"\"Long running computation with range iterator.\"\"\"\n    # trange(steps) is a shortcut for `tqdm(range(steps))`\n    for _i in trange(steps):\n        sleep(delay)\n\n\nlong_running.show(run=True)\n

Total running time of the script: ( 0 minutes 0.040 seconds)

Download Python source code: progress.py

Download Jupyter notebook: progress.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/progress_bars/progress_indeterminate/","title":"Indeterminate progress bar","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/progress_bars/progress_indeterminate/#indeterminate-progress-bar","title":"Indeterminate progress bar","text":"

Example of an indeterminate progress bar for a long running computation of unknown time.

Out:

<FunctionGui long_running(sleep_time=5)>\n

import time\n\nfrom superqt.utils import thread_worker\n\nfrom magicgui import magicgui\nfrom magicgui.tqdm import tqdm\n\n\n@magicgui(call_button=True, layout=\"horizontal\")\ndef long_running(sleep_time=5):\n    \"\"\"Long running computation with an indeterminate progress bar.\"\"\"\n    # Here tqdm is not provided an iterable argument, or the 'total' kwarg\n    # so it cannot calculate the expected number of iterations\n    # which means it will create an indeterminate progress bar\n    with tqdm() as pbar:\n        # It is best practice to use a separate thread for long running computations\n        # This makes the function non-blocking, you can still interact with the widget\n        @thread_worker(connect={\"finished\": lambda: pbar.progressbar.hide()})\n        def sleep(secs):\n            time.sleep(secs)\n\n        sleep(sleep_time)\n\n\nlong_running.show(run=True)\n

Total running time of the script: ( 0 minutes 0.045 seconds)

Download Python source code: progress_indeterminate.py

Download Jupyter notebook: progress_indeterminate.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/progress_bars/progress_manual/","title":"Manual progress bar","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/progress_bars/progress_manual/#manual-progress-bar","title":"Manual progress bar","text":"

Example of a progress bar being updated manually.

Out:

<FunctionGui manual(pbar: magicgui.widgets.ProgressBar = ProgressBar(value=<function TypeMap.match_type.<locals>.<lambda> at 0x1255b65c0>, annotation=<class 'magicgui.widgets.ProgressBar'>, name='pbar'), increment: bool = 1)>\n

from magicgui import magicgui\nfrom magicgui.widgets import ProgressBar\n\n\n@magicgui(call_button=\"tick\", pbar={\"min\": 0, \"step\": 2, \"max\": 20, \"value\": 0})\ndef manual(pbar: ProgressBar, increment: bool = True):\n    \"\"\"Example of manual progress bar control.\"\"\"\n    if increment:\n        pbar.increment()\n    else:\n        pbar.decrement()\n\n\nmanual.show(run=True)\n

Total running time of the script: ( 0 minutes 0.052 seconds)

Download Python source code: progress_manual.py

Download Jupyter notebook: progress_manual.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/progress_bars/progress_nested/","title":"Nested progress bars","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/progress_bars/progress_nested/#nested-progress-bars","title":"Nested progress bars","text":"

Example using nested progress bars in magicgui.

Out:

<FunctionGui long_function(steps=10, repeats=4, choices='ABCDEFGHIJKLMNOP12345679', char='', delay=0.05)>\n

import random\nfrom time import sleep\n\nfrom magicgui import magicgui\nfrom magicgui.tqdm import tqdm, trange\n\n# if magicui.tqdm.tqdm or trange are used outside of a @magicgui function, (such as in\n# interactive use in IPython), then they fall back to the standard terminal output\n\n\n# If use inside of a magicgui-decorated function\n# a progress bar widget will be added to the magicgui container\n@magicgui(call_button=True, layout=\"vertical\")\ndef long_function(\n    steps=10, repeats=4, choices=\"ABCDEFGHIJKLMNOP12345679\", char=\"\", delay=0.05\n):\n    \"\"\"Long running computation with nested iterators.\"\"\"\n    # trange and tqdm accept all the kwargs from tqdm itself, as well as any\n    # valid kwargs for magicgui.widgets.ProgressBar, (such as \"label\")\n    for _r in trange(repeats, label=\"repeats\"):\n        letters = [random.choice(choices) for _ in range(steps)]\n        # `tqdm`, like `tqdm`, accepts any iterable\n        # this progress bar is nested and will be run & reset multiple times\n        for letter in tqdm(letters, label=\"steps\"):\n            long_function.char.value = letter\n            sleep(delay)\n\n\nlong_function.show(run=True)\n

Total running time of the script: ( 0 minutes 0.047 seconds)

Download Python source code: progress_nested.py

Download Jupyter notebook: progress_nested.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/under_the_hood/class_method/","title":"Deocrate class methods with magicgui","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/under_the_hood/class_method/#deocrate-class-methods-with-magicgui","title":"Deocrate class methods with magicgui","text":"

Demonstrates decorating a class method with magicgui.

Once the class is instantiated, instance.method_name will return a FunctionGui in which the instance will always be provided as the first argument (i.e. \"self\") when the FunctionGui or method is called.

Out:

instance: a, counter: 0.0, sigma: 0.0\ninstance: b, counter: 0.0, sigma: 0.0\n

from magicgui import event_loop, magicgui\nfrom magicgui.widgets import Container\n\n\nclass MyObject:\n    \"\"\"Example object class.\"\"\"\n\n    def __init__(self, name):\n        self.name = name\n        self.counter = 0.0\n\n    @magicgui(auto_call=True)\n    def method(self, sigma: float = 0):\n        \"\"\"Example class method.\"\"\"\n        print(f\"instance: {self.name}, counter: {self.counter}, sigma: {sigma}\")\n        self.counter = self.counter + sigma\n        return self.name\n\n\nwith event_loop():\n    a = MyObject(\"a\")\n    b = MyObject(\"b\")\n    container = Container(widgets=[a.method, b.method])\n    container.show()\n    assert a.method() == \"a\"\n    assert b.method() == \"b\"\n

Total running time of the script: ( 0 minutes 0.052 seconds)

Download Python source code: class_method.py

Download Jupyter notebook: class_method.ipynb

Gallery generated by mkdocs-gallery

"},{"location":"generated_examples/under_the_hood/mg_execution_times/","title":"Computation times","text":"

00:00.090 total execution time for generated_examples_under_the_hood files:

+----------------------------------------------------------------------------------------+-----------+--------+ | class_method (docs/examples/under_the_hood/class_method.py) | 00:00.052 | 0.0 MB | +----------------------------------------------------------------------------------------+-----------+--------+ | self_reference (docs/examples/under_the_hood/self_reference.py) | 00:00.039 | 0.0 MB | +----------------------------------------------------------------------------------------+-----------+--------+

"},{"location":"generated_examples/under_the_hood/self_reference/","title":"Self reference magicgui widgets","text":"

Note

Click here to download the full example code

"},{"location":"generated_examples/under_the_hood/self_reference/#self-reference-magicgui-widgets","title":"Self reference magicgui widgets","text":"

Widgets created with magicgui can reference themselves, and use the widget API.

Out:

<FunctionGui function(width=400, x: int = 50)>\n

from magicgui import magicgui\n\n\n@magicgui(auto_call=True, width={\"max\": 800, \"min\": 100}, x={\"widget_type\": \"Slider\"})\ndef function(width=400, x: int = 50):\n    \"\"\"Example function.\"\"\"\n    # the widget can reference itself, and use the widget API\n    function.x.width = width\n\n\nfunction.show(run=True)\n

Total running time of the script: ( 0 minutes 0.039 seconds)

Download Python source code: self_reference.py

Download Jupyter notebook: self_reference.ipynb

Gallery generated by mkdocs-gallery

"}]} \ No newline at end of file diff --git a/type_map/index.html b/type_map/index.html index f5affc909..9750d78af 100644 --- a/type_map/index.html +++ b/type_map/index.html @@ -3360,7 +3360,7 @@

Default Type Mappingmagicgui.widgets.ProgressBar ProgressBar -{'bind': <function TypeMap.match_type.<locals>.<lambda> at 0x11f1979c0>, 'visible': True} +{'bind': <function TypeMap.match_type.<locals>.<lambda> at 0x123e8ec00>, 'visible': True} types.FunctionType