bmtool 0.5.3__tar.gz → 0.5.4__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 (27) hide show
  1. {bmtool-0.5.3 → bmtool-0.5.4}/PKG-INFO +1 -1
  2. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/bmplot.py +92 -4
  3. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/connectors.py +96 -6
  4. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/util/util.py +27 -10
  5. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool.egg-info/PKG-INFO +1 -1
  6. {bmtool-0.5.3 → bmtool-0.5.4}/setup.py +1 -1
  7. {bmtool-0.5.3 → bmtool-0.5.4}/LICENSE +0 -0
  8. {bmtool-0.5.3 → bmtool-0.5.4}/README.md +0 -0
  9. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/__init__.py +0 -0
  10. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/__main__.py +0 -0
  11. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/debug/__init__.py +0 -0
  12. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/debug/commands.py +0 -0
  13. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/debug/debug.py +0 -0
  14. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/graphs.py +0 -0
  15. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/manage.py +0 -0
  16. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/plot_commands.py +0 -0
  17. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/singlecell.py +0 -0
  18. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/util/__init__.py +0 -0
  19. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/util/commands.py +0 -0
  20. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/util/neuron/__init__.py +0 -0
  21. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool/util/neuron/celltuner.py +0 -0
  22. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool.egg-info/SOURCES.txt +0 -0
  23. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool.egg-info/dependency_links.txt +0 -0
  24. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool.egg-info/entry_points.txt +0 -0
  25. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool.egg-info/requires.txt +0 -0
  26. {bmtool-0.5.3 → bmtool-0.5.4}/bmtool.egg-info/top_level.txt +0 -0
  27. {bmtool-0.5.3 → bmtool-0.5.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bmtool
3
- Version: 0.5.3
3
+ Version: 0.5.4
4
4
  Summary: BMTool
5
5
  Home-page: https://github.com/cyneuro/bmtool
6
6
  Download-URL:
@@ -367,10 +367,15 @@ def connection_histogram(config=None,nodes=None,edges=None,sources=[],targets=[]
367
367
  if include_gap == False:
368
368
  temp = temp[temp['is_gap_junction'] != True]
369
369
  node_pairs = temp.groupby('target_node_id')['source_node_id'].count()
370
- conn_mean = statistics.mean(node_pairs.values)
371
- conn_std = statistics.stdev(node_pairs.values)
372
- conn_median = statistics.median(node_pairs.values)
373
- label = "mean {:.2f} std ({:.2f}) median {:.2f}".format(conn_mean,conn_std,conn_median)
370
+ try:
371
+ conn_mean = statistics.mean(node_pairs.values)
372
+ conn_std = statistics.stdev(node_pairs.values)
373
+ conn_median = statistics.median(node_pairs.values)
374
+ label = "mean {:.2f} std ({:.2f}) median {:.2f}".format(conn_mean,conn_std,conn_median)
375
+ except: # lazy fix for std not calculated with 1 node
376
+ conn_mean = statistics.mean(node_pairs.values)
377
+ conn_median = statistics.median(node_pairs.values)
378
+ label = "mean {:.2f} median {:.2f}".format(conn_mean,conn_median)
374
379
  plt.hist(node_pairs.values,density=True,bins='auto',stacked=True,label=label)
375
380
  plt.legend()
376
381
  plt.xlabel("# of conns from {} to {}".format(source_cell,target_cell))
@@ -495,6 +500,89 @@ def plot_connection_info(text, num, source_labels,target_labels, title, syn_info
495
500
  plt.savefig(save_file)
496
501
  return
497
502
 
503
+ def connector_percent_matrix(csv_path = None):
504
+ """
505
+ useful because can display percent connectivity factoring in distance easily
506
+ Generates a connection matrix from the output of bmtool.connector
507
+ csv: An output csv from the bmtool.connector classes see function save_connection_report() in that module
508
+ returns: connection matrix plot
509
+ """
510
+ # Read the CSV data
511
+ df = pd.read_csv(csv_path)
512
+
513
+ # Choose the column to display
514
+ selected_column = "Fraction of connected pairs in possible ones (%)" # Change this to the desired column name
515
+
516
+ # Create an empty dictionary to store connection percentages
517
+ connection_data = {}
518
+
519
+ # Iterate over each row in the DataFrame
520
+ for index, row in df.iterrows():
521
+ source = row['Source']
522
+ target = row['Target']
523
+ selected_percentage = row[selected_column]
524
+
525
+ # If the selected percentage is an array-like string, extract the first and second values
526
+ if isinstance(selected_percentage, str):
527
+ selected_percentage = selected_percentage.strip('[]').split()
528
+ selected_percentage = [float(p) for p in selected_percentage] # Convert to float
529
+
530
+ # Store the selected percentage(s) for the source-target pair
531
+ connection_data[(source, target)] = selected_percentage
532
+
533
+ # Prepare unique populations and create an empty matrix
534
+ populations = sorted(list(set(df['Source'].unique()) | set(df['Target'].unique())))
535
+ num_populations = len(populations)
536
+ connection_matrix = np.zeros((num_populations, num_populations), dtype=float)
537
+
538
+ # Populate the matrix with the selected connection percentages
539
+ for source, target in connection_data.keys():
540
+ source_idx = populations.index(source)
541
+ target_idx = populations.index(target)
542
+ connection_probabilities = connection_data[(source, target)]
543
+
544
+ # Use the first value for one-way connection from source to target
545
+ connection_matrix[source_idx][target_idx] = connection_probabilities[0]
546
+
547
+ # Check if the source and target are the same population
548
+ if source == target:
549
+ # Use the first value (uni-directional) and ignore the second value (bi-directional)
550
+ continue
551
+
552
+ # Check if there is a bidirectional connection and use the second value
553
+ if len(connection_probabilities) > 1:
554
+ connection_matrix[target_idx][source_idx] = connection_probabilities[1]
555
+
556
+ # Replace NaN values with 0
557
+ connection_matrix[np.isnan(connection_matrix)] = 0
558
+
559
+ # Plot the matrix
560
+ fig, ax = plt.subplots(figsize=(10, 8))
561
+ im = ax.imshow(connection_matrix, cmap='viridis', interpolation='nearest')
562
+
563
+ # Add annotations
564
+ for i in range(num_populations):
565
+ for j in range(num_populations):
566
+ text = ax.text(j, i, f"{connection_matrix[i, j]:.2f}%",
567
+ ha="center", va="center", color="w", size=10, weight='bold')
568
+
569
+ # Add colorbar
570
+ plt.colorbar(im, label=f'Percentage of connected pairs ({selected_column})')
571
+
572
+ # Set title and axis labels
573
+ ax.set_title('Neuronal Connection Matrix')
574
+ ax.set_xlabel('Target Population')
575
+ ax.set_ylabel('Source Population')
576
+
577
+ # Set ticks and labels
578
+ ax.set_xticks(np.arange(num_populations))
579
+ ax.set_yticks(np.arange(num_populations))
580
+ ax.set_xticklabels(populations, rotation=45, ha="right", size=12, weight='semibold')
581
+ ax.set_yticklabels(populations, size=12, weight='semibold')
582
+
583
+ plt.tight_layout()
584
+ plt.show()
585
+
498
586
  def raster_old(config=None,title=None,populations=['hippocampus']):
499
587
  """
500
588
  old function probs dep
@@ -5,6 +5,8 @@ from scipy.optimize import minimize_scalar
5
5
  from functools import partial
6
6
  import time
7
7
  import types
8
+ import pandas as pd
9
+ import re
8
10
 
9
11
  rng = np.random.default_rng()
10
12
 
@@ -532,7 +534,7 @@ class ReciprocalConnector(AbstractConnector):
532
534
  pr=0., pr_arg=None, estimate_rho=True, rho=None,
533
535
  dist_range_forward=None, dist_range_backward=None,
534
536
  n_syn0=1, n_syn1=1, autapses=False,
535
- quick_pop_check=False, cache_data=True, verbose=True):
537
+ quick_pop_check=False, cache_data=True, verbose=True,save_report=True):
536
538
  args = locals()
537
539
  var_set = ('p0', 'p0_arg', 'p1', 'p1_arg',
538
540
  'pr', 'pr_arg', 'n_syn0', 'n_syn1')
@@ -550,6 +552,7 @@ class ReciprocalConnector(AbstractConnector):
550
552
  self.quick = quick_pop_check
551
553
  self.cache = self.ConnectorCache(cache_data and self.estimate_rho)
552
554
  self.verbose = verbose
555
+ self.save_report = save_report
553
556
 
554
557
  self.conn_prop = [{}, {}]
555
558
  self.stage = 0
@@ -947,6 +950,8 @@ class ReciprocalConnector(AbstractConnector):
947
950
  if self.wrong_pr:
948
951
  print("Warning: Value of 'pr' outside the bounds occurred.\n")
949
952
  self.connection_number_info()
953
+ if self.save_report:
954
+ self.save_connection_report()
950
955
 
951
956
  def make_connection(self):
952
957
  """ Assign number of synapses per iteration.
@@ -1042,6 +1047,31 @@ class ReciprocalConnector(AbstractConnector):
1042
1047
  print("Fraction of connected pairs in all pairs: (%s)\n"
1043
1048
  % arr2str(100 * fraction[1], '%.2f%%'))
1044
1049
 
1050
+ def save_connection_report(self):
1051
+ """Save connections into a CSV file to be read from later"""
1052
+ src_str, trg_str = self.get_nodes_info()
1053
+ n_conn, n_poss, n_pair, fraction = self.connection_number()
1054
+
1055
+ # Extract the population name from source_str and target_str
1056
+ data = {
1057
+ "Source": [src_str],
1058
+ "Target": [trg_str],
1059
+ "Fraction of connected pairs in possible ones (%)": [fraction[0]*100],
1060
+ "Fraction of connected pairs in all pairs (%)": [fraction[1]*100]
1061
+ }
1062
+ df = pd.DataFrame(data)
1063
+
1064
+ # Append the data to the CSV file
1065
+ try:
1066
+ # Check if the file exists by trying to read it
1067
+ existing_df = pd.read_csv('connection_report.csv')
1068
+ # If no exception is raised, append without header
1069
+ df.to_csv('connection_report.csv', mode='a', header=False, index=False)
1070
+ except FileNotFoundError:
1071
+ # If the file does not exist, write with header
1072
+ df.to_csv('connection_report.csv', mode='w', header=True, index=False)
1073
+
1074
+
1045
1075
 
1046
1076
  class UnidirectionConnector(AbstractConnector):
1047
1077
  """
@@ -1074,12 +1104,13 @@ class UnidirectionConnector(AbstractConnector):
1074
1104
  This is useful in similar manner as in ReciprocalConnector.
1075
1105
  """
1076
1106
 
1077
- def __init__(self, p=1., p_arg=None, n_syn=1, verbose=True):
1107
+ def __init__(self, p=1., p_arg=None, n_syn=1, verbose=True,save_report=True):
1078
1108
  args = locals()
1079
1109
  var_set = ('p', 'p_arg', 'n_syn')
1080
1110
  self.vars = {key: args[key] for key in var_set}
1081
1111
 
1082
1112
  self.verbose = verbose
1113
+ self.save_report = save_report
1083
1114
  self.conn_prop = {}
1084
1115
  self.iter_count = 0
1085
1116
 
@@ -1157,6 +1188,9 @@ class UnidirectionConnector(AbstractConnector):
1157
1188
  if self.verbose:
1158
1189
  self.connection_number_info()
1159
1190
  self.timer.report('Done! \nTime for building connections')
1191
+ if self.save_report:
1192
+ self.save_connection_report()
1193
+
1160
1194
  return nsyns
1161
1195
 
1162
1196
  # *** Helper functions for verbose ***
@@ -1175,6 +1209,32 @@ class UnidirectionConnector(AbstractConnector):
1175
1209
  print("Number of total pairs: %d" % self.n_pair)
1176
1210
  print("Fraction of connected pairs in all pairs: %.2f%%\n"
1177
1211
  % (100. * self.n_conn / self.n_pair))
1212
+
1213
+ def save_connection_report(self):
1214
+ """Save connections into a CSV file to be read from later"""
1215
+ src_str, trg_str = self.get_nodes_info()
1216
+ n_pair = self.n_pair
1217
+ fraction_0 = self.n_conn / self.n_poss if self.n_poss else 0.
1218
+ fraction_1 = self.n_conn / self.n_pair
1219
+
1220
+ # Convert fraction to percentage and prepare data for the DataFrame
1221
+ data = {
1222
+ "Source": [src_str],
1223
+ "Target": [trg_str],
1224
+ "Fraction of connected pairs in possible ones (%)": [fraction_0*100],
1225
+ "Fraction of connected pairs in all pairs (%)": [fraction_1*100]
1226
+ }
1227
+ df = pd.DataFrame(data)
1228
+
1229
+ # Append the data to the CSV file
1230
+ try:
1231
+ # Check if the file exists by trying to read it
1232
+ existing_df = pd.read_csv('connection_report.csv')
1233
+ # If no exception is raised, append without header
1234
+ df.to_csv('connection_report.csv', mode='a', header=False, index=False)
1235
+ except FileNotFoundError:
1236
+ # If the file does not exist, write with header
1237
+ df.to_csv('connection_report.csv', mode='w', header=True, index=False)
1178
1238
 
1179
1239
 
1180
1240
  class GapJunction(UnidirectionConnector):
@@ -1198,8 +1258,8 @@ class GapJunction(UnidirectionConnector):
1198
1258
  Similar to `UnidirectionConnector`.
1199
1259
  """
1200
1260
 
1201
- def __init__(self, p=1., p_arg=None, verbose=True):
1202
- super().__init__(p=p, p_arg=p_arg, verbose=verbose)
1261
+ def __init__(self, p=1., p_arg=None, verbose=True,save_report=True):
1262
+ super().__init__(p=p, p_arg=p_arg, verbose=verbose,save_report=save_report)
1203
1263
 
1204
1264
  def setup_nodes(self, source=None, target=None):
1205
1265
  super().setup_nodes(source=source, target=target)
@@ -1239,6 +1299,8 @@ class GapJunction(UnidirectionConnector):
1239
1299
  if self.verbose:
1240
1300
  self.connection_number_info()
1241
1301
  self.timer.report('Done! \nTime for building connections')
1302
+ if self.save_report:
1303
+ self.save_connection_report()
1242
1304
  return nsyns
1243
1305
 
1244
1306
  def connection_number_info(self):
@@ -1247,6 +1309,32 @@ class GapJunction(UnidirectionConnector):
1247
1309
  super().connection_number_info()
1248
1310
  self.n_pair = n_pair
1249
1311
 
1312
+ def save_connection_report(self):
1313
+ """Save connections into a CSV file to be read from later"""
1314
+ src_str, trg_str = self.get_nodes_info()
1315
+ n_pair = self.n_pair
1316
+ fraction_0 = self.n_conn / self.n_poss if self.n_poss else 0.
1317
+ fraction_1 = self.n_conn / self.n_pair
1318
+
1319
+ # Convert fraction to percentage and prepare data for the DataFrame
1320
+ data = {
1321
+ "Source": [src_str+"Gap"],
1322
+ "Target": [trg_str+"Gap"],
1323
+ "Fraction of connected pairs in possible ones (%)": [fraction_0*100],
1324
+ "Fraction of connected pairs in all pairs (%)": [fraction_1*100]
1325
+ }
1326
+ df = pd.DataFrame(data)
1327
+
1328
+ # Append the data to the CSV file
1329
+ try:
1330
+ # Check if the file exists by trying to read it
1331
+ existing_df = pd.read_csv('connection_report.csv')
1332
+ # If no exception is raised, append without header
1333
+ df.to_csv('connection_report.csv', mode='a', header=False, index=False)
1334
+ except FileNotFoundError:
1335
+ # If the file does not exist, write with header
1336
+ df.to_csv('connection_report.csv', mode='w', header=True, index=False)
1337
+
1250
1338
 
1251
1339
  class CorrelatedGapJunction(GapJunction):
1252
1340
  """
@@ -1276,8 +1364,8 @@ class CorrelatedGapJunction(GapJunction):
1276
1364
  """
1277
1365
 
1278
1366
  def __init__(self, p_non=1., p_uni=1., p_rec=1., p_arg=None,
1279
- connector=None, verbose=True):
1280
- super().__init__(p=p_non, p_arg=p_arg, verbose=verbose)
1367
+ connector=None, verbose=True,save_report=True):
1368
+ super().__init__(p=p_non, p_arg=p_arg, verbose=verbose,save_report=save_report)
1281
1369
  self.vars['p_non'] = self.vars.pop('p')
1282
1370
  self.vars['p_uni'] = p_uni
1283
1371
  self.vars['p_rec'] = p_rec
@@ -1340,6 +1428,8 @@ class CorrelatedGapJunction(GapJunction):
1340
1428
  if self.verbose:
1341
1429
  self.connection_number_info()
1342
1430
  self.timer.report('Done! \nTime for building connections')
1431
+ if self.save_report:
1432
+ self.save_connection_report()
1343
1433
  return nsyns
1344
1434
 
1345
1435
 
@@ -611,7 +611,11 @@ def connection_totals(config=None,nodes=None,edges=None,sources=[],targets=[],si
611
611
 
612
612
  total = edges[(edges[source_id_type] == source_id) & (edges[target_id_type]==target_id)]
613
613
  if include_gap == False:
614
- total = total[total['is_gap_junction'] != True]
614
+ try:
615
+ cons = cons[cons['is_gap_junction'] != True]
616
+ except:
617
+ raise Exception("no gap junctions found to drop from connections")
618
+
615
619
  total = total.count()
616
620
  total = total.source_node_id # may not be the best way to pick
617
621
  return total
@@ -632,7 +636,11 @@ def percent_connections(config=None,nodes=None,edges=None,sources=[],targets=[],
632
636
 
633
637
  cons = edges[(edges[source_id_type] == source_id) & (edges[target_id_type]==target_id)]
634
638
  if include_gap == False:
635
- cons = cons[cons['is_gap_junction'] != True]
639
+ try:
640
+ cons = cons[cons['is_gap_junction'] != True]
641
+ except:
642
+ raise Exception("no gap junctions found to drop from connections")
643
+
636
644
  total_cons = cons.count().source_node_id
637
645
  # to determine reciprocal connectivity
638
646
  # create a copy and flip source/dest
@@ -685,7 +693,10 @@ def connection_divergence(config=None,nodes=None,edges=None,sources=[],targets=[
685
693
 
686
694
  cons = edges[(edges[source_id_type] == source_id) & (edges[target_id_type]==target_id)]
687
695
  if include_gap == False:
688
- cons = cons[cons['is_gap_junction'] != True]
696
+ try:
697
+ cons = cons[cons['is_gap_junction'] != True]
698
+ except:
699
+ raise Exception("no gap junctions found to drop from connections")
689
700
 
690
701
  if convergence:
691
702
  if method == 'min':
@@ -739,7 +750,10 @@ def gap_junction_connections(config=None,nodes=None,edges=None,sources=[],target
739
750
  cons = edges[(edges[source_id_type] == source_id) & (edges[target_id_type]==target_id)]
740
751
  #print(cons)
741
752
 
742
- cons = cons[cons['is_gap_junction'] == True] #only gap_junctions
753
+ try:
754
+ cons = cons[cons['is_gap_junction'] != True]
755
+ except:
756
+ raise Exception("no gap junctions found to drop from connections")
743
757
  mean = cons['target_node_id'].value_counts().mean()
744
758
  std = cons['target_node_id'].value_counts().std()
745
759
  return (round(mean,2)), (round(std,2))
@@ -755,7 +769,11 @@ def gap_junction_connections(config=None,nodes=None,edges=None,sources=[],target
755
769
 
756
770
  cons = edges[(edges[source_id_type] == source_id) & (edges[target_id_type]==target_id)]
757
771
  #add functionality that shows only the one's with gap_junctions
758
- cons = cons[cons['is_gap_junction'] == True]
772
+ try:
773
+ cons = cons[cons['is_gap_junction'] != True]
774
+ except:
775
+ raise Exception("no gap junctions found to drop from connections")
776
+
759
777
  total_cons = cons.count().source_node_id
760
778
 
761
779
  num_sources = s_list[source_id_type].value_counts().sort_index().loc[source_id]
@@ -775,10 +793,6 @@ def gap_junction_percent_connections(config=None,nodes=None,edges=None,sources=[
775
793
  import pandas as pd
776
794
 
777
795
 
778
-
779
-
780
-
781
-
782
796
 
783
797
  def connection_probabilities(config=None,nodes=None,edges=None,sources=[],
784
798
  targets=[],sids=[],tids=[],prepend_pop=True,dist_X=True,dist_Y=True,dist_Z=True,num_bins=10,include_gap=True):
@@ -857,7 +871,10 @@ def connection_probabilities(config=None,nodes=None,edges=None,sources=[],
857
871
 
858
872
  relevant_edges = edges[(edges[source_id_type] == source_id) & (edges[target_id_type]==target_id)]
859
873
  if include_gap == False:
860
- relevant_edges = relevant_edges[relevant_edges['is_gap_junction'] != True]
874
+ try:
875
+ relevant_edges = relevant_edges[relevant_edges['is_gap_junction'] != True]
876
+ except:
877
+ raise Exception("no gap junctions found to drop from connections")
861
878
  connected_distances = eudist(relevant_edges,dist_X,dist_Y,dist_Z).values.tolist()
862
879
  if len(connected_distances)>0:
863
880
  if connected_distances[0]==0:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bmtool
3
- Version: 0.5.3
3
+ Version: 0.5.4
4
4
  Summary: BMTool
5
5
  Home-page: https://github.com/cyneuro/bmtool
6
6
  Download-URL:
@@ -6,7 +6,7 @@ with open("README.md", "r") as fh:
6
6
 
7
7
  setup(
8
8
  name="bmtool",
9
- version="0.5.3",
9
+ version="0.5.4",
10
10
  author="Neural Engineering Laboratory at the University of Missouri",
11
11
  author_email="gregglickert@mail.missouri.edu",
12
12
  description="BMTool",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes