OSCR

The membrane-to-cortex distance regulates mDia1 activity to control cortical mechanics.

Code ↔ Paper

4 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 4 matches
  1. [1] § Methods › Cryo-electron tomography ↔ branch_detection_validation/branch_analysis.ipynb, lines 58–177 · score 0.79 · maximal distance, closest points, actin point, extrapolating, intersection, candidates
  2. [2] § Methods › Cryo-electron tomography ↔ jupyter_based_processing/filament_segmentation_to_coordinates/jupyter/filament_segmentation_to_coordinates.ipynb, lines 42–147 · score 0.73 · Bspline fit, branch points, eroded, equidistant, skeletonized, labelled
  3. [3] § Methods › Cryo-electron tomography ↔ jupyter_based_processing/filament_segmentation_to_coordinates/cluster_python/filament_segmentation_to_coordinates.py, lines 91–153 · score 0.60 · Bspline fit, equidistant, skeletonized, labelled, resampled, orientations
  4. [4] § Methods › Magnetic pincher ↔ Code_Python/TrackAnalyser.py, lines 959–1012 · score 0.55 · cortex thickness, relaxation, tracking, compression, median, field

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Jupyter notebook · 557 lines · 30 KB · GPL-3.0 · 1 match

  1. # %% [markdown]
  2. # # Branch Analysis
  3. #
  4. # ##### This script identifies branch points on filaments. Credits to Marc Siggel (Kosinski/Mahamid lab) for the initial translation of matlab code to python.
  5. # %% [markdown]
  6. # ## Initialization
  7. # %%
  8. import numpy as np
  9. import pandas as pd
  10. from scipy.spatial.distance import cdist
  11. import os
  12. # %% [markdown]
  13. # ## Helper Functions
  14. # %%
  15. def distance_of_two_lines(e1, e2, r1, r2):
  16. # r1, r2 = Point where the line passes through
  17. # e1, e2 = Direction vector
  18. # Find the unit vector perpendicular to both lines
  19. n = np.cross(e1, e2)
  20. n /= np.linalg.norm(n)
  21. # Calculate distance
  22. d = abs(np.dot(n, r1 - r2))
  23. return d
  24. # normalize to vector
  25. def unit_vector(vector):
  26. return vector / np.linalg.norm(vector)
  27. # find angle between two vectors (undirectionla)
  28. def angle_between(v1, v2):
  29. v1_u = unit_vector(v1)
  30. v2_u = unit_vector(v2)
  31. angle = np.degrees(np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0)))
  32. if angle > 90:
  33. angle = 180 - angle
  34. return angle
  35. # write bild file for chimera visualization
  36. def write_bild_file(list_of_fragments, output_filename, downscale=1.34808, diameter=1, color="gold"):
  37. bild_file = ".color {}\n".format(color)
  38. #print(positions)
  39. for fragment in list_of_fragments:
  40. for i in range(len(fragment)-1):
  41. #print(positions[i])
  42. bild_file += ".cylinder {} {} {} {} {} {} {}\n".format(fragment[i][0]/downscale, fragment[i][1]/downscale, fragment[i][2]/downscale, fragment[i+1][0]/downscale, fragment[i+1][1]/downscale, fragment[i+1][2]/downscale, diameter)
  43. text_file = open(output_filename, "w")
  44. text_file.write(bild_file)
  45. text_file.close()
  46. return
  47. #branch analysis
  48. def branch_analysis(array, cutoff, cutoff_branch, angle_cutoff, voxel_size = 1.34808):
  49. """ cutoff: cutoff of actin points within a tip whihc are considered
  50. cutoff_branch: maximal distance of the two extrapolated line segments at their closest point.
  51. (Note: perfect intersection is unlikely but small error margin is allowed for)
  52. (This avoids any false positives where the actin passes behind another filament)
  53. angle_cutoff: min angle between the two actin segments (max 90 degreess)
  54. Returns: the branch count
  55. """
  56. candidates_per_filament = []
  57. all_results = [] # indicies of all points that belong to a branch for visualization
  58. tip_for_viz = [] # list of points for filament tip visualization
  59. branch_index = 0 # running_index of the branches use because heterogeneous loop
  60. all_angles_list = []
  61. mother_intersect_point = [] # list of all points on mother filaments that is a branch intersection
  62. all_tip_coordinates = [] # list of filament tip coordinates
  63. # generate list of 3 points at the beginning or end of each filament
  64. for fil_idx in array["fil_idx"].unique():
  65. points = array[array["fil_idx"] == fil_idx][["X_coord", "Y_coord", "Z_coord"]] .to_numpy()
  66. end1 = points[0:4]
  67. end2 = points[-3:]
  68. all_tip_coordinates.append(end1)
  69. all_tip_coordinates.append(end2)
  70. all_tip_coordinates = np.vstack(all_tip_coordinates)
  71. # identify branches
  72. for fil_idx in array["fil_idx"].unique():
  73. current_fil = array.index[array["fil_idx"] == fil_idx].to_numpy() #point index on current filament
  74. points = array[array["fil_idx"] == fil_idx][["X_coord", "Y_coord", "Z_coord"]].to_numpy() #coordinates of points on current filament
  75. all_points_coord = array[["X_coord", "Y_coord", "Z_coord"]].to_numpy()
  76. tip1 = np.array([points[0]]) #tip 1 coordinates
  77. tip2 = np.array([points[-1]]) #tip 2 coordinates
  78. # list of points for visualizing each tip
  79. points_for_viz_tip1 = points[0:7]
  80. points_for_viz_tip2 = points[-8:]
  81. tip_for_viz.append(points_for_viz_tip1)
  82. tip_for_viz.append(points_for_viz_tip2)
  83. below_cutoff_tip1 = np.argwhere(cdist(tip1, all_points_coord) < cutoff)[:,1] #index of points of dist below cutoff fom tip 1
  84. below_cutoff_tip2 = np.argwhere(cdist(tip2, all_points_coord) < cutoff)[:,1] #index of points of dist below cutoff from tip 2
  85. not_overlap_tip1 = list(set(below_cutoff_tip1) - set(current_fil)) #excluding points on the same filament
  86. not_overlap_tip2 = list(set(below_cutoff_tip2) - set(current_fil)) #excluding points on the same filament
  87. if len(not_overlap_tip1) != 0:
  88. not_overlap_tip1 = np.sort(not_overlap_tip1)
  89. filament_indices = array.iloc[not_overlap_tip1]["fil_idx"].to_numpy()
  90. # here we analyze all candidates for a specfic tip.
  91. for fil_index in np.unique(filament_indices):
  92. candidate = not_overlap_tip1[filament_indices == fil_index] #all points on potential mother filament
  93. central_index = candidate[int(len(candidate)/2)] #center point index
  94. connection_indices = array.iloc[np.max([central_index-5,0]):central_index+5] #5 points before and after center
  95. connection_indices = connection_indices[connection_indices["fil_idx"] == fil_index] #make sure they're on the potential mother filament
  96. connection_points = connection_indices[["X_coord", "Y_coord", "Z_coord"]].to_numpy() #get coordinates of mother filament points
  97. vector_tip = points_for_viz_tip1[0] - points_for_viz_tip1[-1] #vector of orientation at tip/branch point
  98. vector_connection = connection_points[0] - connection_points[-1] #vector of orientation at connection point of mother filament
  99. line_dist = distance_of_two_lines(vector_tip, vector_connection, points_for_viz_tip1[0], connection_points[0]) # calculate min distance from projected distance from line vec
  100. line_angle = angle_between(vector_tip, vector_connection) #angle between two vectors
  101. closest = connection_points[np.argmin(cdist(tip1,connection_points)[0])] #closest point to tip from potential mother filament
  102. # check if the identified mother-daughter combination is already in the results set. If yes, skip to next.
  103. if len(all_results) == 0:
  104. pass
  105. else:
  106. all_stacked_results = np.vstack(all_results)
  107. if len(np.intersect1d(points_for_viz_tip1, all_stacked_results)) != 0 and len(np.intersect1d(connection_points, all_stacked_results)) != 0:
  108. continue
  109. # if the mother-daughter pair satisfies all criteria on distance and angle, and the mother closest point is not a tip, identify this as a branch
  110. if line_dist <= cutoff_branch and line_angle > angle_cutoff and len(np.intersect1d(closest,all_tip_coordinates)) == 0:
  111. all_results.append(points_for_viz_tip1)
  112. all_results.append(connection_points)
  113. mother_intersect_point.append(array.iloc[central_index][["X_coord", "Y_coord", "Z_coord"]].to_numpy())
  114. branch_index += 1
  115. # repeat above with the other tip
  116. if len(not_overlap_tip2) != 0:
  117. not_overlap_tip2 = np.sort(not_overlap_tip2)
  118. filament_indices = array.iloc[not_overlap_tip2]["fil_idx"].to_numpy()
  119. for fil_index in np.unique(filament_indices):
  120. candidate = not_overlap_tip2[filament_indices == fil_index]
  121. central_index = candidate[int(len(candidate)/2)]
  122. connection_indices = array[np.max([central_index-5,0]):central_index+5]
  123. connection_indices = connection_indices[connection_indices["fil_idx"] == fil_index]
  124. connection_points = connection_indices[["X_coord", "Y_coord", "Z_coord"]].to_numpy()
  125. vector_tip = points_for_viz_tip2[0] - points_for_viz_tip2[-1]
  126. vector_connection = connection_points[0] - connection_points[-1]
  127. line_dist = distance_of_two_lines(vector_tip, vector_connection, points_for_viz_tip2[0], connection_points[0])
  128. line_angle = angle_between(vector_tip, vector_connection)
  129. closest = connection_points[np.argmin(cdist(tip2,connection_points)[0])]
  130. if len(all_results) == 0:
  131. pass
  132. else:
  133. all_stacked_results = np.vstack(all_results)
  134. if len(np.intersect1d(points_for_viz_tip2,all_stacked_results)) != 0 and len(np.intersect1d(connection_points,all_stacked_results)) != 0:
  135. continue
  136. if line_dist <= cutoff_branch and line_angle > angle_cutoff and len(np.intersect1d(closest,all_tip_coordinates)) == 0:
  137. all_results.append(points_for_viz_tip2)
  138. all_results.append(connection_points)
  139. mother_intersect_point.append(array.iloc[central_index][["X_coord", "Y_coord", "Z_coord"]].to_numpy())
  140. branch_index += 1
  141. # add branch information into point csv, a point is only considered a branch point if it is a point on the mother filament at which the branch occurs
  142. is_intersect_point = np.zeros(len(array))
  143. for i in range(len(is_intersect_point)):
  144. if len(mother_intersect_point) == 0:
  145. break
  146. if ((mother_intersect_point == array.iloc[i][["X_coord", "Y_coord", "Z_coord"]].to_numpy()).all(axis = 1)).any(): #check if coordinates match between intesect point array and each point
  147. is_intersect_point[i] = 1
  148. array['branch'] = is_intersect_point
  149. return branch_index, array, all_results
  150. #branch analysis
  151. def branch_analysis_without_endpoint_suppression(array, cutoff, cutoff_branch, angle_cutoff, voxel_size = 1.34808):
  152. """ cutoff: cutoff of actin points within a tip whihc are considered
  153. cutoff_branch: maximal distance of the two extrapolated line segments at their closest point.
  154. (Note: perfect intersection is unlikely but small error margin is allowed for)
  155. (This avoids any false positives where the actin passes behind another filament)
  156. angle_cutoff: min angle between the two actin segments (max 90 degreess)
  157. Returns: the branch count
  158. """
  159. candidates_per_filament = []
  160. all_results = [] # indicies of all points that belong to a branch for visualization
  161. tip_for_viz = [] # list of points for filament tip visualization
  162. branch_index = 0 # running_index of the branches use because heterogeneous loop
  163. all_angles_list = []
  164. mother_intersect_point = [] # list of all points on mother filaments that is a branch intersection
  165. all_tip_coordinates = [] # list of filament tip coordinates
  166. # generate list of 3 points at the beginning or end of each filament
  167. for fil_idx in array["fil_idx"].unique():
  168. points = array[array["fil_idx"] == fil_idx][["X_coord", "Y_coord", "Z_coord"]] .to_numpy()
  169. end1 = points[0:4]
  170. end2 = points[-3:]
  171. all_tip_coordinates.append(end1)
  172. all_tip_coordinates.append(end2)
  173. all_tip_coordinates = np.vstack(all_tip_coordinates)
  174. # identify branches
  175. for fil_idx in array["fil_idx"].unique():
  176. current_fil = array.index[array["fil_idx"] == fil_idx].to_numpy() #point index on current filament
  177. points = array[array["fil_idx"] == fil_idx][["X_coord", "Y_coord", "Z_coord"]].to_numpy() #coordinates of points on current filament
  178. all_points_coord = array[["X_coord", "Y_coord", "Z_coord"]].to_numpy()
  179. tip1 = np.array([points[0]]) #tip 1 coordinates
  180. tip2 = np.array([points[-1]]) #tip 2 coordinates
  181. # list of points for visualizing each tip
  182. points_for_viz_tip1 = points[0:7]
  183. points_for_viz_tip2 = points[-8:]
  184. tip_for_viz.append(points_for_viz_tip1)
  185. tip_for_viz.append(points_for_viz_tip2)
  186. below_cutoff_tip1 = np.argwhere(cdist(tip1, all_points_coord) < cutoff)[:,1] #index of points of dist below cutoff fom tip 1
  187. below_cutoff_tip2 = np.argwhere(cdist(tip2, all_points_coord) < cutoff)[:,1] #index of points of dist below cutoff from tip 2
  188. not_overlap_tip1 = list(set(below_cutoff_tip1) - set(current_fil)) #excluding points on the same filament
  189. not_overlap_tip2 = list(set(below_cutoff_tip2) - set(current_fil)) #excluding points on the same filament
  190. if len(not_overlap_tip1) != 0:
  191. not_overlap_tip1 = np.sort(not_overlap_tip1)
  192. filament_indices = array.iloc[not_overlap_tip1]["fil_idx"].to_numpy()
  193. # here we analyze all candidates for a specfic tip.
  194. for fil_index in np.unique(filament_indices):
  195. candidate = not_overlap_tip1[filament_indices == fil_index] #all points on potential mother filament
  196. central_index = candidate[int(len(candidate)/2)] #center point index
  197. connection_indices = array.iloc[np.max([central_index-5,0]):central_index+5] #5 points before and after center
  198. connection_indices = connection_indices[connection_indices["fil_idx"] == fil_index] #make sure they're on the potential mother filament
  199. connection_points = connection_indices[["X_coord", "Y_coord", "Z_coord"]].to_numpy() #get coordinates of mother filament points
  200. vector_tip = points_for_viz_tip1[0] - points_for_viz_tip1[-1] #vector of orientation at tip/branch point
  201. vector_connection = connection_points[0] - connection_points[-1] #vector of orientation at connection point of mother filament
  202. line_dist = distance_of_two_lines(vector_tip, vector_connection, points_for_viz_tip1[0], connection_points[0]) # calculate min distance from projected distance from line vec
  203. line_angle = angle_between(vector_tip, vector_connection) #angle between two vectors
  204. closest = connection_points[np.argmin(cdist(tip1,connection_points)[0])] #closest point to tip from potential mother filament
  205. # check if the identified mother-daughter combination is already in the results set. If yes, skip to next.
  206. if len(all_results) == 0:
  207. pass
  208. else:
  209. all_stacked_results = np.vstack(all_results)
  210. if len(np.intersect1d(points_for_viz_tip1, all_stacked_results)) != 0 and len(np.intersect1d(connection_points, all_stacked_results)) != 0:
  211. continue
  212. # if the mother-daughter pair satisfies all criteria on distance and angle, and the mother closest point is not a tip, identify this as a branch
  213. if line_dist <= cutoff_branch and line_angle > angle_cutoff:
  214. all_results.append(points_for_viz_tip1)
  215. all_results.append(connection_points)
  216. mother_intersect_point.append(array.iloc[central_index][["X_coord", "Y_coord", "Z_coord"]].to_numpy())
  217. branch_index += 1
  218. # repeat above with the other tip
  219. if len(not_overlap_tip2) != 0:
  220. not_overlap_tip2 = np.sort(not_overlap_tip2)
  221. filament_indices = array.iloc[not_overlap_tip2]["fil_idx"].to_numpy()
  222. for fil_index in np.unique(filament_indices):
  223. candidate = not_overlap_tip2[filament_indices == fil_index]
  224. central_index = candidate[int(len(candidate)/2)]
  225. connection_indices = array[np.max([central_index-5,0]):central_index+5]
  226. connection_indices = connection_indices[connection_indices["fil_idx"] == fil_index]
  227. connection_points = connection_indices[["X_coord", "Y_coord", "Z_coord"]].to_numpy()
  228. vector_tip = points_for_viz_tip2[0] - points_for_viz_tip2[-1]
  229. vector_connection = connection_points[0] - connection_points[-1]
  230. line_dist = distance_of_two_lines(vector_tip, vector_connection, points_for_viz_tip2[0], connection_points[0])
  231. line_angle = angle_between(vector_tip, vector_connection)
  232. closest = connection_points[np.argmin(cdist(tip2,connection_points)[0])]
  233. if len(all_results) == 0:
  234. pass
  235. else:
  236. all_stacked_results = np.vstack(all_results)
  237. if len(np.intersect1d(points_for_viz_tip2,all_stacked_results)) != 0 and len(np.intersect1d(connection_points,all_stacked_results)) != 0:
  238. continue
  239. if line_dist <= cutoff_branch and line_angle > angle_cutoff:
  240. all_results.append(points_for_viz_tip2)
  241. all_results.append(connection_points)
  242. mother_intersect_point.append(array.iloc[central_index][["X_coord", "Y_coord", "Z_coord"]].to_numpy())
  243. branch_index += 1
  244. # add branch information into point csv, a point is only considered a branch point if it is a point on the mother filament at which the branch occurs
  245. is_intersect_point = np.zeros(len(array))
  246. for i in range(len(is_intersect_point)):
  247. if len(mother_intersect_point) == 0:
  248. break
  249. if ((mother_intersect_point == array.iloc[i][["X_coord", "Y_coord", "Z_coord"]].to_numpy()).all(axis = 1)).any(): #check if coordinates match between intesect point array and each point
  250. is_intersect_point[i] = 1
  251. array['branch'] = is_intersect_point
  252. return branch_index, array, all_results
  253. #calculate actin length
  254. def calc_length_all_actin(array, voxel_size = 1.34808):
  255. """calculates the lengtht of all actins (loop over other fxn)"""
  256. length_list = []
  257. positions_bild = []
  258. for fil in array["fil_idx"].unique():
  259. # pick points of single filament
  260. points = array[["X_coord", "Y_coord", "Z_coord"]][array["fil_idx"] == fil].to_numpy()
  261. # vectorized numpy computation of distances
  262. d = np.diff(points, axis=0)
  263. segdists = np.sqrt((d ** 2).sum(axis=1))
  264. # sum parrtial distances between points
  265. full_dist = np.sum(segdists)
  266. length_list.append(full_dist)
  267. positions_bild.append(points)
  268. # sum all filaments
  269. full_length = np.sum(length_list) #total actin length
  270. return full_length, positions_bild
  271. # %% [markdown]
  272. # ## Variable setup
  273. # %%
  274. # list of conditions to compare, if no comparison is needed just enter [""] - the empty quotation within the array is important
  275. conditions = [""]
  276. # list of samples in each condition, each in a separate list; if only one condition is needed it should be [[tomograms]]
  277. tomo_list = [["TS_11", "TS_12", "TS_13", "TS_14"]]
  278. # directory where resampled actin csv files are stored
  279. actin_csv_dir = "/g/scb/mahamid/Dorothy/MCA_Project/Branching_validation/20231016_branch_verficiation_more_actin"
  280. # prefix and suffix of actin file, such as the csv file name is prefix_tomoname_suffix.csv for each file, where tomoname is the name entered in tomo_list
  281. actin_file_prefix = ""
  282. actin_file_suffix = "_coord"
  283. # if separate cell analysis is not needed, enter [""] - the empty quotation within the array is important
  284. cell_suffix = [""]
  285. # directory where membrane csv files are stored
  286. memb_csv_dir = ""
  287. # prefix and suffix of membrane files, such as the csv file name is prefix_tomoname_suffix_memb_1/2.csv for each file, where tomoname is the name entered in tomo_list
  288. memb_file_prefix = ""
  289. memb_file_suffix = ""
  290. # output directory for output files
  291. out_dir = "/g/scb/mahamid/Dorothy/MCA_Project/Branching_validation/20231016_branch_verficiation_more_actin"
  292. # voxel size in sample to be analyzed
  293. voxel_size = 1.3544
  294. # maximum standard distance between mother and daughter filament, in nm
  295. cutoff_std = 35
  296. #cutoff_test = [5, 10, 15, 20, 25]
  297. cutoff_test = [35]
  298. # maximum standard vertical distance at closest point for mother and daughter filament, in nm
  299. cutoff_branch_std = 3
  300. # cutoff_branch_test = [3,5,8,10]
  301. cutoff_branch_test = [3]
  302. # minimum standard angle between mother and daughter filament
  303. angle_cutoff_std = 50
  304. # angle_cutoff_test = [50, 60, 70]
  305. angle_cutoff_test = [50]
  306. # %% [markdown]
  307. # ## Main code
  308. # ##### This code analyzes the number of branches in each tomogram (or in each cell per tomogram, as needed). The actin csv file is updated with a column "branches" which shows 1 if a point is considered a branch point on a mother filament and 0 otherwise. A csv file "branch_analysis" is created to summarize the number of branches and the number of branches per actin length in each tomogrm/cell.
  309. # %%
  310. # set up data frame
  311. df = pd.DataFrame({"condition": [], "cutoff": [], "cutoff_branch": [], "angle_cutoff": [], "cell": [], "num_branch_point": [], "branch_fraction": []})
  312. # create test conditions with different cutoff values (maintaining the same cutoff_branch and angle_cutoff)
  313. list_of_test_conditions = []
  314. for cutoff in cutoff_test:
  315. cutoff_branch = cutoff_branch_std
  316. angle_cutoff = angle_cutoff_std
  317. # check if this condition has already been tested
  318. if (cutoff, cutoff_branch, angle_cutoff) in list_of_test_conditions:
  319. continue
  320. else:
  321. list_of_test_conditions.append((cutoff, cutoff_branch, angle_cutoff))
  322. # create test conditions with different cutoff_branch values (maintaining the same cutoff and angle_cutoff)
  323. for cutoff_branch in cutoff_branch_test:
  324. cutoff = cutoff_std
  325. angle_cutoff = angle_cutoff_std
  326. # check if this condition has already been tested
  327. if (cutoff, cutoff_branch, angle_cutoff) in list_of_test_conditions:
  328. continue
  329. else:
  330. list_of_test_conditions.append((cutoff, cutoff_branch, angle_cutoff))
  331. # create test conditions with different angle_cutoff values (maintaining the same cutoff and cutoff_branch)
  332. for angle_cutoff in angle_cutoff_test:
  333. cutoff = cutoff_std
  334. cutoff_branch = cutoff_branch_std
  335. # check if this condition has already been tested
  336. if (cutoff, cutoff_branch, angle_cutoff) in list_of_test_conditions:
  337. continue
  338. else:
  339. list_of_test_conditions.append((cutoff, cutoff_branch, angle_cutoff))
  340. print(list_of_test_conditions)
  341. for i, condition in enumerate(conditions):
  342. # for storing results
  343. list_of_tomo = []
  344. list_of_num_branch_points = []
  345. list_of_branch_fraction = []
  346. list_of_conditions = []
  347. list_of_cutoff = []
  348. list_of_cutoff_branch = []
  349. list_of_angle_cutoff = []
  350. # run function for all sample files for each test condition
  351. for (cutoff, cutoff_branch, angle_cutoff) in list_of_test_conditions:
  352. for tomo in tomo_list[i]:
  353. for cell in cell_suffix:
  354. suffix = "" + cell
  355. print("Analyzing {}{} with conditions cutoff {}, cutoff_branch {}, angle_cutoff {}".format(tomo, suffix, cutoff, cutoff_branch, angle_cutoff))
  356. list_of_conditions.append(condition)
  357. list_of_tomo.append(tomo + suffix)
  358. list_of_cutoff.append(cutoff)
  359. list_of_cutoff_branch.append(cutoff_branch)
  360. list_of_angle_cutoff.append(angle_cutoff)
  361. # read data
  362. actin = pd.read_csv(os.path.join(actin_csv_dir, actin_file_prefix + tomo + actin_file_suffix + suffix + ".csv"), delimiter = ",")
  363. # calculate full length
  364. full_length, positions = calc_length_all_actin(actin, voxel_size)
  365. # perform branch analysis
  366. branch_index, actin, branch_positions = branch_analysis(actin, cutoff, cutoff_branch, angle_cutoff, voxel_size)
  367. list_of_num_branch_points.append(branch_index)
  368. list_of_branch_fraction.append(float(branch_index)/float(full_length))
  369. # write result summray
  370. df_condition = pd.DataFrame({"condition": list_of_conditions, "cutoff": list_of_cutoff, "cutoff_branch": list_of_cutoff_branch, "angle_cutoff": list_of_angle_cutoff, "cell": list_of_tomo, "num_branch_point": list_of_num_branch_points, "branch_fraction": list_of_branch_fraction})
  371. df = pd.concat([df, df_condition], axis = 0)
  372. df.to_csv(os.path.join(out_dir, "branch_analysis.csv"), sep = ",", index = False)
  373. # re-calculate and save data for the main conditions
  374. for tomo in tomo_list[0]:
  375. # read data
  376. actin = pd.read_csv(os.path.join(actin_csv_dir, actin_file_prefix + tomo + actin_file_suffix + suffix + ".csv"), delimiter = ",")
  377. # calculate full length
  378. full_length, positions = calc_length_all_actin(actin, voxel_size)
  379. # perform branch analysis
  380. branch_index, actin, branch_positions = branch_analysis(actin, cutoff_std, cutoff_branch_std, angle_cutoff_std, voxel_size)
  381. list_of_num_branch_points.append(branch_index)
  382. list_of_branch_fraction.append(float(branch_index)/float(full_length))
  383. # write bild files of branches
  384. write_bild_file(branch_positions, os.path.join(out_dir, "{}_branches.bild".format(tomo + suffix)), downscale=voxel_size, diameter=4, color="gold")
  385. # update actin csv with branch information
  386. actin.to_csv(os.path.join(actin_csv_dir, actin_file_prefix + tomo + actin_file_suffix + suffix + ".csv"), sep = ",", index = False)
  387. # %% [markdown]
  388. # ##### This code performs the same calculation as above, but uses no endpoint suppression in branch detection. That is, it does not exclude detected branch points where the intersection point is at the tip of the mother and daugher filament. Note that this overwrites the coord.csv file so that the branch points are the ones without endpoint suppression. In order to use branch points with endpoint suppression detection for further processing, skip this step (or re-run the previous step after running this step).
  389. # %%
  390. # set up data frame
  391. df = pd.DataFrame({"condition": [], "cutoff": [], "cutoff_branch": [], "angle_cutoff": [], "cell": [], "num_branch_point": [], "branch_fraction": []})
  392. # create test conditions with different cutoff values (maintaining the same cutoff_branch and angle_cutoff)
  393. list_of_test_conditions = []
  394. for cutoff in cutoff_test:
  395. cutoff_branch = cutoff_branch_std
  396. angle_cutoff = angle_cutoff_std
  397. # check if this condition has already been tested
  398. if (cutoff, cutoff_branch, angle_cutoff) in list_of_test_conditions:
  399. continue
  400. else:
  401. list_of_test_conditions.append((cutoff, cutoff_branch, angle_cutoff))
  402. # create test conditions with different cutoff_branch values (maintaining the same cutoff and angle_cutoff)
  403. for cutoff_branch in cutoff_branch_test:
  404. cutoff = cutoff_std
  405. angle_cutoff = angle_cutoff_std
  406. # check if this condition has already been tested
  407. if (cutoff, cutoff_branch, angle_cutoff) in list_of_test_conditions:
  408. continue
  409. else:
  410. list_of_test_conditions.append((cutoff, cutoff_branch, angle_cutoff))
  411. # create test conditions with different angle_cutoff values (maintaining the same cutoff and cutoff_branch)
  412. for angle_cutoff in angle_cutoff_test:
  413. cutoff = cutoff_std
  414. cutoff_branch = cutoff_branch_std
  415. # check if this condition has already been tested
  416. if (cutoff, cutoff_branch, angle_cutoff) in list_of_test_conditions:
  417. continue
  418. else:
  419. list_of_test_conditions.append((cutoff, cutoff_branch, angle_cutoff))
  420. print(list_of_test_conditions)
  421. for i, condition in enumerate(conditions):
  422. # for storing results
  423. list_of_tomo = []
  424. list_of_num_branch_points = []
  425. list_of_branch_fraction = []
  426. list_of_conditions = []
  427. list_of_cutoff = []
  428. list_of_cutoff_branch = []
  429. list_of_angle_cutoff = []
  430. # run function for all sample files for each test condition
  431. for (cutoff, cutoff_branch, angle_cutoff) in list_of_test_conditions:
  432. for tomo in tomo_list[i]:
  433. for cell in cell_suffix:
  434. suffix = "" + cell
  435. print("Analyzing {}{} with conditions cutoff {}, cutoff_branch {}, angle_cutoff {}".format(tomo, suffix, cutoff, cutoff_branch, angle_cutoff))
  436. list_of_conditions.append(condition)
  437. list_of_tomo.append(tomo + suffix)
  438. list_of_cutoff.append(cutoff)
  439. list_of_cutoff_branch.append(cutoff_branch)
  440. list_of_angle_cutoff.append(angle_cutoff)
  441. # read data
  442. actin = pd.read_csv(os.path.join(actin_csv_dir, actin_file_prefix + tomo + actin_file_suffix + suffix + ".csv"), delimiter = ",")
  443. # calculate full length
  444. full_length, positions = calc_length_all_actin(actin, voxel_size)
  445. # perform branch analysis
  446. branch_index, actin, branch_positions = branch_analysis_without_endpoint_suppression(actin, cutoff, cutoff_branch, angle_cutoff, voxel_size)
  447. list_of_num_branch_points.append(branch_index)
  448. list_of_branch_fraction.append(float(branch_index)/float(full_length))
  449. # write result summray
  450. df_condition = pd.DataFrame({"condition": list_of_conditions, "cutoff": list_of_cutoff, "cutoff_branch": list_of_cutoff_branch, "angle_cutoff": list_of_angle_cutoff, "cell": list_of_tomo, "num_branch_point": list_of_num_branch_points, "branch_fraction": list_of_branch_fraction})
  451. df = pd.concat([df, df_condition], axis = 0)
  452. df.to_csv(os.path.join(out_dir, "branch_analysis_without_endpoint_suppression.csv"), sep = ",", index = False)
  453. # re-calculate and save data for the main conditions
  454. for tomo in tomo_list[0]:
  455. # read data
  456. actin = pd.read_csv(os.path.join(actin_csv_dir, actin_file_prefix + tomo + actin_file_suffix + suffix + ".csv"), delimiter = ",")
  457. # calculate full length
  458. full_length, positions = calc_length_all_actin(actin, voxel_size)
  459. # perform branch analysis
  460. branch_index, actin, branch_positions = branch_analysis_without_endpoint_suppression(actin, cutoff_std, cutoff_branch_std, angle_cutoff_std, voxel_size)
  461. list_of_num_branch_points.append(branch_index)
  462. list_of_branch_fraction.append(float(branch_index)/float(full_length))
  463. # write bild files of branches
  464. write_bild_file(branch_positions, os.path.join(out_dir, "{}_branches_without_endpoint_suppression.bild".format(tomo + suffix)), downscale=voxel_size, diameter=4, color="gold")
  465. # update actin csv with branch information
  466. actin.to_csv(os.path.join(actin_csv_dir, actin_file_prefix + tomo + actin_file_suffix + suffix + ".csv"), sep = ",", index = False)

