bmtool 0.7.4__py3-none-any.whl → 0.7.5__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.
bmtool/synapses.py CHANGED
@@ -113,12 +113,20 @@ class SynapseTuner:
113
113
  else:
114
114
  # Merge defaults with user-provided
115
115
  self.general_settings = {**DEFAULT_GENERAL_SETTINGS, **general_settings}
116
+
117
+ # Store the initial connection name and set up connection
118
+ self.current_connection = connection
116
119
  self.conn = self.conn_type_settings[connection]
120
+ self._current_cell_type = self.conn["spec_settings"]["post_cell"]
117
121
  self.synaptic_props = self.conn["spec_syn_param"]
118
122
  self.vclamp = self.general_settings["vclamp"]
119
123
  self.current_name = current_name
120
124
  self.other_vars_to_record = other_vars_to_record or []
121
125
  self.ispk = None
126
+ self.input_mode = False # Add input_mode attribute
127
+
128
+ # Store original slider_vars for connection switching
129
+ self.original_slider_vars = slider_vars or list(self.synaptic_props.keys())
122
130
 
123
131
  if slider_vars:
124
132
  # Start by filtering based on keys in slider_vars
@@ -174,6 +182,90 @@ class SynapseTuner:
174
182
 
175
183
  self._set_up_recorders()
176
184
 
185
+ def _switch_connection(self, new_connection: str) -> None:
186
+ """
187
+ Switch to a different connection type and update all related properties.
188
+
189
+ Parameters:
190
+ -----------
191
+ new_connection : str
192
+ Name of the new connection type to switch to.
193
+ """
194
+ if new_connection not in self.conn_type_settings:
195
+ raise ValueError(f"Connection '{new_connection}' not found in conn_type_settings.")
196
+
197
+ # Update current connection
198
+ self.current_connection = new_connection
199
+ self.conn = self.conn_type_settings[new_connection]
200
+ self.synaptic_props = self.conn["spec_syn_param"]
201
+
202
+ # Update slider vars for new connection
203
+ if hasattr(self, 'original_slider_vars'):
204
+ # Filter slider vars based on new connection's parameters
205
+ self.slider_vars = {
206
+ key: value for key, value in self.synaptic_props.items()
207
+ if key in self.original_slider_vars
208
+ }
209
+
210
+ # Check for missing keys and try to get them from the synapse
211
+ for key in self.original_slider_vars:
212
+ if key not in self.synaptic_props:
213
+ try:
214
+ # We'll get this after recreating the synapse
215
+ pass
216
+ except AttributeError as e:
217
+ print(f"Warning: Could not access '{key}' for connection '{new_connection}': {e}")
218
+ else:
219
+ self.slider_vars = self.synaptic_props
220
+
221
+ # Need to recreate the cell if it's different
222
+ if self.hoc_cell is None:
223
+ # Check if we need a different cell type
224
+ new_cell_type = self.conn["spec_settings"]["post_cell"]
225
+ if not hasattr(self, '_current_cell_type') or self._current_cell_type != new_cell_type:
226
+ self._current_cell_type = new_cell_type
227
+ self._set_up_cell()
228
+
229
+ # Recreate synapse for new connection
230
+ self._set_up_synapse()
231
+
232
+ # Update any missing slider vars from the new synapse
233
+ if hasattr(self, 'original_slider_vars'):
234
+ for key in self.original_slider_vars:
235
+ if key not in self.synaptic_props:
236
+ try:
237
+ value = getattr(self.syn, key)
238
+ self.slider_vars[key] = value
239
+ except AttributeError as e:
240
+ print(f"Warning: Could not access '{key}' for connection '{new_connection}': {e}")
241
+
242
+ # Recreate NetCon connections with new synapse
243
+ self.nc = h.NetCon(
244
+ self.nstim,
245
+ self.syn,
246
+ self.general_settings["threshold"],
247
+ self.general_settings["delay"],
248
+ self.general_settings["weight"],
249
+ )
250
+ self.nc2 = h.NetCon(
251
+ self.nstim2,
252
+ self.syn,
253
+ self.general_settings["threshold"],
254
+ self.general_settings["delay"],
255
+ self.general_settings["weight"],
256
+ )
257
+
258
+ # Recreate voltage clamp with potentially new cell
259
+ self.vcl = h.VClamp(self.cell.soma[0](0.5))
260
+
261
+ # Recreate recorders for new synapse
262
+ self._set_up_recorders()
263
+
264
+ # Reset NEURON state
265
+ h.finitialize()
266
+
267
+ print(f"Successfully switched to connection: {new_connection}")
268
+
177
269
  def _update_spec_syn_param(self, json_folder_path: str) -> None:
