{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "In a previous notebook https://github.com/AllenInstitute/aisynphys/blob/master/doc/connectivity_vs_distance.ipynb, we explored the distance dependenc on connectivity and how it can be modeled such that we can reliably compare connection probability among cells of different types probed at different distances. Here we extend that analysis to a number of other features in our dataset that are known to contribute to our ability to estimate the true, in vivo, connection probability. These factors fall into two main categories, those related to affects on neuronal processes due to the slicing procedure and our ability to detect small connections in noisy electrophysiological recordings.\n", "\n", "Multipatch slice electrophysiology is one of the best methods for indepth characterization of synaptic connections. However, a consistent criticism of slice physgiology is that measured connection probability (Cp) is a lower bounds of the true Cp due to severing of processes during slicing. We took multiple steps to reduce this liklihood in our dataset including the use of relatively thick slices (350um), targeting cells deep into the slice (at least 40um) and close together (typically 100um). We have additional measurements of axon and apical dendrite length before truncation from biocytin fills of recorded cells which we may use to estimage the affect on connection probability. \n", "\n", "It is also the case that electrophysiological recordings contain some amount of baseline noise. The level of this can be cell type dependent and may obscure very small responses unless we can average many many responses together, which is ultimately related to how long we record from the cells.\n", "\n", "This notebook will explore these data and the impact it might have on Cp." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First let's import a bunch of stuff we might need including the database which holds all of our data" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "18\n" ] } ], "source": [ "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "from scipy import stats\n", "from aisynphys.database import default_db as db\n", "from aisynphys.cell_class import CellClass, classify_cells, classify_pairs\n", "from aisynphys.connectivity import measure_connectivity, connectivity_profile, pair_was_probed, measure_distance, GaussianModel, LinearModel, ExpModel\n", "from aisynphys.ui.notebook import show_connectivity_profile, show_distance_binned_cp, show_connectivity_raster, show_connectivity_fit, set_distance_xticks\n", "print(db.schema_version)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Make excitatory and inhibitory cell class and pull out some pairs" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [], "source": [ "# select all excitatory / inhibitory pairs\n", "kwargs = {\n", " 'project_name': [\"mouse V1 coarse matrix\", \"mouse V1 pre-production\"],\n", "}\n", "ex_pairs = db.pair_query(pre_class=CellClass(cell_class_nonsynaptic='ex'), **kwargs).all()\n", "in_pairs = db.pair_query(pre_class=CellClass(cell_class_nonsynaptic='in'), **kwargs).all()\n", "\n", "# filter pairs on several criteria:\n", "def check_pair(p, syn_type):\n", " return (\n", " # must have been probed for connectivity\n", " pair_was_probed(p, syn_type) and\n", " # must have a true/false connection call\n", " p.has_synapse is not None and\n", " # intersomatic distance < 500 µm (removes some bad data with very large distances)\n", " p.distance is not None and \n", " p.distance < 500e-6\n", " )\n", "ex_pairs = [p for p in ex_pairs if check_pair(p, 'ex')]\n", "in_pairs = [p for p in in_pairs if check_pair(p, 'in')]\n", "all_pairs = np.concatenate([ex_pairs, in_pairs])\n", "\n", "# get intersomatic distances\n", "ex_dist = np.array([p.distance for p in ex_pairs])\n", "ex_lat_dist = np.array([p.lateral_distance for p in ex_pairs])\n", "in_dist = np.array([p.distance for p in in_pairs])\n", "in_lat_dist = np.array([p.lateral_distance for p in in_pairs])\n", "all_dist = np.concatenate([ex_dist, in_dist])\n", "all_lat_dist = np.concatenate([ex_lat_dist, in_lat_dist])\n", "\n", "# get connectivity\n", "ex_conn = np.array([p.has_synapse for p in ex_pairs], dtype=bool)\n", "in_conn = np.array([p.has_synapse for p in in_pairs], dtype=bool)\n", "all_conn = np.concatenate([ex_conn, in_conn])" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [], "source": [ "def pre_axon_length(pair):\n", " cell_morph = pair.pre_cell.morphology\n", " if cell_morph is None:\n", " return np.nan\n", " if cell_morph.axon_trunc_distance is not None:\n", " return cell_morph.axon_trunc_distance\n", " elif cell_morph.axon_truncation == 'intact':\n", " return 200e-6\n", " \n", "def avg_pair_depth(pair):\n", " if pair.pre_cell.depth is None or pair.post_cell.depth is None:\n", " return np.nan\n", " avg_depth = np.mean([pair.pre_cell.depth, pair.post_cell.depth])\n", " if avg_depth < 0 or avg_depth > 300e-6:\n", " return np.nan\n", " return avg_depth\n", "\n", "def n_test_spikes(pair):\n", " syn_type = pair.pre_cell.cell_class_nonsynaptic\n", " if syn_type not in ['ex', 'in']:\n", " return np.nan\n", " \n", " q = db.query(db.StimPulse.n_spikes)\n", " q = q.join(db.PulseResponse)\n", " q = q.filter(db.PulseResponse.pair_id==pair.id)\n", " q = q.join(db.PatchClampRecording, db.PatchClampRecording.recording_id==db.StimPulse.recording_id).join(db.MultiPatchProbe)\n", " \n", " q = q.filter(db.MultiPatchProbe.induction_frequency <= 50)\n", " q = q.filter(db.StimPulse.n_spikes==1)\n", " q = q.filter(db.StimPulse.first_spike_time is not None)\n", " \n", " if syn_type == 'ex':\n", " q = q.filter(db.PatchClampRecording.baseline_potential.between(-80e-3, -60e-3))\\\n", " .filter(db.PulseResponse.ex_qc_pass==True)\n", " elif syn_type == 'in':\n", " q = q.filter(db.PatchClampRecording.baseline_potential.between(-60e-3, -45e-3))\\\n", " .filter(db.PulseResponse.in_qc_pass==True)\n", "\n", " return(q.count()) \n", "\n", "def baseline_rms_noise(pair):\n", " post_cell = pair.post_cell\n", " q = db.query(db.PatchClampRecording)\n", " q = q.join(db.Recording).join(db.Electrode).join(db.Cell)\n", " q = q.filter(db.Cell.id==post_cell.id).filter(db.PatchClampRecording.clamp_mode=='ic')\n", " pcrs = q.all()\n", " pcr_noise = [pcr.baseline_rms_noise for pcr in pcrs if pcr.qc_pass]\n", " if len(pcr_noise) > 1:\n", " return np.mean(pcr_noise)\n", " else:\n", " return np.nan" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Calculate some metrics that we want to investigate with relation to connectivity" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "56.697656671206154\n" ] } ], "source": [ "import time\n", "# takes about an hour to run\n", "mouse_e_pairs = {'pairs': ex_pairs, 'distance': ex_dist, 'lateral_distance': ex_lat_dist, 'has_synapse': ex_conn}\n", "mouse_i_pairs = {'pairs': in_pairs, 'distance': in_dist, 'lateral_distance': in_lat_dist, 'has_synapse': in_conn}\n", "\n", "start = time.time()\n", "for pair_group in [mouse_e_pairs, mouse_i_pairs]:\n", " pairs = pair_group['pairs']\n", " pair_group['pre_axon_trunc_dist'] = [pre_axon_length(p) for p in pairs]\n", " pair_group['avg_pair_depth'] = [avg_pair_depth(p) for p in pairs]\n", " pair_group['n_test_spikes'] = [n_test_spikes(p) for p in pairs]\n", " pair_group['baseline_rms_noise'] = [baseline_rms_noise(p) for p in pairs]\n", "end = time.time()\n", "print((end-start)/60)" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [], "source": [ "mouse_pairs = {\n", " 'pairs': all_pairs, \n", " 'distance': all_dist, \n", " 'lateral_distance': all_lat_dist,\n", " 'has_synapse': all_conn,\n", " 'pre_axon_trunc_dist': np.concatenate([mouse_e_pairs['pre_axon_trunc_dist'], mouse_i_pairs['pre_axon_trunc_dist']]),\n", " 'avg_pair_depth': np.concatenate([mouse_e_pairs['avg_pair_depth'], mouse_i_pairs['avg_pair_depth']]), \n", " 'n_test_spikes': np.concatenate([mouse_e_pairs['n_test_spikes'], mouse_i_pairs['n_test_spikes']]),\n", " 'baseline_rms_noise': np.concatenate([mouse_e_pairs['baseline_rms_noise'], mouse_i_pairs['baseline_rms_noise']]),\n", "}\n", "\n", "mouse_e_pairs['lateral_distance'] = ex_lat_dist\n", "mouse_i_pairs['lateral_distance'] = in_lat_dist" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "19681\n" ] }, { "data": { "text/html": [ "
| \n", " | pairs | \n", "distance | \n", "lateral_distance | \n", "has_synapse | \n", "pre_axon_trunc_dist | \n", "avg_pair_depth | \n", "n_test_spikes | \n", "baseline_rms_noise | \n", "
|---|---|---|---|---|---|---|---|---|
| 0 | \n", "<Pair 1506537287.635 5 8> | \n", "0.000227 | \n", "0.000226 | \n", "False | \n", "NaN | \n", "0.000106 | \n", "912 | \n", "0.000245 | \n", "
| 1 | \n", "<Pair 1506537287.635 6 4> | \n", "0.000096 | \n", "0.000096 | \n", "False | \n", "0.0002 | \n", "0.000102 | \n", "1020 | \n", "0.000496 | \n", "
| 2 | \n", "<Pair 1506537287.635 6 5> | \n", "0.000115 | \n", "0.000113 | \n", "False | \n", "0.0002 | \n", "0.000110 | \n", "1020 | \n", "0.000603 | \n", "
| 3 | \n", "<Pair 1506537287.635 6 7> | \n", "0.000095 | \n", "0.000090 | \n", "True | \n", "0.0002 | \n", "0.000112 | \n", "996 | \n", "0.000231 | \n", "
| 4 | \n", "<Pair 1506537287.635 6 8> | \n", "0.000114 | \n", "0.000113 | \n", "False | \n", "0.0002 | \n", "0.000099 | \n", "1020 | \n", "0.000245 | \n", "