syd 1.0.2__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- syd/__init__.py +3 -10
- syd/flask_deployment/deployer.py +119 -26
- syd/flask_deployment/static/css/styles.css +100 -67
- syd/flask_deployment/static/css/viewer.css +48 -0
- syd/flask_deployment/static/js/modules/api.js +89 -0
- syd/flask_deployment/static/js/modules/config.js +22 -0
- syd/flask_deployment/static/js/modules/plot.js +75 -0
- syd/flask_deployment/static/js/modules/state.js +89 -0
- syd/flask_deployment/static/js/modules/system_controls.js +191 -0
- syd/flask_deployment/static/js/modules/ui_controls.js +812 -0
- syd/flask_deployment/static/js/modules/utils.js +49 -0
- syd/flask_deployment/static/js/old_viewer.js +1195 -0
- syd/flask_deployment/static/js/viewer.js +53 -826
- syd/flask_deployment/templates/index.html +1 -1
- syd/notebook_deployment/deployer.py +1 -3
- syd/notebook_deployment/widgets.py +45 -27
- syd/support.py +25 -0
- syd/viewer.py +35 -4
- {syd-1.0.2.dist-info → syd-1.2.0.dist-info}/METADATA +24 -10
- syd-1.2.0.dist-info/RECORD +28 -0
- syd-1.0.2.dist-info/RECORD +0 -19
- {syd-1.0.2.dist-info → syd-1.2.0.dist-info}/WHEEL +0 -0
- {syd-1.0.2.dist-info → syd-1.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -29,6 +29,6 @@
|
|
|
29
29
|
data-controls-width-percent="{{ config.controls_width_percent }}"
|
|
30
30
|
style="display:none;"></div>
|
|
31
31
|
|
|
32
|
-
<script src="{{ url_for('static', filename='js/viewer.js') }}"></script>
|
|
32
|
+
<script type="module" src="{{ url_for('static', filename='js/viewer.js') }}"></script>
|
|
33
33
|
</body>
|
|
34
34
|
</html>
|
|
@@ -39,7 +39,6 @@ class NotebookDeployer:
|
|
|
39
39
|
viewer: Viewer,
|
|
40
40
|
controls_position: Literal["left", "top", "right", "bottom"] = "left",
|
|
41
41
|
controls_width_percent: int = 20,
|
|
42
|
-
continuous: bool = False,
|
|
43
42
|
suppress_warnings: bool = True,
|
|
44
43
|
update_threshold: float = 1.0,
|
|
45
44
|
):
|
|
@@ -49,7 +48,6 @@ class NotebookDeployer:
|
|
|
49
48
|
self._updating = False # Flag to check circular updates
|
|
50
49
|
self.controls_position = controls_position
|
|
51
50
|
self.controls_width_percent = controls_width_percent
|
|
52
|
-
self.continuous = continuous
|
|
53
51
|
|
|
54
52
|
# Initialize containers
|
|
55
53
|
self.backend_type = get_backend_type()
|
|
@@ -117,7 +115,7 @@ class NotebookDeployer:
|
|
|
117
115
|
def build_components(self) -> None:
|
|
118
116
|
"""Create widget instances for all parameters and equip callbacks."""
|
|
119
117
|
for name, param in self.viewer.parameters.items():
|
|
120
|
-
widget = create_widget(param
|
|
118
|
+
widget = create_widget(param)
|
|
121
119
|
self.components[name] = widget
|
|
122
120
|
callback = lambda _, n=name: self.handle_component_engagement(n)
|
|
123
121
|
widget.observe(callback)
|
|
@@ -36,13 +36,15 @@ class BaseWidget(Generic[T, W], ABC):
|
|
|
36
36
|
def __init__(
|
|
37
37
|
self,
|
|
38
38
|
parameter: T,
|
|
39
|
-
continuous: bool = False,
|
|
40
39
|
width: str = "auto",
|
|
41
40
|
margin: str = "3px 0px",
|
|
42
41
|
description_width: str = "initial",
|
|
43
42
|
):
|
|
44
43
|
self._widget = self._create_widget(
|
|
45
|
-
parameter,
|
|
44
|
+
parameter,
|
|
45
|
+
width,
|
|
46
|
+
margin,
|
|
47
|
+
description_width,
|
|
46
48
|
)
|
|
47
49
|
self._updating = False # Flag to prevent circular updates
|
|
48
50
|
# List of callbacks to remember for quick disabling/enabling
|
|
@@ -52,7 +54,6 @@ class BaseWidget(Generic[T, W], ABC):
|
|
|
52
54
|
def _create_widget(
|
|
53
55
|
self,
|
|
54
56
|
parameter: T,
|
|
55
|
-
continuous: bool,
|
|
56
57
|
width: str = "auto",
|
|
57
58
|
margin: str = "3px 0px",
|
|
58
59
|
description_width: str = "initial",
|
|
@@ -123,7 +124,6 @@ class TextWidget(BaseWidget[TextParameter, widgets.Text]):
|
|
|
123
124
|
def _create_widget(
|
|
124
125
|
self,
|
|
125
126
|
parameter: TextParameter,
|
|
126
|
-
continuous: bool,
|
|
127
127
|
width: str = "auto",
|
|
128
128
|
margin: str = "3px 0px",
|
|
129
129
|
description_width: str = "initial",
|
|
@@ -131,7 +131,7 @@ class TextWidget(BaseWidget[TextParameter, widgets.Text]):
|
|
|
131
131
|
return widgets.Text(
|
|
132
132
|
value=parameter.value,
|
|
133
133
|
description=parameter.name,
|
|
134
|
-
continuous=
|
|
134
|
+
continuous=False,
|
|
135
135
|
layout=widgets.Layout(width=width, margin=margin),
|
|
136
136
|
style={"description_width": description_width},
|
|
137
137
|
)
|
|
@@ -143,7 +143,6 @@ class BooleanWidget(BaseWidget[BooleanParameter, widgets.ToggleButton]):
|
|
|
143
143
|
def _create_widget(
|
|
144
144
|
self,
|
|
145
145
|
parameter: BooleanParameter,
|
|
146
|
-
continuous: bool,
|
|
147
146
|
width: str = "auto",
|
|
148
147
|
margin: str = "3px 0px",
|
|
149
148
|
description_width: str = "initial",
|
|
@@ -162,7 +161,6 @@ class SelectionWidget(BaseWidget[SelectionParameter, widgets.Dropdown]):
|
|
|
162
161
|
def _create_widget(
|
|
163
162
|
self,
|
|
164
163
|
parameter: SelectionParameter,
|
|
165
|
-
continuous: bool,
|
|
166
164
|
width: str = "auto",
|
|
167
165
|
margin: str = "3px 0px",
|
|
168
166
|
description_width: str = "initial",
|
|
@@ -198,7 +196,6 @@ class MultipleSelectionWidget(
|
|
|
198
196
|
def _create_widget(
|
|
199
197
|
self,
|
|
200
198
|
parameter: MultipleSelectionParameter,
|
|
201
|
-
continuous: bool,
|
|
202
199
|
width: str = "auto",
|
|
203
200
|
margin: str = "3px 0px",
|
|
204
201
|
description_width: str = "initial",
|
|
@@ -235,7 +232,6 @@ class IntegerWidget(BaseWidget[IntegerParameter, widgets.IntSlider]):
|
|
|
235
232
|
def _create_widget(
|
|
236
233
|
self,
|
|
237
234
|
parameter: IntegerParameter,
|
|
238
|
-
continuous: bool,
|
|
239
235
|
width: str = "auto",
|
|
240
236
|
margin: str = "3px 0px",
|
|
241
237
|
description_width: str = "initial",
|
|
@@ -247,7 +243,7 @@ class IntegerWidget(BaseWidget[IntegerParameter, widgets.IntSlider]):
|
|
|
247
243
|
max=parameter.max,
|
|
248
244
|
step=1,
|
|
249
245
|
description=parameter.name,
|
|
250
|
-
continuous_update=
|
|
246
|
+
continuous_update=False,
|
|
251
247
|
style={"description_width": description_width},
|
|
252
248
|
layout=widgets.Layout(width=width, margin=margin),
|
|
253
249
|
)
|
|
@@ -264,6 +260,10 @@ class IntegerWidget(BaseWidget[IntegerParameter, widgets.IntSlider]):
|
|
|
264
260
|
def extra_updates_from_parameter(self, parameter: IntegerParameter) -> None:
|
|
265
261
|
"""Update the widget attributes from the parameter."""
|
|
266
262
|
current_value = self._widget.value
|
|
263
|
+
if parameter.min > self._widget.max:
|
|
264
|
+
self._widget.max = parameter.min + 1
|
|
265
|
+
if parameter.max < self._widget.min:
|
|
266
|
+
self._widget.min = parameter.max - 1
|
|
267
267
|
self._widget.min = parameter.min
|
|
268
268
|
self._widget.max = parameter.max
|
|
269
269
|
self.value = max(parameter.min, min(parameter.max, current_value))
|
|
@@ -275,7 +275,6 @@ class FloatWidget(BaseWidget[FloatParameter, widgets.FloatSlider]):
|
|
|
275
275
|
def _create_widget(
|
|
276
276
|
self,
|
|
277
277
|
parameter: FloatParameter,
|
|
278
|
-
continuous: bool,
|
|
279
278
|
width: str = "auto",
|
|
280
279
|
margin: str = "3px 0px",
|
|
281
280
|
description_width: str = "initial",
|
|
@@ -287,7 +286,7 @@ class FloatWidget(BaseWidget[FloatParameter, widgets.FloatSlider]):
|
|
|
287
286
|
max=parameter.max,
|
|
288
287
|
step=parameter.step,
|
|
289
288
|
description=parameter.name,
|
|
290
|
-
continuous_update=
|
|
289
|
+
continuous_update=False,
|
|
291
290
|
style={"description_width": description_width},
|
|
292
291
|
layout=widgets.Layout(width=width, margin=margin),
|
|
293
292
|
)
|
|
@@ -305,6 +304,10 @@ class FloatWidget(BaseWidget[FloatParameter, widgets.FloatSlider]):
|
|
|
305
304
|
def extra_updates_from_parameter(self, parameter: FloatParameter) -> None:
|
|
306
305
|
"""Update the widget attributes from the parameter."""
|
|
307
306
|
current_value = self._widget.value
|
|
307
|
+
if parameter.min > self._widget.max:
|
|
308
|
+
self._widget.max = parameter.min + 1
|
|
309
|
+
if parameter.max < self._widget.min:
|
|
310
|
+
self._widget.min = parameter.max - 1
|
|
308
311
|
self._widget.min = parameter.min
|
|
309
312
|
self._widget.max = parameter.max
|
|
310
313
|
self._widget.step = parameter.step
|
|
@@ -317,7 +320,6 @@ class IntegerRangeWidget(BaseWidget[IntegerRangeParameter, widgets.IntRangeSlide
|
|
|
317
320
|
def _create_widget(
|
|
318
321
|
self,
|
|
319
322
|
parameter: IntegerRangeParameter,
|
|
320
|
-
continuous: bool,
|
|
321
323
|
width: str = "auto",
|
|
322
324
|
margin: str = "3px 0px",
|
|
323
325
|
description_width: str = "initial",
|
|
@@ -330,7 +332,7 @@ class IntegerRangeWidget(BaseWidget[IntegerRangeParameter, widgets.IntRangeSlide
|
|
|
330
332
|
max=parameter.max,
|
|
331
333
|
step=1,
|
|
332
334
|
description=parameter.name,
|
|
333
|
-
continuous_update=
|
|
335
|
+
continuous_update=False,
|
|
334
336
|
style={"description_width": description_width},
|
|
335
337
|
layout=widgets.Layout(width=width, margin=margin),
|
|
336
338
|
)
|
|
@@ -349,6 +351,10 @@ class IntegerRangeWidget(BaseWidget[IntegerRangeParameter, widgets.IntRangeSlide
|
|
|
349
351
|
def extra_updates_from_parameter(self, parameter: IntegerRangeParameter) -> None:
|
|
350
352
|
"""Update the widget attributes from the parameter."""
|
|
351
353
|
low, high = self._widget.value
|
|
354
|
+
if parameter.min > self._widget.max:
|
|
355
|
+
self._widget.max = parameter.min + 1
|
|
356
|
+
if parameter.max < self._widget.min:
|
|
357
|
+
self._widget.min = parameter.max - 1
|
|
352
358
|
self._widget.min = parameter.min
|
|
353
359
|
self._widget.max = parameter.max
|
|
354
360
|
# Ensure values stay within bounds
|
|
@@ -363,7 +369,6 @@ class FloatRangeWidget(BaseWidget[FloatRangeParameter, widgets.FloatRangeSlider]
|
|
|
363
369
|
def _create_widget(
|
|
364
370
|
self,
|
|
365
371
|
parameter: FloatRangeParameter,
|
|
366
|
-
continuous: bool,
|
|
367
372
|
width: str = "auto",
|
|
368
373
|
margin: str = "3px 0px",
|
|
369
374
|
description_width: str = "initial",
|
|
@@ -376,7 +381,7 @@ class FloatRangeWidget(BaseWidget[FloatRangeParameter, widgets.FloatRangeSlider]
|
|
|
376
381
|
max=parameter.max,
|
|
377
382
|
step=parameter.step,
|
|
378
383
|
description=parameter.name,
|
|
379
|
-
continuous_update=
|
|
384
|
+
continuous_update=False,
|
|
380
385
|
style={"description_width": description_width},
|
|
381
386
|
layout=widgets.Layout(width=width, margin=margin),
|
|
382
387
|
)
|
|
@@ -396,6 +401,10 @@ class FloatRangeWidget(BaseWidget[FloatRangeParameter, widgets.FloatRangeSlider]
|
|
|
396
401
|
def extra_updates_from_parameter(self, parameter: FloatRangeParameter) -> None:
|
|
397
402
|
"""Update the widget attributes from the parameter."""
|
|
398
403
|
low, high = self._widget.value
|
|
404
|
+
if parameter.min > self._widget.max:
|
|
405
|
+
self._widget.max = parameter.min + 1
|
|
406
|
+
if parameter.max < self._widget.min:
|
|
407
|
+
self._widget.min = parameter.max - 1
|
|
399
408
|
self._widget.min = parameter.min
|
|
400
409
|
self._widget.max = parameter.max
|
|
401
410
|
self._widget.step = parameter.step
|
|
@@ -411,7 +420,6 @@ class UnboundedIntegerWidget(BaseWidget[UnboundedIntegerParameter, widgets.IntTe
|
|
|
411
420
|
def _create_widget(
|
|
412
421
|
self,
|
|
413
422
|
parameter: UnboundedIntegerParameter,
|
|
414
|
-
continuous: bool,
|
|
415
423
|
width: str = "auto",
|
|
416
424
|
margin: str = "3px 0px",
|
|
417
425
|
description_width: str = "initial",
|
|
@@ -440,7 +448,6 @@ class UnboundedFloatWidget(BaseWidget[UnboundedFloatParameter, widgets.FloatText
|
|
|
440
448
|
def _create_widget(
|
|
441
449
|
self,
|
|
442
450
|
parameter: UnboundedFloatParameter,
|
|
443
|
-
continuous: bool,
|
|
444
451
|
width: str = "auto",
|
|
445
452
|
margin: str = "3px 0px",
|
|
446
453
|
description_width: str = "initial",
|
|
@@ -470,7 +477,6 @@ class ButtonWidget(BaseWidget[ButtonAction, widgets.Button]):
|
|
|
470
477
|
def _create_widget(
|
|
471
478
|
self,
|
|
472
479
|
parameter: ButtonAction,
|
|
473
|
-
continuous: bool,
|
|
474
480
|
width: str = "auto",
|
|
475
481
|
margin: str = "3px 0px",
|
|
476
482
|
description_width: str = "initial",
|
|
@@ -514,19 +520,32 @@ class ButtonWidget(BaseWidget[ButtonAction, widgets.Button]):
|
|
|
514
520
|
|
|
515
521
|
def create_widget(
|
|
516
522
|
parameter: Union[Parameter[Any], ButtonAction],
|
|
517
|
-
continuous: bool = False,
|
|
518
523
|
width: str = "auto",
|
|
519
524
|
margin: str = "3px 0px",
|
|
520
525
|
description_width: str = "initial",
|
|
521
526
|
) -> BaseWidget[Union[Parameter[Any], ButtonAction], widgets.Widget]:
|
|
522
527
|
"""Create and return the appropriate widget for the given parameter.
|
|
523
528
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
529
|
+
Parameters
|
|
530
|
+
----------
|
|
531
|
+
parameter : Union[Parameter[Any], ButtonAction]
|
|
532
|
+
The parameter to create a widget for.
|
|
533
|
+
width : str, optional
|
|
534
|
+
Width of the widget. Default is 'auto'.
|
|
535
|
+
margin : str, optional
|
|
536
|
+
Margin of the widget. Default is '3px 0px'.
|
|
537
|
+
description_width : str, optional
|
|
538
|
+
Width of the description label. Default is 'initial'.
|
|
539
|
+
|
|
540
|
+
Returns
|
|
541
|
+
-------
|
|
542
|
+
BaseWidget[Union[Parameter[Any], ButtonAction], widgets.Widget]
|
|
543
|
+
The appropriate widget instance for the given parameter type.
|
|
544
|
+
|
|
545
|
+
Raises
|
|
546
|
+
------
|
|
547
|
+
ValueError
|
|
548
|
+
If no widget implementation exists for the given parameter type.
|
|
530
549
|
"""
|
|
531
550
|
widget_map = {
|
|
532
551
|
TextParameter: TextWidget,
|
|
@@ -562,7 +581,6 @@ def create_widget(
|
|
|
562
581
|
|
|
563
582
|
return widget_class(
|
|
564
583
|
parameter,
|
|
565
|
-
continuous,
|
|
566
584
|
width=width,
|
|
567
585
|
margin=margin,
|
|
568
586
|
description_width=description_width,
|
syd/support.py
CHANGED
|
@@ -5,6 +5,31 @@ from contextlib import contextmanager
|
|
|
5
5
|
import matplotlib.pyplot as plt
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
def show_open_servers():
|
|
9
|
+
"""Show all open Flask servers."""
|
|
10
|
+
from .flask_deployment.deployer import server_manager
|
|
11
|
+
|
|
12
|
+
print(server_manager.servers)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def close_servers(port: int | None = None):
|
|
16
|
+
"""Close any Flask servers running on a given port (or all of them).
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
port : int | None, optional
|
|
21
|
+
The port of the Flask server to close. If None, all servers will be closed.
|
|
22
|
+
|
|
23
|
+
Examples
|
|
24
|
+
--------
|
|
25
|
+
>>> close() # Close all Flask servers
|
|
26
|
+
>>> close(8000) # Close the Flask server running on port 8000
|
|
27
|
+
"""
|
|
28
|
+
from .flask_deployment.deployer import server_manager
|
|
29
|
+
|
|
30
|
+
server_manager.close_app(port)
|
|
31
|
+
|
|
32
|
+
|
|
8
33
|
@contextmanager
|
|
9
34
|
def plot_context():
|
|
10
35
|
plt.ioff()
|
syd/viewer.py
CHANGED
|
@@ -12,6 +12,36 @@ NO_UPDATE = NoUpdate()
|
|
|
12
12
|
NO_INITIAL_VALUE = NoInitialValue()
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
def make_viewer(plot_func: Optional[Callable] = None) -> "Viewer":
|
|
16
|
+
"""Create an empty viewer object.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
plot_func : Callable, optional
|
|
21
|
+
A function that takes a state dictionary and returns a matplotlib figure.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
viewer : Viewer
|
|
26
|
+
A new viewer object
|
|
27
|
+
|
|
28
|
+
Examples
|
|
29
|
+
--------
|
|
30
|
+
>>> from syd import make_viewer
|
|
31
|
+
>>> def plot(state):
|
|
32
|
+
>>> ... generate figure, plot stuff ...
|
|
33
|
+
>>> return fig
|
|
34
|
+
>>> viewer = make_viewer(plot)
|
|
35
|
+
>>> viewer.add_float('x', value=1.0, min=0, max=10)
|
|
36
|
+
>>> viewer.on_change('x', viewer.update_based_on_x)
|
|
37
|
+
>>> viewer.show()
|
|
38
|
+
"""
|
|
39
|
+
viewer = Viewer()
|
|
40
|
+
if plot_func is not None:
|
|
41
|
+
viewer.set_plot(plot_func)
|
|
42
|
+
return viewer
|
|
43
|
+
|
|
44
|
+
|
|
15
45
|
def validate_parameter_operation(
|
|
16
46
|
operation: str,
|
|
17
47
|
parameter_type: Union[ParameterType, ActionType],
|
|
@@ -216,7 +246,6 @@ class Viewer:
|
|
|
216
246
|
self,
|
|
217
247
|
controls_position: Literal["left", "top", "right", "bottom"] = "left",
|
|
218
248
|
controls_width_percent: int = 20,
|
|
219
|
-
continuous: bool = False,
|
|
220
249
|
suppress_warnings: bool = True,
|
|
221
250
|
update_threshold: float = 1.0,
|
|
222
251
|
):
|
|
@@ -228,7 +257,6 @@ class Viewer:
|
|
|
228
257
|
env="notebook",
|
|
229
258
|
controls_position=controls_position,
|
|
230
259
|
controls_width_percent=controls_width_percent,
|
|
231
|
-
continuous=continuous,
|
|
232
260
|
suppress_warnings=suppress_warnings,
|
|
233
261
|
update_threshold=update_threshold,
|
|
234
262
|
)
|
|
@@ -243,6 +271,8 @@ class Viewer:
|
|
|
243
271
|
host: str = "127.0.0.1",
|
|
244
272
|
port: Optional[int] = None,
|
|
245
273
|
open_browser: bool = True,
|
|
274
|
+
update_threshold: float = 1.0,
|
|
275
|
+
timeout_threshold: float = 10.0,
|
|
246
276
|
):
|
|
247
277
|
"""Share the viewer on a web browser using Flask
|
|
248
278
|
|
|
@@ -258,6 +288,8 @@ class Viewer:
|
|
|
258
288
|
host=host,
|
|
259
289
|
port=port,
|
|
260
290
|
open_browser=open_browser,
|
|
291
|
+
update_threshold=update_threshold,
|
|
292
|
+
timeout_threshold=timeout_threshold,
|
|
261
293
|
)
|
|
262
294
|
|
|
263
295
|
def deploy(self, env: str = "notebook", **kwargs):
|
|
@@ -427,9 +459,8 @@ class Viewer:
|
|
|
427
459
|
try:
|
|
428
460
|
self._in_callbacks = True
|
|
429
461
|
if name in self.callbacks:
|
|
430
|
-
state = self.state
|
|
431
462
|
for callback in self.callbacks[name]:
|
|
432
|
-
callback(state)
|
|
463
|
+
callback(self.state)
|
|
433
464
|
finally:
|
|
434
465
|
self._in_callbacks = False
|
|
435
466
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: syd
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: A Python package for making GUIs for data science easy.
|
|
5
5
|
Project-URL: Homepage, https://github.com/landoskape/syd
|
|
6
6
|
Author-email: Andrew Landau <andrew+tyler+landau+getridofthisanddtheplusses@gmail.com>
|
|
@@ -47,7 +47,7 @@ Have you ever wanted to look through all your data really quickly interactively?
|
|
|
47
47
|
|
|
48
48
|
Syd is a system for creating a data viewing GUI that you can view in a jupyter notebook or in a web browser. And guess what? Since it can open in a web browser, you can even open it on any other computer on your local network! For example, your PI's computer. Gone are the days of single random examples that they make infinitely stubborn conclusions about. Now, you can look at all the examples, quickly and easily, on their computer. And that's why Syd stands for share your data!
|
|
49
49
|
|
|
50
|
-
Okay, so what is it? Syd is an automated system to convert some basic python plotting code into an interactive GUI. This means you only have to think about what you want to
|
|
50
|
+
Okay, so what is it? Syd is an automated system to convert some basic python plotting code into an interactive GUI. This means you only have to think about _**what you want to plot**_ and _**which parameters**_ you want to be interactive. Syd handles all the behind-the-scenes action required to make an interface. And guess what? That means you get to _**spend your time thinking**_ about your data, rather than writing code to look at it. And that's why Syd stands for Science, Yes! Dayummmm!
|
|
51
51
|
|
|
52
52
|
## Installation
|
|
53
53
|
It's easy, just use pip install. The dependencies are light so it should work in most environments.
|
|
@@ -56,7 +56,7 @@ pip install syd
|
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
## Documentation
|
|
59
|
-
The full documentation is available
|
|
59
|
+
The full documentation is available [here](https://shareyourdata.readthedocs.io/). It includes a quick start guide, a comprehensive tutorial, and an API reference for the different elements of Syd. If you have any questions or want to suggest improvements to the docs, please let us know on the [github issues page](https://github.com/landoskape/syd/issues)!
|
|
60
60
|
|
|
61
61
|
## Quick Start
|
|
62
62
|
This is an example of a sine wave viewer which is about as simple as it gets. You can choose which env to use - if you use ``env="notebook"`` then the GUI will deploy as the output of a jupyter cell (this only works in jupyter!). If you use ``env="browser"`` then the GUI will open a page in your default web browser and you can interact with the data there (works in jupyter notebooks and also from python scripts!).
|
|
@@ -78,9 +78,8 @@ viewer.add_float("amplitude", value=1.0, min=0.1, max=2.0)
|
|
|
78
78
|
viewer.add_float("frequency", value=1.0, min=0.1, max=5.0)
|
|
79
79
|
viewer.add_selection("color", value="red", options=["red", "blue", "green", "black"])
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
viewer.show()
|
|
81
|
+
viewer.show() # for viewing in a jupyter notebook
|
|
82
|
+
# viewer.share() # for viewing in a web browser
|
|
84
83
|
```
|
|
85
84
|
|
|
86
85
|

|
|
@@ -202,7 +201,21 @@ This project is licensed under the GNU General Public License v3.0 - see the [LI
|
|
|
202
201
|
|
|
203
202
|
## Contributing
|
|
204
203
|
|
|
205
|
-
Contributions are welcome!
|
|
204
|
+
Contributions are welcome! If you have an idea for an improvement or a bug report, please let us know by opening an
|
|
205
|
+
issue on the [github issues page](https://github.com/landoskape/syd/issues). You can also contribute code by submitting
|
|
206
|
+
a pull request. Here are some guidelines for contributing:
|
|
207
|
+
|
|
208
|
+
### 1. Reporting Bugs
|
|
209
|
+
If you find a bug, (e.g. any error or strange behavior that is not expected), please let us know by opening an issue on the [github issues page](https://github.com/landoskape/syd/issues).
|
|
210
|
+
|
|
211
|
+
### 2. Suggesting Features
|
|
212
|
+
If you have an idea for a feature or improvement, please let tell us. Opening an issue on the [github issues page](https://github.com/landoskape/syd/issues).
|
|
213
|
+
|
|
214
|
+
### 3. Improvements to the Documentation
|
|
215
|
+
A package is only as good as its documentation. If you think the documentation is missing something, confusing, or could be improved in any way, please let us know by opening an issue on the [github issues page](https://github.com/landoskape/syd/issues).
|
|
216
|
+
|
|
217
|
+
### 4. Contributing Code
|
|
218
|
+
If you want to contribute code (good for you!), here's how you can do it:
|
|
206
219
|
|
|
207
220
|
1. Fork the repository
|
|
208
221
|
2. Create a new branch (`git checkout -b feature/amazing-feature`)
|
|
@@ -212,7 +225,7 @@ Contributions are welcome! Here's how you can help:
|
|
|
212
225
|
6. Push to the branch (`git push origin feature/amazing-feature`)
|
|
213
226
|
7. Open a Pull Request online
|
|
214
227
|
|
|
215
|
-
Please make sure to update tests as appropriate and adhere to the existing coding style (black, line-length=88, other style guidelines not capture by black, generally following pep8 guidelines). Try to make the code coverage report improve or stay the same rather than decrease (right now the deployment system isn't covered by tests).
|
|
228
|
+
Please make sure to update tests as appropriate and adhere to the existing coding style (black, line-length=88, other style guidelines not capture by black, generally following pep8 guidelines). Try to make the code coverage report improve or stay the same rather than decrease (right now the deployment system isn't covered by tests). There aren't any precommit hooks or anything so you're responsible for checking this yourself. You can process the code with black as follows:
|
|
216
229
|
```bash
|
|
217
230
|
pip install black
|
|
218
231
|
black . # from the root directory of the repo
|
|
@@ -220,7 +233,6 @@ black . # from the root directory of the repo
|
|
|
220
233
|
|
|
221
234
|
## To-Do List
|
|
222
235
|
- Layout controls
|
|
223
|
-
- [ ] Improve the display and make it look better
|
|
224
236
|
- [ ] Add a "save" button that saves the current state of the viewer to a json file
|
|
225
237
|
- [ ] Add a "load" button that loads the viewer state from a json file
|
|
226
238
|
- [ ] Add a "freeze" button that allows the user to update state variables without updating the plot until unfreezing
|
|
@@ -228,4 +240,6 @@ black . # from the root directory of the repo
|
|
|
228
240
|
- [ ] Consider "app_deployed" context for each deployer...
|
|
229
241
|
- Export options:
|
|
230
242
|
- [ ] Export lite: export the viewer as a HTML/Java package that contains an incomplete set of renderings of figures -- using a certain set of parameters.
|
|
231
|
-
- [ ] Export full: export the viewer in a way that contains the data to give full functionality.
|
|
243
|
+
- [ ] Export full: export the viewer in a way that contains the data to give full functionality.
|
|
244
|
+
- [ ] Idea for sharing: https://github.com/analyticalmonk/awesome-neuroscience, https://github.com/fasouto/awesome-dataviz
|
|
245
|
+
- [ ] The handling of value in Selection parameters is kind of weird.... I think we need to think more about what to do for fails!!!!
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
syd/__init__.py,sha256=ln2sVWmAbfLzF0oqYPE0g2TYdIqms9_Va984I0eBfiU,117
|
|
2
|
+
syd/parameters.py,sha256=dlnYOVsi1CDtC2toVECf0kNBRipVrtUjr6XVX86b5MA,42886
|
|
3
|
+
syd/support.py,sha256=WVvcKKHWChZWJewc9-vwSChGwmzXobxU5pNmrjrsC3k,6770
|
|
4
|
+
syd/viewer.py,sha256=c53tJlnbnTCGDJEYhiuKZ76tU7Dcd7S8VWY_1O8aAN0,51692
|
|
5
|
+
syd/flask_deployment/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
6
|
+
syd/flask_deployment/deployer.py,sha256=8W51sUZx7iUtFTseNacRa2XOgQVOGGR96nBf8NZS2Qg,29287
|
|
7
|
+
syd/flask_deployment/testing_principles.md,sha256=GyULM97sDeie8h3tSPoduOckdMNGyWuwm1RdHo5jzK0,10130
|
|
8
|
+
syd/flask_deployment/static/__init__.py,sha256=ieWE8NKR-APw7h4Ge0ooZGk6wZrneSSs_1cMyTPbQSA,65
|
|
9
|
+
syd/flask_deployment/static/css/styles.css,sha256=GQgIPbWMdfTgU-HN80FCObA8bd1FPiwa1Dq0yRANsPc,5944
|
|
10
|
+
syd/flask_deployment/static/css/viewer.css,sha256=rViWJ4w6vahuOr0RIpowgJfg7HN4TzMAuYrQmqhi1V0,805
|
|
11
|
+
syd/flask_deployment/static/js/old_viewer.js,sha256=aIh0gxrwMWUYVge4taj0pucg2RiCcWVuV9ekBvUVsPU,40594
|
|
12
|
+
syd/flask_deployment/static/js/viewer.js,sha256=D-I0hUZQPMSIgB9b8taWNVIsBBUeK1VpLjWI1KtOgSo,2672
|
|
13
|
+
syd/flask_deployment/static/js/modules/api.js,sha256=WTx4SRIzsCLyB0yD94j836KR4npJPEJdW9pNKw5gsHc,3160
|
|
14
|
+
syd/flask_deployment/static/js/modules/config.js,sha256=XxvyNhOUoyXXcacmhNzawKZiy9Q473sY98y7WipofLs,850
|
|
15
|
+
syd/flask_deployment/static/js/modules/plot.js,sha256=dHZAaw_hjrrMa1IGet8HhYJvB0Ze3KoFjmB6duuhFhg,2622
|
|
16
|
+
syd/flask_deployment/static/js/modules/state.js,sha256=-sfQ9ppDgr0p3XO5_oN3g-waf1-j0iwSfSSGS_lIK70,3133
|
|
17
|
+
syd/flask_deployment/static/js/modules/system_controls.js,sha256=7HYd8meNWEgp_xfQCFHKQzKMOrnrz8DeMu2nJXA9baM,7645
|
|
18
|
+
syd/flask_deployment/static/js/modules/ui_controls.js,sha256=Z7n1TPvx25Xtw-cVKhIsEV72TBIrdUmdG6yVhjFQ5Rw,30038
|
|
19
|
+
syd/flask_deployment/static/js/modules/utils.js,sha256=xqIBRvTrZCnm65xZ9R6mqeHFni4h0Q2x3G6gtQ9AWw8,1420
|
|
20
|
+
syd/flask_deployment/templates/__init__.py,sha256=ieWE8NKR-APw7h4Ge0ooZGk6wZrneSSs_1cMyTPbQSA,65
|
|
21
|
+
syd/flask_deployment/templates/index.html,sha256=OmGaEdEPZ_ALPq7ZHk47jw-ZX9pOUUk57M3gXT0V1Lk,1608
|
|
22
|
+
syd/notebook_deployment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
+
syd/notebook_deployment/deployer.py,sha256=ELtYiR6ac8Rg0I1Hh8_K-w5j_oZIAXf-nDazWvbD3Uc,12225
|
|
24
|
+
syd/notebook_deployment/widgets.py,sha256=ptys7exVA6NCF4eCRZMTPJblT0ZbtPdN4o2A0Yh5Cfc,20781
|
|
25
|
+
syd-1.2.0.dist-info/METADATA,sha256=_5dekAuzzkgmS8UjpD42Bu6dVRKfM2Jyimuv8LudNHM,14934
|
|
26
|
+
syd-1.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
27
|
+
syd-1.2.0.dist-info/licenses/LICENSE,sha256=YF6QR6Vjxcg5b_sYIyqkME7FZYau5TfEUGTG-0JeRK0,35129
|
|
28
|
+
syd-1.2.0.dist-info/RECORD,,
|
syd-1.0.2.dist-info/RECORD
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
syd/__init__.py,sha256=X6Ij4JC9wWFTejHeTRAhKNze3H6WZNVHHRehRq2jmlQ,250
|
|
2
|
-
syd/parameters.py,sha256=dlnYOVsi1CDtC2toVECf0kNBRipVrtUjr6XVX86b5MA,42886
|
|
3
|
-
syd/support.py,sha256=7wztPMaL750opyBDnaYYRVyBR5QUJtVspDzQWpu50rk,6106
|
|
4
|
-
syd/viewer.py,sha256=I2uWCup3AZkF-CZ4Ux_glTZWKrPcqERAsO3HqXziomg,50846
|
|
5
|
-
syd/flask_deployment/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
6
|
-
syd/flask_deployment/deployer.py,sha256=w-zuXX1PCnWRa_VCevbQ7yqMTNH5x3Dri-sQQXOF1sM,25110
|
|
7
|
-
syd/flask_deployment/testing_principles.md,sha256=GyULM97sDeie8h3tSPoduOckdMNGyWuwm1RdHo5jzK0,10130
|
|
8
|
-
syd/flask_deployment/static/__init__.py,sha256=ieWE8NKR-APw7h4Ge0ooZGk6wZrneSSs_1cMyTPbQSA,65
|
|
9
|
-
syd/flask_deployment/static/css/styles.css,sha256=gA-Urdq9wmd-XpVcxILxPGlkiOtKtujG7Mw7dWftIVM,5210
|
|
10
|
-
syd/flask_deployment/static/js/viewer.js,sha256=kSY24VGjlQLe-jtPOEU1nE7U0ALC_ZaVzGIBuEXZsTs,27441
|
|
11
|
-
syd/flask_deployment/templates/__init__.py,sha256=ieWE8NKR-APw7h4Ge0ooZGk6wZrneSSs_1cMyTPbQSA,65
|
|
12
|
-
syd/flask_deployment/templates/index.html,sha256=fr1g9IOwNttULhQCIcw_fo0sNpmdgznSGfPStQllR_E,1594
|
|
13
|
-
syd/notebook_deployment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
syd/notebook_deployment/deployer.py,sha256=sf3f9STRXpU1ac-OGENYv1g5yBpUaiIcREBKtKWvIlA,12324
|
|
15
|
-
syd/notebook_deployment/widgets.py,sha256=UbkasRf8wY9beUwpwJYjv9X0Lus3DvgAEIORHwaC-zA,20058
|
|
16
|
-
syd-1.0.2.dist-info/METADATA,sha256=NtVVyB_wKzL9lDzjVgOkz_D1bcSp_6MiJVv9uDBUi2k,13741
|
|
17
|
-
syd-1.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
18
|
-
syd-1.0.2.dist-info/licenses/LICENSE,sha256=YF6QR6Vjxcg5b_sYIyqkME7FZYau5TfEUGTG-0JeRK0,35129
|
|
19
|
-
syd-1.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|