178
270
  """
179
271
  Update specific synaptic parameters using JSON files located in the specified folder.
@@ -722,8 +814,9 @@ class SynapseTuner:
722
814
  for i in range(3):
723
815
  self.vcl.amp[i] = self.conn["spec_settings"]["vclamp_amp"]
724
816
  self.vcl.dur[i] = vcldur[1][i]
725
- h.finitialize(self.cell.Vinit * mV)
726
- h.continuerun(self.tstop * ms)
817
+ #h.finitialize(self.cell.Vinit * mV)
818
+ #h.continuerun(self.tstop * ms)
819
+ h.run()
727
820
  else:
728
821
  self.tstop = self.general_settings["tstart"] + self.general_settings["tdur"]
729
822
  self.nstim.interval = 1000 / input_frequency
@@ -731,14 +824,16 @@ class SynapseTuner:
731
824
  self.nstim2.number = 0
732
825
  self.tstop = self.w_duration.value + self.general_settings["tstart"]
733
826
 
734
- h.finitialize(self.cell.Vinit * mV)
735
- h.continuerun(self.tstop * ms)
827
+ #h.finitialize(self.cell.Vinit * mV)
828
+ #h.continuerun(self.tstop * ms)
829
+ h.run()
736
830
 
737
831
  def InteractiveTuner(self):
738
832
  """
739
833
  Sets up interactive sliders for tuning short-term plasticity (STP) parameters in a Jupyter Notebook.
740
834
 
741
835
  This method creates an interactive UI with sliders for:
836
+ - Connection type selection dropdown
742
837
  - Input frequency
743
838
  - Delay between pulse trains
744
839
  - Duration of stimulation (for continuous input mode)
@@ -764,6 +859,15 @@ class SynapseTuner:
764
859
  duration0 = 300
765
860
  vlamp_status = self.vclamp
766
861
 
862
+ # Connection dropdown
863
+ connection_options = list(self.conn_type_settings.keys())
864
+ w_connection = widgets.Dropdown(
865
+ options=connection_options,
866
+ value=self.current_connection,
867
+ description="Connection:",
868
+ style={'description_width': 'initial'}
869
+ )
870
+
767
871
  w_run = widgets.Button(description="Run Train", icon="history", button_style="primary")
768
872
  w_single = widgets.Button(description="Single Event", icon="check", button_style="success")
769
873
  w_vclamp = widgets.ToggleButton(
@@ -783,28 +887,33 @@ class SynapseTuner:
783
887
  options=durations, value=duration0, description="Duration"
784
888
  )
785
889
 
890
+ def create_dynamic_sliders():
891
+ """Create sliders based on current connection's parameters"""
892
+ sliders = {}
893
+ for key, value in self.slider_vars.items():
894
+ if isinstance(value, (int, float)): # Only create sliders for numeric values
895
+ if hasattr(self.syn, key):
896
+ if value == 0:
897
+ print(
898
+ f"{key} was set to zero, going to try to set a range of values, try settings the {key} to a nonzero value if you dont like the range!"
899
+ )
900
+ slider = widgets.FloatSlider(
901
+ value=value, min=0, max=1000, step=1, description=key
902
+ )
903
+ else:
904
+ slider = widgets.FloatSlider(
905
+ value=value, min=0, max=value * 20, step=value / 5, description=key
906
+ )
907
+ sliders[key] = slider
908
+ else:
909
+ print(f"skipping slider for {key} due to not being a synaptic variable")
910
+ return sliders
911
+
786
912
  # Generate sliders dynamically based on valid numeric entries in self.slider_vars
