interactive-pipe 0.8.8__tar.gz → 0.8.10__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. {interactive_pipe-0.8.8/src/interactive_pipe.egg-info → interactive_pipe-0.8.10}/PKG-INFO +155 -118
  2. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/pyproject.toml +33 -8
  3. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/readme.md +151 -110
  4. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/__init__.py +25 -15
  5. interactive_pipe-0.8.10/src/interactive_pipe/core/backend.py +12 -0
  6. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/core/cache.py +2 -6
  7. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/core/context.py +17 -17
  8. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/core/engine.py +10 -17
  9. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/core/filter.py +23 -42
  10. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/core/graph.py +65 -23
  11. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/core/pipeline.py +44 -52
  12. interactive_pipe-0.8.10/src/interactive_pipe/core/signature.py +10 -0
  13. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/data_objects/audio.py +16 -14
  14. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/data_objects/curves.py +55 -73
  15. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/data_objects/data.py +18 -22
  16. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/data_objects/image.py +11 -5
  17. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/data_objects/parameters.py +7 -12
  18. interactive_pipe-0.8.10/src/interactive_pipe/data_objects/table.py +328 -0
  19. interactive_pipe-0.8.10/src/interactive_pipe/graphical/gradio_control.py +201 -0
  20. interactive_pipe-0.8.10/src/interactive_pipe/graphical/gradio_gui.py +651 -0
  21. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/graphical/gui.py +64 -35
  22. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/graphical/mpl_control.py +56 -37
  23. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/graphical/mpl_gui.py +41 -41
  24. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/graphical/mpl_window.py +23 -10
  25. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/graphical/nb_control.py +52 -36
  26. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/graphical/nb_gui.py +8 -8
  27. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/graphical/qt_control.py +153 -99
  28. interactive_pipe-0.8.10/src/interactive_pipe/graphical/qt_gui.py +981 -0
  29. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/graphical/window.py +10 -7
  30. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/headless/control.py +87 -44
  31. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/headless/keyboard.py +27 -15
  32. interactive_pipe-0.8.10/src/interactive_pipe/headless/panel.py +141 -0
  33. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/headless/pipeline.py +116 -84
  34. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/helper/choose_backend.py +7 -5
  35. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/helper/control_abbreviation.py +62 -72
  36. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/helper/filter_decorator.py +16 -14
  37. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/helper/keyword_args_analyzer.py +15 -26
  38. interactive_pipe-0.8.10/src/interactive_pipe/helper/pipeline_decorator.py +71 -0
  39. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10/src/interactive_pipe.egg-info}/PKG-INFO +155 -118
  40. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe.egg-info/SOURCES.txt +5 -1
  41. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe.egg-info/requires.txt +4 -7
  42. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_context.py +47 -35
  43. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_context_compatibility.py +11 -24
  44. interactive_pipe-0.8.10/test/test_control_abbreviations.py +83 -0
  45. interactive_pipe-0.8.10/test/test_controller.py +112 -0
  46. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_core.py +1 -3
  47. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_core_exceptions.py +9 -10
  48. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_curves.py +2 -4
  49. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_data_objects_exceptions.py +7 -7
  50. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_decorator.py +2 -1
  51. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_edge_cases.py +17 -6
  52. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_engine.py +6 -13
  53. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_filter.py +1 -3
  54. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_graphical_exceptions.py +33 -29
  55. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_headless.py +7 -11
  56. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_headless_exceptions.py +4 -5
  57. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_image.py +2 -2
  58. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_legacy_warnings.py +17 -39
  59. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_mutable_defaults.py +1 -0
  60. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_recorder.py +7 -6
  61. interactive_pipe-0.8.10/test/test_table.py +397 -0
  62. interactive_pipe-0.8.8/src/interactive_pipe/core/signature.py +0 -18
  63. interactive_pipe-0.8.8/src/interactive_pipe/graphical/gradio_control.py +0 -168
  64. interactive_pipe-0.8.8/src/interactive_pipe/graphical/gradio_gui.py +0 -428
  65. interactive_pipe-0.8.8/src/interactive_pipe/graphical/qt_gui.py +0 -650
  66. interactive_pipe-0.8.8/src/interactive_pipe/helper/pipeline_decorator.py +0 -64
  67. interactive_pipe-0.8.8/test/test_control_abbreviations.py +0 -125
  68. interactive_pipe-0.8.8/test/test_controller.py +0 -33
  69. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/LICENSE +0 -0
  70. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/setup.cfg +0 -0
  71. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/core/__init__.py +0 -0
  72. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/data_objects/__init__.py +0 -0
  73. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/graphical/__init__.py +0 -0
  74. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/headless/__init__.py +0 -0
  75. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/helper/__init__.py +0 -0
  76. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe/helper/_private.py +0 -0
  77. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe.egg-info/dependency_links.txt +0 -0
  78. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/src/interactive_pipe.egg-info/top_level.txt +0 -0
  79. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_cache.py +0 -0
  80. {interactive_pipe-0.8.8 → interactive_pipe-0.8.10}/test/test_parameters.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: interactive_pipe