branch_analysis.ipynb at commit 819e80c, under GPL-3.0 · at the source

Overview

Authors: Léanne Strauss1, Sergio Lembo1,2, Samuel F Gérard1,3, Marc Siggel3,4,5, Dorothy Cheng1,3, Martin Bergert1, Sarah K Foster1, Joseph Vermeil6,7,8,9,10, Mauricio Toro-Nahuelpan1,3,11, Lena M Fischer1, Qin Yu1,12, Ewa Sitarska1,13,14, Chii Jou Chan15,16, Jan Kosinski3,4,5, Matthieu Piel6,7, Olivia du Roure8, Julien Heuvingh8, Julia Mahamid1,3, Alba Diz-Muñoz1
16 affiliations
  1. Cell Biology and Biophysics Unit, European Molecular Biology Laboratory (EMBL), Heidelberg, Germany
  2. Present Address: Institute of Science and Technology Austria (ISTA), Klosterneuburg, Austria
  3. Molecular Systems Biology Unit, EMBL, Heidelberg, Germany
  4. EMBL Hamburg, Hamburg, Germany
  5. Centre for Structural Systems Biology (CSSB), Hamburg, Germany
  6. Institut Curie, PSL University, CNRS, Paris, France
  7. Institut Pierre Gilles de Gennes, PSL University, CNRS, Paris, France
  8. Physique et Mécanique des Milieux Hétérogènes (PMMH), CNRS, ESPCI Paris–Université PSL, Sorbonne Université, Université Paris Cité, Paris, France
  9. Present Address: Laboratoire Jean Perrin, Institut de Biologie Paris-Seine, Sorbonne Université, 11 CNRS UMR, Paris, France
  10. Present Address: Institut Jacques Monod, CNRS UMR, Paris, France
  11. Present Address: Computational Innovation, Boehringer Ingelheim Pharma GmbH & Co. KG, Biberach, Germany
  12. Present Address: The Francis Crick Institute, London, UK
  13. Present Address: Department of Cell Biology, Harvard Medical School, Boston, MA USA
  14. Present Address: Program in Cellular and Molecular Medicine, Boston Children’s Hospital, Boston, MA USA
  15. Developmental Biology Unit, EMBL, Heidelberg, Germany
  16. Present Address: Mechanobiology Institute, Department of Biological Sciences, National University of Singapore, Singapore, Singapore
