syd 1.0.1__py3-none-any.whl → 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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, continuous, width, margin, description_width
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=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=continuous,
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=continuous,
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=continuous,
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=continuous,
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
- Args:
525
- parameter: The parameter to create a widget for
526
- continuous: Whether to update the widget value continuously during user interaction
527
- width: Width of the widget
528
- margin: Margin of the widget
529
- description_width: Width of the description label
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/viewer.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import List, Any, Callable, Dict, Tuple, Union, Optional
1
+ from typing import List, Any, Callable, Dict, Tuple, Union, Optional, Literal
2
2
  from functools import wraps, partial
3
3
  import inspect
4
4
  from contextlib import contextmanager
@@ -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],
@@ -212,6 +242,52 @@ class Viewer:
212
242
  """Set the plot method for the viewer"""
213
243
  self.plot = self._prepare_function(func, context="Setting plot:")
214
244
 
245
+ def show(
246
+ self,
247
+ controls_position: Literal["left", "top", "right", "bottom"] = "left",
248
+ controls_width_percent: int = 20,
249
+ suppress_warnings: bool = True,
250
+ update_threshold: float = 1.0,
251
+ ):
252
+ """Show the viewer in a notebook
253
+
254
+ Same as deploy(env="notebook") except it doesn't return the viewer object.
255
+ """
256
+ _ = self.deploy(
257
+ env="notebook",
258
+ controls_position=controls_position,
259
+ controls_width_percent=controls_width_percent,
260
+ suppress_warnings=suppress_warnings,
261
+ update_threshold=update_threshold,
262
+ )
263
+
264
+ def share(
265
+ self,
266
+ controls_position: str = "left",
267
+ fig_dpi: int = 300,
268
+ controls_width_percent: int = 20,
269
+ suppress_warnings: bool = True,
270
+ debug: bool = False,
271
+ host: str = "127.0.0.1",
272
+ port: Optional[int] = None,
273
+ open_browser: bool = True,
274
+ ):
275
+ """Share the viewer on a web browser using Flask
276
+
277
+ Same as deploy(env="browser") except it doesn't return the viewer object.
278
+ """
279
+ _ = self.deploy(
280
+ env="browser",
281
+ controls_position=controls_position,
282
+ fig_dpi=fig_dpi,
283
+ controls_width_percent=controls_width_percent,
284
+ suppress_warnings=suppress_warnings,
285
+ debug=debug,
286
+ host=host,
287
+ port=port,
288
+ open_browser=open_browser,
289
+ )
290
+
215
291
  def deploy(self, env: str = "notebook", **kwargs):
216
292
  """Deploy the app in a notebook or standalone environment"""
217
293
  env = env.lower()
@@ -223,7 +299,7 @@ class Viewer:
223
299
  deployer.deploy()
224
300
  return self
225
301
 
226
- elif env == "browser" or env == "flask":
302
+ elif env == "browser":
227
303
  # On demand import because the deployers need to import the viewer
228
304
  from .flask_deployment.deployer import FlaskDeployer
229
305
 
@@ -238,7 +314,7 @@ class Viewer:
238
314
 
239
315
  else:
240
316
  raise ValueError(
241
- f"Unsupported environment: {env}, only 'notebook', 'flask'/'browser' are supported right now."
317
+ f"Unsupported environment: {env}, only 'notebook', 'browser' are supported right now."
242
318
  )
243
319
 
244
320
  @contextmanager
@@ -379,9 +455,8 @@ class Viewer:
379
455
  try:
380
456
  self._in_callbacks = True
381
457
  if name in self.callbacks:
382
- state = self.state
383
458
  for callback in self.callbacks[name]:
384
- callback(state)
459
+ callback(self.state)
385
460
  finally:
386
461
  self._in_callbacks = False