787
- self.dynamic_sliders = {}
913
+ self.dynamic_sliders = create_dynamic_sliders()
788
914
  print(
789
915
  "Setting up slider! The sliders ranges are set by their init value so try changing that if you dont like the slider range!"
790
916
  )
791
- for key, value in self.slider_vars.items():
792
- if isinstance(value, (int, float)): # Only create sliders for numeric values
793
- if hasattr(self.syn, key):
794
- if value == 0:
795
- print(
796
- f"{key} was set to zero, going to try to set a range of values, try settings the {key} to a nonzero value if you dont like the range!"
797
- )
798
- slider = widgets.FloatSlider(
799
- value=value, min=0, max=1000, step=1, description=key
800
- )
801
- else:
802
- slider = widgets.FloatSlider(
803
- value=value, min=0, max=value * 20, step=value / 5, description=key
804
- )
805
- self.dynamic_sliders[key] = slider
806
- else:
807
- print(f"skipping slider for {key} due to not being a synaptic variable")
808
917
 
809
918
  def run_single_event(*args):
810
919
  clear_output()
@@ -814,6 +923,46 @@ class SynapseTuner:
814
923
  self.ispk = None
815
924
  self.SingleEvent()
816
925
 
926
+ def on_connection_change(*args):
927
+ """Handle connection dropdown change"""
928
+ try:
929
+ new_connection = w_connection.value
930
+ if new_connection != self.current_connection:
931
+ # Switch to new connection
932
+ self._switch_connection(new_connection)
933
+
934
+ # Recreate dynamic sliders for new connection
935
+ self.dynamic_sliders = create_dynamic_sliders()
936
+
937
+ # Update UI
938
+ update_ui_layout()
939
+ update_ui()
940
+
941
+ except Exception as e:
942
+ print(f"Error switching connection: {e}")
943
+
944
+ def update_ui_layout():
945
+ """Update the UI layout with new sliders"""
946
+ nonlocal ui, slider_columns
947
+
948
+ # Add the dynamic sliders to the UI
949
+ slider_widgets = [slider for slider in self.dynamic_sliders.values()]
950
+
951
+ if slider_widgets:
952
+ half = len(slider_widgets) // 2
953
+ col1 = VBox(slider_widgets[:half])
954
+ col2 = VBox(slider_widgets[half:])
955
+ slider_columns = HBox([col1, col2])
956
+ else:
957
+ slider_columns = VBox([])
958
+
959
+ # Reconstruct the UI
960
+ connection_row = HBox([w_connection])
961
+ button_row = HBox([w_run, w_single, w_vclamp, w_input_mode])
962
+ slider_row = HBox([w_input_freq, self.w_delay, self.w_duration])
963
+
964
+ ui = VBox([connection_row, button_row, slider_row, slider_columns])
965
+
817
966
  # Function to update UI based on input mode
818
967
  def update_ui(*args):
819
968
  clear_output()
@@ -841,7 +990,8 @@ class SynapseTuner:
841
990
  self.w_delay.layout.display = "" # Show delay slider
842
991
  self.w_duration.layout.display = "none" # Hide duration slider
843
992
 
844
- # Link input mode to slider switch
993
+ # Link widgets to their callback functions
994
+ w_connection.observe(on_connection_change, names="value")
845
995
  w_input_mode.observe(switch_slider, names="value")
846
996
 
847
997
  # Hide the duration slider initially until the user selects it
@@ -850,18 +1000,10 @@ class SynapseTuner:
850
1000
  w_single.on_click(run_single_event)
851
1001
  w_run.on_click(update_ui)
852
1002
 
853
- # Add the dynamic sliders to the UI
854
- slider_widgets = [slider for slider in self.dynamic_sliders.values()]
855
-
856
- button_row = HBox([w_run, w_single, w_vclamp, w_input_mode])
857
- slider_row = HBox([w_input_freq, self.w_delay, self.w_duration])
858
-
859
- half = len(slider_widgets) // 2
860
- col1 = VBox(slider_widgets[:half])
861
- col2 = VBox(slider_widgets[half:])
862
- slider_columns = HBox([col1, col2])
863
-
864
- ui = VBox([button_row, slider_row, slider_columns])
1003
+ # Initial UI setup
1004
+ slider_columns = VBox([])
1005
+ ui = VBox([])
1006
+ update_ui_layout()
865
1007
 