Journal: Nature communications, volume 17, issue 1, article 9501
Dates: received 12 March 2026; accepted 21 April 2026; published online 4 September 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1038/s41467-026-72845-3 · PMID 42697882 · PMCID PMC13545285 · OpenAlex W7208712085
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: histology / microscopy (modality), human (organism), mouse (organism), cellular / molecular (subfield)
Methods: Connectivity, Evoked potentials, Machine learning, fMRI & imaging, Preprocessing
Keywords: Biophysics, Actin
MeSH: Cell Membrane*, Formins*, Actins, Animals, Biomechanical Phenomena, Cryoelectron Microscopy, Humans, Mice (* major topic)
Topic: Cellular Mechanics and Interactions (Cell Biology, Biochemistry, Genetics and Molecular Biology), according to OpenAlex
Funding: European Research Council (101124221); Deutsche Forschungsgemeinschaft (DI 2205/3-1)
Citations: not cited yet (Europe PMC); 119 references in the paper

Abstract

The shape of animal cells is controlled by their surface, which comprises the cell cortex, a peripheral actin network, tethered to the plasma membrane by membrane-to-cortex attachment proteins. Changes in cortical components have long been considered to dominate the regulation of forces and mechanical properties at the cell surface and drive morphogenesis. Here, we show that the coupling of the cortex to the membrane is also key for the regulation of its mechanical properties. By combining molecular engineering with biophysical approaches and in-cell cryo-electron tomography we describe the cell surface with nanometer-resolution and link its organization to cell-scale mechanics. We find that membrane-to-cortex attachment proteins can physically draw the cortex closer to the membrane, in a density and length-dependent manner. This reduction of the membrane-to-cortex distance controls the activity of the formin mDia1, leading to a reduction in cortical tension. Our study thus defines a novel mechanism whereby the membrane-to-cortex distance is a functional geometrical parameter that regulates cell surface properties.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repositories

Its files are read in the Code ↔ Paper reader above, with 4 matches between paragraphs and lines of code.

jvermeil-biophys/CortExplore_PublicVersion

License: GPL-3.0
State: the link answers, verified on 26 September 2026
Evidence: files inventoried
Commit: ffddc269c9507e067bf38001d2d0619954a59cf8, 11 April 2023
Languages: Python (17)
Size: 25 files, 17 scripts
Software Heritage: not archived
Found in: the text, “Magnetic pincher”
Holds: README, license file
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (15 files), Matplotlib (14 files), pandas (14 files), SciPy (13 files), seaborn (11 files), statsmodels (10 files), scikit-image (5 files), OpenCV (1 file)
Availability: 1 check, the latest on 26 September 2026: the link answers
  • 26 September 2026: the link answers
19 files

mahamidlab/actin_cortex_analysis

License: GPL-3.0
State: the link answers, verified on 26 September 2026
Evidence: files inventoried
Commit: 819e80c9f6eaf55845c0cea39303e55339f683f0, 30 January 2024
Languages: Jupyter (17), Python (9), R (9), Shell (2), MATLAB (1)
Size: 43 files, 38 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, license file, environment (jupyter_based_processing/setup.py), 17 notebooks
Not found: CITATION.cff, tests, continuous integration, documentation
Tools: NumPy (25 files), pandas (25 files), SciPy (22 files), ggpubr (8 files), scikit-image (8 files), Matplotlib (7 files), tidyverse (6 files), ggplot2 (2 files), seaborn (2 files), car (1 file), Image Processing Toolbox (1 file)
Availability: 1 check, the latest on 26 September 2026: the link answers
  • 26 September 2026: the link answers
40 files

Code availability

The code used for cortex analysis from binary segmentations obtained during cryo-ET data processing is available on GitHub with the following link: https://github.com/MahamidLab/actin_cortex_analysis/tree/revision.

The Napari plugin for reviewing and manually correct spot detections used in the filopodia analysis is available at GitHub with the following link: https://github.com/diz-lab/filospot.

Reproduced under the paper's license (CC BY), from the paper cited above.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 55 scripts, each with its path and the digest of its content;
  • 4 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data Availability Statement

The dataset for the analysis of cortical actin and p-myosin in fixed cells, as well as actin and myosin−2 in live cells can be found together with the corresponding Fiji macro for immunofluorescence quantification in the Biostudies database (accession number S-BIAD2611).

All raw frames, tilt series, metadata, tomograms and segmentations generated for this work are deposited in the Electron Microscopy Public Image Archive (EMPIAR)118 under accession code EMPIAR-13326. A representative tomogram associated with this entry is available in the Electron Microscopy Data Bank (EMDB)119 under entry EMD-56367.

The experimental imaging data for the filopodia analysis, the used Spotiflow model with corresponding training data and example datasets are available in the BioStudies database (accession number S-BIAD2611).

Raw numbers for plots presented in this paper as well as western blot images are available in the Source Data. All other data and unique reagents that support this study are available from the corresponding authors upon request. Source data are provided in this paper. Source data are provided with this paper.