3
- Version: 0.8.8
3
+ Version: 0.8.10
4
4
  Summary: Library to create flexible interactive image processing pipelines and automatically add a graphical user interface without knowing anything about GUI coding!
5
5
  Author-email: Balthazar Neveu <balthazarneveu@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/balthazarneveu/interactive_pipe
@@ -15,13 +15,6 @@ Requires-Dist: matplotlib>=3.5.3
15
15
  Requires-Dist: numpy>=1.21.6
16
16
  Requires-Dist: Pillow>=9.0.1
17
17
  Requires-Dist: PyYAML>=5.4.1
18
- Requires-Dist: PyQt6>=6.5.2
19
- Requires-Dist: PyQt6_sip>=13.5.2
20
- Requires-Dist: opencv_python_headless>=4.8.1.78
21
- Requires-Dist: pytest>=6.2.5
22
- Requires-Dist: ipywidgets>=7.7.1
23
- Requires-Dist: pandas
24
- Requires-Dist: gradio
25
18
  Provides-Extra: qt6
26
19
  Requires-Dist: PyQt6>=6.5.2; extra == "qt6"
27
20
  Requires-Dist: PyQt6_sip>=13.5.2; extra == "qt6"
@@ -41,6 +34,9 @@ Requires-Dist: pytest>=6.2.5; extra == "full"
41
34
  Requires-Dist: ipywidgets>=7.7.1; extra == "full"
42
35
  Requires-Dist: pandas; extra == "full"
43
36
  Requires-Dist: gradio; extra == "full"
37
+ Provides-Extra: dev
38
+ Requires-Dist: ruff>=0.9.0; extra == "dev"
39
+ Requires-Dist: pyright>=1.1.390; extra == "dev"
44
40
  Dynamic: license-file
45
41
 
46
42
 
@@ -61,7 +57,7 @@ Dynamic: license-file
61
57
  - Develop an algorithm while debugging visually with plots, while checking robustness & continuity to parameters change.
62
58
  - Magically create a graphical interface to easily demonstrate a concept or simply tune your algorithm.
63
59
 
64
- :heart: **You do not need to learn anything about making a graphical user interface (GUI)** :heart:
60
+ ❤️ **You do not need to learn anything about making a graphical user interface (GUI)** ❤️
65
61
 
66
62
 
67
63
  ### Examples
@@ -86,13 +82,13 @@ pip install -e ".[full]"
86
82
  ----------------------
87
83
 
88
84
  ### Who is this for?
89
- #### :mortar_board: Scientific education
85
+ #### 🎓 Scientific education
90
86
  - Demonstrate concepts by interacting with curves / images.
91
87
  - Easy integration in Jupyter Notebooks (popular with Google Collab)
92
- #### :gift: DIY hobbyist
88
+ #### 🎁 DIY hobbyist
93
89
  - You can also use the declarative nature of interactive pipe to make a graphical interface in a few lines of codes.
94
90
  - For instance, it is possible to code a jukebox for a toddler on a RaspberryPi.
95
- #### :camera: Engineering *(computer vision, image/signal processing)*
91
+ #### 📷 Engineering *(computer vision, image/signal processing)*
96
92
  - While prototyping an algorithm or testing a neural network, you may be interested in making small experiments with visual checks. Instead of making a draft quick & dirty code that you'll never keep, you can use interactive pipe to show your team how your library works. A visual demo is always good, it shows that the algorithm is not buggy if anyone can play with it.
97
93
  - Tune your algorithms with a graphical interface and save your parameters for later batch processing.
98
94
  - Ready to batch under the hood, the processing engine can be ran without GUI (therefore allowing to use the same code for tuning & batch processing if needed).
@@ -102,31 +98,30 @@ pip install -e ".[full]"
102
98
 
103
99
 
104
100
  ----------------------
105
- ## :scroll: Terminology
106
101
 
107
- ![interactive_pipe_concept](static/interact-pipe-concept.svg)
102
+ ## 📜 Features
108
103
 