387
462
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syd
3
- Version: 1.0.1
3
+ Version: 1.1.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 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!
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,13 +56,9 @@ pip install syd
56
56
  ```
57
57
 
58
58
  ## Documentation
59
- The full documentation is available at [shareyourdata.readthedocs.io](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)!
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
- <!-- <div style="float: right; margin-left: 100px; margin-bottom: 10px;">
63
- <img src="./docs/assets/viewer_screenshots/readme_example_gif.gif" alt="Syd" width="300" align="right"/>
64
- </div> -->
65
-
66
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!).
67
63
 
68
64
  ```python
@@ -82,12 +78,12 @@ viewer.add_float("amplitude", value=1.0, min=0.1, max=2.0)
82
78
  viewer.add_float("frequency", value=1.0, min=0.1, max=5.0)
83
79
  viewer.add_selection("color", value="red", options=["red", "blue", "green", "black"])
84
80
 
85
- # env = "browser" # for viewing in a web browser (accessible via an IP address)
86
- env = "notebook" # for viewing within a jupyter notebook
87
- viewer = viewer.deploy(env=env)
81
+ viewer.show() # for viewing in a jupyter notebook
82
+ # viewer.share() # for viewing in a web browser
88
83
  ```
89
84
 
90
85
  ![Quick Start Viewer](./docs/assets/viewer_screenshots/readme_example_gif.gif)
86
+
91
87
  ### More Examples
92
88
  We have several examples of more complex viewers with detailed explanations in the comments. Here are the links and descriptions to each of them:
93
89
 
@@ -101,7 +97,7 @@ We have several examples of more complex viewers with detailed explanations in t
101
97
 
102
98
 
103
99
  ### Data loading
104
- Thinking about how to get data into a Syd viewer can be non-intuitive. For some examples that showcase different ways to get your data into a Syd viewer, check out the [data loading example](examples/3-data_loading.ipynb). Or, if you just want a quick example, check this out:
100
+ Thinking about how to get data into a Syd viewer can be non-intuitive. For some examples that showcase different ways to get your data into a Syd viewer, check out the [data loading example](examples/3-data_loading.ipynb). Or, if you just want a quick and fast example, check this one out:
105
101
  ```python
106
102
  import numpy as np
107
103
  from matplotlib import pyplot as plt
@@ -122,15 +118,15 @@ def plot(state):
122
118
  # Since plot "knows" about the data variable, all you need to do is pass the plot
123
119
  # function to the syd viewer and it'll be able to access the data once deployed!
124
120
  viewer = make_viewer(plot)
125
- viewer.deploy(env="browser")
121
+ viewer.show()
126
122
  ```
127
123
 
128
124
  ### Handling Hierarchical Callbacks
129
- Syd dramatically reduces the amount of work you need to do to build a GUI for viewing your data. However, it can still be a bit complicated to think about callbacks. Below is a quick demonstration, to try it yourself, check out the full example [here](examples/4-hierarchical_callbacks.ipynb).
125
+ Syd dramatically reduces the amount of work you need to do to build a GUI for viewing your data. However, it can still be a bit complicated to think about callbacks. Below is a quick demonstration. To try it yourself, check out the full example [here](examples/4-hierarchical_callbacks.ipynb) or open it in colab [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/landoskape/syd/blob/main/examples/4-hierarchical_callbacks.ipynb).
130
126
 
131
- For example, suppose your dataset is composed of electrophysiology recordings from 3 mice, where each mouse has a different number of sesssions, and each session has a different number of neurons. You want to build a viewer to choose the mouse, then choose the session, and then view a particular neuron from within that session. But the viewer will break if you try to index to session 5 for mouse 2 but mouse 2 only has 4 sessions!
127
+ For example, suppose your dataset is composed of electrophysiology recordings from 3 mice, where each mouse has a different number of sesssions, and each session has a different number of neurons. You want to build a viewer to view a particular neuron from a particular session from a particular mouse. But the viewer will break if you try to index to session 5 for mouse 2 when mouse 2 has less than 5 sessions!
132
128
 
133
- This is where hierarchical callbacks come in. There's a straightforward pattern to handling this kind of situation that you can follow. You can write a callback for each **level** of the hierarchy. Then, each callback can call the next callback in the hierarchy. It looks like this:
129
+ This is where hierarchical callbacks come in. There's a straightforward pattern to handling this kind of situation that you can follow. You can write a callback for each **level** of the hierarchy. Then, each callback can **update** the state and call the next callback in the hierarchy once it's finished. It looks like this:
134
130
  ```python