866
1008
  display(ui)
867
1009
  update_ui()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bmtool
3
- Version: 0.7.4
3
+ Version: 0.7.5
4
4
  Summary: BMTool
5
5
  Home-page: https://github.com/cyneuro/bmtool
6
6
  Download-URL:
@@ -6,7 +6,7 @@ bmtool/graphs.py,sha256=gBTzI6c2BBK49dWGcfWh9c56TAooyn-KaiEy0Im1HcI,6717
6
6
  bmtool/manage.py,sha256=lsgRejp02P-x6QpA7SXcyXdalPhRmypoviIA2uAitQs,608
7
7
  bmtool/plot_commands.py,sha256=Dxm_RaT4CtHnfsltTtUopJ4KVbfhxtktEB_b7bFEXII,12716
8
8
  bmtool/singlecell.py,sha256=I2yolbAnNC8qpnRkNdnDCLidNW7CktmBuRrcowMZJ3A,45041
9
- bmtool/synapses.py,sha256=-kg_TJoqXStIgE5iHpJWpXU6VRKT0YyIVpTw8frNbxA,69653
9
+ bmtool/synapses.py,sha256=Yg0JOXT7zUvvoeAOkEvA4RBcwRkIvoROsUTvRkP00fw,75453
10
10
  bmtool/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  bmtool/analysis/entrainment.py,sha256=NQloQtVpEWjDzmkZwMWVcm3hSjErHBZfQl1mrBVoIE8,25321
12
12
  bmtool/analysis/lfp.py,sha256=S2JvxkjcK3-EH93wCrhqNSFY6cX7fOq74pz64ibHKrc,26556
@@ -26,9 +26,9 @@ bmtool/util/commands.py,sha256=Nn-R-4e9g8ZhSPZvTkr38xeKRPfEMANB9Lugppj82UI,68564
26
26
  bmtool/util/util.py,sha256=TAWdGd0tDuouS-JiusMs8WwP7kQpWHPr1nu0XG01TBQ,75056
27
27
  bmtool/util/neuron/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  bmtool/util/neuron/celltuner.py,sha256=lokRLUM1rsdSYBYrNbLBBo39j14mm8TBNVNRnSlhHCk,94868
29
- bmtool-0.7.4.dist-info/licenses/LICENSE,sha256=qrXg2jj6kz5d0EnN11hllcQt2fcWVNumx0xNbV05nyM,1068
30
- bmtool-0.7.4.dist-info/METADATA,sha256=126Cn17YBt6twoBgMXYXK10kOWUXRhnLnGmPr7z7k_4,3595
31
- bmtool-0.7.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
32
- bmtool-0.7.4.dist-info/entry_points.txt,sha256=0-BHZ6nUnh0twWw9SXNTiRmKjDnb1VO2DfG_-oprhAc,45
33
- bmtool-0.7.4.dist-info/top_level.txt,sha256=gpd2Sj-L9tWbuJEd5E8C8S8XkNm5yUE76klUYcM-eWM,7
34
- bmtool-0.7.4.dist-info/RECORD,,
29
+ bmtool-0.7.5.dist-info/licenses/LICENSE,sha256=qrXg2jj6kz5d0EnN11hllcQt2fcWVNumx0xNbV05nyM,1068
30
+ bmtool-0.7.5.dist-info/METADATA,sha256=2KlbH04Q4LTGqmoMHqPFRPRHXPhfVBypKt4LIjGRUQ0,3595
31
+ bmtool-0.7.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
32
+ bmtool-0.7.5.dist-info/entry_points.txt,sha256=0-BHZ6nUnh0twWw9SXNTiRmKjDnb1VO2DfG_-oprhAc,45
33
+ bmtool-0.7.5.dist-info/top_level.txt,sha256=gpd2Sj-L9tWbuJEd5E8C8S8XkNm5yUE76klUYcM-eWM,7
34
+ bmtool-0.7.5.dist-info/RECORD,,
File without changes