The code used for cortex analysis from binary segmentations obtained during cryo-ET data processing is available on GitHub with the following link: https://github.com/MahamidLab/actin_cortex_analysis/tree/revision.

The Napari plugin for reviewing and manually correct spot detections used in the filopodia analysis is available at GitHub with the following link: https://github.com/diz-lab/filospot.

Reproduced under the paper's license (CC BY), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 19 authors, 2 keywords, 8 MeSH terms, 2 funders, 116 references.

Cite

This paper

Strauss, L., Lembo, S., Gérard, S. F., Siggel, M., Cheng, D., Bergert, M., Foster, S. K., Vermeil, J., Toro-Nahuelpan, M., Fischer, L. M., Yu, Q., Sitarska, E., Chan, C. J., Kosinski, J., Piel, M., du Roure, O., Heuvingh, J., Mahamid, J., & Diz-Muñoz, A. (2026). The membrane-to-cortex distance regulates mDia1 activity to control cortical mechanics. Nature communications, 17(1), 9501. https://doi.org/10.1038/s41467-026-72845-3

BibTeX

@article{strauss2026membrane,
author = {Strauss, Léanne and Lembo, Sergio and Gérard, Samuel F and Siggel, Marc and Cheng, Dorothy and Bergert, Martin and Foster, Sarah K and Vermeil, Joseph and Toro-Nahuelpan, Mauricio and Fischer, Lena M and Yu, Qin and Sitarska, Ewa and Chan, Chii Jou and Kosinski, Jan and Piel, Matthieu and du Roure, Olivia and Heuvingh, Julien and Mahamid, Julia and Diz-Muñoz, Alba},
title = {{The membrane-to-cortex distance regulates mDia1 activity to control cortical mechanics}},
journal = {Nature communications},
year = {2026},
month = sep,
volume = {17},
number = {1},
pages = {9501},
publisher = {Nature Publishing Group},
issn = {2041-1723},
doi = {10.1038/s41467-026-72845-3},
url = {https://doi.org/10.1038/s41467-026-72845-3},
pmid = {42697882},
pmcid = {PMC13545285}
}

RIS

TY - JOUR
AU - Strauss, Léanne
AU - Lembo, Sergio
AU - Gérard, Samuel F
AU - Siggel, Marc
AU - Cheng, Dorothy
AU - Bergert, Martin
AU - Foster, Sarah K
AU - Vermeil, Joseph
AU - Toro-Nahuelpan, Mauricio
AU - Fischer, Lena M
AU - Yu, Qin
AU - Sitarska, Ewa
AU - Chan, Chii Jou
AU - Kosinski, Jan
AU - Piel, Matthieu
AU - du Roure, Olivia
AU - Heuvingh, Julien
AU - Mahamid, Julia
AU - Diz-Muñoz, Alba
TI - The membrane-to-cortex distance regulates mDia1 activity to control cortical mechanics
T2 - Nature communications
J2 - Nat Commun
PY - 2026
DA - 2026/09/04
VL - 17
IS - 1
SP - 9501
SN - 2041-1723
PB - Nature Publishing Group
DO - 10.1038/s41467-026-72845-3
UR - https://doi.org/10.1038/s41467-026-72845-3
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41467-026-72845-3",
"type": "article-journal",
"title": "The membrane-to-cortex distance regulates mDia1 activity to control cortical mechanics",
"container-title": "Nature communications",
"author": [
{
"family": "Strauss",
"given": "Léanne"
},
{
"family": "Lembo",
"given": "Sergio"
},
{
"family": "Gérard",
"given": "Samuel F"
},
{
"family": "Siggel",
"given": "Marc"
},
{
"family": "Cheng",
"given": "Dorothy"
},
{
"family": "Bergert",
"given": "Martin"
},
{
"family": "Foster",
"given": "Sarah K"
},
{
"family": "Vermeil",
"given": "Joseph"
},
{
"family": "Toro-Nahuelpan",
"given": "Mauricio"
},
{
"family": "Fischer",
"given": "Lena M"
},
{
"family": "Yu",
"given": "Qin"
},
{
"family": "Sitarska",
"given": "Ewa"
},
{
"family": "Chan",
"given": "Chii Jou"
},
{
"family": "Kosinski",
"given": "Jan"
},
{
"family": "Piel",
"given": "Matthieu"
},
{
"family": "du Roure",
"given": "Olivia"
},
{
"family": "Heuvingh",
"given": "Julien"
},
{
"family": "Mahamid",
"given": "Julia"
},
{
"family": "Diz-Muñoz",
"given": "Alba"
}
],
"container-title-short": "Nat Commun",
"volume": "17",
"issue": "1",
"page": "9501",
"DOI": "10.1038/s41467-026-72845-3",
"PMID": "42697882",
"PMCID": "PMC13545285",
"ISSN": "2041-1723",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41467-026-72845-3",
"language": "en",
"issued": {
"date-parts": [
[
2026,
9,
4
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1126/sciadv.aeb3209 [code]
The actomyosin cortex controls t-tubule remodeling in skeletal muscle.
Journal: Science advances
In common: mouse, cellular / molecular, 9 references
[2] doi:10.1016/j.xcrm.2026.102766 [code]
A longitudinal single-cell and spatial multiomic atlas of pediatric high-grade glioma.
Journal: Cell reports. Medicine
In common: car, OpenCV, scikit-image, 8 other tools, cellular / molecular
[3] doi:10.1038/s42003-026-10957-8 [code]
Brain defence by the extracellular matrix protein Cochlin.
Journal: Communications biology
In common: OpenCV, scikit-image, ggpubr, 8 other tools, mouse, cellular / molecular
[4] doi:10.1016/j.nicl.2026.104012 [code]
Structural-functional multilayer brain network properties and outcome of combined repetitive transcranial magnetic stimulation and psychotherapy for obsessive-compulsive disorder.
Journal: NeuroImage. Clinical
In common: car, ggpubr, Image Processing Toolbox, 8 other tools
[5] doi:10.1093/braincomms/fcag176 [code]
Tau topography subtypes account for clinical heterogeneity and longitudinal trajectories in early-onset Alzheimer's disease.
Journal: Brain communications
In common: car, ggpubr, Image Processing Toolbox, 8 other tools
[6] doi:10.1093/nc/niag029 [code]
A data-driven approach to identifying and evaluating connectivity-based neural correlates of conscious visual perception.
Journal: Neuroscience of consciousness
In common: car, scikit-image, ggpubr, 8 other tools
[7] doi:10.1002/imt2.70163 [code]
Spatial multi-omics unveils sphingolipid metabolic reprogramming within the retinal pathological niche.
Journal: iMeta
In common: OpenCV, scikit-image, ggpubr, 7 other tools, mouse, cellular / molecular
[8] doi:10.1038/s41593-026-02376-z [code]
A framework for comparative analysis of human and mouse cortical neuron dendrites in corresponding brain regions.
Journal: Nature neuroscience
In common: OpenCV, Image Processing Toolbox, statsmodels, 7 other tools, mouse
[9] doi:10.1038/s41597-026-07350-9 [code]
An open multi-center MEG-EEG dataset for studying conscious visual perception.
Journal: Scientific data
In common: car, scikit-image, statsmodels, 7 other tools
[10] doi:10.1038/s41597-026-07377-y [code]
An open-access multi-site fMRI dataset for investigating conscious visual perception.
Journal: Scientific data
In common: car, scikit-image, statsmodels, 7 other tools

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.