135
131
  import numpy as np
136
132
  from syd import Viewer # Much easier to build a Viewer class for hierarchical callbacks
@@ -141,19 +137,22 @@ class MouseViewer(Viewer):
141
137
 
142
138
  self.add_selection("mouse", options=list(mice_names))
143
139
 
144
- # We don't know how many sessions or neurons to pick from yet!
140
+ # We don't know how many sessions or neurons to pick from yet,
141
+ # so just set the max to 1 for now.
145
142
  self.add_integer("session", min=0, max=1)
146
143
  self.add_integer("neuron", min=0, max=1)
147
144
 
148
- # Any time the mouse changes, update the sessions to pick from
145
+ # Any time the mouse changes, update the sessions to pick from!
149
146
  self.on_change("mouse", self.update_mouse)
150
147
 
151
- # Any time the session changes, update the neurons to pick from
148
+ # Any time the session changes, update the neurons to pick from!
152
149
  self.on_change("session", self.update_session)
153
150
 
154
151
  # Since we built callbacks for setting the range of the session
155
- # and neuron parameters, we can use them here!
156
- # To get the state, we can use self.state, which is the current
152
+ # and neuron parameters, we can use them here so the viewer is
153
+ # fully ready and up to date.
154
+
155
+ # To get the state, use self.state, which is the current
157
156
  # state of the viewer (in the init function, it'll just be the
158
157
  # default value for each parameter you've added already).
159
158
  self.update_mouse(self.state)
@@ -166,9 +165,13 @@ class MouseViewer(Viewer):
166
165
  self.update_integer("session", max=num_sessions - 1)
167
166
 
168
167
  # Now we need to update the neurons to choose from ....
169
- # But! Updating the session parameter might trigger a change to the
170
- # session value. So, instead of using the state dictionary that was
171
- # passed into the function, we can get the ~NEW~ state dictionary like this:
168
+
169
+ # But! Updating the session parameter's max value might trigger a change
170
+ # to the current session value. This ~won't be reflected~ in the state
171
+ # dictionary that was passed to this function.
172
+
173
+ # So, we need to load the ~NEW~ state dictionary, which is always
174
+ # accessible as self.state (or viewer.state if you're not using a class).
172
175
  new_state = self.state
173
176
 
174
177
  # Then perform the session update callback!
@@ -189,7 +192,7 @@ class MouseViewer(Viewer):
189
192
 
190
193
  # Now we can create a viewer and deploy it
191
194
  viewer = MouseViewer(["Mouse 1", "Mouse 2", "Mouse 3"])