109
- ## :scroll: Features
110
-
111
- **Version 0.8.8**
104
+ **Version 0.8.10**
112
105
  - Modular multi-image processing filters
113
106
  - Declarative: Easily make graphical user interface without having to learn anything about pyQt or matplotlib
114
107
  - Support in jupyter notebooks
115
108
  - Tuning sliders & check buttons with a GUI
116
109
  - Cache intermediate results in RAM for much faster processing
117
110
  - `KeyboardControl` : no slider on UI but exactly the same internal mechanism, update on key press.
118
- - Support Curve plots (2D signals)
111
+ - Support Curve plots (2D signals).
119
112
  - Gradio backend (+allows sharing with others).
120
113
  - Audio support in Gradio (live audio or display several players by returning 1D numpy arrays)
121
114
  - Circular sliders for Qt Backend
122
115
  - Text prompt (`free_text=("Hello world!", None),`)
123
116
  - TimeControl (possibility to play/pause time using an incrementing timer)
124
- - :new: **Context API**: Direct access to shared context across filters via `get_context()`, `context`, `layout`, `audio`
125
- - :new: MIT License
117
+ - 🆕 **Context API**: Direct access to shared context across filters via `get_context()`, `context`, `layout`, `audio`
118
+ - 🆕 MIT License
119
+ - 🆕 Panel **Panel System**: group the sliders in defined panels. allows fine control on GUI layout.
120
+ - 🆕 Support Table outputs
126
121
 
127
122
 
128
123
 
129
- #### :keyboard: Keyboard shortcuts
124
+ #### ⌨️ Keyboard shortcuts
130
125
  Shortcuts while using the GUI (QT & matplotlib backends)
131
126
 
132
127
  - `F1` to show the help shortcuts in the terminal
@@ -142,27 +137,31 @@ Shortcuts while using the GUI (QT & matplotlib backends)
142
137
 
143
138
  # Status
144
139
  - supported backends
145
- - :ok: `gui='qt'` pyQt/pySide
146
- - :ok: `gui='mpl'` matplotlib
147
- - :ok: `gui='nb'` ipywidget for jupyter notebooks
148
- - :test_tube: `gui='gradio'` gradio wrapping (+use `share_gradio_app=True` to share your app with others)
140
+ - `gui='qt'` pyQt/pySide
141
+ - `gui='mpl'` matplotlib
142
+ - `gui='nb'` ipywidget for jupyter notebooks
143
+ - `gui='gradio'` gradio wrapping (+use `share_gradio_app=True` to share your app with others)
149
144
  - tested platforms
150
- - :ok: Linux (Ubuntu / KDE Neon)
151
- - :ok: RapsberryPi
152
- - :ok: On google collab (use `gui='nb'`)
145
+ - Linux (Ubuntu / KDE Neon)
146
+ - RapsberryPi
147
+ - On google collab (use `gui='nb'`)
153
148
 
154
149
 
155
150
 
156
- | :star: | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* | *Gradio* |
151
+ | | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* | *Gradio* |
157
152
  |:-----: |:-----:|:------:|:----: |:----: |
158
153
  | Backend name | `qt` | `mpl` | `nb`| `gradio` |
159
154
  | Preview | ![qt backend](/doc/images/qt_backend.jpg) | ![mpl backend](/doc/images/mpl_backend.jpg) | ![nb backend](/doc/images/notebook_backend.jpg) | ![mpl backend](/doc/images/gradio_backend.jpg)|
160
- | Plot curves | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark:|
161
- | Auto refreshed layout | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: |
162
- | Keyboard shortcuts / fullscreen| :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
163
- | Audio support | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_check_mark: |
164
- | Image buttons| :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign:|
165
- | Circular slider| :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign:|
155
+ | Plot curves | | | | ✅|
156
+ | Change layout | | | | |
157
+ | Keyboard shortcuts / fullscreen| | | | |
158
+ | Audio support | | | | |
159
+ | Image buttons| | | | |
160
+ | Circular slider| | | | |
161
+ | Collapsible Panels | ✅ | ➖ | ➖ | ✅ |
162
+ | Animations | ✅ | ➖ | ➖ | ➖ |
163
+ | Panels with sliders | ✅ | ➖ | ➖ | ✅ |
164
+ | Tables | ✅ | ✅ | ✅ | ✅|
166
165
 
167
166
 
168
167
 
@@ -189,7 +188,7 @@ Shortcuts while using the GUI (QT & matplotlib backends)
189
188
 
190
189
 
191
190
 
192
- ## :rocket: Ultra short code
191
+ ## 🚀 Ultra short code
193
192
 