192
- viewer.deploy(env="browser")
195
+ viewer.show()
193
196
  ```
194
197
 
195
198
  ## License
@@ -216,7 +219,6 @@ black . # from the root directory of the repo
216
219
 
217
220
  ## To-Do List
218
221
  - Layout controls
219
- - [ ] Improve the display and make it look better
220
222
  - [ ] Add a "save" button that saves the current state of the viewer to a json file
221
223
  - [ ] Add a "load" button that loads the viewer state from a json file
222
224
  - [ ] Add a "freeze" button that allows the user to update state variables without updating the plot until unfreezing
@@ -225,4 +227,6 @@ black . # from the root directory of the repo
225
227
  - Export options:
226
228
  - [ ] 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.
227
229
  - [ ] Export full: export the viewer in a way that contains the data to give full functionality.
228
- - [ ] Keep deploy() for backwards compatibility, but deprecate it in favor of show() and share() (for notebook and browser, respectively)
230
+ - [ ] Idea for sharing: https://github.com/analyticalmonk/awesome-neuroscience, https://github.com/fasouto/awesome-dataviz
231
+ - [ ] The handling of value in Selection parameters is kind of weird.... I think we need to think more about what to do for fails!!!!
232
+ - [ ] Range parameters render poorly in browser mode.
@@ -0,0 +1,20 @@
1
+ syd/__init__.py,sha256=scju2nVDJzGslTNmtc0Mp_ftux6TzB4BAOCrgU9R19A,63
2
+ syd/parameters.py,sha256=dlnYOVsi1CDtC2toVECf0kNBRipVrtUjr6XVX86b5MA,42886
3
+ syd/support.py,sha256=7wztPMaL750opyBDnaYYRVyBR5QUJtVspDzQWpu50rk,6106
4
+ syd/viewer.py,sha256=t4NWOMrzsVHwKsnEJ8Um_wDGSEE9FcyZyb_fp_pVpko,51516
5
+ syd/flask_deployment/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
6
+ syd/flask_deployment/deployer.py,sha256=LnIWvFBxphFONABJCD6WoMu-a89YWIV0ZCuN_sgvB1A,25657
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=Gec78sj73IJDHz5OzE68e6LqyQf4E_JX0tc5zmavT4A,5533
10
+ syd/flask_deployment/static/css/viewer.css,sha256=9HToyeDhTA1Vhawmvev7ceyxKAVZASSX_azj8Hh-OVI,1644
11
+ syd/flask_deployment/static/js/viewer.js,sha256=aIh0gxrwMWUYVge4taj0pucg2RiCcWVuV9ekBvUVsPU,40594
12
+ syd/flask_deployment/templates/__init__.py,sha256=ieWE8NKR-APw7h4Ge0ooZGk6wZrneSSs_1cMyTPbQSA,65
13
+ syd/flask_deployment/templates/index.html,sha256=fr1g9IOwNttULhQCIcw_fo0sNpmdgznSGfPStQllR_E,1594
14
+ syd/notebook_deployment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ syd/notebook_deployment/deployer.py,sha256=ELtYiR6ac8Rg0I1Hh8_K-w5j_oZIAXf-nDazWvbD3Uc,12225
16
+ syd/notebook_deployment/widgets.py,sha256=ptys7exVA6NCF4eCRZMTPJblT0ZbtPdN4o2A0Yh5Cfc,20781
17
+ syd-1.1.0.dist-info/METADATA,sha256=tSSGUSgt_nNjzDYUGouMjas2UKFpZZa9oOfwgvMsHL0,13952
18
+ syd-1.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
19
+ syd-1.1.0.dist-info/licenses/LICENSE,sha256=YF6QR6Vjxcg5b_sYIyqkME7FZYau5TfEUGTG-0JeRK0,35129
20
+ syd-1.1.0.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- syd/__init__.py,sha256=Lx1We_TNKsV2Co9v5RB05WgqXpFqieSBh-y3zF0q1LE,250
2
- syd/parameters.py,sha256=dlnYOVsi1CDtC2toVECf0kNBRipVrtUjr6XVX86b5MA,42886
3
- syd/support.py,sha256=7wztPMaL750opyBDnaYYRVyBR5QUJtVspDzQWpu50rk,6106
4
- syd/viewer.py,sha256=UYDfH9TNds0CiC3vThINLrMNZE8ikSFqJHgjM8yMD94,49323
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.1.dist-info/METADATA,sha256=pHDBBxQoLRmHRBsWPtF5VlYI0hpd_tX6zcmYBNhdIJQ,13668
17
- syd-1.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
- syd-1.0.1.dist-info/licenses/LICENSE,sha256=YF6QR6Vjxcg5b_sYIyqkME7FZYau5TfEUGTG-0JeRK0,35129
19
- syd-1.0.1.dist-info/RECORD,,
File without changes