194
193
 
195
194
  *Since ipywidgets in notebooks are supported, the tutorial is also available in a [google collab notebook](https://colab.research.google.com/drive/1PZn8P_5TABVCugT3IcLespvZG-gxnFbO?usp=sharing)*
@@ -202,9 +201,9 @@ By design:
202
201
  - keyword arguments are the parameters which can be later turned into interactive widgets.
203
202
  - output buffers are simply returned like you'd do in a regular function.
204
203
 
205
- We use the `@interactive()` wrapper which will turn each keyword parameters initialized to a **tuple/list** into a graphical interactive widgets (slider, tick box, dropdown men).
204
+ We use the `@interactive()` decorator to specify which parameters become interactive widgets. Parameters defined in the decorator as **tuple/list** will become graphical interactive widgets (slider, tick box, dropdown menu).
206
205
 
207
- The syntax to turn keyword arguments into sliders is pretty simple `(default, [min, max], name)` will turn into a float slider for instance.
206
+ The syntax to turn keyword arguments into sliders is pretty simple: `@interactive(param=(default, [min, max], name))` will create a float slider for instance.
208
207
 
209
208
  Finally, we need to the glue to combo these filters. This is where the sample_pipeline function comes in.
210
209
 
@@ -215,8 +214,11 @@ By decorating it with `@interactive_pipeline(gui="qt")`, calling this function w
215
214
  from interactive_pipe import interactive, interactive_pipeline
216
215
  import numpy as np
217
216
 
218
- @interactive()
219
- def exposure(img, coeff = (1., [0.5, 2.], "exposure"), bias=(0., [-0.2, 0.2])):
217
+ @interactive(
218
+ coeff=(1., [0.5, 2.], "exposure"),
219
+ bias=(0., [-0.2, 0.2])
220
+ )
221
+ def exposure(img, coeff=1., bias=0.):
220
222
  '''Applies a multiplication by coeff & adds a constant bias to the image'''
221
223
  # In the GUI, the coeff will be labelled as "exposure".
222
224
  # As the default tuple provided to bias does not end up with a string,
@@ -224,15 +226,15 @@ def exposure(img, coeff = (1., [0.5, 2.], "exposure"), bias=(0., [-0.2, 0.2])):
224
226
  return img*coeff + bias
225
227
 
226
228
 
227
- @interactive()
228
- def black_and_white(img, bnw=(True, "black and white")):
229
+ @interactive(bnw=(True, "black and white"))
230
+ def black_and_white(img, bnw=True):
229
231
  '''Averages the 3 color channels (Black & White) if bnw=True
230
232
  '''
231
233
  # Special mention for booleans: using a tuple like (True,) allows creating the tick box.
232
234
  return np.repeat(np.expand_dims(np.average(img, axis=-1), -1), img.shape[-1], axis=-1) if bnw else img
233
235
 
234
- @interactive()
235
- def blend(img0, img1, blend_coeff=(0.5, [0., 1.])):
236
+ @interactive(blend_coeff=(0.5, [0., 1.]))
237
+ def blend(img0, img1, blend_coeff=0.5):
236
238
  '''Blends between two image.
237
239
  - when blend_coeff=0 -> image 0 [slider to the left ]
238
240
  - when blend_coeff=1 -> image 1 [slider to the right]
@@ -252,25 +254,25 @@ if __name__ == '__main__':
252
254
  sample_pipeline(input_image)
253
255
 
254
256
  ```
255
- :heart: This code shall display you a GUI with three images. The middle one is the result of the blend
257
+ ❤️ This code shall display you a GUI with three images. The middle one is the result of the blend
256
258
 
257
259
 
258
260
 
259
261
  Notes:
260
- - If you write `def blend(img0, img1, blend_coeff=0.5):`, blend_coeff will simply not be a slider on the GUI no more.
261
- - If you write `blend_coeff=[0., 1.]` , blend_coeff will be a slider initalized to 0.5
262
- - If you write `bnw=(True, "black and white", "k")`, the checkbox will disappear and be replaced by a keypress event (press `k` to enable/disable black & white)
262
+ - If you write `@interactive()` with `def blend(img0, img1, blend_coeff=0.5):`, blend_coeff will simply not be a slider on the GUI.
263
+ - If you write `@interactive(blend_coeff=[0., 1.])` in the decorator, blend_coeff will be a slider initialized to 0.5
264
+ - If you write `@interactive(bnw=(True, "black and white", "k"))`, the checkbox will disappear and be replaced by a keypress event (press `k` to enable/disable black & white)
263
265
 
264
266
  -----------
265
- ## :bulb: Some more tips
267
+ ## 💡 Some more tips
266
268
 
267
269
  ```python
268
- from interactive_pipe import interactive, interactive_pipeline
270
+ from interactive_pipe import interactive, interactive_pipeline, context
269
271
  import numpy as np
270
272
 
271
273
  COLOR_DICT = {"red": [1., 0., 0.], "green": [0., 1.,0.], "blue": [0., 0., 1.], "gray": [0.5, 0.5, 0.5]}
272
- @interactive()
273
- def generate_flat_colored_image(color_choice=["red", "green", "blue", "gray"], context={}):
274
+ @interactive(color_choice=["red", "green", "blue", "gray"])
275
+ def generate_flat_colored_image(color_choice="red"):
274
276
  '''Generate a constant colorful image
275
277
  '''
276
278
  flat_array = np.array(COLOR_DICT.get(color_choice)) * np.ones((64, 64, 3))
@@ -282,15 +284,15 @@ def generate_flat_colored_image(color_choice=["red", "green", "blue", "gray"], c
282
284
  - The `color_choice` list will be turned into a nice dropdown menu. Default value here will be red as this is the first element of the list!
283
285
  ----------
284
286
 
285
- :bulb: Can filters communicate together?
286
- Yes, using the special keyword argument `context={}`.
287
- - Check carefully how we stored the image average of the flat image in context.
287
+ 💡 Can filters communicate together?
288
+ Yes, using the `context` proxy from `interactive_pipe`.
289
+ - Check carefully how we stored the image average of the flat image in context.
288
290
  - This value will be available to other filters.
289
291
  `special_image_slice` is going to use that value to set the half bottom image to dark in case the average is high.
290
292
 
291
293
  ```python
292
- @interactive()
293
- def special_image_slice(img, context={}):
294
+ def special_image_slice(img):
295
+ out_img = img.copy()
294
296
  if context["avg"] > 0.4:
295
297
  out_img[out_img.shape[0]//2:, ...] = 0.
296
298
  return out_img
@@ -299,8 +301,8 @@ def special_image_slice(img, context={}):
299
301
 
300
302
 
301
303
  ```python
302
- @interactive()
303
- def switch_image(img1, img2, img3, image_index=(0, [0, 2], None, ["pagedown", "pageup", True])):
304
+ @interactive(image_index=(0, [0, 2], None, ["pagedown", "pageup", True]))
305
+ def switch_image(img1, img2, img3, image_index=0):
304
306
  '''Switch between 3 images
305
307
  '''
306
308
  return [img1, img2, img3][image_index]
@@ -308,8 +310,8 @@ def switch_image(img1, img2, img3, image_index=(0, [0, 2], None, ["pagedown", "p
308
310
  Note that you can create a filter to switch between several images. In `["pagedown", "pageup", True]`, True means that the image_index will wrap around. (it will return to 0 as soon as it goes above the maximum value of 2).
309
311
 
310
312
  ```python
311
- @interactive()
312
- def black_top_image_slice(img, top_slice_black=(True, "special", "k"), context={}):
313
+ @interactive(top_slice_black=(True, "special", "k"))
314
+ def black_top_image_slice(img, top_slice_black=True):
313
315
  out_img = img.copy()
314
316
  if top_slice_black:
315
317
  out_img[:out_img.shape[0]//2, ...] = 0.
@@ -332,6 +334,40 @@ if __name__ == '__main__':
332
334
 
333
335
  ### Release Notes
334
336
 
337
+
338
+ #### Version 0.8.10 (March 2026)
339
+ - Bugfix for jupyter notebooks backends.
340
+ #### Version 0.8.9 (February 2026)
341
+
342
+ **New Features:**
343
+ - **Panel System**: Control panel layout and organization
344
+ - Flexible panel positioning (left, right, top, bottom)
345
+ - Detached control panels for separate windows
346
+ - Nested panels and subpanels support
347
+ - Grouped controls within panels
348
+ - Improved spacing and borders for better visual organization
349
+ - Full backend support (Qt, Gradio, matplotlib, notebook)
350
+
351
+ - **Table Data Type**: Display tabular data natively
352
+ - Core Table functionality without external dependencies
353
+ - Optional pandas DataFrame support for advanced use cases
354
+ - Rendering support across all backends (Qt, Gradio, matplotlib)
355
+ - Headerless tables option
356
+
357
+ - **TimeControl Enhancements**: Better time-based parameter control
358
+ - Improved slider help display
359
+ - Additional demos showcasing time-based animations
360
+
361
+ **API Improvements:**
362
+ - Context support at pipeline initialization
363
+ - Backend selection via enum (string format still supported)
364
+ - Graph visualization for GUI pipelines (press `G`)
365
+
366
+ **Deprecations:**
367
+ - Inline syntax deprecated (use decorator syntax instead)
368
+ - `output_canvas` argument removed
369
+ - Context aliases (`global_params`, `states` etc...) deprecated at initialization
370
+
335
371
  #### Version 0.8.8 (January 2026)
336
372
 
337
373
  **New Features:**
@@ -357,27 +393,34 @@ if __name__ == '__main__':
357
393
  - Fixed pytest failures for optional dependencies in CI
358
394
  - Fixed various edge cases in error handling
359
395
 
360
- **Migration of old context or global_params:**
361
- - Use `global_params=SharedContext.injected()` to let code interpreters know that there's no need to pass this parameter.
396
+ **Migration from old `context={}` or `global_params={}` patterns:**
362
397
 
363
398
  ```python
364
- # Before
365
- def apply_brightness(img:np.ndarray, brightness: float = 0.5, global_params:dict =None):
366
- global_params["brightness"] = brightness
367
- return img * brightness
399
+ # OLD (deprecated) - using context={} or global_params={}
400
+ from interactive_pipe import interactive
368
401
 
369
- # Progressive migration
370
- def apply_brightness(img:np.ndarray, brightness: float = 0.5, global_params:dict ==SharedContext.injected()):
371
- global_params["brightness"] = brightness
402
+ @interactive(brightness=(0.5, [0., 1.]))
403
+ def apply_brightness(img:np.ndarray, brightness: float = 0.5, global_params={}):
404
+ global_params["brightness"] = brightness # Storing shared data
405
+ global_params["__output_styles"]["output"] = {"title": "Brightened"} # Setting layout
372
406
  return img * brightness
373
407
 
374
- # Recommended version
375
- from interactive_pipe import context
408
+ # NEW (recommended) - using context and layout proxies
409
+ from interactive_pipe import interactive, context, layout
410
+
411
+ @interactive(brightness=(0.5, [0., 1.]))
376
412
  def apply_brightness(img:np.ndarray, brightness: float = 0.5):
377
- context.shared_brightness = brightness # shared with all filters
413
+ context["brightness"] = brightness # or: context.brightness = brightness
414
+ layout.style("output", title="Brightened")
378
415
  return img * brightness
379
416
  ```
380
417
 
418
+ The new API provides:
419
+ - `context` - For sharing data between filters (replaces `global_params["key"]`)
420
+ - `layout` - For controlling output display (replaces `global_params["__output_styles"]`)
421
+ - `audio` - For audio playback control
422
+ - `get_context()` - Get the shared context dictionary directly
423
+
381
424
 
382
425
 
383
426
 
@@ -395,7 +438,7 @@ def apply_brightness(img:np.ndarray, brightness: float = 0.5):
395
438
 
396
439
 
397
440
  ### FAQ
398
- - :question: What is the recommended way to access shared context?
441
+ - What is the recommended way to access shared context?
399
442
  > **New in v0.8.8**: Use the clean context API for direct access:
400
443
  > ```python
401
444
  > from interactive_pipe import context, layout, audio, get_context
@@ -409,7 +452,7 @@ def apply_brightness(img:np.ndarray, brightness: float = 0.5):
409
452
  > return img
410
453
  > ```
411
454
 
412
- - :question: How do I change the layout? *Can I change the grid layout of images live? (like you compare 2 images side by side and you want to start comparing 4 images in a 2x2 fashion for debugging purpose)*. It is possible with Qt backend.
455
+ - How do I change the layout? *Can I change the grid layout of images live? (like you compare 2 images side by side and you want to start comparing 4 images in a 2x2 fashion for debugging purpose)*. It is possible with Qt backend.
413
456
 
414
457
  > Use the `layout` helper to control image arrangement and styling:
415
458
  > ```python
@@ -434,16 +477,16 @@ def apply_brightness(img:np.ndarray, brightness: float = 0.5):
434
477
  > return result
435
478
  > ```
436
479
 
437
- - :question: Do I have to remove `KeyboardSlider` when using gradio or notebook backends?
480
+ - Do I have to remove `KeyboardSlider` when using gradio or notebook backends?
438
481
  > No, don't worry, these will be mapped back to regular sliders!
439
- - :question: How do I play audio live?
440
- > :sound: Inside a processing block, write the audio file to disk and use the audio helper:
482
+ - How do I play audio live?
483
+ > 🔊 Inside a processing block, write the audio file to disk and use the audio helper:
441
484
  > ```python
442
485
  > from interactive_pipe import audio
443
486
  > audio.set_audio(audio_file) # New clean API (v0.8.8)
444
487
  > # or legacy: context["__set_audio"](audio_file)
445
488
  > ```
446
- - :question: Do I have to decorate my processing block using the `@interactive`
489
+ - Do I have to decorate my processing block using the `@interactive`
447
490
  > If you use the `@` decoration style, your function won't be useable in a regular manner (wich may be problematic in a serious development environment)
448
491
  ```python
449
492
  @interactive(angle=(0., [-360., 360.]))
@@ -465,11 +508,11 @@ from core_filter import processing_block
465
508
  def add_interactivity():
466
509
  interactive(angle=(0., [-360., 360.]))(processing_block)
467
510
  ```
468
- - :question: Can I call the pipeline in a command line/batch fashion?
469
- > Yes, headless mode is supported. :soon: documentation needed.
511
+ - Can I call the pipeline in a command line/batch fashion?
512
+ > Yes, headless mode is supported. 🔜 documentation needed.
470
513
 
471
514
 
472
- - :question: Can I use inplace operations?
515
+ - Can I use inplace operations?
473
516
  > Better avoid these in general. To avoid making extra copies, computing hashes everywhere and avoid loosing precious computation time, there are no checks that inputs are not modified in place.
474
517
  ```python
475
518
  # Don't do that!
@@ -477,38 +520,18 @@ def bad_processing_block(inp):
477
520
  inp+=1
478
521
  ```
479
522
 
480
- - :question: Is there a difference between `global_params` and `context` ?
523
+ - Is there a difference between `global_params` and `context` ?
481
524
  > No, `global_params`, `global_parameters`, `global_state`, `global_context`, `context`, `state` all mean the same thing and are all supported for legacy reasons. `context` is the preferred wording. However, we now recommend using the clean context API (see above).
482
- > :warning: The old `global_params={}` / `context={}` keyword argument style still works for backwards compatibility but is deprecated.
525
+ > ⚠️ The old `global_params={}` / `context={}` keyword argument style still works for backwards compatibility but is deprecated.
483
526
 
484
527
 
485
528
 
486
529
  # Roadmap and todos
487
- :bug: Want to contribute or interested in adding new features? Enter a new [Github issue](https://github.com/balthazarneveu/interactive_pipe/issues)
530
+ 🐛 Want to contribute or interested in adding new features? Enter a new [Github issue](https://github.com/balthazarneveu/interactive_pipe/issues)
488
531
 
489
- :gift: Want to dig into the code? Take a look at [code_architecture.md](/code_architecture.md)
532
+ 🎁 Want to dig into the code? Take a look at [code_architecture.md](/code_architecture.md)
490
533
 
491
- ## Short term roadmap
492
- - Backport previous features
493
- - Image class support in interactive pipe (Heatmaps/Float images)
494
534
 
495
- ## Long term roadmap
496
- - Advanced feature
497
- - Webcam based "slider" for dropdown menu (like "elephant" will trigget if an elephant is magically detected on the webcam)
498
- - Animations/While loops/Video source (Time slider)
499
- - Exploratory backends
500
- - Create a [textual](https://github.com/Textualize/textual) backend for simplified GUI (probably no images displayed)
501
- - Create a [Kivy](https://kivy.org/) backend
502
-
503
-
504
- ### Further examples
505
-
506
- #### [Minimalistic pytorch based ISP ](https://github.com/balthazarneveu/interactive_pipe/tree/sample_interactive_isp/samples/isp)
507
- [ISP means image signal processor](https://en.wikipedia.org/wiki/Image_processor)
508
-
509
- :warning: Work in progess (no proper demosaicking, no denoiser, no tone mapping.)
510
-
511
- ![Ultra simplistic ISP](/doc/images/isp_pipeline.png)
512
535
 
513
536
  ----------------------
514
537
 
@@ -516,30 +539,44 @@ def bad_processing_block(inp):
516
539
 
517
540
  #### Code quality checks
518
541
 
519
- Before committing, ensure your code passes the linters and tests. The CI runs these checks automatically:
542
+ Before committing, ensure your code passes the linters, type checker, and tests. The CI runs these checks automatically:
520
543
 
521
544
  **What CI does:**
522
- - **Black formatting check** (`.github/workflows/formatting.yaml`): Runs `black --check` to verify code formatting
523
- - **Flake8 linting** (`.github/workflows/flake8.yaml`): Runs `flake8` to check code quality
545
+ - **Ruff formatting check** (`.github/workflows/ruff-format.yaml`): Runs `ruff format --check` to verify code formatting
546
+ - **Ruff linting** (`.github/workflows/ruff-lint.yaml`): Runs `ruff check` to check code quality (replaces flake8)
547
+ - **Pyright type checking** (`.github/workflows/pyright.yaml`): Runs `pyright` for static type checking (informational, non-blocking)
524
548
  - **Pytest tests** (`.github/workflows/pytest.yaml`): Runs `pytest` on Python 3.9, 3.10, and 3.11
525
549
 
526
550
  **Local commands (match CI):**
527
551
 
528
552
  ```bash
529
- # Install linting tools and test dependencies
530
- pip install black flake8
531
- pip install -e ".[pytest]"
553
+ # Install development tools and test dependencies
554
+ pip install -e ".[dev,pytest]"
532
555
 
533
- # Check code formatting (Black) - matches CI
534
- black --check .
556
+ # Format code (Ruff) - matches CI
557
+ ruff format .
535
558
 
536
- # Auto-format code (Black) - run this if check fails
537
- black .
559
+ # Check formatting (Ruff) - matches CI
560
+ ruff format --check .
538
561
 
539
- # Run linting checks (flake8) - matches CI
540
- flake8 .
562
+ # Lint code (Ruff) - matches CI (auto-fixes when possible)
563
+ ruff check .
564
+
565
+ # Auto-fix linting issues (Ruff)
566
+ ruff check --fix .
567
+
568
+ # Type check (Pyright) - matches CI (informational)
569
+ pyright src/
541
570
 
542
571
  # Run tests (pytest) - matches CI
543
572
  pytest
573
+
574
+ # Pre-commit checklist (run all before committing)
575
+ ruff format .
576
+ ruff check --fix .
577
+ pyright src/ # Optional, won't block commit
578
+ pytest
544
579
  ```
545
580
 
581
+ **Note:** Ruff replaces both Black (formatting) and Flake8 (linting) in a single, faster tool. Pyright provides static type checking to catch type errors early.
582
+
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
 
6
6
  [project]
7
7
  name = "interactive_pipe"
8
- version = "0.8.8"
8
+ version = "0.8.10"
9
9
  authors = [
10
10
  { name="Balthazar Neveu", email="balthazarneveu@gmail.com" },
11
11
  ]
@@ -14,13 +14,6 @@ dependencies = [
14
14
  "numpy>=1.21.6",
15
15
  "Pillow>=9.0.1",
16
16
  "PyYAML>=5.4.1",
17
- "PyQt6>=6.5.2",
18
- "PyQt6_sip>=13.5.2",
19
- "opencv_python_headless>=4.8.1.78",
20
- "pytest>=6.2.5",
21
- "ipywidgets>=7.7.1",
22
- "pandas",
23
- "gradio",
24
17
  ]
25
18
 
26
19
  description = "Library to create flexible interactive image processing pipelines and automatically add a graphical user interface without knowing anything about GUI coding!"
@@ -65,3 +58,35 @@ full=[
65
58
  "pandas",
66
59
  "gradio",
67
60
  ]
61
+
62
+ dev=[
63
+ "ruff>=0.9.0",
64
+ "pyright>=1.1.390",
65
+ ]
66
+
67
+ [tool.ruff]
68
+ line-length = 120
69
+ target-version = "py39"
70
+ exclude = ["__init__.py", "*/__pycache__/*", "*venv*/*"]
71
+
72
+ [tool.ruff.lint]
73
+ select = ["E", "F", "W", "I"] # E/F/W = flake8 rules, I = isort
74
+ ignore = ["E203"] # E203: whitespace before ':' (conflicts with black formatting)
75
+
76
+ [tool.ruff.lint.isort]
77
+ # isort compatibility
78
+
79
+ [tool.ruff.format]
80
+ # Black-compatible formatting (default)
81
+
82
+ [tool.pyright]
83
+ pythonVersion = "3.9"
84
+ typeCheckingMode = "basic"
85
+ include = ["src"]
86
+ exclude = ["**/venv/**", "**/__pycache__/**", "test/**"]
87
+ reportMissingImports = "none" # Qt libs and other optional dependencies
88
+ reportMissingTypeStubs = false
89
+ reportUnknownMemberType = false
90
+ reportUnknownArgumentType = false
91
+ reportUnknownVariableType = false
92
+ reportPrivateUsage = false