diff --git a/.gitignore b/.gitignore index 693c45d8e..2f3ddade0 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,5 @@ figures/ .vscode/ \.DS_Store + +visual_behavior/clustering/multiscope_fn/.... diff --git a/notebooks/200713_create_metrics_array_for_clustering.ipynb b/notebooks/200713_create_metrics_array_for_clustering.ipynb new file mode 100644 index 000000000..6a7d0b0de --- /dev/null +++ b/notebooks/200713_create_metrics_array_for_clustering.ipynb @@ -0,0 +1,3055 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "\n", + "import seaborn as sns\n", + "sns.set_context('notebook', font_scale=1.5, rc={'lines.markeredgewidth': 2})" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import visual_behavior.data_access.loading as loading\n", + "import visual_behavior.ophys.response_analysis.utilities as ut\n", + "from visual_behavior.ophys.response_analysis.response_analysis import ResponseAnalysis" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "experiments_table = loading.get_filtered_ophys_experiment_table() " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ophys_session_idbehavior_session_idcontainer_idproject_codecontainer_workflow_stateexperiment_workflow_statesession_namesession_typeequipment_namedate_of_acquisition...imaging_depthtargeted_structurepublished_atsuper_container_idcre_linesession_tagsfailure_tagsexposure_numbermodel_outputs_availablelocation
ophys_experiment_id
9536597459524308179525545481018028339VisualBehaviorMultiscopecompletedpassed20190923_457841_2imagesAOPHYS_2_images_A_passiveMESO.12019-09-23 08:13:07.627573...75VISpNaN850862430Sst-IRES-CreNaNz_drift_corr_um_diff,z_drift_corr_um_diff,z_dr...0FalseSst_VISp_75
9536597499524308179525545481018028354VisualBehaviorMultiscopecompletedpassed20190923_457841_2imagesAOPHYS_2_images_A_passiveMESO.12019-09-23 08:13:07.627573...150VISlNaN850862430Sst-IRES-CreNaNz_drift_corr_um_diff,z_drift_corr_um_diff,z_dr...0FalseSst_VISl_150
9536597529524308179525545481018028357VisualBehaviorMultiscopecompletedpassed20190923_457841_2imagesAOPHYS_2_images_A_passiveMESO.12019-09-23 08:13:07.627573...225VISlNaN850862430Sst-IRES-CreNaNz_drift_corr_um_diff,z_drift_corr_um_diff,z_dr...0FalseSst_VISl_225
9536597439524308179525545481018028345VisualBehaviorMultiscopecompletedpassed20190923_457841_2imagesAOPHYS_2_images_A_passiveMESO.12019-09-23 08:13:07.627573...225VISpNaN850862430Sst-IRES-CreNaNz_drift_corr_um_diff,z_drift_corr_um_diff,z_dr...0FalseSst_VISp_225
9585274749549544029539829601018028339VisualBehaviorMultiscopecompletedpassed20190924_457841_3imagesAOPHYS_3_images_AMESO.12019-09-24 16:00:00.000000...75VISpNaN850862430Sst-IRES-CreNaNNaN0TrueSst_VISp_75
\n", + "

5 rows × 27 columns

\n", + "
" + ], + "text/plain": [ + " ophys_session_id behavior_session_id container_id \\\n", + "ophys_experiment_id \n", + "953659745 952430817 952554548 1018028339 \n", + "953659749 952430817 952554548 1018028354 \n", + "953659752 952430817 952554548 1018028357 \n", + "953659743 952430817 952554548 1018028345 \n", + "958527474 954954402 953982960 1018028339 \n", + "\n", + " project_code container_workflow_state \\\n", + "ophys_experiment_id \n", + "953659745 VisualBehaviorMultiscope completed \n", + "953659749 VisualBehaviorMultiscope completed \n", + "953659752 VisualBehaviorMultiscope completed \n", + "953659743 VisualBehaviorMultiscope completed \n", + "958527474 VisualBehaviorMultiscope completed \n", + "\n", + " experiment_workflow_state session_name \\\n", + "ophys_experiment_id \n", + "953659745 passed 20190923_457841_2imagesA \n", + "953659749 passed 20190923_457841_2imagesA \n", + "953659752 passed 20190923_457841_2imagesA \n", + "953659743 passed 20190923_457841_2imagesA \n", + "958527474 passed 20190924_457841_3imagesA \n", + "\n", + " session_type equipment_name \\\n", + "ophys_experiment_id \n", + "953659745 OPHYS_2_images_A_passive MESO.1 \n", + "953659749 OPHYS_2_images_A_passive MESO.1 \n", + "953659752 OPHYS_2_images_A_passive MESO.1 \n", + "953659743 OPHYS_2_images_A_passive MESO.1 \n", + "958527474 OPHYS_3_images_A MESO.1 \n", + "\n", + " date_of_acquisition ... imaging_depth \\\n", + "ophys_experiment_id ... \n", + "953659745 2019-09-23 08:13:07.627573 ... 75 \n", + "953659749 2019-09-23 08:13:07.627573 ... 150 \n", + "953659752 2019-09-23 08:13:07.627573 ... 225 \n", + "953659743 2019-09-23 08:13:07.627573 ... 225 \n", + "958527474 2019-09-24 16:00:00.000000 ... 75 \n", + "\n", + " targeted_structure published_at super_container_id \\\n", + "ophys_experiment_id \n", + "953659745 VISp NaN 850862430 \n", + "953659749 VISl NaN 850862430 \n", + "953659752 VISl NaN 850862430 \n", + "953659743 VISp NaN 850862430 \n", + "958527474 VISp NaN 850862430 \n", + "\n", + " cre_line session_tags \\\n", + "ophys_experiment_id \n", + "953659745 Sst-IRES-Cre NaN \n", + "953659749 Sst-IRES-Cre NaN \n", + "953659752 Sst-IRES-Cre NaN \n", + "953659743 Sst-IRES-Cre NaN \n", + "958527474 Sst-IRES-Cre NaN \n", + "\n", + " failure_tags \\\n", + "ophys_experiment_id \n", + "953659745 z_drift_corr_um_diff,z_drift_corr_um_diff,z_dr... \n", + "953659749 z_drift_corr_um_diff,z_drift_corr_um_diff,z_dr... \n", + "953659752 z_drift_corr_um_diff,z_drift_corr_um_diff,z_dr... \n", + "953659743 z_drift_corr_um_diff,z_drift_corr_um_diff,z_dr... \n", + "958527474 NaN \n", + "\n", + " exposure_number model_outputs_available location \n", + "ophys_experiment_id \n", + "953659745 0 False Sst_VISp_75 \n", + "953659749 0 False Sst_VISl_150 \n", + "953659752 0 False Sst_VISl_225 \n", + "953659743 0 False Sst_VISp_225 \n", + "958527474 0 True Sst_VISp_75 \n", + "\n", + "[5 rows x 27 columns]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "experiments_table.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ophys_session_id 882386411\n", + "behavior_session_id 882446265\n", + "container_id 1018027561\n", + "project_code VisualBehaviorMultiscope\n", + "container_workflow_state completed\n", + "experiment_workflow_state passed\n", + "session_name 20190606_451787_3imagesA_2\n", + "session_type OPHYS_3_images_A\n", + "equipment_name MESO.1\n", + "date_of_acquisition 2019-06-06 13:37:46.000000\n", + "isi_experiment_id 846136902\n", + "specimen_id 837581585\n", + "sex M\n", + "age_in_days 127\n", + "full_genotype Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-G...\n", + "reporter_line ['Ai93(TITL-GCaMP6f)']\n", + "driver_line ['Camk2a-tTA', 'Slc17a7-IRES2-Cre']\n", + "imaging_depth 225\n", + "targeted_structure VISl\n", + "published_at NaN\n", + "super_container_id 837581585\n", + "cre_line Slc17a7-IRES2-Cre\n", + "session_tags NaN\n", + "failure_tags NaN\n", + "exposure_number 0\n", + "model_outputs_available True\n", + "location Slc17a7_VISl_225\n", + "Name: 882551962, dtype: object" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arbitrary_index = 650\n", + "experiments_table.iloc[arbitrary_index]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### get metrics for one experiment " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "ophys_experiment_id = experiments_table.index.values[arbitrary_index]\n", + "\n", + "dataset = loading.get_ophys_dataset(ophys_experiment_id)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + } + ], + "source": [ + "analysis = ResponseAnalysis(dataset) " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n" + ] + } + ], + "source": [ + "sdf = analysis.get_response_df(df_name='stimulus_response_df')\n", + "tdf = analysis.get_response_df(df_name='trials_response_df')" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "msdf = ut.get_mean_df(sdf, conditions=['cell_specimen_id', 'omitted', 'image_name'], flashes=True)\n", + "mtdf = ut.get_mean_df(tdf, conditions=['cell_specimen_id', 'go', 'change_image_name'])\n", + "\n", + "# pooled images and image changes\n", + "msdf_p = ut.get_mean_df(sdf, conditions=['cell_specimen_id', 'omitted'], flashes=True)\n", + "mtdf_p = ut.get_mean_df(tdf, conditions=['cell_specimen_id', 'go'])" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + } + ], + "source": [ + "session_type = dataset.metadata['session_type']" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "df_list = []\n", + "for cell_specimen_id in msdf.cell_specimen_id.unique():\n", + " \n", + " cdf = msdf[msdf.cell_specimen_id==cell_specimen_id]\n", + " for omitted in cdf.omitted.unique():\n", + " if omitted: \n", + " condition = 'omitted_post'\n", + " mean_response = cdf[cdf.omitted==True].mean_response.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " \n", + " condition = 'omitted_pre'\n", + " mean_response = cdf[cdf.omitted==True].mean_baseline.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " else: \n", + " for i, image_name in enumerate(cdf.image_name.unique()): \n", + " if 'images_B' in session_type: \n", + " i = i+8\n", + " condition = 'im'+str(i)+'_post'\n", + " mean_response = cdf[cdf.image_name==image_name].mean_response.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " condition = 'im'+str(i)+'_pre'\n", + " mean_response = cdf[cdf.image_name==image_name].mean_baseline.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " \n", + " \n", + " cdf = mtdf[mtdf.cell_specimen_id==cell_specimen_id]\n", + " cdf = cdf[cdf.go]\n", + " for i, change_image_name in enumerate(cdf.change_image_name.unique()): \n", + " if 'images_B' in session_type: \n", + " i = i+8\n", + " condition = 'change_im'+str(i)+'_post'\n", + " mean_response = cdf[cdf.change_image_name==change_image_name].mean_response.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " \n", + " condition = 'change_im'+str(i)+'_pre'\n", + " mean_response = cdf[cdf.change_image_name==change_image_name].mean_baseline.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " \n", + " \n", + " # pooled images \n", + " cdf = msdf_p[msdf_p.cell_specimen_id==cell_specimen_id]\n", + " cdf = cdf[cdf.omitted]\n", + "\n", + " condition = 'im_pooled_post'\n", + " mean_response = cdf.mean_response.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + "\n", + " condition = 'im_pooled_pre'\n", + " mean_response = cdf.mean_baseline.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " \n", + " # pooled image changes\n", + " cdf = mtdf_p[mtdf_p.cell_specimen_id==cell_specimen_id]\n", + " cdf = cdf[cdf.go]\n", + " \n", + " condition = 'change_im_pooled_post'\n", + " mean_response = cdf.mean_response.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + "\n", + " condition = 'change_im_pooled_pre'\n", + " mean_response = cdf.mean_baseline.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "metrics_df = pd.DataFrame(data=df_list, columns=['cell_specimen_id','condition','mean_response'])" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "metrics_df = metrics_df.set_index(['cell_specimen_id', 'condition'])" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
mean_response
cell_specimen_idcondition
1028768480im0_post0.000419
im0_pre-0.002450
im1_post-0.000753
im1_pre-0.000518
im2_post0.001859
.........
1028772542change_im7_pre0.017372
im_pooled_post-0.004091
im_pooled_pre-0.006202
change_im_pooled_post0.024975
change_im_pooled_pre0.010802
\n", + "

2120 rows × 1 columns

\n", + "
" + ], + "text/plain": [ + " mean_response\n", + "cell_specimen_id condition \n", + "1028768480 im0_post 0.000419\n", + " im0_pre -0.002450\n", + " im1_post -0.000753\n", + " im1_pre -0.000518\n", + " im2_post 0.001859\n", + "... ...\n", + "1028772542 change_im7_pre 0.017372\n", + " im_pooled_post -0.004091\n", + " im_pooled_pre -0.006202\n", + " change_im_pooled_post 0.024975\n", + " change_im_pooled_pre 0.010802\n", + "\n", + "[2120 rows x 1 columns]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "metrics_df" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "unstacked_metrics = metrics_df.unstack(level=-1)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
mean_response
conditionchange_im0_postchange_im0_prechange_im1_postchange_im1_prechange_im2_postchange_im2_prechange_im3_postchange_im3_prechange_im4_postchange_im4_pre...im6_postim6_preim7_postim7_preim8_postim8_preim_pooled_postim_pooled_preomitted_postomitted_pre
cell_specimen_id
1028768480-0.0025080.0108850.0007330.015663-0.003659-0.0023800.0109270.0286080.092709-0.055401...0.001369-0.0009370.004199-0.000932-0.007145-0.003984-0.007145-0.003984-0.007145-0.003984
10287686070.0097320.0174730.0048400.0179560.0126030.0098410.0196040.0222470.0377410.033929...0.0381020.0235320.0009670.0018510.0177120.0071600.0177120.0071600.0177120.007160
10287686260.0354140.0139180.0266190.0198310.011897-0.0025310.0196220.0054380.0231110.050005...0.0037140.0033450.0015450.0022290.0046500.0054210.0046500.0054210.0046500.005421
10287687160.0329510.0003790.004358-0.0029340.013827-0.0044450.0139710.0148480.016971-0.006414...0.0039770.0015640.0051080.0005220.004696-0.0035330.004696-0.0035330.004696-0.003533
10287688710.0123400.0071200.0158250.0033350.021601-0.0084250.0175510.0036600.0155350.006574...0.002560-0.0011400.0033150.000880-0.000052-0.003911-0.000052-0.003911-0.000052-0.003911
\n", + "

5 rows × 40 columns

\n", + "
" + ], + "text/plain": [ + " mean_response \\\n", + "condition change_im0_post change_im0_pre change_im1_post \n", + "cell_specimen_id \n", + "1028768480 -0.002508 0.010885 0.000733 \n", + "1028768607 0.009732 0.017473 0.004840 \n", + "1028768626 0.035414 0.013918 0.026619 \n", + "1028768716 0.032951 0.000379 0.004358 \n", + "1028768871 0.012340 0.007120 0.015825 \n", + "\n", + " \\\n", + "condition change_im1_pre change_im2_post change_im2_pre \n", + "cell_specimen_id \n", + "1028768480 0.015663 -0.003659 -0.002380 \n", + "1028768607 0.017956 0.012603 0.009841 \n", + "1028768626 0.019831 0.011897 -0.002531 \n", + "1028768716 -0.002934 0.013827 -0.004445 \n", + "1028768871 0.003335 0.021601 -0.008425 \n", + "\n", + " \\\n", + "condition change_im3_post change_im3_pre change_im4_post \n", + "cell_specimen_id \n", + "1028768480 0.010927 0.028608 0.092709 \n", + "1028768607 0.019604 0.022247 0.037741 \n", + "1028768626 0.019622 0.005438 0.023111 \n", + "1028768716 0.013971 0.014848 0.016971 \n", + "1028768871 0.017551 0.003660 0.015535 \n", + "\n", + " ... \\\n", + "condition change_im4_pre ... im6_post im6_pre im7_post im7_pre \n", + "cell_specimen_id ... \n", + "1028768480 -0.055401 ... 0.001369 -0.000937 0.004199 -0.000932 \n", + "1028768607 0.033929 ... 0.038102 0.023532 0.000967 0.001851 \n", + "1028768626 0.050005 ... 0.003714 0.003345 0.001545 0.002229 \n", + "1028768716 -0.006414 ... 0.003977 0.001564 0.005108 0.000522 \n", + "1028768871 0.006574 ... 0.002560 -0.001140 0.003315 0.000880 \n", + "\n", + " \\\n", + "condition im8_post im8_pre im_pooled_post im_pooled_pre \n", + "cell_specimen_id \n", + "1028768480 -0.007145 -0.003984 -0.007145 -0.003984 \n", + "1028768607 0.017712 0.007160 0.017712 0.007160 \n", + "1028768626 0.004650 0.005421 0.004650 0.005421 \n", + "1028768716 0.004696 -0.003533 0.004696 -0.003533 \n", + "1028768871 -0.000052 -0.003911 -0.000052 -0.003911 \n", + "\n", + " \n", + "condition omitted_post omitted_pre \n", + "cell_specimen_id \n", + "1028768480 -0.007145 -0.003984 \n", + "1028768607 0.017712 0.007160 \n", + "1028768626 0.004650 0.005421 \n", + "1028768716 0.004696 -0.003533 \n", + "1028768871 -0.000052 -0.003911 \n", + "\n", + "[5 rows x 40 columns]" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "unstacked_metrics.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(53, 40)" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "metrics_array = unstacked_metrics.values\n", + "metrics_array.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### for a bunch of experiments" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "def get_metrics_df(mean_stim_df, mean_trials_df, mean_stim_pooled_df, mean_trials_pooled_df, session_type, experiment_id, session_id): \n", + " msdf = mean_stim_df.copy()\n", + " mtdf = mean_trials_df.copy()\n", + " msdf_p = mean_stim_pooled_df.copy()\n", + " mtdf_p = mean_trials_pooled_df.copy()\n", + " \n", + " df_list = []\n", + " for cell_specimen_id in msdf.cell_specimen_id.unique():\n", + " cdf = msdf[msdf.cell_specimen_id==cell_specimen_id]\n", + " for omitted in cdf.omitted.unique():\n", + " if omitted: \n", + " condition = 'omitted_post'\n", + " mean_response = cdf[cdf.omitted==True].mean_response.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " \n", + " condition = 'omitted_pre'\n", + " mean_response = cdf[cdf.omitted==True].mean_baseline.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " else: \n", + " for i, image_name in enumerate(cdf.image_name.unique()): \n", + " if 'images_B' in session_type: \n", + " i = i+8\n", + " condition = 'im'+str(i)+'_post'\n", + " mean_response = cdf[cdf.image_name==image_name].mean_response.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " \n", + " condition = 'im'+str(i)+'_pre'\n", + " mean_response = cdf[cdf.image_name==image_name].mean_baseline.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " \n", + " \n", + " cdf = mtdf[mtdf.cell_specimen_id==cell_specimen_id]\n", + " cdf = cdf[cdf.go]\n", + " for i, change_image_name in enumerate(cdf.change_image_name.unique()): \n", + " if 'images_B' in session_type: \n", + " i = i+8\n", + " condition = 'change_im'+str(i)+'_post'\n", + " mean_response = cdf[cdf.change_image_name==change_image_name].mean_response.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " \n", + " condition = 'change_im'+str(i)+'_pre'\n", + " mean_response = cdf[cdf.change_image_name==change_image_name].mean_baseline.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + " \n", + " \n", + " # pooled images \n", + " cdf = msdf_p[msdf_p.cell_specimen_id==cell_specimen_id]\n", + " cdf = cdf[cdf.omitted]\n", + "\n", + " condition = 'im_pooled_post'\n", + " mean_response = cdf.mean_response.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + "\n", + " condition = 'im_pooled_pre'\n", + " mean_response = cdf.mean_baseline.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + "\n", + "\n", + " # pooled image changes\n", + " cdf = mtdf_p[mtdf_p.cell_specimen_id==cell_specimen_id]\n", + " cdf = cdf[cdf.go]\n", + "\n", + " condition = 'change_im_pooled_post'\n", + " mean_response = cdf.mean_response.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + "\n", + " condition = 'change_im_pooled_pre'\n", + " mean_response = cdf.mean_baseline.values[0]\n", + " df_list.append([cell_specimen_id, condition, mean_response])\n", + "\n", + "\n", + " metrics_df = pd.DataFrame(data=df_list, columns=['cell_specimen_id','condition','mean_response'])\n", + " metrics_df['experiment_id'] = experiment_id\n", + " metrics_df['session_id'] = session_id\n", + " \n", + " return metrics_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Experiment 1 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "problem for 945586450\n", + "Experiment 2 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "problem for 945586458\n", + "Experiment 3 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "problem for 945586456\n", + "Experiment 4 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "problem for 945586454\n", + "Experiment 5 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "problem for 945586452\n", + "Experiment 6 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "problem for 945586448\n", + "Experiment 7 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "problem for 945586446\n", + "Experiment 8 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "problem for 945586444\n", + "Experiment 9 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n", + "Experiment 10 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "must provide analysis object to get_mean_df to compute reliability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n", + "Experiment 11 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n", + "Experiment 12 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n", + "Experiment 13 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n", + "Experiment 14 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n", + "Experiment 15 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n", + "Experiment 16 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.sync.process_sync:Sync photodiode error needs to be fixed. Using assumed monitor delay: 0.0351\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n", + "Experiment 17 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n", + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n", + "Experiment 18 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n", + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability\n", + "must provide analysis object to get_mean_df to compute reliability" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "must provide analysis object to get_mean_df to compute reliability\n", + "resampling mesoscope 2P frame times\n", + "Experiment 19 / 750\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "C:\\Users\\marinag\\Documents\\Code\\AllenSDK\\allensdk\\brain_observatory\\sync_dataset.py:109: UserWarning: The loaded sync file contains the following deprecated line label keys: {'cam2_exposure', 'cam1_exposure'}. Consider updating the sync file line labels.\n", + " self._check_line_labels()\n", + "WARNING:root:Could not find valid lines for the following data sources\n", + "WARNING:root:acquiring (valid line label(s) = ['2p_acquiring']\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n", + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen driver line: can't adapt type 'numpy.int64'\n", + "ERROR:visual_behavior.ophys.io.lims_database:cannot query specimen reporter line: can't adapt type 'numpy.int64'\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "resampling mesoscope 2P frame times\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame.\n", + "Try using .loc[row_indexer,col_indexer] = value instead\n", + "\n", + "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " self.obj[item] = s\n" + ] + } + ], + "source": [ + "# ophys_experiment_ids = experiments_table[experiments_table.project_code=='VisualBehaviorMultiscope'].index.values\n", + "# print(ophys_experiment_ids.shape)\n", + "\n", + "# multi_session_metrics_df = pd.DataFrame()\n", + "\n", + "count = 0\n", + "for ophys_experiment_id in ophys_experiment_ids[165:]:\n", + " try: \n", + " count = count+1\n", + " print(f'Experiment {count} / {len(ophys_experiment_ids)}')\n", + " session_id = experiments_table[experiments_table.index.values==ophys_experiment_id].iloc[0]['ophys_session_id']\n", + "\n", + " dataset = loading.get_ophys_dataset(ophys_experiment_id)\n", + "\n", + " analysis = ResponseAnalysis(dataset)\n", + "\n", + " sdf = analysis.get_response_df(df_name='stimulus_response_df')\n", + " tdf = analysis.get_response_df(df_name='trials_response_df')\n", + "\n", + " mean_stim_df = ut.get_mean_df(sdf, conditions=['cell_specimen_id', 'omitted', 'image_name'], flashes=True)\n", + " mean_trials_df = ut.get_mean_df(tdf, conditions=['cell_specimen_id', 'go', 'change_image_name'])\n", + " # pooled images and image changes\n", + " mean_stim_pooled_df = ut.get_mean_df(sdf, conditions=['cell_specimen_id', 'omitted'], flashes=True)\n", + " mean_trials_pooled_df = ut.get_mean_df(tdf, conditions=['cell_specimen_id', 'go'])\n", + "\n", + " session_type = dataset.metadata['session_type']\n", + " experiment_id = dataset.ophys_experiment_id\n", + "\n", + " metrics_df = get_metrics_df(mean_stim_df, mean_trials_df, mean_stim_pooled_df, mean_trials_pooled_df, session_type, experiment_id, session_id)\n", + "\n", + " multi_session_metrics_df = pd.concat([multi_session_metrics_df, metrics_df])\n", + " except: \n", + " print('problem for',ophys_experiment_id)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# problem experiment 945586450 - from a mesoscope session so need to get the other 7 experiments too" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "len(multi_session_metrics.experiment_id.unique())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "multi_session_metrics_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## unstack to make metrics columns, then be able to extract the metrics as an array\n", + "multi_session_metrics_df = multi_session_metrics_df.set_index(['cell_specimen_id', 'experiment_id', 'session_id', 'condition'])\n", + "unstacked_metrics = multi_session_metrics_df.unstack(level=-1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "unstacked_metrics.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# get rid of unecessary 'mean_response' column multi-index and set rows multi-index to columns with reset_index\n", + "unstacked_metrics = unstacked_metrics.droplevel(axis=1, level=0).reset_index()\n", + "unstacked_metrics.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# merge unstacked_metrics with metadata from experiments_table\n", + "expts = experiments_table.reset_index().rename(columns={'ophys_experiment_id':'experiment_id'})\n", + "unstacked_metrics = unstacked_metrics.merge(expts, on='experiment_id')\n", + "unstacked_metrics.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### save data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# there is an easy function to get the default path for the 'visual_behavior_production_analysis' folder:\n", + "# loading.get_analysis_cache_dir()\n", + "\n", + "multi_session_metrics_df.to_hdf(os.path.join(loading.get_analysis_cache_dir(), 'multi_session_summary_dfs', 'response_metrics_feature_matrix.h5'), key='df')\n", + "\n", + "unstacked_metrics.to_hdf(os.path.join(loading.get_analysis_cache_dir(), 'multi_session_summary_dfs', 'response_metrics_feature_matrix_unstacked.h5'), key='df')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### load previously saved data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# there is an easy function to get the default path for the 'visual_behavior_production_analysis' folder:\n", + "# loading.get_analysis_cache_dir()\n", + "\n", + "multi_session_metrics_df = pd.read_hdf(os.path.join(loading.get_analysis_cache_dir(), 'multi_session_summary_dfs', 'response_metrics_feature_matrix.h5'), key='df')\n", + "\n", + "unstacked_metrics = pd.read_hdf(os.path.join(loading.get_analysis_cache_dir(), 'multi_session_summary_dfs', 'response_metrics_feature_matrix_unstacked.h5'), key='df')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### get the metrics array without all the metadata columns " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### i assume this array is what goes into PCA or UMAP" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "metrics_array = unstacked_metrics.drop(columns=experiments_table.columns)\n", + "metrics_array = metrics_array.set_index(['cell_specimen_id','experiment_id','session_id'])\n", + "metrics_array.values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### to get just the metadata columns (corresponding to the rows in metrics_array)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### can then use this metadata to label points in umap or split by cre line, etc" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "expts = experiments_table.reset_index().rename(columns={'ophys_experiment_id':'experiment_id'})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "metadata_df = metrics_array.reset_index()[['cell_specimen_id','experiment_id','session_id']]\n", + "metadata_df = metadata_df.merge(expts, on='experiment_id')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "metadata_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/notebooks/200928_get_data_for_decoding.ipynb b/notebooks/200928_get_data_for_decoding.ipynb index b686b3623..e515eaa62 100644 --- a/notebooks/200928_get_data_for_decoding.ipynb +++ b/notebooks/200928_get_data_for_decoding.ipynb @@ -80,7 +80,16 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# experiments_table.reset_index(inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, "metadata": { "scrolled": true }, @@ -91,7 +100,8 @@ "text": [ "problem for VisualBehaviorMultiscope Slc17a7-IRES2-Cre 4\n", "Attribute 'block1_items_variety' does not exist in node: '/df'\n", - "Wall time: 1min 13s\n" + "CPU times: user 26.2 s, sys: 12.4 s, total: 38.6 s\n", + "Wall time: 1min 22s\n" ] } ], @@ -112,7 +122,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -132,7 +142,7 @@ " dtype='object')" ] }, - "execution_count": 9, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -144,7 +154,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -152,13 +162,14 @@ "text/plain": [ "Index(['ophys_session_id', 'stimulus_presentations_id', 'image_index',\n", " 'image_name', 'image_name_next_flash', 'image_index_next_flash',\n", - " 'omitted', 'change', 'pre_change', 'mean_running_speed', 'licked',\n", - " 'rewarded', 'reward_rate', 'hit_fraction', 'engagement_state',\n", + " 'image_name_previous_flash', 'image_index_previous_flash', 'omitted',\n", + " 'change', 'pre_change', 'mean_running_speed', 'licked', 'rewarded',\n", + " 'reward_rate', 'hit_fraction', 'engagement_state',\n", " 'lick_on_next_flash'],\n", " dtype='object')" ] }, - "execution_count": 10, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -170,7 +181,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ @@ -188,6 +199,35 @@ "cell_type": "code", "execution_count": 15, "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "((13,), (13,))" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "session_data.iloc[0]['trace_timestamps'].shape, session_data.iloc[0]['trace'].shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#image_index --> [0, .25]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, "outputs": [ { "data": { @@ -235,7 +275,7 @@ " \n", " \n", " \n", - " 1429311\n", + " 1429311\n", " 935514366\n", " 933439847\n", " 0\n", @@ -259,7 +299,7 @@ " 4\n", " \n", " \n", - " 1429312\n", + " 1429312\n", " 935514366\n", " 933439847\n", " 0\n", @@ -283,7 +323,7 @@ " 4\n", " \n", " \n", - " 1429313\n", + " 1429313\n", " 935514366\n", " 933439847\n", " 0\n", @@ -307,7 +347,7 @@ " 4\n", " \n", " \n", - " 1429314\n", + " 1429314\n", " 935514366\n", " 933439847\n", " 0\n", @@ -331,7 +371,7 @@ " 4\n", " \n", " \n", - " 1429315\n", + " 1429315\n", " 935514366\n", " 933439847\n", " 0\n", @@ -354,9 +394,153 @@ " True\n", " 4\n", " \n", + " \n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + " \n", + " \n", + " 2172686\n", + " 935514364\n", + " 933439847\n", + " 4793\n", + " 1028826336\n", + " [-0.04203548048280133, 0.00865223382310488, 0....\n", + " [-0.4661836057592707, -0.3729468846074166, -0....\n", + " 0.000778\n", + " -0.011421\n", + " 10.73\n", + " 933504759\n", + " ...\n", + " NaN\n", + " 840355567\n", + " Vip-IRES-Cre\n", + " NaN\n", + " NaN\n", + " 0\n", + " True\n", + " Vip_VISp_302\n", + " False\n", + " 4\n", + " \n", + " \n", + " 2172687\n", + " 935514364\n", + " 933439847\n", + " 4794\n", + " 1028826306\n", + " [0.008957387258731485, -0.0078002063182496875,...\n", + " [-0.4661836057592707, -0.3729468846074166, -0....\n", + " -0.052871\n", + " -0.045847\n", + " 10.73\n", + " 933504759\n", + " ...\n", + " NaN\n", + " 840355567\n", + " Vip-IRES-Cre\n", + " NaN\n", + " NaN\n", + " 0\n", + " True\n", + " Vip_VISp_302\n", + " False\n", + " 4\n", + " \n", + " \n", + " 2172688\n", + " 935514364\n", + " 933439847\n", + " 4794\n", + " 1028826336\n", + " [-0.09607093690166217, 0.13266915997263648, 0....\n", + " [-0.4661836057592707, -0.3729468846074166, -0....\n", + " 0.112905\n", + " 0.117679\n", + " 10.73\n", + " 933504759\n", + " ...\n", + " NaN\n", + " 840355567\n", + " Vip-IRES-Cre\n", + " NaN\n", + " NaN\n", + " 0\n", + " True\n", + " Vip_VISp_302\n", + " False\n", + " 4\n", + " \n", + " \n", + " 2172689\n", + " 935514364\n", + " 933439847\n", + " 4795\n", + " 1028826306\n", + " [-0.03298763997876436, -0.09288862486973551, -...\n", + " [-0.4661836057592707, -0.3729468846074166, -0....\n", + " -0.031667\n", + " -0.059583\n", + " 10.73\n", + " 933504759\n", + " ...\n", + " NaN\n", + " 840355567\n", + " Vip-IRES-Cre\n", + " NaN\n", + " NaN\n", + " 0\n", + " True\n", + " Vip_VISp_302\n", + " False\n", + " 4\n", + " \n", + " \n", + " 2172690\n", + " 935514364\n", + " 933439847\n", + " 4795\n", + " 1028826336\n", + " [0.11794579926653898, 0.2174981477115695, 0.07...\n", + " [-0.4661836057592707, -0.3729468846074166, -0....\n", + " 0.005729\n", + " 0.020169\n", + " 10.73\n", + " 933504759\n", + " ...\n", + " NaN\n", + " 840355567\n", + " Vip-IRES-Cre\n", + " NaN\n", + " NaN\n", + " 0\n", + " True\n", + " Vip_VISp_302\n", + " False\n", + " 4\n", + " \n", " \n", "\n", - "

5 rows × 37 columns

\n", + "

743380 rows × 37 columns

\n", "" ], "text/plain": [ @@ -366,6 +550,12 @@ "1429313 935514366 933439847 0 \n", "1429314 935514366 933439847 0 \n", "1429315 935514366 933439847 0 \n", + "... ... ... ... \n", + "2172686 935514364 933439847 4793 \n", + "2172687 935514364 933439847 4794 \n", + "2172688 935514364 933439847 4794 \n", + "2172689 935514364 933439847 4795 \n", + "2172690 935514364 933439847 4795 \n", "\n", " cell_specimen_id trace \\\n", "1429311 1028832095 [-0.17192417690638828, -0.10087936870557397, -... \n", @@ -373,6 +563,12 @@ "1429313 1028831625 [0.06380861310592205, -0.04206825108114767, 0.... \n", "1429314 1028832772 [-0.019588022839854006, -0.10852957256893847, ... \n", "1429315 1028832779 [-0.11147707535109455, 0.04882343961900136, -0... \n", + "... ... ... \n", + "2172686 1028826336 [-0.04203548048280133, 0.00865223382310488, 0.... \n", + "2172687 1028826306 [0.008957387258731485, -0.0078002063182496875,... \n", + "2172688 1028826336 [-0.09607093690166217, 0.13266915997263648, 0.... \n", + "2172689 1028826306 [-0.03298763997876436, -0.09288862486973551, -... \n", + "2172690 1028826336 [0.11794579926653898, 0.2174981477115695, 0.07... \n", "\n", " trace_timestamps mean_response \\\n", "1429311 [-0.4661836057592707, -0.3729468846074166, -0.... 0.079789 \n", @@ -380,6 +576,12 @@ "1429313 [-0.4661836057592707, -0.3729468846074166, -0.... 0.062733 \n", "1429314 [-0.4661836057592707, -0.3729468846074166, -0.... 0.024200 \n", "1429315 [-0.4661836057592707, -0.3729468846074166, -0.... 0.009895 \n", + "... ... ... \n", + "2172686 [-0.4661836057592707, -0.3729468846074166, -0.... 0.000778 \n", + "2172687 [-0.4661836057592707, -0.3729468846074166, -0.... -0.052871 \n", + "2172688 [-0.4661836057592707, -0.3729468846074166, -0.... 0.112905 \n", + "2172689 [-0.4661836057592707, -0.3729468846074166, -0.... -0.031667 \n", + "2172690 [-0.4661836057592707, -0.3729468846074166, -0.... 0.005729 \n", "\n", " baseline_response ophys_frame_rate behavior_session_id ... \\\n", "1429311 -0.017712 10.73 933504759 ... \n", @@ -387,6 +589,12 @@ "1429313 0.000480 10.73 933504759 ... \n", "1429314 0.003009 10.73 933504759 ... \n", "1429315 -0.067906 10.73 933504759 ... \n", + "... ... ... ... ... \n", + "2172686 -0.011421 10.73 933504759 ... \n", + "2172687 -0.045847 10.73 933504759 ... \n", + "2172688 0.117679 10.73 933504759 ... \n", + "2172689 -0.059583 10.73 933504759 ... \n", + "2172690 0.020169 10.73 933504759 ... \n", "\n", " published_at super_container_id cre_line session_tags \\\n", "1429311 NaN 840355567 Vip-IRES-Cre NaN \n", @@ -394,13 +602,25 @@ "1429313 NaN 840355567 Vip-IRES-Cre NaN \n", "1429314 NaN 840355567 Vip-IRES-Cre NaN \n", "1429315 NaN 840355567 Vip-IRES-Cre NaN \n", + "... ... ... ... ... \n", + "2172686 NaN 840355567 Vip-IRES-Cre NaN \n", + "2172687 NaN 840355567 Vip-IRES-Cre NaN \n", + "2172688 NaN 840355567 Vip-IRES-Cre NaN \n", + "2172689 NaN 840355567 Vip-IRES-Cre NaN \n", + "2172690 NaN 840355567 Vip-IRES-Cre NaN \n", "\n", - " failure_tags exposure_number model_outputs_available location \\\n", - "1429311 NaN 0 True Vip_VISp_71 \n", - "1429312 NaN 0 True Vip_VISp_71 \n", - "1429313 NaN 0 True Vip_VISp_71 \n", - "1429314 NaN 0 True Vip_VISp_71 \n", - "1429315 NaN 0 True Vip_VISp_71 \n", + " failure_tags exposure_number model_outputs_available location \\\n", + "1429311 NaN 0 True Vip_VISp_71 \n", + "1429312 NaN 0 True Vip_VISp_71 \n", + "1429313 NaN 0 True Vip_VISp_71 \n", + "1429314 NaN 0 True Vip_VISp_71 \n", + "1429315 NaN 0 True Vip_VISp_71 \n", + "... ... ... ... ... \n", + "2172686 NaN 0 True Vip_VISp_302 \n", + "2172687 NaN 0 True Vip_VISp_302 \n", + "2172688 NaN 0 True Vip_VISp_302 \n", + "2172689 NaN 0 True Vip_VISp_302 \n", + "2172690 NaN 0 True Vip_VISp_302 \n", "\n", " has_events session_number \n", "1429311 True 4 \n", @@ -408,200 +628,32 @@ "1429313 True 4 \n", "1429314 True 4 \n", "1429315 True 4 \n", + "... ... ... \n", + "2172686 False 4 \n", + "2172687 False 4 \n", + "2172688 False 4 \n", + "2172689 False 4 \n", + "2172690 False 4 \n", "\n", - "[5 rows x 37 columns]" + "[743380 rows x 37 columns]" ] }, - "execution_count": 15, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "session_data.head()" + "session_data" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
ophys_session_idstimulus_presentations_idimage_indeximage_nameimage_name_next_flashimage_index_next_flashomittedchangepre_changemean_running_speedlickedrewardedreward_ratehit_fractionengagement_statelick_on_next_flash
093343984700im000im0000.0FalseFalseFalse1.6256961FalseNoneNoneNoneNone
193343984710im000im0000.0FalseFalseFalse2.2252130FalseNoneNoneNoneNone
293343984720im000im0000.0FalseFalseFalse5.0248910FalseNoneNoneNoneNone
393343984730im000im0000.0FalseFalseFalse4.0807980FalseNoneNoneNoneNone
493343984740im000im0000.0FalseFalseFalse2.0530801FalseNoneNoneNoneNone
\n", - "
" - ], - "text/plain": [ - " ophys_session_id stimulus_presentations_id image_index image_name \\\n", - "0 933439847 0 0 im000 \n", - "1 933439847 1 0 im000 \n", - "2 933439847 2 0 im000 \n", - "3 933439847 3 0 im000 \n", - "4 933439847 4 0 im000 \n", - "\n", - " image_name_next_flash image_index_next_flash omitted change pre_change \\\n", - "0 im000 0.0 False False False \n", - "1 im000 0.0 False False False \n", - "2 im000 0.0 False False False \n", - "3 im000 0.0 False False False \n", - "4 im000 0.0 False False False \n", - "\n", - " mean_running_speed licked rewarded reward_rate hit_fraction \\\n", - "0 1.625696 1 False None None \n", - "1 2.225213 0 False None None \n", - "2 5.024891 0 False None None \n", - "3 4.080798 0 False None None \n", - "4 2.053080 1 False None None \n", - "\n", - " engagement_state lick_on_next_flash \n", - "0 None None \n", - "1 None None \n", - "2 None None \n", - "3 None None \n", - "4 None None " - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "session_stimuli.head()" + "session_stimuli" ] }, { @@ -835,29 +887,18 @@ "metadata": {}, "outputs": [], "source": [ - "# get image index for next flash (should be previous flash...)\n", + "# get image index for next flash\n", "image_index_next_flash = omission_trials[omission_trials.stimulus_presentations_id==this_trial].image_index_next_flash.values[0]" ] }, { "cell_type": "code", - "execution_count": 57, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "7.0" - ] - }, - "execution_count": 57, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "# label for this trial \n", - "image_index_next_flash" + "# image shown at time 0\n", + "image_index = omission_trials[omission_trials.stimulus_presentations_id==this_trial].image_index.values[0]" ] }, { @@ -979,6 +1020,15 @@ "from visual_behavior.ophys.response_analysis.response_analysis import ResponseAnalysis" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# dont run below; it's just the example" + ] + }, { "cell_type": "code", "execution_count": null, @@ -1442,9 +1492,21 @@ ], "metadata": { "kernelspec": { - "display_name": "visual_behavior_sdk", + "display_name": "Python 3", "language": "python", - "name": "visual_behavior_sdk" + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" } }, "nbformat": 4, diff --git a/notebooks/210926_loading_data_for_platform_paper_analysis.ipynb b/notebooks/210926_loading_data_for_platform_paper_analysis.ipynb deleted file mode 100644 index e5d63d1c6..000000000 --- a/notebooks/210926_loading_data_for_platform_paper_analysis.ipynb +++ /dev/null @@ -1,2028 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The purpose of this notebook is to demonstrate how to load data for platform paper analysis using the SDK and VBA functions" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt\n", - "\n", - "import seaborn as sns\n", - "sns.set_context('notebook', font_scale=1.5, rc={'lines.markeredgewidth': 2})" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext autoreload\n", - "%autoreload 2\n", - "\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "import visual_behavior.data_access.loading as loading " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Get `VisualBehaviorOphysProjectCache` using a `cache_dir` containing NWB files downloaded from AWS" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "from allensdk.brain_observatory.behavior.behavior_project_cache import VisualBehaviorOphysProjectCache" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### This cache directory contains the final manifest and NWB files downloaded from AWS" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "//allen/programs/braintv/workgroups/nc-ophys/visual_behavior/platform_paper_cache\n" - ] - } - ], - "source": [ - "cache_dir = loading.get_platform_analysis_cache_dir()\n", - "print(cache_dir)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### create a cache object using this cache_dir" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "cache = VisualBehaviorOphysProjectCache.from_s3_cache(cache_dir=cache_dir)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Load the `ophys_experiment_table` from the cache" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This table includes ALL released data" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "experiments_table = cache.get_ophys_experiment_table()" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1941" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(experiments_table)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Remove VisualBehaviorMultiscope4areasx2d and Ai94 (GCaMP6s) data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "These experiments should not be included in the platform paper analysis" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# remove 4x2 and Ai94 data\n", - "experiments_table = experiments_table[(experiments_table.project_code!='VisualBehaviorMultiscope4areasx2d')&\n", - " (experiments_table.reporter_line!='Ai94(TITL-GCaMP6s)')]" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1249" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(experiments_table)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Add useful columns for analysis" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "import visual_behavior.data_access.utilities as utilities" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:376: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame.\n", - "Try using .loc[row_indexer,col_indexer] = value instead\n", - "\n", - "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " self.obj[key] = _infer_fill_value(value)\n", - "C:\\Users\\marinag\\AppData\\Roaming\\Python\\Python37\\site-packages\\pandas\\core\\indexing.py:494: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame.\n", - "Try using .loc[row_indexer,col_indexer] = value instead\n", - "\n", - "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " self.obj[item] = s\n" - ] - }, - { - "data": { - "text/plain": [ - "array(['Sst Inhibitory', 'Vip Inhibitory', 'Excitatory'], dtype=object)" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "experiments_table = utilities.add_cell_type_column(experiments_table)\n", - "experiments_table.cell_type.unique()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Load experiments table using VBA" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This function does the same thing as the code above. It will return only the experiments we want to analyze for the platform paper, and adds extra useful columns like `cell_type`, `n_relative_to_first_novel` or `last_familiar`. " - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1249" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "experiments_table = loading.get_platform_paper_experiment_table()\n", - "len(experiments_table)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array(['Excitatory', 'Vip Inhibitory', 'Sst Inhibitory'], dtype=object)" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "experiments_table.cell_type.unique()" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Index(['cell_type', 'depth', 'first_novel', 'n_relative_to_first_novel',\n", - " 'last_familiar', 'last_familiar_active', 'second_novel',\n", - " 'second_novel_active', 'experience_exposure'],\n", - " dtype='object')" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# this table also includes several additional columns for filtering sessions based on their experience level and relationship to the first novel session\n", - "experiments_table.keys()[-9:]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Use `loading.get_filtered_ophys_experiment_table(`) if you want to load data from lims, and/or get a broader set of experiments. For example, if you want to include failed experiments in addition to passed experiments. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Check what project_codes are included" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array(['VisualBehavior', 'VisualBehaviorTask1B',\n", - " 'VisualBehaviorMultiscope'], dtype=object)" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "experiments_table.project_code.unique()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### This means there is a mix of data from mice trained on A and mice trained on B" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This is justified because we see that novelty effects are observed regardless of which image set was used for training" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Load a `behavior_ophys_experiment` (aka the dataset object) \n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Using SDK directly" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "from allensdk.brain_observatory.behavior.behavior_project_cache import VisualBehaviorOphysProjectCache\n", - "\n", - "cache_dir = loading.get_platform_analysis_cache_dir()\n", - "cache = VisualBehaviorOphysProjectCache.from_s3_cache(cache_dir=cache_dir)\n", - "\n", - "experiments_table = cache.get_ophys_experiment_table()" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "experiment_id = experiments_table.index.values[0]" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "dataset = cache.get_behavior_ophys_experiment(experiment_id)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
start_timestop_timedurationimage_nameimage_indexis_changeomittedstart_frameend_frameimage_set
stimulus_presentations_id
0309.27537309.525570.25020im0650FalseFalse1798618001.0Natural_Images_Lum_Matched_set_training_2017.0...
1310.02598310.276190.25021im0650FalseFalse1803118046.0Natural_Images_Lum_Matched_set_training_2017.0...
2310.77660311.026800.25020im0650FalseFalse1807618091.0Natural_Images_Lum_Matched_set_training_2017.0...
3311.52721311.777400.25019im0650FalseFalse1812118136.0Natural_Images_Lum_Matched_set_training_2017.0...
4312.27782312.528060.25024im0650FalseFalse1816618181.0Natural_Images_Lum_Matched_set_training_2017.0...
.................................
47963909.817373910.067570.25020im0650FalseFalse233842233857.0Natural_Images_Lum_Matched_set_training_2017.0...
47973910.567983910.818190.25021im0650FalseFalse233887233902.0Natural_Images_Lum_Matched_set_training_2017.0...
47983911.318603911.568800.25020im0650FalseFalse233932233947.0Natural_Images_Lum_Matched_set_training_2017.0...
47993912.069213912.319390.25018im0650FalseFalse233977233992.0Natural_Images_Lum_Matched_set_training_2017.0...
48003912.819803913.070020.25022im0650FalseFalse234022234037.0Natural_Images_Lum_Matched_set_training_2017.0...
\n", - "

4801 rows × 10 columns

\n", - "
" - ], - "text/plain": [ - " start_time stop_time duration image_name \\\n", - "stimulus_presentations_id \n", - "0 309.27537 309.52557 0.25020 im065 \n", - "1 310.02598 310.27619 0.25021 im065 \n", - "2 310.77660 311.02680 0.25020 im065 \n", - "3 311.52721 311.77740 0.25019 im065 \n", - "4 312.27782 312.52806 0.25024 im065 \n", - "... ... ... ... ... \n", - "4796 3909.81737 3910.06757 0.25020 im065 \n", - "4797 3910.56798 3910.81819 0.25021 im065 \n", - "4798 3911.31860 3911.56880 0.25020 im065 \n", - "4799 3912.06921 3912.31939 0.25018 im065 \n", - "4800 3912.81980 3913.07002 0.25022 im065 \n", - "\n", - " image_index is_change omitted start_frame \\\n", - "stimulus_presentations_id \n", - "0 0 False False 17986 \n", - "1 0 False False 18031 \n", - "2 0 False False 18076 \n", - "3 0 False False 18121 \n", - "4 0 False False 18166 \n", - "... ... ... ... ... \n", - "4796 0 False False 233842 \n", - "4797 0 False False 233887 \n", - "4798 0 False False 233932 \n", - "4799 0 False False 233977 \n", - "4800 0 False False 234022 \n", - "\n", - " end_frame \\\n", - "stimulus_presentations_id \n", - "0 18001.0 \n", - "1 18046.0 \n", - "2 18091.0 \n", - "3 18136.0 \n", - "4 18181.0 \n", - "... ... \n", - "4796 233857.0 \n", - "4797 233902.0 \n", - "4798 233947.0 \n", - "4799 233992.0 \n", - "4800 234037.0 \n", - "\n", - " image_set \n", - "stimulus_presentations_id \n", - "0 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "1 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "2 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "3 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "4 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "... ... \n", - "4796 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "4797 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "4798 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "4799 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "4800 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "\n", - "[4801 rows x 10 columns]" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dataset.stimulus_presentations" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Using VBA" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This function loads the dataset from NWB files using the SDK method shown above, then adds `extended_stimulus_presentations` and `behavior_movie_timestamps`. This is the default behavior of this function. See documentation for alternate parameter settings such as `load_from_lims`. If you do not need `extended_stimulus_presentations`, you can set `get_extended_stimulus_presentations` to False, which will speed up loading of the dataset. " - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "import visual_behavior.data_access.loading as loading" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "dataset = loading.get_ophys_dataset(experiment_id)" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
start_timestop_timedurationimage_nameimage_indexis_changeomittedstart_frameend_frameimage_set...flash_after_omittedflash_after_changeimage_name_next_flashimage_index_next_flashimage_name_previous_flashimage_index_previous_flashlick_on_next_flashlick_rate_next_flashlick_on_previous_flashlick_rate_previous_flash
stimulus_presentations_id
0309.27537309.525570.25020im0650FalseFalse1798618001.0Natural_Images_Lum_Matched_set_training_2017.0......NaNNaNim0650.0NaNNaNFalse0.000000NaNNaN
1310.02598310.276190.25021im0650FalseFalse1803118046.0Natural_Images_Lum_Matched_set_training_2017.0......FalseFalseim0650.0im0650.0True0.148148False0.000000
2310.77660311.026800.25020im0650FalseFalse1807618091.0Natural_Images_Lum_Matched_set_training_2017.0......FalseFalseim0650.0im0650.0False0.250000False0.000000
3311.52721311.777400.25019im0650FalseFalse1812118136.0Natural_Images_Lum_Matched_set_training_2017.0......FalseFalseim0650.0im0650.0False0.266667True0.148148
4312.27782312.528060.25024im0650FalseFalse1816618181.0Natural_Images_Lum_Matched_set_training_2017.0......FalseFalseim0650.0im0650.0False0.259259False0.250000
..................................................................
47963909.817373910.067570.25020im0650FalseFalse233842233857.0Natural_Images_Lum_Matched_set_training_2017.0......FalseTrueim0650.0im0650.0False0.001432False0.001536
47973910.567983910.818190.25021im0650FalseFalse233887233902.0Natural_Images_Lum_Matched_set_training_2017.0......FalseFalseim0650.0im0650.0False0.001380False0.001484
47983911.318603911.568800.25020im0650FalseFalse233932233947.0Natural_Images_Lum_Matched_set_training_2017.0......FalseFalseim0650.0im0650.0False0.001328False0.001432
47993912.069213912.319390.25018im0650FalseFalse233977233992.0Natural_Images_Lum_Matched_set_training_2017.0......FalseFalseim0650.0im0650.0False0.001276False0.001380
48003912.819803913.070020.25022im0650FalseFalse234022234037.0Natural_Images_Lum_Matched_set_training_2017.0......FalseFalseNaNNaNim0650.0NaNNaNFalse0.001328
\n", - "

4801 rows × 41 columns

\n", - "
" - ], - "text/plain": [ - " start_time stop_time duration image_name \\\n", - "stimulus_presentations_id \n", - "0 309.27537 309.52557 0.25020 im065 \n", - "1 310.02598 310.27619 0.25021 im065 \n", - "2 310.77660 311.02680 0.25020 im065 \n", - "3 311.52721 311.77740 0.25019 im065 \n", - "4 312.27782 312.52806 0.25024 im065 \n", - "... ... ... ... ... \n", - "4796 3909.81737 3910.06757 0.25020 im065 \n", - "4797 3910.56798 3910.81819 0.25021 im065 \n", - "4798 3911.31860 3911.56880 0.25020 im065 \n", - "4799 3912.06921 3912.31939 0.25018 im065 \n", - "4800 3912.81980 3913.07002 0.25022 im065 \n", - "\n", - " image_index is_change omitted start_frame \\\n", - "stimulus_presentations_id \n", - "0 0 False False 17986 \n", - "1 0 False False 18031 \n", - "2 0 False False 18076 \n", - "3 0 False False 18121 \n", - "4 0 False False 18166 \n", - "... ... ... ... ... \n", - "4796 0 False False 233842 \n", - "4797 0 False False 233887 \n", - "4798 0 False False 233932 \n", - "4799 0 False False 233977 \n", - "4800 0 False False 234022 \n", - "\n", - " end_frame \\\n", - "stimulus_presentations_id \n", - "0 18001.0 \n", - "1 18046.0 \n", - "2 18091.0 \n", - "3 18136.0 \n", - "4 18181.0 \n", - "... ... \n", - "4796 233857.0 \n", - "4797 233902.0 \n", - "4798 233947.0 \n", - "4799 233992.0 \n", - "4800 234037.0 \n", - "\n", - " image_set \\\n", - "stimulus_presentations_id \n", - "0 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "1 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "2 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "3 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "4 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "... ... \n", - "4796 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "4797 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "4798 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "4799 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "4800 Natural_Images_Lum_Matched_set_training_2017.0... \n", - "\n", - " ... flash_after_omitted flash_after_change \\\n", - "stimulus_presentations_id ... \n", - "0 ... NaN NaN \n", - "1 ... False False \n", - "2 ... False False \n", - "3 ... False False \n", - "4 ... False False \n", - "... ... ... ... \n", - "4796 ... False True \n", - "4797 ... False False \n", - "4798 ... False False \n", - "4799 ... False False \n", - "4800 ... False False \n", - "\n", - " image_name_next_flash image_index_next_flash \\\n", - "stimulus_presentations_id \n", - "0 im065 0.0 \n", - "1 im065 0.0 \n", - "2 im065 0.0 \n", - "3 im065 0.0 \n", - "4 im065 0.0 \n", - "... ... ... \n", - "4796 im065 0.0 \n", - "4797 im065 0.0 \n", - "4798 im065 0.0 \n", - "4799 im065 0.0 \n", - "4800 NaN NaN \n", - "\n", - " image_name_previous_flash \\\n", - "stimulus_presentations_id \n", - "0 NaN \n", - "1 im065 \n", - "2 im065 \n", - "3 im065 \n", - "4 im065 \n", - "... ... \n", - "4796 im065 \n", - "4797 im065 \n", - "4798 im065 \n", - "4799 im065 \n", - "4800 im065 \n", - "\n", - " image_index_previous_flash lick_on_next_flash \\\n", - "stimulus_presentations_id \n", - "0 NaN False \n", - "1 0.0 True \n", - "2 0.0 False \n", - "3 0.0 False \n", - "4 0.0 False \n", - "... ... ... \n", - "4796 0.0 False \n", - "4797 0.0 False \n", - "4798 0.0 False \n", - "4799 0.0 False \n", - "4800 0.0 NaN \n", - "\n", - " lick_rate_next_flash lick_on_previous_flash \\\n", - "stimulus_presentations_id \n", - "0 0.000000 NaN \n", - "1 0.148148 False \n", - "2 0.250000 False \n", - "3 0.266667 True \n", - "4 0.259259 False \n", - "... ... ... \n", - "4796 0.001432 False \n", - "4797 0.001380 False \n", - "4798 0.001328 False \n", - "4799 0.001276 False \n", - "4800 NaN False \n", - "\n", - " lick_rate_previous_flash \n", - "stimulus_presentations_id \n", - "0 NaN \n", - "1 0.000000 \n", - "2 0.000000 \n", - "3 0.148148 \n", - "4 0.250000 \n", - "... ... \n", - "4796 0.001536 \n", - "4797 0.001484 \n", - "4798 0.001432 \n", - "4799 0.001380 \n", - "4800 0.001328 \n", - "\n", - "[4801 rows x 41 columns]" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dataset.extended_stimulus_presentations" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Load the `ophys_cells_table`" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Using the SDK" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This gets a table with all `cell_roi_ids`, `cell_specimen_ids`, and `ophys_experiment_ids` in the released dataset" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This is the preferred method for loading the cell table" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "cell_table = cache.get_ophys_cells_table()" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "133227" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(cell_table)" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cell_specimen_idophys_experiment_id
cell_roi_id
10808843431086496928775614751
10808841731086496914775614751
10808838431086496838775614751
10808866741086491756775614751
10808856581086491699775614751
\n", - "
" - ], - "text/plain": [ - " cell_specimen_id ophys_experiment_id\n", - "cell_roi_id \n", - "1080884343 1086496928 775614751\n", - "1080884173 1086496914 775614751\n", - "1080883843 1086496838 775614751\n", - "1080886674 1086491756 775614751\n", - "1080885658 1086491699 775614751" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cell_table.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Merge with experiments_table to get metadata for cells" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "cell_table = cell_table.merge(experiments_table, on='ophys_experiment_id')" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cell_specimen_idophys_experiment_idequipment_namefull_genotypemouse_idreporter_linedriver_linesexage_in_dayscre_line...ophys_container_idproject_codeimaging_depthtargeted_structuredate_of_acquisitionsession_typeexperience_levelpassiveimage_setfile_id
01086496928775614751CAM2P.5Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-G...403491Ai93(TITL-GCaMP6f)[Slc17a7-IRES2-Cre, Camk2a-tTA]F160.0Slc17a7-IRES2-Cre...782536745VisualBehavior375VISp2018-11-08 18:38:05.000000OPHYS_1_images_AFamiliarFalseA945253901
11086496914775614751CAM2P.5Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-G...403491Ai93(TITL-GCaMP6f)[Slc17a7-IRES2-Cre, Camk2a-tTA]F160.0Slc17a7-IRES2-Cre...782536745VisualBehavior375VISp2018-11-08 18:38:05.000000OPHYS_1_images_AFamiliarFalseA945253901
21086496838775614751CAM2P.5Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-G...403491Ai93(TITL-GCaMP6f)[Slc17a7-IRES2-Cre, Camk2a-tTA]F160.0Slc17a7-IRES2-Cre...782536745VisualBehavior375VISp2018-11-08 18:38:05.000000OPHYS_1_images_AFamiliarFalseA945253901
\n", - "

3 rows × 27 columns

\n", - "
" - ], - "text/plain": [ - " cell_specimen_id ophys_experiment_id equipment_name \\\n", - "0 1086496928 775614751 CAM2P.5 \n", - "1 1086496914 775614751 CAM2P.5 \n", - "2 1086496838 775614751 CAM2P.5 \n", - "\n", - " full_genotype mouse_id \\\n", - "0 Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-G... 403491 \n", - "1 Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-G... 403491 \n", - "2 Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-G... 403491 \n", - "\n", - " reporter_line driver_line sex age_in_days \\\n", - "0 Ai93(TITL-GCaMP6f) [Slc17a7-IRES2-Cre, Camk2a-tTA] F 160.0 \n", - "1 Ai93(TITL-GCaMP6f) [Slc17a7-IRES2-Cre, Camk2a-tTA] F 160.0 \n", - "2 Ai93(TITL-GCaMP6f) [Slc17a7-IRES2-Cre, Camk2a-tTA] F 160.0 \n", - "\n", - " cre_line ... ophys_container_id project_code imaging_depth \\\n", - "0 Slc17a7-IRES2-Cre ... 782536745 VisualBehavior 375 \n", - "1 Slc17a7-IRES2-Cre ... 782536745 VisualBehavior 375 \n", - "2 Slc17a7-IRES2-Cre ... 782536745 VisualBehavior 375 \n", - "\n", - " targeted_structure date_of_acquisition session_type \\\n", - "0 VISp 2018-11-08 18:38:05.000000 OPHYS_1_images_A \n", - "1 VISp 2018-11-08 18:38:05.000000 OPHYS_1_images_A \n", - "2 VISp 2018-11-08 18:38:05.000000 OPHYS_1_images_A \n", - "\n", - " experience_level passive image_set file_id \n", - "0 Familiar False A 945253901 \n", - "1 Familiar False A 945253901 \n", - "2 Familiar False A 945253901 \n", - "\n", - "[3 rows x 27 columns]" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cell_table.head(3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Using VBA" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are two ways to load a cell table in VBA. One function, `load_cell_table` loads the cells table from the SDK using the same code as shown above, and optionally filters for platform paper experiments only (no 4x2, no Ai94). The second method, `load_cell_table_from_lims` gets cell ROI information from lims for all experiments, regardless of whether they are passed or failed, unless otherwise specified by the input params. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### From SDK for platform paper cache" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1249\n" - ] - } - ], - "source": [ - "cell_table = loading.get_cell_table()\n", - "print(len(cell_table.ophys_experiment_id.unique()))" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1249\n" - ] - } - ], - "source": [ - "# setting platform_paper_only to True filters out Ai94 and 4x2 data\n", - "cell_table = loading.get_cell_table(platform_paper_only=True)\n", - "print(len(cell_table.ophys_experiment_id.unique()))" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cell_specimen_idophys_experiment_idequipment_namefull_genotypemouse_idreporter_linedriver_linesexage_in_dayscre_line...file_idcell_typedepthfirst_noveln_relative_to_first_novellast_familiarlast_familiar_activesecond_novelsecond_novel_activeexperience_exposure
cell_roi_id
10808843431086496928775614751CAM2P.5Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-G...403491Ai93(TITL-GCaMP6f)[Slc17a7-IRES2-Cre, Camk2a-tTA]F160.0Slc17a7-IRES2-Cre...945253901Excitatory350FalseNaNFalseFalseFalseFalseFamiliar 5
10808841731086496914775614751CAM2P.5Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-G...403491Ai93(TITL-GCaMP6f)[Slc17a7-IRES2-Cre, Camk2a-tTA]F160.0Slc17a7-IRES2-Cre...945253901Excitatory350FalseNaNFalseFalseFalseFalseFamiliar 5
10808838431086496838775614751CAM2P.5Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-G...403491Ai93(TITL-GCaMP6f)[Slc17a7-IRES2-Cre, Camk2a-tTA]F160.0Slc17a7-IRES2-Cre...945253901Excitatory350FalseNaNFalseFalseFalseFalseFamiliar 5
\n", - "

3 rows × 36 columns

\n", - "
" - ], - "text/plain": [ - " cell_specimen_id ophys_experiment_id equipment_name \\\n", - "cell_roi_id \n", - "1080884343 1086496928 775614751 CAM2P.5 \n", - "1080884173 1086496914 775614751 CAM2P.5 \n", - "1080883843 1086496838 775614751 CAM2P.5 \n", - "\n", - " full_genotype mouse_id \\\n", - "cell_roi_id \n", - "1080884343 Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-G... 403491 \n", - "1080884173 Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-G... 403491 \n", - "1080883843 Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;Ai93(TITL-G... 403491 \n", - "\n", - " reporter_line driver_line sex \\\n", - "cell_roi_id \n", - "1080884343 Ai93(TITL-GCaMP6f) [Slc17a7-IRES2-Cre, Camk2a-tTA] F \n", - "1080884173 Ai93(TITL-GCaMP6f) [Slc17a7-IRES2-Cre, Camk2a-tTA] F \n", - "1080883843 Ai93(TITL-GCaMP6f) [Slc17a7-IRES2-Cre, Camk2a-tTA] F \n", - "\n", - " age_in_days cre_line ... file_id cell_type \\\n", - "cell_roi_id ... \n", - "1080884343 160.0 Slc17a7-IRES2-Cre ... 945253901 Excitatory \n", - "1080884173 160.0 Slc17a7-IRES2-Cre ... 945253901 Excitatory \n", - "1080883843 160.0 Slc17a7-IRES2-Cre ... 945253901 Excitatory \n", - "\n", - " depth first_novel n_relative_to_first_novel last_familiar \\\n", - "cell_roi_id \n", - "1080884343 350 False NaN False \n", - "1080884173 350 False NaN False \n", - "1080883843 350 False NaN False \n", - "\n", - " last_familiar_active second_novel second_novel_active \\\n", - "cell_roi_id \n", - "1080884343 False False False \n", - "1080884173 False False False \n", - "1080883843 False False False \n", - "\n", - " experience_exposure \n", - "cell_roi_id \n", - "1080884343 Familiar 5 \n", - "1080884173 Familiar 5 \n", - "1080883843 Familiar 5 \n", - "\n", - "[3 rows x 36 columns]" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cell_table.head(3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### From lims " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This function loads a cell table that includes all available data in lims, unless you provide a list of `ophys_experiment_ids`, or set `platform_paper_only` to True. It will include invalid ROIs unless you set `valid_rois_only` to True." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [], - "source": [ - "lims_cell_table = loading.get_cell_table_from_lims(ophys_experiment_ids=None, valid_rois_only=False, platform_paper_only=False)" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "253537" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(lims_cell_table)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The table includes `cell_roi_ids`, `cell_specimen_ids`, and `ophys_experiment_ids`, as well as information about the ROI masks, such as their x and y location in the FOV. " - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cell_roi_idcell_specimen_idophys_experiment_idxywidthheightvalid_roimask_matrixmax_correction_upmax_correction_downmax_correction_rightmax_correction_leftmask_image_planeophys_cell_segmentation_run_id
0108088711110864971817756147512611303126False[[False, False, False, False, False, False, Fa...13.016.08.023.021080818871
1108088674110864971517756147513182631915False[[False, False, False, False, False, False, Fa...13.016.08.023.001080818871
2108088624610864970957756147511083993621False[[False, False, False, False, False, False, Fa...13.016.08.023.021080818871
\n", - "
" - ], - "text/plain": [ - " cell_roi_id cell_specimen_id ophys_experiment_id x y width \\\n", - "0 1080887111 1086497181 775614751 261 130 31 \n", - "1 1080886741 1086497151 775614751 318 263 19 \n", - "2 1080886246 1086497095 775614751 108 399 36 \n", - "\n", - " height valid_roi mask_matrix \\\n", - "0 26 False [[False, False, False, False, False, False, Fa... \n", - "1 15 False [[False, False, False, False, False, False, Fa... \n", - "2 21 False [[False, False, False, False, False, False, Fa... \n", - "\n", - " max_correction_up max_correction_down max_correction_right \\\n", - "0 13.0 16.0 8.0 \n", - "1 13.0 16.0 8.0 \n", - "2 13.0 16.0 8.0 \n", - "\n", - " max_correction_left mask_image_plane ophys_cell_segmentation_run_id \n", - "0 23.0 2 1080818871 \n", - "1 23.0 0 1080818871 \n", - "2 23.0 2 1080818871 " - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "lims_cell_table.head(3)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "visual_behavior_sdk", - "language": "python", - "name": "visual_behavior_sdk" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/notebooks/210929_platform_paper_selection_criteria.ipynb b/notebooks/210929_platform_paper_selection_criteria.ipynb deleted file mode 100644 index b31cced26..000000000 --- a/notebooks/210929_platform_paper_selection_criteria.ipynb +++ /dev/null @@ -1,2755 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt\n", - "\n", - "import seaborn as sns\n", - "sns.set_context('notebook', font_scale=1.5, rc={'lines.markeredgewidth': 2})" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext autoreload\n", - "%autoreload 2\n", - "\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "from visual_behavior.data_access import loading as loading\n", - "\n", - "from allensdk.brain_observatory.behavior.behavior_project_cache import VisualBehaviorOphysProjectCache" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "import visual_behavior.data_access.utilities as utilities\n", - "\n", - "import visual_behavior.visualization.ophys.platform_paper_figures as ppf" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### load experiments_table from cache" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "cache_dir = loading.get_platform_analysis_cache_dir()\n", - "# cache = VisualBehaviorOphysProjectCache.from_s3_cache(cache_dir=cache_dir)\n", - "# print(cache_dir)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1249\n" - ] - } - ], - "source": [ - "experiments_table = loading.get_platform_paper_experiment_table()\n", - "print(len(experiments_table))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### load cells table" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1249\n" - ] - } - ], - "source": [ - "cells_table = loading.get_cell_table()\n", - "print(len(cells_table.ophys_experiment_id.unique()))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### get number of experiments, mice & cells per experience level & cell type " - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "def value_counts(df, conditions=['cell_type', 'experience_level', 'mouse_id']):\n", - " \"\"\"\n", - " group by the first conditions and count the last one\n", - " \"\"\"\n", - " counts = df.groupby(conditions).count().reset_index().groupby(conditions[:-1]).count()\n", - " counts = counts[[conditions[-1]]].rename(columns={conditions[-1]:'n_'+conditions[-1]})\n", - " return counts" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### full experiment table" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_id
cell_typeexperience_level
ExcitatoryFamiliar4128088
Novel 1367171
Novel >14119688
Sst InhibitoryFamiliar1914446
Novel 1153737
Novel >11910745
Vip InhibitoryFamiliar2221769
Novel 1174747
Novel >12215066
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 41 280 \n", - " Novel 1 36 71 \n", - " Novel >1 41 196 \n", - "Sst Inhibitory Familiar 19 144 \n", - " Novel 1 15 37 \n", - " Novel >1 19 107 \n", - "Vip Inhibitory Familiar 22 217 \n", - " Novel 1 17 47 \n", - " Novel >1 22 150 \n", - "\n", - " n_ophys_container_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 88 \n", - " Novel 1 71 \n", - " Novel >1 88 \n", - "Sst Inhibitory Familiar 46 \n", - " Novel 1 37 \n", - " Novel >1 45 \n", - "Vip Inhibitory Familiar 69 \n", - " Novel 1 47 \n", - " Novel >1 66 " - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mice = value_counts(experiments_table, conditions=['cell_type', 'experience_level', 'mouse_id'])\n", - "experiments = value_counts(experiments_table, conditions=['cell_type', 'experience_level', 'ophys_experiment_id'])\n", - "containers = value_counts(experiments_table, conditions=['cell_type', 'experience_level', 'ophys_container_id'])\n", - "\n", - "counts = mice.merge(experiments, on=['cell_type', 'experience_level'])\n", - "counts = counts.merge(containers, on=['cell_type', 'experience_level'])\n", - "counts" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### full cells table" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "def count_mice_expts_containers_cells(df):\n", - " mice = value_counts(df, conditions=['cell_type', 'experience_level', 'mouse_id'])\n", - " experiments = value_counts(df, conditions=['cell_type', 'experience_level', 'ophys_experiment_id'])\n", - " containers = value_counts(df, conditions=['cell_type', 'experience_level', 'ophys_container_id'])\n", - " cells = value_counts(df, conditions=['cell_type', 'experience_level', 'cell_specimen_id'])\n", - "\n", - " counts = mice.merge(experiments, on=['cell_type', 'experience_level'])\n", - " counts = counts.merge(containers, on=['cell_type', 'experience_level'])\n", - " counts = counts.merge(cells, on=['cell_type', 'experience_level'])\n", - " return counts" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar412808818782
Novel 13671719225
Novel >1411968815705
Sst InhibitoryFamiliar1914446738
Novel 1153737414
Novel >11910745678
Vip InhibitoryFamiliar22217691852
Novel 1174747792
Novel >122150661547
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 41 280 \n", - " Novel 1 36 71 \n", - " Novel >1 41 196 \n", - "Sst Inhibitory Familiar 19 144 \n", - " Novel 1 15 37 \n", - " Novel >1 19 107 \n", - "Vip Inhibitory Familiar 22 217 \n", - " Novel 1 17 47 \n", - " Novel >1 22 150 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 88 18782 \n", - " Novel 1 71 9225 \n", - " Novel >1 88 15705 \n", - "Sst Inhibitory Familiar 46 738 \n", - " Novel 1 37 414 \n", - " Novel >1 45 678 \n", - "Vip Inhibitory Familiar 69 1852 \n", - " Novel 1 47 792 \n", - " Novel >1 66 1547 " - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "count_mice_expts_containers_cells(cells_table)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### limit to last familiar active and second novel active" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "def limit_to_last_familiar_second_novel_active(df):\n", - " \"\"\"\n", - " Drops rows that are not the last familiar active session or the second novel active session\n", - " \"\"\"\n", - " # drop novel sessions that arent the second active one\n", - " indices = df[(df.experience_level=='Novel >1')&(df.second_novel_active==False)].index.values\n", - " df = df.drop(labels=indices, axis=0)\n", - " \n", - " # drop Familiar sessions that arent the last active one\n", - " indices = df[(df.experience_level=='Familiar')&(df.last_familiar_active==False)].index.values\n", - " df = df.drop(labels=indices, axis=0)\n", - " \n", - " return df" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "28582" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cells_table = utilities.limit_to_last_familiar_second_novel_active(cells_table)\n", - "len(cells_table)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar3570708147
Novel 13671719225
Novel >13563637666
Sst InhibitoryFamiliar153737392
Novel 1153737414
Novel >1153030320
Vip InhibitoryFamiliar174747861
Novel 1174747792
Novel >1174242765
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 35 70 \n", - " Novel 1 36 71 \n", - " Novel >1 35 63 \n", - "Sst Inhibitory Familiar 15 37 \n", - " Novel 1 15 37 \n", - " Novel >1 15 30 \n", - "Vip Inhibitory Familiar 17 47 \n", - " Novel 1 17 47 \n", - " Novel >1 17 42 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 70 8147 \n", - " Novel 1 71 9225 \n", - " Novel >1 63 7666 \n", - "Sst Inhibitory Familiar 37 392 \n", - " Novel 1 37 414 \n", - " Novel >1 30 320 \n", - "Vip Inhibitory Familiar 47 861 \n", - " Novel 1 47 792 \n", - " Novel >1 42 765 " - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "count_mice_expts_containers_cells(cells_table)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### limit to containers with all 3 experience levels" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "def get_containers_with_all_experience_levels(experiments_table):\n", - " \"\"\"\n", - " identifies containers with all 3 experience levels in ['Familiar', 'Novel 1', 'Novel >1']\n", - " \"\"\"\n", - " experience_level_counts = experiments_table.groupby(['ophys_container_id', 'experience_level']).count().reset_index().groupby(['ophys_container_id']).count()[['experience_level']]\n", - " containers_with_all_experience_levels = experience_level_counts[experience_level_counts.experience_level==3].index.unique()\n", - " return containers_with_all_experience_levels\n", - "\n", - "\n", - "def limit_to_containers_with_all_experience_levels(experiments_table):\n", - " \"\"\"\n", - " returns experiment_table limited to containers with all 3 experience levels in ['Familiar', 'Novel 1', 'Novel >1']\n", - " \"\"\"\n", - " containers_with_all_experience_levels = get_containers_with_all_experience_levels(experiments_table)\n", - " experiments_table = experiments_table[experiments_table.ophys_container_id.isin(containers_with_all_experience_levels)]\n", - " return experiments_table\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "26075\n" - ] - } - ], - "source": [ - "cells_table = utilities.limit_to_containers_with_all_experience_levels(cells_table)\n", - "print(len(cells_table))" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar3462627302
Novel 13462627974
Novel >13462627544
Sst InhibitoryFamiliar153030321
Novel 1153030337
Novel >1153030320
Vip InhibitoryFamiliar174242794
Novel 1174242718
Novel >1174242765
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 34 62 \n", - " Novel 1 34 62 \n", - " Novel >1 34 62 \n", - "Sst Inhibitory Familiar 15 30 \n", - " Novel 1 15 30 \n", - " Novel >1 15 30 \n", - "Vip Inhibitory Familiar 17 42 \n", - " Novel 1 17 42 \n", - " Novel >1 17 42 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 62 7302 \n", - " Novel 1 62 7974 \n", - " Novel >1 62 7544 \n", - "Sst Inhibitory Familiar 30 321 \n", - " Novel 1 30 337 \n", - " Novel >1 30 320 \n", - "Vip Inhibitory Familiar 42 794 \n", - " Novel 1 42 718 \n", - " Novel >1 42 765 " - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "count_mice_expts_containers_cells(cells_table)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### just for Multiscope" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar836363604
Novel 1836363996
Novel >1836363783
Sst InhibitoryFamiliar52020198
Novel 152020215
Novel >152020194
Vip InhibitoryFamiliar63131548
Novel 163131507
Novel >163131523
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 8 36 \n", - " Novel 1 8 36 \n", - " Novel >1 8 36 \n", - "Sst Inhibitory Familiar 5 20 \n", - " Novel 1 5 20 \n", - " Novel >1 5 20 \n", - "Vip Inhibitory Familiar 6 31 \n", - " Novel 1 6 31 \n", - " Novel >1 6 31 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 36 3604 \n", - " Novel 1 36 3996 \n", - " Novel >1 36 3783 \n", - "Sst Inhibitory Familiar 20 198 \n", - " Novel 1 20 215 \n", - " Novel >1 20 194 \n", - "Vip Inhibitory Familiar 31 548 \n", - " Novel 1 31 507 \n", - " Novel >1 31 523 " - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "multiscope_cells_table = cells_table[cells_table.project_code=='VisualBehaviorMultiscope'].copy()\n", - "\n", - "count_mice_expts_containers_cells(multiscope_cells_table)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### limit to cells matched across experience levels" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "def get_cell_specimen_ids_with_all_experience_levels(df):\n", - " \"\"\"\n", - " identifies cell_specimen_ids with all 3 experience levels in ['Familiar', 'Novel 1', 'Novel >1'] in the input dataframe\n", - " input dataframe must have column 'cell_specimen_id', such as in ophys_cells_table\n", - " \"\"\"\n", - " experience_level_counts = df.groupby(['cell_specimen_id', 'experience_level']).count().reset_index().groupby(['cell_specimen_id']).count()[['experience_level']]\n", - " cell_specimen_ids_with_all_experience_levels = experience_level_counts[experience_level_counts.experience_level==3].index.unique()\n", - " return cell_specimen_ids_with_all_experience_levels\n", - "\n", - "\n", - "def limit_to_cell_specimen_ids_matched_in_all_experience_levels(cells_table):\n", - " \"\"\"\n", - " returns dataframe limited to cell_specimen_ids that are present in all 3 experience levels in ['Familiar', 'Novel 1', 'Novel >1']\n", - " input dataframe is typically ophys_cells_table but can be any df with columns 'cell_specimen_id' and 'experience_level'\n", - " \"\"\"\n", - " cell_specimen_ids_with_all_experience_levels = get_cell_specimen_ids_with_all_experience_levels(cells_table)\n", - " matched_cells_table = cells_table[cells_table.cell_specimen_id.isin(cell_specimen_ids_with_all_experience_levels)].copy()\n", - " return matched_cells_table" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "11823" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "matched_cells_table = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(cells_table)\n", - "len(matched_cells_table)" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar3462623326
Novel 13462623326
Novel >13462623326
Sst InhibitoryFamiliar142828200
Novel 1142828200
Novel >1142828200
Vip InhibitoryFamiliar174141415
Novel 1174141415
Novel >1174141415
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 34 62 \n", - " Novel 1 34 62 \n", - " Novel >1 34 62 \n", - "Sst Inhibitory Familiar 14 28 \n", - " Novel 1 14 28 \n", - " Novel >1 14 28 \n", - "Vip Inhibitory Familiar 17 41 \n", - " Novel 1 17 41 \n", - " Novel >1 17 41 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 62 3326 \n", - " Novel 1 62 3326 \n", - " Novel >1 62 3326 \n", - "Sst Inhibitory Familiar 28 200 \n", - " Novel 1 28 200 \n", - " Novel >1 28 200 \n", - "Vip Inhibitory Familiar 41 415 \n", - " Novel 1 41 415 \n", - " Novel >1 41 415 " - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "count_mice_expts_containers_cells(matched_cells_table)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Compare selection criteria" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### all cells" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "77922\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar412808818782
Novel 13671719225
Novel >1411968815705
Sst InhibitoryFamiliar1914446738
Novel 1153737414
Novel >11910745678
Vip InhibitoryFamiliar22217691852
Novel 1174747792
Novel >122150661547
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 41 280 \n", - " Novel 1 36 71 \n", - " Novel >1 41 196 \n", - "Sst Inhibitory Familiar 19 144 \n", - " Novel 1 15 37 \n", - " Novel >1 19 107 \n", - "Vip Inhibitory Familiar 22 217 \n", - " Novel 1 17 47 \n", - " Novel >1 22 150 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 88 18782 \n", - " Novel 1 71 9225 \n", - " Novel >1 88 15705 \n", - "Sst Inhibitory Familiar 46 738 \n", - " Novel 1 37 414 \n", - " Novel >1 45 678 \n", - "Vip Inhibitory Familiar 69 1852 \n", - " Novel 1 47 792 \n", - " Novel >1 66 1547 " - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# load cells table\n", - "cells_table = loading.get_cell_table()\n", - "print(len(cells_table))\n", - "\n", - "all_cells = count_mice_expts_containers_cells(cells_table)\n", - "all_cells" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### allow matches for any familiar and any novel >1" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "77922\n", - "62384\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar36226715695
Novel 13671715695
Novel >136142715695
Sst InhibitoryFamiliar1511236292
Novel 1153636292
Novel >1158436292
Vip InhibitoryFamiliar1713744540
Novel 1174444540
Novel >1179644540
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 36 226 \n", - " Novel 1 36 71 \n", - " Novel >1 36 142 \n", - "Sst Inhibitory Familiar 15 112 \n", - " Novel 1 15 36 \n", - " Novel >1 15 84 \n", - "Vip Inhibitory Familiar 17 137 \n", - " Novel 1 17 44 \n", - " Novel >1 17 96 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 71 5695 \n", - " Novel 1 71 5695 \n", - " Novel >1 71 5695 \n", - "Sst Inhibitory Familiar 36 292 \n", - " Novel 1 36 292 \n", - " Novel >1 36 292 \n", - "Vip Inhibitory Familiar 44 540 \n", - " Novel 1 44 540 \n", - " Novel >1 44 540 " - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# load cells table\n", - "cells_table = loading.get_cell_table()\n", - "print(len(cells_table))\n", - "\n", - "# limit to containers with all 3 experience levels\n", - "cells_table = utilities.limit_to_containers_with_all_experience_levels(cells_table)\n", - "print(len(cells_table))\n", - "\n", - "# limit to cells matched across experience levels\n", - "matched_cells_table = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(cells_table)\n", - "len(matched_cells_table)\n", - "\n", - "any_matches = count_mice_expts_containers_cells(matched_cells_table)\n", - "any_matches" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### limit to last familiar and second novel" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "77922\n", - "29461\n", - "28304\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar3467673672
Novel 13467673672
Novel >13467673672
Sst InhibitoryFamiliar153131214
Novel 1153131214
Novel >1153131214
Vip InhibitoryFamiliar174343447
Novel 1174343447
Novel >1174343447
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 34 67 \n", - " Novel 1 34 67 \n", - " Novel >1 34 67 \n", - "Sst Inhibitory Familiar 15 31 \n", - " Novel 1 15 31 \n", - " Novel >1 15 31 \n", - "Vip Inhibitory Familiar 17 43 \n", - " Novel 1 17 43 \n", - " Novel >1 17 43 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 67 3672 \n", - " Novel 1 67 3672 \n", - " Novel >1 67 3672 \n", - "Sst Inhibitory Familiar 31 214 \n", - " Novel 1 31 214 \n", - " Novel >1 31 214 \n", - "Vip Inhibitory Familiar 43 447 \n", - " Novel 1 43 447 \n", - " Novel >1 43 447 " - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# load cells table\n", - "cells_table = loading.get_cell_table()\n", - "print(len(cells_table))\n", - "\n", - "# limit to last familiar and second novel \n", - "cells_table = utilities.limit_to_last_familiar_second_novel(cells_table)\n", - "print(len(cells_table))\n", - "\n", - "# limit to containers with all 3 experience levels\n", - "cells_table = utilities.limit_to_containers_with_all_experience_levels(cells_table)\n", - "print(len(cells_table))\n", - "\n", - "# limit to cells matched across experience levels\n", - "matched_cells_table = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(cells_table)\n", - "len(matched_cells_table)\n", - "\n", - "last_and_second = count_mice_expts_containers_cells(matched_cells_table)\n", - "last_and_second" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### limit to last active familiar and second active novel" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "77922\n", - "28582\n", - "26075\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar3462623326
Novel 13462623326
Novel >13462623326
Sst InhibitoryFamiliar142828200
Novel 1142828200
Novel >1142828200
Vip InhibitoryFamiliar174141415
Novel 1174141415
Novel >1174141415
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 34 62 \n", - " Novel 1 34 62 \n", - " Novel >1 34 62 \n", - "Sst Inhibitory Familiar 14 28 \n", - " Novel 1 14 28 \n", - " Novel >1 14 28 \n", - "Vip Inhibitory Familiar 17 41 \n", - " Novel 1 17 41 \n", - " Novel >1 17 41 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 62 3326 \n", - " Novel 1 62 3326 \n", - " Novel >1 62 3326 \n", - "Sst Inhibitory Familiar 28 200 \n", - " Novel 1 28 200 \n", - " Novel >1 28 200 \n", - "Vip Inhibitory Familiar 41 415 \n", - " Novel 1 41 415 \n", - " Novel >1 41 415 " - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# load cells table\n", - "cells_table = loading.get_cell_table()\n", - "print(len(cells_table))\n", - "\n", - "# limit to last familiar active and second novel active\n", - "cells_table = utilities.limit_to_last_familiar_second_novel_active(cells_table)\n", - "print(len(cells_table))\n", - "\n", - "# limit to containers with all 3 experience levels\n", - "cells_table = utilities.limit_to_containers_with_all_experience_levels(cells_table)\n", - "print(len(cells_table))\n", - "\n", - "# limit to cells matched across experience levels\n", - "matched_cells_table = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(cells_table)\n", - "len(matched_cells_table)\n", - "\n", - "last_and_second_active = count_mice_expts_containers_cells(matched_cells_table)\n", - "last_and_second_active" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### fraction of all cells matched in all 3 experience levels" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar0.8780490.8071430.8068180.303216
Novel 11.0000001.0000001.0000000.617344
Novel >10.8780490.7244900.8068180.362623
Sst InhibitoryFamiliar0.7894740.7777780.7826090.395664
Novel 11.0000000.9729730.9729730.705314
Novel >10.7894740.7850470.8000000.430678
Vip InhibitoryFamiliar0.7727270.6313360.6376810.291577
Novel 11.0000000.9361700.9361700.681818
Novel >10.7727270.6400000.6666670.349063
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 0.878049 0.807143 \n", - " Novel 1 1.000000 1.000000 \n", - " Novel >1 0.878049 0.724490 \n", - "Sst Inhibitory Familiar 0.789474 0.777778 \n", - " Novel 1 1.000000 0.972973 \n", - " Novel >1 0.789474 0.785047 \n", - "Vip Inhibitory Familiar 0.772727 0.631336 \n", - " Novel 1 1.000000 0.936170 \n", - " Novel >1 0.772727 0.640000 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 0.806818 0.303216 \n", - " Novel 1 1.000000 0.617344 \n", - " Novel >1 0.806818 0.362623 \n", - "Sst Inhibitory Familiar 0.782609 0.395664 \n", - " Novel 1 0.972973 0.705314 \n", - " Novel >1 0.800000 0.430678 \n", - "Vip Inhibitory Familiar 0.637681 0.291577 \n", - " Novel 1 0.936170 0.681818 \n", - " Novel >1 0.666667 0.349063 " - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "any_matches/all_cells" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### fraction of all cells matched inlast familiar and second novel active" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar0.8292680.2214290.7045450.177084
Novel 10.9444440.8732390.8732390.360542
Novel >10.8292680.3163270.7045450.211780
Sst InhibitoryFamiliar0.7368420.1944440.6086960.271003
Novel 10.9333330.7567570.7567570.483092
Novel >10.7368420.2616820.6222220.294985
Vip InhibitoryFamiliar0.7727270.1889400.5942030.224082
Novel 11.0000000.8723400.8723400.523990
Novel >10.7727270.2733330.6212120.268261
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 0.829268 0.221429 \n", - " Novel 1 0.944444 0.873239 \n", - " Novel >1 0.829268 0.316327 \n", - "Sst Inhibitory Familiar 0.736842 0.194444 \n", - " Novel 1 0.933333 0.756757 \n", - " Novel >1 0.736842 0.261682 \n", - "Vip Inhibitory Familiar 0.772727 0.188940 \n", - " Novel 1 1.000000 0.872340 \n", - " Novel >1 0.772727 0.273333 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 0.704545 0.177084 \n", - " Novel 1 0.873239 0.360542 \n", - " Novel >1 0.704545 0.211780 \n", - "Sst Inhibitory Familiar 0.608696 0.271003 \n", - " Novel 1 0.756757 0.483092 \n", - " Novel >1 0.622222 0.294985 \n", - "Vip Inhibitory Familiar 0.594203 0.224082 \n", - " Novel 1 0.872340 0.523990 \n", - " Novel >1 0.621212 0.268261 " - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "last_and_second_active/all_cells" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### fraction of cells matched across any 3 that are matched across last familiar and second novel active" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar0.9444440.2743360.8732390.584021
Novel 10.9444440.8732390.8732390.584021
Novel >10.9444440.4366200.8732390.584021
Sst InhibitoryFamiliar0.9333330.2500000.7777780.684932
Novel 10.9333330.7777780.7777780.684932
Novel >10.9333330.3333330.7777780.684932
Vip InhibitoryFamiliar1.0000000.2992700.9318180.768519
Novel 11.0000000.9318180.9318180.768519
Novel >11.0000000.4270830.9318180.768519
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 0.944444 0.274336 \n", - " Novel 1 0.944444 0.873239 \n", - " Novel >1 0.944444 0.436620 \n", - "Sst Inhibitory Familiar 0.933333 0.250000 \n", - " Novel 1 0.933333 0.777778 \n", - " Novel >1 0.933333 0.333333 \n", - "Vip Inhibitory Familiar 1.000000 0.299270 \n", - " Novel 1 1.000000 0.931818 \n", - " Novel >1 1.000000 0.427083 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 0.873239 0.584021 \n", - " Novel 1 0.873239 0.584021 \n", - " Novel >1 0.873239 0.584021 \n", - "Sst Inhibitory Familiar 0.777778 0.684932 \n", - " Novel 1 0.777778 0.684932 \n", - " Novel >1 0.777778 0.684932 \n", - "Vip Inhibitory Familiar 0.931818 0.768519 \n", - " Novel 1 0.931818 0.768519 \n", - " Novel >1 0.931818 0.768519 " - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "last_and_second_active/any_matches" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Examine depth and binned depth columns" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1249\n" - ] - } - ], - "source": [ - "experiments_table = loading.get_platform_paper_experiment_table()\n", - "print(len(experiments_table))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `depth` column is the average depth across all experiments in a container. This is useful to have because some containers have slightly ifferent values of `imaging_depth` each day, even though it is targeting the same field of view. These discrepancies are likely due to differences in where the microscope was zeroed on the brain surface from day to day. " - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
imaging_depthdepth
ophys_experiment_id
8505173507577
8510932897577
8533637477577
8547598988377
8561231248177
\n", - "
" - ], - "text/plain": [ - " imaging_depth depth\n", - "ophys_experiment_id \n", - "850517350 75 77\n", - "851093289 75 77\n", - "853363747 75 77\n", - "854759898 83 77\n", - "856123124 81 77" - ] - }, - "execution_count": 63, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "container_id = experiments_table.ophys_container_id.unique()[99]\n", - "experiments_table[experiments_table.ophys_container_id==container_id][['imaging_depth', 'depth']]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `binned_depth` column groups depth values into 4 bins spanning 100um each, starting at 0um. Because the bulk of the data is collected at [75, 175, 275, 375], the bins are labeled as [75, 175, 275, 375] " - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
imaging_depthdepthbinned_depth
ophys_experiment_id
850517350757775
851093289757775
853363747757775
854759898837775
856123124817775
\n", - "
" - ], - "text/plain": [ - " imaging_depth depth binned_depth\n", - "ophys_experiment_id \n", - "850517350 75 77 75\n", - "851093289 75 77 75\n", - "853363747 75 77 75\n", - "854759898 83 77 75\n", - "856123124 81 77 75" - ] - }, - "execution_count": 62, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "container_id = experiments_table.ophys_container_id.unique()[99]\n", - "experiments_table[experiments_table.ophys_container_id==container_id][['imaging_depth', 'depth', 'binned_depth']]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### plot histogram of `depth` values for bins in `binned_depth`" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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NQ8Mw9DkyZN15swZTZ8+Pc+bU9qQB8UTWfArd82CunXr6vz583r99dcdxv/3v/8pMTHR/h1syAKemlGopk2bpv/973+aMmWKNm3apPbt28vHx0fJyclav369srKyNHPmTElS5cqVFR4erjfeeEPXrl1TUFCQLl26pNdff1333Xef/UYytsdDbdq0SYZhKCIiwuEGMM4gMTFR48aNU4cOHZSUlKR33nlH3bp1u+1j7ipUqKCvv/5ab7zxhlq0aKEHH3xQUVFRWrVqlYYOHaqQkBCdO3dOq1atkp+fnyZNmpSvuQQHB6t8+fLaunWr+vTpc9u7+v5eycnJkvJ+PrB089FF0dHRevjhh9W/f39duXJFq1evVsmSJR2uB4R74NgvHsd+fpERxRt54N55sG/fPh08eFBVq1bVvffem+Mvmd7e3g7XoJMHxRdZ4N5ZUKlSJUVHR2vRokUaMWKEunTpoh9++EGvv/66KleubH/sqg1ZQBFRqCpUqKD169fr1Vdf1a5du7RkyRJdu3ZNlStXVteuXTVmzBhVrlzZvv4zzzyj6tWra8uWLdqyZYvKli2r1q1ba8KECfZrgerUqaOoqCitX79en3/+uVq2bFmgU5ussGDBAiUkJOi5555T+fLlNXbsWEVHR992m8cee0yzZs3Sv/71L0VHR6tu3bp6+umnVatWLb311luaO3euypUrp9DQUD3++OOqWrVqvuZSqlQphYWFac2aNYV2h2zbtXy3u8YsJCRES5Ys0csvv6x58+apTJkyatGihSZOnKg6deoUyrxQdDj2i8exn19kRPFGHrh3HthufJeSkqIpU6bkWF61alWHIoI8KL7IAvfOAkkaN26cypUrp9WrV+u5556Tn5+fHnroIU2YMMHh91YiCyTJw7jd3T8ANzBr1izt2rVL77//foFujAPAtXHsA7AhDwBIZIEz4R4RcGuXLl3Su+++q969exM2QDHCsQ/AhjwAIJEFzoZLM+CWvvzyS73yyiv63//+p4yMjBzP4AXgnjj2AdiQBwAkssBZcUYE3JKvr68+/PBDZWdna968ebe9EQwA98GxD8CGPAAgkQXOyqXuEZGdna3U1FRVqVLF6e4IC8Ba5AEAG/IAgA15ALgGlzojIjU1VV26dFFqampRTwVAESMPANiQBwBsyAPANbhUEQEAAAAAAFwbRQQAAAAAALAM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/ODBg6pQoYKqV69eiq2DFbj2fUNaWpq6d++uAwcOKD4+3uX9iBG+hXjg/Xbu3ClJuvvuux3KY2JiJKnIRKVEPPA1xAPv9/PPP6tRo0YO8cDPz08RERH65ZdfCj3vNr4YD0hElKDY2FhduXJFH374odO2DRs26MqVK/apV5Lz/Vfx8fEaPHiwtmzZorvuuktNmjRRnz59lJqa+ofaEx8fr2HDhunjjz/W3XffrTvuuEOdOnXSggULlJ+f71Q/LS3Nod6iRYsc6hV139fu3bvVr18/3XHHHeratauWLVvmsP3394Ht3LlTf/3rXyVJycnJDveHXbhwQXPmzFGXLl3UuHFjdenSRc8//7zDFLU1a9YoLCxMqamp6tKli5o2bapnn31WTZo00eOPP+7UtjfeeENhYWE6ePDgH+rDazl58qTeeOMNde3aVREREQ7b/vOf/ygkJER+fn66fPmyLl26ZPrrw31w7Xv/tX/o0CG1bt1a7777rqKjo13ahxjhm4gH3h0P+vXrp7Vr16pOnToO5b/99pskyd/fv9D9iAe+iXjg3fGgffv2WrNmjdMtFAcOHNCNN96oSpUqFbqfr8YDEhElqGPHjqpUqZI2bNjgtG39+vWqXr26WrRocc3nOHTokB577DG1bNlS48aNU5kyZfTYY49p3bp1f6hN33//vZ544gm1bt1aU6ZMUc2aNZWcnKxVq1Y51Pvll180atQo3XnnnXryySdVrVo1zZ8/X6+99lqxrzF06FCFhIRo0qRJql69umbMmFHkwjj16tXT5MmTJV29X2rWrFmqXLmycnNzNWTIEL3yyiv2NrRq1UqvvPKKhg4dqry8PIfnmTx5smJjYzVq1Ch17dpVHTt21EcffeR0X9369esVFham22+//Xq6zSVLly7VxYsX9eijjzpts02rGjp0qJo1a6amTZtqwIAB+vbbb01vB0of1773X/sDBgzQiy++WOg9nkUhRvgm4oF3x4PAwEA1aNBA5cqVcyi39WXz5s0L3Y944JuIB94dD37v0qVL+v777/X0009r+/btevjhh53ihI3PxgMDJWrKlClGgwYNjKysLHtZZmamERYWZsydO9eh7oMPPmh07tzZ4XFoaKjx6quv2ssuXLhgREdHG5GRkcaVK1eKfN3PPvvMCA0NNZKSkpyeb/PmzfayixcvGi1btjT69+/vVG/jxo32srNnzxrNmzc3HnjgAXvZxIkTjdDQUKfHM2fOtJdduXLFGDhwoNG4cWPj1KlThmEYRlJSkhEaGmocP37cMAzDOH78uFNb33jjDadjNwzDeOWVV4zQ0FBj5cqVhmEYxttvv22EhoYaEydOdKiXmppqhIaGGh988IG9LDMz06hfv77x0ksvFdlvf9SFCxeMli1bGoMHD3badvbsWSM0NNRo1KiRMWvWLGPz5s3G0qVLjdatWxvNmjUzDh48aHp7UPq49n3j2jeM//b522+/XWQdYoRvIx74TjwwDMP49NNPjYYNGxpdu3Y1cnNznbYTD3wb8cA34sHSpUuN0NBQIzQ01Lj//vuN06dPF1rPl+MBMyJKmG0K1ubNm+1lKSkpMgzDYepVUYKCgvTAAw/YH99www0aMGCAfv75Z3399dfX3Z4KFSqoU6dO9sfly5dX3bp19euvvzrV+/1UsMDAQIWEhDjVK8zw4cPt/y9TpowefPBB5ebmaseOHS63c8uWLQoMDHRazGfgwIEKDAx06E9JioyMdHjcqVMnBQUFOWScbf3eo0cPl9vhqtTUVJ05c0YPPvig07YrV65ozJgxWrhwocaPH68uXbpoyJAhev3115Wbm6v58+eb3h6UPq5937j2XUWM8G3EA9+JB3v37tXIkSMVEBCguXPnFvoXUOKBbyMe+EY8aN68uRYuXKgxY8bo+++/17333qtTp0451fPleEAiooS1bNlS1apVcxj0H3zwgRo1auR0/1BhatWq5bRgTe3atSVJP/zww3W356abblKZMo6nPSAgwOk+sJtuusnpvsYbbrjBadpTYc9v++kdm5o1a153e0+cOKGaNWs6vYEHBASoZs2aTs91yy23ONWLjo7WRx99pPPnz0u62u/h4eHXXOzl1KlT+uWXXxz+uWLLli2qWLGi2rdv77StUqVKSkhIcFr59y9/+YuaN29uX+gK3oVr3zeufVcRI3wb8cA34sFnn32mIUOGKC8vTwsWLFCjRo0KrUc88G3EA9+IB02bNlVUVJQSEhKUmJioY8eO6fXXX3eq58vxgERECfPz81OPHj302Wef6fTp0zpx4oS++uorlzKekgrNpNsCQ1ELIF1LwUDzZ+sV5Ofn51RmGMZ1P6dtn8Lk5+c79Uthz92rVy9dvHhR27Zts/d7z549r/m699xzjyIjIx3+Fefy5cvavn27OnXqdN2rHFeuXFnnzp27rn3gGbj2vf/adxUxAsQD748HW7Zs0UMPPaT8/Hy98MILRe5DPADxwPvjQUHt27dXUFCQ07oOvh4PypZ2A3xBr1699Morr2jr1q06deqU/P39XZ4CdOLECRmG4XARHz16VNJ/s5/u5MyZM8rJyVFgYKC9zNbe61nUrXr16tqzZ4/y8vIcAktubq5OnDjhtKJsYVq3bq1bb71Vmzdv1i+//KKyZcvaf06rKLNnz77u1WgPHjyos2fPqk2bNoVu37x5s2bOnKmpU6c6/R70kSNHvO43gfFfXPtHJXnvte8qYgQk4oE3x4NPP/1Ujz32mAICAvTyyy9fs13EA0jEA2+NBy+//LKWLVumlJQUh1/IuHz5si5evOjws5wS8YAZERYIDQ1VWFiYtm3bpq1bt6pNmza69dZbXdr3119/VUpKiv3xhQsXtGrVKtWpU6fQn8cpbfn5+fr3v/9tf3z58mUtX75cN954Y5EXmS17+/spYF26dFFOTo5WrlzpUPeNN97QuXPnHO5lK0qZMmXUo0cPpaWladu2bbrzzjudpoYV1KJFC7Vt29bhX3G+++47SVKDBg0K3R4SEqKMjAytWLHCoXzTpk06cOBAsZlYeC6ufe++9l1FjIBEPPDWeJCVlaXRo0erTJkyWrJkSbFfhogHkIgH3hoPatWqpaysLK1evdqhfMWKFcrLy1Pnzp0dyn09HjAjwiK9evXSokWLdPHiRT377LMu71euXDlNnjxZ33zzjW677Ta9/fbbOnnypF588cUSbO0fV6FCBSUlJemnn35SrVq1tH79eu3evVtTp05VUFBQofvY7k3bsmWLqlWrpq5du+ree+/VO++8o+eee07ff/+9GjdurK+//lpr1qxR06ZNde+997rUnp49e2rZsmXasWOHZs6caeah2h07dkySVK1atUK3161bVwMHDtTy5cv18MMPq3Pnzjp8+LBWrVqlhg0batiwYSXSLrgHrn3vvfZdRYyADfHA++LB0qVL9dtvv6lDhw7KyMhQRkaGw/ZatWopPDzc/ph4ABvigffFg27duqldu3ZKTEzUiRMn1LBhQ+3Zs0dr165VZGSk0+03vh4PmBFhkZ49e+rChQv2hVJcddttt2nOnDnauHGj5s2bp6CgIL366qum3r9spuDgYC1cuFA7duzQjBkz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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots(3,4, figsize=(15,10), sharex='col', sharey='row')\n", - "ax = ax.ravel()\n", - "i = 0\n", - "for cell_type in np.sort(experiments_table.cell_type.unique()):\n", - " for binned_depth in np.sort(experiments_table.binned_depth.unique()):\n", - " data = experiments_table[(experiments_table.cell_type==cell_type)&(experiments_table.binned_depth==binned_depth)]\n", - " ax[i].hist(data.depth.values, bins=20)\n", - " ax[i].set_title(cell_type+' - '+str(binned_depth))\n", - " i+=1\n", - "fig.tight_layout()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### The `area_depth` and `area_binned_depth` columns are useful to partition data by area and depth simultaneously" - ] - }, - { - "cell_type": "code", - "execution_count": 71, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots()\n", - "area_binned_depth = np.sort(experiments_table.area_binned_depth.unique())\n", - "sns.pointplot(data=experiments_table, x='area_binned_depth', y='imaging_depth', hue='cell_type', \n", - " order=area_binned_depth, join=False, dodge=0.5)\n", - "ax.set_xticklabels(area_binned_depth, rotation=90);\n", - "ax.legend(bbox_to_anchor=(1,1))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "visual_behavior_sdk", - "language": "python", - "name": "visual_behavior_sdk" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/notebooks/211008_validate_filtering_criteria_and_check_exposure_number.ipynb b/notebooks/211008_validate_filtering_criteria_and_check_exposure_number.ipynb deleted file mode 100644 index 98c7dad4b..000000000 --- a/notebooks/211008_validate_filtering_criteria_and_check_exposure_number.ipynb +++ /dev/null @@ -1,3681 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt\n", - "\n", - "import seaborn as sns\n", - "sns.set_context('notebook', font_scale=1.5, rc={'lines.markeredgewidth': 2})" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext autoreload\n", - "%autoreload 2\n", - "\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "from visual_behavior.data_access import loading as loading\n", - "from visual_behavior.data_access import utilities \n", - "\n", - "from allensdk.brain_observatory.behavior.behavior_project_cache import VisualBehaviorOphysProjectCache" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### get experiment and cell tables" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "experiments_table = loading.get_platform_paper_experiment_table()\n", - "cells_table = loading.get_cell_table()" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "ophys_experiment_id\n", - "775614751 20181108\n", - "778644591 20181113\n", - "788490510 20181129\n", - "796106850 20181215\n", - "792815735 20181210\n", - " ... \n", - "1086910729 20210225\n", - "1087430659 20210301\n", - "1087825608 20210303\n", - "1088351118 20210305\n", - "1088916626 20210308\n", - "Name: date, Length: 1249, dtype: int64" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# make sure date string column is there\n", - "experiments_table.date" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### look at columns for filtering and make sure they make sense" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "df = experiments_table.copy()" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
session_typedate_of_acquisitiondateexperience_leveln_relative_to_first_novelfirst_novelsecond_novelsecond_novel_activelast_familiarlast_familiar_activeprior_exposures_to_image_set
ophys_experiment_id
962473290OPHYS_1_images_B2019-10-07 16:54:33.00000020191007Familiar-4.0FalseFalseFalseFalseFalse18.0
963394065OPHYS_1_images_B2019-10-08 16:36:06.00000020191008Familiar-3.0FalseFalseFalseFalseFalse19.0
964955813OPHYS_2_images_B_passive2019-10-09 17:34:04.00000020191009Familiar-2.0FalseFalseFalseFalseFalse20.0
965231035OPHYS_3_images_B2019-10-10 18:03:17.00000020191010Familiar-1.0FalseFalseFalseTrueTrue21.0
967007328OPHYS_4_images_A2019-10-14 15:15:27.00000020191014Novel 10.0TrueFalseFalseFalseFalse0.0
967877560OPHYS_5_images_A_passive2019-10-15 16:40:48.00000020191015Novel >11.0FalseTrueFalseFalseFalse1.0
969807132OPHYS_6_images_A2019-10-17 15:01:11.00000020191017Novel >12.0FalseFalseTrueFalseFalse3.0
\n", - "
" - ], - "text/plain": [ - " session_type date_of_acquisition \\\n", - "ophys_experiment_id \n", - "962473290 OPHYS_1_images_B 2019-10-07 16:54:33.000000 \n", - "963394065 OPHYS_1_images_B 2019-10-08 16:36:06.000000 \n", - "964955813 OPHYS_2_images_B_passive 2019-10-09 17:34:04.000000 \n", - "965231035 OPHYS_3_images_B 2019-10-10 18:03:17.000000 \n", - "967007328 OPHYS_4_images_A 2019-10-14 15:15:27.000000 \n", - "967877560 OPHYS_5_images_A_passive 2019-10-15 16:40:48.000000 \n", - "969807132 OPHYS_6_images_A 2019-10-17 15:01:11.000000 \n", - "\n", - " date experience_level n_relative_to_first_novel \\\n", - "ophys_experiment_id \n", - "962473290 20191007 Familiar -4.0 \n", - "963394065 20191008 Familiar -3.0 \n", - "964955813 20191009 Familiar -2.0 \n", - "965231035 20191010 Familiar -1.0 \n", - "967007328 20191014 Novel 1 0.0 \n", - "967877560 20191015 Novel >1 1.0 \n", - "969807132 20191017 Novel >1 2.0 \n", - "\n", - " first_novel second_novel second_novel_active \\\n", - "ophys_experiment_id \n", - "962473290 False False False \n", - "963394065 False False False \n", - "964955813 False False False \n", - "965231035 False False False \n", - "967007328 True False False \n", - "967877560 False True False \n", - "969807132 False False True \n", - "\n", - " last_familiar last_familiar_active \\\n", - "ophys_experiment_id \n", - "962473290 False False \n", - "963394065 False False \n", - "964955813 False False \n", - "965231035 True True \n", - "967007328 False False \n", - "967877560 False False \n", - "969807132 False False \n", - "\n", - " prior_exposures_to_image_set \n", - "ophys_experiment_id \n", - "962473290 18.0 \n", - "963394065 19.0 \n", - "964955813 20.0 \n", - "965231035 21.0 \n", - "967007328 0.0 \n", - "967877560 1.0 \n", - "969807132 3.0 " - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df[df.ophys_container_id==df.ophys_container_id.unique()[30]][['session_type', 'date_of_acquisition', 'date', \n", - " 'experience_level', 'n_relative_to_first_novel', 'first_novel', \n", - " 'second_novel', 'second_novel_active', \n", - " 'last_familiar', 'last_familiar_active', 'prior_exposures_to_image_set']]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## evaluate different filtering steps on cells table" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### limit to containers with 3 exp levels" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "df = utilities.limit_to_containers_with_all_experience_levels(cells_table)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
experience_levelcell_specimen_idophys_experiment_idequipment_namefull_genotypemouse_idreporter_linedriver_linesexage_in_days...area_deptharea_binned_depthdatefirst_noveln_relative_to_first_novellast_familiarlast_familiar_activesecond_novelsecond_novel_activeexperience_exposure
ophys_container_id
7913524333333333333...3333333333
8035175293333333333...3333333333
8035894373333333333...3333333333
8128587553333333333...3333333333
8147966123333333333...3333333333
..................................................................
10790281263333333333...3333333333
10802846713333333333...3333333333
10816837013333333333...3333333333
10842302373333333333...3333333333
10842302513333333333...3333333333
\n", - "

152 rows × 39 columns

\n", - "
" - ], - "text/plain": [ - " experience_level cell_specimen_id ophys_experiment_id \\\n", - "ophys_container_id \n", - "791352433 3 3 3 \n", - "803517529 3 3 3 \n", - "803589437 3 3 3 \n", - "812858755 3 3 3 \n", - "814796612 3 3 3 \n", - "... ... ... ... \n", - "1079028126 3 3 3 \n", - "1080284671 3 3 3 \n", - "1081683701 3 3 3 \n", - "1084230237 3 3 3 \n", - "1084230251 3 3 3 \n", - "\n", - " equipment_name full_genotype mouse_id reporter_line \\\n", - "ophys_container_id \n", - "791352433 3 3 3 3 \n", - "803517529 3 3 3 3 \n", - "803589437 3 3 3 3 \n", - "812858755 3 3 3 3 \n", - "814796612 3 3 3 3 \n", - "... ... ... ... ... \n", - "1079028126 3 3 3 3 \n", - "1080284671 3 3 3 3 \n", - "1081683701 3 3 3 3 \n", - "1084230237 3 3 3 3 \n", - "1084230251 3 3 3 3 \n", - "\n", - " driver_line sex age_in_days ... area_depth \\\n", - "ophys_container_id ... \n", - "791352433 3 3 3 ... 3 \n", - "803517529 3 3 3 ... 3 \n", - "803589437 3 3 3 ... 3 \n", - "812858755 3 3 3 ... 3 \n", - "814796612 3 3 3 ... 3 \n", - "... ... ... ... ... ... \n", - "1079028126 3 3 3 ... 3 \n", - "1080284671 3 3 3 ... 3 \n", - "1081683701 3 3 3 ... 3 \n", - "1084230237 3 3 3 ... 3 \n", - "1084230251 3 3 3 ... 3 \n", - "\n", - " area_binned_depth date first_novel \\\n", - "ophys_container_id \n", - "791352433 3 3 3 \n", - "803517529 3 3 3 \n", - "803589437 3 3 3 \n", - "812858755 3 3 3 \n", - "814796612 3 3 3 \n", - "... ... ... ... \n", - "1079028126 3 3 3 \n", - "1080284671 3 3 3 \n", - "1081683701 3 3 3 \n", - "1084230237 3 3 3 \n", - "1084230251 3 3 3 \n", - "\n", - " n_relative_to_first_novel last_familiar \\\n", - "ophys_container_id \n", - "791352433 3 3 \n", - "803517529 3 3 \n", - "803589437 3 3 \n", - "812858755 3 3 \n", - "814796612 3 3 \n", - "... ... ... \n", - "1079028126 3 3 \n", - "1080284671 3 3 \n", - "1081683701 3 3 \n", - "1084230237 3 3 \n", - "1084230251 3 3 \n", - "\n", - " last_familiar_active second_novel second_novel_active \\\n", - "ophys_container_id \n", - "791352433 3 3 3 \n", - "803517529 3 3 3 \n", - "803589437 3 3 3 \n", - "812858755 3 3 3 \n", - "814796612 3 3 3 \n", - "... ... ... ... \n", - "1079028126 3 3 3 \n", - "1080284671 3 3 3 \n", - "1081683701 3 3 3 \n", - "1084230237 3 3 3 \n", - "1084230251 3 3 3 \n", - "\n", - " experience_exposure \n", - "ophys_container_id \n", - "791352433 3 \n", - "803517529 3 \n", - "803589437 3 \n", - "812858755 3 \n", - "814796612 3 \n", - "... ... \n", - "1079028126 3 \n", - "1080284671 3 \n", - "1081683701 3 \n", - "1084230237 3 \n", - "1084230251 3 \n", - "\n", - "[152 rows x 39 columns]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['ophys_container_id', 'experience_level']).count().reset_index().groupby(['ophys_container_id']).count()" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([3], dtype=int64)" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['ophys_container_id', 'experience_level']).count().reset_index().groupby(['ophys_container_id']).count().experience_level.unique()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are only 3 experience levels per container" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### count number of experiments and cells" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar362277115268
Novel 13671719225
Novel >1361427111962
Sst InhibitoryFamiliar1511537598
Novel 1153737414
Novel >1158537548
Vip InhibitoryFamiliar17138441233
Novel 1174444742
Novel >11796441067
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 36 227 \n", - " Novel 1 36 71 \n", - " Novel >1 36 142 \n", - "Sst Inhibitory Familiar 15 115 \n", - " Novel 1 15 37 \n", - " Novel >1 15 85 \n", - "Vip Inhibitory Familiar 17 138 \n", - " Novel 1 17 44 \n", - " Novel >1 17 96 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 71 15268 \n", - " Novel 1 71 9225 \n", - " Novel >1 71 11962 \n", - "Sst Inhibitory Familiar 37 598 \n", - " Novel 1 37 414 \n", - " Novel >1 37 548 \n", - "Vip Inhibitory Familiar 44 1233 \n", - " Novel 1 44 742 \n", - " Novel >1 44 1067 " - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "utilities.count_mice_expts_containers_cells(df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are many more cells and experiments for Familiar and Novel >1 because each container can have multiple of each of those. There is only one Novel 1 session per container by definition." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### limit to last familiar and second novel active" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This should make the numbers of experiments and cells for each container more similar" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "df = utilities.limit_to_last_familiar_second_novel_active(cells_table)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
experience_levelcell_specimen_idophys_experiment_idequipment_namefull_genotypemouse_idreporter_linedriver_linesexage_in_days...area_deptharea_binned_depthdatefirst_noveln_relative_to_first_novellast_familiarlast_familiar_activesecond_novelsecond_novel_activeexperience_exposure
ophys_container_id
7913524333333333333...3333333333
8035175293333333333...3333333333
8035894373333333333...3333333333
8128587552222222222...2222222222
8147966123333333333...3333333333
..................................................................
10790281263333333333...3333333333
10802846713333333333...3333333333
10816837013333333333...3333333333
10842302373333333333...3333333333
10842302513333333333...3333333333
\n", - "

155 rows × 39 columns

\n", - "
" - ], - "text/plain": [ - " experience_level cell_specimen_id ophys_experiment_id \\\n", - "ophys_container_id \n", - "791352433 3 3 3 \n", - "803517529 3 3 3 \n", - "803589437 3 3 3 \n", - "812858755 2 2 2 \n", - "814796612 3 3 3 \n", - "... ... ... ... \n", - "1079028126 3 3 3 \n", - "1080284671 3 3 3 \n", - "1081683701 3 3 3 \n", - "1084230237 3 3 3 \n", - "1084230251 3 3 3 \n", - "\n", - " equipment_name full_genotype mouse_id reporter_line \\\n", - "ophys_container_id \n", - "791352433 3 3 3 3 \n", - "803517529 3 3 3 3 \n", - "803589437 3 3 3 3 \n", - "812858755 2 2 2 2 \n", - "814796612 3 3 3 3 \n", - "... ... ... ... ... \n", - "1079028126 3 3 3 3 \n", - "1080284671 3 3 3 3 \n", - "1081683701 3 3 3 3 \n", - "1084230237 3 3 3 3 \n", - "1084230251 3 3 3 3 \n", - "\n", - " driver_line sex age_in_days ... area_depth \\\n", - "ophys_container_id ... \n", - "791352433 3 3 3 ... 3 \n", - "803517529 3 3 3 ... 3 \n", - "803589437 3 3 3 ... 3 \n", - "812858755 2 2 2 ... 2 \n", - "814796612 3 3 3 ... 3 \n", - "... ... ... ... ... ... \n", - "1079028126 3 3 3 ... 3 \n", - "1080284671 3 3 3 ... 3 \n", - "1081683701 3 3 3 ... 3 \n", - "1084230237 3 3 3 ... 3 \n", - "1084230251 3 3 3 ... 3 \n", - "\n", - " area_binned_depth date first_novel \\\n", - "ophys_container_id \n", - "791352433 3 3 3 \n", - "803517529 3 3 3 \n", - "803589437 3 3 3 \n", - "812858755 2 2 2 \n", - "814796612 3 3 3 \n", - "... ... ... ... \n", - "1079028126 3 3 3 \n", - "1080284671 3 3 3 \n", - "1081683701 3 3 3 \n", - "1084230237 3 3 3 \n", - "1084230251 3 3 3 \n", - "\n", - " n_relative_to_first_novel last_familiar \\\n", - "ophys_container_id \n", - "791352433 3 3 \n", - "803517529 3 3 \n", - "803589437 3 3 \n", - "812858755 2 2 \n", - "814796612 3 3 \n", - "... ... ... \n", - "1079028126 3 3 \n", - "1080284671 3 3 \n", - "1081683701 3 3 \n", - "1084230237 3 3 \n", - "1084230251 3 3 \n", - "\n", - " last_familiar_active second_novel second_novel_active \\\n", - "ophys_container_id \n", - "791352433 3 3 3 \n", - "803517529 3 3 3 \n", - "803589437 3 3 3 \n", - "812858755 2 2 2 \n", - "814796612 3 3 3 \n", - "... ... ... ... \n", - "1079028126 3 3 3 \n", - "1080284671 3 3 3 \n", - "1081683701 3 3 3 \n", - "1084230237 3 3 3 \n", - "1084230251 3 3 3 \n", - "\n", - " experience_exposure \n", - "ophys_container_id \n", - "791352433 3 \n", - "803517529 3 \n", - "803589437 3 \n", - "812858755 2 \n", - "814796612 3 \n", - "... ... \n", - "1079028126 3 \n", - "1080284671 3 \n", - "1081683701 3 \n", - "1084230237 3 \n", - "1084230251 3 \n", - "\n", - "[155 rows x 39 columns]" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['ophys_container_id', 'experience_level']).count().reset_index().groupby(['ophys_container_id']).count()" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([3, 2], dtype=int64)" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['ophys_container_id', 'experience_level']).count().reset_index().groupby(['ophys_container_id']).count().experience_level.unique()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are some containers with only 2 experience levels, which means they are missing a Novel 1 session because we already filtered to select for the last Familiar and second Novel session, so we need to filter again to ensure we only have containers with all 3" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### limit to last familiar and second novel active, and limit to containers with all 3 experience levels" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "its important to limit to last familiar and second novel active first, so that limiting to 3 experience levels only considers the last familiar and second novel active sessions" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "df = utilities.limit_to_last_familiar_second_novel_active(cells_table) # important that this goes first\n", - "df = utilities.limit_to_containers_with_all_experience_levels(df)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([3], dtype=int64)" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['ophys_container_id', 'experience_level']).count().reset_index().groupby(['ophys_container_id']).count().experience_level.unique()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are only 3 experience levels per container" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There should only be 1 experiment per experience level" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1], dtype=int64)" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['ophys_container_id', 'experience_level', 'ophys_experiment_id']).count().reset_index().groupby(['ophys_container_id', 'experience_level']).count().ophys_experiment_id.unique()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### count numbers of expts and cells" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There should be the same number of experiments for each experience level, and a similar number of cells" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar3462627302
Novel 13462627974
Novel >13462627404
Sst InhibitoryFamiliar153030321
Novel 1153030337
Novel >1153030320
Vip InhibitoryFamiliar174242794
Novel 1174242718
Novel >1174242765
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 34 62 \n", - " Novel 1 34 62 \n", - " Novel >1 34 62 \n", - "Sst Inhibitory Familiar 15 30 \n", - " Novel 1 15 30 \n", - " Novel >1 15 30 \n", - "Vip Inhibitory Familiar 17 42 \n", - " Novel 1 17 42 \n", - " Novel >1 17 42 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 62 7302 \n", - " Novel 1 62 7974 \n", - " Novel >1 62 7404 \n", - "Sst Inhibitory Familiar 30 321 \n", - " Novel 1 30 337 \n", - " Novel >1 30 320 \n", - "Vip Inhibitory Familiar 42 794 \n", - " Novel 1 42 718 \n", - " Novel >1 42 765 " - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "utilities.count_mice_expts_containers_cells(df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### limit to cells matched in all 3 experience levels, including any Familiar or Novel >1 session " - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "df = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(cells_table)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar36226715695
Novel 13671715695
Novel >136142715695
Sst InhibitoryFamiliar1511236292
Novel 1153636292
Novel >1158436292
Vip InhibitoryFamiliar1713744540
Novel 1174444540
Novel >1179644540
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 36 226 \n", - " Novel 1 36 71 \n", - " Novel >1 36 142 \n", - "Sst Inhibitory Familiar 15 112 \n", - " Novel 1 15 36 \n", - " Novel >1 15 84 \n", - "Vip Inhibitory Familiar 17 137 \n", - " Novel 1 17 44 \n", - " Novel >1 17 96 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 71 5695 \n", - " Novel 1 71 5695 \n", - " Novel >1 71 5695 \n", - "Sst Inhibitory Familiar 36 292 \n", - " Novel 1 36 292 \n", - " Novel >1 36 292 \n", - "Vip Inhibitory Familiar 44 540 \n", - " Novel 1 44 540 \n", - " Novel >1 44 540 " - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "utilities.count_mice_expts_containers_cells(df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are the same number of cell_specimen_ids for each experience level, but different numbers of experiment_ids, because we considered any Familiar or Novel >1 as a candidate for a match" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([3], dtype=int64)" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['ophys_container_id', 'experience_level']).count().reset_index().groupby(['ophys_container_id']).count().experience_level.unique()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are always 3 experience levels per container" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([3, 1, 2, 4, 6, 5], dtype=int64)" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['ophys_container_id', 'experience_level', 'ophys_experiment_id']).count().reset_index().groupby(['ophys_container_id', 'experience_level']).count().ophys_experiment_id.unique()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "But can be more than one experiment per experience level" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### limit to cells matched in all 3 experience levels, only considering last Familiar and second Novel active" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "df = utilities.limit_to_last_familiar_second_novel_active(cells_table) # important that this goes first\n", - "df = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(df)" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar3462623306
Novel 13462623306
Novel >13462623306
Sst InhibitoryFamiliar142828200
Novel 1142828200
Novel >1142828200
Vip InhibitoryFamiliar174141415
Novel 1174141415
Novel >1174141415
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 34 62 \n", - " Novel 1 34 62 \n", - " Novel >1 34 62 \n", - "Sst Inhibitory Familiar 14 28 \n", - " Novel 1 14 28 \n", - " Novel >1 14 28 \n", - "Vip Inhibitory Familiar 17 41 \n", - " Novel 1 17 41 \n", - " Novel >1 17 41 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 62 3306 \n", - " Novel 1 62 3306 \n", - " Novel >1 62 3306 \n", - "Sst Inhibitory Familiar 28 200 \n", - " Novel 1 28 200 \n", - " Novel >1 28 200 \n", - "Vip Inhibitory Familiar 41 415 \n", - " Novel 1 41 415 \n", - " Novel >1 41 415 " - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "utilities.count_mice_expts_containers_cells(df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now the number of cell_specimen_ids AND the number of experiment_ids are the same across all 3 experience levels, because we have limited to only the last Familiar and first Novel active sessions" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([3], dtype=int64)" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['ophys_container_id', 'experience_level']).count().reset_index().groupby(['ophys_container_id']).count().experience_level.unique()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are 3 experience levels per container" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1], dtype=int64)" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['ophys_container_id', 'experience_level', 'ophys_experiment_id']).count().reset_index().groupby(['ophys_container_id', 'experience_level']).count().ophys_experiment_id.unique()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And only one experiment per experience level per container" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### This is the most conservative set of experiments and cells - matched cells across experience levels, only considering the most recent Familiar and Novel >1 sessions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### What is the number of image set exposures when we limit to last familiar and second novel active?" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "df = utilities.limit_to_last_familiar_second_novel_active(cells_table) # important that this goes first\n", - "df = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(df)" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
prior_exposures_to_image_set
countmeanstdmin25%50%75%max
cell_typeexperience_level
ExcitatoryFamiliar22.028.63636414.25798210.017.0027.535.2559.0
Novel 11.00.000000NaN0.00.000.00.000.0
Novel >14.02.5000001.2909941.01.752.53.254.0
Sst InhibitoryFamiliar13.030.92307716.37814410.018.0029.042.0068.0
Novel 11.00.000000NaN0.00.000.00.000.0
Novel >13.02.0000001.0000001.01.502.02.503.0
Vip InhibitoryFamiliar15.031.40000015.39387611.019.0026.046.5053.0
Novel 11.00.000000NaN0.00.000.00.000.0
Novel >14.03.0000002.1602471.01.752.53.756.0
\n", - "
" - ], - "text/plain": [ - " prior_exposures_to_image_set \\\n", - " count mean \n", - "cell_type experience_level \n", - "Excitatory Familiar 22.0 28.636364 \n", - " Novel 1 1.0 0.000000 \n", - " Novel >1 4.0 2.500000 \n", - "Sst Inhibitory Familiar 13.0 30.923077 \n", - " Novel 1 1.0 0.000000 \n", - " Novel >1 3.0 2.000000 \n", - "Vip Inhibitory Familiar 15.0 31.400000 \n", - " Novel 1 1.0 0.000000 \n", - " Novel >1 4.0 3.000000 \n", - "\n", - " \n", - " std min 25% 50% 75% max \n", - "cell_type experience_level \n", - "Excitatory Familiar 14.257982 10.0 17.00 27.5 35.25 59.0 \n", - " Novel 1 NaN 0.0 0.00 0.0 0.00 0.0 \n", - " Novel >1 1.290994 1.0 1.75 2.5 3.25 4.0 \n", - "Sst Inhibitory Familiar 16.378144 10.0 18.00 29.0 42.00 68.0 \n", - " Novel 1 NaN 0.0 0.00 0.0 0.00 0.0 \n", - " Novel >1 1.000000 1.0 1.50 2.0 2.50 3.0 \n", - "Vip Inhibitory Familiar 15.393876 11.0 19.00 26.0 46.50 53.0 \n", - " Novel 1 NaN 0.0 0.00 0.0 0.00 0.0 \n", - " Novel >1 2.160247 1.0 1.75 2.5 3.75 6.0 " - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['cell_type', 'experience_level', 'prior_exposures_to_image_set']).mean().reset_index().groupby(['cell_type', 'experience_level']).describe()[['prior_exposures_to_image_set']]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "* For Excitatory cells, the average exposure number for Novel >1 is 2.5, with a std of 1.3\n", - "* For Sst cells, the average exposure number for Novel >1 is 2 with a std of 1\n", - "* For Vip cells, the average exposure number for Novel >1 is 3 with a std of 2.16" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### What if we dont limit to active sessions? " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### What is the number of image set exposures when we limit to last familiar and second novel, including passive sessions?" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "df = utilities.limit_to_last_familiar_second_novel(cells_table) # important that this goes first\n", - "df = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(df)" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
prior_exposures_to_image_set
countmeanstdmin25%50%75%max
cell_typeexperience_level
ExcitatoryFamiliar24.027.79166714.2553709.015.7526.034.5059.0
Novel 11.00.000000NaN0.00.000.00.000.0
Novel >13.02.3333331.5275251.01.502.03.004.0
Sst InhibitoryFamiliar15.032.66666718.14885511.018.5029.043.5068.0
Novel 11.00.000000NaN0.00.000.00.000.0
Novel >12.01.5000000.7071071.01.251.51.752.0
Vip InhibitoryFamiliar16.030.43750015.79860211.017.5024.545.2554.0
Novel 11.00.000000NaN0.00.000.00.000.0
Novel >13.02.0000001.0000001.01.502.02.503.0
\n", - "
" - ], - "text/plain": [ - " prior_exposures_to_image_set \\\n", - " count mean \n", - "cell_type experience_level \n", - "Excitatory Familiar 24.0 27.791667 \n", - " Novel 1 1.0 0.000000 \n", - " Novel >1 3.0 2.333333 \n", - "Sst Inhibitory Familiar 15.0 32.666667 \n", - " Novel 1 1.0 0.000000 \n", - " Novel >1 2.0 1.500000 \n", - "Vip Inhibitory Familiar 16.0 30.437500 \n", - " Novel 1 1.0 0.000000 \n", - " Novel >1 3.0 2.000000 \n", - "\n", - " \n", - " std min 25% 50% 75% max \n", - "cell_type experience_level \n", - "Excitatory Familiar 14.255370 9.0 15.75 26.0 34.50 59.0 \n", - " Novel 1 NaN 0.0 0.00 0.0 0.00 0.0 \n", - " Novel >1 1.527525 1.0 1.50 2.0 3.00 4.0 \n", - "Sst Inhibitory Familiar 18.148855 11.0 18.50 29.0 43.50 68.0 \n", - " Novel 1 NaN 0.0 0.00 0.0 0.00 0.0 \n", - " Novel >1 0.707107 1.0 1.25 1.5 1.75 2.0 \n", - "Vip Inhibitory Familiar 15.798602 11.0 17.50 24.5 45.25 54.0 \n", - " Novel 1 NaN 0.0 0.00 0.0 0.00 0.0 \n", - " Novel >1 1.000000 1.0 1.50 2.0 2.50 3.0 " - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['cell_type', 'experience_level', 'prior_exposures_to_image_set']).mean().reset_index().groupby(['cell_type', 'experience_level']).describe()[['prior_exposures_to_image_set']]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "* For Excitatory cells, the average exposure number for Novel >1 is 2.3, with a std of 1.5\n", - "* For Sst cells, the average exposure number for Novel >1 is 1.5 with a std of 0.7\n", - "* For Vip cells, the average exposure number for Novel >1 is 2 with a std of 1" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Quantify exposure numbers per experience level for full dataset" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First limit to containers with all experience levels so we dont consider containers without a first Novel session" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [], - "source": [ - "df = utilities.limit_to_containers_with_all_experience_levels(cells_table)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that there can be more than one experiment per experience level in this scenario" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
prior_exposures_to_image_set
countmeanstdmin25%50%75%max
cell_typeexperience_level
ExcitatoryFamiliar39.029.38461514.8547628.017.5028.037.5059.0
Novel 11.00.000000NaN0.00.000.00.000.0
Novel >16.03.5000001.8708291.02.253.54.756.0
Sst InhibitoryFamiliar36.032.80555618.1025969.018.7528.543.5069.0
Novel 11.00.000000NaN0.00.000.00.000.0
Novel >16.03.5000001.8708291.02.253.54.756.0
Vip InhibitoryFamiliar32.031.00000015.04616610.017.7526.546.2554.0
Novel 11.00.000000NaN0.00.000.00.000.0
Novel >17.04.0000002.1602471.02.504.05.507.0
\n", - "
" - ], - "text/plain": [ - " prior_exposures_to_image_set \\\n", - " count mean \n", - "cell_type experience_level \n", - "Excitatory Familiar 39.0 29.384615 \n", - " Novel 1 1.0 0.000000 \n", - " Novel >1 6.0 3.500000 \n", - "Sst Inhibitory Familiar 36.0 32.805556 \n", - " Novel 1 1.0 0.000000 \n", - " Novel >1 6.0 3.500000 \n", - "Vip Inhibitory Familiar 32.0 31.000000 \n", - " Novel 1 1.0 0.000000 \n", - " Novel >1 7.0 4.000000 \n", - "\n", - " \n", - " std min 25% 50% 75% max \n", - "cell_type experience_level \n", - "Excitatory Familiar 14.854762 8.0 17.50 28.0 37.50 59.0 \n", - " Novel 1 NaN 0.0 0.00 0.0 0.00 0.0 \n", - " Novel >1 1.870829 1.0 2.25 3.5 4.75 6.0 \n", - "Sst Inhibitory Familiar 18.102596 9.0 18.75 28.5 43.50 69.0 \n", - " Novel 1 NaN 0.0 0.00 0.0 0.00 0.0 \n", - " Novel >1 1.870829 1.0 2.25 3.5 4.75 6.0 \n", - "Vip Inhibitory Familiar 15.046166 10.0 17.75 26.5 46.25 54.0 \n", - " Novel 1 NaN 0.0 0.00 0.0 0.00 0.0 \n", - " Novel >1 2.160247 1.0 2.50 4.0 5.50 7.0 " - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['cell_type', 'experience_level', 'prior_exposures_to_image_set']).mean().reset_index().groupby(['cell_type', 'experience_level']).describe()[['prior_exposures_to_image_set']]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "* For Excitatory cells, the average exposure number for Novel >1 is 3.5, with a std of 1.8\n", - "* For Sst cells, the average exposure number for Novel >1 is 3.5 with a std of 1.8\n", - "* For Vip cells, the average exposure number for Novel >1 is 4 with a std of 2.16" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Limit to containers with all 3 experience levels, where the Novel >1 session is the second exposure to novelty" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [], - "source": [ - "df = utilities.limit_to_containers_with_all_experience_levels(cells_table)" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [], - "source": [ - "df = utilities.limit_to_second_novel_exposure(df)" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [], - "source": [ - "# # code moved to utilities, but this is what id does to limit to second exposure\n", - "# # drop novel >1 sessions that arent the second exposure (prior exposures = 1)\n", - "# indices = df[(df.experience_level == 'Novel >1') & (df.prior_exposures_to_image_set != 1)].index.values\n", - "# df = df.drop(labels=indices, axis=0)" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "# now limit to last familiar second novel and cells matched in all 3\n", - "df = utilities.limit_to_last_familiar_second_novel(df) # important that this goes first\n", - "df = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(df)" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar2556562925
Novel 12556562925
Novel >12556562925
Sst InhibitoryFamiliar132323127
Novel 1132323127
Novel >1132323127
Vip InhibitoryFamiliar153636378
Novel 1153636378
Novel >1153636378
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 25 56 \n", - " Novel 1 25 56 \n", - " Novel >1 25 56 \n", - "Sst Inhibitory Familiar 13 23 \n", - " Novel 1 13 23 \n", - " Novel >1 13 23 \n", - "Vip Inhibitory Familiar 15 36 \n", - " Novel 1 15 36 \n", - " Novel >1 15 36 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 56 2925 \n", - " Novel 1 56 2925 \n", - " Novel >1 56 2925 \n", - "Sst Inhibitory Familiar 23 127 \n", - " Novel 1 23 127 \n", - " Novel >1 23 127 \n", - "Vip Inhibitory Familiar 36 378 \n", - " Novel 1 36 378 \n", - " Novel >1 36 378 " - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "utilities.count_mice_expts_containers_cells(df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we get way fewer cells. But we can still quantify our effects here to be sure that prior exposures does not have a major effect" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Compare to when we allow Novel >1 to be any exposure number, including passive sessions" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [], - "source": [ - "df = utilities.limit_to_last_familiar_second_novel(cells_table) # important that this goes first\n", - "df = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(df)" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar3467673672
Novel 13467673672
Novel >13467673672
Sst InhibitoryFamiliar153131214
Novel 1153131214
Novel >1153131214
Vip InhibitoryFamiliar174343447
Novel 1174343447
Novel >1174343447
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 34 67 \n", - " Novel 1 34 67 \n", - " Novel >1 34 67 \n", - "Sst Inhibitory Familiar 15 31 \n", - " Novel 1 15 31 \n", - " Novel >1 15 31 \n", - "Vip Inhibitory Familiar 17 43 \n", - " Novel 1 17 43 \n", - " Novel >1 17 43 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 67 3672 \n", - " Novel 1 67 3672 \n", - " Novel >1 67 3672 \n", - "Sst Inhibitory Familiar 31 214 \n", - " Novel 1 31 214 \n", - " Novel >1 31 214 \n", - "Vip Inhibitory Familiar 43 447 \n", - " Novel 1 43 447 \n", - " Novel >1 43 447 " - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "utilities.count_mice_expts_containers_cells(df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### What do we get if we require that Novel >1 is the second exposure and is an active session? " - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [], - "source": [ - "df = utilities.limit_to_containers_with_all_experience_levels(cells_table)" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [], - "source": [ - "# drop novel >1 sessions that arent the second exposure (prior exposures = 1)\n", - "indices = df[(df.experience_level == 'Novel >1') & (df.prior_exposures_to_image_set != 1)].index.values\n", - "df = df.drop(labels=indices, axis=0)" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [], - "source": [ - "df = utilities.limit_to_last_familiar_second_novel_active(df) # important that this goes first\n", - "df = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(df)" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
n_mouse_idn_ophys_experiment_idn_ophys_container_idn_cell_specimen_id
cell_typeexperience_level
ExcitatoryFamiliar714141015
Novel 1714141015
Novel >1714141015
Sst InhibitoryFamiliar22211
Novel 122211
Novel >122211
Vip InhibitoryFamiliar62020162
Novel 162020162
Novel >162020162
\n", - "
" - ], - "text/plain": [ - " n_mouse_id n_ophys_experiment_id \\\n", - "cell_type experience_level \n", - "Excitatory Familiar 7 14 \n", - " Novel 1 7 14 \n", - " Novel >1 7 14 \n", - "Sst Inhibitory Familiar 2 2 \n", - " Novel 1 2 2 \n", - " Novel >1 2 2 \n", - "Vip Inhibitory Familiar 6 20 \n", - " Novel 1 6 20 \n", - " Novel >1 6 20 \n", - "\n", - " n_ophys_container_id n_cell_specimen_id \n", - "cell_type experience_level \n", - "Excitatory Familiar 14 1015 \n", - " Novel 1 14 1015 \n", - " Novel >1 14 1015 \n", - "Sst Inhibitory Familiar 2 11 \n", - " Novel 1 2 11 \n", - " Novel >1 2 11 \n", - "Vip Inhibitory Familiar 20 162 \n", - " Novel 1 20 162 \n", - " Novel >1 20 162 " - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "utilities.count_mice_expts_containers_cells(df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Surprisingly, there are a good number of Novel >1 experiments that are the second exposure and are active sessions (surprising because a passive session is typically supposed to come after a first novel session)" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cell_specimen_id
cell_typeexperience_levelsession_type
ExcitatoryFamiliarOPHYS_1_images_A25
OPHYS_1_images_B79
OPHYS_3_images_A680
OPHYS_3_images_B231
Novel 1OPHYS_4_images_A310
OPHYS_4_images_B705
Novel >1OPHYS_4_images_A189
OPHYS_4_images_B658
OPHYS_6_images_A121
OPHYS_6_images_B47
Sst InhibitoryFamiliarOPHYS_3_images_B11
Novel 1OPHYS_4_images_A11
Novel >1OPHYS_4_images_A11
Vip InhibitoryFamiliarOPHYS_1_images_A69
OPHYS_3_images_A71
OPHYS_3_images_B22
Novel 1OPHYS_4_images_A22
OPHYS_4_images_B140
Novel >1OPHYS_4_images_A19
OPHYS_4_images_B94
OPHYS_6_images_A3
OPHYS_6_images_B46
\n", - "
" - ], - "text/plain": [ - " cell_specimen_id\n", - "cell_type experience_level session_type \n", - "Excitatory Familiar OPHYS_1_images_A 25\n", - " OPHYS_1_images_B 79\n", - " OPHYS_3_images_A 680\n", - " OPHYS_3_images_B 231\n", - " Novel 1 OPHYS_4_images_A 310\n", - " OPHYS_4_images_B 705\n", - " Novel >1 OPHYS_4_images_A 189\n", - " OPHYS_4_images_B 658\n", - " OPHYS_6_images_A 121\n", - " OPHYS_6_images_B 47\n", - "Sst Inhibitory Familiar OPHYS_3_images_B 11\n", - " Novel 1 OPHYS_4_images_A 11\n", - " Novel >1 OPHYS_4_images_A 11\n", - "Vip Inhibitory Familiar OPHYS_1_images_A 69\n", - " OPHYS_3_images_A 71\n", - " OPHYS_3_images_B 22\n", - " Novel 1 OPHYS_4_images_A 22\n", - " OPHYS_4_images_B 140\n", - " Novel >1 OPHYS_4_images_A 19\n", - " OPHYS_4_images_B 94\n", - " OPHYS_6_images_A 3\n", - " OPHYS_6_images_B 46" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(['cell_type', 'experience_level', 'session_type']).count()[['cell_specimen_id']]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "visual_behavior_sdk", - "language": "python", - "name": "visual_behavior_sdk" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/visual_behavior/data_access/loading.py b/visual_behavior/data_access/loading.py index 54b48e0cd..8c6264207 100644 --- a/visual_behavior/data_access/loading.py +++ b/visual_behavior/data_access/loading.py @@ -1193,6 +1193,14 @@ def get_extended_stimulus_presentations_for_session(session): return extended_stimulus_presentations +def get_behavior_model_summary_table(): + data_dir = get_behavior_model_outputs_dir() + data = pd.read_csv(os.path.join(data_dir, '_summary_table.csv')) + data2 = pd.read_csv(os.path.join(data_dir, '_meso_summary_table.csv')) + data = data.append(data2) + return data + + def get_model_output_file(behavior_session_id): model_output_dir = get_behavior_model_outputs_dir() model_output_file = [file for file in os.listdir(model_output_dir) if diff --git a/visual_behavior/decoding_population/anova_tukey.py b/visual_behavior/decoding_population/anova_tukey.py new file mode 100644 index 000000000..17a1cd584 --- /dev/null +++ b/visual_behavior/decoding_population/anova_tukey.py @@ -0,0 +1,230 @@ +""" + +Created on Wed Apr 14 19:10:05 2021 +@author: farzaneh + +""" + +#################################################################################### +#################################################################################### +### ANOVA on response quantifications (image and omission evoked response amplitudes) +#################################################################################### +#################################################################################### + +import numpy as np +import pandas as pd + +import statsmodels.api as sm +from statsmodels.formula.api import ols +from statsmodels.stats.multicomp import (pairwise_tukeyhsd, MultiComparison) + + +def do_anova_tukey(summary_vars_all, crenow, stagenow, inds_v1, inds_lm, inds_pooled): + +# print(f'_______________') +# print(f'\n{crenow}, ophys {stagenow}\n') + + tc = summary_vars_all[summary_vars_all['cre'] == crenow] + tc = tc[tc['stage'] == stagenow] + + pa_all = tc['resp_amp'].values[0] + aa = pa_all[:,:,1] # testing data +# aa.shape # 8 x sessions + + depth_ave = tc['depth_ave'].values[0] + + ############### + cols = ['area', 'depth', 'value', 'idepth'] + + inds_now = inds_v1 + a_data = pd.DataFrame([], columns = cols) + i_at = -1 + for i_depth in range(len(inds_now)): # i_depth=0 + a_now = aa[inds_now[i_depth],:][~np.isnan(aa[inds_now[i_depth]])] +# print(a_now.shape) # number of valid sessions per depth + for i_a in range(len(a_now)): + i_at = i_at+1 + a_data.at[i_at, 'area'] = 'V1' + a_data.at[i_at, 'depth'] = int(depth_ave[i_depth]) + a_data.at[i_at, 'idepth'] = i_depth + a_data.at[i_at, 'value'] = a_now[i_a] + + + if ~np.isnan(inds_lm[0]): + inds_now = inds_lm + for i_depth in range(len(inds_now)): + a_now = aa[inds_now[i_depth],:][~np.isnan(aa[inds_now[i_depth]])] + # print(a_now.shape) # number of valid sessions per depth + for i_a in range(len(a_now)): + i_at = i_at+1 + a_data.at[i_at, 'area'] = 'LM' + a_data.at[i_at, 'depth'] = int(depth_ave[i_depth]) + a_data.at[i_at, 'idepth'] = i_depth + a_data.at[i_at, 'value'] = a_now[i_a] + a_data.at[:,'value'] = a_data['value'].values.astype(float) + + +# if project_codes == ['VisualBehaviorMultiscope']: + inds_now = inds_pooled + for i_depth in range(4): + a_now = aa[inds_now[i_depth],:].flatten()[~np.isnan(aa[inds_now[i_depth]].flatten())] +# print(a_now.shape) # number of valid sessions per depth + for i_a in range(len(a_now)): + i_at = i_at+1 + a_data.at[i_at, 'area'] = 'V1-LM' + a_data.at[i_at, 'depth'] = int(depth_ave[i_depth]) + a_data.at[i_at, 'idepth'] = i_depth + a_data.at[i_at, 'value'] = a_now[i_a] + a_data.at[:,'value'] = a_data['value'].values.astype(float) + a_data + + + + ########### Do anova and tukey for each area + tukey_all = [] +# if project_codes == ['VisualBehaviorMultiscope']: + for ars in ['V1', 'LM', 'V1-LM']: # ars = 'V1' +# print(ars) + a_data_now = a_data[a_data['area'].values==ars] +# a_data_now = a_data + + ### ANOVA + # https://reneshbedre.github.io/blog/anova.html + # https://pythonhealthcare.org/2018/04/13/55-statistics-multi-comparison-with-tukeys-test-and-the-holm-bonferroni-method/ + # https://help.xlstat.com/s/article/how-to-interpret-contradictory-results-between-anova-and-multiple-pairwise-comparisons?language=es + # https://pythonhealthcare.org/2018/04/13/55-statistics-multi-comparison-with-tukeys-test-and-the-holm-bonferroni-method/ + + # Ordinary Least Squares (OLS) model + # 2-way + # C(Genotype):C(years) represent interaction term +# model = ols('value ~ C(area) + C(depth) + C(area):C(depth)', data=a_data).fit() + + # 1-way + model = ols('value ~ C(depth)', data=a_data_now).fit() +# anova_table = sm.stats.anova_lm(model, typ=3) + anova_table = sm.stats.anova_lm(model, typ=2) +# print(anova_table) +# print('\n') + + # scipy anova: same result as above +# a = aa[inds_v1,:] +# fvalue, pvalue = st.f_oneway(a[0][~np.isnan(a[0])], a[1][~np.isnan(a[1])], a[2][~np.isnan(a[2])], a[3][~np.isnan(a[3])]) +# print(fvalue, pvalue) + + + ### TUKEY HSD +# from statsmodels.stats.multicomp import (pairwise_tukeyhsd, MultiComparison) + + # v = a_data['value'] + # f = a_data['depth'] + + v = a_data_now['value'] #a_data['value'] + f = a_data_now['idepth'] #a_data['depth'] +# f = a_data_now['idepth'] # if you want to have depth (instead of depth index) in the summary table use this. it's easier to go with depth index because sometimes some depth are nan and missing, and matching depth is harder than matching depth indices. + + MultiComp = MultiComparison(v, f) +# print(MultiComp.tukeyhsd().summary()) # Show all pair-wise comparisons + + tukey_all.append(MultiComp.tukeyhsd().summary()) + + + return tukey_all + + + + +#################################################################################################### +#################################################################################################### + +def add_tukey_lines(tukey_all, toana, ax, col, inds_v1, inds_lm, inds_pooled, top, top_sd, x_new): + # toana = 'v1', or 'lm', or 'v1-lm' + + # ['V1', 'LM'] this is the order of indices in tukey_all + ''' + if (inds_now == inds_v1).all(): + inds_v1_lm = 0 + elif (inds_now == inds_lm).all(): + inds_v1_lm = 1 + ''' + + if toana == 'v1': + inds_v1_lm = 0 + inds_now = inds_v1 + elif toana == 'lm': + inds_v1_lm = 1 + inds_now = inds_lm + elif toana == 'v1-lm': + inds_v1_lm = 2 + inds_now = range(4) + + + ##### + tukey = tukey_all[inds_v1_lm] +# print(tukey) + + y_new = top[inds_now, 1] + top_sd[inds_now, 1] + mn = np.nanmin(top[:,2]-top_sd[:,2]) + mx = np.nanmax(top[:,1]+top_sd[:,1]) + + t = np.array(tukey.data) +# print(t.shape) + # depth index for group 1 in tukey table + g1inds = np.unique(np.array([t[i][[0,1]] for i in np.arange(1,t.shape[0])]).astype(int)[:,0]) + g2inds = np.unique(np.array([t[i][[0,1]] for i in np.arange(1,t.shape[0])]).astype(int)[:,1]) +# print(g1inds, g2inds) + cnt = 0 + cntr = 0 + for group1_ind in g1inds: #range(3): + for group2_ind in g2inds[g2inds > group1_ind]: #np.arange(group1_ind+1, 4): +# print(group1_ind, group2_ind) + cnt = cnt+1 +# x_new = xnowall[0] # ophys3 + + if tukey.data[cnt][-1] == False: + txtsig = "ns" + else: + txtsig = "*" + cntr = cntr+1 + r = cntr*((mx-mn)/10) + + x1, x2 = x_new[group1_ind], x_new[group2_ind] + y, h, col = np.max([y_new[group1_ind], y_new[group2_ind]]) + r, (mx-mn)/20, col + +# trans = ax.get_xaxis_transform() +# ax.annotate(txtsig, xy=((x1+x2)*.5, y+h), xycoords=trans, ha="center", va='top', color=col) + ax.plot([x1, x1, x2, x2], [y, y+h, y+h, y], lw=1.5, c=col, clip_on=True) #, transform=trans) + ax.text((x1+x2)*.5, y+h, txtsig, ha='center', va='bottom', color=col) + + # plot the line outside, but it didnt work: +# https://stackoverflow.com/questions/47597534/how-to-add-horizontal-lines-as-annotations-outside-of-axes-in-matplotlib + + ylim = ax.get_ylim() + + + return ylim + + + +''' +from statannot import add_stat_annotation + +x = x+xgap +y = top[inds_v1, 1] +tc +add_stat_annotation(ax, data=df, x=x, y=y, order=order, + box_pairs=[("Thur", "Fri"), ("Thur", "Sat"), ("Fri", "Sun")], + test='Mann-Whitney', text_format='star', loc='outside', verbose=2) +''' + + +''' +# heatmap +plt.imshow(top_allstage[:,:,1].T) +plt.colorbar() + +plt.imshow(np.diff(top_allstage[:,:,1], axis=0).T) +plt.colorbar() +''' + + + diff --git a/visual_behavior/decoding_population/anova_tukey_fn.py b/visual_behavior/decoding_population/anova_tukey_fn.py new file mode 100644 index 000000000..be4bfe2f4 --- /dev/null +++ b/visual_behavior/decoding_population/anova_tukey_fn.py @@ -0,0 +1,126 @@ +# Perform Anova (1 way) and pairwise Tukey HSD + +import numpy as np +import pandas as pd +import statsmodels.api as sm +from statsmodels.formula.api import ols +from statsmodels.stats.multicomp import (pairwise_tukeyhsd, MultiComparison) + +def anova_tukey(svm_df, values_stat, label_stat='experience_levels', cres=['Slc17a7', 'Sst', 'Vip'], exp_level_all=['Familiar', 'Novel 1', 'Novel >1']): + +# svm_df is a df which contains the following columns: +# 'cre': identifies mouse cre line +# label_stat: a column that shows the labels which categorize values_stat column +# values_stat: a column with values which we want to do statistics on. +# e.g. use of the code: + ''' + label_stat='experience_levels' + values_stat = 'decoding_magnitude' + anova_all, tukey_all = anova_tukey(svm_df, values_stat, label_stat) + ''' + + anova_all = [] # each index is for 1 cre line, and shows the results of Anova (1 way) across experience levels. + tukey_all = [] # each index is for 1 cre line, and shows the results of pairwise tukey test for experience levels. + +# cres = svm_df['cre'].unique() + + for cre in cres: + + print(f'\n\n----------- Perfoming ANOVA/TUKEY on {cre} -----------\n') + + thiscre = svm_df[svm_df['cre']==cre] + thiscre = thiscre[['cre', label_stat, values_stat]] # only take the relevant columns + + print(thiscre.shape) + + + ############ create dataframe "stats_df", which is suitable for doing anova ############ + + # rename the column that is used for doing anova to "value" + stats_df = thiscre.rename(columns={'decoding_magnitude': 'value'}) + + # only take valid values + stats_df = stats_df[~np.isnan(stats_df['value'])] + print(stats_df.shape) + + # replace Familiar, Novel 1, and Novel >1 in the df with 0, 1, and 2 + cnt = -1 + dfall = pd.DataFrame() + for expl in exp_level_all: + cnt = cnt+1 + dfnow = stats_df[stats_df[label_stat]==expl] + dfnow[label_stat] = [cnt for x in dfnow[label_stat]] + dfall = pd.concat([dfall, dfnow]) + stats_df = dfall + # stats_df + + + ############ ANOVA, 1-way : compare stats_df['value'] across stats_df['experience_levels]' ############ + # model = ols('value ~ C(experience_levels)', data=stats_df).fit() + model = ols('value ~ C(eval(label_stat))', data=stats_df).fit() + anova_table = sm.stats.anova_lm(model, typ=2) + print(anova_table) + print('\n') + + anova_all.append(anova_table) + + + ############ TUKEY HSD : compare stats_df['value'] across pairs of stats_df['experience_levels]' ############ + v = stats_df['value'] + f = stats_df[label_stat] + + MultiComp = MultiComparison(v, f) + tukey_table = MultiComp.tukeyhsd().summary() + + print(tukey_table) # Show all pair-wise comparisons + + tukey_all.append(tukey_table) # cres x 2 (test-shfl ; test) x tukey_table (ie 4 x7) + + + return anova_all, tukey_all + + + + + + +############### Add tukey lines in the plot: if a pariwaise tukey comparison is significant, add a line and an asterisk +## NOTE: the code below needs further refinement! + +def add_tukey_lines_new(ax, df, tukey_all, icre): + + tukey = tukey_all[icre] + y_new = df['test_av']+df['test_sd'] + mn = np.nanmin(df['shfl_av']-df['shfl_sd']) + mx = np.nanmax(df['test_av']+df['test_sd']) + + + t = np.array(tukey.data) + # print(t.shape) + + g1inds = np.unique(np.array([t[i][[0,1]] for i in np.arange(1,t.shape[0])]).astype(int)[:,0]) + g2inds = np.unique(np.array([t[i][[0,1]] for i in np.arange(1,t.shape[0])]).astype(int)[:,1]) + # print(g1inds, g2inds) + + cnt = 0 + cntr = 0 + for group1_ind in g1inds: #range(3): + for group2_ind in g2inds[g2inds > group1_ind]: #np.arange(group1_ind+1, 4): + # print(group1_ind, group2_ind) + cnt = cnt+1 + + if tukey.data[cnt][-1] == False: + txtsig = "ns" + else: + txtsig = "*" + cntr = cntr+1 + r = cntr*((mx-mn)/10) + + x1, x2 = x_new[group1_ind], x_new[group2_ind] + y, h, col = np.max([y_new[group1_ind], y_new[group2_ind]]) + r, (mx-mn)/20, 'k' + + ax.plot([x1, x1, x2, x2], [y, y+h, y+h, y], lw=1.5, c=col, clip_on=True) #, transform=trans) + ax.text((x1+x2)*.5, y+h, txtsig, ha='center', va='bottom', color=col) + + # plot the line outside, but it didnt work: + # https://stackoverflow.com/questions/47597534/how-to-add-horizontal-lines-as-annotations-outside-of-axes-in-matplotlib diff --git a/visual_behavior/decoding_population/general_funs.py b/visual_behavior/decoding_population/general_funs.py new file mode 100644 index 000000000..4c3dfc338 --- /dev/null +++ b/visual_behavior/decoding_population/general_funs.py @@ -0,0 +1,259 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Tue Oct 13 21:23:43 2019 + +@author: farzaneh +""" +''' +from importlib import reload +import x +reload(x) +''' + +import numpy as np +import matplotlib.pyplot as plt + +def set_frame_window_flash_omit(time_win, samps_bef, frame_dur): + # Convert a time window (relative to trial onset) to frames units, relative to "trace" begining; i.e. index on the trace whose time 0 is trace[samps_bef]. + # samps_bef: number of frames before image/omission + + import numpy as np + + frames_win = samps_bef + np.round(time_win / frame_dur).astype(int) # convert peak_win to frames (new way to code time_win_frames) + frames_win[-1] = frames_win[0] + np.round(np.diff(time_win) / frame_dur).astype(int) # we redefine the upper limit of the window, otherwise the same window duration can lead to different upper limit values due to the division and flooring, and turning into int. + time_win_frames = np.arange(frames_win[0], frames_win[-1]) #+1) # [40, 41, 42, 43, 44, 45, 46, 47, 48] + # for omit-evoked peak timing, compute it relative to samps_bef (which is the index of omission) + + return time_win_frames + + + +def all_sess_set_h5_fileName(name, dir_now, all_files=0): + # Look for a file in a directory; if desired, sort by modification time, and only return the latest file. + # example inputs: + # name = 'all_sess_%s_.' %(analysis_name) + # name = 'Yneuron%d_model_' %neuron_y + + import re + import os + import numpy as np + + regex = re.compile(name) # + '.h5') +# regex = re.compile(aname + '(.*).hdf5') # note: "aname" does not include the directory path; it's just the file name. + + l = os.listdir(dir_now) + + h5_files = [string for string in l if re.match(regex, string)] # string=l[0] + + if len(h5_files)==0: + print('Error: no h5 file exists!!!') + allSessName = '' + + if all_files==0: # only get the latest file, otherwise get all file names + # Get the modification times of the existing analysis folders + modifTimes = [os.path.getmtime(os.path.join(dir_now, h5_files[i])) for i in range(len(h5_files))] + + # Find all the old analysis folders + if len(modifTimes) > 1: + h5_files = np.array(h5_files)[np.argsort(modifTimes).squeeze()] + print(h5_files) + + + if len(h5_files)==0: + print(name) + print('\nall_sess h5 file does not exist! (run svm_init to call svm_plots_init and save all_sess)') + elif len(h5_files)>1: + print('\nMore than 1 h5 file exists! Using the latest file') + allSessName = os.path.join(dir_now, h5_files[-1]) + else: + allSessName = os.path.join(dir_now, h5_files[0]) + print(allSessName) + print(f'\n') + + else: + allSessName = [] + for i in range(len(h5_files)): + allSessName.append(os.path.join(dir_now, h5_files[i])) + print(allSessName) + + # read hdf file +# all_sess = pd.read_hdf(allSessName, key='all_sess') #'svm_vars') ## Load all_sess dataframe +# input_vars = pd.read_hdf(allSessName, key='input_vars') ## Load input_vars dataframe + + return allSessName, h5_files + + + + +def colorOrder(nlines=30): + # change color order of lines in matplotlib to a given colormap + + from numpy import linspace + from matplotlib import cm + cmtype = cm.jet # jet; what kind of colormap? + + start = 0.0 + stop = 1.0 + number_of_lines = nlines #len(days) + cm_subsection = linspace(start, stop, number_of_lines) + colorsm = [ cmtype(x) for x in cm_subsection ] + + #% Change color order to jet +# from cycler import cycler +# plt.rcParams['axes.prop_cycle'] = cycler(color=colors) + +# a = plt.scatter(y, y2, c=np.arange(len(y)), cmap=cm.jet, edgecolors='face')#, label='class accuracy (% correct testing trials)') + + return colorsm + + + +def flash_gray_onset_relOmit(samps_bef, samps_aft, frame_dur, flash_dur=.25, gray_dur=.5): + #%% For traces that are aligned on omission, this funciton will give us the time (and frame number) of flashes and gray screens + + import numpy as np + + # To align on omissions, get 40 frames before omission and 39 frames after omission + samps_bef_time = (samps_bef+1) * frame_dur # 1 is added bc below we do np.arange(0,-samps_bef), so we get upto one value below samps_bef + samps_aft_time = samps_aft * frame_dur # frames_after_omission in svm_main # we trained the classifier until 30 frames after omission + + flash_gray_dur = flash_dur + gray_dur # .75 # sec (.25 flash + .5 gray) + + # times (sec) of flash onset, when aligned on omission (0 is the onset of omission) +# flashes_win_trace_index_unq_time = np.unique(np.concatenate((np.arange(samps_bef_time, 0, -flash_gray_dur), [gray_dur], \ +# np.arange(gray_dur, samps_aft_time, flash_gray_dur)))) + ### NOTE: you should remove 0 from flashes_win_trace_index_unq_time + ### because at time 0, there is no flash, there is omission!! + flashes_win_trace_index_unq_time = np.unique(np.concatenate((np.arange(0, -samps_bef_time, -flash_gray_dur), \ + np.arange(0, samps_aft_time, flash_gray_dur)))) + + # times (sec) of gray onset, when aligned on omission (0 is the onset of omission) + grays_win_trace_index_unq_time = np.unique(np.concatenate((np.arange(0+flash_dur, -samps_bef_time, -flash_gray_dur), \ + np.arange(0+flash_dur, samps_aft_time, flash_gray_dur)))) + + # same as above, except in frame + # below will give us [0, 8, 16, 24, 32]: these are the frames of flash onset, when aligned on omission (0 is the onset of omission) + flashes_win_trace_index_unq = flashes_win_trace_index_unq_time / frame_dur + # below will give us [2.7, 10.8, 18.8 , 26.9]: these are the frames of flash onset, when aligned on omission (0 is the onset of omission) + grays_win_trace_index_unq = grays_win_trace_index_unq_time / frame_dur + + return flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, flashes_win_trace_index_unq, grays_win_trace_index_unq #= flash_gray_onset_relOmit(samps_bef, samps_aft, frame_dur) + + + +def plot_flashLines_ticks_legend(lims, H, flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, x='', xmjn='', bbox_to_anchor=(1, .7), ylab='% Classification accuracy', xlab='Time rel. trial onset (sec)', omit_aligned=0): + ### NOTE: there is also this same code in def_funs + + #%% Add to the plots the following: flash/ gray screen lines , proper tick marks, and legend +# h1 = plt.plot() +# plot_flashLines_ticks_legend([], h1, flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, time_trace, bbox_to_anchor=bb, ylab=ylabel, xmjn=xmjn) + + import numpy as np + import matplotlib.pyplot as plt + import matplotlib.gridspec as gridspec + import matplotlib.ticker as ticker + from matplotlib.ticker import (MultipleLocator, FormatStrFormatter, AutoMinorLocator) + import seaborn + + + if len(lims)!=0: # set lims=[] when lims is not known. + mn = lims[0] # np.round(np.nanmin(av_test_shfl_avSess_eachP)) # 45 + mx = lims[1] # np.round(np.nanmax(av_test_data_avSess_eachP)) # 80 + # rg = (mx - mn) / 10. + else: + mn = plt.gca().get_ylim()[0]; + mx = plt.gca().get_ylim()[1]; + + # mark omission onset + plt.vlines([0], mn, mx, color='k', linestyle='--') + + # mark flash duration with a shaded area ### NOTE: you should remove 0 from flashes_win_trace_index_unq_time because at time 0, there is no flash, there is omission!! + flashes_win_trace_index_unq_time0 = flashes_win_trace_index_unq_time + + flash_dur = .25 #np.unique(grays_win_trace_index_unq_time - flashes_win_trace_index_unq_time0) + if omit_aligned: + omit_ind = np.argwhere(flashes_win_trace_index_unq_time0==0).squeeze() + # flashes_win_trace_index_unq_time = np.delete(flashes_win_trace_index_unq_time, omit_ind) + flashes_win_trace_index_unq_time_new = np.delete(flashes_win_trace_index_unq_time0, omit_ind) + else: + flashes_win_trace_index_unq_time_new = flashes_win_trace_index_unq_time0 + + for i in range(len(flashes_win_trace_index_unq_time_new)): + plt.axvspan(flashes_win_trace_index_unq_time_new[i], flashes_win_trace_index_unq_time_new[i] + flash_dur, alpha=0.2, facecolor='y') + + ''' + # mark the onset of flashes + plt.vlines(flashes_win_trace_index_unq_time_new, mn, mx, color='y', linestyle='-.', linewidth=.7) + # mark the onset of grays + plt.vlines(grays_win_trace_index_unq_time, mn, mx, color='gray', linestyle=':', linewidth=.7) + ''' + if xmjn=='': +# xmj = np.round(np.unique(np.concatenate((np.arange(0, time_trace[0], -.05), np.arange(0, time_trace[-1], .05)))), 2) + xmj = np.round(np.unique(np.concatenate((np.arange(0, -1, -.05), np.arange(0, 1, .05)))), 2) + xmn = [] #np.arange(-.5, time_trace[-1], 1) + else: + xmj = xmjn[0] + xmn = xmjn[1] + + ax = plt.gca() + + ax.set_xticks(xmj); # plt.xticks(np.arange(0,x[-1],.25)); #, fontsize=10) + ax.set_xticklabels(xmj, rotation=45, ha='right') + + ax.xaxis.set_minor_locator(ticker.FixedLocator(xmn)) + ax.tick_params(labelsize=10, length=6, width=2, which='major') + ax.tick_params(labelsize=10, length=5, width=1, which='minor') + # plt.xticklabels(np.arange(0,x[-1],.25)) + + if len(H)!=0: + plt.legend(handles=H, loc='center left', bbox_to_anchor=bbox_to_anchor, frameon=False, handlelength=1, fontsize=12) + plt.ylabel(ylab, fontsize=12); + plt.xlabel(xlab, fontsize=12); + if len(lims)!=0: + plt.ylim(lims); +# plt.legend(handles=[h1[0], h1[1], h1[2], h1[3], h1[4], h1[5], h1[6], h1[7], h2], loc='center left', bbox_to_anchor=(1, .7), frameon=False, handlelength=1, fontsize=12) + + plt.grid(False) # plt.box(on=None) # plt.axis(True) + seaborn.despine()#left=True, bottom=True, right=False, top=False) + + + + + +def makeNicePlots(ax, rmv2ndXtickLabel=0, rmv2ndYtickLabel=0): + + # Hide the right and top spines + ax.spines['right'].set_visible(False) + ax.spines['top'].set_visible(False) + # Only show ticks on the left and bottom spines + ax.yaxis.set_ticks_position('left') + ax.xaxis.set_ticks_position('bottom') + + # Make tick directions outward + ax.tick_params(direction='out') + # Tweak spacing between subplots to prevent labels from overlapping + #plt.subplots_adjust(hspace=0.5) +# ymin, ymax = ax.get_ylim() + + # Remove every other tick label + if rmv2ndXtickLabel: + [label.set_visible(False) for label in ax.xaxis.get_ticklabels()[::2]] + + if rmv2ndYtickLabel: + [label.set_visible(False) for label in ax.yaxis.get_ticklabels()[::2]] +# a = np.array(ax.yaxis.get_ticklabels())[np.arange(0,len(ax.yaxis.get_ticklabels()),2).astype(int).flatten()] +# [label.set_visible(False) for label in a] + + plt.grid(False) + + ax.tick_params(labelsize=12) + + # gap between tick labeles and axis +# ax.tick_params(axis='x', pad=30) + +# plt.xticks(x, labels, rotation='vertical') + #ax.xaxis.label.set_color('red') +# plt.gca().spines['left'].set_color('white') + #plt.gca().yaxis.set_visible(False) + \ No newline at end of file diff --git a/visual_behavior/decoding_population/set_metadata_basic.py b/visual_behavior/decoding_population/set_metadata_basic.py new file mode 100644 index 000000000..d2c520472 --- /dev/null +++ b/visual_behavior/decoding_population/set_metadata_basic.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +#%% Function to set metadata_basic, a df that includes basic metadata for all the 8 experiments of all sessions in list_all_sessions_valid; metadata include: 'session_id', 'experiment_id', 'area', 'depth', 'valid' + +This function gets called in svm_init_images_pre.py. + + +Created on Wed Oct 14 23:07:43 2020 +@author: farzaneh +""" + +# import sys +# sys.setrecursionlimit(1500) + +def set_metadata_basic(list_all_sessions_valid, list_all_experiments_valid): +# list_all_sessions_valid = stimulus_response_data['ophys_session_id'].unique() + + import pandas as pd + import numpy as np + + import ophysextractor + from ophysextractor.datasets.lims_ophys_session import LimsOphysSession + from ophysextractor.utils.util import mongo, get_psql_dict_cursor + + DB = mongo.qc.metrics + + metadata_basic = pd.DataFrame() + for isess in range(len(list_all_sessions_valid)): + print(isess) + session_id = list_all_sessions_valid[isess] + + try: + Session_obj = LimsOphysSession(lims_id=session_id) + cont = True + except Exception as E: + cont = False + print(f'Note: metadata cannot be set for isess {isess}, session_id {session_id}!!') + print(E) + + + if cont: + # get all the 8 experiments ids for this session + experiment_ids_this_session = np.sort(np.array(Session_obj.data_pointer['ophys_experiment_ids'])) + + # experiment_ids_this_session.shape, list_all_experiments_valid[isess].shape + valid_allexp_this_session = np.in1d(experiment_ids_this_session, list_all_experiments_valid[isess]) + + metadata_now = pd.DataFrame([], columns=['session_id', 'experiment_id', 'area', 'depth', 'valid']) + for i in range(len(experiment_ids_this_session)): # ophys_experiment_id = experiment_ids_this_session[0] + experiment_id = experiment_ids_this_session[i] + + # We have to get depth from Mouse-seeks database + db_cursor = DB.find({"lims_id":int(experiment_id)}) + depth = db_cursor[0]['lims_ophys_experiment']['depth'] + area = db_cursor[0]['lims_ophys_experiment']['area'] + + valid = valid_allexp_this_session[i] + + metadata_now.at[i, :] = session_id, experiment_id, area, depth, valid + + ## Important: here we sort metadata_basic by area and depth + metadata_now = metadata_now.sort_values(by=['area', 'depth']) + + metadata_basic = pd.concat([metadata_basic, metadata_now]) + +# len(metadata_basic) +# metadata_basic + + return(metadata_basic) \ No newline at end of file diff --git a/visual_behavior/decoding_population/set_trialsdf_existing_in_stimdf.py b/visual_behavior/decoding_population/set_trialsdf_existing_in_stimdf.py new file mode 100644 index 000000000..081e23b11 --- /dev/null +++ b/visual_behavior/decoding_population/set_trialsdf_existing_in_stimdf.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +#%% Function to set a subset of trials df that includes only those rows (flashes) in trials df that also exist in stim df + +This function gets called in svm_images_main_pbs.py + + +Created on Sun Nov 1 17:50:43 2020 +@author: farzaneh +""" + +import numpy as np + +def set_trialsdf_existing_in_stimdf(stim_response_df, trials_response_df): + + # set a subset of trials df that includes only those rows (flashes) in trials df that also exist in stim df + # note: you need to set use_extended_stimulus_presentations=True so stim_response_df has start_time as a column. + + # trialsdf_existing_in_stimdf has the same size as scdf, and so can be used to link trials df and stimulus df, hence to get certain rows out of scdf (eg hit or aborted trials, etc) + +# dataset = loading.get_ophys_dataset(ophys_experiment_id) +# analysis = ResponseAnalysis(dataset, use_extended_stimulus_presentations=True) # False # use_extended_stimulus_presentations flag is set to False, meaning that only the main stimulus metadata will be present (image name, whether it is a change or omitted, and a few other things). If you need other columns (like engagement_state or anything from the behavior strategy model), you have to set that to True +# trials_response_df = analysis.get_response_df(df_name='trials_response_df') +# stim_response_df = analysis.get_response_df(df_name='stimulus_response_df') + + + scdf = stim_response_df[stim_response_df['change']==True] + sdf_start = scdf['start_time'].values + tdf_start = trials_response_df['start_time'].values + tdf_stop = trials_response_df['stop_time'].values +# print(sdf_start.shape, tdf_start.shape, tdf_stop.shape) + + # add the last element of tdf_stop to tdf_start, so we can catch the last trial too + tdf_start = np.concatenate((tdf_start, [tdf_stop[-1]])) +# print(sdf_start.shape, tdf_start.shape, tdf_stop.shape) + + # identify the row of trials df that belongs to each element of stim df + stimdf_ind_in_trdf = np.full((len(sdf_start)), np.nan) # same size as scdf (ie stim df for change trials) + for i in range(len(sdf_start)): + stimdf_ind_in_trdf[i] = np.argwhere((sdf_start[i] - tdf_start)<0).flatten()[0] - 1 + + # set trialsdf_existing_in_stimdf: includes a subset of rows in trials df that exist in stim df + trialsdf_existing_in_stimdf = trials_response_df.iloc[stimdf_ind_in_trdf] # same size as scdf + print(trialsdf_existing_in_stimdf.shape, scdf.shape) + + return trialsdf_existing_in_stimdf diff --git a/visual_behavior/decoding_population/svm_funs.py b/visual_behavior/decoding_population/svm_funs.py new file mode 100644 index 000000000..85129e70c --- /dev/null +++ b/visual_behavior/decoding_population/svm_funs.py @@ -0,0 +1,1265 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Tue Jul 23 13:12:43 2019 + +@author: farzaneh +""" + +import numpy as np + +#%% +""" +Fits SVM using XTrain, and returns percent class loss for XTrain and XTest +""" + +def linearSVM(XTrain, YTrain, XTest, YTest, **options): + + import numpy as np + from sklearn import svm +# from sklearn.multiclass import OneVsRestClassifier, OneVsOneClassifier +# from sklearn.svm import SVC + + linear_svm = [] + + # Create a classifier: a support vector classifier + # dual: Prefer dual=False when n_samples > n_features. + if options.get('l1'): + l1 = options.get('l1'); + linear_svm = svm.LinearSVC(C = l1, loss='squared_hinge', penalty='l1', dual=False) + + elif options.get('l2'): + l2 = options.get('l2'); +# linear_svm = svm.LinearSVC(C=l2, loss='squared_hinge', penalty='l2', dual=True) # max_iter=2000 # default max_iter=1000 # multi_class='ovr' + linear_svm = svm.LinearSVC(C=l2, loss='squared_hinge', penalty='l2', dual=False) + + # linear, poly, rbf, sigmoid +# linear_svm = svm.SVC(kernel='linear', C=l2) #, decision_function_shape='ovo') # one-vs-one (‘ovo’) is always used as multi-class strategy. +# linear_svm = svm.SVC(kernel='poly', degree=3, C=l2) +# linear_svm = svm.SVC(kernel='rbf', gamma=1, C=l2) +# linear_svm = svm.SVC(kernel='sigmoid', C=l2) + +# linear_svm = OneVsRestClassifier(SVC(kernel='linear', C=l2)) +# linear_svm = OneVsOneClassifier(SVC(kernel='linear', C=l2)) +# linear_svm = OneVsRestClassifier(SVC(kernel='rbf', gamma=1, C=l2)) +# linear_svm = OneVsOneClassifier(SVC(kernel='rbf', gamma=1, C=l2)) + +# print(linear_svm) +# print(linear_svm.get_params) + + linear_svm.fit(XTrain, np.squeeze(YTrain)) + + + ## compute classification error + perClassErrorTest = (1-linear_svm.score(XTest, YTest))*100 + perClassErrorTrain = (1-linear_svm.score(XTrain, YTrain))*100 + + # the following two are the same: +# linear_svm.score(XTest, YTest) +# np.mean(YTest == linear_svm.predict(XTest)) + + #%% below only works for 2 classes + ''' + def perClassError(Y, Yhat): + import numpy as np + perClassEr = np.sum(abs(np.squeeze(Yhat).astype(float)-np.squeeze(Y).astype(float)))/len(Y)*100 + return perClassEr + + perClassErrorTest = perClassError(YTest, linear_svm.predict(XTest)) + perClassErrorTrain = perClassError(YTrain, linear_svm.predict(XTrain)) + ''' + + + #%% + class summaryClass: + perClassErrorTrain = [] + perClassErrorTest = [] + model = [] + XTest = [] + XTrain = [] + YTest = [] + YTrain = [] + + summary = summaryClass() + summary.perClassErrorTrain = perClassErrorTrain + summary.perClassErrorTest = perClassErrorTest + summary.model = linear_svm + summary.XTest = XTest + summary.XTrain = XTrain + summary.YTest = YTest + summary.YTrain = YTrain + + return summary + + + + + +#%% + +""" +crossValidateModel: divides data into training and test datasets. Calls linearSVM.py, which does linear SVM +using XTrain, and returns percent class loss for XTrain and XTest. +""" +# summary,_ = crossValidateModel(X[ifr,:,:].transpose(), Y, linearSVM, kfold = kfold, l1 = cvect[i], shflTrs = shuffleTrs) +def crossValidateModel(X, Y, modelFn, **options): + +# modelFn = linearSVM +# shflTrs = shuffleTrs +# l2 = cvect[i] +# l1 = cvect[i] + + # X: trials x neurons +# X = X.T + + import numpy as np + import numpy.random as rng +# from linearSVM import linearSVM +# from linearSVR import linearSVR + + if options.get('kfold'): + kfold = options.get('kfold') + else: + kfold = 10 + + if np.logical_or(options.get('shflTrs'), options.get('shflTrs')==0): + shflTrs = options.get('shflTrs') + else: + shflTrs = True +# print shflTrs + + + + if options.get('use_balanced_trials'): + use_balanced_trials = options.get('use_balanced_trials') + else: + use_balanced_trials = 0 + + +# Y = np.squeeze(np.array(Y).astype(int)); # commented so it works for svr too. + + if X.shape[0]>len(Y): + numObservations = len(Y); + numFeatures = len(X)/numObservations; + X = np.reshape(np.array(X.astype('float')), (numObservations, numFeatures), order='F'); + + numObservations, numFeatures = X.shape # trials x neurons + + + ## %%%%% + + classes = np.unique(Y).astype(int) + num_classes = len(classes) # 2 + + if num_classes==2 and use_balanced_trials==1: + + #### make sure there are equal number of trials of each class in the training and testing datasets + # get 90% of each class and then concatenated across classes to form YTrain + + if shflTrs==1: # shuffle trials to break any dependencies on the sequence of trails; Also since we take the first 90% of trials as training and the last 10% as testing, for each run of this code we want to make sure we use different sets of trials as testing and training. + print('shuffling trials in crossValidateModel') + shfl = rng.permutation(np.arange(0, numObservations)) + Ys = Y[shfl] + Xs = X[shfl, :] + testTrInds = shfl[np.arange(int((kfold-1.)/kfold*numObservations), numObservations)] # index of testing trials (that will be used in svm below) + else: # here, while is meaningless bc shfl is not changing from one loop to the other. but. we have already checked for the existence of all classes in Ytrain in set_bestc + shfl = np.arange(0, numObservations) + Ys = Y + Xs = X + + + Ys_now = Ys[Ys==0] + Xs_now = Xs[Ys==0] + numO = len(Ys_now) +# print(Ys_now.shape, Xs_now.shape) + YTrain_0 = Ys_now[np.arange(0, int((kfold-1.) / kfold * numO))] # Take the first 90% of trials as training set + YTest_0 = Ys_now[np.arange(int((kfold-1.)/kfold*numO), numO)] # Take the last 10% of trials as testing set + XTrain_0 = Xs_now[np.arange(0, int((kfold-1.) / kfold * numO))] # Take the first 90% of trials as training set + XTest_0 = Xs_now[np.arange(int((kfold-1.)/kfold*numO), numO)] # Take the last 10% of trials as testing set + + Ys_now = Ys[Ys==1] + Xs_now = Xs[Ys==1] + numO = len(Ys_now) +# print(Ys_now.shape, Xs_now.shape) + YTrain_1 = Ys_now[np.arange(0, int((kfold-1.) / kfold * numO))] # Take the first 90% of trials as training set + YTest_1 = Ys_now[np.arange(int((kfold-1.)/kfold*numO), numO)] # Take the last 10% of trials as testing set + XTrain_1 = Xs_now[np.arange(0, int((kfold-1.) / kfold * numO))] # Take the first 90% of trials as training set + XTest_1 = Xs_now[np.arange(int((kfold-1.)/kfold*numO), numO)] # Take the last 10% of trials as testing set + + YTrain = np.concatenate((YTrain_0, YTrain_1)) + YTest = np.concatenate((YTest_0, YTest_1)) + XTrain = np.concatenate((XTrain_0, XTrain_1), axis=0) + XTest = np.concatenate((XTest_0, XTest_1), axis=0) + + print(f'YTrain: n_trials of each class: {[sum(YTrain==irng) for irng in classes]}') + print(f'YTest: n_trials of each class: {[sum(YTest==irng) for irng in classes]}') + + # Fit the classifier + results = modelFn(XTrain, YTrain, XTest, YTest, **options) + + return results, shfl # shfl includes the index of trials in X whose first 90% are used for training and the last 10% are used for testing. + + + else: + + cls = [0] + attempt = 0 + while len(cls) < num_classes: # make sure all classes exist in YTrain + attempt = attempt+1 + if attempt==1001: + print(f'NOTE: reached {attempt} attempts but failed to have all classes in the training data! Only {len(cls)}/{num_classes} classes exist in the training data!') + # NOTE: ideally you want to set a red flag variable here so later you can exclude these data from analysis! + break + if shflTrs==1: # shuffle trials to break any dependencies on the sequence of trails; Also since we take the first 90% of trials as training and the last 10% as testing, for each run of this code we want to make sure we use different sets of trials as testing and training. + print('shuffling trials in crossValidateModel') + shfl = rng.permutation(np.arange(0, numObservations)) + Ys = Y[shfl] + Xs = X[shfl, :] + testTrInds = shfl[np.arange(int((kfold-1.)/kfold*numObservations), numObservations)] # index of testing trials (that will be used in svm below) + else: # here, while is meaningless bc shfl is not changing from one loop to the other. but. we have already checked for the existence of all classes in Ytrain in set_bestc + shfl = np.arange(0, numObservations) + Ys = Y + Xs = X + + ## %%%%% divide data to training and testing sets + YTrain = Ys[np.arange(0, int((kfold-1.) / kfold * numObservations))] # Take the first 90% of trials as training set + cls = np.unique(YTrain) + # print(cls) + + + if len(cls)==num_classes: + YTest = Ys[np.arange(int((kfold-1.)/kfold*numObservations), numObservations)] # Take the last 10% of trials as testing set + + XTrain = Xs[np.arange(0, int((kfold-1.)/kfold*numObservations)), :] + XTest = Xs[np.arange(int((kfold-1.)/kfold*numObservations), numObservations), :] + + print(f'YTrain: n_trials of each class: {[sum(YTrain==irng) for irng in classes]}') + print(f'YTest: n_trials of each class: {[sum(YTest==irng) for irng in classes]}') + + + # Fit the classifier + results = modelFn(XTrain, YTrain, XTest, YTest, **options) + + return results, shfl # shfl includes the index of trials in X whose first 90% are used for training and the last 10% are used for testing. + + + + + + + +#%% Function to run SVM (when X is frames x units x trials) +# below cannot be true; because set_best_c gets called inside the frames loop; so different frames will get different training/testing dataset but it doesnt matter at all! +# Remember each numSamples will have a different set of training and testing dataset, however for each numSamples, the same set of testing/training dataset +# will be used for all frames and all values of c (unless shuffleTrs is 1, in which case different frames and c values will have different training/testing datasets.) + +def set_best_c(X,Y,regType,kfold,numDataPoints,numSamples,doPlots,useEqualTrNums,smallestC,shuffleTrs,cbest=np.nan,fr2an=np.nan, shflTrLabs=0, X_svm_incorr=0, Y_svm_incorr=0, mnHRLR_acrossDays=np.nan, use_balanced_trials=0): + ''' + X = X_svm + Y = Y_svm + cbest=np.nan + fr2an=np.nan + shflTrLabs = 0 + X_svm_incorr=0 + Y_svm_incorr=0 + mnHRLR_acrossDays=np.nan + ''' + + # numSamples = 10; # number of iterations for finding the results = modelFn(XTrain, YTrain, XTest, YTest, **options)best c (inverse of regularization parameter) + # if you don't want to regularize, go with a very high cbest and don't run the section below. + # cbest = 10**6 + # regType = 'l1' + # kfold = 10; + + # shuffleTrs = False + # if 1 shuffle trials inside crossValidateModel to break any dependencies on the sequence of trials + # if 0, shuffle trials here (instead of inside crossValidateModel) + +# import numpy as np + import numpy.random as rng + import sys + +# from imaging_decisionMaking_exc_inh.utils.lassoClassifier.crossValidateModel import crossValidateModel +# from imaging_decisionMaking_exc_inh.utils.lassoClassifier.linearSVM import linearSVM +# from crossValidateModel import crossValidateModel +# from linearSVM import linearSVM + + # below works only for 2 classes. use this instead: perClassErrorTest = (1-linear_svm.score(XTest, YTest))*100 + ''' + def perClassError(Y, Yhat): + perClassEr = np.sum(abs(np.squeeze(Yhat).astype(float)-np.squeeze(Y).astype(float)))/len(Y)*100 + return perClassEr + ''' + + #%% set range of c (regularization parameters) to check + if np.isnan(cbest).all(): # we need to set cbest + bestcProvided = False + if regType == 'l1': + print('\n----- Running l1 svm classification -----\r') + # cvect = 10**(np.arange(-4, 6,0.2))/numTrials; + cvect = 10**(np.arange(-4, 6, 0.2)) / numDataPoints + elif regType == 'l2': + print('\n----- Running l2 svm classification -----\r') + cvect = 10**(np.arange(-6, 6, 0.2)) / numDataPoints +# cvect = cvect[[0,1]] + nCvals = len(cvect) + print(f'Trying {nCvals} regularization values.') +# print('try the following regularization values: \n', cvect +# formattedList = ['%.2f' % member for member in cvect] +# print('try the following regularization values = \n', formattedList + else: # bestc is provided and we want to fit svm on shuffled trial labels + bestcProvided = True + nCvals = 1 # cbest is already provided + + + #%% +# smallestC = 0 # if 1: smallest c whose CV error falls below 1 se of min CV error will be used as optimal C; if 0: c that gives min CV error will be used as optimal c. + if smallestC==1: + print('bestc = smallest c whose cv error is less than 1se of min cv error') + else: + print('bestc = c that gives min cv error') + #I think we should go with min c as the bestc... at least we know it gives the best cv error... and it seems like it has nothing to do with whether the decoder generalizes to other data or not. + + + #%% + ############## +# hrn = (Y==1).sum() +# lrn = (Y==0).sum() +# +# if ~np.isnan(mnHRLR_acrossDays): # we will make sure for all days SVM is trained on similar number of trials, ie mnHRLR_acrossDays trials of HR and mnHRLR_acrossDays trials of LR. +# trsn = mnHRLR_acrossDays +# numTrials = 2*mnHRLR_acrossDays +# print('using %d HR and %d LR trials for SVM training, same across all sessions' %(mnHRLR_acrossDays, mnHRLR_acrossDays)) +# else: +# if useEqualTrNums and hrn!=lrn: # if the HR and LR trials numbers are not the same, pick equal number of trials of the 2 classes! +# trsn = min(lrn,hrn) +# if hrn > lrn: +# print('Subselecting HR trials so both classes have the same number of trials!') +# numTrials = lrn*2 +# elif lrn > hrn: +# print('Subselecting LR trials so both classes have the same number of trials!') +# numTrials = hrn*2 +# else: +# numTrials = X.shape[2] + + + #%% + classes = np.unique(Y).astype(int) + num_classes = len(classes) + + numTrials = X.shape[1] + print('FINAL: %d trials; %d neurons' %(numTrials, X.shape[0])) + + if num_classes==2 and use_balanced_trials==1: + numO = sum(Y==0) + len_test = 2*len(np.arange(int((kfold-1.)/kfold*numO), numO)) + else: + len_test = numTrials - int((kfold-1.)/kfold*numTrials) # number of testing trials # numTrials - int((100-kfold)/100 * numTrials) +# print(len_test) + + + + X0 = X + 0 # units x trials + Y0 = Y + 0 + + print(f'Y: n_trials of each class: {[sum(Y0==irng) for irng in np.unique(Y0)]}') + + + #%% Initiate vars + ######################################################################################################################################################################## + ######################################################################################################################################################################## +# nFrs = np.shape(X)[0] + if num_classes==2: + wAllC = np.ones((numSamples, nCvals, X.shape[0])) + np.nan # (1, n_features) + bAllC = np.ones((numSamples, nCvals)) + np.nan # (1,) + else: + wAllC = np.ones((numSamples, nCvals, num_classes, X.shape[0])) + np.nan # (n_classes, n_features) + bAllC = np.ones((numSamples, nCvals, num_classes)) + np.nan # (n_classes,) + + + perClassErrorTrain = np.ones((numSamples, nCvals)) + np.nan + perClassErrorTest = np.ones((numSamples, nCvals)) + np.nan + perClassErrorTest_shfl = np.ones((numSamples, nCvals)) + np.nan + perClassErrorTest_chance = np.ones((numSamples, nCvals)) + np.nan + + testTrInds_allSamps = np.full((numSamples, len_test), np.nan) + Ytest_allSamps = np.full((numSamples, len_test), np.nan) + Ytest_hat_allSampsFrs = np.full((numSamples, nCvals, len_test), np.nan) +# testTrInds_outOfY0_allSamps = np.full((numSamples, len_test), np.nan) + trsnow_allSamps = np.full((numSamples, numTrials), np.nan) +# eqy = np.full((X0.shape[0], numSamples), np.nan) + + # incorr: +# if testIncorr: +# perClassErrorTest_incorr = np.ones((numSamples, nCvals)) + np.nan +# perClassErrorTest_shfl_incorr = np.ones((numSamples, nCvals)) + np.nan +# perClassErrorTest_chance_incorr = np.ones((numSamples, nCvals)) + np.nan +# Ytest_hat_allSampsFrs_incorr = np.full((numSamples, nCvals, len_test_incorr), np.nan) + + + #%% + ########################################## Train SVM numSamples times to get numSamples cross-validated datasets. + for s in range(numSamples): # s=0 + if s==0 or s==numSamples-1: + print('Iteration %d' %(s)) + + ############ Make sure both classes have the same number of trials when training the classifier + # set trsnow: # index of trials (out of Y0) after picking random hr (or lr) in order to make sure both classes have the same number in the final Y (on which svm was run) + +# if ~np.isnan(mnHRLR_acrossDays): +# randtrs_hr = np.argwhere(Y0==1)[rng.permutation(hrn)[0:trsn]].squeeze() # subselect mnHRLR_acrossDays trials from HR +# randtrs_lr = np.argwhere(Y0==0)[rng.permutation(lrn)[0:trsn]].squeeze() # subselect mnHRLR_acrossDays trials from LR +# trsnow = np.sort(np.concatenate((randtrs_hr , randtrs_lr))) # index of trials after picking random hr (or lr) in order to make sure both classes have the same number in the final Y (on which svm was run) +# +# X = X0[:,:,trsnow] # trsnow : index of trials (out of X0 and Y0) that are used to set X and Y +# Y = Y0[trsnow] +# +# else: +# if useEqualTrNums and hrn!=lrn: # if the HR and LR trials numbers are not the same, pick equal number of trials of the 2 classes! +# if hrn > lrn: +# randtrs = np.argwhere(Y0==1)[rng.permutation(hrn)[0:trsn]].squeeze() +# trsnow = np.sort(np.concatenate((randtrs , np.argwhere(Y0==0).squeeze()))) # index of trials after picking random hr (or lr) in order to make sure both classes have the same number in the final Y (on which svm was run) +# elif lrn > hrn: +# randtrs = np.argwhere(Y0==0)[rng.permutation(lrn)[0:trsn]].squeeze() # random sample of the class with more trials +# trsnow = np.sort(np.concatenate((randtrs , np.argwhere(Y0==1).squeeze()))) # all trials of the class with fewer trials + the random sample set above for the other class +# +# X = X0[:,:,trsnow] # trsnow : index of trials (out of X0 and Y0) that are used to set X and Y +# Y = Y0[trsnow] +# +# else: # include all trials +# trsnow = np.arange(0, len(Y0)) + + trsnow = np.arange(0, len(Y0)) + X = X0[:,trsnow] # trsnow : index of trials (out of X0 and Y0) that are used to set X and Y + Y = Y0[trsnow] + + trsnow_allSamps[s,:] = trsnow +# numTrials, numNeurons = X.shape[2], X.shape[1] +# print('FINAL: %d trials; %d neurons' %(numTrials, numNeurons) + + + ######################## Setting indices for shuffled data; also setting chance Y: same length as Y for testing data, and with equal number of classes 0 and 1. +# no = Y.shape[0] +# len_test = numTrials - int((kfold-1.)/kfold*numTrials) + permIxs = rng.permutation(len_test) # needed to set perClassErrorTest_shfl + + + ## set Y_chance (works for any number of classes) + ## NOTE: this was so not easy to do: to divide trials in a fair way among each class ... + + a = np.arange(0, len_test, np.round(len_test/float(num_classes)).astype(int)) + +# all_classes_in_ychance = 1 + if len(a)-1 == num_classes: + divis = a + divis[-1] = len_test + elif len(a) == num_classes: + divis = np.concatenate((a, [len_test])) + else: + if len_test > num_classes: + a = np.arange(0, len_test, np.floor(len_test/float(num_classes)).astype(int)) + else: # we have very few test trials; fewer than the number of classes + a = np.arange(0, len_test) +# all_classes_in_ychance = 0 + + divis = a[:num_classes+1] + divis[-1] = len_test + + +# if len(divis)!=num_classes+1: +# print(divis) +# sys.exit('error: "divis" has too many elements; check how you are setting it above!') + + ######## + Y_chance = np.zeros(len_test) + for irng in range(len(divis)-1): + Y_chance[divis[irng]: divis[irng+1]] = irng + + # shuffle it + Y_chance = Y_chance[rng.permutation(len_test)] +# Y_chance.shape, Y_chance + + if s==0: # sanity check + print(f'Y_chance: n_trials of each class: {[sum(Y_chance==irng) for irng in classes]}') + + + ## old code: setting Y_chance; only works if there are 2 classes. + ''' + Y_chance = np.zeros(len_test) + if rng.rand()>.5: + b = rng.permutation(len_test)[0:np.floor(len_test/float(2)).astype(int)] + else: + b = rng.permutation(len_test)[0:np.ceil(len_test/float(2)).astype(int)] + Y_chance[b] = 1 + ''' + +# if testIncorr: +# permIxs_incorr = rng.permutation(len_test_incorr) +# Y_chance_incorr = np.zeros(len_test_incorr) +# if rng.rand()>.5: +# b = rng.permutation(len_test_incorr)[0:np.floor(len_test_incorr/float(2)).astype(int)] +# else: +# b = rng.permutation(len_test_incorr)[0:np.ceil(len_test_incorr/float(2)).astype(int)] +# Y_chance_incorr[b] = 1 + + + ####################### Set the chance Y for training SVM on shuffled trial labels + if shflTrLabs: # shuffle trial classes in Y + Y = np.zeros(numTrials) # Y_chance0 + if rng.rand()>.5: + b = rng.permutation(numTrials)[0:np.floor(numTrials/float(2)).astype(int)] + else: + b = rng.permutation(numTrials)[0:np.ceil(numTrials/float(2)).astype(int)] + Y[b] = 1 + + + ######################## Shuffle trial orders, so the training and testing datasets are different for each numSamples (we only do this if shuffleTrs is 0, so crossValidateModel does not shuffle trials, so we have to do it here, otherwise all numSamples will have the same set of testing and training datasets.) + ######################## REMEMBER : YOU ARE CHANGING THE ORDER OF TRIALS HERE!!! + ######################## + ######################## + if shuffleTrs==0: # shuffle trials here (instead of inside crossValidateModel) to break any dependencies on the sequence of trails +# Ybefshfl = Y + + cls = [0] + attempt = 0 + while len(cls) < num_classes: # make sure all classes exist in YTrain + attempt = attempt+1 + if attempt==1001: + print(f'NOTE: reached {attempt} attempts but failed to have all classes in the training data! Only {len(cls)}/{num_classes} classes exist in the training data!') + # NOTE: ideally you want to set a red flag variable here so later you can exclude these data from analysis! + break + + shfl = rng.permutation(np.arange(0, numTrials)) # shfl: new order of trials ... shuffled indeces of Y... the last 1/10th indeces will be testing trials. + + Ys = Y[shfl] + Xs = X[:,shfl] + + ## %%%%% divide data to training and testing sets + YTrain = Ys[np.arange(0, int((kfold-1.) / kfold * numTrials))] # Take the first 90% of trials as training set + cls = np.unique(YTrain) + + Y = Ys + X = Xs + + # Ytest_allSamps[s,:] : Y that will be used as testing trials in this sample + Ytest_allSamps[s,:] = Y[np.arange(numTrials-len_test, numTrials)] # the last 1/10th of Y (after applying shfl labels to it) + testTrInds = shfl[np.arange(numTrials-len_test, numTrials)] # indeces to be applied on trsnow in order to get the trials (index out of Y0) that were used as testing trs; eg stimrate[trsnow[testTrInds]] is the stimrate of testing trials +# testTrInds_outOfY0 = trsnow[testTrInds] # index of testing trials out of Y0 (not Y!) (that will be used in svm below) + ######## IMPORTANT: Ybefshfl[testTrInds] is same as Y0[trsnow[testTrInds]] and same as Y[np.arange(numTrials-len_test, numTrials)] and same as summary.YTest computed below ######## + + testTrInds_allSamps[s,:] = testTrInds + +# print(np.equal(Y0[testTrInds], Ytest_allSamps[s])) # sanity check. must be True +# testTrInds_outOfY0_allSamps[s,:] = testTrInds_outOfY0 + else: + testTrInds_allSamps = np.nan # for now, but to set it correctly: testTrInds will be set in crossValidateModel.py, you just need to output it from crossValidateModel + Ytest_allSamps[s,:] = np.nan + + + + + ########################## Start training SVM ########################## + ######################## + ######################## + ######################## +# for ifr in frs: # train SVM on each frame + if bestcProvided: + cvect = [cbest] #[cbest[ifr]] + +# print('\tFrame %d' %(ifr) + #%%######################## Loop over different values of regularization + for i in range(nCvals): # i = 0 # train SVM using different values of regularization parameter +# print(f'\tc = {cvect[i]}') + + # to train the classifier on shuffled data, use Y[rng.permutation(len(Y))] + if regType == 'l1': + summary,_ = crossValidateModel(X.transpose(), Y, linearSVM, kfold = kfold, l1 = cvect[i], shflTrs = shuffleTrs, use_balanced_trials = use_balanced_trials) + + elif regType == 'l2': + summary,_ = crossValidateModel(X.transpose(), Y, linearSVM, kfold = kfold, l2 = cvect[i], shflTrs = shuffleTrs, use_balanced_trials = use_balanced_trials) + # modelFn = linearSVM + # l2 = cvect[i] + # shflTrs = shuffleTrs + + ''' + ###### below is the gist of the codes for svm training (done in linearSVM.py) ###### + + import sklearn.svm as svm + + linear_svm = svm.LinearSVC(C = cbest_allExc[12], loss='squared_hinge', penalty='l2', dual=True) # get c for a frame, eg frame 12. + linear_svm.fit(X_svm[12,:,:].transpose(), np.squeeze(Y_svm)) # x should be in trials x units + + linear_svm.predict(XTest) + linear_svm.coef_ + linear_svm.intercept_ + + ### + # def perClassError(Y, Yhat): + # import numpy as np + # perClassEr = np.sum(abs(np.squeeze(Yhat).astype(float)-np.squeeze(Y).astype(float)))/len(Y)*100 + # return perClassEr + + # perClassErrorTest = perClassError(YTest, linear_svm.predict(XTest)); + + # summary.model = linear_svm; + ''' + + # coef_ only exists for the linear kernel +# print(summary.model.intercept_.shape) + wAllC[s,i] = np.squeeze(summary.model.coef_) # weights of all neurons for each value of c and each shuffle # shape (1, n_features) if n_classes == 2 else (n_classes, n_features) + bAllC[s,i] = np.squeeze(summary.model.intercept_) # shape (1,) if n_classes == 2 else (n_classes,) + + # classification errors + perClassErrorTrain[s,i] = summary.perClassErrorTrain + perClassErrorTest[s,i] = summary.perClassErrorTest # perClassError(YTest, linear_svm.predict(XTest)); + + # Testing correct shuffled data: same decoder trained on correct trials, but use shuffled trial labels to compute class error + Ytest_hat = summary.model.predict(summary.XTest) # prediction of trial label for each trial + + perClassErrorTest_shfl[s,i] = (1 - summary.model.score(summary.XTest, summary.YTest[permIxs]))*100 + perClassErrorTest_chance[s,i] = (1 - summary.model.score(summary.XTest, Y_chance))*100 + + # commenting below bc it only works for 2 classes. +# perClassErrorTest_shfl[s,i] = perClassError(summary.YTest[permIxs], Ytest_hat) # fraction of incorrect predicted trial labels +# perClassErrorTest_chance[s,i] = perClassError(Y_chance, Ytest_hat) + + Ytest_hat_allSampsFrs[s,i,:] = Ytest_hat + + # Incorrect trials +# if testIncorr: +# Ytest_hat_incorr = summary.model.predict(X_svm_incorr[ifr,:,:].transpose()) # prediction of trial label for each trial +# perClassErrorTest_incorr[s,i] = perClassError(Y_svm_incorr, Ytest_hat_incorr) # fraction of incorrect predicted trial labels +# perClassErrorTest_shfl_incorr[s,i] = perClassError(Y_svm_incorr[permIxs_incorr], Ytest_hat_incorr) # fraction of incorrect predicted trial labels +# perClassErrorTest_chance_incorr[s,i] = perClassError(Y_chance_incorr, Ytest_hat_incorr) +# Ytest_hat_allSampsFrs_incorr[s,i,:] = Ytest_hat_incorr + + + ########## sanity check ########## + """ + trsnow = trsnow_allSamps[s].astype(int) + testTrInds = testTrInds_allSamps[s].astype(int) + testTrInds_outOfY0 = trsnow[testTrInds] + xx = X0[ifr][:,testTrInds_outOfY0] + yy = Y0[testTrInds_outOfY0] + + ww = wAllC[s,i,:,ifr] +# normw = sci.linalg.norm(ww) # numSamps x numFrames +# ww = ww / normw + + bb = bAllC[s,i,ifr] + + # Project population activity of each frame onto the decoder of frame ifr + yhat = np.dot(ww, xx) + bb # testingFrs x testing trials + th = 0 + yhat[yhatth] = 1 + + d = yhat - yy # testing Frs x nTesting Trials # difference between actual and predicted y + c = np.mean(abs(d), axis=-1) * 100 + + eqy[ifr, s] = np.equal(c, perClassErrorTest[s,i,ifr]) + + if eqy[ifr, s]==0: + print(np.mean(np.equal(xx.T, summary.XTest)) + print(np.mean(np.equal(yy, summary.YTest)) + print(np.mean(np.equal(yhat, Ytest_hat)) + print(ifr, s + print(c, perClassErrorTest[s,i,ifr] + sys.exit('Error!') + """ + + print(summary.model) + + #%% + ######################### Find bestc for each frame, and plot the c path + if bestcProvided: + cbestAllFrs = cbest + cbestFrs = cbest + + else: + print('----- Identifying best c -----') +# cbestFrs = np.full((X.shape[0]), np.nan) +# cbestAllFrs = np.full((X.shape[0]), np.nan) + +# for ifr in frs: #range(X.shape[0]): + #######%% Compute average of class errors across numSamples + meanPerClassErrorTrain = np.mean(perClassErrorTrain[:,:], axis = 0); + semPerClassErrorTrain = np.std(perClassErrorTrain[:,:], axis = 0)/np.sqrt(numSamples); + + meanPerClassErrorTest = np.mean(perClassErrorTest[:,:], axis = 0); + semPerClassErrorTest = np.std(perClassErrorTest[:,:], axis = 0)/np.sqrt(numSamples); + + meanPerClassErrorTest_shfl = np.mean(perClassErrorTest_shfl[:,:], axis = 0); +# semPerClassErrorTest_shfl = np.std(perClassErrorTest_shfl[:,:], axis = 0)/np.sqrt(numSamples); + meanPerClassErrorTest_chance = np.mean(perClassErrorTest_chance[:,:], axis = 0); +# semPerClassErrorTest_chance = np.std(perClassErrorTest_chance[:,:], axis = 0)/np.sqrt(numSamples); + + + #######%% Identify best c + # Use all range of c... it may end up a value at which all weights are 0. + ix = np.argmin(meanPerClassErrorTest) + if smallestC==1: + cbest = cvect[meanPerClassErrorTest <= (meanPerClassErrorTest[ix]+semPerClassErrorTest[ix])]; + cbest = cbest[0]; # best regularization term based on minError+SE criteria + cbestAll = cbest + else: + cbestAll = cvect[ix] +# print('\tFrame %d: %f' %(ifr,cbestAll)) + print('\t%f, index %d' %(cbestAll, ix)) +# cbestAllFrs[ifr] = cbestAll + cbestAllFrs = cbestAll + + + + ####### Make sure at bestc at least one weight is non-zero (ie pick bestc from only those values of c that give non-0 average weights.) + if regType == 'l1': # in l2, we don't really have 0 weights! + sys.exit('Needs work! below wAllC has to be for 1 frame') + + a = abs(wAllC)>eps # non-zero weights + b = np.mean(a, axis=(0,2,3)) # Fraction of non-zero weights (averaged across shuffles) + c1stnon0 = np.argwhere(b)[0].squeeze() # first element of c with at least 1 non-0 w in 1 shuffle + cvectnow = cvect[c1stnon0:] + + meanPerClassErrorTestnow = np.mean(perClassErrorTest[:,c1stnon0:], axis = 0); + semPerClassErrorTestnow = np.std(perClassErrorTest[:,c1stnon0:], axis = 0)/np.sqrt(numSamples); + ix = np.argmin(meanPerClassErrorTestnow) + if smallestC==1: + cbest = cvectnow[meanPerClassErrorTestnow <= (meanPerClassErrorTestnow[ix]+semPerClassErrorTestnow[ix])]; + cbest = cbest[0]; # best regularization term based on minError+SE criteria + else: + cbest = cvectnow[ix] + + print('best c (at least 1 non-0 weight) = ', cbest) + else: + cbest = cbestAll + +# cbestFrs[ifr] = cbest + cbestFrs = cbest + + + ########%% Set the decoder and class errors at best c (for data) + """ + # you don't need to again train classifier on data bc you already got it above when you found bestc. You just need to do it for shuffled. ... [you already have access to test/train error as well as b and w of training SVM with bestc.)] + # we just get the values of perClassErrorTrain and perClassErrorTest at cbest (we already computed these values above when training on all values of c) + indBestC = np.in1d(cvect, cbest) + + w_bestc_data = wAllC[:,indBestC,:,ifr].squeeze() # numSamps x neurons + b_bestc_data = bAllC[:,indBestC,ifr] + + classErr_bestC_train_data = perClassErrorTrain[:,indBestC,ifr].squeeze() + + classErr_bestC_test_data = perClassErrorTest[:,indBestC,ifr].squeeze() + classErr_bestC_test_shfl = perClassErrorTest_shfl[:,indBestC,ifr].squeeze() + classErr_bestC_test_chance = perClassErrorTest_chance[:,indBestC,ifr].squeeze() + """ + + + #%% + ########### Plot C path + if doPlots: + import matplotlib.pyplot as plt + # print('Best c (inverse of regularization parameter) = %.2f' %cbest + plt.figure() +# plt.subplot(1,2,1) + plt.fill_between(cvect, meanPerClassErrorTrain-semPerClassErrorTrain, meanPerClassErrorTrain+ semPerClassErrorTrain, alpha=0.5, edgecolor='k', facecolor='k') + plt.fill_between(cvect, meanPerClassErrorTest-semPerClassErrorTest, meanPerClassErrorTest+ semPerClassErrorTest, alpha=0.5, edgecolor='r', facecolor='r') + # plt.fill_between(cvect, meanPerClassErrorTest_chance-semPerClassErrorTest_chance, meanPerClassErrorTest_chance+ semPerClassErrorTest_chance, alpha=0.5, edgecolor='b', facecolor='b') + # plt.fill_between(cvect, meanPerClassErrorTest_shfl-semPerClassErrorTest_shfl, meanPerClassErrorTest_shfl+ semPerClassErrorTest_shfl, alpha=0.5, edgecolor='y', facecolor='y') + + plt.plot(cvect, meanPerClassErrorTrain, 'k', label = 'training') + plt.plot(cvect, meanPerClassErrorTest, 'r', label = 'validation') + plt.plot(cvect, meanPerClassErrorTest_chance, 'b', label = 'cv-chance') + plt.plot(cvect, meanPerClassErrorTest_shfl, 'y', label = 'cv-shfl') + + plt.plot(cvect[cvect==cbest], meanPerClassErrorTest[cvect==cbest], 'bo') + plt.title(f'{cvect[cvect==cbest]}, {meanPerClassErrorTest[cvect==cbest]}') + + plt.xscale('log') +# plt.xlim([cvect[0], cvect[-1]]) + plt.xlabel('c (inverse of regularization parameter)') + plt.ylabel('classification error (%)') + plt.legend(loc='center left', bbox_to_anchor=(1, .7)) + +# plt.title('Frame %d' %(ifr)) + plt.tight_layout() + + + + #%% + ############## + +# if testIncorr: +# return perClassErrorTrain, perClassErrorTest, wAllC, bAllC, cbestAllFrs, cbestFrs, cvect, perClassErrorTest_shfl, perClassErrorTest_chance, testTrInds_allSamps, Ytest_allSamps, Ytest_hat_allSampsFrs, trsnow_allSamps, perClassErrorTest_incorr, perClassErrorTest_shfl_incorr, perClassErrorTest_chance_incorr, Ytest_hat_allSampsFrs_incorr +# else: + return perClassErrorTrain, perClassErrorTest, wAllC, bAllC, cbestAllFrs, cbestFrs, cvect, perClassErrorTest_shfl, perClassErrorTest_chance, testTrInds_allSamps, Ytest_allSamps, Ytest_hat_allSampsFrs, trsnow_allSamps + + + + + + + + + + + + + + +#%% Function to run SVM (when X is frames x units x trials) +# Remember each numSamples will have a different set of training and testing dataset, however for each numSamples, the same set of testing/training dataset +# will be used for all frames and all values of c (unless shuffleTrs is 1, in which case different frames and c values will have different training/testing datasets.) + +def set_best_c_diffNumNeurons(X,Y,regType,kfold,numDataPoints,numSamples,population_sizes_to_try,doPlots,useEqualTrNums,smallestC,shuffleTrs,cbest=np.nan,fr2an=np.nan, shflTrLabs=0, X_svm_incorr=0, Y_svm_incorr=0, mnHRLR_acrossDays=np.nan): + + ''' + X = X_svm + Y = Y_svm + cbest = np.nan + fr2an = np.nan + shflTrLabs = 0 # shuffle trial classes in Y + X_svm_incorr = 0 + Y_svm_incorr = 0 + mnHRLR_acrossDays = np.nan + ''' + # numSamples = 10 # number of iterations for finding the best c (inverse of regularization parameter) + # if you don't want to regularize, go with a very high cbest and don't run the section below. + # cbest = 10**6 + # regType = 'l1' + # kfold = 10; + + # shuffleTrs = False # if 1 shuffle trials to break any dependencies on the sequence of trials + + + #%% +# import numpy as np + import numpy.random as rng + import sys + + def perClassError(Y, Yhat): + perClassEr = np.sum(abs(np.squeeze(Yhat).astype(float)-np.squeeze(Y).astype(float)))/len(Y)*100 + return perClassEr + + + #%% Set c values (regularization parameter) + + if np.isnan(cbest).all(): # we need to set cbest + bestcProvided = False + if regType == 'l1': + print('\n-------------- Running l1 svm classification --------------\r') + cvect = 10**(np.arange(-4, 6,0.2)) / numDataPoints + elif regType == 'l2': + print('\n-------------- Running l2 svm classification --------------\r') + cvect = 10**(np.arange(-6, 6,0.2)) / numDataPoints + nCvals = len(cvect) +# print('try the following regularization values: \n', cvect) + else: # bestc is provided and we want to fit svm on shuffled trial labels + bestcProvided = True + nCvals = 1 # cbest is already provided + + + #%% +# smallestC = 0 + # if 1: the smallest c whose CV error falls below 1 se of min CV error will be used as optimal C + # if 0: c that gives min CV error will be used as optimal c. + + if smallestC==1: + print('bestc = smallest c whose cv error is less than 1se of min cv error') + else: + print('bestc = c that gives min cv error') + #I think we should go with min c as the bestc... at least we know it gives the best cv error... and it seems like it has nothing to do with whether the decoder generalizes to other data or not. + + + #%% + numTrials = X.shape[1] + print('FINAL: %d trials; %d neurons' %(numTrials, X.shape[0])) + + len_test = numTrials - int((kfold-1.)/kfold*numTrials) # number of testing trials + + X0 = X + 0 # units x trials + Y0 = Y + 0 + + + #%% + ######################################################################################################################################################################## + ######################################################################################################################################################################## + + #%% Loop over population size, ie number of neurons to use in SVM training # nN = 1:totalNumNeurons + # right now, we are not changing the number of neurons in the population... + # but the codes are ready to assess how changing the population size affects classification accuracy. + + nnt = X0.shape[0] #X_svm0.shape[1] # total number of neurons +# population_sizes_to_try = [nN_trainSVM] # [x+1 for x in range(X0.shape[0])] : if you want to try all possible population sizes + + # all lists below have length len(population_sizes_to_try); each element has size + # numShufflesN x nSamples x nFrs + # wAllC_nN_all : each cell has size: numShufflesN x nSamples x nNerons_used_for_training x nFrs + # eg. perClassErrorTest_shfl_nN_all[nN][inN] = (numSamples x nfr) shows when we subselected nN+1 neurons out of all neurons, + # in the inN-th iteration, we got numSamples of classAccuracy values for each of the nfr frames (coming from numSamples of subselecting trials). + + # Each element of the following arrays includes svm related vars for a population of a given size (nN) + wAllC_nN_all = [] + bAllC_nN_all = [] + perClassErrorTrain_nN_all = [] + perClassErrorTest_nN_all = [] + perClassErrorTest_shfl_nN_all = [] + perClassErrorTest_chance_nN_all = [] + inds_subselected_neurons_nN_all = [] + +# cbest = 10**6 # if you don't want to regularize, go with a very high cbest + + for nN in population_sizes_to_try: # nN = nN_trainSVM + + # Select nN random neurons from X, do this numShufflesN times + numShufflesN = np.ceil(nnt/float(nN)).astype(int) # if you are selecting only 1 neuron out of 500 neurons, you will do this 500 times to get a selection of all neurons. On the other hand if you are selecting 400 neurons out of 500 neurons, you will do this only twice. + print('Subsampling %d out of %d neurons %d times....' %(nN, nnt, numShufflesN)) + + # CHECK THE SIZE OF ARRAYS BELOW + wAllC = np.full((numShufflesN, numSamples, nCvals, nN), np.nan) + bAllC = np.full((numShufflesN, numSamples, nCvals), np.nan) + perClassErrorTrain = np.full((numShufflesN, numSamples, nCvals), np.nan) + perClassErrorTest = np.full((numShufflesN, numSamples, nCvals), np.nan) + perClassErrorTest_shfl = np.full((numShufflesN, numSamples, nCvals), np.nan) + perClassErrorTest_chance = np.full((numShufflesN, numSamples, nCvals), np.nan) + + inds_subselected_neurons = np.full((numShufflesN, nN), np.nan) # index of neurons in X0 that were used for training svm + + # you have to add numShufflesN to the arrays below if you actually want to set them here +# testTrInds_allSamps = np.full((numSamples, len_test), np.nan) +# Ytest_allSamps = np.full((numSamples, len_test), np.nan) +# Ytest_hat_allSampsFrs = np.full((numSamples, nCvals, len_test), np.nan) +# trsnow_allSamps = np.full((numSamples, numTrials), np.nan) + + + #%% Loop over subselecting nN number of neurons out of all neurons + ######## (subsampling neurons) ######## + + for inN in range(numShufflesN): # eg. for 20 iterations subselect 10 neuron out of 200 neurons # inN = 0 + print('\tIteration %d/%d of subsampling neurons' %(inN+1, numShufflesN)) + + if nN==1: # when only training SVM with one neuron, go through neurons from begining to end, no need to do subselection! + Xnow = X0[[inN],:] + else: # subselect nN number of neurons (so neuron orders get shuffled here!) + inds = rng.permutation(nnt) + inds = inds[range(nN)] + Xnow = X0[inds,:] + inds_subselected_neurons[inN] = inds # index of neurons in X0 that were used for training svm + + + #%%################# Loop over subselecting testing/training trials... to get numSamples cross-validated datasets #################### + ######## (subsampling trials) ######## + + print('\tSubsampling testing/training trials %d times....' %(numSamples)) + + for s in range(numSamples): # s = 0 + print('\t\tIteration %d' %(s)) + + trsnow = np.arange(0, len(Y0)) + X = Xnow[:,trsnow] # trsnow : index of trials (out of Xnow and Y0) that are used to set X and Y + Y = Y0[trsnow] + +# trsnow_allSamps[s,:] = trsnow + # numTrials, numNeurons = X.shape[2], X.shape[1] + # print('FINAL: %d trials; %d neurons' %(numTrials, numNeurons) + + ######################## Setting chance Y: same length as Y for testing data, and with equal number of classes 0 and 1. + # no = Y.shape[0] + # len_test = numTrials - int((kfold-1.)/kfold*numTrials) + permIxs = rng.permutation(len_test) # needed to set perClassErrorTest_shfl + + Y_chance = np.zeros(len_test) + if rng.rand()>.5: + b = rng.permutation(len_test)[0:np.floor(len_test/float(2)).astype(int)] + else: + b = rng.permutation(len_test)[0:np.ceil(len_test/float(2)).astype(int)] + Y_chance[b] = 1 + + + ####################### Set the chance Y for training SVM on shuffled trial labels + if shflTrLabs: # shuffle trial classes in Y + Y = np.zeros(numTrials) # Y_chance0 + if rng.rand()>.5: + b = rng.permutation(numTrials)[0:np.floor(numTrials/float(2)).astype(int)] + else: + b = rng.permutation(numTrials)[0:np.ceil(numTrials/float(2)).astype(int)] + Y[b] = 1 + + + ######################## Shuffle trial orders, so the training and testing datasets are different for each numSamples (we only do this if shuffleTrs is 0, so crossValidateModel does not shuffle trials, so we have to do it here, otherwise all numSamples will have the same set of testing and training datasets.) + ######################## REMEMBER : YOU ARE CHANGING THE ORDER OF TRIALS HERE!!! ######################## + if shuffleTrs==0: # shuffle trials here (instead of inside crossValidateModel) to break any dependencies on the sequence of trails + + # Ybefshfl = Y + shfl = rng.permutation(np.arange(0, numTrials)) # shfl: new order of trials ... shuffled indeces of Y... the last 1/10th indeces will be testing trials. + + Y = Y[shfl] + X = X[:,shfl] + + # Ytest_allSamps[s,:] : Y that will be used as testing trials in this sample +# Ytest_allSamps[s,:] = Y[np.arange(numTrials-len_test, numTrials)] # the last 1/10th of Y (after applying shfl labels to it) +# testTrInds = shfl[np.arange(numTrials-len_test, numTrials)] # indeces to be applied on trsnow in order to get the trials (index out of Y0) that were used as testing trs; eg stimrate[trsnow[testTrInds]] is the stimrate of testing trials + # testTrInds_outOfY0 = trsnow[testTrInds] # index of testing trials out of Y0 (not Y!) (that will be used in svm below) + ######## IMPORTANT: Ybefshfl[testTrInds] is same as Y0[trsnow[testTrInds]] and same as Y[np.arange(numTrials-len_test, numTrials)] and same as summary.YTest computed below ######## + +# testTrInds_allSamps[s,:] = testTrInds + + # print(np.equal(Y0[testTrInds], Ytest_allSamps[s])) # sanity check. must be True + # testTrInds_outOfY0_allSamps[s,:] = testTrInds_outOfY0 +# else: +# testTrInds_allSamps = np.nan # for now, but to set it correctly: testTrInds will be set in crossValidateModel.py, you just need to output it from crossValidateModel +# Ytest_allSamps[s,:] = np.nan + + + # for ifr in frs: # train SVM on each frame + if bestcProvided: + cvect = [cbest] #[cbest[ifr]] + # print('\tFrame %d' %(ifr) + + + #%%######################## Loop over different values of regularization ######################## + ####### Start training SVM here ####### + + print('\t\t\tRunning SVM on %d C values...' %nCvals) + for i in range(nCvals): # i = 0 # train SVM using different values of regularization parameter + if regType == 'l1': + summary,_ = crossValidateModel(X.transpose(), Y, linearSVM, kfold = kfold, l1 = cvect[i], shflTrs = shuffleTrs) + + elif regType == 'l2': + summary,_ = crossValidateModel(X.transpose(), Y, linearSVM, kfold = kfold, l2 = cvect[i], shflTrs = shuffleTrs) + + + wAllC[inN,s,i,:] = np.squeeze(summary.model.coef_) # weights of all neurons for each value of c and each shuffle + bAllC[inN,s,i] = np.squeeze(summary.model.intercept_) + + # classification errors + perClassErrorTrain[inN,s,i] = summary.perClassErrorTrain + perClassErrorTest[inN,s,i] = summary.perClassErrorTest # perClassError(YTest, linear_svm.predict(XTest)); + + # Testing correct shuffled data: same decoder trained on correct trials, but use shuffled trial labels to compute class error + Ytest_hat = summary.model.predict(summary.XTest) # prediction of trial label for each trial + perClassErrorTest_shfl[inN,s,i] = perClassError(summary.YTest[permIxs], Ytest_hat) # fraction of incorrect predicted trial labels + perClassErrorTest_chance[inN,s,i] = perClassError(Y_chance, Ytest_hat) +# Ytest_hat_allSampsFrs[s,i,:] = Ytest_hat + + + ###### below is the gist of the codes for svm training (used in linearSVM.py) ###### + ''' + import sklearn.svm as svm + + linear_svm = svm.LinearSVC(C = cbest_allExc[12], loss='squared_hinge', penalty='l2', dual=True) # get c for a frame, eg frame 12. + linear_svm.fit(X_svm[12,:,:].transpose(), np.squeeze(Y_svm)) # x should be in trials x units + + linear_svm.predict(XTest) + linear_svm.coef_ + linear_svm.intercept_ + + ### + # def perClassError(Y, Yhat): + # import numpy as np + # perClassEr = np.sum(abs(np.squeeze(Yhat).astype(float)-np.squeeze(Y).astype(float)))/len(Y)*100 + # return perClassEr + + # perClassErrorTest = perClassError(YTest, linear_svm.predict(XTest)); + + # summary.model = linear_svm + ''' + + + ########## sanity checks ########## + """ + trsnow = trsnow_allSamps[s].astype(int) + testTrInds = testTrInds_allSamps[s].astype(int) + testTrInds_outOfY0 = trsnow[testTrInds] + xx = X0[ifr][:,testTrInds_outOfY0] + yy = Y0[testTrInds_outOfY0] + + ww = wAllC[s,i,:,ifr] + # normw = sci.linalg.norm(ww) # numSamps x numFrames + # ww = ww / normw + + bb = bAllC[s,i,ifr] + + # Project population activity of each frame onto the decoder of frame ifr + yhat = np.dot(ww, xx) + bb # testingFrs x testing trials + th = 0 + yhat[yhatth] = 1 + + d = yhat - yy # testing Frs x nTesting Trials # difference between actual and predicted y + c = np.mean(abs(d), axis=-1) * 100 + + eqy[ifr, s] = np.equal(c, perClassErrorTest[s,i,ifr]) + + if eqy[ifr, s]==0: + print(np.mean(np.equal(xx.T, summary.XTest)) + print(np.mean(np.equal(yy, summary.YTest)) + print(np.mean(np.equal(yhat, Ytest_hat)) + print(ifr, s + print(c, perClassErrorTest[s,i,ifr] + sys.exit('Error!') + """ + + + #%% Each element of the following arrays includes svm related vars for a population of a given size (population_sizes_to_try) + + wAllC_nN_all.append(wAllC) # each element has size: numShufflesN x nSamples x nCvals x nNerons_used_for_training + bAllC_nN_all.append(bAllC) # each element has size: # numShufflesN x nSamples x nCvals + perClassErrorTrain_nN_all.append(perClassErrorTrain) # each element has size: # numShufflesN x nSamples x nCvals + perClassErrorTest_nN_all.append(perClassErrorTest) + perClassErrorTest_shfl_nN_all.append(perClassErrorTest_shfl) + perClassErrorTest_chance_nN_all.append(perClassErrorTest_chance) + inds_subselected_neurons_nN_all.append(inds_subselected_neurons) # each element has size: numShufflesN x nNerons_used_for_training + + # eg. perClassErrorTest_shfl_nN_all[nN][inN] = (numSamples x nfr) shows when we subselected nN+1 neurons out of all neurons, + # in the inN-th iteration, we got numSamples of classAccuracy values for each of the nfr frames (coming from numSamples of subselecting trials). + + + + #%% Find bestc for each frame, and plot the c path + +# numShufflesN, numSamples, nCvals, nN +# numShufflesN, numSamples, nCvals + + if bestcProvided: + cbestAllFrs = cbest +# cbestFrs = cbest + + else: + print('--------------- Identifying best c ---------------') + cbestAllFrs_nN_all = [] + # cbestAllFrs_nN_all: each element is for a population of a given size; + # cbestAllFrs_nN_all[0]: each element is the best c (the c that gave min error on average across numSamples) for training svm on a given neuron subselect + + for i_pop_size in range(len(population_sizes_to_try)): # nN = nN_trainSVM + cbestAllFrs_all = np.full((numShufflesN), np.nan) + + for inN in range(numShufflesN): # inN = 0 + perClassErrorTrain = perClassErrorTrain_nN_all[i_pop_size][inN] # each element of perClassErrorTrain_nN_all has size: # numShufflesN x nSamples x nCvals + perClassErrorTest = perClassErrorTest_nN_all[i_pop_size][inN] + perClassErrorTest_shfl = perClassErrorTest_shfl_nN_all[i_pop_size][inN] + perClassErrorTest_chance = perClassErrorTest_chance_nN_all[i_pop_size][inN] + + # cbestFrs = np.full((X.shape[0]), np.nan) + # cbestAllFrs = np.full((X.shape[0]), np.nan) + # for ifr in frs: #range(X.shape[0]): + #######%% Compute average of class errors across numSamples + meanPerClassErrorTrain = np.mean(perClassErrorTrain[:,:], axis = 0) + semPerClassErrorTrain = np.std(perClassErrorTrain[:,:], axis = 0)/np.sqrt(numSamples) + + meanPerClassErrorTest = np.mean(perClassErrorTest[:,:], axis = 0) + semPerClassErrorTest = np.std(perClassErrorTest[:,:], axis = 0)/np.sqrt(numSamples) + + meanPerClassErrorTest_shfl = np.mean(perClassErrorTest_shfl[:,:], axis = 0) + # semPerClassErrorTest_shfl = np.std(perClassErrorTest_shfl[:,:], axis = 0)/np.sqrt(numSamples) + meanPerClassErrorTest_chance = np.mean(perClassErrorTest_chance[:,:], axis = 0) + # semPerClassErrorTest_chance = np.std(perClassErrorTest_chance[:,:], axis = 0)/np.sqrt(numSamples) + + + ####### Identify best c ####### + # Use all range of c... it may end up a value at which all weights are 0. + ix = np.argmin(meanPerClassErrorTest) + if smallestC==1: + cbest = cvect[meanPerClassErrorTest <= (meanPerClassErrorTest[ix]+semPerClassErrorTest[ix])] + cbest = cbest[0] # best regularization term based on minError+SE criteria + # cbestAll = cbest + else: + cbest = cvect[ix] + # cbestAll = cvect[ix] + # print('\tFrame %d: %f' %(ifr,cbestAll)) + print('Best C for neuron subselect %d = %f' %(inN, cbest)) + # cbestAllFrs[ifr] = cbestAll + cbestAllFrs = cbest#All + + cbestAllFrs_all[inN] = cbestAllFrs # each element has size: numShufflesN + + ####### Make sure at bestc at least one weight is non-zero (ie pick bestc from only those values of c that give non-0 average weights.) + ''' + if regType == 'l1': # in l2, we don't really have 0 weights! + sys.exit('Needs work! below wAllC has to be for 1 frame') + + a = abs(wAllC)>eps # non-zero weights + b = np.mean(a, axis=(0,2,3)) # Fraction of non-zero weights (averaged across shuffles) + c1stnon0 = np.argwhere(b)[0].squeeze() # first element of c with at least 1 non-0 w in 1 shuffle + cvectnow = cvect[c1stnon0:] + + meanPerClassErrorTestnow = np.mean(perClassErrorTest[:,c1stnon0:], axis = 0); + semPerClassErrorTestnow = np.std(perClassErrorTest[:,c1stnon0:], axis = 0)/np.sqrt(numSamples) + ix = np.argmin(meanPerClassErrorTestnow) + if smallestC==1: + cbest = cvectnow[meanPerClassErrorTestnow <= (meanPerClassErrorTestnow[ix]+semPerClassErrorTestnow[ix])] + cbest = cbest[0] # best regularization term based on minError+SE criteria + else: + cbest = cvectnow[ix] + + print('best c (at least 1 non-0 weight) = ', cbest) + else: + cbest = cbestAll + + # cbestFrs[ifr] = cbest + cbestFrs = cbest + ''' + + ########%% Set the decoder and class errors at best c (for data) + """ + # you don't need to again train classifier on data bc you already got it above when you found bestc. You just need to do it for shuffled. ... [you already have access to test/train error as well as b and w of training SVM with bestc.)] + # we just get the values of perClassErrorTrain and perClassErrorTest at cbest (we already computed these values above when training on all values of c) + indBestC = np.in1d(cvect, cbest) + + w_bestc_data = wAllC[:,indBestC,:,ifr].squeeze() # numSamps x neurons + b_bestc_data = bAllC[:,indBestC,ifr] + + classErr_bestC_train_data = perClassErrorTrain[:,indBestC,ifr].squeeze() + + classErr_bestC_test_data = perClassErrorTest[:,indBestC,ifr].squeeze() + classErr_bestC_test_shfl = perClassErrorTest_shfl[:,indBestC,ifr].squeeze() + classErr_bestC_test_chance = perClassErrorTest_chance[:,indBestC,ifr].squeeze() + """ + + + #%% Plot C path + + if doPlots: + import matplotlib.pyplot as plt + # print('Best c (inverse of regularization parameter) = %.2f' %cbest + plt.figure() + # plt.subplot(1,2,1) + plt.fill_between(cvect, meanPerClassErrorTrain-semPerClassErrorTrain, meanPerClassErrorTrain+ semPerClassErrorTrain, alpha=0.5, edgecolor='k', facecolor='k') + plt.fill_between(cvect, meanPerClassErrorTest-semPerClassErrorTest, meanPerClassErrorTest+ semPerClassErrorTest, alpha=0.5, edgecolor='r', facecolor='r') + # plt.fill_between(cvect, meanPerClassErrorTest_chance-semPerClassErrorTest_chance, meanPerClassErrorTest_chance+ semPerClassErrorTest_chance, alpha=0.5, edgecolor='b', facecolor='b') + # plt.fill_between(cvect, meanPerClassErrorTest_shfl-semPerClassErrorTest_shfl, meanPerClassErrorTest_shfl+ semPerClassErrorTest_shfl, alpha=0.5, edgecolor='y', facecolor='y') + + plt.plot(cvect, meanPerClassErrorTrain, 'k', label = 'training') + plt.plot(cvect, meanPerClassErrorTest, 'r', label = 'validation') + plt.plot(cvect, meanPerClassErrorTest_chance, 'b', label = 'cv-chance') + plt.plot(cvect, meanPerClassErrorTest_shfl, 'y', label = 'cv-shfl') + + plt.plot(cvect[cvect==cbest], meanPerClassErrorTest[cvect==cbest], 'bo') + + plt.xlim([cvect[1], cvect[-1]]) + plt.xscale('log') + plt.xlabel('c (inverse of regularization parameter)') + plt.ylabel('classification error (%)') + plt.legend(loc='center left', bbox_to_anchor=(1, .7)) + + # plt.title('Frame %d' %(ifr)) + plt.tight_layout() + + + #%% + cbestAllFrs_nN_all.append(cbestAllFrs_all) + + + + #%% + return perClassErrorTrain_nN_all, perClassErrorTest_nN_all, wAllC_nN_all, bAllC_nN_all, \ + cbestAllFrs_nN_all, cvect, \ + perClassErrorTest_shfl_nN_all, perClassErrorTest_chance_nN_all,\ + inds_subselected_neurons_nN_all, numShufflesN + + + + + + + + diff --git a/visual_behavior/decoding_population/svm_images_init_pbs.py b/visual_behavior/decoding_population/svm_images_init_pbs.py new file mode 100644 index 000000000..d7124986d --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_init_pbs.py @@ -0,0 +1,284 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Run on the cluster (Slurm) for the SVM analysis. It calls svm_images_main_pre_pbs.py which sets vars for the svm analysis, and subsequently calls svm_images_main_pbs.py to run the SVM analysis. + +Once the analysis is done and svm results are saved, run svm_images_plots_init.py to set vars for making plots. + + +Created on Thu Oct 9 12:29:43 2020 +@author: farzaneh +""" + +import numpy as np +import visual_behavior.data_access.loading as loading +from visual_behavior.data_access import utilities +import numpy as np +import os +# import pickle + + +#%% Define vars for svm_images analysis + +project_codes = 'VisualBehaviorMultiscope' #'VisualBehavior' # has to only include 1 project # project_codes : ['VisualBehaviorMultiscope', 'VisualBehaviorTask1B', 'VisualBehavior', 'VisualBehaviorMultiscope4areasx2d'] + +# Note: the variable names 'to_decode' and 'trial_type' are confusing. The names really only make sense when we are decoding images (ie when trial_type is images/changes/omissions), in which case they mean we are decoding to_decode image (eg current image) from trial_type (eg images); otherwise, to_decode is useless (we just default it to 'current') and trial_type indicates what was decoded from what (eg hits_vs_misses) +to_decode = 'current' # 'current' (default): decode current image. 'previous': decode previous image. 'next': decode next image. # remember for omissions, you cant do "current", bc there is no current image, it has to be previous or next! +trial_type = 'changes' #'omissions' #'baseline_vs_nobaseline' #'hits_vs_misses' #'changes_vs_nochanges' # 'images_omissions', 'images', 'changes', 'omissions' # what trials to use for SVM analysis # the population activity of these trials at time time_win will be used to decode the image identity of flashes that occurred at their time 0 (if to_decode='current') or 750ms before (if to_decode='previous'). # if 'changes_vs_nochanges', we will decode image changes from no changes; in this case set to_decode to 'current', but it doesnt really matter. # 'baseline_vs_nobaseline' # decode activity at each frame vs. baseline (ie the frame before omission unless use_spont_omitFrMinus1 = 1 (see below)) +#### NOTE: svm codes will result in decoding 9 classes (8 images + omissions) when to_decode='previous' and trial_type='images'. (it wont happen when to_decode='current' because above we only include images for trial_type='images'; it also wont happen when trial_type='omissions' or 'changes', because changes and omissions are not preceded by omissions (although rarely we do see double omissions)) +# if you want to also decode omissions (in addition to the 8 images) when to_decode='current', you should set trial_type='images_omissions'; HOWEVER, I dont think it's a good idea to mix image and omission aligned traces because omission aligned traces may have prediction/error signal, so it wont be easy to interpret the results bc we wont know if the decoding reflects image-evoked or image-prediciton/error related signals. + +use_events = 1 #0 #1 # whether to run the analysis on detected events (inferred spikes) or dff traces. + +use_matched_cells = 0 #123 # 0: analyze all cells of an experiment. 123: analyze cells matched in all experience levels (familiar, novel 1 , novel >1); 12: cells matched in familiar and novel 1. 23: cells matched in novel 1 and novel >1. 13: cells matched in familiar and novel >1 + +svm_blocks = -100 #-1 #-100 # 2 # -101: run the analysis only on engaged trials # -1: divide trials based on some engagement metric (defined by engagement_pupil_running below) # 2 # number of trial blocks to divide the session to, and run svm on. # -100: run svm analysis on the whole session +engagement_pupil_running = 0 # only applicable when svm_blocks=-1 # np.nan or 0,1,2 for engagement, pupil, running: which metric to use to define engagement? + +use_spont_omitFrMinus1 = 1 # applicable when trial_type='baseline_vs_nobaseline' # if 0, classify omissions against randomly picked spontanoues frames (the initial gray screen); if 1, classify omissions against the frame right before the omission + + +# Note: in the cases below, we are decoding baseline from no-baseline , hits from misses, and changes from no-changes, respectively. +# since we are not decoding images, to_decode really doesnt mean anything (when decoding images, to_decode means current/next/previous image) and we just set it to 'current' so it takes some value. +if trial_type == 'baseline_vs_nobaseline' or trial_type == 'hits_vs_misses' or trial_type == 'changes_vs_nochanges': + to_decode = 'current' + use_balanced_trials = 1 #only effective when num_classes=2 #if 1, use same number of trials for each class; only applicable when we have 2 classes (binary classification). +else: # decoding images + use_balanced_trials = 0 #1 #only effective when num_classes=2 #if 1, use same number of trials for each class; only applicable when we have 2 classes (binary classification). + + + + +#%% Use March 2021 data release sessions +''' +# experiments_table = loading.get_filtered_ophys_experiment_table() +experiments_table = loading.get_filtered_ophys_experiment_table(release_data_only=True) +''' + +#%% Use only those project codes that will be used for the paper +experiments_table = loading.get_platform_paper_experiment_table() +# len(experiments_table) +# experiments_table.keys() +# experiments_table.project_code.unique() + +experiments_table = experiments_table.reset_index('ophys_experiment_id') +# metadata_valid = experiments_table[experiments_table['project_code']=='VisualBehaviorMultiscope'] # multiscope sessions + +# get those rows of experiments_table that are for a specific project code +metadata_valid = experiments_table[experiments_table['project_code'].isin([project_codes])] +metadata_valid = metadata_valid.sort_values('ophys_session_id') + +# Use the new list of sessions that are de-crosstalked and will be released in March 2021 +list_all_sessions_valid = metadata_valid['ophys_session_id'].unique() +# list_all_sessions_valid = sessions_ctDone + + +################################################################################################ +if use_matched_cells!=0: + + #%% get matched cells to redeine list of valid sessions + + #%% New method: match across the following 3 experience levels: last familiar active; Novel 1; second novel active + # from Marina's notebook: visual_behavior_analysis/notebooks/211008_validate_filtering_criteria_and_check_exposure_number.ipynb + + cells_table = loading.get_cell_table() + cells_table.shape + + # limit to cells matched in all 3 experience levels, only considering last Familiar and second Novel active + df = utilities.limit_to_last_familiar_second_novel_active(cells_table) # important that this goes first + df = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(df) + + # Sanity checks: + # count numbers of expts and cells¶ + # there should be the same number of experiments for each experience level, and a similar number of cells + # now the number of cell_specimen_ids AND the number of experiment_ids are the same across all 3 experience levels, because we have limited to only the last Familiar and first Novel active sessions + # this is the most conservative set of experiments and cells - matched cells across experience levels, only considering the most recent Familiar and Novel >1 sessions + +# utilities.count_mice_expts_containers_cells(df) + print(utilities.count_mice_expts_containers_cells(df)['n_cell_specimen_id']) + + ''' + # there are only 3 experience levels per container + df.groupby(['ophys_container_id', 'experience_level']).count().reset_index().groupby(['ophys_container_id']).count().experience_level.unique() + # there should only be 1 experiment per experience level + df.groupby(['ophys_container_id', 'experience_level', 'ophys_experiment_id']).count().reset_index().groupby(['ophys_container_id', 'experience_level']).count().ophys_experiment_id.unique() + ''' + + list_all_sessions_valid_matched = df[df['project_code']==project_codes]['ophys_session_id'].unique() # note that if you get ophys experiments it has to be a multiplication of 3. (not ophys sessions.) + list_all_sessions_valid_matched = np.sort(list_all_sessions_valid_matched) + + b = len(list_all_sessions_valid_matched) / len(list_all_sessions_valid) + print(f'{len(list_all_sessions_valid_matched)}/{len(list_all_sessions_valid)}, {b*100:.0f}% of {project_codes} sessions have matched cells in the 3 experience levels.') + + + ### redefine list all sessions valid if using matched cells + list_all_sessions_valid = list_all_sessions_valid_matched + + +print(f'{len(list_all_sessions_valid)}: Number of de-crosstalked sessions for analysis') + +################################################################################################ + + + +#%% Define slurm vars + +# before running the code below, you need to run the following in the terminal: pip install simple_slurm +from simple_slurm import Slurm + +# define the job record output folder +stdout_location = '/allen/programs/braintv/workgroups/nc-ophys/Farzaneh/ClusterJobs/SVMJobs' #os.path.join(os.path.expanduser("~"), 'job_records') + +# make the job record location if it doesn't already exist +os.mkdir(stdout_location) if not os.path.exists(stdout_location) else None + + +# define the conda environment +conda_environment = 'visbeh2' #'visbeh' + +jobname0 = 'SVM' +jobname = f'{jobname0}' +# jobname = f'{jobname0}:{session_id}' + + +python_file = r"/home/farzaneh.najafi/analysis_codes/visual_behavior_analysis/visual_behavior/decoding_population/svm_images_main_pre_pbs.py" #r"/home/farzaneh.najafi/analysis_codes/multiscope_fn/svm_main_pbs.py" + + + + +# build the python path +# this assumes that the environments are saved in the user's home directory in a folder called 'anaconda3' +# this will be user setup dependent. +python_path = os.path.join( + os.path.expanduser("~"), + 'anaconda3', + 'envs', + conda_environment, + 'bin', + 'python' +) + + +print(python_path) + + +# instantiate a Slurm object +slurm = Slurm( +# array = range(len(list_all_sessions_valid)), + cpus_per_task = 4, #4 + job_name = jobname, + output = f'{stdout_location}/{Slurm.JOB_ARRAY_MASTER_ID}_{Slurm.JOB_ARRAY_ID}.out', + partition = 'braintv', + mem = '24g', #'24g' + time = '120:00:00' + ) +# c = 1 + +print(slurm) + +# call the `sbatch` command to run the jobs +# slurm.sbatch('python ../demo_python_scripts/simple_demo.py ' + Slurm.SLURM_ARRAY_TASK_ID) + + + + +#%% Loop through valid sessions to perform the analysis + +# example active session: isess = -2; session_id = 914639324; isess = -30; session_id = 981845703 +cnt_sess = -1 +for isess in range(len(list_all_sessions_valid)): # [0,1]: # isess = -35 # session_id = list_all_sessions_valid[0] #[num_valid_exps_each_sess == 8][0] + + session_id = int(list_all_sessions_valid[isess]) + + + cnt_sess = cnt_sess + 1 + print('\n\n======================== %d: session %d out of %d sessions ========================\n' % + (session_id, cnt_sess, len(list_all_sessions_valid))) + + + + + + ##### call the `sbatch` command to run the jobs +# slurm.sbatch(f'{python_path} {python_file} --isess {isess} --use_events {use_events} --to_decode {to_decode} --trial_type {trial_type} --svm_blocks {svm_blocks} --engagement_pupil_running {engagement_pupil_running} --use_spont_omitFrMinus1 {use_spont_omitFrMinus1} --use_balanced_trials {use_balanced_trials}') # + Slurm.SLURM_ARRAY_TASK_ID + + slurm.sbatch('{} {} --isess {} --project_codes {} --use_events {} --to_decode {} --trial_type {} --svm_blocks {} --engagement_pupil_running {} --use_spont_omitFrMinus1 {} --use_balanced_trials {} --use_matched_cells {}'.format( + python_path, + python_file, + isess, + project_codes, + use_events, + to_decode, + trial_type, + svm_blocks, + engagement_pupil_running, + use_spont_omitFrMinus1, + use_balanced_trials, + use_matched_cells, + ) + ) + +# slurm.sbatch('{} ../demo_python_scripts/plotting_demo.py --frequency {} --save-loc {}'.format( +# python_path, +# frequency, +# plot_save_location, +# ) + + + + + + + + +############################################################################################### +##### Save a dataframe entries to MONGO and retrieve them later +##### code from Doug: https://gist.github.com/dougollerenshaw/b2ddb9f5e26f33059001f21bae49ea2b +############################################################################################### +''' +#%% save the dataframe to mongo (make every row a 'document' or entry)¶ +# This might be slow for a big table, but you only need to do it once + +project_codes = ['VisualBehaviorMultiscope'] # ['VisualBehaviorMultiscope', 'VisualBehaviorTask1B', 'VisualBehavior', 'VisualBehaviorMultiscope4areasx2d'] +session_numbers = [4] + +import numpy as np +import visual_behavior.data_access.loading as loading +stim_response_dfs = loading.get_concatenated_stimulus_response_dfs(project_codes, session_numbers) # stim_response_data has cell response data and all experiment metadata + +df = stim_response_dfs +print(df.shape) + + +from visual_behavior import database + +conn = database.Database('visual_behavior_data') +collection_name = f'{project_codes}_{session_numbers}' # 'test_table' +collection = conn['ophys_population_analysis'][collection_name] + +print(collection_name) + + +# if kernel stops, use below to find the last entry (or 1 to the last just to be safe), and resume running the code below to save the remaining data to mongo +# alle = collection.find({}) +# print(alle.count()) +# print(alle.count() / df.shape[0]) +# alle[alle.count()-2] + +# 1202985 + +# for idx,row in df.iterrows(): +for idx in np.arange(alle.count()-2, len(df)): + row = df.iloc[idx] + # run every document through the 'clean_and_timestamp' function. + # this function ensures that all datatypes are good for mongo, then adds an additional field with the current timestamp + document_to_save = database.clean_and_timestamp(row.to_dict()) + database.update_or_create( + collection = collection, # this is the collection you defined above. it's the mongo equivalent of a table + document = document_to_save, # save the document in mongo. Think of every document as a row in your table + keys_to_check = ['ophys_experiment_id', 'ophys_session_id', 'stimulus_presentations_id', 'cell_specimen_id'], # this will check to make sure that duplicate documents don't exist + ) + +# close the connection when you're done with it +conn.close() +''' \ No newline at end of file diff --git a/visual_behavior/decoding_population/svm_images_main_pbs.py b/visual_behavior/decoding_population/svm_images_main_pbs.py new file mode 100644 index 000000000..c6214fac9 --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_main_pbs.py @@ -0,0 +1,1125 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Gets called in svm_images_main_pre_pbs.py + +Performs SVM analysis and saves the results in: dir_svm = '/allen/programs/braintv/workgroups/nc-ophys/Farzaneh'. +If using same_num_neuron_all_planes, results will be saved in: dir_svm/ 'same_num_neurons_all_planes' + +Once the analysis is done and svm results are saved, run svm_images_plots_init.py to set vars for making plots. + + +Created on Fri Aug 2 15:24:17 2019 +@author: farzaneh +""" + +#%% +import os +import datetime +import re +import pandas as pd +import copy +import sys +import numpy.random as rnd +from svm_funs import * +# get_ipython().magic(u'matplotlib inline') # %matplotlib inline + + +#%% +def svm_images_main_pbs(session_id, data_list, experiment_ids_valid, df_data, session_trials, trial_type, dir_svm, kfold, frames_svm, numSamples, saveResults, cols_basic, cols_svm, project_codes, to_decode='current', svm_blocks=-100, engagement_pupil_running = np.nan, use_events=False, same_num_neuron_all_planes=0, use_balanced_trials=0, use_spont_omitFrMinus1=1, use_matched_cells=0): + + def svm_run_save(traces_fut_now, image_labels_now, iblock_trials_blocks, svm_blocks, now, engagement_pupil_running, pupil_running_values, use_balanced_trials, project_codes): #, same_num_neuron_all_planes, norm_to_max_svm, svm_total_frs, n_neurons, numSamples, num_classes, samps_bef, regType, kfold, cre, saveResults): + ''' + traces_fut_now = traces_fut_0 + image_labels_now = image_labels_0 + + iblock_trials_blocks = [np.nan, []] + + iblock_trials_blocks = [iblock, trials_blocks] + ''' + + iblock = iblock_trials_blocks[0] + trials_blocks = iblock_trials_blocks[1] + + #%% Normalize each neuron trace by its max (so if on a day a neuron has low FR in general, it will not be read as non responsive!) + # we dont need this because we are z scoring the traces. + + traces_fut_orig = copy.deepcopy(traces_fut_now) + + if 0: #norm_to_max_svm==1: + print('Normalizing each neuron trace by its max.') + # compute max on the entire trace of the session: + aa_mx = [np.max(traces_fut_orig[:,i,:].flatten()) for i in range(n_neurons)] # neurons + if (np.array(aa_mx)==0).any(): + print(aa_mx) + print('\n\nSome neurons have max=0; dividing will lead to NaN! STOP!\n\n') + else: + a = np.transpose(traces_fut_orig, (0,2,1)) # frames x trials x units + b = a / aa_mx + traces_fut_now = np.transpose(b, (0,2,1)) # frames x units x trials + + + + #%% Starting to set variables for the SVM analysis + + meanX_allFrs = np.full((svm_total_frs, n_neurons), np.nan) + stdX_allFrs = np.full((svm_total_frs, n_neurons), np.nan) + + if same_num_neuron_all_planes: + nnt = n_neurons #X_svm[0] + numShufflesN = np.ceil(nnt/float(nN_trainSVM)).astype(int) # if you are selecting only 1 neuron out of 500 neurons, you will do this 500 times to get a selection of all neurons. On the other hand if you are selecting 400 neurons out of 500 neurons, you will do this only twice. + + perClassErrorTrain_data_allFrs = np.full((len(population_sizes_to_try), numShufflesN, numSamples, svm_total_frs), np.nan) + perClassErrorTest_data_allFrs = np.full((len(population_sizes_to_try), numShufflesN, numSamples, svm_total_frs), np.nan) + perClassErrorTest_shfl_allFrs = np.full((len(population_sizes_to_try), numShufflesN, numSamples, svm_total_frs), np.nan) + perClassErrorTest_chance_allFrs = np.full((len(population_sizes_to_try), numShufflesN, numSamples, svm_total_frs), np.nan) + if nN_trainSVM==1: + if num_classes==2: + w_data_allFrs = np.full((len(population_sizes_to_try), numShufflesN, numSamples, nN_trainSVM, svm_total_frs), np.nan).squeeze() # squeeze helps if n_neurons=1 + # else: + else: + if num_classes==2: + w_data_allFrs = np.full((len(population_sizes_to_try), numShufflesN, numSamples, nN_trainSVM, svm_total_frs), np.nan) # squeeze helps if n_neurons=1 + # else: + if num_classes==2: + b_data_allFrs = np.full((len(population_sizes_to_try), numShufflesN, numSamples, svm_total_frs), np.nan) + # else: + + cbest_allFrs = np.full((len(population_sizes_to_try), numShufflesN, svm_total_frs), np.nan) + + + ########################## + else: + perClassErrorTrain_data_allFrs = np.full((numSamples, svm_total_frs), np.nan) + perClassErrorTest_data_allFrs = np.full((numSamples, svm_total_frs), np.nan) + perClassErrorTest_shfl_allFrs = np.full((numSamples, svm_total_frs), np.nan) + perClassErrorTest_chance_allFrs = np.full((numSamples, svm_total_frs), np.nan) + if n_neurons==1: + if num_classes==2: + w_data_allFrs = np.full((numSamples, n_neurons, svm_total_frs), np.nan).squeeze() # squeeze helps if n_neurons=1 + else: + w_data_allFrs = np.full((numSamples, num_classes, n_neurons, svm_total_frs), np.nan).squeeze() + else: + if num_classes==2: + w_data_allFrs = np.full((numSamples, n_neurons, svm_total_frs), np.nan) # squeeze helps if n_neurons=1 + else: + w_data_allFrs = np.full((numSamples, num_classes, n_neurons, svm_total_frs), np.nan) + + if num_classes==2: + b_data_allFrs = np.full((numSamples, svm_total_frs), np.nan) + else: + b_data_allFrs = np.full((numSamples, num_classes, svm_total_frs), np.nan) + + cbest_allFrs = np.full(svm_total_frs, np.nan) + + + + ########################## + if trial_type == 'baseline_vs_nobaseline': # decode activity at each frame vs. baseline + numTrials = 2*traces_fut_now.shape[2] + else: + numTrials = traces_fut_now.shape[2] # numDataPoints = X_svm.shape[1] # trials + + if num_classes==2 and use_balanced_trials==1: + numO = sum(image_labels_now==0) + len_test = 2*len(np.arange(int((kfold-1.)/kfold*numO), numO)) + else: + len_test = numTrials - int((kfold-1.)/kfold*numTrials) # number of testing trials + + numDataPoints = numTrials + print(f'\n{len_test} testing trials in SVM. {numTrials} total number of trials.\n') + + if len_test==1: + Ytest_hat_allSampsFrs_allFrs = np.full((numSamples, len_test, svm_total_frs), np.nan).squeeze() # squeeze helps if len_test=1 + else: + Ytest_hat_allSampsFrs_allFrs = np.full((numSamples, len_test, svm_total_frs), np.nan) + Ytest_allSamps_allFrs = np.full((numSamples, len_test, svm_total_frs), np.nan) + testTrInds_allSamps_allFrs = np.full((numSamples, len_test, svm_total_frs), np.nan) + + + + #%% Use SVM to classify population activity on the gray-screen frame right before the omission vs. the activity on frame + nAftOmit after omission + + ifr = -1 + for nAftOmit in frames_svm: # nAftOmit = frames_svm[0] + + ifr = ifr+1 + if np.isnan(iblock): + print('\n===== Running SVM on frame %d relative to trial onset =====\n' %nAftOmit) + else: + print(f'\n===== BLOCK {iblock} : running SVM on frame {nAftOmit} relative to trial onset =====\n') + + + if trial_type == 'baseline_vs_nobaseline': # decode activity at each frame vs. baseline + # x + if use_spont_omitFrMinus1==0: # if 0, classify omissions against spontanoues frames (the initial gray screen); if 1, classify omissions against the frame right before the omission + rand_spont_frs_num_omit = rnd.permutation(spont_frames.shape[1])[:num_omissions] # pick num_omissions random spontanous frames + g = spont_frames[:,rand_spont_frs_num_omit] # units x trials + elif use_spont_omitFrMinus1==1: + g = traces_fut_now[samps_bef - 1,:,:] # units x trials ; neural activity in the frame before the omission (gray screen) + rand_spont_frs_num_omit = np.nan + + m = traces_fut_now[samps_bef + nAftOmit,:,:] # units x trials ; neural activity on the frame of omission + + # now set the x matrix for svm + X_svm = np.concatenate((g, m), axis=1) # units x (gray + omission) + + + else: + + # x + m = traces_fut_now[samps_bef + nAftOmit,:,:] # units x trials ; neural activity on the frame of omission + + # now set the x matrix for svm + X_svm = m # units x trials + + + # y + Y_svm = image_labels_now # trials + + print(X_svm.shape, Y_svm.shape) + + + + + #%% Z score (make each neuron have mean 0 and std 1 across all trials) + + print('Z scoring acitivity traces!') + + # mean and std of each neuron across all trials (trials here mean both gray screen frames and omission frames) + m = np.mean(X_svm, axis=1) + s = np.std(X_svm, axis=1) + + meanX_allFrs[ifr,:] = m # frs x neurons + stdX_allFrs[ifr,:] = s + + # soft normalziation : neurons with sd2 + b_data = bAllC[:,indBestC].squeeze() # samps, if n_classes=2; # samps x classes, if n_classes>2 + Ytest_hat_allSampsFrs = Ytest_hat_allSampsFrs0[:,indBestC,:].squeeze() + + + ########## keep SVM vars for all frames after omission + cbest_allFrs[ifr] = cbest + + perClassErrorTrain_data_allFrs[:,ifr] = perClassErrorTrain_data # numSamps + perClassErrorTest_data_allFrs[:,ifr] = perClassErrorTest_data + perClassErrorTest_shfl_allFrs[:,ifr] = perClassErrorTest_shfl + perClassErrorTest_chance_allFrs[:,ifr] = perClassErrorTest_chance + if n_neurons==1: + if num_classes==2: + w_data_allFrs[:,ifr] = w_data # numSamps x neurons, if n_classes=2; # samps x classes x neurons, if n_classes>2 + else: + w_data_allFrs[:,:,ifr] = w_data + else: + if num_classes==2: + w_data_allFrs[:,:,ifr] = w_data # numSamps x neurons, if n_classes=2; # samps x classes x neurons, if n_classes>2 + else: + w_data_allFrs[:,:,:,ifr] = w_data + + if num_classes==2: + b_data_allFrs[:,ifr] = b_data + else: + b_data_allFrs[:,:,ifr] = b_data + + Ytest_hat_allSampsFrs_allFrs[:,:,ifr] = Ytest_hat_allSampsFrs # numSamps x numTestTrs + + Ytest_allSamps_allFrs[:,:,ifr] = Ytest_allSamps # numSamps x numTestTrs + testTrInds_allSamps_allFrs[:,:,ifr] = testTrInds_allSamps # numSamps x numTestTrs + # trsnow_allSamps_allFrs = trsnow_allSamps + + ''' + a_train = np.mean(perClassErrorTrain, axis=0) + a_test = np.mean(perClassErrorTest, axis=0) + a_shfl = np.mean(perClassErrorTestShfl, axis=0) + a_chance = np.mean(perClassErrorTestChance, axis=0) + + import matplotlib.pyplot as plt + plt.figure() + plt.plot(a_train, color='k', label='train') + plt.plot(a_test, color='r', label='test') + plt.plot(a_shfl, color='y', label='shfl') + plt.plot(a_chance, color='b', label='chance') + plt.legend(loc='center left', bbox_to_anchor=(1, .7)) + plt.ylabel('% Classification error') + plt.xlabel('C values') + ''' + #### Sanity checks #### + # the following two are the same: + # (abs(Ytest_hat_allSampsFrs[0] - Y_svm[testTrInds_allSamps[0].astype(int)])).mean() + # perClassErrorTest_data[0] + + # the following two are the same: + # Ytest_allSamps[2] + # Y_svm[testTrInds_allSamps[2].astype(int)] + + + + #################################################################################################################################### + #%% Save SVM vars (for each experiment separately) + #################################################################################################################################### + + #%% Set svm dataframe + + svm_vars = pd.DataFrame([], columns = np.concatenate((cols_basic, cols_svm))) +# svm_vars.at[index, cols_basic] = this_sess.iloc[index, :] # experiment info + svm_vars.at[index, cols_basic] = this_sess.loc[index, :] + + # svm output + if same_num_neuron_all_planes: + svm_vars.at[index, cols_svm] = frames_svm, to_decode, use_balanced_trials, thAct, numSamples, softNorm, kfold, regType, cvect, meanX_allFrs, stdX_allFrs, \ + image_labels_now, image_indices, image_indices_previous_flash, image_indices_next_flash, \ + num_classes, iblock, trials_blocks, engagement_pupil_running, pupil_running_values, \ + cbest_allFrs, w_data_allFrs, b_data_allFrs, \ + perClassErrorTrain_data_allFrs, perClassErrorTest_data_allFrs, \ + perClassErrorTest_shfl_allFrs, perClassErrorTest_chance_allFrs, \ + inds_subselected_neurons_all, population_sizes_to_try, numShufflesN + + else: + svm_vars.at[index, cols_svm] = frames_svm, to_decode, use_balanced_trials, thAct, numSamples, softNorm, kfold, regType, cvect, meanX_allFrs, stdX_allFrs, \ + image_labels_now, image_indices, image_indices_previous_flash, image_indices_next_flash, \ + num_classes, iblock, trials_blocks, engagement_pupil_running, pupil_running_values, \ + cbest_allFrs, w_data_allFrs, b_data_allFrs, \ + perClassErrorTrain_data_allFrs, perClassErrorTest_data_allFrs, \ + perClassErrorTest_shfl_allFrs, perClassErrorTest_chance_allFrs, \ + testTrInds_allSamps_allFrs, Ytest_allSamps_allFrs, Ytest_hat_allSampsFrs_allFrs + + + + #%% Save SVM results + + cre_now = cre[:cre.find('-')] + # mouse, session, experiment: m, s, e + ending = '' + if same_num_neuron_all_planes: + ending = 'sameNumNeuronsAllPlanes_' + + if ~np.isnan(iblock): # svm ran on the trial blocks + if svm_blocks==-1: # divide trials into blocks based on the engagement state + word = 'engaged' + else: + word = 'block' + ending = f'{ending}{word}{iblock}_' + + + name = f'{cre_now}_m-{mouse}_s-{session_id}_e-{lims_id}_{svmn}_frames{frames_svm[0]}to{frames_svm[-1]}_{ending}' + +# if project_codes == 'VisualBehavior': + name = f'{name}{project_codes}_' + + name = f'{name}{now}' + + + if saveResults: + svmName = os.path.join(dir_svm, name + '.h5') # os.path.join(d, svmn+os.path.basename(pnevFileName)) + print(svmName) + + print('Saving .h5 file') + svm_vars.to_hdf(svmName, key='svm_vars', mode='w') + + + return svmName + + + + + #################################################################################################### + #################################################################################################### + #################################################################################################### + #################################################################################################### + #%% Set SVM vars + #################################################################################################### + #################################################################################################### + #################################################################################################### + #################################################################################################### + + svm_min_neurs = 3 # min population size for training svm + +# same_num_neuron_all_planes = 1 # if 1, use the same number of neurons for all planes to train svm +# frames_svm = np.arange(-10, 30) #30 # run svm on how what frames relative to omission +# numSamples = 3 #10 #50 +# saveResults = 1 + + e = 'events_' if use_events else '' + + if trial_type=='changes_vs_nochanges': # change, then no-change will be concatenated + svmn = f'{e}svm_decode_changes_from_nochanges' + elif trial_type=='hits_vs_misses': + svmn = f'{e}svm_decode_hits_from_misses' + elif trial_type == 'baseline_vs_nobaseline': + svmn = f'{e}svm_decode_baseline_from_nobaseline' #f'{e}svm_gray_omit' #svm_decode_baseline_from_nobaseline + if use_spont_omitFrMinus1==0: + svmn = svmn + '_spontFrs' + else: + svmn = f'{e}svm_decode_{to_decode}_image_from_{trial_type}' # 'svm_gray_omit' + + if use_matched_cells==123: + svmn = svmn + '_matched_cells_FN1N2' #'_matched_cells_FN1Nn' #Familiar, N1, N+1 + elif use_matched_cells==12: + svmn = svmn + '_matched_cells_FN1' + elif use_matched_cells==23: + svmn = svmn + '_matched_cells_N1Nn' + elif use_matched_cells==13: + svmn = svmn + '_matched_cells_FNn' + + print(svmn) + + +# kfold = 5 #2 #10 # KFold divides all the samples in groups of samples, called folds (if , this is equivalent to the Leave One Out strategy), of equal sizes (if possible). The prediction function is learned using folds, and the fold left out is used for test. + regType = 'l2' + + norm_to_max_svm = 1 # normalize each neuron trace by its max # NOTE: no need to do this as we are z scoring neurons! + doPlots = 0 # svm regularization plots + + softNorm = 1 # soft normalziation : neurons with sd0: + print(f'Number of double omissions: {do}') + print(f'\nRemoving {do*2} double-omission trials from analysis!\n') + aa = np.argwhere(image_indices_next_flash==8).flatten() + bb = np.argwhere(image_indices_previous_flash==8).flatten() + image_indices_next_flash[aa] = np.nan + image_indices_next_flash[bb] = np.nan +# c = [[image_indices_previous_flash[i], all_stim_indices[a[i]], image_indices_next_flash[i]] for i in range(len(a))] +# c + + a = image_indices_previous_flash - image_indices_next_flash + a = a[~np.isnan(a)] + if a.any(): + print(f'UNCANNY: in {sum(a!=0)} cases, the images before and after the omission are different!!') + + elif trial_type=='images': # all images excluding omissions: + image_data = df_data[df_data['image_name']!='omitted'] + image_indices_previous_flash = all_stim_indices_previous_flash[all_stim_indices!=8] + image_indices_next_flash = all_stim_indices_next_flash[all_stim_indices!=8] + + elif trial_type=='changes' or trial_type=='changes_vs_nochanges': # image changes: + image_data = df_data[df_data['change']==True] + image_indices_previous_flash = all_stim_indices_previous_flash[all_stim_trials['change']==True] + image_indices_next_flash = all_stim_indices_next_flash[all_stim_trials['change']==True] + + + if trial_type=='changes_vs_nochanges': # decode image change vs no image change + #image_data = df_data[df_data['change']==True] # change + image_data2 = df_data[df_data['image_name']!='omitted'] # all images for now; below we will only get the image preceding the change + + + + #%% Set the vector of image indices for each trial (current flash) (at time 0 of trial_data.iloc[0]['trace_timestamps']) + u, u_i = np.unique(image_data[tr_id].values, return_index=True) # u_i is the index of the first occurrence of unique values in image_data[tr_id] + image_trials = image_data.iloc[u_i,:] # image_trials is the same as image_data, except it includes only data from one neuron (yet all trials) # get the first row for each stimulus_presentations_id (multiple rows belong to the same stimulus_presentations_id, but different cells) + image_indices = image_trials['image_index'].values + + if trial_type=='changes_vs_nochanges': # decode image change vs no image change + u, u_i = np.unique(image_data2[tr_id].values, return_index=True) # u_i is the index of the first occurrence of unique values in image_data[tr_id] + image_trials2 = image_data2.iloc[u_i,:] # image_trials is the same as image_data, except it includes only data from one neuron (yet all trials) # get the first row for each stimulus_presentations_id (multiple rows belong to the same stimulus_presentations_id, but different cells) + + rel2image_change = - 1 + # set image_data2 only for images right preceding the image change + image_data2_n = image_data2[image_data2[tr_id].isin(image_trials[tr_id].values + rel2image_change)] + + # find those rows of image_trials2 that belong to the image right preceding the image change + # image_trials2_n = image_trials2[image_trials2[tr_id].isin(image_trials[tr_id].values + rel2image_change)] + # if (image_trials2_n.shape == image_trials.shape) == False: + # print('doesnt make sense! imagetrials and imagetrials2 must be the same shape') + + + + #%% Set the vector of image labels which will be used for decoding + if trial_type=='changes_vs_nochanges' or trial_type == 'baseline_vs_nobaseline': # change, then no-change will be concatenated + a = np.full((len(image_indices)), 0) + b = np.full((len(image_indices)), 1) + image_labels = np.concatenate((a,b)) + + else: + + if to_decode == 'current': + image_labels = image_indices + elif to_decode == 'previous': + image_labels = image_indices_previous_flash + elif to_decode == 'next': + image_labels = image_indices_next_flash + + + image_trials0 = copy.deepcopy(image_trials) + image_labels0 = copy.deepcopy(image_labels) + #len(image_labels0) + print(f'Unique image labels: {np.unique(image_labels0)}') + + + + + #### NOTE: codes above will result in decoding 9 classes (8 images + omissions) when to_decode='previous' and trial_type='images'. (it wont happen when to_decode='current' because above we only include images for trial_type='images'; it also wont happen when trial_type='omissions' or 'changes', because changes and omissions are not preceded by omissions (although rarely we do see double omissions)) + # if you want to also decode omissions (in addition to the 8 images) when to_decode='current', you should change trial_type='images' to trial_type='images_omissions' + + + if trial_type=='changes': # image changes: + no_change = np.argwhere((image_indices_previous_flash - image_indices)==0) + if len(no_change)>0: + sys.exit('Supposed to be an image change, but actually no image change occurred!') + + + + #%% If session_data and session_trials are given given as input: + ''' +# #%% Set cell responses and trial types, using dataframes stim_response_data and stim_presentations + +# # get cell response data for this session +# session_data = stim_response_data[stim_response_data['ophys_session_id']==session_id].copy() + +# # get stimulus presentations data for this session +# session_trials = stim_presentations[stim_presentations['ophys_session_id']==session_id].copy() +# # these two dataframes are linked by stimulus_presentations_id and ophys_session_id + + # get image trials + image_trials = session_trials[session_trials['omitted']==False] +# image_trials.shape + + # get cell response data for those trials + image_stimulus_presentation_ids = image_trials.stimulus_presentations_id.values + image_data = session_data[session_data.stimulus_presentations_id.isin(image_stimulus_presentation_ids)] # n_trials +# image_data.shape + + # NOTE: no need to sort image_data below! because we loop through experiments in data_list which is already sorted; also we find the corresponding experiment in image_data by finding the right experiment id + # sort image_data by area and depth; this is mainly for consistency with my previous codes; also so that we analyze experiments in a good order, instead of randomly. +# image_data = image_data.sort_values(by=['targeted_structure', 'imaging_depth']) + + + # set the vector of image indices for each trial (flash) (at time 0 of trial_data.iloc[0]['trace_timestamps']) + image_indices = image_trials['image_index'].values +# image_indices.shape + ''' + + + + + #%% + exp_ids = data_list['ophys_experiment_id'].values +# exp_ids = image_data['ophys_experiment_id'].unique() # get all the 8 experiments of a given session + + date = str(image_data.iloc[0]['date_of_acquisition'])[:10] + cre = image_data.iloc[0]['cre_line'] + stage = image_data.iloc[0]['session_type'] + experience_level = image_data.iloc[0]['experience_level'] + + mouse = int(data_list['mouse_id'].iloc[0]) + container_id = data_list['ophys_container_id'].iloc[0] + + # old method for setting mouse_id ('external_donor_name') + ''' + session_name = str(image_data.iloc[0]['session_name']) + uind = [m.start() for m in re.finditer('_', session_name)] + mid = session_name[uind[0]+1 : uind[1]] + if len(mid)<6: # a different nomenclature for session_name was used for session_id: 935559843 + mouse = int(session_name[uind[-1]+1 :]) + else: + mouse = int(mid) + + if mouse==6: + print('this guy has an invalid id! fixing it!') + mouse = 453988 + ''' + + + + #%% Set number of neurons for all planes + # Do this if training svm on the same number of neurons on all planes + + if same_num_neuron_all_planes==1: + n_neurons_all_planes = [] # for invalid experiments it will be nan. + for index, lims_id in enumerate(exp_ids): + ''' + for il in [7]: #range(num_planes): + index = il + lims_id = exp_ids[il] + ''' + # get data for a single experiment + image_data_this_exp = image_data[image_data['ophys_experiment_id']==lims_id] # (neurons x trials) # all neurons for trial 1, then all neurons for trial 2, etc + + if trial_type=='changes_vs_nochanges': + # image preceding image change + image_data_this_exp2 = image_data2_n[image_data2_n['ophys_experiment_id']==lims_id] # (neurons x trials) # all neurons for trial 1, then all neurons for trial 2, etc + + n_neurons = image_data_this_exp['cell_specimen_id'].unique().shape[0] + + n_neurons_all_planes.append(n_neurons) + + min_n_neurons_all_planes = np.nanmin(n_neurons_all_planes) + nN_trainSVM = np.max([svm_min_neurs, min_n_neurons_all_planes]) # use the same number of neurons for all planes to train svm + + # Train SVM on the following population sizes + population_sizes_to_try = [nN_trainSVM] # [x+1 for x in range(X0.shape[0])] : if you want to try all possible population sizes + + print('Number of neurons per plane: %s' %str(sorted(n_neurons_all_planes))) + print('Training SVM on the following population sizes for all planes: %s neurons.' %str(population_sizes_to_try)) + + + + + + #%% Loop through the 8 planes of each session + + # initiate the pandas tabledatetime.datetime.fromtimestamp(1548449865.568) + this_sess = pd.DataFrame([], columns = cols) + + for index, lims_id in enumerate(exp_ids): + + ''' + ll = list(enumerate(exp_ids)) + l = ll[0]; # first plane + index = l[0]; # plane index + lims_id = l[1] # experiment id + ''' + ''' + for il in [2]: #range(num_planes): + index = il + lims_id = exp_ids[il] + ''' + + print(f'\n\n------------- Analyzing {cre[:3]}, experiment_id: {lims_id} -------------\n\n') + + area = data_list.iloc[index]['targeted_structure'] #area + depth = int(data_list.iloc[index]['imaging_depth']) #depth + valid = sum(np.in1d(experiment_ids_valid, int(lims_id)))>0 #data_list.iloc[index]['valid'] + + this_sess.at[index, cols[range(10)]] = session_id, lims_id, mouse, container_id, date, cre, stage, experience_level, area, depth #, valid + + if valid==False: + print(f'Experiment {index} is not valid; skipping analysis...') + + elif valid: # do the analysis only if the experiment is valid + + # get data for a single experiment + image_data_this_exp = image_data[image_data['ophys_experiment_id']==lims_id] + + if trial_type=='changes_vs_nochanges': + # image preceding image change + image_data_this_exp2 = image_data2_n[image_data2_n['ophys_experiment_id']==lims_id] # (neurons x trials) # all neurons for trial 1, then all neurons for trial 2, etc + + # image_data_this_exp.shape # (neurons x trials) # all neurons for trial 1, then all neurons for trial 2, etc + + ''' + area = image_data_this_exp.iloc[0]['targeted_structure'] + depth = int(image_data_this_exp.iloc[0]['imaging_depth']) + print(area, depth) + + this_sess.at[index, cols[range(8)]] = session_id, lims_id, mouse, date, cre, stage, area, depth + ''' + + #%% Compute frame duration + trace_time = image_data_this_exp['trace_timestamps'].iloc[0] + samps_bef = np.argwhere(trace_time==0)[0][0] + samps_aft = len(trace_time)-samps_bef + + frame_dur = np.mean(np.diff(trace_time)) # difference in sec between frames + print(f'Frame duration {frame_dur:.3f} ms') + + # for mesoscope data: + # if np.logical_or(frame_dur < .09, frame_dur > .1): + # print(f'\n\nWARNING:Frame duration is unexpected!! {frame_dur}ms\n\n') + + + #%% Set image-aligned traces in the format: frames x units x trials + # create traces_fut, ie the traces in shape f x u x t: frames x units x trials, for each experiment of a given session + n_frames = image_data_this_exp['trace'].values[0].shape[0] + n_neurons = image_data_this_exp['cell_specimen_id'].unique().shape[0] + n_trials = image_data_this_exp[tr_id].unique().shape[0] + print(f'n_frames, n_neurons, n_trials: {n_frames, n_neurons, n_trials}') + + cell_specimen_id = image_data_this_exp['cell_specimen_id'].unique() + + # image_data_this_exp['trace'].values.shape # (neurons x trials) # all neurons for trial 1, then all neurons for trial 2, etc + traces = np.concatenate((image_data_this_exp['trace'].values)) # (frames x neurons x trials) + traces_fut = np.reshape(traces, (n_frames, n_neurons, n_trials), order='F') +# traces_fut.shape # frames x neurons x trials + + + if trial_type=='changes_vs_nochanges': + # image preceding image change + traces2 = np.concatenate((image_data_this_exp2['trace'].values)) # (frames x neurons x trials) + traces_fut2 = np.reshape(traces2, (n_frames, n_neurons, n_trials), order='F') + + #plt.figure(); plt.plot(np.nanmean(traces_fut2, axis=(1,2))); plt.plot(np.nanmean(traces_fut, axis=(1,2)), color='r') + + # concatenate change and no-change trials + traces_fut = np.concatenate((traces_fut, traces_fut2), axis=2) + #traces_fut.shape + + + ''' + aa_mx = np.array([np.max(traces_fut[:,i,:].flatten()) for i in range(traces_fut.shape[1])]) # neurons + if (aa_mx==0).any(): +# print(aa_mx) + print('\n\nSome neurons have max=0; excluding them!\n\n') + traces_fut = traces_fut[:, aa_mx!=0, :] + + n_neurons = traces_fut.shape[1] + + print(f'n_frames, n_neurons, n_trials: {n_frames, n_neurons, n_trials}') + ''' + + #%% Take care of nan values in image_labels (it happens if we are decoding the previous or next image and trial_type is images), and remove them frome traces and image_labels + if to_decode != 'current': + masknan = ~np.isnan(image_labels0) + # remove the nan from labels and traces + image_labels = image_labels0[masknan] + traces_fut = traces_fut[:,:,masknan] + image_trials = image_trials0[masknan] + else: + image_labels = copy.deepcopy(image_labels0) + + + num_classes = len(np.unique(image_labels)) # number of classes to be classified by the svm + + print(f'Number of classes in SVM: {num_classes}') + + + + ###################################################### + # use balanced trials; same number of trials for each class + if num_classes==2 and use_balanced_trials==1: # if 1, use same number of trials for each class + + hrn = (image_labels==1).sum() # hit + lrn = (image_labels==0).sum() # miss + if hrn > lrn: + print('\nSubselecting hit trials so both classes have the same number of trials!\n') + elif lrn > hrn: + print('\nSubselecting miss trials so both classes have the same number of trials!\n') + else: + print('\nTrials are balanced; no need for subselecting\n') + + if lrn != hrn: + mn_n_trs = np.min([sum(image_labels==0) , sum(image_labels==1)]) + ind_mn_n_trs = np.argmin([sum(image_labels==0) , sum(image_labels==1)]) # class with fewer trials + # which class has more trials; this is the class that we want to resample + ind_mx_n_trs = np.argmax([sum(image_labels==0) , sum(image_labels==1)]) + + # get random order of trials from the class with more trials + # rnd.permutation(sum(image_labels==ind_mx_n_trs)) # then get the first mn_n_trs trials from the class with more trials + tr_inds = rnd.permutation(sum(image_labels==ind_mx_n_trs))[:mn_n_trs] + + traces_larger_class = traces_fut[:,:,image_labels==ind_mx_n_trs][:,:,tr_inds] + labels_larger_class = image_labels[image_labels==ind_mx_n_trs][tr_inds] + + # get the traces and labels for the smaller class + traces_smaller_class = traces_fut[:,:,image_labels==ind_mn_n_trs] + labels_smaller_class = image_labels[image_labels==ind_mn_n_trs] + + # concatenate the 2 classes + traces_fut = np.concatenate((traces_smaller_class, traces_larger_class), axis=2) + image_labels = np.concatenate((labels_smaller_class, labels_larger_class)) + + print(traces_fut.shape , image_labels.shape) + +# import matplotlib.pyplot as plt +# m = np.mean(traces_fut, axis=(1,2)) +# plt.plot(trace_time[samps_bef+frames_svm[0] : samps_bef+frames_svm[-1]], m[samps_bef+frames_svm[0] : samps_bef+frames_svm[-1]]) + + ###################################################### + # reset n_trials + n_trials = len(image_labels) #traces_fut.shape[2] # note: when trial_type='baseline_vs_nobaseline', traces_fut includes half the trials at this point; so we go with image_labels to get the number of trials. + print(n_trials) + + # double check reshape above worked fine. + ''' + c_all = [] + for itr in image_data_this_exp[tr_id].unique(): + this_data = image_data_this_exp[image_data_this_exp[tr_id]==itr] + c = np.vstack(this_data['trace'].values) + # c.shape # neurons x frames + c_all.append(c) # trials x neurons x frames + + c_all = np.array(c_all) + c_all.shape + + np.equal(traces_fut[:,-2,102], c_all[102,-2,:]).sum() + ''' + + # image_indices = [] + # for itr in image_data_this_exp[tr_id].unique(): + # image_index = image_trials[image_trials[tr_id]==itr]['image_index'].values[0] + # image_indices.append(image_index) + + + + this_sess.at[index, ['n_trials', 'n_neurons', 'cell_specimen_id', 'frame_dur', 'samps_bef', 'samps_aft']] = n_trials, n_neurons, cell_specimen_id, frame_dur, samps_bef, samps_aft + print('===== plane %d: %d neurons; %d trials =====' %(index, n_neurons, n_trials)) + + + + ###################################################### + #%% Do not continue the analysis if neurons or trials are too few, or if there are not enough unique classes in the data + + continue_analysis = True + + if n_neurons==0: # some of the de-crosstalked planes don't have any neurons. + this_sess.at[index, 'valid'] = False + continue_analysis = False + print('0 neurons! skipping invalid experiment %d, index %d' %(int(lims_id), index)) + + if n_trials < 10: + continue_analysis = False + print('Skipping; too few trials to do SVM training! omissions=%d' %(n_trials)) + + if n_neurons < svm_min_neurs: #np.logical_and(same_num_neuron_all_planes , n_neurons < svm_min_neurs): + continue_analysis = False + print('Skipping; too few neurons to do SVM training! neurons=%d' %(n_neurons)) + + if num_classes < 2: + continue_analysis = False + print('Skipping; too few classes to do SVM training! number of classes=%d' %(num_classes)) + + + + ######################## If everything is fine, continue with the SVM analysis ######################## + + if continue_analysis: + + traces_fut_0 = copy.deepcopy(traces_fut) + image_labels_0 = copy.deepcopy(image_labels) + print(traces_fut_0.shape , image_labels_0.shape) + + pupil_running_values = np.nan + + ############################################################################### + ############################################################################### + #### run svm analysis on the whole session + if svm_blocks == -100 or svm_blocks == -101: + + svmName = svm_run_save(traces_fut_0, image_labels_0, [np.nan, []], svm_blocks, now, engagement_pupil_running, pupil_running_values, use_balanced_trials, project_codes) #, same_num_neuron_all_planes, norm_to_max_svm, svm_total_frs, n_neurons, numShufflesN, numSamples, num_classes, samps_bef, regType, kfold, cre, saveResults) + + + #### run svm analysis only on engaged trials +# if svm_blocks==-101: +# # only take the engaged trials +# engaged = image_trials['engagement_state'].values +# engaged[engaged=='engaged'] = 1 +# engaged[engaged=='disengaged'] = 0 + + + ############################################################################### + ############################################################################### + #### divide trials based on the engagement state + elif svm_blocks == -1: + + #### engagement_state; based on lick rate and reward rate + if engagement_pupil_running == 0: + engaged = image_trials['engagement_state'].values + engaged[engaged=='engaged'] = 1 + engaged[engaged=='disengaged'] = 0 + + #### running speed or mean_pupil_area; trials above the median are called engaged + else: + if engagement_pupil_running == 1: + metric = image_trials['mean_pupil_area'].values + + elif engagement_pupil_running == 2: + metric = image_trials['mean_running_speed'].values + + th_eng = np.nanmedian(metric) + engaged = metric+0 + engaged[metric>=th_eng] = 1 + engaged[metric1 sessions') + elif use_matched_cells==13: + print(f'Matching cells across Familiar & Novel >1 sessions') + + + #%% + dir_server_me = '/allen/programs/braintv/workgroups/nc-ophys/Farzaneh' + + # make svm dir to save analysis results + dir_svm = os.path.join(dir_server_me, 'SVM') + + if same_num_neuron_all_planes: + dir_svm = os.path.join(dir_svm, 'same_n_neurons_all_planes') + + if svm_blocks!=-100: + dir_svm = os.path.join(dir_svm, f'trial_blocks') + + if not os.path.exists(dir_svm): + os.makedirs(dir_svm) + + + + + #%% Use below for VIP and SST, since concatenated_stimulus_response_dfs exists for them. + ''' + #%% Set session_numbers from filen; NOTE: below will work only if a single element exists in session_numbers + + sn = os.path.basename(filen)[len('metadata_basic_'):].find('_'); + session_numbers = [int(os.path.basename(filen)[len('metadata_basic_'):][sn+1:])] + + print(f'The following sessions will be analyzed: {project_codes}, {session_numbers}') + + #%% Set the project and stage for sessions to be loaded # Note: it would be nice to pass the following two vars as python args in the python job (pbs tools); except I'm not sure how to pass an array as an argument. + # we need these to set "stim_response_data" and "stim_presentations" dataframes + # r1 = filen.find('metadata_basic_'); r2 = filen.find(']_'); + # project_codes = [filen[r1+3:r2-1]] + # session_numbers = [int(filen[filen.rfind('_[')+2:-1])] # may not work if multiple sessions are being passed as session_numbers + + + + #%% Set "stim_response_data" and "stim_presentations" dataframes + + stim_response_dfs = loading.get_concatenated_stimulus_response_dfs(project_codes, session_numbers) # stim_response_data has cell response data and all experiment metadata + experiments_table = loading.get_filtered_ophys_experiment_table() # functions to load cell response data and stimulus presentations metadata for a set of sessions + + # merge stim_response_dfs with experiments_table + stim_response_data = stim_response_dfs.merge(experiments_table, on=['ophys_experiment_id', 'ophys_session_id']) + # stim_response_data.keys() + + stim_presentations = loading.get_concatenated_stimulus_presentations(project_codes, session_numbers) # stim_presentations has stimulus presentations metadata for the same set of experiments + # stim_presentations.keys() + + + + + #%% Load the pickle file that includes the list of sessions and metadata + + pkl = open(filen, 'rb') + dict_se = pickle.load(pkl) + metadata_basic = pickle.load(pkl) + + list_all_sessions_valid = dict_se['list_all_sessions_valid'] + list_all_experiments_valid = dict_se['list_all_experiments_valid'] + + + + + #%% Set the session to be analyzed, and its metada + + session_id = int(list_all_sessions_valid[isess]) + data_list = metadata_basic[metadata_basic['session_id'].values==session_id] + + + #%% Set session_data and session_trials for the current session. # these two dataframes are linked by stimulus_presentations_id and ophys_session_id + + session_data = stim_response_data[stim_response_data['ophys_session_id']==session_id].copy() # get cell response data for this session + session_trials = stim_presentations[stim_presentations['ophys_session_id']==session_id].copy() # get stimulus presentations data for this session + + df_data = session_data + ''' + + + + + #%% We need below for slc, because stim_response_dfs could not be saved for it! + + #%% Load metadata_basic, and use it to set list_all_sessions_valid + # note metadata is set in code: svm_init_images_pre + ''' + dir_server_me = '/allen/programs/braintv/workgroups/nc-ophys/Farzaneh' + dir_svm = os.path.join(dir_server_me, 'SVM') + a = '_'.join(project_codes) + filen = os.path.join(dir_svm, f'metadata_basic_{a}_slc') + print(filen) + ''' + + # import visual_behavior.data_access.loading as loading + + # use only those project codes that will be used for the paper + experiments_table = loading.get_platform_paper_experiment_table() + experiments_table = experiments_table.reset_index('ophys_experiment_id') + + # get those rows of experiments_table that are for a specific project code + metadata_valid = experiments_table[experiments_table['project_code']==project_codes] + metadata_valid = metadata_valid.sort_values('ophys_session_id') + + list_all_sessions_valid = metadata_valid['ophys_session_id'].unique() + + + + + ################################################################################################ + ################################################################################################ + ################################################################################################ + ################################################################################################ + if use_matched_cells!=0: + + #%% get matched cells + + #%% New method: match across the following 3 experience levels: last familiar active; Novel 1; second novel active + + # from Marina's notebook: visual_behavior_analysis/notebooks/211008_validate_filtering_criteria_and_check_exposure_number.ipynb + +# experiments_table = loading.get_platform_paper_experiment_table() + cells_table = loading.get_cell_table() + cells_table.shape + + # limit to cells matched in all 3 experience levels, only considering last Familiar and second Novel active df = utilities.limit_to_last_familiar_second_novel_active(cells_table) # important that this goes first + df = utilities.limit_to_last_familiar_second_novel_active(cells_table) # important that this goes first + df = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(df) + + # Sanity checks: + # count numbers of expts and cells¶ + # there should be the same number of experiments for each experience level, and a similar number of cells + # now the number of cell_specimen_ids AND the number of experiment_ids are the same across all 3 experience levels, because we have limited to only the last Familiar and first Novel active sessions + # this is the most conservative set of experiments and cells - matched cells across experience levels, only considering the most recent Familiar and Novel >1 sessions + +# utilities.count_mice_expts_containers_cells(df) + print(utilities.count_mice_expts_containers_cells(df)['n_cell_specimen_id']) + + ''' + # there are only 3 experience levels per container + df.groupby(['ophys_container_id', 'experience_level']).count().reset_index().groupby(['ophys_container_id']).count().experience_level.unique() + # there should only be 1 experiment per experience level + df.groupby(['ophys_container_id', 'experience_level', 'ophys_experiment_id']).count().reset_index().groupby(['ophys_container_id', 'experience_level']).count().ophys_experiment_id.unique() + ''' + + list_all_sessions_valid_matched = df[df['project_code']==project_codes]['ophys_session_id'].unique() + list_all_sessions_valid_matched = np.sort(list_all_sessions_valid_matched) +# b = len(list_all_sessions_valid_matched) / len(list_all_sessions_valid) +# print(f'{len(list_all_sessions_valid_matched)}/{len(list_all_sessions_valid)}, {b*100:.0f}% of {project_codes} sessions have matched cells in the 3 experience levels.') + + + ### redefine list all sessions valid if using matched cells. + list_all_sessions_valid = list_all_sessions_valid_matched + + matched_cells = df + + + + ################################################################################################ + ################################################################################################ + + print(f'{len(list_all_sessions_valid)}: Number of de-crosstalked sessions for analysis') + + + + #################################################################################################################### + #### Set metadata_all : includes metadata for all the 8 experiments of a session, even if they are failed. + #################################################################################################################### + + # get the list of all the 8 experiments for each session; we need this to set the depth and area for all experiments, since we need the metadata for all the 8 experiments for our analysis even if we dont analyze some experiments. this is because we want to know which experiment belongs to which plane. we later make plots for each plot individually. + experiments_table = loading.get_filtered_ophys_experiment_table(include_failed_data=True) # , release_data_only=False + experiments_table = experiments_table.reset_index('ophys_experiment_id') +# experiments_table.shape + + metadata_all = experiments_table[experiments_table['ophys_session_id'].isin(list_all_sessions_valid)==True] # metadata_all = experiments_table[np.in1d(experiments_table['ophys_session_id'].values, list_all_sessions_valid)] + metadata_all = metadata_all.sort_values('ophys_session_id') +# metadata_all.shape +# metadata_all.shape[0]/8 + + + + # set the list of all the 8 experiments for each session in list_all_sessions_valid + if project_codes != 'VisualBehaviorMultiscope': #project_codes == 'VisualBehavior': + list_all_experiments = metadata_all['ophys_experiment_id'].values + + else: + try: + list_all_experiments = np.reshape(metadata_all['ophys_experiment_id'].values, (8, len(list_all_sessions_valid)), order='F').T + + except Exception as E: + print(E) + + list_all_experiments = [] + for sess in list_all_sessions_valid: # sess = list_all_sessions_valid[0] + es = metadata_all[metadata_all['ophys_session_id']==sess]['ophys_experiment_id'].values + list_all_experiments.append(es) + list_all_experiments = np.array(list_all_experiments) + + list_all_experiments.shape + + b = np.array([len(list_all_experiments[i]) for i in range(len(list_all_experiments))]) + no8 = list_all_sessions_valid[b!=8] + if len(no8)>0: + print(f'The following sessions dont have all the 8 experiments, excluding them! {no8}') + list_all_sessions_valid = list_all_sessions_valid[b==8] + list_all_experiments = list_all_experiments[b==8] + + print(list_all_sessions_valid.shape, list_all_experiments.shape) + + list_all_experiments = np.vstack(list_all_experiments) + + list_all_experiments = np.sort(list_all_experiments) # sorts across axis 1, ie experiments within each session (does not change the order of sessions!) + + print(list_all_experiments.shape) + + #################################################################################################################### + #################################################################################################################### + + + + #%% Set experiments_table to be merged with stim response df later + + experiments_table = loading.get_filtered_ophys_experiment_table(include_failed_data=True) #loading.get_filtered_ophys_experiment_table() + + # only keep certain columns of experiments_table, before merging it with stim_response_df + experiments_table_sub = experiments_table.reset_index('ophys_experiment_id') + # add 'mouse_id', 'ophys_container_id' to the following too. Currently we are getting those from data_list, but it would be nice to have them in df_data + experiments_table_sub = experiments_table_sub.loc[:, ['ophys_experiment_id', 'ophys_session_id', 'cre_line', 'session_name', 'date_of_acquisition', 'session_type', 'exposure_number']] + + ''' + # make sure all experiments in metadata exist in experiment_table + es = experiments_table.index + esmeta = metadata_basic[metadata_basic['valid']]['experiment_id'].unique() + if np.in1d(es, esmeta).sum() == len(esmeta): + print(f'All experiments in metadata df exist in experiment_table, as expected') + else: + print(f'Some experiments in metadata df do NOT exist in experiment_table; very uncanny!') + ''' + + + + ############################################################################################ + ####################### Set vars for the session to be analyzed ####################### + ############################################################################################ + + #%% Set the session to be analyzed, and its metada + + session_id = list_all_sessions_valid[isess] #session_id = int(list_all_sessions_valid[isess]) # experiment_ids = list_all_experiments_valid[isess] + experiment_ids = list_all_experiments[isess] # we want to have the list of all experiments for each session regardless of whethere they were valid or not... this way we can find the same plane across all sessions. + + + #%% Set experiment_ids_valid + + metadata_now = metadata_valid[metadata_valid['ophys_session_id']==session_id] # Note: we cant use metadata from allensdk because it doesnt include all experiments of a session, it only includes the valid experiments, so it wont allow us to set the metadata for all experiments. + + # If using matched cells for mesoscope data, we cant use metadata_now to set experiment_ids_valid: + # because some planes (experiments) are not passed for last familiar active or second novel active, after matching cells, some planes (experiments) of a mesoscope session become invalid, so we need to reset experiment_ids_valid. + # for VB (or task1B) projects though, an experiment and its session become invalid at the same time, so we can still use metadata_now. + if use_matched_cells!=0: + experiment_ids_valid = matched_cells[matched_cells['ophys_session_id']==session_id]['ophys_experiment_id'].unique() + else: + experiment_ids_valid = metadata_now['ophys_experiment_id'].values + + experiment_ids_valid = np.sort(experiment_ids_valid) + + if use_matched_cells!=0: + v = metadata_now['ophys_experiment_id'].values + print(f"Before matching cells across experience levels, {sum(np.in1d(experiment_ids, v)==False)} experiments were invalid; but now:") + print(f'\n{sum(np.in1d(experiment_ids, experiment_ids_valid)==False)} of the experiments are invalid!\n') + + #cnt_sess = cnt_sess + 1 + print('\n\n======================== Analyzing session %d, %d/%d ========================\n' %(session_id, isess, len(list_all_sessions_valid))) + # print('%d: session %d out of %d sessions' %(session_id, cnt_sess+1, len(list_all_sessions_valid))) + + + + #%% Set data_list: metadata for this session including a valid column + + data_list = metadata_all[metadata_all['ophys_session_id']==session_id] + data_list['valid'] = False + data_list.loc[data_list['ophys_experiment_id'].isin(experiment_ids_valid), 'valid'] = True + # sort by area and depth + data_list = data_list.sort_values(by=['targeted_structure', 'imaging_depth']) + + if project_codes != 'VisualBehaviorMultiscope': + experiment_ids_this_session = [experiment_ids] + else: + experiment_ids_this_session = experiment_ids + + + + ''' + # isess = 0 + session_id = int(list_all_sessions_valid[isess]) + data_list = metadata_basic[metadata_basic['session_id'].values==session_id] + experiment_ids_this_session = data_list['experiment_id'].values + ''' + + + #%% Set stimulus_response_df_allexp, which includes stimulus_response_df (plus some metadata columns) for all experiments of a session + + # from set_trialsdf_existing_in_stimdf import * + + # set columns of stim_response_df to keep + if trial_type != 'hits_vs_misses': + c = ['stimulus_presentations_id', 'cell_specimen_id', 'trace', 'trace_timestamps', 'image_index', 'image_name', 'change', 'engagement_state', 'mean_running_speed', 'mean_pupil_area'] + else: + c = ['trials_id', 'cell_specimen_id', 'trace', 'trace_timestamps', 'hit', 'false_alarm', 'miss', 'stimulus_change', 'aborted', 'go', 'catch', 'auto_rewarded', 'correct_reject', 'initial_image_name', 'change_image_name', 'engagement_state', 'mean_running_speed'] + + stimulus_response_df_allexp = pd.DataFrame() + + + for ophys_experiment_id in experiment_ids_this_session: # ophys_experiment_id = experiment_ids_this_session[0] + + if sum(np.in1d(experiment_ids_valid, int(ophys_experiment_id)))>0: # make sure lims_id is among the experiments in the data release + # if data_list[data_list['experiment_id']==ophys_experiment_id].iloc[0]['valid']: + + valid = True + print(f'Setting stimulus df for valid experiment {ophys_experiment_id}') + + dataset = loading.get_ophys_dataset(ophys_experiment_id) + # analysis = ResponseAnalysis(dataset, use_extended_stimulus_presentations=True) # False # use_extended_stimulus_presentations flag is set to False, meaning that only the main stimulus metadata will be present (image name, whether it is a change or omitted, and a few other things). If you need other columns (like engagement_state or anything from the behavior strategy model), you have to set that to True + analysis = ResponseAnalysis(dataset, use_extended_stimulus_presentations=True, use_events=use_events) + + if trial_type == 'hits_vs_misses': + trials_response_df = analysis.trials_response_df #(use_extended_stimulus_presentations=True) + + #### add engagement state from trials_df to trials_response_df + trials_df = dataset.extended_trials + + for itrid in trials_df.index.values: # itrid = trials_df.index.values[4] + thistr = trials_response_df['trials_id']==itrid + if sum(thistr)>0:# it's not an aborted trial + trials_response_df.loc[thistr, 'engagement_state'] = trials_df.iloc[itrid]['engagement_state'] + + + stim_response_df = trials_response_df # so it matches the naming of the rest of the code down here + # c = stim_response_df.keys().values # get all the columns + else: + stim_response_df = analysis.get_response_df(df_name='stimulus_response_df') + + # dataset.running_speed['speed'].values + # dataset.eye_tracking['pupil_area'] # dataset.eye_tracking['time'] + + # dataset.extended_stimulus_presentations['mean_running_speed'].values + # dataset.extended_stimulus_presentations['mean_pupil_area'] + + + + # work on this + # if svm_blocks==-1 and np.isnan(np.unique(stim_response_df['engagement_state'].values)): + # sys.exit(f'Session {session_id} does not have engagement state!') + + ########### + if 0: #trial_type == 'changes': + # if desired, set a subset of stimulus df that only includes image changes with a given trial condition (hit, autorewarded, etc) + # trials_response_df.keys() # 'hit', 'false_alarm', 'miss', 'correct_reject', 'aborted', 'go', 'catch', 'auto_rewarded', 'stimulus_change' + + scdf = stim_response_df[stim_response_df['change']==True] + # trials_response_df = analysis.get_response_df(df_name='trials_response_df') + + # get a subset of trials df that includes only those rows (flashes) in trials df that also exist in stim df # note: you need to set use_extended_stimulus_presentations=True so stim_response_df has start_time as a column. + trialsdf_existing_in_stimdf = set_trialsdf_existing_in_stimdf(stim_response_df, trials_response_df) # trialsdf_existing_in_stimdf has the same size as scdf, and so can be used to link trials df and stimulus df, hence to get certain rows out of scdf (eg hit or aborted trials, etc) + # trialsdf_existing_in_stimdf.shape, scdf.shape, trials_response_df.shape + + # only get those stimulus df rows that are go trials; seems like all stim df rows are go trials. + # stim_response_df_new = scdf[(trialsdf_existing_in_stimdf['go']==True).values] + + # only get those stimulus df rows that are not aborted and not auto_rewarded (we use trialsdf_existing_in_stimdf to get this information) + a = np.logical_and((trialsdf_existing_in_stimdf['auto_rewarded']==False), (trialsdf_existing_in_stimdf['aborted']==False)) + stim_response_df_new = scdf.iloc[a.values] + stim_response_df_new.shape + + # only get those stimulus df rows that are hit trials + # stim_response_df_new = scdf[(trialsdf_existing_in_stimdf['hit']==True).values] + + # reset stim_response_df + stim_response_df = stim_response_df_new + ############################################ + + stim_response_df0 = stim_response_df # stim_response_df.keys() + + # only get certain columns of stim_response_df defined by c + stim_response_df = stim_response_df0.loc[:,c] + + else: # invalid experiment; set the columns of stim_response_df to nan + valid = False + stim_response_df = pd.DataFrame([np.full((len(c)), np.nan)], columns=c) + + #################################################################### + ############ done with a given experiment (valid or not) of a session ############ + stim_response_df['ophys_session_id'] = session_id #data_list[data_list['experiment_id']==ophys_experiment_id].iloc[0]['session_id'] + stim_response_df['ophys_experiment_id'] = ophys_experiment_id # data_list[data_list['experiment_id']==ophys_experiment_id].iloc[0]['experiment_id'] + + stim_response_df['experience_level'] = metadata_all[metadata_all['ophys_experiment_id']==ophys_experiment_id].iloc[0]['experience_level'] + stim_response_df['area'] = metadata_all[metadata_all['ophys_experiment_id']==ophys_experiment_id].iloc[0]['targeted_structure'] + stim_response_df['depth'] = metadata_all[metadata_all['ophys_experiment_id']==ophys_experiment_id].iloc[0]['imaging_depth'] + stim_response_df['valid'] = valid + + # stim_response_df['area'] = data_list[data_list['experiment_id']==ophys_experiment_id].iloc[0]['area'] + # stim_response_df['depth'] = data_list[data_list['experiment_id']==ophys_experiment_id].iloc[0]['depth'] + # stim_response_df['valid'] = data_list[data_list['experiment_id']==ophys_experiment_id].iloc[0]['valid'] + + + #### set the final stim_response_data_this_exp + + stim_response_data_this_exp = stim_response_df.merge(experiments_table_sub, on=['ophys_experiment_id', 'ophys_session_id']) # add to stim_response_df columns with info on cre, date, etc + # reorder columns, so metadata columns come first then stimulus and cell data + stim_response_data_this_exp = stim_response_data_this_exp.iloc[:, np.concatenate((np.arange(len(c), stim_response_data_this_exp.shape[-1]), np.arange(0, len(c))))] + + #### keep data from all experiments + stimulus_response_df_allexp = pd.concat([stimulus_response_df_allexp, stim_response_data_this_exp]) + +# stimulus_response_df_allexp +# stimulus_response_df_allexp.keys() + + + #################################################################################### + ######################## done with all experiments of a session ######################## + df_data = stimulus_response_df_allexp + session_trials = np.nan # we need it as an input to the function + + df_data0 = copy.deepcopy(df_data) # each row is for a given stimulus presentation + + + ################################################################################ + #%% redefine df_data, only keep matched cells! + ################################################################################ + + if use_matched_cells!=0: + + # get cells for this session + cells_to_keep = matched_cells[matched_cells['ophys_session_id']==session_id]['cell_specimen_id'].unique() + + if len(cells_to_keep)==0: # this should never happen because in svm_images_init we reset list all sessions valid to list all sessions valid matched; ie we only go through sessions that have matched cells + sys.exit(f'Exiting analysis! No matched cells across 3 experience levels for session {session_id}!') + + + d = df_data0['cell_specimen_id'].unique() + d = d[~np.isnan(d)] + a = d.shape[0] + b = cells_to_keep.shape[0] + # note: the number below includes all experiments of a mesoscope session if analyzing a mesosocope session + print(f"\n{b}/{a}, {100*b/a:.0f}% of {data_list['cre_line'].iloc[0][:3]} cells in this session are matched in all 3 experience levels.\n") + + if project_codes == 'VisualBehaviorMultiscope': # print number of matched cells per experiment (plane) + for en in experiment_ids_valid: # en = experiment_ids_valid[0] + p = matched_cells[matched_cells['ophys_experiment_id']==en]['cell_specimen_id'].unique() + n = df_data0[df_data0['ophys_experiment_id']==en]['cell_specimen_id'].unique().shape[0] + print(f'\t{p.shape[0]} out of {n} cells are matched for experiment {en}') + + + #### reset df_data, only include those rows that are for matched cells + df_data = df_data0[df_data0['cell_specimen_id'].isin(cells_to_keep)] +# df_data0.shape, df_data.shape, df_data['ophys_experiment_id'].unique() + + + + ### some tests related to images changes in stim df vs. trials df + # trials_response_df[~np.in1d(range(len(trials_response_df)), stimdf_ind_in_trdf)]['trial_type'].unique() + # trials_response_df[~np.in1d(range(len(trials_response_df)), stimdf_ind_in_trdf)]['catch'].unique() + + # trials_response_df.keys() # 'hit', 'false_alarm', 'miss', 'correct_reject', 'aborted', 'go', 'catch', 'auto_rewarded', 'stimulus_change' + # stimdf_ind_in_trdf.shape + + + # (trialsdf_existing_in_stimdf['catch']==True).sum() + # a = trialsdf_existing_in_stimdf[trialsdf_existing_in_stimdf['go']==False] + # a['stimulus_change'] + # a['lick_times'] + # a['auto_rewarded'] + + # b = scdf[(trialsdf_existing_in_stimdf['go']==False).values] + # b['licked'] + # b['rewarded'] + # b['start_time'] + + ''' + trials_response_df[trials_response_df['auto_rewarded']==True]['catch'] # all autorewarded are marked as neither catch or go. + + # find the change cases where animal licked but no reward is delivered and see if they are catch or not, if not whats wrong? (seems like stim df does not have catches, but has one of these weird cases) + d = np.logical_and(np.logical_and((stim_response_df['licked']==1) , (stim_response_df['rewarded']==0)) , (stim_response_df['change']==True)) + dd = np.argwhere(d).flatten() + stim_response_df.iloc[dd] + stim_response_df[dd[1]] + ''' + + #################################################################################### + #################################################################################### + #%% Set frames_svm + + # Note: trials df has a much longer time_trace (goes up to 4.97) compared to stimulus df (goes up to .71), so frames_svm ends up being 1 element longer for trials df (ie when decoding hits from misses) compared to stimulus df (ie when decoding the images) + + # trace_time = np.array([-0.46631438, -0.3730515 , -0.27978863, -0.18652575, -0.09326288, + # 0. , 0.09326288, 0.18652575, 0.27978863, 0.3730515 , + # 0.46631438, 0.55957726, 0.65284013]) + + # trace_time = array([-0.48482431, -0.45250269, -0.42018107, -0.38785944, -0.35553782, + # -0.3232162 , -0.29089458, -0.25857296, -0.22625134, -0.19392972, + # -0.1616081 , -0.12928648, -0.09696486, -0.06464324, -0.03232162, + # 0. , 0.03232162, 0.06464324, 0.09696486, 0.12928648, + # 0.1616081 , 0.19392972, 0.22625134, 0.25857296, 0.29089458, + # 0.3232162 , 0.35553782, 0.38785944, 0.42018107, 0.45250269, + # 0.48482431, 0.51714593, 0.54946755, 0.58178917, 0.61411079, + # 0.64643241, 0.67875403, 0.71107565, 0.74339727]) + + + first_valid_row = int(np.argwhere(np.array([type(df_data['trace_timestamps'].iloc[i])==float for i in range(len(df_data))])==False)[0]) + trace_time = df_data.iloc[first_valid_row]['trace_timestamps'] + + # set samps_bef and samps_aft: on the image-aligned traces, samps_bef frames were before the image, and samps_aft-1 frames were after the image + samps_bef = np.argwhere(trace_time==0)[0][0] # 5 + samps_aft = len(trace_time)-samps_bef #8 + print(samps_bef, samps_aft) + + r1 = np.argwhere((trace_time-time_win[0])>=0)[0][0] + r2 = np.argwhere((trace_time-time_win[1])>=0) + if len(r2)>0: + r2 = r2[0][0] + else: + r2 = len(trace_time) + + frames_svm = range(r1, r2)-samps_bef # range(-10, 30) # range(-1,1) # run svm on these frames relative to trial (image/omission) onset. + print(frames_svm) + + # samps_bef (=40) frames before omission ; index: 0:39 + # omission frame ; index: 40 + # samps_aft - 1 (=39) frames after omission ; index: 41:79 + + + + + + #%% + cols_basic = np.array(['session_id', 'experiment_id', 'mouse_id', 'container_id', 'date', 'cre', 'stage', 'experience_level', 'area', 'depth', 'n_trials', 'n_neurons', 'cell_specimen_id', 'frame_dur', 'samps_bef', 'samps_aft']) #, 'flash_omit_dur_all', 'flash_omit_dur_fr_all']) + cols_svm_0 = ['frames_svm', 'to_decode', 'use_balanced_trials', 'thAct', 'numSamples', 'softNorm', 'kfold', 'regType', 'cvect', 'meanX_allFrs', 'stdX_allFrs', + 'image_labels', 'image_indices', 'image_indices_previous_flash', 'image_indices_next_flash', + 'num_classes', 'iblock', 'trials_blocks', 'engagement_pupil_running', 'pupil_running_values' , + 'cbest_allFrs', 'w_data_allFrs', 'b_data_allFrs', + 'perClassErrorTrain_data_allFrs', 'perClassErrorTest_data_allFrs', + 'perClassErrorTest_shfl_allFrs', 'perClassErrorTest_chance_allFrs'] + if same_num_neuron_all_planes: + cols_svm = np.concatenate((cols_svm_0, ['inds_subselected_neurons_all', 'population_sizes_to_try', 'numShufflesN'])) + + else: + cols_svm = np.concatenate((cols_svm_0, ['testTrInds_allSamps_allFrs', 'Ytest_allSamps_allFrs', 'Ytest_hat_allSampsFrs_allFrs'])) + + + + + #%% Run the SVM function + + c = data_list['cre_line'].iloc[0][:3] + s = data_list['session_type'].iloc[0] + # numSamples = 2 + print(f'\n\n======================== Analyzing {c}, {s}\nsession %d, %d/%d ========================\n' %(session_id, isess, len(list_all_sessions_valid))) + + # Use below if you set session_data and session_trials above: for VIP and SST + svm_images_main_pbs(session_id, data_list, experiment_ids_valid, df_data, session_trials, trial_type, dir_svm, kfold, frames_svm, numSamples, saveResults, cols_basic, cols_svm, project_codes, to_decode, svm_blocks, engagement_pupil_running, use_events, same_num_neuron_all_planes, use_balanced_trials, use_spont_omitFrMinus1, use_matched_cells) + + # svm_main_images_pbs(data_list, df_data, session_trials, trial_type, dir_svm, kfold, frames_svm, numSamples, saveResults, cols_basic, cols_svm, to_decode, svm_blocks, use_events, same_num_neuron_all_planes) + + # Use below if you set stimulus_response_df_allexp above: for Slc (can be also used for other cell types too; but we need it for Slc, as the concatenated dfs could not be set for it) + # svm_main_images_pbs(data_list, stimulus_response_df_allexp, dir_svm, frames_svm, numSamples, saveResults, cols_basic, cols_svm, same_num_neuron_all_planes=0) + + + + + +###################################################### +###################################################### +#%% For SLURM +###################################################### +###################################################### + +import argparse + +if __name__ == "__main__": + + # define args + parser = argparse.ArgumentParser() + + parser.add_argument('--isess', type=int) + parser.add_argument('--project_codes', type=str) + parser.add_argument('--use_events', type=int) + parser.add_argument('--to_decode', type=str) + parser.add_argument('--trial_type', type=str) + parser.add_argument('--svm_blocks', type=int) + parser.add_argument('--engagement_pupil_running', type=int) + parser.add_argument('--use_spont_omitFrMinus1', type=int) + parser.add_argument('--use_balanced_trials', type=int) + parser.add_argument('--use_matched_cells', type=int) + + args = parser.parse_args() + + + + + # call the function + svm_images_main_pre_pbs( + args.isess, + args.project_codes, + args.use_events, + args.to_decode, + args.trial_type, + args.svm_blocks, + args.engagement_pupil_running, + args.use_spont_omitFrMinus1, + args.use_balanced_trials, + args.use_matched_cells) + + + + + + +#%% Old method: match cells across "sessions" (not experience levels) +''' +# codes below are adapted from marina's notebook: https://gist.github.com/matchings/880aee8adf9c1c6c56e994df511c4c3d ###### + +from allensdk.brain_observatory.behavior.behavior_project_cache import VisualBehaviorOphysProjectCache + +cache = VisualBehaviorOphysProjectCache.from_lims() +cell_table = cache.get_ophys_cells_table() + +# cell_table = loading.get_cell_table(ophys_session_ids=experiments_table.index.unique()) + +# merge in metadata to get experience level +cell_table = cell_table.merge(experiments_table, on='ophys_experiment_id') + + +if use_matched_cells==123: + experience_levels = ['Familiar', 'Novel 1', 'Novel >1'] +else: + if use_matched_cells==12: # limit to cells in Familiar or Novel 1 + experience_levels = ['Familiar', 'Novel 1'] + elif use_matched_cells==23: + experience_levels = ['Novel 1', 'Novel >1'] + elif use_matched_cells==13: + experience_levels = ['Familiar', 'Novel >1'] + + # only get those rows of cell_table that belong to experience_levels + + cell_table = cell_table[cell_table.experience_level.isin(experience_levels)] + + + +n_sessions_matched = len(experience_levels) + + +# get the number of unique experience levels per cell specimen id +n_unique_sessions_per_cell = cell_table.groupby(['cell_specimen_id'])['experience_level'].nunique().reset_index() + +# only keep those cells that have all the experience levels defined above +matched_cell_table = n_unique_sessions_per_cell[n_unique_sessions_per_cell['experience_level'] == n_sessions_matched] +matched_cell_ids = matched_cell_table['cell_specimen_id'].unique() + +# also get the session ids that have all the experience levels... so you dont run the analysis on sessions that only have 2 of the experience levels. + + + +####################### marina's method ####################### +# group by cell and experience level to figure out how many sessions each cell has for each experience level +exp_matched = cell_table.groupby(['cell_specimen_id', 'experience_level', 'ophys_experiment_id']).count() +exp_matched = exp_matched.reset_index() + +### NOTE: we do the following for now until Marina averages the multiple values for an experience level + +# drop rows where a single cell_specimen_id has more than one session for each experience level¶ +exp_matched = exp_matched.drop_duplicates(subset=['cell_specimen_id', 'experience_level']) + + +# count how many remaining sessions there are per cell and experience level +n_matched = exp_matched.groupby(['cell_specimen_id']).count()[['experience_level']].rename(columns={'experience_level':'n_sessions_matched'}) + +# only keep cells that have 3 sessions - one per experience level, i.e. cells that are matched in all 3 types +matched_cell_ids = n_matched[n_matched['n_sessions_matched']==n_sessions_matched].index.unique() +################################################################ + + +print(len(matched_cell_ids), len(cell_table.cell_specimen_id.unique())) +print(np.round(len(matched_cell_ids)/len(cell_table['cell_specimen_id'].unique()),3)*100, 'percent of cells are matched in all 3 experience levels') + + +# get list of matched cells with other metadata including experiment and session ID +tmp = exp_matched[['cell_specimen_id', 'ophys_experiment_id']].merge(experiments_table, on='ophys_experiment_id') + +matched_cells = tmp[tmp.cell_specimen_id.isin(matched_cell_ids)] +# print(len(matched_cells.cell_specimen_id.unique())) +# matched_cells + + +# This list only includes cells that are matched across sessions for Familiar, Novel 1, Novel >1¶ +# There is only one session of each type per cell + +# Save it +# save_dir = r'\\allen\programs\braintv\workgroups\nc-ophys\visual_behavior\platform_paper_cache\matched_cell_lists' +# matched_cells.to_csv(os.path.join(save_dir, 'cells_matched_across_experience_levels.csv')) + +''' diff --git a/visual_behavior/decoding_population/svm_images_plots_compare_experience_levels.py b/visual_behavior/decoding_population/svm_images_plots_compare_experience_levels.py new file mode 100644 index 000000000..508c04d05 --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_compare_experience_levels.py @@ -0,0 +1,424 @@ +""" +Gets called in svm_images_plots_setVars.py + +Makes summary errorbar plots for svm decoding accuracy across the experience levels + +Vars needed here are set in svm_images_plots_setVars_sumMice3_svmdf.py + +Created on Fri Oct 29 22:02:05 2021 +@author: farzaneh + +""" + +import matplotlib.gridspec as gridspec +import seaborn +import visual_behavior.visualization.utils as utils +import scipy.stats as st +import statsmodels.api as sm +from statsmodels.formula.api import ols +from statsmodels.stats.multicomp import (pairwise_tukeyhsd, MultiComparison) +from anova_tukey_fn import * + +# sigval = .05 # value for ttest significance +fmt_all = ['o', 'x'] +fmt_now = fmt_all[0] +if baseline_subtract: # subtract the baseline (CA average during baseline, ie before time 0) from the evoked CA (classification accuracy) + ylabs = '% Class accuracy rel. baseline' #'Amplitude' +else: + ylabs = '% Classification accuracy' #'Amplitude' +cres = ['Slc17a7', 'Sst', 'Vip'] + + +# svm_df_all = pd.concat(svm_df_allpr) + + +############################################################################################################################## +############################################################################################################################## +#%% Plot response amplitude for **experience levels**: +# errorbars comparing SVM decoding accuracy (averaged across all experiemnts) across experience levels; +# also do anova/tukey +############################################################################################################################## +############################################################################################################################## + + + +############################################################################################################################## +#%% Compute p values and ttest stats between actual and shuffled +############################################################################################################################## + +p_act_shfl = np.full((len(cres), len(exp_level_all)), np.nan) +icre = -1 +for crenow in cres: # crenow = cres[0] + icre = icre+1 + iexpl = -1 + for expl in exp_level_all: # expl = exp_level_all[0] + iexpl = iexpl+1 + + a = svm_df_all[np.logical_and(svm_df_all['cre_allPlanes']==crenow , svm_df_all['experience_levels']==expl)] + + a_amp = np.vstack(a['peak_amp_allPlanes_allExp'].values)[:,1] # n_exp + b_amp = np.vstack(a['peak_amp_allPlanes_allExp'].values)[:,2] # n_exp + print(a_amp.shape, b_amp.shape) + print(sum(~np.isnan(a_amp)), sum(~np.isnan(b_amp))) + + _, p = st.ttest_ind(a_amp, b_amp, nan_policy='omit') #, axis=1, equal_var=equal_var) + p_act_shfl[icre, iexpl] = p + +p_act_shfl_sigval = p_act_shfl+0 +p_act_shfl_sigval[p_act_shfl <= sigval] = 1 +p_act_shfl_sigval[p_act_shfl > sigval] = np.nan + +print(f'\n---------------------\n') +print(f'Actual vs. shuffled data significance, for each experience level') +print(p_act_shfl_sigval) +print(f'\n---------------------\n') + + + + +############################################################################################################################## +#%% Do stats; for each cre line, are the 3 experience levels significantly different? do anova; then tukey +############################################################################################################################## + +if np.isnan(svm_blocks) or svm_blocks==-101: # svm was run on the whole session (no block by block analysis) + + svm_df = svm_df_all.rename(columns={'cre_allPlanes': 'cre'}) + svm_df = svm_df.rename(columns={'peak_amp_allPlanes_allExp':'decoding_magnitude0'}) + + ########## take testing dataset decoding accuracy + test = np.array([svm_df['decoding_magnitude0'].values[i][1] for i in range(svm_df.shape[0])]) + svm_df['decoding_magnitude'] = list(test) + + ### call the anova/tukey function + label_stat='experience_levels' + values_stat = 'decoding_magnitude' + anova_all, tukey_all_ts = anova_tukey(svm_df, values_stat, label_stat, cres=cres) + + + ########## take testing minus shuffled dataset decoding accuracy + shfl = np.array([svm_df['decoding_magnitude0'].values[i][2] for i in range(svm_df.shape[0])]) + svm_df['decoding_magnitude'] = list(test-shfl) + + ### call the anova/tukey function + label_stat='experience_levels' + values_stat = 'decoding_magnitude' + anova_all, tukey_all_tsSh = anova_tukey(svm_df, values_stat, label_stat, cres=cres) + + + ########### keep tukey results for both test and test minus shuffled cases + tukey_all = [] + tukey_all.append(tukey_all_ts) # 2 (test-shfl ; test) x cres x tukey_table (ie 4 x7) : 2 x 3 x 4 x 7 + tukey_all.append(tukey_all_tsSh) + + + ''' + tukey_all = [] + for cre in cres: # cre = cresdf[0] + + print(f'\n\n----------- Perfoming ANOVA/TUKEY on {cre} -----------\n') + thiscre = svm_df[svm_df['cre_allPlanes']==cre] + + a_data_now = thiscre[['cre_allPlanes', 'experience_levels', 'peak_amp_allPlanes_allExp']] + a_data_now = a_data_now.rename(columns={'peak_amp_allPlanes_allExp': 'value'}) + + c = a_data_now.copy() + print(c.shape) + + + # only take valid values + c = c[np.array([~np.isnan(c['value'].values[i][0]) for i in range(c.shape[0])])] + print(c.shape) + + + # replace Familiar, Novel 1, and Novel >1 in the df with 0, 1, and 2 + cnt = -1 + b = pd.DataFrame() + for expl in exp_level_all: + cnt = cnt+1 + a = c[c['experience_levels']==expl] + a['experience_levels'] = [cnt for x in a['experience_levels']] + b = pd.concat([b,a]) + c = b + + + #### set the column "value" in the df that goes into anova model + + # take test and shuffle values + test = np.array([c['value'].values[i][1] for i in range(c.shape[0])]) + shfl = np.array([c['value'].values[i][2] for i in range(c.shape[0])]) + + tukey_all_ts_tsSh = [] + for j in range(2): + if j==0: # run stats on test values + v = test + elif j==1: # run stats on test-shuffle values + v = test-shfl + # v.shape + + c['value'] = list(v) + # c + + + ############ ANOVA, 1-way ############ + model = ols('value ~ C(experience_levels)', data=c).fit() + anova_table = sm.stats.anova_lm(model, typ=2) + print(anova_table) + print('\n') + + + ### TUKEY HSD + v = c['value'] + f = c['experience_levels'] + + MultiComp = MultiComparison(v, f) + # MultiComp.tukeyhsd().summary() + print(MultiComp.tukeyhsd().summary()) # Show all pair-wise comparisons + + + tukey_all_ts_tsSh.append(MultiComp.tukeyhsd().summary()) + + tukey_all.append(tukey_all_ts_tsSh) # cres x 2 (test-shfl ; test) x tukey_table (ie 4 x7) + ''' + + + +############################################################################################################################## +#%% Plot error bars for the SVM decoding accuracy across the 3 experience levels, for each cre line +############################################################################################################################## + +colors = utils.get_experience_level_colors() # will always be in order of Familiar, Novel 1, Novel >1 + +if project_codes_all == ['VisualBehaviorMultiscope']: + x = np.array([0,1,2,3])*len(whichStages)*1.1 +else: + x = np.array([0]) + +if len(project_codes_all)==1: + areasn = ['V1', 'LM', 'V1,LM'] +else: + areasn = ['V1,LM', 'V1,LM', 'V1,LM'] # distinct_areas #['VISp'] + +addleg = 0 +xgapg = .15*len(exp_level_all)/1.1 # gap between sessions within a depth + +if np.isnan(svm_blocks) or svm_blocks==-101: # svm was run on the whole session (no block by block analysis) + + icre = -1 + for crenow in cres: # crenow = cres[0] + icre = icre+1 + + ####### set axes + plt.figure(figsize=(6,2.5)) + gs1 = gridspec.GridSpec(1,3) #, width_ratios=[3, 1]) + gs1.update(bottom=.15, top=0.8, left=0.05, right=0.95, wspace=.55, hspace=.5) + + allaxes = [] + ax1 = plt.subplot(gs1[0]) + allaxes.append(ax1) + ax2 = plt.subplot(gs1[1]) + allaxes.append(ax2) + ax3 = plt.subplot(gs1[2]) + allaxes.append(ax3) + + + ####### set df for all experience levels of a given cre line + df = resp_amp_sum_df[resp_amp_sum_df['cre']==crenow] + + mn = np.nanmin(df['shfl_av']-df['shfl_sd']) + mx = np.nanmax(df['test_av']+df['test_sd']) + + + ####### set some vars for plotting + stcn = -1 + xnowall = [] +# mn_mx_allstage = [] # min, max for each experience level + for expl in exp_level_all: # expl = exp_level_all[0] + stcn = stcn+1 + xnow = x + xgapg*stcn + xnowall.append(xnow) +# mn = np.nanmin(df['shfl_av']-df['shfl_sd']) +# mx = np.nanmax(df['test_av']+df['test_sd']) +# mn_mx_allstage.append([mn, mx]) + + xnowall0 = copy.deepcopy(xnowall) + + + ####### plot the errorbars, showing for each cre line, the svm decoding accuracy for the 3 experience levels + # ax1: plot test and shuffled + for pos, y, err, c in zip(xnowall, df['test_av'], df['test_sd'], colors): + ax1.errorbar(pos, y, err, fmt=fmt_now, markersize=5, color = c) # capsize = 0, capthick = 4, lw = 2, + for pos, y, err, c in zip(xnowall, df['shfl_av'], df['shfl_sd'], colors): + ax1.errorbar(pos, y, err, fmt=fmt_now, markersize=5, color = 'gray') + + # ax2: plot test - shuffle + for pos, y, err, c in zip(xnowall, df['test_av']-df['shfl_av'], df['test_sd']-df['shfl_sd'], colors): + ax2.errorbar(pos, y, err, fmt=fmt_now, markersize=5, color = c) + + + + ####### take care of plot labels, etc; do this for each figure; ie each cre line +# ylims_now = [np.nanmin(ylims), np.nanmax(ylims)] + + plt.suptitle(crenow, fontsize=18, y=1.15) + + iax = -1 # V1, LM + for ax in allaxes: #[ax1,ax2,ax3]: + iax=iax+1 + if project_codes_all == ['VisualBehaviorMultiscope']: + ax.set_xticks(x) # depth + ax.set_xticklabels(xticklabs, rotation=45) + ax.set_xlim([-1, xnowall[-1][-1]+1]) # x[-1]+xgap+.5 # -.5-xgapg + else: + ax.set_xticks(np.array(xnowall0).flatten()) + ax.set_xticklabels(exp_level_all, rotation=45) + ax.set_xlim([-.5, xnowall0[-1][-1]+.5]) # x[-1]+xgap+.5 + + ax.tick_params(labelsize=10) +# ax.set_xlabel(xlabs, fontsize=12) +# ax.set_ylim(ylims_now) + if ax==ax1: + ax.set_ylabel(ylabs, fontsize=12) #, labelpad=35) # , rotation=0 + ax.set_title(f'data\n{areasn[iax]}', y=1.1) + if ax==ax2: + ax.set_title(f'data-shuffle\n{areasn[iax]}', y=1.1) + if ax==ax3: # print number of experiments per experience level + ax.set_title(f"n experiments\n{df['n_experiments'].values.astype(int)}", y=1.1) + + + + ####### add legend + bb = (.97,.8) + if project_codes_all == ['VisualBehaviorMultiscope']: + ax = ax3 + else: + ax = ax1 + if addleg: + ax.legend(loc='center left', bbox_to_anchor=[bb[0]+xgapg, bb[1]], frameon=True, handlelength=1, fontsize=12, numpoints=1) + + seaborn.despine() + + + + + ############### add_tukey_lines: if a pariwaise tukey comparison is significant add a line and an asterisk symbol + iax = -1 + for ax in [ax1, ax2]: # test, test-shfl # ax = ax1 + iax = iax+1 + + x_new = xnowall + tukey = tukey_all[iax][icre] +# print(tukey) + + if ax==ax1: # testing data + y_new = df['test_av']+df['test_sd'] #top[inds_now, 1] + top_sd[inds_now, 1] + mn = np.nanmin(df['shfl_av']-df['shfl_sd']) + mx = np.nanmax(df['test_av']+df['test_sd']) + elif ax==ax2: # test-shfl + y_new = (df['test_av']-df['shfl_av']) + df['test_sd'] + mn = np.nanmin((df['test_av']-df['shfl_av']) - df['test_sd']) + mx = np.nanmax((df['test_av']-df['shfl_av']) + df['test_sd']) +# print(mn,mx) + + + t = np.array(tukey.data) + # print(t.shape) + # depth index for group 1 in tukey table + g1inds = np.unique(np.array([t[i][[0,1]] for i in np.arange(1,t.shape[0])]).astype(int)[:,0]) + g2inds = np.unique(np.array([t[i][[0,1]] for i in np.arange(1,t.shape[0])]).astype(int)[:,1]) + # print(g1inds, g2inds) + cnt = 0 + cntr = 0 + for group1_ind in g1inds: #range(3): + for group2_ind in g2inds[g2inds > group1_ind]: #np.arange(group1_ind+1, 4): + # print(group1_ind, group2_ind) + cnt = cnt+1 + # x_new = xnowall[0] # ophys3 + + if tukey.data[cnt][-1] == False: + txtsig = "ns" + else: + txtsig = "*" + cntr = cntr+1 + r = cntr*((mx-mn)/10) + + x1, x2 = x_new[group1_ind], x_new[group2_ind] + y, h, col = np.max([y_new.values[group1_ind], y_new.values[group2_ind]]) + r, (mx-mn)/20, 'k' + + ax.plot([x1, x1, x2, x2], [y, y+h, y+h, y], lw=1.5, c=col, clip_on=True) #, transform=trans) + ax.text((x1+x2)*.5, y+h, txtsig, ha='center', va='bottom', color=col) + + # plot the line outside, but it didnt work: + # https://stackoverflow.com/questions/47597534/how-to-add-horizontal-lines-as-annotations-outside-of-axes-in-matplotlib + + ylim = ax.get_ylim() + print(ylim) + + + + + + + #### + if dosavefig: + + whatSess = f'_summaryExperienceLevels' + + fgn = '' #f'{whatSess}' + if same_num_neuron_all_planes: + fgn = fgn + '_sameNumNeursAllPlanes' + + if baseline_subtract==1: + bln = f'timewin{time_win}_blSubtracted' + else: + bln = f'timewin{time_win}_blNotSubtracted' + + if svm_blocks==-1: + word = 'engaged_disengaged_blocks_' + elif svm_blocks==-101: + word = 'only_engaged_' + elif ~np.isnan(svm_blocks): + word = 'blocks_' + else: + word = '' + + if use_events: + word = word + 'events' + + word = word + '_anovaTukey' + + + fgn = f'{fgn}_{word}' + if len(project_codes_all)==1: + fgn = f'{fgn}_frames{frames_svm[0]}to{frames_svm[-1]}' + fgn = fgn + '_ClassAccur' + fgn = f'{fgn}_allProjects' + + if len(project_codes_all)==1: + pcn = project_codes_all[0] + '_' + else: + pcn = '' + for ipc in range(len(project_codes_all)): + pcn = pcn + project_codes_all[ipc][0] + '_' + pcn = pcn[:-1] + + fgn = f'{fgn}_{pcn}' + + nam = f'{crenow[:3]}{whatSess}_{bln}_aveExpPooled{fgn}_{now}' + + fign = os.path.join(dir0, 'svm', dir_now, nam+fmt) + print(fign) + + + plt.savefig(fign, bbox_inches='tight') # , bbox_extra_artists=(lgd,) + + + + +#%% Print these p values + +print(f'\n---------------------\n') +print(f'Actual vs. shuffled data significance, for each experience level') +print(p_act_shfl_sigval) +print(f'\n---------------------\n') + + \ No newline at end of file diff --git a/visual_behavior/decoding_population/svm_images_plots_compare_experience_levels_area_depth.py b/visual_behavior/decoding_population/svm_images_plots_compare_experience_levels_area_depth.py new file mode 100644 index 000000000..ef981b370 --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_compare_experience_levels_area_depth.py @@ -0,0 +1,498 @@ +""" +Gets called in svm_images_plots_setVars.py + +Makes summary errorbar plots for svm decoding accuracy comparing depth and area for each experience level. + +Vars needed here are set in svm_images_plots_setVars_sumMice3_resp_sum_area_depth.py + +Created on Fri Oct 29 22:02:05 2021 +@author: farzaneh + +""" + +import matplotlib.gridspec as gridspec +import seaborn +import visual_behavior.visualization.utils as utils +import scipy.stats as st +import statsmodels.api as sm +from statsmodels.formula.api import ols +from statsmodels.stats.multicomp import (pairwise_tukeyhsd, MultiComparison) +from anova_tukey_fn import * + +sigval = .05 # value for ttest significance +fmt_all = ['o', 'x'] +fmt_now = fmt_all[0] +if baseline_subtract: # subtract the baseline (CA average during baseline, ie before time 0) from the evoked CA (classification accuracy) + ylabs = '% Class accuracy rel. baseline' #'Amplitude' +else: + ylabs = '% Classification accuracy' #'Amplitude' + +cres = ['Slc17a7', 'Sst', 'Vip'] + + +###### +# labsad = ['LM', 'V1'] +labsad = ['<200um', '>200um'] + +# svm_df_all = pd.concat(svm_df_allpr) + + +############################################################################################################################## +############################################################################################################################## +#%% Plot response amplitude for depth/area comparison within each experience levels: +# errorbars comparing SVM decoding accuracy (averaged across all experiemnts) between V1/LM or superifical/deep layers for each experience level; +############################################################################################################################## +############################################################################################################################## + + +### Area comparison plots + +############################################################################################################################## +#%% Plot error bars for the SVM decoding accuracy across the 3 experience levels, for each cre line +############################################################################################################################## + +group_col = 'area' +# group_col = 'binned_depth' + +# colors = utils.get_experience_level_colors() # will always be in order of Familiar, Novel 1, Novel >1 + +colors_bin1 = ['gray', 'gray', 'gray'] # lm; first element of resp_amp_sum_df_area for each cre and exp level +colors_bin2 = ['k', 'k', 'k'] # v1; second element of resp_amp_sum_df_area for each cre and exp level +colors = np.vstack([colors_bin1, colors_bin2]).T.flatten() + +if project_codes_all == ['VisualBehaviorMultiscope']: + x = np.array([0,1,2,3])*len(whichStages)*1.1 +else: + x = np.array([0]) + +if len(project_codes_all)==1: + areasn = ['V1', 'LM', 'V1,LM'] +else: + areasn = ['V1,LM', 'V1,LM', 'V1,LM'] # distinct_areas #['VISp'] + +addleg = 0 +xgapg = .15*len(exp_level_all)/1.1 # gap between sessions within a depth + +if np.isnan(svm_blocks) or svm_blocks==-101: # svm was run on the whole session (no block by block analysis) + + icre = -1 + for crenow in cres: # crenow = cres[0] + icre = icre+1 + + ############################################################################# + ####### set axes + plt.figure(figsize=(6,2.5)) + gs1 = gridspec.GridSpec(1,3) #, width_ratios=[3, 1]) + gs1.update(bottom=.15, top=0.8, left=0.05, right=0.95, wspace=.55, hspace=.5) + + allaxes = [] + ax1 = plt.subplot(gs1[0]) + allaxes.append(ax1) + ax2 = plt.subplot(gs1[1]) + allaxes.append(ax2) +# ax3 = plt.subplot(gs1[2]) +# allaxes.append(ax3) + + + ############################################################################# + ####### set df for all experience levels of a given cre line + df = resp_amp_sum_df_area[resp_amp_sum_df_area['cre']==crenow] +# df = resp_amp_sum_df_depth[resp_amp_sum_df_depth['cre']==crenow] + + mn = np.nanmin(df['shfl_av']-df['shfl_sd']) + mx = np.nanmax(df['test_av']+df['test_sd']) + + + ############################################################################# + ####### set some vars for plotting + stcn = -1 + xnowall = [] +# mn_mx_allstage = [] # min, max for each experience level + for expl in exp_level_all: # expl = exp_level_all[0] + stcn = stcn+1 + xnow = x + xgapg*stcn + xnowall.append(xnow) +# mn = np.nanmin(df['shfl_av']-df['shfl_sd']) +# mx = np.nanmax(df['test_av']+df['test_sd']) +# mn_mx_allstage.append([mn, mx]) + + xnowall0 = copy.deepcopy(xnowall) + xnowall = np.hstack([xnowall, xnowall]).flatten() + + legs = np.hstack([df[group_col][:2].values, '_nolegend_', '_nolegend_', '_nolegend_', '_nolegend_']) + + + ############################################################################# + ####### plot the errorbars, showing for each cre line, the svm decoding accuracy for the 3 experience levels + # ax1: plot test and shuffled + # testing data + for pos, y, err, c,l in zip(xnowall, df['test_av'], df['test_sd'], colors, legs): + ax1.errorbar(pos, y, err, fmt=fmt_now, markersize=5, color = c, label=l) # capsize = 0, capthick = 4, lw = 2, + + # shuffled data + for pos, y, err, c in zip(xnowall, df['shfl_av'], df['shfl_sd'], colors): + ax1.errorbar(pos, y, err, fmt=fmt_now, markersize=5, color = 'lightsteelblue') + + # ax2: plot test - shuffle + for pos, y, err, c in zip(xnowall, df['test_av']-df['shfl_av'], df['test_sd']-df['shfl_sd'], colors): + ax2.errorbar(pos, y, err, fmt=fmt_now, markersize=5, color = c) + + + ############################################################################# + ####### plot an asterisk if p_area is significant + + p = p_depth_area_df[p_depth_area_df['cre']==crenow]['sig_area'].values # p_area_sigval[icre] + ax1.plot(np.array(xnowall0).flatten(), p*mx-np.diff([mn,mx])*.03, color='tomato', marker='*', linestyle='') # cols_stages[stcn] + + + ############################################################################# + ####### take care of plot labels, etc; do this for each figure; ie each cre line +# ylims_now = [np.nanmin(ylims), np.nanmax(ylims)] + + plt.suptitle(crenow, fontsize=18, y=1.15) + + iax = -1 # V1, LM + for ax in allaxes: #[ax1,ax2,ax3]: + iax=iax+1 + if project_codes_all == ['VisualBehaviorMultiscope']: + ax.set_xticks(x) # depth + ax.set_xticklabels(xticklabs, rotation=45) + ax.set_xlim([-1, xnowall[-1][-1]+1]) # x[-1]+xgap+.5 # -.5-xgapg + else: + ax.set_xticks(np.array(xnowall0).flatten()) + ax.set_xticklabels(exp_level_all, rotation=45) + ax.set_xlim([-.5, xnowall0[-1][-1]+.5]) # x[-1]+xgap+.5 + + ax.tick_params(labelsize=10) +# ax.set_xlabel(xlabs, fontsize=12) +# ax.set_ylim(ylims_now) + if ax==ax1: + ax.set_ylabel(ylabs, fontsize=12) #, labelpad=35) # , rotation=0 + ax.set_title(f'data\nall depths', y=1.1) + if ax==ax2: + ax.set_title(f'data-shuffle\nall depths', y=1.1) + + +# if ax==ax3: # print number of experiments per experience level +# ax.set_title(f"n experiments\n{df['n_experiments'].values.astype(int)}", y=1.1) + + + ############################################################################# + ####### add legend + bb = (.4, 1.2) + if project_codes_all == ['VisualBehaviorMultiscope']: + ax = ax3 + else: + ax = ax1 + + if 1: #addleg: + ax.legend(loc='center left', bbox_to_anchor=[bb[0]+xgapg, bb[1]], frameon=True, handlelength=1, fontsize=12, numpoints=1, prop={'size': 10}) + + seaborn.despine() + + + + + + + + #### + if dosavefig: + + whatSess = f'_summaryExperienceLevelsArea' + + if use_matched_cells==123: + whatSess = whatSess + '_matched_cells_FN1N2' #Familiar, N1, N+1 + elif use_matched_cells==12: + whatSess = whatSess + '_matched_cells_FN1' + elif use_matched_cells==23: + whatSess = whatSess + '_matched_cells_N1Nn' + elif use_matched_cells==13: + whatSess = whatSess + '_matched_cells_FNn' + + + fgn = '' #f'{whatSess}' + if same_num_neuron_all_planes: + fgn = fgn + '_sameNumNeursAllPlanes' + + if baseline_subtract==1: + bln = f'timewin{time_win}_blSubtracted' + else: + bln = f'timewin{time_win}_blNotSubtracted' + + if svm_blocks==-1: + word = 'engaged_disengaged_blocks_' + elif svm_blocks==-101: + word = 'only_engaged_' + elif ~np.isnan(svm_blocks): + word = 'blocks_' + else: + word = '' + + if use_events: + word = word + 'events' + +# word = word + '_anovaTukey' + + + fgn = f'{fgn}_{word}' + if len(project_codes_all)==1: + fgn = f'{fgn}_frames{frames_svm[0]}to{frames_svm[-1]}' + fgn = fgn + '_ClassAccur' + fgn = f'{fgn}_allProjects' + + pcn = project_codes_all[2][0] + '_' # 'VisualBehaviorMultiscope' +# if len(project_codes_all)==1: +# pcn = project_codes_all[0] + '_' +# else: +# pcn = '' +# for ipc in range(len(project_codes_all)): +# pcn = pcn + project_codes_all[ipc][0] + '_' + pcn = pcn[:-1] + + fgn = f'{fgn}_{pcn}' + + nam = f'{crenow[:3]}{whatSess}_{bln}_aveExpPooled{fgn}_{now}' + + fign = os.path.join(dir0, 'svm', dir_now, nam+fmt) + print(fign) + + + plt.savefig(fign, bbox_inches='tight') # , bbox_extra_artists=(lgd,) + + + + +######################################################## +######################################################## +######################################################## +######################################################## +######################################################## +######################################################## +######################################################## +######################################################## +######################################################## +######################################################## +######################################################## +######################################################## + +# Depth comparison plots + + +############################################################################################################################## +#%% Plot error bars for the SVM decoding accuracy across the 3 experience levels, for each cre line +############################################################################################################################## + +# group_col = 'area' +group_col = 'binned_depth' + +# labsad = ['LM', 'V1'] +# labsad = ['<200um', '>200um'] + +# colors = utils.get_experience_level_colors() # will always be in order of Familiar, Novel 1, Novel >1 + +colors_bin1 = ['gray', 'gray', 'gray'] # lm; first element of resp_amp_sum_df_area for each cre and exp level +colors_bin2 = ['k', 'k', 'k'] # v1; second element of resp_amp_sum_df_area for each cre and exp level +colors = np.vstack([colors_bin1, colors_bin2]).T.flatten() + +if project_codes_all == ['VisualBehaviorMultiscope']: + x = np.array([0,1,2,3])*len(whichStages)*1.1 +else: + x = np.array([0]) + +if len(project_codes_all)==1: + areasn = ['V1', 'LM', 'V1,LM'] +else: + areasn = ['V1,LM', 'V1,LM', 'V1,LM'] # distinct_areas #['VISp'] + +addleg = 0 +xgapg = .15*len(exp_level_all)/1.1 # gap between sessions within a depth + +if np.isnan(svm_blocks) or svm_blocks==-101: # svm was run on the whole session (no block by block analysis) + + icre = -1 + for crenow in cres: # crenow = cres[0] + icre = icre+1 + + ####### set axes + plt.figure(figsize=(6,2.5)) + gs1 = gridspec.GridSpec(1,3) #, width_ratios=[3, 1]) + gs1.update(bottom=.15, top=0.8, left=0.05, right=0.95, wspace=.55, hspace=.5) + + allaxes = [] + ax1 = plt.subplot(gs1[0]) + allaxes.append(ax1) + ax2 = plt.subplot(gs1[1]) + allaxes.append(ax2) +# ax3 = plt.subplot(gs1[2]) +# allaxes.append(ax3) + + + ####### set df for all experience levels of a given cre line +# df = resp_amp_sum_df_area[resp_amp_sum_df_area['cre']==crenow] + df = resp_amp_sum_df_depth[resp_amp_sum_df_depth['cre']==crenow] + + mn = np.nanmin(df['shfl_av']-df['shfl_sd']) + mx = np.nanmax(df['test_av']+df['test_sd']) + + + ############################################################################# + ####### set some vars for plotting + stcn = -1 + xnowall = [] +# mn_mx_allstage = [] # min, max for each experience level + for expl in exp_level_all: # expl = exp_level_all[0] + stcn = stcn+1 + xnow = x + xgapg*stcn + xnowall.append(xnow) +# mn = np.nanmin(df['shfl_av']-df['shfl_sd']) +# mx = np.nanmax(df['test_av']+df['test_sd']) +# mn_mx_allstage.append([mn, mx]) + + xnowall0 = copy.deepcopy(xnowall) + xnowall = np.hstack([xnowall, xnowall]).flatten() + +# legs = np.hstack([df[group_col][:2].values, '_nolegend_', '_nolegend_', '_nolegend_', '_nolegend_']) + legs = np.hstack([labsad, '_nolegend_', '_nolegend_', '_nolegend_', '_nolegend_']) + + + ############################################################################# + ####### plot the errorbars, showing for each cre line, the svm decoding accuracy for the 3 experience levels + # ax1: plot test and shuffled + for pos, y, err, c,l in zip(xnowall, df['test_av'], df['test_sd'], colors, legs): + ax1.errorbar(pos, y, err, fmt=fmt_now, markersize=5, color = c, label=l) # capsize = 0, capthick = 4, lw = 2, + + for pos, y, err, c in zip(xnowall, df['shfl_av'], df['shfl_sd'], colors): + ax1.errorbar(pos, y, err, fmt=fmt_now, markersize=5, color = 'lightsteelblue') + + # ax2: plot test - shuffle + for pos, y, err, c in zip(xnowall, df['test_av']-df['shfl_av'], df['test_sd']-df['shfl_sd'], colors): + ax2.errorbar(pos, y, err, fmt=fmt_now, markersize=5, color = c) + + + + ############################################################################# + ####### plot an asterisk if p_depth is significant + + p = p_depth_area_df[p_depth_area_df['cre']==crenow]['sig_depth'].values # p_depth_sigval[icre] + ax1.plot(np.array(xnowall0).flatten(), p*mx-np.diff([mn,mx])*.03, color='tomato', marker='*', linestyle='') # cols_stages[stcn] + + + ############################################################################# + ####### take care of plot labels, etc; do this for each figure; ie each cre line +# ylims_now = [np.nanmin(ylims), np.nanmax(ylims)] + + plt.suptitle(crenow, fontsize=18, y=1.15) + + iax = -1 # V1, LM + for ax in allaxes: #[ax1,ax2,ax3]: + iax=iax+1 + if project_codes_all == ['VisualBehaviorMultiscope']: + ax.set_xticks(x) # depth + ax.set_xticklabels(xticklabs, rotation=45) + ax.set_xlim([-1, xnowall[-1][-1]+1]) # x[-1]+xgap+.5 # -.5-xgapg + else: + ax.set_xticks(np.array(xnowall0).flatten()) + ax.set_xticklabels(exp_level_all, rotation=45) + ax.set_xlim([-.5, xnowall0[-1][-1]+.5]) # x[-1]+xgap+.5 + + ax.tick_params(labelsize=10) +# ax.set_xlabel(xlabs, fontsize=12) +# ax.set_ylim(ylims_now) + if ax==ax1: + ax.set_ylabel(ylabs, fontsize=12) #, labelpad=35) # , rotation=0 + ax.set_title(f'data\n{areasn[iax]}', y=1.1) + if ax==ax2: + ax.set_title(f'data-shuffle\n{areasn[iax]}', y=1.1) + + +# if ax==ax3: # print number of experiments per experience level +# ax.set_title(f"n experiments\n{df['n_experiments'].values.astype(int)}", y=1.1) + + + ############################################################################# + ####### add legend + bb = (.4, 1.2) + if project_codes_all == ['VisualBehaviorMultiscope']: + ax = ax3 + else: + ax = ax1 + + if 1: #addleg: + ax.legend(loc='center left', bbox_to_anchor=[bb[0]+xgapg, bb[1]], frameon=True, handlelength=1, fontsize=12, numpoints=1, prop={'size': 10}) + + seaborn.despine() + + + + + + + + #### + if dosavefig: + + whatSess = f'_summaryExperienceLevelsDepth' + + if use_matched_cells==123: + whatSess = whatSess + '_matched_cells_FN1N2' #Familiar, N1, N+1 + elif use_matched_cells==12: + whatSess = whatSess + '_matched_cells_FN1' + elif use_matched_cells==23: + whatSess = whatSess + '_matched_cells_N1Nn' + elif use_matched_cells==13: + whatSess = whatSess + '_matched_cells_FNn' + + + fgn = '' #f'{whatSess}' + if same_num_neuron_all_planes: + fgn = fgn + '_sameNumNeursAllPlanes' + + if baseline_subtract==1: + bln = f'timewin{time_win}_blSubtracted' + else: + bln = f'timewin{time_win}_blNotSubtracted' + + if svm_blocks==-1: + word = 'engaged_disengaged_blocks_' + elif svm_blocks==-101: + word = 'only_engaged_' + elif ~np.isnan(svm_blocks): + word = 'blocks_' + else: + word = '' + + if use_events: + word = word + 'events' + +# word = word + '_anovaTukey' + + + fgn = f'{fgn}_{word}' + if len(project_codes_all)==1: + fgn = f'{fgn}_frames{frames_svm[0]}to{frames_svm[-1]}' + fgn = fgn + '_ClassAccur' + fgn = f'{fgn}_allProjects' + + pcn = project_codes_all[2][0] + '_' # 'VisualBehaviorMultiscope' +# if len(project_codes_all)==1: +# pcn = project_codes_all[0] + '_' +# else: +# pcn = '' +# for ipc in range(len(project_codes_all)): +# pcn = pcn + project_codes_all[ipc][0] + '_' + pcn = pcn[:-1] + + fgn = f'{fgn}_{pcn}' + + nam = f'{crenow[:3]}{whatSess}_{bln}_aveExpPooled{fgn}_{now}' + + fign = os.path.join(dir0, 'svm', dir_now, nam+fmt) + print(fign) + + + plt.savefig(fign, bbox_inches='tight') # , bbox_extra_artists=(lgd,) + + + + diff --git a/visual_behavior/decoding_population/svm_images_plots_compare_ophys_stages.py b/visual_behavior/decoding_population/svm_images_plots_compare_ophys_stages.py new file mode 100644 index 000000000..026896947 --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_compare_ophys_stages.py @@ -0,0 +1,1208 @@ +""" +This script is called in "svm_images_plots_setVars_blocks.py" +Plot and compare svm class accuracy across ophys stages +Also make plots comparing experience levels +Do statistical tests (ttest; anova/tukey) between actual and shuffle; across depths; across ophys stages + + +Created on Tue Apr 27 12:09:05 2021 +@author: farzaneh + +""" + +whichStages_pval_allComparisonParis = [[3,4], [4,6]] # compute ttest between stages 3,4 also between 4,6. # whichStages_pval = [3,4] # compute ttest between these 2 stages +ttest_actShfl_stages = 1 # 0: plot ttet comparison of actual and shuffled (it will be the default when len(whichStages)=1)); 1: plot ttest comparison between ophys stages, as long as len(whichStages)=2 +show_depth_stats = 0 #1 # if 1, plot the bars that show anova/tukey comparison across depths + + +# whichStages: compare svm class accuracy for which stages? +# ttest will compare whichStages[0] and whichStages[1] +if trial_type =='hits_vs_misses': + whichStages = [1,3,4,6] +else: + if summary_which_comparison == 'novelty': + whichStages = [1,3,4,6] #[1,2,3,4,5,6] #[1,2] #[3,4] #stages to plot on top of each other to compare + elif summary_which_comparison == 'engagement': + whichStages = [1,2,3] # + elif summary_which_comparison == 'all': + whichStages = [1,2,3,4,5,6] + else: + whichStages = summary_which_comparison + +whichStages = np.array(whichStages) +if svm_blocks==-1 and engagement_pupil_running==0: # because the engagement metric relies on lick measurement, there wont be data for passive sessions + whichStages = whichStages[~np.in1d(whichStages, [2,5])] + print(f'Removing passive sessions because there is no data for them!') + + + + +import visual_behavior.visualization.utils as utils +colors = utils.get_colors_for_session_numbers() +# colors[2] = colors[0] +# familiar: colors[0] +# novel: colors[3] + +if len(whichStages)==1: + ttest_actShfl_stages = 0 + +fmt_now = fmt_all[0] + + + +#%% +import scipy.stats as st +import anova_tukey + +cres = ['Slc17a7', 'Sst', 'Vip'] +sigval = .05 # value for ttest significance +equal_var = False # needed for ttest # equal_var: If True (default), perform a standard independent 2 sample test that assumes equal population variances [1]. If False, perform Welch’s t-test, which does not assume equal population variance + +ophys_stage_labels = ['Familiar 1', 'Familiar 2', 'Familiar 3', 'Novel 1', 'Novel 2', 'Novel 3'] +inds_pooled = [[inds_v1[idepth] , inds_lm[idepth]] for idepth in range(len(inds_v1))] + +inds_lm_orig = inds_lm +if len(project_codes_all)>1: + inds_v1 = [0] + inds_lm = [np.nan] + + + + + +############################################################### +#%% function to plot the errorbars quanitfying response amplityde for each stage +############################################################### + +def errorbar_respamp(compare_areas=False): + +# tc = summary_vars_all[summary_vars_all['cre'] == crenow] + + if np.isnan(svm_blocks) or svm_blocks==-101: + tc_stage = tc[tc['stage'] == stagenow] + else: # svm was run on blocks of trials + tc_stage = tc[np.logical_and(tc['stage'] == stagenow , tc['block'] == iblock)] + + + ################# + if len(project_codes_all)==1: + pa_all = tc_stage['resp_amp'].values[0] # 8_planes x sessions x 4_trTsShCh +# print(pa_all.shape) + depth_ave = tc_stage['depth_ave'].values[0] + + else: + # reshape data from each project to to (planes x sessions) x 4 + r_allpr = [] + for ipc in range(len(project_codes_all)): + pa_all = tc_stage['resp_amp'].values[ipc] # 8_planes x sessions x 4_trTsShCh + # reshape to (planes x sessions) x 4 + r = np.reshape(pa_all, (pa_all.shape[0] * pa_all.shape[1], pa_all.shape[2]), order='F') # first all planes of session 1, then all planes of session 2, etc # r[:,-3], pa_all[:,1,-3] + r_allpr.append(r) + + # concatenate data from both projects + rr = np.concatenate((r_allpr)) # (planes x sessions) x 4 + pa_all = rr[np.newaxis, :] # 1 x (planes x sessions) x 4 + + # pool and average depths across both projects + depth_ave = [np.nanmean(np.concatenate((tc_stage['depth_ave'].values)))] + + inds_v1 = [0] + inds_lm = [np.nan] +# pa_all.shape + + + # average across both sessions and areas + if project_codes_all == ['VisualBehaviorMultiscope']: + top_pooled = np.array([np.nanmean(pa_all[inds_pooled[idepth]], axis=(0,1)) for idepth in range(num_depth)]) # 4depth (pooled areas) x 4_trTsShCh + top_sd_pooled = np.array([np.nanstd(pa_all[inds_pooled[idepth]], axis=(0,1)) / np.sqrt(2*pa_all.shape[1]) for idepth in range(num_depth)]) # 4depth (pooled areas) x 4_trTsShCh + else: + top_pooled = [] + top_sd_pooled = [] + + # average across sessions + top = np.nanmean(pa_all, axis=1) # 8_planes x 4_trTsShCh + top_sd = np.nanstd(pa_all, axis=1) / np.sqrt(pa_all.shape[1]) + ################# + + +# mn = np.nanmin(top[:,1]-top_sd[:,1]) + mn = np.nanmin(top[:,2]-top_sd[:,2]) + mx = np.nanmax(top[:,1]+top_sd[:,1]) +# top_allstage.append(top) +# mn_mx_allstage.append([mn, mx]) + + if compare_areas: + xnow = x + xgapg*areai + else: + xnow = x + xgapg*stcn +# xnowall.append(xnow) +# print(x+xgap) + + return xnow, top, top_sd, mn, mx, depth_ave, top_pooled, top_sd_pooled, pa_all + + + + +############################################################################## +####### take care of some plot labels etc +############################################################################## + + +def add_plot_labs(top_allstage, mn_mx_allstage, ylims, addleg=1, compare_areas=False): + + top_allstage = np.array(top_allstage) # we are not using this in this function!!! + mn_mx_allstage = np.array(mn_mx_allstage) + + mn_mx = [np.nanmin(mn_mx_allstage), np.nanmax(mn_mx_allstage)] +# print(f'icre {icre}, stage {stagenow-1}, mn_mx: {mn_mx}') + + if project_codes_all == ['VisualBehaviorMultiscope']: + xlabs = 'Depth (um)' + xticklabs = np.round(depth_ave).astype(int) # x = np.arange(num_depth) + else: + xlabs = 'Session' + + ylims_now = [np.nanmin(ylims), np.nanmax(ylims)] + + + if compare_areas: + p2plot = p_areas_sigval[icre, istage] # stagenow-1 # 4depths + else: + if len(project_codes_all)==1: + p2plot = p_sigval[icre][:, inds_v1] # len(whichStages_pval_allComparisonParis) x 4 # previously: 4 + else: + p2plot = p_sigval[icre] # len(whichStages_pval_allComparisonParis) + + + # add an asterisk if ttest is significant between whichStages_pval (eg ophys 3 and 4) + if compare_areas or (ttest_actShfl_stages == 1 and sum(np.in1d(whichStages, whichStages_pval_allComparisonParis))>=2): # compare ophys stages + + if compare_areas==False: # place it in between the x values for sessions 3 and 4 + cn = 'k' + # compute x to place the asterisk + cwp=-1 + for whichStages_pval in whichStages_pval_allComparisonParis: + xs1 = np.argwhere(whichStages == whichStages_pval[0])[0][0] + xs2 = np.argwhere(whichStages == whichStages_pval[1])[0][0] + x_whichStages_pval = (xnowall[xs1] + xnowall[xs2]) / 2 # x+xgapg/2 + cwp = cwp+1 + + # plot an asterisk if p2plot is significant # print(f'test: {x_whichStages_pval, p2plot*mn_mx[1]-np.diff(mn_mx)*.03}') + ax1.plot(x_whichStages_pval, p2plot[cwp]*mn_mx[1]-np.diff(mn_mx)*.03, '*', color=cn) + + if ~np.isnan(inds_lm[0]): + ax2.plot(x_whichStages_pval, p_sigval[icre, cwp, inds_lm]*mn_mx[1]-np.diff(mn_mx)*.03, 'k*') + if project_codes_all == ['VisualBehaviorMultiscope']: + ax3.plot(x_whichStages_pval, p_sigval_pooled[icre, cwp, :]*mn_mx[1]-np.diff(mn_mx)*.03, 'k*') + + else: + cn = 'r' + xs1 = 0 + xs2 = 1 + x_whichStages_pval = (xnowall[xs1] + xnowall[xs2]) / 2 # x+xgapg/2 + + # plot an asterisk if p2plot is significant + # print(f'test: {x_whichStages_pval, p2plot*mn_mx[1]-np.diff(mn_mx)*.03}') + ax1.plot(x_whichStages_pval, p2plot*mn_mx[1]-np.diff(mn_mx)*.03, '*', color=cn) + + + + iax = 0 # V1, LM + for ax in allaxes: #[ax1,ax2,ax3]: + # ax.hlines(0, x[0], x[-1], linestyle='dashed', color='gray') + if project_codes_all == ['VisualBehaviorMultiscope']: + ax.set_xticks(x) # depth + ax.set_xticklabels(xticklabs, rotation=45) + ax.set_xlim([-1, xnowall[-1][-1]+1]) # x[-1]+xgap+.5 # -.5-xgapg + else: + ax.set_xticks(np.array(xnowall).flatten()) # stages # + ax.set_xticklabels(whichStages, rotation=45) + ax.set_xlim([-1, xnowall[-1][-1]+1]) # x[-1]+xgap+.5 + + ax.tick_params(labelsize=10) + ax.set_xlabel(xlabs, fontsize=12) + + # ax.hlines(0, x[0], x[-1], linestyle='dashed', color='gray') + + # ax.set_ylim(mn_mx) +# print(f'test ylim: {ylims_now}') + ax.set_ylim(ylims_now) + if ax==ax1: + ax.set_ylabel(ylabs, fontsize=12) #, labelpad=35) # , rotation=0 + + if compare_areas: + ax.set_title(f'ophys {stagenow}') + else: + ax.set_title(areasn[iax]) + + iax=iax+1 + + bb = (.97,.8) + if project_codes_all == ['VisualBehaviorMultiscope']: + ax = ax3 + else: + ax = ax1 + if compare_areas==True: + ax = ax1 + + if addleg: + ax.legend(loc='center left', bbox_to_anchor=[bb[0]+xgapg, bb[1]], frameon=True, handlelength=1, fontsize=12, numpoints=1) + +# if len(allaxes)==1: +# ax.set_title(crenow, fontsize=18, y=1.1) +# else: + + if compare_areas==False: + plt.suptitle(crenow, fontsize=18, y=1.1) + + seaborn.despine() + + + + +############################################################################## +####### do anova and tukey hsd for pairwise comparison of depths per area, and per session type +############################################################################## + +def run_anova_tukey(): + + ylims = [] + if project_codes_all == ['VisualBehaviorMultiscope'] and show_depth_stats: + tukey_all = anova_tukey.do_anova_tukey(summary_vars_all, crenow, stagenow, inds_v1, inds_lm, inds_pooled) + a = anova_tukey.add_tukey_lines(tukey_all, 'v1', ax1, colors[stagenow-1], inds_v1, inds_lm, inds_pooled, top, top_sd, xnowall[stcn]) # cols_stages[stcn] + b = anova_tukey.add_tukey_lines(tukey_all, 'lm', ax2, colors[stagenow-1], inds_v1, inds_lm, inds_pooled, top, top_sd, xnowall[stcn]) # cols_stages[stcn] + c = anova_tukey.add_tukey_lines(tukey_all, 'v1-lm', ax3, colors[stagenow-1], inds_v1, inds_lm, inds_pooled, top_pooled, top_sd_pooled, xnowall[stcn]) # cols_stages[stcn] + + ylims.append(a) + ylims.append(b) + ylims.append(c) + + else: + ylims.append(ax1.get_ylim()) + if ~np.isnan(inds_lm[0]): # ~np.isnan(inds_lm).squeeze(): + ylims.append(ax2.get_ylim()) + ylims.append(ax3.get_ylim()) + + return ylims + + + + + +############################################################### +#%% Set stages_alln: all analyzable stages for a given decoding analysis +############################################################### + +if trial_type == 'hits_vs_misses': + stages_alln = [1,3,4,6] +else: + if use_matched_cells == 123: # + print(f"Cells are matched across stages: {summary_vars_all['stage'].unique()}") +# if sum(summary_vars_all['stage']==1)>0: +# print(f'... changing stage 1 to 3, because we care about experience levels, not actual stage numbers!') +# summary_vars_all.loc[summary_vars_all['stage']==1, 'stage']=3 + stages_alln = [3,4,6] + else: + stages_alln = [1,2,3,4,5,6] +stages_alln = np.array(stages_alln) +if svm_blocks==-1 and engagement_pupil_running==0: # because the engagement metric relies on lick measurement, there wont be data for passive sessions + stages_alln = stages_alln[~np.in1d(stages_alln, [2,5])] + + + +############################################################### +#%% Compute p values and ttest stats between actual and shuffled +############################################################### + +p_act_shfl = np.full((len(cres), len(stages_alln), 8), np.nan) +p_act_shfl_pooled = np.full((len(cres), len(stages_alln), 4), np.nan) # pooled areas +icre = -1 + +for crenow in cres: # crenow = cres[0] + icre = icre+1 + istage = -1 + + for which_stage in stages_alln: # which_stage = 1 + istage = istage+1 + + a = summary_vars_all[np.logical_and(summary_vars_all['cre']==crenow , summary_vars_all['stage']==which_stage)] + + if len(project_codes_all)==1: + a_amp = a['resp_amp'].values[0][:,:,1] # actual # 8depths x sessions + b_amp = a['resp_amp'].values[0][:,:,2] # shuffled + else: + a_amp_allpr = [] + b_amp_allpr = [] + for ipc in range(len(project_codes_all)): + apr = np.hstack(a['resp_amp'].values[ipc][:,:,1]) # data from 1 plane, all sessions; then 2nd plane all sessions, etc are vectorized. + bpr = np.hstack(a['resp_amp'].values[ipc][:,:,2]) # data from 1 plane, all sessions; then 2nd plane all sessions, etc are vectorized. + a_amp_allpr.append(apr) # actual # 8depths x sessions + b_amp_allpr.append(bpr) # shuffled + a_amp = np.concatenate((a_amp_allpr))[np.newaxis, :] + b_amp = np.concatenate((b_amp_allpr))[np.newaxis, :] + +# a_amp.shape, b_amp.shape + + + ############## pool areas ############## + if project_codes_all == ['VisualBehaviorMultiscope']: + a_amp_pooled = np.array([a_amp[inds_pooled[idepth]].flatten() for idepth in range(num_depth)]) + b_amp_pooled = np.array([b_amp[inds_pooled[idepth]].flatten() for idepth in range(num_depth)]) + +# print(a_amp_pooled.shape, b_amp_pooled.shape) + + _, p = st.ttest_ind(a_amp, b_amp, nan_policy='omit', axis=1, equal_var=equal_var) + p_act_shfl[icre, istage, :] = p + + # pooled areas + if project_codes_all == ['VisualBehaviorMultiscope']: + _, p = st.ttest_ind(a_amp_pooled, b_amp_pooled, nan_policy='omit', axis=1, equal_var=equal_var) + p_act_shfl_pooled[icre, istage, :] = p + + +p_act_shfl_sigval = p_act_shfl+0 +p_act_shfl_sigval[p_act_shfl <= sigval] = 1 +p_act_shfl_sigval[p_act_shfl > sigval] = np.nan +# print(p_act_shfl_sigval) + +if project_codes_all == ['VisualBehaviorMultiscope']: + p_act_shfl_sigval_pooled = p_act_shfl_pooled+0 + p_act_shfl_sigval_pooled[p_act_shfl_pooled <= sigval] = 1 + p_act_shfl_sigval_pooled[p_act_shfl_pooled > sigval] = np.nan + # print(p_act_shfl_sigval_pooled) + + + +############################################################### +#%% Compute p values and ttest stats between the 2 ophys stages in whichStages (eg between ophys 3 and 4), for each cre line +############################################################### + +if np.isnan(svm_blocks) or svm_blocks==-101: + + p_all_allComparisonParis = [] + p_all_pooled_allComparisonParis = [] + + if sum(np.in1d(whichStages, whichStages_pval_allComparisonParis))>=2: #==2: # not anymore (I extend the code to compute p across any number of stage pairs): only run this section when comparing sessions 3 and 4 + for crenow in cres: # crenow = cres[0] + + p_all = [] + p_all_pooled = [] + + for whichStages_pval in whichStages_pval_allComparisonParis: # whichStages_pval_allComparisonParis = [[3,4], [4,6]] + + # whichStages_pval = whichStages_pval_allComparisonParis[0] + + ############### set a_amp and b_amp vectors to use as input to ttest ############### + + a = summary_vars_all[np.logical_and(summary_vars_all['cre']==crenow , summary_vars_all['stage']==whichStages_pval[0])] + b = summary_vars_all[np.logical_and(summary_vars_all['cre']==crenow , summary_vars_all['stage']==whichStages_pval[1])] + + if len(project_codes_all)==1: + a_amp = a['resp_amp'].values[0][:,:,1] # actual # 8depths x sessions + b_amp = b['resp_amp'].values[0][:,:,1] # shuffled + else: + a_amp_allpr = [] + b_amp_allpr = [] + for ipc in range(len(project_codes_all)): + apr = np.hstack(a['resp_amp'].values[ipc][:,:,1]) # data from 1 plane, all sessions; then 2nd plane all sessions, etc are vectorized. + bpr = np.hstack(b['resp_amp'].values[ipc][:,:,1]) # data from 1 plane, all sessions; then 2nd plane all sessions, etc are vectorized. + a_amp_allpr.append(apr) # actual # 8depths x sessions + b_amp_allpr.append(bpr) # shuffled + a_amp = np.concatenate((a_amp_allpr))[np.newaxis, :] + b_amp = np.concatenate((b_amp_allpr))[np.newaxis, :] + +# a_amp.shape, b_amp.shape + + + ############## pool areas # 4pooled depths x sessions ############## + if project_codes_all == ['VisualBehaviorMultiscope']: + a_amp_pooled = np.array([a_amp[inds_pooled[idepth]].flatten() for idepth in range(num_depth)]) + b_amp_pooled = np.array([b_amp[inds_pooled[idepth]].flatten() for idepth in range(num_depth)]) + + # print(a_amp.shape, b_amp.shape, a_amp_pooled.shape, b_amp_pooled.shape) + + + ############### compute p value ############### + + _, pi = st.ttest_ind(a_amp, b_amp, nan_policy='omit', axis=1, equal_var=equal_var) + + # pooled + if project_codes_all == ['VisualBehaviorMultiscope']: + _, pp = st.ttest_ind(a_amp_pooled, b_amp_pooled, nan_policy='omit', axis=1, equal_var=equal_var) + + + ################### done with a given pair in whichStages_pval_allComparisonParis; keep all values for a given cre line ################## + p_all.append(pi) +# p_all = np.array(p_all) +# if np.ndim(p_all)==1: +# p_all = p_all[:, np.newaxis] + + # pooled + if project_codes_all == ['VisualBehaviorMultiscope']: + p_all_pooled.append(pp) +# p_all_pooled = np.array(p_all_pooled) + + + + ################### done with looping over all values of whichStages_pval_allComparisonParis for a given cre line; keep all values for all cre lines ################## + p_all_allComparisonParis.append(p_all) # P_all size: 2: len(whichStages_pval_allComparisonParis) + p_all_pooled_allComparisonParis.append(p_all_pooled) + + + + ############### done with all cre lines ############### + p_all_allComparisonParis = np.array(p_all_allComparisonParis) # # p_all_allComparisonParis size: 3x2: num_cre x len(whichStages_pval_allComparisonParis) + p_all_pooled_allComparisonParis = np.array(p_all_pooled_allComparisonParis) + + + ############### compute significance ############### + + p_sigval = p_all_allComparisonParis + 0 + p_sigval[p_all_allComparisonParis <= sigval] = 1 + p_sigval[p_all_allComparisonParis > sigval] = np.nan + + # pooled + p_sigval_pooled = p_all_pooled_allComparisonParis + 0 + p_sigval_pooled[p_all_pooled_allComparisonParis <= sigval] = 1 + p_sigval_pooled[p_all_pooled_allComparisonParis > sigval] = np.nan + +# print(p_sigval) +# print(p_sigval_pooled) + + + + + +############################################################### +#%% Compute p values and ttest stats between visual areas: V1 vs. LM +############################################################### + +if project_codes_all == ['VisualBehaviorMultiscope']: + + p_areas = np.full((len(cres), len(stages_alln), 4), np.nan) # num_cres x num_stages x 4depths + icre = -1 + + for crenow in cres: # crenow = cres[0] + icre = icre+1 + istage = -1 + + for which_stage in stages_alln: # which_stage = 1 + istage = istage+1 + + a = summary_vars_all[np.logical_and(summary_vars_all['cre']==crenow , summary_vars_all['stage']==which_stage)] + + if len(project_codes_all)==1: + aa = a['resp_amp'].values[0][:,:,1] # actual # 8depths x sessions + + # v1: + a_amp = aa[inds_v1] # 4depths x sessions + # lm: + b_amp = aa[inds_lm] + + _, p = st.ttest_ind(a_amp, b_amp, nan_policy='omit', axis=1, equal_var=equal_var) # 4 + p_areas[icre, istage, :] = p + + p_areas_sigval = p_areas+0 + p_areas_sigval[p_areas <= sigval] = 1 + p_areas_sigval[p_areas > sigval] = np.nan + # print(p_areas_sigval) + + + + + +############################################################### +#%% Set min and max for each cre line across all ophys stages that will be plotted below +############################################################### + +if np.isnan(svm_blocks) or svm_blocks==-101: + + mn_mx_allcre = np.full((len(cres), 2), np.nan) +# mn_mx_allstage_allcre = np.full((len(cres), len(whichStages), 2), np.nan) + + for crenow in cres: # crenow = cres[0] + + tc = summary_vars_all[summary_vars_all['cre'] == crenow] + icre = np.argwhere(np.in1d(cres, crenow))[0][0] #icre+1 + mn_mx_allstage = [] + + for stagenow in whichStages: # stagenow = whichStages[0] + tc_stage = tc[tc['stage'] == stagenow] + + for ipc in range(len(project_codes_all)): + pa_all = tc_stage['resp_amp'].values[ipc] # 8_planes x sessions x 4_trTsShCh + + # average across sessions + top = np.nanmean(pa_all, axis=1) # 8_planes x 4_trTsShCh + top_sd = np.nanstd(pa_all, axis=1) / np.sqrt(pa_all.shape[1]) + + mn = np.nanmin(top[:,2]-top_sd[:,2]) # shuffled accuracy - sd + mx = np.nanmax(top[:,1]+top_sd[:,1]) # testing accuracy + sd + mn_mx_allstage.append([mn, mx]) + +# mn_mx_allstage_allcre[icre,:] = mn_mx_allstage + mn_mx_allstage = np.array(mn_mx_allstage) + mn_mx = [np.nanmin(mn_mx_allstage), np.nanmax(mn_mx_allstage)] + + mn_mx_allcre[icre,:] = mn_mx + + + +############################################################################################################################## +############################################################################################################################## +############################################################################################################################## +############################################################################################################################## +############################################################################################################################## +############################################################################################################################## +#%% Plot response amplitude (errorbars) comparing ophys STAGES; also do anova/tukey +## make separate figures for V1 and LM +############################################################################################################################## +############################################################################################################################## +############################################################################################################################## +############################################################################################################################## +############################################################################################################################## +############################################################################################################################## + +if project_codes_all == ['VisualBehaviorMultiscope']: + x = np.array([0,1,2,3])*len(whichStages)*1.1 #/1.5 #np.array([0,2,4,6]) # gap between depths +else: + x = np.array([0]) + +cols_stages = plt.rcParams['axes.prop_cycle'].by_key()['color'] + +if len(project_codes_all)==1: + areasn = ['V1', 'LM', 'V1,LM'] +else: + areasn = ['V1,LM', 'V1,LM', 'V1,LM'] # distinct_areas #['VISp'] + + + +if np.isnan(svm_blocks) or svm_blocks==-101: # svm was run on the whole session (no block by block analysis) + + xgapg = .15*len(whichStages)/1.1 # gap between sessions within a depth +# inds_now_all = [inds_v1, inds_lm] + + # icre = -1 + for crenow in cres: # crenow = cres[0] + + tc = summary_vars_all[summary_vars_all['cre'] == crenow] + icre = np.argwhere(np.in1d(cres, crenow))[0][0] #icre+1 + + plt.figure(figsize=(6,2.5)) + gs1 = gridspec.GridSpec(1,3) #, width_ratios=[3, 1]) + gs1.update(bottom=.15, top=0.8, left=0.05, right=0.95, wspace=.55, hspace=.5) + + allaxes = [] + ax1 = plt.subplot(gs1[0]) + allaxes.append(ax1) + if ~np.isnan(inds_lm).squeeze().all(): + ax2 = plt.subplot(gs1[1]) + ax3 = plt.subplot(gs1[2]) + allaxes.append(ax2) + allaxes.append(ax3) + + xgap = 0 + top_allstage = [] + mn_mx_allstage = [] + stcn = -1 + xnowall = [] + + for stagenow in whichStages: # stagenow = whichStages[0] + + stcn = stcn+1 + + xnow, top, top_sd, mn, mx, depth_ave, top_pooled, top_sd_pooled, pa_all = errorbar_respamp() + + top_allstage.append(top) + mn_mx_allstage.append([mn, mx]) + xnowall.append(xnow) + # print(x+xgap) + + ####################################### + ############# plot errorbars ############# + ####################################### + # test + ax1.errorbar(xnow, top[inds_v1, 1], yerr=top_sd[inds_v1, 1], fmt=fmt_now, markersize=5, capsize=0, label=f'{ophys_stage_labels[stagenow-1]}', color=colors[stagenow-1]) #cols_stages[stcn] + if ~np.isnan(inds_lm[0]): + ax2.errorbar(xnow, top[inds_lm, 1], yerr=top_sd[inds_lm, 1], fmt=fmt_now, markersize=5, capsize=0, label=f'{ophys_stage_labels[stagenow-1]}', color=colors[stagenow-1]) + # shuffle + ax1.errorbar(xnow, top[inds_v1, 2], yerr=top_sd[inds_v1, 2], fmt=fmt_now, markersize=3, capsize=0, color='gray') + if ~np.isnan(inds_lm[0]): + ax2.errorbar(xnow, top[inds_lm, 2], yerr=top_sd[inds_lm, 2], fmt=fmt_now, markersize=3, capsize=0, color='gray') + + ##### areas pooled + if project_codes_all == ['VisualBehaviorMultiscope']: + # test + ax3.errorbar(xnow, top_pooled[:, 1], yerr=top_sd_pooled[:, 1], fmt=fmt_now, markersize=5, capsize=0, label=f'{ophys_stage_labels[stagenow-1]}', color=colors[stagenow-1]) #cols_stages[stcn] + # shuffle + ax3.errorbar(xnow, top_pooled[:, 2], yerr=top_sd_pooled[:, 2], fmt=fmt_now, markersize=3, capsize=0, color='gray') + + + + ############################################################################## + ####### do anova and tukey hsd for pairwise comparison of depths per area + ############################################################################## + ylims = run_anova_tukey() # ylims for each cre line (after adding anova lines/stars), for each of the 3 axes (ax1,ax2,ax3) + + + ############################################################################## + ####### compare actual and shuffled for each ophys stage + ############################################################################## + if ttest_actShfl_stages == 0: + ax1.plot(xnow, p_act_shfl_sigval[icre, stagenow-1, inds_v1]*mn_mx_allcre[icre][1]-np.diff(mn_mx_allcre[icre])*.03, color=colors[stagenow-1], marker='*', linestyle='') # cols_stages[stcn] + ax2.plot(xnow, p_act_shfl_sigval[icre, stagenow-1, inds_lm]*mn_mx_allcre[icre][1]-np.diff(mn_mx_allcre[icre])*.03, color=colors[stagenow-1], marker='*', linestyle='') + ax3.plot(xnow, p_act_shfl_sigval_pooled[icre, stagenow-1, :]*mn_mx_allcre[icre][1]-np.diff(mn_mx_allcre[icre])*.03, color=colors[stagenow-1], marker='*', linestyle='') + + + ############################################################################## + ####### take care of plot labels, etc; done with all stages; do this for each cre line + ############################################################################## + add_plot_labs(top_allstage, mn_mx_allstage, ylims, addleg=1) + + + + + #### + if dosavefig: + + snn = [str(sn) for sn in whichStages] + snn = '_'.join(snn) + whatSess = f'_summaryStages_{snn}' + + fgn = '' #f'{whatSess}' + if same_num_neuron_all_planes: + fgn = fgn + '_sameNumNeursAllPlanes' + + if baseline_subtract==1: + bln = f'timewin{time_win}_blSubtracted' + else: + bln = f'timewin{time_win}_blNotSubtracted' + + if svm_blocks==-1: + word = 'engaged_disengaged_blocks_' + elif svm_blocks==-101: + word = 'only_engaged_' + elif ~np.isnan(svm_blocks): + word = 'blocks_' + else: + word = '' + + if use_events: + word = word + 'events' + + if show_depth_stats: + word = word + '_anova' + + + fgn = f'{fgn}_{word}' + if len(project_codes_all)==1: + fgn = f'{fgn}_frames{frames_svm[0]}to{frames_svm[-1]}' + fgn = fgn + '_ClassAccur' +# if project_codes_all == ['VisualBehavior']: +# fgn = f'{fgn}_{project_codes_all[0]}' + + if len(project_codes_all)==1: + pcn = project_codes_all[0] + '_' + else: + pcn = '' + for ipc in range(len(project_codes_all)): + pcn = pcn + project_codes_all[ipc][0] + '_' + pcn = pcn[:-1] + + fgn = f'{fgn}_{pcn}' + + nam = f'{crenow[:3]}{whatSess}_{bln}_aveMice_aveSessPooled{fgn}_{now}' + + fign = os.path.join(dir0, 'svm', dir_now, nam+fmt) + print(fign) + + + plt.savefig(fign, bbox_inches='tight') # , bbox_extra_artists=(lgd,) + + + + +############################################################################################################################## +############################################################################################################################## +############################################################################################################################## +#%% Plot response amplitude (errorbars) comparing visual AREAS per ophys stage; also do anova/tukey +############################################################################################################################## +############################################################################################################################## +############################################################################################################################## + +if project_codes_all == ['VisualBehaviorMultiscope']: + x = np.array([0,1,2,3])*len(whichStages)*1.1 #/1.5 #np.array([0,2,4,6]) # gap between depths +# else: +# x = np.array([0]) + + cols_stages = plt.rcParams['axes.prop_cycle'].by_key()['color'] + + if len(project_codes_all)==1: + areasn = ['V1', 'LM', 'V1,LM'] + else: + areasn = ['V1,LM', 'V1,LM', 'V1,LM'] # distinct_areas #['VISp'] + + areas_col = 'k', 'b' + inds_vl = inds_v1, inds_lm_orig + + if np.isnan(svm_blocks) or svm_blocks==-101: # svm was run on the whole session (no block by block analysis) + + xgapg = .15*len(inds_vl)/1.1 # gap between areas within a depth +# xgapg = .15*len(whichStages)/1.1 # gap between sessions within a depth + # inds_now_all = [inds_v1, inds_lm] + + # icre = -1 + for crenow in cres: # crenow = cres[0] + + plt.figure(figsize=(1,4*len(whichStages))) + gs1 = gridspec.GridSpec(len(whichStages),1) #, width_ratios=[3, 1]) + gs1.update(bottom=.15, top=0.8, left=0.05, right=0.95, wspace=.55, hspace=1) + + tc = summary_vars_all[summary_vars_all['cre'] == crenow] + icre = np.argwhere(np.in1d(cres, crenow))[0][0] #icre+1 + istage = -1 + + for stagenow in whichStages: # stagenow = whichStages[0] + istage = istage+1 + + allaxes = [] + ax1 = plt.subplot(gs1[istage]) + allaxes.append(ax1) +# if ~np.isnan(inds_lm).squeeze().all(): +# ax2 = plt.subplot(gs1[1]) +# ax3 = plt.subplot(gs1[2]) +# allaxes.append(ax2) +# allaxes.append(ax3) + + xgap = 0 + top_allstage = [] + mn_mx_allstage = [] + areai = -1 + xnowall = [] + ylimsall = [] + + # loop through areas + for ia in range(2): + areai = areai+1 + + xnow, top, top_sd, mn, mx, depth_ave, top_pooled, top_sd_pooled, pa_all = errorbar_respamp(compare_areas=True) + top_allstage.append(top) + mn_mx_allstage.append([mn, mx]) + xnowall.append(xnow) + # print(x+xgap) + + ####################################### + ############# plot errorbars ############# + ####################################### + # test + ax1.errorbar(xnow, top[inds_vl[ia], 1], yerr=top_sd[inds_vl[ia], 1], fmt=fmt_now, markersize=5, capsize=0, label=f'{areasn[ia]}', color=areas_col[ia])#colors[stagenow-1])#, linestyle = linestyle_all[0]) #cols_stages[stcn] + # if ~np.isnan(inds_lm[0]): + # ax1.errorbar(xnow, top[inds_vl[ia], 1], yerr=top_sd[inds_lm, 1], fmt=fmt_now, markersize=5, capsize=0, label=f'{ophys_stage_labels[stagenow-1]}', color=areas_col[ia])#, linestyle = linestyle_all[1]) + # shuffle + ax1.errorbar(xnow, top[inds_vl[ia], 2], yerr=top_sd[inds_vl[ia], 2], fmt=fmt_now, markersize=3, capsize=0, color='gray') + # if ~np.isnan(inds_lm[0]): + # ax1.errorbar(xnow, top[inds_lm, 2], yerr=top_sd[inds_lm, 2], fmt=fmt_now, markersize=3, capsize=0, color='gray') + + ##### areas pooled + # if project_codes_all == ['VisualBehaviorMultiscope']: + # # test + # ax3.errorbar(xnow, top_pooled[:, 1], yerr=top_sd_pooled[:, 1], fmt=fmt_now, markersize=5, capsize=0, label=f'{ophys_stage_labels[stagenow-1]}', color=colors[stagenow-1]) #cols_stages[stcn] + # # shuffle + # ax3.errorbar(xnow, top_pooled[:, 2], yerr=top_sd_pooled[:, 2], fmt=fmt_now, markersize=3, capsize=0, color='gray') + + + + ############################################################################## + ####### do anova and tukey hsd for pairwise comparison of depths per area + ############################################################################## + # ylims = run_anova_tukey() + + ylims = ax1.get_ylim() + ylimsall.append(ylims) + + ############################################################################## + ####### compare actual and shuffled for each ophys stage + ############################################################################## + # if ttest_actShfl_stages == 0: + # ax1.plot(xnow, p_act_shfl_sigval[icre, stagenow-1, inds_v1]*mn_mx_allcre[icre][1]-np.diff(mn_mx_allcre[icre])*.03, color=colors[stagenow-1], marker='*', linestyle='') # cols_stages[stcn] + # ax2.plot(xnow, p_act_shfl_sigval[icre, stagenow-1, inds_lm]*mn_mx_allcre[icre][1]-np.diff(mn_mx_allcre[icre])*.03, color=colors[stagenow-1], marker='*', linestyle='') + # ax3.plot(xnow, p_act_shfl_sigval_pooled[icre, stagenow-1, :]*mn_mx_allcre[icre][1]-np.diff(mn_mx_allcre[icre])*.03, color=colors[stagenow-1], marker='*', linestyle='') + + + ############################################################################## + ####### take care of plot labels, etc; done with both areas for each stage + ############################################################################## +# print(f'mn_mx_allstage: {mn_mx_allstage}') +# print(f'ylimsall: {ylimsall}') + ylimsall = np.array(ylimsall) # includes ylims for the two areas + ylims = [np.nanmin(ylimsall.flatten()) , np.nanmax(ylimsall.flatten())] +# ylims = [np.nanmin(mn_mx_allstage), np.nanmax(mn_mx_allstage)] # same as: mn_mx_allstage_allcre[icre, stagenow-1] + +# plt.subplots_adjust(hspace=2) + add_plot_labs(top_allstage, mn_mx_allstage, ylims, addleg=1, compare_areas=True) + + + + + ############ done with all stages, each cre line ############ + plt.suptitle(crenow, fontsize=18, y=.85); + + if dosavefig: + + snn = [str(sn) for sn in whichStages] + snn = '_'.join(snn) + whatSess = f'_summaryAreas_stages{snn}' + + fgn = '' #f'{whatSess}' + if same_num_neuron_all_planes: + fgn = fgn + '_sameNumNeursAllPlanes' + + if baseline_subtract==1: + bln = f'timewin{time_win}_blSubtracted' + else: + bln = f'timewin{time_win}_blNotSubtracted' + + if svm_blocks==-1: + word = 'engaged_disengaged_blocks_' + elif svm_blocks==-101: + word = 'only_engaged_' + elif ~np.isnan(svm_blocks): + word = 'blocks_' + else: + word = '' + + if use_events: + word = word + 'events' + + if show_depth_stats: + word = word + '_anova' + + + fgn = f'{fgn}_{word}' + if len(project_codes_all)==1: + fgn = f'{fgn}_frames{frames_svm[0]}to{frames_svm[-1]}' + fgn = fgn + '_ClassAccur' + # if project_codes_all == ['VisualBehavior']: + # fgn = f'{fgn}_{project_codes_all[0]}' + + if len(project_codes_all)==1: + pcn = project_codes_all[0] + '_' + else: + pcn = '' + for ipc in range(len(project_codes_all)): + pcn = pcn + project_codes_all[ipc][0] + '_' + pcn = pcn[:-1] + + fgn = f'{fgn}_{pcn}' + + nam = f'{crenow[:3]}{whatSess}_{bln}_aveMice_aveSessPooled{fgn}_{now}' + + fign = os.path.join(dir0, 'svm', dir_now, nam+fmt) + print(fign) + + + plt.savefig(fign, bbox_inches='tight') # , bbox_extra_artists=(lgd,) + + + + + + + + + + +#%% ################################################################################################ +#################################################################################################### +#################################################################################################### +######################## Same as above but when svm was run on blocks of trials #################### +#################################################################################################### +#################################################################################################### +#%% ################################################################################################ + +if ~np.isnan(svm_blocks) and svm_blocks!=-101: # svm was run on blocks of trials + + ############################################################################ + #%% Compute ttest stats between blocks or stages (eg ophys 3 and 4), for each cre line + ############################################################################ + + whichStages_all = [[whichStages[i]] for i in range(len(whichStages))] #[[1], [2], [3], [4], [5], [6]] + + for wsn in whichStages_all: #wsn=[1] #[1,2] #[3,4] #[1,3,4,6] # stages to plot on top of each other to compare + + blocks_toplot = [1] # which block to compare between stages in "whichStages" # only care about it if compare_stages_or_blocks = 'stages'; it will reset if compare_stages_or_blocks='blocks' + compare_stages_or_blocks = 'blocks' # 'blocks' # if "stages", we compare class accuracy of block "blocks_toplot" between the stages in "whichStages"; # if "blocks", we compare class accuracy of blocks in "blocks_toplot" for the stage "whichStages"; + + if compare_stages_or_blocks == 'blocks': + blocks_toplot = br # [0,1] + + equal_var = False # needed for ttest # equal_var: If True (default), perform a standard independent 2 sample test that assumes equal population variances [1]. If False, perform Welch’s t-test, which does not assume equal population variance + sigval = .05 # value for ttest significance + + cres = ['Slc17a7', 'Sst', 'Vip'] + + + p_all = [] + p_all_pooled = [] + for crenow in cres: # crenow = cres[0] + + if compare_stages_or_blocks == 'blocks': + stagehere = wsn[0] # compare blocks for this stage + this_cre_stage_block_0 = np.all(np.array([summary_vars_all['cre']==crenow , summary_vars_all['stage']==stagehere , summary_vars_all['block'] == 0]), axis=0) + this_cre_stage_block_1 = np.all(np.array([summary_vars_all['cre']==crenow , summary_vars_all['stage']==stagehere , summary_vars_all['block'] == 1]), axis=0) + + elif compare_stages_or_blocks == 'stages': + blockhere = blocks_toplot[0] # compare stages for this block + this_cre_stage_block_0 = np.all(np.array([summary_vars_all['cre']==crenow , summary_vars_all['stage']==wsn[0] , summary_vars_all['block'] == blockhere]), axis=0) + this_cre_stage_block_1 = np.all(np.array([summary_vars_all['cre']==crenow , summary_vars_all['stage']==wsn[1] , summary_vars_all['block'] == blockhere]), axis=0) + + a = summary_vars_all[this_cre_stage_block_0] + b = summary_vars_all[this_cre_stage_block_1] + + if len(project_codes_all)==1: + a_amp = a['resp_amp'].values[0][:,:,1] # actual # 8depths x sessions + b_amp = b['resp_amp'].values[0][:,:,1] # shuffled + else: + a_amp_allpr = [] + b_amp_allpr = [] + for ipc in range(len(project_codes_all)): + apr = np.hstack(a['resp_amp'].values[ipc][:,:,1]) # data from 1 plane, all sessions; then 2nd plane all sessions, etc are vectorized. + bpr = np.hstack(b['resp_amp'].values[ipc][:,:,1]) # data from 1 plane, all sessions; then 2nd plane all sessions, etc are vectorized. + a_amp_allpr.append(apr) # actual # 8depths x sessions + b_amp_allpr.append(bpr) # shuffled + a_amp = np.concatenate((a_amp_allpr))[np.newaxis, :] + b_amp = np.concatenate((b_amp_allpr))[np.newaxis, :] + +# a_amp.shape, b_amp.shape + + + # pool areas # 4pooled depths x sessions + if project_codes_all == ['VisualBehaviorMultiscope']: + a_amp_pooled = np.array([a_amp[inds_pooled[idepth]].flatten() for idepth in range(num_depth)]) + b_amp_pooled = np.array([b_amp[inds_pooled[idepth]].flatten() for idepth in range(num_depth)]) + +# print(a_amp.shape, b_amp.shape, a_amp_pooled.shape, b_amp_pooled.shape) + + + + _, p = st.ttest_ind(a_amp, b_amp, nan_policy='omit', axis=1, equal_var=equal_var) + p_all.append(p) + + # shuffled + if project_codes_all == ['VisualBehaviorMultiscope']: + _, p = st.ttest_ind(a_amp_pooled, b_amp_pooled, nan_policy='omit', axis=1, equal_var=equal_var) + p_all_pooled.append(p) + + p_all = np.array(p_all) + p_all_pooled = np.array(p_all_pooled) +# p_all.shape + if np.ndim(p_all)==1: + p_all = p_all[:, np.newaxis] + + p_sigval = p_all+0 + p_sigval[p_all <= sigval] = 1 + p_sigval[p_all > sigval] = np.nan + + # pooled + p_sigval_pooled = p_all_pooled+0 + p_sigval_pooled[p_all_pooled <= sigval] = 1 + p_sigval_pooled[p_all_pooled > sigval] = np.nan + +# print(p_sigval) +# print(p_sigval_pooled) + + + + + ############################################################################ + ############################################################################ + ############################################################################ + ############################################################################ + #%% Plot response amplitude (errorbars) comparing ophys stages; also do anova/tukey + ############################################################################ + + xgapg = .15*len(whichStages)/2 + + for crenow in cres: #crenow = cres[0] + + tc = summary_vars_all[summary_vars_all['cre'] == crenow] + icre = np.argwhere(np.in1d(cres, crenow))[0][0] #icre+1 + +# plt.figure(figsize=(4,2.5)) +# gs1 = gridspec.GridSpec(1,2) #, width_ratios=[3, 1]) +# gs1.update(bottom=.15, top=0.8, left=0.05, right=0.95, wspace=.55, hspace=.5) + + plt.figure(figsize=(6,2.5)) + gs1 = gridspec.GridSpec(1,3) #, width_ratios=[3, 1]) + gs1.update(bottom=.15, top=0.8, left=0.05, right=0.95, wspace=.55, hspace=.5) + + allaxes = [] + ax1 = plt.subplot(gs1[0]) + allaxes.append(ax1) + if ~np.isnan(inds_lm).squeeze().all(): + ax2 = plt.subplot(gs1[1]) + ax3 = plt.subplot(gs1[2]) + allaxes.append(ax2) + allaxes.append(ax3) + + + + xgap = 0 + top_allstage = [] + mn_mx_allstage = [] + stcn = -1 + xnowall = [] + + for stagenow in whichStages: # stagenow = whichStages[0] + + stcn = stcn+1 + + for iblock in blocks_toplot: # np.unique(blocks_all): # iblock=0 ; iblock=np.nan + + linestyle_now = linestyle_all[iblock] + cols_area_now = cols_area_all[iblock] +# cols_stages_now = [cols_stages , ['tomato', 'salmon', 'skyblue', 'cyan', 'pink']][iblock] +# cols_stages_now = [['tomato', 'tomato', 'tomato', 'tomato', 'tomato', 'tomato'], np.array(colors)[[0,2,3,5],:]][iblock] # ['tomato', 'salmon', 'skyblue', 'green', 'pink'] + cols_stages_now = [['tomato', 'tomato', 'tomato', 'tomato', 'tomato', 'tomato'], ['black', 'black', 'black', 'black', 'black', 'black']][iblock] + line_styles_now = ['dashed', 'solid'] + + if svm_blocks==-1: + # lab_b = f'e{iblock}' # engagement + if iblock==0: + lab_b = f'disengaged' + elif iblock==1: + lab_b = f'engaged' + else: + lab_b = f'b{iblock}' # block + +# lab = f'ophys{stagenow}, {lab_b}' + lab = f'{lab_b}' + + + xnow, top, top_sd, mn, mx, depth_ave, top_pooled, top_sd_pooled, pa_all = errorbar_respamp() + + top_allstage.append(top) + mn_mx_allstage.append([mn, mx]) + + ####################################### + ############# plot errorbars ############# + ####################################### + + lab='' if stcn!=0 else lab # only add legend for the 1st time point + + if project_codes_all == ['VisualBehaviorMultiscope']: + colnow = colors[stagenow-1] + else: + colnow = cols_stages_now[stcn] + + # test + eb1 = ax1.errorbar(xnow, top[inds_v1, 1], yerr=top_sd[inds_v1, 1], fmt=fmt_now, markersize=5, capsize=0, label=lab, color=colnow, linestyle = line_styles_now[iblock]) #cols_stages[stcn] # colors[stagenow-1] + if iblock==0: + eb1[-1][0].set_linestyle('--') + + if ~np.isnan(inds_lm[0]): + ax2.errorbar(xnow, top[inds_lm, 1], yerr=top_sd[inds_lm, 1], fmt=fmt_now, markersize=5, capsize=0, label=lab, color=colnow, linestyle = line_styles_now[iblock]) + # shuffle + ax1.errorbar(xnow, top[inds_v1, 2], yerr=top_sd[inds_v1, 2], fmt=fmt_now, markersize=3, capsize=0, color='gray') + if ~np.isnan(inds_lm[0]): + ax2.errorbar(xnow, top[inds_lm, 2], yerr=top_sd[inds_lm, 2], fmt=fmt_now, markersize=3, capsize=0, color='gray') + + ##### areas pooled + if project_codes_all == ['VisualBehaviorMultiscope']: + # test + ax3.errorbar(xnow, top_pooled[:, 1], yerr=top_sd_pooled[:, 1], fmt=fmt_now, markersize=5, capsize=0, label=lab, color=colors[stagenow-1], linestyle = line_styles_now[iblock]) #cols_stages[stcn] + # shuffle + ax3.errorbar(xnow, top_pooled[:, 2], yerr=top_sd_pooled[:, 2], fmt=fmt_now, markersize=3, capsize=0, color='gray') + + xnowall.append(xnow) # do it only for 1 block + + + + + ####### done with plotting blocks_toplot + ############################################################################## + ####### do anova and tukey hsd for pairwise comparison of depths per area + ############################################################################## + ylims = run_anova_tukey() + + + ############################################################################## + ####### compare actual and shuffled for each ophys stage + ############################################################################## + if ttest_actShfl_stages == 0: + ax1.plot(xnow, p_act_shfl_sigval[icre, stagenow-1, inds_v1]*mn_mx_allcre[icre][1]-np.diff(mn_mx_allcre[icre])*.03, color=colors[stagenow-1], marker='*', linestyle='') # cols_stages[stcn] + ax2.plot(xnow, p_act_shfl_sigval[icre, stagenow-1, inds_lm]*mn_mx_allcre[icre][1]-np.diff(mn_mx_allcre[icre])*.03, color=colors[stagenow-1], marker='*', linestyle='') + ax3.plot(xnow, p_act_shfl_sigval_pooled[icre, stagenow-1, :]*mn_mx_allcre[icre][1]-np.diff(mn_mx_allcre[icre])*.03, color=colors[stagenow-1], marker='*', linestyle='') + + + + ############################################################################## + ####### take care of some plot labels etc + ############################################################################## + import matplotlib as mpl + mpl.rcParams['legend.handlelength'] = 10 + mpl.rcParams['legend.markerscale'] = 0 + + add_plot_labs(top_allstage, mn_mx_allstage, ylims, addleg=1) + + + + #### + if dosavefig: + + snn = [str(sn) for sn in whichStages] + snn = '_'.join(snn) + whatSess = f'_summaryStages_{snn}' + + fgn = '' #f'{whatSess}' + if same_num_neuron_all_planes: + fgn = fgn + '_sameNumNeursAllPlanes' + + if baseline_subtract==1: + bln = f'timewin{time_win}_blSubtracted' + else: + bln = f'timewin{time_win}_blNotSubtracted' + + if svm_blocks==-1: + word = 'engaged_disengaged_blocks_' + elif svm_blocks==-101: + word = 'only_engaged_' + elif ~np.isnan(svm_blocks): + word = 'blocks_' + else: + word = '' + + if use_events: + word = word + 'events' + + if show_depth_stats: + word = word + '_anova' + + + fgn = f'{fgn}_{word}' + if len(project_codes_all)==1: + fgn = f'{fgn}_frames{frames_svm[0]}to{frames_svm[-1]}' + fgn = fgn + '_ClassAccur' +# if project_codes_all == ['VisualBehavior']: +# fgn = f'{fgn}_{project_codes_all[0]}' + + if len(project_codes_all)==1: + pcn = project_codes_all[0] + '_' + else: + pcn = '' + for ipc in range(len(project_codes_all)): + pcn = pcn + project_codes_all[ipc][0] + '_' + pcn = pcn[:-1] + + fgn = f'{fgn}_{pcn}' + + nam = f'{crenow[:3]}{whatSess}_{bln}_aveMice_aveSessPooled{fgn}_{now}' + + fign = os.path.join(dir0, 'svm', dir_now, nam+fmt) + print(fign) + + + plt.savefig(fign, bbox_inches='tight') # , bbox_extra_artists=(lgd,) + + + diff --git a/visual_behavior/decoding_population/svm_images_plots_compare_traces_experience_levels.py b/visual_behavior/decoding_population/svm_images_plots_compare_traces_experience_levels.py new file mode 100644 index 000000000..97a993981 --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_compare_traces_experience_levels.py @@ -0,0 +1,198 @@ +""" +Gets called in svm_images_plots_setVars.py + +Here, we use svm_df from all projects to plot the decoding traces (timeseries), averaged across project codes, for each experience level + +Vars needed here are set in svm_images_plots_setVars_sumMice3_svmdf.py + +Created on Sat Nov 13 09:26:05 2021 +@author: farzaneh + +""" + +# scientifica +''' +frame_dur +0.032 + +time_trace +array([-0.48 , -0.448, -0.416, -0.384, -0.352, -0.32 , -0.288, -0.256, + -0.224, -0.192, -0.16 , -0.128, -0.096, -0.064, -0.032, 0. , + 0.032, 0.064, 0.096, 0.128, 0.16 , 0.192, 0.224, 0.256, + 0.288, 0.32 , 0.352, 0.384, 0.416, 0.448, 0.48 , 0.512, + 0.544, 0.576, 0.608, 0.64 , 0.672, 0.704]) +''' + +# mesoscope +''' +frame_dur +0.093 + +time_trace +array([-0.465, -0.372, -0.279, -0.186, -0.093, 0. , 0.093, 0.186, + 0.279, 0.372, 0.465, 0.558, 0.651]) +''' + +# svm_df_all.keys() +# svm_df_all['project_code'].unique() + + +######################### + +time_trace_vb = np.array([-0.48 , -0.448, -0.416, -0.384, -0.352, -0.32 , -0.288, -0.256, + -0.224, -0.192, -0.16 , -0.128, -0.096, -0.064, -0.032, 0. , + 0.032, 0.064, 0.096, 0.128, 0.16 , 0.192, 0.224, 0.256, + 0.288, 0.32 , 0.352, 0.384, 0.416, 0.448, 0.48 , 0.512, + 0.544, 0.576, 0.608, 0.64 , 0.672, 0.704]) + +time_trace_ms = np.array([-0.465, -0.372, -0.279, -0.186, -0.093, 0. , 0.093, 0.186, + 0.279, 0.372, 0.465, 0.558, 0.651]) + + +colors = utils.get_experience_level_colors() # will always be in order of Familiar, Novel 1, Novel >1 + +plt.figure(figsize=(16,4)) +icre = 0 +for cren in cres: # cren = cres[0] + icre = icre+1 + plt.subplot(1,3,icre) + iel = -1 + h = [] + for el in exp_level_all: # el = exp_level_all[0] + iel = iel+1 + sdf = svm_df_all[svm_df_all['project_code']=='VisualBehaviorMultiscope'] + sdf = sdf[sdf['cre_allPlanes']==cren] + sdf = sdf[sdf['experience_levels']==el] + traces_ms = np.vstack(sdf['av_test_data_allPlanes'].values) +# print(traces_ms.shape) + + sdf = svm_df_all[svm_df_all['project_code']=='VisualBehavior'] + sdf = sdf[sdf['cre_allPlanes']==cren] + sdf = sdf[sdf['experience_levels']==el] + traces_vb = np.vstack(sdf['av_test_data_allPlanes'].values) +# print(traces_vb.shape) + + sdf = svm_df_all[svm_df_all['project_code']=='VisualBehaviorTask1B'] + sdf = sdf[sdf['cre_allPlanes']==cren] + sdf = sdf[sdf['experience_levels']==el] + traces_1b = np.vstack(sdf['av_test_data_allPlanes'].values) +# print(traces_1b.shape) + + ### for omission decoding, set the frame right before omission to nan; so we dont have to deal with the dip we see there; which you have an explanation for (check OneNote, Research, SVM notes); in brief it is because frame -1 represents one of the classes, so when training SVM on that frame, frame -1 is representing both classes (ie the same data represents both classes!), this causes the classifier to get trained on a certail class for a given observation, but in the testing set see a different class for that same observation, hence the lower than chance performance. + if trial_type=='baseline_vs_nobaseline': + traces_ms[:, np.argwhere(time_trace_ms==0)-1] = np.nan + traces_vb[:, np.argwhere(time_trace_vb==0)-1] = np.nan + traces_1b[:, np.argwhere(time_trace_vb==0)-1] = np.nan + + if trial_type=='baseline_vs_nobaseline' or trial_type=='omissions': + omit_aligned = 1 + else: + omit_aligned = 0 + + ### upsample mesoscope traces to match scientifica data + x = time_trace_vb + xp = time_trace_ms + traces_ms_interp = [] + for i in range(traces_ms.shape[0]): + fp = traces_ms[i] + traces_ms_interp.append(np.interp(x, xp, fp)) + traces_ms_interp = np.array(traces_ms_interp) + print(traces_ms_interp.shape) + + + ############################### plots ############################### + # plot individual project codes +# plt.plot(xp, np.nanmean(traces_ms, axis=0), color='b') +# plt.plot(x, np.nanmean(traces_ms_interp, axis=0), color='r') +# plt.plot(x, np.nanmean(traces_vb, axis=0), color='k') +# plt.plot(x, np.nanmean(traces_1b, axis=0), color='g') + + + # plot the average traces across project codes + m = np.concatenate((traces_ms_interp, traces_vb, traces_1b)) +# print(m.shape) + + av = np.nanmean(m, axis=0) + se = np.nanstd(m, axis=0) / np.sqrt(sum(~np.isnan(m[:,0]))) + + plt.fill_between(x, av-se, av+se, alpha=.3, edgecolor=colors[iel], facecolor=colors[iel]) + hn = plt.plot(x, av, color=colors[iel], label=el) + + h.append(hn) + + + #### done with all exp levels for a given cre line + handles, labels = plt.gca().get_legend_handles_labels(); +# lims = [np.min(np.min(lims_v1lm, axis=1)), np.max(np.max(lims_v1lm, axis=1))] + plot_flashLines_ticks_legend([], handles, flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, time_trace_vb, xmjn=xmjn, bbox_to_anchor=bb, ylab=ylabel, xlab=xlabel, omit_aligned=omit_aligned) + plt.xlim(xlim); + plt.title(cren, fontsize=13, y=1); # np.unique(area) + # mark time_win: the window over which the response quantification (peak or mean) was computed + lims = plt.gca().get_ylim(); + plt.hlines(lims[1], time_win[0], time_win[1], color='gray') + plt.subplots_adjust(wspace=.8) + + +#%% +if dosavefig: + + whatSess = f'_timeCourse_experienceLevels' + + fgn = '' #f'{whatSess}' + if same_num_neuron_all_planes: + fgn = fgn + '_sameNumNeursAllPlanes' + + if svm_blocks==-1: + word = 'engaged_disengaged_blocks_' + elif svm_blocks==-101: + word = 'only_engaged_' + elif ~np.isnan(svm_blocks): + word = 'blocks_' + else: + word = '' + + if use_events: + word = word + 'events' + +# frames_svmn = np.arange(-15,23) + frames_svmf = -np.argwhere(time_trace_vb==0).squeeze() + frames_svml = len(time_trace_vb)-np.argwhere(time_trace_vb==0).squeeze()-1 + + fgn = f'{fgn}_{word}_frames{frames_svmf}to{frames_svml}' + fgn = fgn + '_ClassAccur' + fgn = f'{fgn}_allProjects' + + nam = f'AllCre{whatSess}_aveExpPooled{fgn}_{now}' + fign = os.path.join(dir0, 'svm', dir_now, nam+fmt) + print(fign) + + plt.savefig(fign, bbox_inches='tight') # , bbox_extra_artists=(lgd,) + + + + + + +''' +# build a tidy dataframe + +list_of_cell_dfs = [] +for i in range(traces.shape[0]): # loop over sessions + cell_df = pd.DataFrame({ + 'timestamps': time_trace, + 'decoded_events': traces[i]}) + + # append the dataframe for this cell to the list of cell dataframes + list_of_cell_dfs.append(cell_df) + +# concatenate all dataframes in the list +tidy_df = pd.concat(list_of_cell_dfs) +tidy_df + +tidy_df.shape +np.product(np.shape(traces)) + +neural_data = tidy_df + +''' + diff --git a/visual_behavior/decoding_population/svm_images_plots_corr_beh_strategy.py b/visual_behavior/decoding_population/svm_images_plots_corr_beh_strategy.py new file mode 100644 index 000000000..92cfe1e23 --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_corr_beh_strategy.py @@ -0,0 +1,329 @@ +""" +This script is called in "svm_images_plots_setVars_blocks.py" +correlate classification accuracy with behavioral strategy. + +it will be executed if trial_type =='changes_vs_nochanges' or trial_type =='hits_vs_misses' + +Created on Mon Apr 26 17:48:05 2021 +@author: farzaneh + +""" + +import matplotlib.pyplot as plt + +''' +pool_all_stages = True #True +fit_reg = False # lmplots: add the fitted line to the catter plot or not +superimpose_all_cre = False +plot_testing_shufl = 0 # if 0 correlate testing data with strategy dropout index; if 1, correlated shuffled data with strategy dropout index +''' + +#%% correlate classification accuracy with behavioral strategy + +# loading.get_behavior_model_summary_table() +directory = '/allen/programs/braintv/workgroups/nc-ophys/visual_behavior/behavior_model_output/' +model_table = pd.read_csv(directory+'_summary_table.csv') + +# strategy dropout +model_table_allsess = model_table[model_table['ophys_session_id'].isin(all_sess0['session_id'])] +cn = 'strategy_dropout_index' # 'visual_only_dropout_index' # 'timing_only_dropout_index' # 'strategy_dropout_index' +sdi = model_table_allsess[cn].values +sdi0 = sdi +0 + +if project_codes == ['VisualBehavior']: + print(f'{len(model_table_allsess)} / {len(all_sess0)} sessions of all_sess have behavioral strategy data') +else: + print(f'{len(model_table_allsess)} / {len(all_sess0)/num_planes} sessions of all_sess have behavioral strategy data') + + +# set allsess for sessions in model table, and get some vars out of it +all_sess0_modeltable = all_sess0[all_sess0['session_id'].isin(model_table['ophys_session_id'])] +peak_amp_all = np.vstack(all_sess0_modeltable['peak_amp_trainTestShflChance'].values) # 744 x 4 +bl_all = np.vstack(all_sess0_modeltable['bl_pre0'].values) # 744 x 4 +stages = np.vstack(all_sess0_modeltable['stage'].values).flatten() # 744 + +stages_each = np.reshape(stages, (num_planes, len(model_table_allsess)), order='F') # 8 x 93 +# np.unique(stages_each) # 'OPHYS_1_images_A', 'OPHYS_3_images_A', 'OPHYS_4_images_B', 'OPHYS_6_images_A', 'OPHYS_6_images_B' + +if trial_type =='changes_vs_nochanges': + stagesall = [1,2,3,4,5,6] +elif trial_type =='hits_vs_misses': + stagesall = [1,3,4,6] + + +if pool_all_stages: + stagesall = [0] + +##### loop over each ophys stage +for stage_2_analyze in stagesall: # stage_2_analyze = stagesall[0] + + if stage_2_analyze==0: # pool all stages + stinds = np.full((len(stages)), 6) + else: + stinds = np.array([stages[istage].find(str(stage_2_analyze)) for istage in range(len(stages))]) + stages2an = (stinds != -1) + nsnow = int(sum(stages2an) / num_planes) + + if stage_2_analyze==0: # pool all stages + ophys_title = f'all stages' + print(f'{nsnow} sessions; pooled ophys stages') + else: + ophys_title = f'ophys{stage_2_analyze}' + print(f'{nsnow} sessions are ophys {stage_2_analyze}') + + sessionsNow = np.reshape(stages2an, (num_planes, len(model_table_allsess)), order='F') # 8 x 93 + sessionsNow = sessionsNow[0,:] # get values from only 1 plane + + # get sdi for sessions in the current stage + sdi = sdi0[sessionsNow] + + # testing data class accuracy + peak_amp_test = peak_amp_all[stages2an, 1] + bl_now = bl_all[stages2an, 1] + # compute average of the 8 planes + a = np.reshape(peak_amp_test, (num_planes, nsnow), order='F') # 8 x 93 + b = np.reshape(bl_now, (num_planes, nsnow), order='F') + testing_accur_ave_planes = np.nanmean(a, axis=0) + bl_avp = np.nanmean(b, axis=0) + + if baseline_subtract: # subtract the baseline (CA average during baseline, ie before time 0) from the evoked CA (classification accuracy) + testing_accur_ave_planes = testing_accur_ave_planes - bl_avp + + + + # shuffled data class accuracy + peak_amp_shfl = peak_amp_all[stages2an, 2] + bl_now = bl_all[stages2an, 2] + # compute average of the 8 planes + a = np.reshape(peak_amp_shfl, (num_planes, nsnow), order='F') + b = np.reshape(bl_now, (num_planes, nsnow), order='F') + shfl_accur_ave_planes = np.nanmean(a, axis=0) + bl_avp = np.nanmean(b, axis=0) + + yls = 'Decoder accuracy' + if baseline_subtract: # subtract the baseline (CA average during baseline, ie before time 0) from the evoked CA (classification accuracy) + shfl_accur_ave_planes = shfl_accur_ave_planes - bl_avp + yls = f'{yls} (rel. baseline)' + + + ############################## + # what to plot? + if plot_testing_shufl==0: + topn = testing_accur_ave_planes # testing data class accuracy + fignamets = 'testing_' + elif plot_testing_shufl==1: + topn = shfl_accur_ave_planes + fignamets = 'shfl_' +# topn = testing_accur_ave_planes - shfl_accur_ave_planes # testing-shuffled data class accuracy + + + ############################## + ### get r2 values (corr coeffs) between decoder accuracy and behavioral strategy across all sessions + ### all cre lines + # compute, for each session, corrcoef between strategy dropout index and average testing_class_accuracy across the 8 planes + c, p = ma.corrcoef(ma.masked_invalid(sdi), ma.masked_invalid(topn)) + pallcre = p + + #### cre line for each session + cre_mt = all_sess0_modeltable['cre'].values + cre_mt = np.reshape(cre_mt, (num_planes, len(model_table_allsess)), order='F')[0,:] # len sessions + cre_mt = cre_mt[sessionsNow] + + # cre names + a = np.unique(cre_mt.astype(str)) + cren = a[a!='nan'] + print(cren) + # cren = ['Slc17a7-IRES2-Cre', 'Sst-IRES-Cre', 'Vip-IRES-Cre'] + + #### compute r2 for each cre line separately + c_allcre = [] + for icremt in range(len(cren)): + sdin = sdi[cre_mt == cren[icremt]] + tan = topn[cre_mt == cren[icremt]] + + c, p = ma.corrcoef(ma.masked_invalid(sdin), ma.masked_invalid(tan)) + c_allcre.append(p[0]) + print(cren, c_allcre) + + + ################################# + ############## plots ############ + ################################# + + + ################################# + # lmplot: Plot each cre line in a separate subplot; color code by cre line + + if project_codes == ['VisualBehavior']: + vb_ms = '' + else: + vb_ms = '(average of 8 planes)' + + df = pd.DataFrame([], columns=[f'{yls} {vb_ms}', f'{cn}', 'cre']) + df[f'{yls} {vb_ms}'] = topn #testing_accur_ave_planes + df[f'{cn}'] = sdi + df['cre'] = cre_mt + + g = sns.lmplot(f'{cn}', f'{yls} {vb_ms}', data=df, hue='cre', size=2.5, scatter_kws={"s": 20}, col='cre', fit_reg=fit_reg) + + #### add cc to the titles + # lmplot plots cre lines in the same order as cre_mt; lets get that array of cre lines + cre_mt[[type(cre_mt[i])==float for i in range(len(cre_mt))]] = 'remove' # change nans in cre_mt to 'remove' + a = cre_mt[cre_mt!='remove'] # remove nans from cre_mt + indexes = np.unique(a, return_index=True)[1] + lms = [a[index] for index in sorted(indexes)] + + # now lets match this array with cren; we need it for the plot below + lm_order_in_cren = [np.argwhere(np.in1d(cren, lms[i])).flatten()[0] for i in range(len(lms))] + + + ii = -1 + for icremt in lm_order_in_cren: #[1,0,2]: + ii = ii+1 + g.axes[0][ii].set_title(f'{cren[icremt][:3]}, r2 = {c_allcre[icremt]:.2f}') + plt.suptitle(f'{ophys_title}, r2={pallcre[0]:.2f}', y=1.1); + + + + #### + if dosavefig: + +# snn = [str(sn) for sn in whichStages] +# snn = '_'.join(snn) + + whatSess = ophys_title #f'_summaryStages_{snn}' + + fgn = '' #f'{whatSess}' + if same_num_neuron_all_planes: + fgn = fgn + '_sameNumNeursAllPlanes' + + if svm_blocks==-1: + if iblock==0: + word = 'disengaged_' + elif iblock==1: + word = 'engaged_' + elif svm_blocks==-101: + word = 'only_engaged_' + elif ~np.isnan(svm_blocks): + word = 'blocks_' + else: + word = '' + + if use_events: + word = word + 'events' + + fgn = f'{fgn}_{word}_frames{frames_svm[0]}to{frames_svm[-1]}' + + fgn = fgn + '_ClassAccur' +# if project_codes == ['VisualBehavior']: + fgn = f'{fgn}_{project_codes[0]}' + + nam = f'{whatSess}_{fignamets}beh_strategy_corr_{trial_type}{fgn}_{now}' # {crenow[:3]} + + fign = os.path.join(dir0, 'svm', dir_now, nam+fmt) + print(fign) + + + plt.savefig(fign, bbox_inches='tight') # , bbox_extra_artists=(lgd,) + + + + + + + ################################# + # Plot all cre lines: scatter plot + + if superimpose_all_cre: + # plt.figure(figsize=(3,3)) + # plt.plot(sdi, topn, '.') + g = sns.lmplot(f'{cn}', f'Decoder accuracy {vb_ms}', data=df, hue='cre', size=2.5, scatter_kws={"s": 20}, fit_reg=False) + plt.xlabel(f'{cn}') + plt.ylabel('average decoder accuracy of 8 planes\n rel. baseline') + plt.title(f'{ophys_title}, r2={pallcre[0]:.2f}'); + + + + ################################# + # Plot each cre line in a separate figure + # compute corrcoeff for each cre line +# c_allcre = [] + ''' + plt.figure(figsize=(3,9)) + for icremt in range(len(cren)): + sdin = sdi[cre_mt == cren[icremt]] + tan = topn[cre_mt == cren[icremt]] + +# c, p = ma.corrcoef(ma.masked_invalid(sdin), ma.masked_invalid(tan)) +# c_allcre.append(p[0]) + + plt.subplot(3,1,icremt+1) + plt.plot(sdin, tan, '.') + if icremt==2: + plt.xlabel(f'{cn}') + if icremt==1: + plt.ylabel('Average decoder accuracy of 8 planes\n rel. baseline') + plt.title(f'{ophys_title}, {cren[icremt][:3]}, r2={c_allcre[icremt]:.2f}') + makeNicePlots(plt.gca()) + + plt.subplots_adjust(hspace=0.5) + ''' + + + + ################################# +# NOTE: parts below need work + + ''' + # color code by area + + # repeat strategy index for each plane + a = np.tile(sdi, (num_planes,1)) # 8 x num_sess + sdi_rep = np.reshape(a, (num_planes*a.shape[1]), order='F') +# a.shape + + cre_rep = all_sess0_modeltable['cre'].values + area_rep = all_sess0_modeltable['area'].values +# peak_amp_test.shape + + + ##### plot all cre lines + df = pd.DataFrame([], columns=['Decoder accuracy (each plane)', f'{cn}', 'cre', 'area']) + df['Decoder accuracy (each plane)'] = peak_amp_test + df[f'{cn}'] = sdi_rep + df['cre'] = cre_rep + df['area'] = area_rep + + # all cre lines + dfn = df + # a single cre line +# dfn = df[df['cre']==cren[2]] + sns.lmplot(f'{cn}', 'Decoder accuracy (each plane)', data=dfn, hue='area', fit_reg=False) + + + ##### plot each cre line separately + plt.figure(figsize=(3,6)) + for icremt in range(len(cren)): + sdin = sdi_rep[cre_rep == cren[icremt]] + tan = peak_amp_test[cre_rep == cren[icremt]] + aan = area_rep[cre_rep == cren[icremt]] + + plt.subplot(3,1,icremt+1) + plt.plot(sdin[aan=='VISl'], tan[aan=='VISl'], 'b.', label='VISl') + plt.plot(sdin[aan=='VISp'], tan[aan=='VISp'], 'r.', label='VISp') + if icremt==0: + plt.legend(loc='center left', bbox_to_anchor=(1, .7), frameon=False) + if icremt==2: + plt.xlabel(f'{cn}') + if icremt==1: + plt.ylabel('Decoder accuracy of each plane\n change vs no change') + + plt.subplots_adjust(hspace=0.5) + + + ################################# + # color code by depth + + ''' + + diff --git a/visual_behavior/decoding_population/svm_images_plots_eachMouse.py b/visual_behavior/decoding_population/svm_images_plots_eachMouse.py new file mode 100644 index 000000000..a780e50b2 --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_eachMouse.py @@ -0,0 +1,510 @@ +""" +Vars needed here are set in svm_images_plots_setvars. +This script uses pandas table "svm_this_plane_allsess" to make svm related plots for each mouse. +Figures will be saved in "/home/farzaneh/OneDrive/Analysis/svm_images/" + +# Follow this script by "svm_images_plots_setVars_sumMice.py" to set vars for making average plots across mice (for each cre line). + + +Created on Tue Oct 20 14:20:00 2020 +@author: farzaneh +""" + +import matplotlib.pyplot as plt +import matplotlib.gridspec as gridspec +import matplotlib.ticker as ticker +from matplotlib.ticker import (MultipleLocator, FormatStrFormatter, AutoMinorLocator) +import seaborn + +from general_funs import * + +import warnings +import matplotlib.cbook +warnings.filterwarnings("ignore",category=matplotlib.cbook.mplDeprecation) + + +##################################################################################### +####################################### PLOTS ####################################### +##################################################################################### + +#%% For each plane, and each area, plot session-averaged data. We do this for each mouse + +cols = colorOrder(num_planes) +bb = (.92, .7) # (.9, .7) + +for im in range(len(svm_this_plane_allsess)): # im=0 + + #%% + mouse_id = svm_this_plane_allsess.iloc[im]['mouse_id'] + cre = svm_this_plane_allsess.iloc[im]['cre'] + session_stages = svm_this_plane_allsess.iloc[im]['session_stages'] + + area_this_plane_allsess_allp = svm_this_plane_allsess.iloc[im]['area_this_plane_allsess_allp'] # size: (8 x num_sessions x 1) + depth_this_plane_allsess_allp = svm_this_plane_allsess.iloc[im]['depth_this_plane_allsess_allp'] # size: (8 x num_sessions x 1) + + av_n_neurons_avSess_eachP = svm_this_plane_allsess.iloc[im]['av_n_neurons_avSess_eachP'] # size: (8) + sd_n_neurons_avSess_eachP = svm_this_plane_allsess.iloc[im]['sd_n_neurons_avSess_eachP'] # size: (8) + + av_n_trials_avSess_eachP = svm_this_plane_allsess.iloc[im]['av_n_trials_avSess_eachP'] # size: (8) + sd_n_trials_avSess_eachP = svm_this_plane_allsess.iloc[im]['sd_n_trials_avSess_eachP'] # size: (8) + + av_test_data_avSess_eachP = svm_this_plane_allsess.iloc[im]['av_test_data_avSess_eachP'] # size: (8 x nFrames_upsampled) + sd_test_data_avSess_eachP = svm_this_plane_allsess.iloc[im]['sd_test_data_avSess_eachP'] # size: (8 x nFrames_upsampled) + + av_test_shfl_avSess_eachP = svm_this_plane_allsess.iloc[im]['av_test_shfl_avSess_eachP'] # size: (8 x nFrames_upsampled) + sd_test_shfl_avSess_eachP = svm_this_plane_allsess.iloc[im]['sd_test_shfl_avSess_eachP'] # size: (8 x nFrames_upsampled) + + av_train_data_avSess_eachP = svm_this_plane_allsess.iloc[im]['av_train_data_avSess_eachP'] # size: (8 x nFrames_upsampled) + sd_train_data_avSess_eachP = svm_this_plane_allsess.iloc[im]['sd_train_data_avSess_eachP'] # size: (8 x nFrames_upsampled) + + av_meanX_avSess_eachP = svm_this_plane_allsess.iloc[im]['av_meanX_avSess_eachP'] # size: (8 x nFrames_upsampled) + + + if same_num_neuron_all_planes: + av_n_neurons_svm_trained_avSess_eachP = svm_this_plane_allsess.iloc[im]['av_n_neurons_svm_trained_avSess_eachP'] # size: (8) + sd_n_neurons_svm_trained_avSess_eachP = svm_this_plane_allsess.iloc[im]['sd_n_neurons_svm_trained_avSess_eachP'] # size: (8) + + + n_trial_session = av_n_trials_avSess_eachP[np.isnan(av_n_trials_avSess_eachP)==False][0] + + ##### set session labels (stage names are too long) # session_beg_inds = np.concatenate(([0], np.cumsum(num_trs_each_sess[:-1])+1)) + num_sessions = len(session_stages) + session_labs = [] + for ibeg in range(num_sessions): + a = str(session_stages[ibeg]) + us = np.argwhere([a[ich]=='_' for ich in range(len(a))]).flatten() # index of underscores + en = us[-1].squeeze() + 6 + txt = str(session_stages[ibeg][15:]) # session_stages[ibeg][8:en] + txt = txt[0:min(3, len(txt))] + + sn = a[us[0]+1: us[1]+1] # stage number + txt = sn + txt + session_labs.append(txt) + + + + ################################################################## + ################################################################## + #%% Plot results per plane + ################################################################## + ################################################################## + + #%% + plt.figure(figsize=(8,11)) + # subplots of peak amp (neuron averaged, per trial) and omit-aligned traces + gs1 = gridspec.GridSpec(2,1) #(3, 2)#, width_ratios=[3, 1]) + gs1.update(bottom=.57, top=0.92, left=0.05, right=0.4, hspace=.5) + gs2 = gridspec.GridSpec(1,2) #(3, 2)#, width_ratios=[3, 1]) + gs2.update(bottom=.31, top=0.48, left=0.05, right=0.95, wspace=.8) + gs3 = gridspec.GridSpec(1,2) #(3, 2)#, width_ratios=[3, 1]) + gs3.update(bottom=.05, top=0.22, left=0.05, right=0.95, wspace=.8) + + plt.suptitle('%s, mouse %d, ~%d trials\n%d sessions: %s' %(cre, mouse_id, n_trial_session, len(session_stages), session_labs), fontsize=14) + + #%% Plot SVM classification accuracy (indicates magnitude of population signal for discriminating images at each frame) + # Make 2 subplots, one for each area + + ############################### 1st area ############################### + h1 = [] + for iplane in range(num_depth): + +# plt.subplot(2,1,1) + ax = plt.subplot(gs1[0,0]) + + area = area_this_plane_allsess_allp[iplane] # num_sess + depth = depth_this_plane_allsess_allp[iplane] # num_sess + + if np.isnan(av_n_neurons_avSess_eachP[iplane])==False: # for invalid experiments, this will be nan + if same_num_neuron_all_planes: + lab = '%s, ~%dum, nNeurs ~%d, trained ~%d' %(np.unique(area)[0], np.mean(depth), av_n_neurons_avSess_eachP[iplane], av_n_neurons_svm_trained_avSess_eachP[iplane]) + else: + lab = '%s, ~%dum, nNeurs ~%d' %(np.unique(area)[0], np.mean(depth), av_n_neurons_avSess_eachP[iplane]) + + h1_0 = plt.plot(time_trace, av_test_data_avSess_eachP[iplane], color=cols[iplane], label=(lab), markersize=3.5)[0] + h2 = plt.plot(time_trace, av_test_shfl_avSess_eachP[iplane], color='gray', label='shfl', markersize=3.5)[0] +# plt.plot(time_trace, av_train_data_avSess_eachP[iplane], color=cols[iplane], label=(lab), markersize=3.5)[0] + + # errorbars (standard error across cv samples) + plt.fill_between(time_trace, av_test_data_avSess_eachP[iplane] - sd_test_data_avSess_eachP[iplane], av_test_data_avSess_eachP[iplane] + sd_test_data_avSess_eachP[iplane], alpha=alph, edgecolor=cols[iplane], facecolor=cols[iplane]) + plt.fill_between(time_trace, av_test_shfl_avSess_eachP[iplane] - sd_test_shfl_avSess_eachP[iplane], av_test_shfl_avSess_eachP[iplane] + sd_test_shfl_avSess_eachP[iplane], alpha=alph, edgecolor='y', facecolor='y') + + h1.append(h1_0) + h1.append(h2) + + + lims = np.array([np.nanmin(np.concatenate((av_test_shfl_avSess_eachP - sd_test_shfl_avSess_eachP , av_test_data_avSess_eachP - sd_test_data_avSess_eachP))), \ + np.nanmax(av_test_data_avSess_eachP + sd_test_data_avSess_eachP)]) + lims[0] = lims[0] - np.diff(lims) / 20. + lims[1] = lims[1] + np.diff(lims) / 20. + + H = h1 # set handles for legend + # add to plots flash lines, ticks and legend + plot_flashLines_ticks_legend(lims, H, flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, time_trace, xmjn) +# plt.ylabel('') + + + + ############################### 2nd area ############################### + h1 = [] + for iplane in np.arange(4,num_planes): #num_planes): + +# plt.subplot(2,1,2) + ax = plt.subplot(gs1[1,0]) + + area = area_this_plane_allsess_allp[iplane] # num_sess + depth = depth_this_plane_allsess_allp[iplane] # num_sess + if np.ndim(area)==0: # happens when len(session_stages)==1 + area = [area] + depth = [depth] + + if np.isnan(av_n_neurons_avSess_eachP[iplane])==False: # for invalid experiments, this will be nan + if same_num_neuron_all_planes: + lab = '%s, ~%dum, nNeurs ~%d, trained ~%d' %(np.unique(area)[0], np.mean(depth), av_n_neurons_avSess_eachP[iplane], av_n_neurons_svm_trained_avSess_eachP[iplane]) + else: + lab = '%s, ~%dum, nNeurs ~%d' %(np.unique(area)[0], np.mean(depth), av_n_neurons_avSess_eachP[iplane]) + + h1_0 = plt.plot(time_trace, av_test_data_avSess_eachP[iplane],color=cols[iplane], label=(lab), markersize=3.5)[0] + h2 = plt.plot(time_trace, av_test_shfl_avSess_eachP[iplane], color='gray', label='shfl', markersize=3.5)[0] +# plt.plot(time_trace, av_train_data_avSess_eachP[iplane], color=cols[iplane], label=(lab), markersize=3.5)[0] + + # errorbars (standard error across cv samples) + plt.fill_between(time_trace, av_test_data_avSess_eachP[iplane] - sd_test_data_avSess_eachP[iplane], av_test_data_avSess_eachP[iplane] + sd_test_data_avSess_eachP[iplane], alpha=alph, edgecolor=cols[iplane], facecolor=cols[iplane]) + plt.fill_between(time_trace, av_test_shfl_avSess_eachP[iplane] - sd_test_shfl_avSess_eachP[iplane], av_test_shfl_avSess_eachP[iplane] + sd_test_shfl_avSess_eachP[iplane], alpha=alph, edgecolor='y', facecolor='y') + + h1.append(h1_0) + h1.append(h2) + + H = h1 # set handles for legend + + # add to plots flash lines, ticks and legend + plot_flashLines_ticks_legend(lims, H, flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, time_trace, xmjn) + + + + ################################################################## + ################################################################## + #%% Plot results per area (pooled across sessions and layers for each area) + # Question 1: is there a difference between areas (V1 vs LM) # for each mouse pool across sessions and layers (for each area) + ################################################################## + ################################################################## + + # Get the total number of valid sessions and layers for each area + num_sessions_valid_eachArea = svm_this_plane_allsess.iloc[im]['num_sessions_valid_eachArea'] + num_sessLayers_valid_eachArea = np.sum(num_sessions_valid_eachArea, axis=1) + + # Average across layers and sessions for each area + # test_data + a = svm_this_plane_allsess.iloc[im]['av_test_data_pooled_sesss_planes_eachArea'] # 2 x (4 x num_sessions) x nFrames_upsampled + av_test_data_pooledSessPlanes_eachArea = np.nanmean(a, axis=1) # 2 x nFrames_upsampled + sd_test_data_pooledSessPlanes_eachArea = np.nanstd(a, axis=1) / np.sqrt(num_sessLayers_valid_eachArea)[:,np.newaxis] # 2 x nFrames_upsampled + + # test_shfl + a = svm_this_plane_allsess.iloc[im]['av_test_shfl_pooled_sesss_planes_eachArea'] # 2 x (4 x num_sessions) x nFrames_upsampled + av_test_shfl_pooledSessPlanes_eachArea = np.nanmean(a, axis=1) # 2 x nFrames_upsampled + sd_test_shfl_pooledSessPlanes_eachArea = np.nanstd(a, axis=1) / np.sqrt(num_sessLayers_valid_eachArea)[:,np.newaxis] # 2 x nFrames_upsampled + + + ################## + colsa = ['b', 'k'] # first plot V1 (in black, index 1) then LM (in blue, index 0) + ax = plt.subplot(gs2[0]) +# ax = plt.subplot(gs1[2,0]) + plt.title('Sessions and layers pooled', fontsize=13, y=1) + + h1 = [] + for iarea in [1,0]: # first plot V1 then LM #range(a.shape[0]): + lab = '%s, n=%d' %(distinct_areas[iarea], num_sessLayers_valid_eachArea[iarea]) + h1_0 = plt.plot(time_trace, av_test_data_pooledSessPlanes_eachArea[iarea], color = colsa[iarea], label=(lab), markersize=3.5)[0] + h2 = plt.plot(time_trace, av_test_shfl_pooledSessPlanes_eachArea[iarea], color='gray', label='shfl', markersize=3.5)[0] + + plt.fill_between(time_trace, av_test_data_pooledSessPlanes_eachArea[iarea] - sd_test_data_pooledSessPlanes_eachArea[iarea] , \ + av_test_data_pooledSessPlanes_eachArea[iarea] + sd_test_data_pooledSessPlanes_eachArea[iarea], alpha=alph, edgecolor=colsa[iarea], facecolor=colsa[iarea]) + + h1.append(h1_0) + h1.append(h2) + + # add to plots flash lines, ticks and legend + lims = np.array([np.nanmin(np.concatenate((av_test_data_pooledSessPlanes_eachArea - sd_test_data_pooledSessPlanes_eachArea , \ + av_test_shfl_pooledSessPlanes_eachArea - sd_test_shfl_pooledSessPlanes_eachArea))), \ + np.nanmax(av_test_data_pooledSessPlanes_eachArea + sd_test_data_pooledSessPlanes_eachArea)]) + lims[0] = lims[0] - np.diff(lims) / 20. + lims[1] = lims[1] + np.diff(lims) / 20. + + H = h1 + plot_flashLines_ticks_legend(lims, H, flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, time_trace, xmjn, bbox_to_anchor=bb) +# plt.ylabel('') + + # Sanity check: above plots should be the same as below +# plt.plot(time_trace, np.mean(av_test_data_avSess_eachP[:4], axis=0), color = colsa[0]) +# plt.plot(time_trace, np.mean(av_test_data_avSess_eachP[4:], axis=0), color = colsa[1]) + + + + ################################################################## + ################################################################## + #%% Plot results per depth (pooled across sessions and areas for each depth) + # Question 2: is there a difference between superficial and deep layers # for each mouse pool across sessions and area (for each layer)... also pool 2 superifical (deep) layers into 1 + ################################################################## + ################################################################## + + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['depth'].values # (pooled: num_planes x num_sessions) + depths_allsess = np.reshape(y, (num_planes, num_sessions), order='F') # num_planes x num_sessions + + + # Get the total number of valid sessions and layers for each depth + num_sessAreas_valid_eachDepth = np.sum(num_sessions_valid_eachArea, axis=0) + + # Average across areas and sessions for each depth + # test_data + a = svm_this_plane_allsess.iloc[im]['av_test_data_pooled_sesss_areas_eachDepth'] # 4 x (2 x num_sessions) x nFrames_upsampled + av_test_data_pooledSessAreas_eachDepth = np.nanmean(a, axis=1) # 4 x nFrames_upsampled + sd_test_data_pooledSessAreas_eachDepth = np.nanstd(a, axis=1) / np.sqrt(num_sessAreas_valid_eachDepth)[:,np.newaxis] # 4 x nFrames_upsampled + + # test_shfl + a = svm_this_plane_allsess.iloc[im]['av_test_shfl_pooled_sesss_areas_eachDepth'] # 4 x (2 x num_sessions) x nFrames_upsampled + av_test_shfl_pooledSessAreas_eachDepth = np.nanmean(a, axis=1) # 4 x nFrames_upsampled + sd_test_shfl_pooledSessAreas_eachDepth = np.nanstd(a, axis=1) / np.sqrt(num_sessAreas_valid_eachDepth)[:,np.newaxis] # 4 x nFrames_upsampled + + + ################## + colsd = colorOrder(a.shape[0]) # depth1_area2 + ax = plt.subplot(gs2[1]) +# ax = plt.subplot(gs1[2,1]) + plt.title('Sessions and areas pooled', fontsize=13, y=1) + + h1 = [] + for idepth in range(a.shape[0]): + lab = '%d um, n=%d' %(depths_allsess[idepth,0], num_sessAreas_valid_eachDepth[idepth]) + h1_0 = plt.plot(time_trace, av_test_data_pooledSessAreas_eachDepth[idepth], color = colsd[idepth], label=(lab), markersize=3.5)[0] + h2 = plt.plot(time_trace, av_test_shfl_pooledSessAreas_eachDepth[idepth], color='gray', label='shfl', markersize=3.5)[0] + + plt.fill_between(time_trace, av_test_data_pooledSessAreas_eachDepth[idepth] - sd_test_data_pooledSessAreas_eachDepth[idepth] , \ + av_test_data_pooledSessAreas_eachDepth[idepth] + sd_test_data_pooledSessAreas_eachDepth[idepth], alpha=alph, edgecolor=colsd[idepth], facecolor=colsd[idepth]) + + h1.append(h1_0) + h1.append(h2) + + # add to plots flash lines, ticks and legend + lims = np.array([np.nanmin(np.concatenate((av_test_data_pooledSessAreas_eachDepth - sd_test_data_pooledSessAreas_eachDepth , \ + av_test_shfl_pooledSessAreas_eachDepth - sd_test_shfl_pooledSessAreas_eachDepth))), \ + np.nanmax(av_test_data_pooledSessAreas_eachDepth + sd_test_data_pooledSessAreas_eachDepth)]) + lims[0] = lims[0] - np.diff(lims) / 20. + lims[1] = lims[1] + np.diff(lims) / 20. + + H = h1 + plot_flashLines_ticks_legend(lims, H, flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, time_trace, xmjn, bbox_to_anchor=bb) +# plt.ylabel('') + + # Sanity check: above plots should be the same as below (or close, as the arrays below are first averaged across sessions, then here we averaged across areas ... depending on how many sessions were valid the results may vary with above) +# plt.plot(time_trace, np.mean(av_test_data_avSess_eachP[[0,4]], axis=0), color = colsd[0]) +# plt.plot(time_trace, np.mean(av_test_data_avSess_eachP[[1,5]], axis=0), color = colsd[1]) +# plt.plot(time_trace, np.mean(av_test_data_avSess_eachP[[2,6]], axis=0), color = colsd[2]) +# plt.plot(time_trace, np.mean(av_test_data_avSess_eachP[[3,7]], axis=0), color = colsd[3]) + + + + ################################################################## + ################################################################## + ################################################################## + ################################################################## + ################################################################## + ################################################################## + + #%% meanX (average DF/F across trials (half gray (frame omission-1), half non gray (frames_svm)) for each neuron... + # these values were subtracted from x_svm to z score the matrix before running SVM). + + ################################################################## + ################################################################## + #%% Plot results per area (pooled across sessions and layers for each area) + # Question 1: is there a difference between areas (V1 vs LM) # for each mouse pool across sessions and layers (for each area) + ################################################################## + ################################################################## + + # Get the total number of valid sessions and layers for each area + num_sessions_valid_eachArea = svm_this_plane_allsess.iloc[im]['num_sessions_valid_eachArea'] + num_sessLayers_valid_eachArea = np.sum(num_sessions_valid_eachArea, axis=1) + + # Average across layers and sessions for each area + # meanX + a = svm_this_plane_allsess.iloc[im]['meanX_pooled_sesss_planes_eachArea'] # 2 x (4 x num_sessions) x nFrames_upsampled + av_meanX_pooledSessPlanes_eachArea = np.nanmean(a, axis=1) # 2 x nFrames_upsampled + sd_meanX_pooledSessPlanes_eachArea = np.nanstd(a, axis=1) / np.sqrt(num_sessLayers_valid_eachArea)[:,np.newaxis] # 2 x nFrames_upsampled + + + ################## + colsa = ['b', 'k'] + ax = plt.subplot(gs3[0]) +# ax = plt.subplot(gs1[2,0]) + plt.title('Sessions and layers pooled', fontsize=13, y=1) + + h1 = [] + for iarea in range(a.shape[0]): + lab = '%s, n=%d' %(distinct_areas[iarea], num_sessLayers_valid_eachArea[iarea]) + h1_0 = plt.plot(time_trace, av_meanX_pooledSessPlanes_eachArea[iarea], color = colsa[iarea], label=(lab), markersize=3.5)[0] + + plt.fill_between(time_trace, av_meanX_pooledSessPlanes_eachArea[iarea] - sd_meanX_pooledSessPlanes_eachArea[iarea] , \ + av_meanX_pooledSessPlanes_eachArea[iarea] + sd_meanX_pooledSessPlanes_eachArea[iarea], alpha=alph, edgecolor=colsa[iarea], facecolor=colsa[iarea]) + + h1.append(h1_0) + h1.append(h2) + + # add to plots flash lines, ticks and legend + lims = np.array([np.nanmin(av_meanX_pooledSessPlanes_eachArea - sd_meanX_pooledSessPlanes_eachArea), \ + np.nanmax(av_meanX_pooledSessPlanes_eachArea + sd_meanX_pooledSessPlanes_eachArea)]) + lims[0] = lims[0] - np.diff(lims) / 20. + lims[1] = lims[1] + np.diff(lims) / 20. + + H = h1 + plot_flashLines_ticks_legend(lims, H, flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, time_trace, xmjn, bbox_to_anchor=bb) + plt.ylabel('DF/F'); + + # Sanity check: above plots should be the same as below +# plt.plot(time_trace, np.mean(av_meanX_avSess_eachP[:4], axis=0), color = colsa[0]) +# plt.plot(time_trace, np.mean(av_meanX_avSess_eachP[4:], axis=0), color = colsa[1]) + + + ################################################################## + ################################################################## + #%% Plot results per depth (pooled across sessions and areas for each depth) + # Question 2: is there a difference between superficial and deep layers # for each mouse pool across sessions and area (for each layer)... also pool 2 superifical (deep) layers into 1 + ################################################################## + ################################################################## + + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['depth'].values # (pooled: num_planes x num_sessions) + depths_allsess = np.reshape(y, (num_planes, num_sessions), order='F') # num_planes x num_sessions + + + # Get the total number of valid sessions and layers for each depth + num_sessAreas_valid_eachDepth = np.sum(num_sessions_valid_eachArea, axis=0) + + # Average across areas and sessions for each depth + # test_data + a = svm_this_plane_allsess.iloc[im]['meanX_pooled_sesss_areas_eachDepth'] # 4 x (2 x num_sessions) x nFrames_upsampled + av_meanX_pooledSessAreas_eachDepth = np.nanmean(a, axis=1) # 4 x nFrames_upsampled + sd_meanX_pooledSessAreas_eachDepth = np.nanstd(a, axis=1) / np.sqrt(num_sessAreas_valid_eachDepth)[:,np.newaxis] # 4 x nFrames_upsampled + + + ################## + colsd = colorOrder(a.shape[0]) # depth1_area2 + ax = plt.subplot(gs3[1]) +# ax = plt.subplot(gs1[2,1]) + plt.title('Sessions and areas pooled', fontsize=13, y=1) + + h1 = [] + for idepth in range(a.shape[0]): + lab = '%d um, n=%d' %(depths_allsess[idepth,0], num_sessAreas_valid_eachDepth[idepth]) + h1_0 = plt.plot(time_trace, av_meanX_pooledSessAreas_eachDepth[idepth], color = colsd[idepth], label=(lab), markersize=3.5)[0] + + plt.fill_between(time_trace, av_meanX_pooledSessAreas_eachDepth[idepth] - sd_meanX_pooledSessAreas_eachDepth[idepth] , \ + av_meanX_pooledSessAreas_eachDepth[idepth] + sd_meanX_pooledSessAreas_eachDepth[idepth], alpha=alph, edgecolor=colsd[idepth], facecolor=colsd[idepth]) + + h1.append(h1_0) + h1.append(h2) + + # add to plots flash lines, ticks and legend + lims = np.array([np.nanmin(av_meanX_pooledSessAreas_eachDepth - sd_meanX_pooledSessAreas_eachDepth), \ + np.nanmax(av_meanX_pooledSessAreas_eachDepth + sd_meanX_pooledSessAreas_eachDepth)]) + lims[0] = lims[0] - np.diff(lims) / 20. + lims[1] = lims[1] + np.diff(lims) / 20. + + H = h1 + plot_flashLines_ticks_legend(lims, H, flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, time_trace, xmjn, bbox_to_anchor=bb) + plt.ylabel('DF/F'); + + # Sanity check: above plots should be the same as below (or close, as the arrays below are first averaged across sessions, then here we averaged across areas ... depending on how many sessions were valid the results may vary with above) +# plt.plot(time_trace, np.mean(av_meanX_avSess_eachP[[0,4]], axis=0), color = colsd[0]) +# plt.plot(time_trace, np.mean(av_meanX_avSess_eachP[[1,5]], axis=0), color = colsd[1]) +# plt.plot(time_trace, np.mean(av_meanX_avSess_eachP[[2,6]], axis=0), color = colsd[2]) +# plt.plot(time_trace, np.mean(av_meanX_avSess_eachP[[3,7]], axis=0), color = colsd[3]) + + + + + #%% Save the figure for each mouse + + if dosavefig: + nam = f'{cre[:3]}_mouse{mouse_id}{fgn}_{now}' + fign = os.path.join(dir0, dir_now, nam+fmt) + plt.savefig(fign, bbox_inches='tight') # , bbox_extra_artists=(lgd,) + + + + + + + + +#%% SVM plots + +#'session_id', 'experiment_id', 'mouse_id', 'date', 'cre', 'stage', 'area', 'depth', 'n_trials', 'n_neurons', 'meanX_allFrs', 'stdX_allFrs', +#'av_train_data', 'av_test_data', 'av_test_shfl', 'av_test_chance', 'sd_train_data', 'sd_test_data', 'sd_test_shfl', 'sd_test_chance' + +""" +plt.figure() + +h0 = plt.plot(time_trace, av_train_data,'ko', time_trace, av_train_data,'k-', label='train', markersize=3.5); +h1 = plt.plot(time_trace, av_test_data,'ro', time_trace, av_test_data,'r-', label='test', markersize=3.5); +h2 = plt.plot(time_trace, av_test_shfl,'yo', time_trace, av_test_shfl,'y-', label='shfl', markersize=3.5); +h3 = plt.plot(time_trace, av_test_chance,'bo', time_trace, av_test_chance,'b-', label='chance', markersize=3.5); + +# errorbars (standard error across cv samples) +alph = .3 +plt.fill_between(time_trace, av_train_data - sd_train_data, av_train_data + sd_train_data, alpha=alph, edgecolor='k', facecolor='k') +plt.fill_between(time_trace, av_test_data - sd_test_data, av_test_data + sd_test_data, alpha=alph, edgecolor='r', facecolor='r') +plt.fill_between(time_trace, av_test_shfl - sd_test_shfl, av_test_shfl + sd_test_shfl, alpha=alph, edgecolor='y', facecolor='y') +plt.fill_between(time_trace, av_test_chance - sd_test_chance, av_test_chance + sd_test_chance, alpha=alph, edgecolor='b', facecolor='b') + + +mn = 45; mx = 80 +# mark omission onset +plt.vlines([0], mn, mx, color='k', linestyle='--') +# mark the onset of flashes +plt.vlines(flashes_win_trace_index_unq_time, mn, mx, color='y', linestyle='-.') +# mark the onset of grays +plt.vlines(grays_win_trace_index_unq_time, mn, mx, color='gray', linestyle=':') + + +ax = plt.gca() +xmj = np.arange(0, x[-1], .5) +ax.set_xticks(xmj); # plt.xticks(np.arange(0,x[-1],.25)); #, fontsize=10) +ax.set_xticklabels(xmj, rotation=45) +xmn = np.arange(.25, x[-1], .5) +ax.xaxis.set_minor_locator(ticker.FixedLocator(xmn)) +ax.tick_params(labelsize=10, length=6, width=2, which='major') +ax.tick_params(labelsize=10, length=5, width=1, which='minor') +# plt.xticklabels(np.arange(0,x[-1],.25)) + + +plt.legend(handles=[h0[1],h1[1],h2[1],h3[1]], loc='center left', bbox_to_anchor=(1, .7), frameon=False, handlelength=.5, fontsize=12) +plt.ylabel('% Classification accuracy', fontsize=12) +plt.xlabel('Time after omission (sec)', fontsize=12) + +plt.grid(False) # plt.box(on=None) # plt.axis(True) +seaborn.despine()#left=True, bottom=True, right=False, top=False) + + +## Plot with x axis in frame units +''' +plt.figure() +plt.plot(av_train_data, color='k', label='train') +plt.plot(av_test_data, color='r', label='test') +plt.plot(av_test_shfl, color='y', label='shfl') +plt.plot(av_test_chance, color='b', label='chance') +plt.legend(loc='center left', bbox_to_anchor=(1, .7)) + +mn = 45; mx = 80 +# mark omission onset +plt.vlines([0], mn, mx, color='k', linestyle='--') +# mark the onset of flashes +plt.vlines(flashes_win_trace_index_unq, mn, mx, color='y', linestyle='-.') +# mark the onset of grays +plt.vlines(grays_win_trace_index_unq, mn, mx, color='gray', linestyle=':') + +plt.legend(handles=[h0[1],h1[1],h2[1],h3[1]], loc='center left', bbox_to_anchor=(1, .7), frameon=False, handlelength=.5, fontsize=12) +plt.ylabel('% Classification accuracy', fontsize=12) +plt.xlabel('Frame after omission (sec)', fontsize=12) + +""" + + + + diff --git a/visual_behavior/decoding_population/svm_images_plots_init.py b/visual_behavior/decoding_population/svm_images_plots_init.py new file mode 100644 index 000000000..f9a30fd5b --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_init.py @@ -0,0 +1,517 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +After SVM analysis is already done and the results are already saved (by running the svm_image_main_pbs code), +run this script to create all_sess, a dataframe in which the svm results of all sessions are concatenated. We need this to make plots for the svm (images) analysis. + +This script calls the function: svm_images_plots_main.py + +After this script, run svm_images_plots_setVars.py to make plots. + +Note: run this script for individual project codes to save their all_sess files. + + +Created on Tue Oct 13 20:48:43 2020 +@author: farzaneh +""" + +#%% +import os +import pickle +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import datetime +import sys + +import visual_behavior.data_access.loading as loading +from visual_behavior.data_access import utilities +from svm_images_plots_main import * + +# import warnings +# warnings.simplefilter(action='ignore', category=pd.errors.PerformanceWarning) # ignore some warnings! + + +#%% Get SVM output for each cell type, and each frames_svm. + + +#%% Set vars + +project_codes = ['VisualBehaviorMultiscope'] # ['VisualBehaviorMultiscope'] # ['VisualBehaviorMultiscope', 'VisualBehaviorTask1B', 'VisualBehavior', 'VisualBehaviorMultiscope4areasx2d'] + +to_decode = 'current' #'next' # 'current' (default): decode current image. 'previous': decode previous image. 'next': decode next image. +trial_type = 'baseline_vs_nobaseline' #'changes_vs_nochanges' #'baseline_vs_nobaseline' #'changes' #'omissions' #'hits_vs_misses' # 'omissions', 'images', 'changes' # what trials to use for SVM analysis # the population activity of these trials at time time_win will be used to decode the image identity of flashes that occurred at their time 0 (if to_decode='current') or 750ms before (if to_decode='previous'). # 'baseline_vs_nobaseline' # decode activity at each frame vs. baseline (ie the frame before omission unless use_spont_omitFrMinus1 = 1 (see below)) + +use_events = True #False # whether to run the analysis on detected events (inferred spikes) or dff traces. +svm_blocks = np.nan #-101 #np.nan # -1: divide trials based on engagement #2 # number of trial blocks to divide the session to, and run svm on. # set to np.nan to run svm analysis on the whole session + +use_matched_cells = 0 #123 # 0: analyze all cells of an experiment. 123: analyze cells matched in all experience levels (familiar, novel 1 , novel >1); 12: cells matched in familiar and novel 1. 23: cells matched in novel 1 and novel >1. 13: cells matched in familiar and novel >1 + +# use ['20210722'] for vb-ms, 'current', 'changes', events, svm_blocks=-1, no matched cells +analysis_dates = [''] #['20210722'] #['20210708'] # ['2020507'] #set to [''] if you want to load the latest file. # the date on which the svm files were saved. + + +# set window for quantifying the responses +if use_events: + time_win = [0, .4] +else: + time_win = [0, .55] # 'frames_svm' # set time_win to a string (any string) to use frames_svm as the window of quantification. # time window relative to trial onset to quantify image signal. Over this window class accuracy traces will be averaged. +if trial_type == 'baseline_vs_nobaseline': + time_win = [0, .75] # we use the entire time after omission because the omission responses slowly go up + + +same_num_neuron_all_planes = 0 +saveResults = 1 + +# engagement_pupil_running = 0 # applicable when svm_blocks=-1 # np.nan or 0,1,2 for engagement, pupil, running: which metric to use to define engagement? + + +#%% + +use_spont_omitFrMinus1 = 1 # applicable when trial_type='baseline_vs_nobaseline' # if 0, classify omissions against randomly picked spontanoues frames (the initial gray screen); if 1, classify omissions against the frame right before the omission + +# Note: in the cases below, we are decoding baseline from no-baseline , hits from misses, and changes from no-changes, respectively. +# since we are not decoding images, to_decode really doesnt mean anything (when decoding images, to_decode means current/next/previous image) and we just set it to 'current' so it takes some value. +if trial_type == 'baseline_vs_nobaseline' or trial_type == 'hits_vs_misses' or trial_type == 'changes_vs_nochanges': + to_decode = 'current' + use_balanced_trials = 1 #only effective when num_classes=2 #if 1, use same number of trials for each class; only applicable when we have 2 classes (binary classification). +else: # decoding images + use_balanced_trials = 0 #1 #only effective when num_classes=2 #if 1, use same number of trials for each class; only applicable when we have 2 classes (binary classification). + + + +# Note: trials df has a much longer time_trace (goes up to 4.97) compared to stimulus df (goes up to .71), so frames_svm ends up being 1 element longer for trials df (ie when decoding hits from misses) compared to stimulus df (ie when decoding the images) +if project_codes != ['VisualBehaviorMultiscope']: + frames_svm_all = [np.arange(-15,23)] #[[-3,-2,-1], [0,1,2,3,4,5]] +else: + # NOTE: some mesoscope sessions were recorded at a different frame rate (9hz, frame duration: 0.109ms vs. 10.7hz, frame duration: 0.093ms), as a result their frames_svm are -4 to 6 instad of -5 to 7. + # example mesoscope sessions with this problem: 1050231786 1050597678 1051107431 + frames_svm_all = [np.arange(-5,8)] + +if trial_type=='hits_vs_misses': + frames_svm_all[0] = np.concatenate((frames_svm_all[0], [frames_svm_all[0][-1] + 1])) # frames_svm_all[0][-1] = frames_svm_all[0][-1] + 1 + +frames_svm = frames_svm_all[0] #[-3,-2,-1] # [0,1,2,3,4,5] # which svm files to load (this will be used to set svm file name) # (frames_svm also gets saved in svm_vars if svm could be run successfully on a session) +# print(f'Analyzing: {cre2ana}, {frames_svm}') + +doPlots = 0 +num_planes = 8 + +if project_codes != ['VisualBehaviorMultiscope']: + frame_dur = np.array([.032]) +else: + frame_dur = np.array([.093]) +# trace_time = np.array([-0.46631438, -0.3730515 , -0.27978863, -0.18652575, -0.09326288, 0., 0.09326288, 0.18652575, 0.27978863, 0.3730515 , 0.46631438, 0.55957726, 0.65284013]) +# trace_time = array([-0.48482431, -0.45250269, -0.42018107, -0.38785944, -0.35553782, +# -0.3232162 , -0.29089458, -0.25857296, -0.22625134, -0.19392972, +# -0.1616081 , -0.12928648, -0.09696486, -0.06464324, -0.03232162, +# 0. , 0.03232162, 0.06464324, 0.09696486, 0.12928648, +# 0.1616081 , 0.19392972, 0.22625134, 0.25857296, 0.29089458, +# 0.3232162 , 0.35553782, 0.38785944, 0.42018107, 0.45250269, +# 0.48482431, 0.51714593, 0.54946755, 0.58178917, 0.61411079, +# 0.64643241, 0.67875403, 0.71107565, 0.74339727]) +# samps_bef = 5 #np.argwhere(trace_time==0)[0][0] # +# samps_aft = 8 #len(trace_time)-samps_bef # + + + + +#%% Set the directory + +dir_server_me = '/allen/programs/braintv/workgroups/nc-ophys/Farzaneh' +dir_svm = os.path.join(dir_server_me, 'SVM') + +# a = '_'.join(project_codes) +# b = cre2ana # b = '_'.join([str(session_numbers[i]) for i in range(len(session_numbers))]) +# filen = os.path.join(dir_svm, f'metadata_basic_{a}_{b}') +# print(filen) + +if same_num_neuron_all_planes: + dir_svm = os.path.join(dir_svm, 'same_n_neurons_all_planes') + +if ~np.isnan(svm_blocks): + dir_svm = os.path.join(dir_svm, f'trial_blocks') + + + + +#%% Use March 2021 data release sessions + +#%% Use only those project codes that will be used for the paper +experiments_table = loading.get_platform_paper_experiment_table() +# len(experiments_table) +# experiments_table.keys() +# experiments_table.project_code.unique() + +experiments_table = experiments_table.reset_index('ophys_experiment_id') + +# get those rows of experiments_table that are for a specific project code +metadata_valid = experiments_table[experiments_table['project_code']==project_codes[0]] +metadata_valid = metadata_valid.sort_values('ophys_session_id') + +# Use the new list of sessions that are de-crosstalked and will be released in March 2021 +list_all_sessions_valid = metadata_valid['ophys_session_id'].unique() +# list_all_sessions_valid = sessions_ctDone + +print(f'{len(list_all_sessions_valid)}: Number of de-crosstalked sessions for analysis') + + + + +################################################################################################ +if use_matched_cells!=0: + + #%% get matched cells to redeine list of valid sessions + + #%% New method: match across the following 3 experience levels: last familiar active; Novel 1; second novel active + # from Marina's notebook: visual_behavior_analysis/notebooks/211008_validate_filtering_criteria_and_check_exposure_number.ipynb + + cells_table = loading.get_cell_table() + cells_table.shape + + # limit to cells matched in all 3 experience levels, only considering last Familiar and second Novel active + df = utilities.limit_to_last_familiar_second_novel_active(cells_table) # important that this goes first + df = utilities.limit_to_cell_specimen_ids_matched_in_all_experience_levels(df) + + # Sanity checks: + # count numbers of expts and cells¶ + # there should be the same number of experiments for each experience level, and a similar number of cells + # now the number of cell_specimen_ids AND the number of experiment_ids are the same across all 3 experience levels, because we have limited to only the last Familiar and first Novel active sessions + # this is the most conservative set of experiments and cells - matched cells across experience levels, only considering the most recent Familiar and Novel >1 sessions + +# utilities.count_mice_expts_containers_cells(df) + print(utilities.count_mice_expts_containers_cells(df)['n_cell_specimen_id']) + + ''' + # there are only 3 experience levels per container + df.groupby(['ophys_container_id', 'experience_level']).count().reset_index().groupby(['ophys_container_id']).count().experience_level.unique() + # there should only be 1 experiment per experience level + df.groupby(['ophys_container_id', 'experience_level', 'ophys_experiment_id']).count().reset_index().groupby(['ophys_container_id', 'experience_level']).count().ophys_experiment_id.unique() + ''' + + list_all_sessions_valid_matched = df[df['project_code']==project_codes[0]]['ophys_session_id'].unique() # note that if you get ophys experiments it has to be a multiplication of 3. (not ophys sessions.) + list_all_sessions_valid_matched = np.sort(list_all_sessions_valid_matched) + + + + + + # TEMPORARY SOLUTION: remove this session; + # SOLUTION: switch to sdk branch rc/2.13.2 to fix : dataset.running_speed has issues. + print(len(list_all_sessions_valid_matched)) + list_all_sessions_valid_matched = list_all_sessions_valid_matched[list_all_sessions_valid_matched!=795625712] # it's a novel 1 session, VB project + print(len(list_all_sessions_valid_matched)) + + + + + + b = len(list_all_sessions_valid_matched) / len(list_all_sessions_valid) + print(f'{len(list_all_sessions_valid_matched)}/{len(list_all_sessions_valid)}, {b*100:.0f}% of {project_codes} sessions have matched cells in the 3 experience levels.') + + + ### redefine list all sessions valid if using matched cells + list_all_sessions_valid = list_all_sessions_valid_matched + matched_cells = df + + +print(f'{len(list_all_sessions_valid)}: Number of de-crosstalked sessions for analysis') + +################################################################################################ + + + + +#################################################################################################################### +#### Set metadata_all : includes metadata for all the 8 experiments of a session, even if they are failed. +#################################################################################################################### + +# get the list of all the 8 experiments for each session; we need this to set the depth and area for all experiments, since we need the metadata for all the 8 experiments for our analysis even if we dont analyze some experiments. this is because we want to know which experiment belongs to which plane. we later make plots for each plot individually. +experiments_table = loading.get_filtered_ophys_experiment_table(include_failed_data=True) # , release_data_only=False +experiments_table = experiments_table.reset_index('ophys_experiment_id') +# experiments_table.shape + +metadata_all = experiments_table[experiments_table['ophys_session_id'].isin(list_all_sessions_valid)==True] # metadata_all = experiments_table[np.in1d(experiments_table['ophys_session_id'].values, list_all_sessions_valid)] +metadata_all = metadata_all.sort_values('ophys_session_id') +# metadata_all.shape +# metadata_all.shape[0]/8 + + + +# set the list of experiments for each session in list_all_sessions_valid +if project_codes != ['VisualBehaviorMultiscope']: + list_all_experiments = metadata_all['ophys_experiment_id'].values + +else: + try: + list_all_experiments = np.reshape(metadata_all['ophys_experiment_id'].values, (8, len(list_all_sessions_valid)), order='F').T + + except Exception as E: + print(E) + + list_all_experiments = [] + for sess in list_all_sessions_valid: # sess = list_all_sessions_valid[0] + es = metadata_all[metadata_all['ophys_session_id']==sess]['ophys_experiment_id'].values + list_all_experiments.append(es) + list_all_experiments = np.array(list_all_experiments) + + list_all_experiments.shape + + b = np.array([len(list_all_experiments[i]) for i in range(len(list_all_experiments))]) + no8 = list_all_sessions_valid[b!=8] + if len(no8)>0: + print(f'The following sessions dont have all the 8 experiments, excluding them! {no8}') + list_all_sessions_valid = list_all_sessions_valid[b==8] + list_all_experiments = list_all_experiments[b==8] + + print(list_all_sessions_valid.shape, list_all_experiments.shape) + + list_all_experiments = np.vstack(list_all_experiments) + + list_all_experiments = np.sort(list_all_experiments) # sorts across axis 1, ie experiments within each session (does not change the order of sessions!) + +print(list_all_experiments.shape) + + + + +#%% Set the columns in dataframe all_sess + +cols0 = np.array(['session_id', 'experiment_id', 'mouse_id', 'date', 'cre', 'stage', 'experience_level', 'area', 'depth', 'n_trials', 'n_neurons', 'cell_specimen_id', 'frame_dur', 'meanX_allFrs', 'stdX_allFrs', 'av_train_data', 'av_test_data', 'av_test_shfl', 'av_test_chance', 'sd_train_data', 'sd_test_data', 'sd_test_shfl', 'sd_test_chance', 'peak_amp_trainTestShflChance', 'bl_pre0']) +if same_num_neuron_all_planes: + cols = np.concatenate((cols0, ['population_sizes_to_try'])) +else: + cols = np.concatenate((cols0, ['av_w_data', 'av_b_data'])) + +if svm_blocks==-101: + br = [np.nan] +elif ~np.isnan(svm_blocks): + if svm_blocks==-1: # divide trials into blocks based on the engagement state + svmb = 2 + else: + svmb = svm_blocks + br = range(svmb) +else: + br = [np.nan] +print(br) + + + + +for iblock in br: # iblock=0; iblock=np.nan +# for icre in np.arange(0, len(cre2ana_all)): # icre=0 + + #%% Set vars for the analysis + +# cre2ana = cre2ana_all[icre] +# print(f'\n=============== Setting all_sess for {cre2ana} ===============\n') + + + #%% Load the pickle file that includes the list of sessions and metadata + ''' + pkl = open(filen, 'rb') + # dict_se = pickle.load(pkl) + metadata_basic = pickle.load(pkl) + + list_all_sessions_valid = metadata_basic[metadata_basic['valid']]['session_id'].unique() + print(f'number of {cre2ana} sessions: {list_all_sessions_valid.shape[0]}') + # list_all_sessions_valid = dict_se['list_all_sessions_valid'] + # list_all_experiments_valid = dict_se['list_all_experiments_valid'] + # print(f'number of sessions: {len(list_all_sessions_valid)}') + ''' + + + #%% Set all_sess: includes svm results from all sessions of a given cre line, all concatenated + + all_sess = pd.DataFrame([], columns=cols) + + for isess in np.arange(0, len(list_all_sessions_valid)): # isess=0 # isess=38 + + session_id = int(list_all_sessions_valid[isess]) +# data_list = metadata_basic[metadata_basic['session_id'].values==session_id] + + print('\n\n======================== Analyzing session %d, %d/%d ========================\n' %(session_id, isess, len(list_all_sessions_valid))) + + experiment_ids = list_all_experiments[isess] # we want to have the list of all experiments for each session regardless of whethere they were valid or not... this way we can find the same plane across all sessions. + + # Note: we cant use metadata from allensdk because it doesnt include all experiments of a session, it only includes the valid experiments, so it wont allow us to set the metadata for all experiments. + # session_id = sessions_ctDone[isess] + metadata_now = metadata_valid[metadata_valid['ophys_session_id']==session_id] + + # If using matched cells, reset experiment ids valid: + # Because some planes (experiments) are not passed for last familiar active or second novel active, after matching cells, some planes (experiments) of a mesoscope session become invalid, so we need to reset experiment_ids_valid. + # For VB (or task1B) projects though, if an experiment and its session become invalid at the same time, so no need to reset the valid experiments. + if use_matched_cells!=0: + experiment_ids_valid = matched_cells[matched_cells['ophys_session_id']==session_id]['ophys_experiment_id'].unique() + else: + experiment_ids_valid = metadata_now['ophys_experiment_id'].values # the problem is that this wont give us the list of all experiments for a session ... it only includes the valid experiments. + + experiment_ids_valid = np.sort(experiment_ids_valid) + + if use_matched_cells!=0: + v = metadata_now['ophys_experiment_id'].values + print(f"Before matching cells across experience levels {sum(np.in1d(experiment_ids, v)==False)} experiments were invalid; but now:") + print(f'\n{sum(np.in1d(experiment_ids, experiment_ids_valid)==False)} of the experiments are invalid!\n') + + + #%% Set data_list: metadata for this session including a valid column + + data_list = metadata_all[metadata_all['ophys_session_id']==session_id] + data_list['valid'] = False + data_list.loc[data_list['ophys_experiment_id'].isin(experiment_ids_valid), 'valid'] = True + # sort by area and depth + data_list = data_list.sort_values(by=['targeted_structure', 'imaging_depth']) + + + #%% Run the main function + + this_sess = svm_images_plots_main(session_id, data_list, svm_blocks, iblock, dir_svm, frames_svm, time_win, trial_type, to_decode, same_num_neuron_all_planes, cols, analysis_dates, project_codes, use_spont_omitFrMinus1, use_events, doPlots, use_matched_cells) + + + all_sess = all_sess.append(this_sess) + + + ####################################### + print(f'\n\nFinal: length of all_sess: {len(all_sess)}\n\n') + + # check if there are any nan values in all_sess, so you can investigate why! + if project_codes == ['VisualBehaviorMultiscope']: + + ns = int(len(all_sess)/8) # number of sessioins + d = np.reshape(all_sess['date'].values, (8, ns), order='F') # 8 x 58 + dr = np.reshape(d, (8*ns, 1), order='F').squeeze() # 464 + ei = np.array([isinstance(dr[i], float) for i in range(len(dr))]) # are there any nan (float) dates? # 464 + eir = np.reshape(ei, (8, ns), order='F') # 8 x 58 + n_valid_exp_per_sess = np.sum(eir, axis=0) + alleinv = n_valid_exp_per_sess == 8 # 58 # find sessions with all experiments invalid (sum will be 8, if all the experiment dates were of type float, ie invalid) +# alleinv + aa = alleinv.any() + + ss = np.reshape(all_sess['session_id'].values, (8, ns), order='F')[0,:] # 58 + si = ss[np.array(alleinv)] # these sessions have all experiments as invalid; investigate them! + if aa==True: + print(f'{len(si)} sessions have all experiments as invalid:\n\n{si}! investigate them!') + + else: + l = np.array([len(all_sess['date'].values[i]) for i in range(len(all_sess))]) + aa = (l != 10).any() + + + # if there are nan rows in all_sess, exit the analysis to investigate why those experiments dont exist! + if aa: + sys.exit(f'There are some invalid rows in all_sess! examine those experiments!') + else: + print(f'\nAll rows in all_sess are valid! Save all_sess file!\n') + +# all_sess + + + + + + + ################################################################## + #%% Save all_sess + ################################################################## + + # Set input_vars dataframe so you know what vars were used in your analysis + cols2 = np.array(['frames_svm', 'time_win', 'use_events', 'trial_type', 'to_decode', 'same_num_neuron_all_planes', 'project_codes']) + input_vars = pd.DataFrame([], columns=cols2) + input_vars.at[0, cols2] = frames_svm, time_win, use_events, trial_type, to_decode, same_num_neuron_all_planes, project_codes + +# cols2 = np.array(['iblock', 'frames_svm', 'cre2ana', 'time_win', 'trial_type', 'to_decode', 'same_num_neuron_all_planes', 'project_codes']) +# input_vars = pd.DataFrame([], columns=cols2) +# input_vars.at[0, cols2] = iblock, frames_svm, cre2ana, time_win, trial_type, to_decode, same_num_neuron_all_planes, project_codes + + + # Set the name of the h5 file for saving all_sess + e = 'events_' if use_events else '' + if trial_type=='changes_vs_nochanges': # change, then no-change will be concatenated + svmn = f'{e}svm_decode_changes_from_nochanges' + elif trial_type=='hits_vs_misses': + svmn = f'{e}svm_decode_hits_from_misses' + elif trial_type == 'baseline_vs_nobaseline': + svmn = f'{e}svm_decode_baseline_from_nobaseline' #f'{e}svm_gray_omit' #svm_decode_baseline_from_nobaseline + if use_spont_omitFrMinus1==0: + svmn = svmn + '_spontFrs' + else: + svmn = f'{e}svm_decode_{to_decode}_image_from_{trial_type}' # 'svm_gray_omit' + + + if use_matched_cells==123: + svmn = svmn + '_matched_cells_FN1N2' #Familiar, N1, N+1 + elif use_matched_cells==12: + svmn = svmn + '_matched_cells_FN1' + elif use_matched_cells==23: + svmn = svmn + '_matched_cells_N1Nn' + elif use_matched_cells==13: + svmn = svmn + '_matched_cells_FNn' + + + if svm_blocks==-101: # run svm analysis only on engaged trials; redifine df_data only including the engaged rows + svmn = f'{svmn}_only_engaged' + + if use_balanced_trials: + svmn = f'{svmn}_equalTrs' + + print(svmn) + + + now = (datetime.datetime.now()).strftime("%Y%m%d_%H%M%S") + + if same_num_neuron_all_planes: + name = 'all_sess_%s_sameNumNeuronsAllPlanes' %(svmn) + else: + name = 'all_sess_%s' %(svmn) + + b = '_'.join(project_codes) + a = f'frames{frames_svm[0]}to{frames_svm[-1]}' +# a = f'{cre2ana}_frames{frames_svm[0]}to{frames_svm[-1]}' # b = '_'.join([str(session_numbers[i]) for i in range(len(session_numbers))]) + + if ~np.isnan(svm_blocks) and svm_blocks!=-101: + if svm_blocks==-1: # divide trials into blocks based on the engagement state + word = 'engaged' + else: + word = 'block' + + a = f'{a}_{word}{iblock}' + + name = f'{name}_{a}_{b}_{now}' + print(name) + + + if saveResults: + print('\n\nSaving all_sess.h5 file') + allSessName = os.path.join(dir_svm, name + '.h5') # os.path.join(d, svmn+os.path.basename(pnevFileName)) + print(allSessName) + + # save to a h5 file + all_sess.to_hdf(allSessName, key='all_sess', mode='w') + + # save input_vars to the h5 file + input_vars.to_hdf(allSessName, key='input_vars', mode='a') + + + + + +#%% rename svm files to add frames_svm to the file name +''' +name = '(.*)_%s_2020.' %(svmn) +svmName ,_ = all_sess_set_h5_fileName(name, dir_svm, all_files=1) + +for i in range(len(svmName)): + + oldname = svmName[i] + b = os.path.basename(oldname) + ind = b.find('_2020') + newname = os.path.join(dir_svm, f'{b[:ind]}_frames0to5{b[ind:]}') + print(newname) + print(oldname) + + os.rename(oldname, newname) +''' + + + + diff --git a/visual_behavior/decoding_population/svm_images_plots_main.py b/visual_behavior/decoding_population/svm_images_plots_main.py new file mode 100644 index 000000000..7eebc0b8b --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_main.py @@ -0,0 +1,630 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +This function is called in svm_images_plots_init. + +It loads the svm file that was saved for each experiment, and returns a pandas dataframe (this_sess), which includes a number of columns, including average and st error of class accuracies across CV samples; also quantification of the image signal. +svm_init combines this_sess for all sessions into a single pandas table (all_sess), and saves it at /allen/programs/braintv/workgroups/nc-ophys/Farzaneh/SVM/same_num_neurons_all_planes/all_sess_svm_images* + +Follow this function by svm_images_plots_setVars.py to make plots. + +Created on Tue Oct 13 20:53:49 2019 +@author: farzaneh +""" + +import os +import pickle +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + +from general_funs import * + +np.warnings.filterwarnings('ignore', category=np.VisibleDeprecationWarning) + + +def svm_images_plots_main(session_id, data_list, svm_blocks, iblock, dir_svm, frames_svm, time_win, trial_type, to_decode, same_num_neuron_all_planes, cols, analysis_dates, project_codes, use_spont_omitFrMinus1, use_events=False, doPlots=0, use_matched_cells=0): + + bl_percentile = 10 #20 # for peak measurements, we subtract pre-omit baseline from the peak. bl_percentile determines what pre-omit values will be used. + + num_classes = 8 # decoding 8 images + num_planes = 8 + + e = 'events_' if use_events else '' + + if trial_type=='changes_vs_nochanges': # change, then no-change will be concatenated + svmn = f'{e}svm_decode_changes_from_nochanges' + elif trial_type=='hits_vs_misses': + svmn = f'{e}svm_decode_hits_from_misses' + elif trial_type == 'baseline_vs_nobaseline': + svmn = f'{e}svm_decode_baseline_from_nobaseline' #f'{e}svm_gray_omit' #svm_decode_baseline_from_nobaseline + if use_spont_omitFrMinus1==0: + svmn = svmn + '_spontFrs' + else: + svmn = f'{e}svm_decode_{to_decode}_image_from_{trial_type}' # 'svm_gray_omit' + + if use_matched_cells==123: + svmn = svmn + '_matched_cells_FN1N2' #Familiar, N1, N+1 + elif use_matched_cells==12: + svmn = svmn + '_matched_cells_FN1' + elif use_matched_cells==23: + svmn = svmn + '_matched_cells_N1Nn' + elif use_matched_cells==13: + svmn = svmn + '_matched_cells_FNn' + + if svm_blocks==-101: # run svm analysis only on engaged trials; redifine df_data only including the engaged rows + svmn = f'{svmn}_only_engaged' + + print(svmn) + + + exp_ids = data_list['ophys_experiment_id'].values +# frame_dur = np.array([0.093]) # sec (~10.7 Hz; each pair of planes that are recorded simultaneously have time resolution frame_dur) + + frames_svm = np.array(frames_svm) + numFrames = len(frames_svm) + + + #%% Loop through the 8 planes of each session + + this_sess = pd.DataFrame([], columns = cols) + + for index, lims_id in enumerate(exp_ids): + + ''' + for il in [5]: #range(num_planes): + index = il + lims_id = exp_ids[il] + ''' + ''' + ll = list(enumerate(exp_ids)); + l = ll[0]; # first plane + index = l[0]; # plane index + lims_id = l[1] # experiment id + ''' + + print('\n------------- Analyzing experiment %s, plane %d/%d -------------\n' %(lims_id, index, num_planes)) + + area = data_list.iloc[index]['targeted_structure'] + depth = int(data_list.iloc[index]['imaging_depth']) + valid = data_list.iloc[index]['valid'] + + this_sess.at[index, ['session_id', 'experiment_id', 'area', 'depth']] = session_id, lims_id, area, depth + + + if valid==False: + print('Skipping invalid experiment %d' %int(lims_id)) +# this_sess.at[index, :] = np.nan # check this works. +# sys.exit() + set_to_nan = 1 # set svm vars to nan + + else: + + #%% Set the h5 filename containing SVM vars + # mouse, session, experiment: m, s, e + if analysis_dates[0] == '': + nown = '.' + else: + nown = f'{analysis_dates[0]}_.' + +# if same_num_neuron_all_planes: +# nown = 'sameNumNeuronsAllPlanes_' + nown +# name = f'(.*)_s-{session_id}_e-{lims_id}_{svmn}_frames{frames_svm[0]}to{frames_svm[-1]}_{nown}' + + ending = '' + if same_num_neuron_all_planes: + ending = 'sameNumNeuronsAllPlanes_' + + if ~np.isnan(iblock): # svm ran on the trial blocks + if svm_blocks==-1: # divide trials into blocks based on the engagement state + word = 'engaged' + else: + word = 'block' + ending = f'{ending}{word}{iblock}_' + + + ############## + #### NOTE #### + ############## + # commenting below so we don't specify frames_svm because some mesoscope sessions were recorded at a different frame rate (9hz, frame duration: 0.109ms vs. 10.7hz, frame duration: 0.093ms), as a result their frames_svm are -4 to 6 instad of -5 to 7. +# name = f'(.*)_s-{session_id}_e-{lims_id}_{svmn}_frames{frames_svm[0]}to{frames_svm[-1]}_{ending}' + name = f'(.*)_s-{session_id}_e-{lims_id}_{svmn}_frames(.*)_{ending}' + + name = f'{name}{project_codes[0]}_' + name = f'{name}{nown}' + + + svmName ,_ = all_sess_set_h5_fileName(name, dir_svm, all_files=0) + + + if len(svmName)==0: + print(name) + print('\nSVM h5 file does not exist! uncanny! (most likely due to either too few neurons or absence of omissions!)') + set_to_nan = 1 + else: + set_to_nan = 0 + + + ######################################################################################################## + ######################################################################################################## + ######################################################################################################## + ######################################################################################################## + + if set_to_nan==0: + + #%% Load svm dataframe and set SVM vars + + svm_vars = pd.read_hdf(svmName, key='svm_vars') + + ''' + 'session_id', 'experiment_id', 'mouse_id', 'date', 'cre', 'stage', + 'area', 'depth', 'n_trials', 'n_neurons', 'thAct', 'numSamples', + 'softNorm', 'regType', 'cvect', 'meanX_allFrs', 'stdX_allFrs', + 'cbest_allFrs', 'w_data_allFrs', 'b_data_allFrs', + 'perClassErrorTrain_data_allFrs', 'perClassErrorTest_data_allFrs', + 'perClassErrorTest_shfl_allFrs', 'perClassErrorTest_chance_allFrs', + 'testTrInds_allSamps_allFrs', 'Ytest_allSamps_allFrs', + 'Ytest_hat_allSampsFrs_allFrs' + ''' + + cre = svm_vars.iloc[0]['cre'] + date = svm_vars.iloc[0]['date'] + mouse = svm_vars.iloc[0]['mouse_id'] + stage = svm_vars.iloc[0]['stage'] + + try: + experience_level = svm_vars.iloc[0]['experience_level'] + except Exception as e: +# print(e) + # get experience level from experiments table + import visual_behavior.data_access.loading as loading + experiments_table = loading.get_filtered_ophys_experiment_table(release_data_only=True) + experiments_table = experiments_table.reset_index('ophys_experiment_id') + + experience_level = experiments_table[experiments_table['ophys_experiment_id']==lims_id].iloc[0]['experience_level'] + + this_sess.at[index, ['mouse_id', 'date', 'cre', 'stage', 'experience_level']] = mouse, date, cre, stage, experience_level + + + n_trials = svm_vars.iloc[0]['n_trials'] + n_neurons = svm_vars.iloc[0]['n_neurons'] + print(f'{n_trials} trials; {n_neurons} neurons') + + try: + cell_specimen_id = svm_vars.iloc[0]['cell_specimen_id'] + except Exception as e: # cell_specimen_id was added to svm code on 04/23/2021; all svm files saved before that wont have this column. + print(e) + cell_specimen_id = [] + + if np.in1d(svm_vars.keys(), 'frame_dur').any(): # svm code was run without setting frame_dur at first. + frame_dur = svm_vars.iloc[0]['frame_dur'] + print(f'Frame duration {frame_dur} ms') + frame_dur = np.round(frame_dur, 3) +# if np.logical_or(frame_dur < .089, frame_dur > .1): +# sys.exit(f'\n\nFrame duration is unexpected!! {frame_dur}ms\n\n') + else: # for mesoscope data + frame_dur = np.array([0.093]) # sec # mesoscope time resolution (4 depth, 2 areas) (~10.7 Hz; each pair of planes that are recorded simultaneously have time resolution frame_dur) + + + + meanX_allFrs = svm_vars.iloc[0]['meanX_allFrs'] # nFrames x nNeurons + stdX_allFrs = svm_vars.iloc[0]['stdX_allFrs'] + + cbest_allFrs = svm_vars.iloc[0]['cbest_allFrs'] # nFrames + numSamples = svm_vars.iloc[0]['numSamples'] # 50 + # if same_num_neuron_all_planes, each element of the arrays below is for a population of a given size (population_sizes_to_try) + # and perClassErrorTrain_data_allFrs[0] has size has size: # numShufflesN x nSamples x nCval + perClassErrorTrain_data_allFrs = svm_vars.iloc[0]['perClassErrorTrain_data_allFrs'] # 50 x 30 (numSamps x nFrames) + perClassErrorTest_data_allFrs = svm_vars.iloc[0]['perClassErrorTest_data_allFrs'] + perClassErrorTest_shfl_allFrs = svm_vars.iloc[0]['perClassErrorTest_shfl_allFrs'] + perClassErrorTest_chance_allFrs = svm_vars.iloc[0]['perClassErrorTest_chance_allFrs'] + + w_data_allFrs = svm_vars.iloc[0]['w_data_allFrs'] # numSamps x nNeurons x nFrames, if n_classes=2; # samps x classes x neurons x nFrames, if n_classes>2 + b_data_allFrs = svm_vars.iloc[0]['b_data_allFrs'] # numSamps x nFrames, if n_classes=2; # samps x classes x nFrames, if n_classes>2 + + frames_svm = svm_vars.iloc[0]['frames_svm'] +# numFrames = len(frames_svm) + + # plt.plot(cbest_allFrs) + # plt.plot(sorted(cbest_allFrs)[:-2]) + + + num_classes = svm_vars.iloc[0]['num_classes'] + + ''' + Ytest_allSamps_allFrs = svm_vars.iloc[0]['Ytest_allSamps_allFrs'] # numSamples x len_test x nFrames + Ytest_hat_allSampsFrs_allFrs = svm_vars.iloc[0]['Ytest_hat_allSampsFrs_allFrs'] # numSamples x len_test x nFrames + testTrInds_allSamps_allFrs = svm_vars.iloc[0]['testTrInds_allSamps_allFrs'] # numSamples x len_test x nFrames + + image_labels = svm_vars.iloc[0]['image_labels'] # number of trials (training and testing) # this is Y_svm; the trial labels that were used for decoding. + image_indices = svm_vars.iloc[0]['image_indices'] # number of trials (training and testing) # image identities of the current flash + image_indices_previous_flash = svm_vars.iloc[0]['image_indices_previous_flash'] # number of trials (training and testing) # image identities of the previous flash + image_indices_next_flash = svm_vars.iloc[0]['image_indices_next_flash'] # number of trials (training and testing) # image identities of the next flash + + unique_image_labels = np.unique(image_labels) + + # all possible previous-current image labels + all_labs = np.arange(1,10) # unique_image_labels+1 # 1 to 9; including also 9 in case omissions are also among image labels. + firstSecondAll = np.array([a*10+b for a in all_labs for b in all_labs]) # length: 81 + + + ##################### for image changes, where we need to compute classification accuracy for each transition + for si in range(numSamples): # si=0 + for fi in range(numFrames): # fi=0 + + #### set the image label for test trials; also for the following flashes on image-aligned traces that were used as testing data: current flash, previous flash, next flash; (note: one of these 3 types of flashes was used as Y_svm for testing data) + Ytest_allSamps_allFrs[si,:,fi].astype(int) # image_labels[testTrInds_allSamps_allFrs[si,:,fi].astype(int)] # these 2 are equal # note, it could be the image label of the previous, or current, or next flash according to to_decode + image_indices[testTrInds_allSamps_allFrs[si,:,fi].astype(int)] + image_indices_previous_flash[testTrInds_allSamps_allFrs[si,:,fi].astype(int)] + image_indices_next_flash[testTrInds_allSamps_allFrs[si,:,fi].astype(int)] + + # also set the predicted image label + Ytest_hat_allSampsFrs_allFrs[si,:,fi].astype(int) + + + + first = image_indices_previous_flash[testTrInds_allSamps_allFrs[si,:,fi].astype(int)] # image index of the previous flash + second = image_indices[testTrInds_allSamps_allFrs[si,:,fi].astype(int)] # image index of the current flash + + # create a double digit number to indicate the previous-current flash image labels. + firstSecond = np.array([(1+first[i])*10 + (1+second[i]) for i in range(len(first))]) #len_test # adding 1 to each index; so image index 0 is now 1, and the image labels range from 1 to 8 (instead of 0 to 7) + + + # how many data points exist for each possible previous-current image label + num_datapoint_each_flashpair = np.sum([firstSecond==firstSecondAll[i] for i in range(len(firstSecondAll))], axis=1) # length: 81 + + + + # now for each value of firstSecondAll, compute classification accuracy + for li in range(len(firstSecondAll)): # image label of previous-current flashes + if num_datapoint_each_flashpair[li]>0: + +# Continue HERE: think about what you want; and continue here. (you want the confusion matrix; ie for each transition, you want to get the actual and the predicted labels, to compute the accuracy) + + + + ############ for omissions: where the pre and post images are the same; so we can only compute 8 classification accuracies. + + class_accur_each_class = np.full((numSamples, numFrames, num_classes), np.nan) + len_test_each_class = np.full((numSamples, numFrames, num_classes), np.nan) + for si in range(numSamples): # si=0 + for fi in range(numFrames): # fi=0 + a = Ytest_allSamps_allFrs[si,:,fi] # actual test trial labels of sample 10 and frame 0 + p = Ytest_hat_allSampsFrs_allFrs[si,:,fi] # predicted test trial labels of sample 10 and frame 0 +# d.append(np.mean(a==p)*100 - (100-perClassErrorTest_data_allFrs[si,fi])) # sanity check; should be 0. + +# for iclass in range(num_classes): # iclass=0 # 9 classes in case omissions were also classified + for iclass in range(unique_image_labels): + inds = (a==iclass) + acc = np.mean(a[inds]==p[inds]) + l = sum(inds) + class_accur_each_class[si,fi,iclass] = acc + len_test_each_class[si,fi,iclass] = l + + np.shape(len_test_each_class), np.shape(class_accur_each_class) # 50*13*8 + + # average across samples + a = np.nanmean(class_accur_each_class, axis=0) # 13*8 + b = np.mean(len_test_each_class, axis=0) + + plt.plot(a); + plt.plot(b); + +# move the above averaging to the section below; also keep sd across samps + ''' + + + ######################################################################################################## + ######################################################################################################## + #%% Average and st error of class accuracies across cross-validation samples + ######################################################################################################## + ######################################################################################################## + + if same_num_neuron_all_planes: # size perClassErrorTrain_data_allFrs: num_all_pop_sizes x numShufflesN x nSamples x nFrames + + population_sizes_to_try = svm_vars.iloc[0]['population_sizes_to_try'] + numShufflesN = np.shape(perClassErrorTrain_data_allFrs[0])[0] +# numShufflesN = svm_vars.iloc[0]['numShufflesN'] + av_train_data_all = np.full((len(population_sizes_to_try), numShufflesN, numFrames), np.nan) + sd_train_data_all = np.full((len(population_sizes_to_try), numShufflesN, numFrames), np.nan) + av_test_data_all = np.full((len(population_sizes_to_try), numShufflesN, numFrames), np.nan) + sd_test_data_all = np.full((len(population_sizes_to_try), numShufflesN, numFrames), np.nan) + av_test_shfl_all = np.full((len(population_sizes_to_try), numShufflesN, numFrames), np.nan) + sd_test_shfl_all = np.full((len(population_sizes_to_try), numShufflesN, numFrames), np.nan) + av_test_chance_all = np.full((len(population_sizes_to_try), numShufflesN, numFrames), np.nan) + sd_test_chance_all = np.full((len(population_sizes_to_try), numShufflesN, numFrames), np.nan) + + for i_pop_size in range(len(population_sizes_to_try)): + for inN in range(numShufflesN): + # For each neuron subsample, compute average and st error of class accuracies across CV samples + av_train_data_all[i_pop_size][inN] = 100-np.nanmean(perClassErrorTrain_data_allFrs[i_pop_size][inN], axis=0) # numFrames + sd_train_data_all[i_pop_size][inN] = np.nanstd(perClassErrorTrain_data_allFrs[i_pop_size][inN], axis=0) / np.sqrt(numSamples) + + av_test_data_all[i_pop_size][inN] = 100-np.nanmean(perClassErrorTest_data_allFrs[i_pop_size][inN], axis=0) # numFrames + sd_test_data_all[i_pop_size][inN] = np.nanstd(perClassErrorTest_data_allFrs[i_pop_size][inN], axis=0) / np.sqrt(numSamples) + + av_test_shfl_all[i_pop_size][inN] = 100-np.nanmean(perClassErrorTest_shfl_allFrs[i_pop_size][inN], axis=0) # numFrames + sd_test_shfl_all[i_pop_size][inN] = np.nanstd(perClassErrorTest_shfl_allFrs[i_pop_size][inN], axis=0) / np.sqrt(numSamples) + + av_test_chance_all[i_pop_size][inN] = 100-np.nanmean(perClassErrorTest_chance_allFrs[i_pop_size][inN], axis=0) # numFrames + sd_test_chance_all[i_pop_size][inN] = np.nanstd(perClassErrorTest_chance_allFrs[i_pop_size][inN], axis=0) / np.sqrt(numSamples) + + ######### Average across *neuron* subsamples (already averaged across cv samples) ######### + av_train_data = np.mean(av_train_data_all, axis=1).squeeze() # numFrames + sd_train_data = np.std(av_train_data_all, axis=1).squeeze() / np.sqrt(numShufflesN) + av_test_data = np.mean(av_test_data_all, axis=1).squeeze() # numFrames + sd_test_data = np.std(av_test_data_all, axis=1).squeeze() / np.sqrt(numShufflesN) + av_test_shfl = np.mean(av_test_shfl_all, axis=1).squeeze() # numFrames + sd_test_shfl = np.std(av_test_shfl_all, axis=1).squeeze() / np.sqrt(numShufflesN) + av_test_chance = np.mean(av_test_chance_all, axis=1).squeeze() # numFrames + sd_test_chance = np.std(av_test_chance_all, axis=1).squeeze() / np.sqrt(numShufflesN) + + else: # average across cv samples # size perClassErrorTrain_data_allFrs: nSamples x nFrames + + av_train_data = 100-np.nanmean(perClassErrorTrain_data_allFrs, axis=0) # numFrames + sd_train_data = np.nanstd(perClassErrorTrain_data_allFrs, axis=0) / np.sqrt(numSamples) + + av_test_data = 100-np.nanmean(perClassErrorTest_data_allFrs, axis=0) # numFrames + sd_test_data = np.nanstd(perClassErrorTest_data_allFrs, axis=0) / np.sqrt(numSamples) + + av_test_shfl = 100-np.nanmean(perClassErrorTest_shfl_allFrs, axis=0) # numFrames + sd_test_shfl = np.nanstd(perClassErrorTest_shfl_allFrs, axis=0) / np.sqrt(numSamples) + + av_test_chance = 100-np.nanmean(perClassErrorTest_chance_allFrs, axis=0) # numFrames + sd_test_chance = np.nanstd(perClassErrorTest_chance_allFrs, axis=0) / np.sqrt(numSamples) + + av_w_data = np.nanmean(w_data_allFrs, axis=0) # nNeurons x nFrames, if n_classes=2; # classes x neurons x nFrames, if n_classes>2 + av_b_data = np.nanmean(b_data_allFrs, axis=0) # nFrames, if n_classes=2; # classes x nFrames, if n_classes>2 + + if n_neurons==1: # make sure all experiments have dimensions nNeurons x nFrames + av_w_data = av_w_data[np.newaxis,:] + + + ######################################################################################################## + ######################################################################################################## + #%% Quantify image signal by averaging the class accuracy traces in the window time_win + ######################################################################################################## + ######################################################################################################## + + # in the svm code used for flash/omission vs. gray, we would compute the baseline and subtract it out. + # here, we are just taking the average of the 750ms time points after the image + + # NOTE: if you end up using events in the decoding analysis, you should add the baseline parts of the code back (bc with events we can get a clean baseline). + + if np.in1d([-1,1], np.sign(frames_svm)).all(): # frames_svm includes both negative and positive values; ie svm was trained on some frames before and some frames after the trial onset. + samps_bef_here = -frames_svm[0] # relative to svm output traces (eg av_train_data) + else: + samps_bef_here = 0 + + if type(time_win)==str: # time_win = 'frames_svm' means : use frames_svm to quantify image signal + time_win_frames = frames_svm + samps_bef_here # these indices will be applied to svm trace outputs. + else: + time_win_frames = set_frame_window_flash_omit(time_win, samps_bef_here, frame_dur) + time_win_frames[np.in1d(time_win_frames, frames_svm + samps_bef_here)] + + print(f'frames_svm: {frames_svm}') + print(f'time_win_frames for quantification: {time_win_frames}') + + + # baseline + bl_index_pre_omit = np.arange(0,samps_bef_here) # you will need for response amplitude quantification, even if you dont use it below. + + + # concatenate CA traces for training, testing, shfl, and chance data, each a column in the matrix below; to compute their peaks all at once. + CA_traces = np.vstack((av_train_data, av_test_data, av_test_shfl, av_test_chance)).T # times x 4 +# print(CA_traces.shape) + + peak_amp_trainTestShflChance = np.nanmean(CA_traces[time_win_frames], axis=0) # 4 + + # compute the baseline + if use_events==0: # bc of the dff decay from the previous image, take the dff value at time 0 as baseline. + bl_preOmit = CA_traces[samps_bef_here] + else: + bl_preOmit = np.percentile(CA_traces[bl_index_pre_omit], bl_percentile, axis=0) # 4 +# peak_amp_trainTestShflChance = peak_amp_trainTestShflChance - bl_preOmit # subtract out the baseline + + this_sess.at[index, ['peak_amp_trainTestShflChance', 'bl_pre0']] = [peak_amp_trainTestShflChance, bl_preOmit] # 4 + + + this_sess.at[index, ['n_trials', 'n_neurons', 'cell_specimen_id', 'frame_dur', 'meanX_allFrs', 'stdX_allFrs']] = [n_trials, n_neurons, cell_specimen_id, frame_dur, meanX_allFrs, stdX_allFrs] + this_sess.at[index, ['av_train_data', 'av_test_data', 'av_test_shfl', 'av_test_chance', 'sd_train_data', 'sd_test_data', 'sd_test_shfl', 'sd_test_chance']] = [av_train_data, av_test_data, av_test_shfl, av_test_chance, sd_train_data, sd_test_data, sd_test_shfl, sd_test_chance] + + if same_num_neuron_all_planes: + this_sess.at[index, ['population_sizes_to_try']] = population_sizes_to_try + else: + this_sess.at[index, 'av_w_data'] = av_w_data + this_sess.at[index, 'av_b_data'] = av_b_data +# this_sess.at[index, ['av_w_data', 'av_b_data']] = [av_w_data, av_b_data] + + + + ######################################################################################################## + ######################################################################################################## + #%% Plots + ######################################################################################################## + ######################################################################################################## + #%% + if doPlots==1: + get_ipython().magic(u'matplotlib inline') +# flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, flashes_win_trace_index_unq, grays_win_trace_index_unq = \ +# flash_gray_onset_relOmit(samps_bef, samps_aft, frame_dur) + + + #%% Plot the mean and std of each neuron (across trials: half omission, half gray) + + if doPlots: + import seaborn #as sns + + plt.figure(figsize=(4.8,6)) + # mean + plt.subplot(211) + plt.plot(frames_svm, meanX_allFrs) + plt.title('meanX, eachN') # (half omit & half gray trials) + + mn = np.min(meanX_allFrs) + mx = np.max(meanX_allFrs) + plt.vlines([0], mn, mx, color='k', linestyle='--') # mark omission onset +# plt.vlines(flashes_win_trace_index_unq, mn, mx, color='y', linestyle='-.') # mark the onset of flashes +# plt.vlines(grays_win_trace_index_unq, mn, mx, color='gray', linestyle=':') # mark the onset of grays + + plt.grid(False) # plt.box(on=None) # plt.axis(True) + seaborn.despine() + + + ## std + plt.subplot(212) + plt.plot(frames_svm, stdX_allFrs) + plt.title('stdX, eachN') # (half omit & half gray trials) + plt.subplots_adjust(hspace=.55) + + mn = np.min(stdX_allFrs) + mx = np.max(stdX_allFrs) + plt.vlines([0], mn, mx, color='k', linestyle='--') # mark omission onset +# plt.vlines(flashes_win_trace_index_unq, mn, mx, color='y', linestyle='-.') # mark the onset of flashes +# plt.vlines(grays_win_trace_index_unq, mn, mx, color='gray', linestyle=':') # mark the onset of grays + plt.xlabel('Frames rel. image onset') + + plt.grid(False) # plt.box(on=None) # plt.axis(True) + seaborn.despine() + + + #%% Make plots of classification accuracy + + ### MAKE SURE to print number of neurons and number of trials in your plots + # some experiments (superficial layers) have only 1 neuron!! + + ### different planes have different number of neurons... so we cannot directly compare svm performance across planes!!! + # unless we subselect neurons!! + + if doPlots: + if (np.sign(frames_svm)==-1).all(): # when frames_svm is all negative + x = np.arange(frames_svm[0] * frame_dur, frames_svm[-1] * frame_dur, frame_dur) + else: +# samps_bef_here = -frames_svm[0] # relative to svm output traces (eg av_train_data) + samps_aft_here = frames_svm[-1]+1 + + samps_bef_time = (samps_bef_here+1) * frame_dur # 1 is added bc below we do np.arange(0,-samps_bef), so we get upto one value below samps_bef + samps_aft_time = samps_aft_here * frame_dur # frames_after_omission in svm_main # we trained the classifier until 30 frames after omission + + x = np.unique(np.concatenate((np.arange(0, -samps_bef_time, -frame_dur)[0:samps_bef_here+1], np.arange(0, samps_aft_time, frame_dur)[0:samps_aft_here]))) + + import seaborn + import matplotlib.ticker as ticker + + ### + plt.figure() + + h0 = plt.plot(x, av_train_data,'ko-', label='train', markersize=3.5); + h1 = plt.plot(x, av_test_data,'ro-', label='test', markersize=3.5); + h2 = plt.plot(x, av_test_shfl,'yo-', label='shfl', markersize=3.5); + h3 = plt.plot(x, av_test_chance,'bo-', label='chance', markersize=3.5); + + # errorbars (standard error across cv samples) + alph = .3 + plt.fill_between(x, av_train_data - sd_train_data, av_train_data + sd_train_data, alpha=alph, edgecolor='k', facecolor='k') + plt.fill_between(x, av_test_data - sd_test_data, av_test_data + sd_test_data, alpha=alph, edgecolor='r', facecolor='r') + plt.fill_between(x, av_test_shfl - sd_test_shfl, av_test_shfl + sd_test_shfl, alpha=alph, edgecolor='y', facecolor='y') + plt.fill_between(x, av_test_chance - sd_test_chance, av_test_chance + sd_test_chance, alpha=alph, edgecolor='b', facecolor='b') + + +# mn = 45; mx = 80 + # mark omission onset +# plt.vlines([0], mn, mx, color='k', linestyle='--') + # mark the onset of flashes +# plt.vlines(flashes_win_trace_index_unq_time, mn, mx, color='y', linestyle='-.') + # mark the onset of grays +# plt.vlines(grays_win_trace_index_unq_time, mn, mx, color='gray', linestyle=':') + + + ax = plt.gca() + xmj = np.round(np.arange(x[0], x[-1], .1), 3) + ax.set_xticks(xmj); # plt.xticks(np.arange(0,x[-1],.25)); #, fontsize=10) + ax.set_xticklabels(xmj, rotation=45) + xmn = np.round(np.arange(x[0]+.5, x[-1], .1), 3) + ax.xaxis.set_minor_locator(ticker.FixedLocator(xmn)) + ax.tick_params(labelsize=10, length=6, width=2, which='major') + ax.tick_params(labelsize=10, length=5, width=1, which='minor') + # plt.xticklabels(np.arange(0,x[-1],.25)) + + + plt.legend(handles=[h0[0],h1[0],h2[0],h3[0]], loc='center left', bbox_to_anchor=(1, .7), frameon=False, handlelength=.5, fontsize=12) + plt.ylabel('% Classification accuracy', fontsize=12) + plt.xlabel('Time rel. image onset (sec)', fontsize=12) + plt.title(f'{cre[:3]}, {area}, {depth}') + + plt.grid(False) # plt.box(on=None) # plt.axis(True) + seaborn.despine()#left=True, bottom=True, right=False, top=False) + + + ## Plot with x axis in frame units + ''' + plt.figure() + plt.plot(av_train_data, color='k', label='train') + plt.plot(av_test_data, color='r', label='test') + plt.plot(av_test_shfl, color='y', label='shfl') + plt.plot(av_test_chance, color='b', label='chance') + plt.legend(loc='center left', bbox_to_anchor=(1, .7)) + + mn = 45; mx = 80 + # mark omission onset + plt.vlines([0], mn, mx, color='k', linestyle='--') + # mark the onset of flashes + plt.vlines(flashes_win_trace_index_unq, mn, mx, color='y', linestyle='-.') + # mark the onset of grays + plt.vlines(grays_win_trace_index_unq, mn, mx, color='gray', linestyle=':') + + plt.legend(handles=[h0[1],h1[1],h2[1],h3[1]], loc='center left', bbox_to_anchor=(1, .7), frameon=False, handlelength=.5, fontsize=12) + plt.ylabel('% Classification accuracy', fontsize=12) + plt.xlabel('Frame after omission (sec)', fontsize=12) + ''' + + + + #%% +# all_sess = all_sess.append(this_sess) # all_sess is initiated in svm_init.py + + if set_to_nan==1: +# x, xnew = upsample_time_imaging(samps_bef, samps_aft, 31.) + + n_neurons = 1 # just an arbitrary number so we can set the arrays below + + av_train_data = np.full((numFrames), np.nan) + av_test_data = np.full((numFrames), np.nan) + av_test_shfl = np.full((numFrames), np.nan) + av_test_chance = np.full((numFrames), np.nan) + sd_train_data = np.full((numFrames), np.nan) + sd_test_data = np.full((numFrames), np.nan) + sd_test_shfl = np.full((numFrames), np.nan) + sd_test_chance = np.full((numFrames), np.nan) + + meanX_allFrs = np.full((numFrames, n_neurons), np.nan) # np.full((numFrames), np.nan) # + stdX_allFrs = np.full((numFrames, n_neurons), np.nan) # np.full((numFrames), np.nan) # + + if num_classes>2: + av_w_data = np.full((num_classes, n_neurons, numFrames), np.nan) + av_b_data = np.full((num_classes, numFrames), np.nan) + else: + av_w_data = np.full((n_neurons, numFrames), np.nan) + av_b_data = np.full((numFrames), np.nan) + + + this_sess.at[index, ['meanX_allFrs', 'stdX_allFrs']] = [meanX_allFrs, stdX_allFrs] + this_sess.at[index, ['av_train_data', 'av_test_data', 'av_test_shfl', 'av_test_chance', 'sd_train_data', 'sd_test_data', 'sd_test_shfl', 'sd_test_chance']] = \ + [av_train_data, av_test_data, av_test_shfl, av_test_chance, sd_train_data, sd_test_data, sd_test_shfl, sd_test_chance] + this_sess.at[index, ['peak_amp_trainTestShflChance']] = [np.full((4), np.nan)] # 4 + this_sess.at[index, ['bl_pre0']] = [np.full((4), np.nan)] # 4 + + if same_num_neuron_all_planes: + this_sess.at[index, ['population_sizes_to_try']] = np.nan + else: + this_sess.at[index, 'av_w_data'] = av_w_data + this_sess.at[index, 'av_b_data'] = av_b_data + + + return this_sess + + + + + + \ No newline at end of file diff --git a/visual_behavior/decoding_population/svm_images_plots_setVars.py b/visual_behavior/decoding_population/svm_images_plots_setVars.py new file mode 100644 index 000000000..01b92064d --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_setVars.py @@ -0,0 +1,674 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +The 1st script to run to make plots. Before this script, "svm_images_plots_init" must be run to save all_sess dataframe. + +This script loads all_sess that is set by function svm_main_post (called in svm_images_init). +It sets all_sess_2an, which is a subset of all_sess that only includes desired sessions for analysis (A, or B, etc). + +Its output is a pandas table "svm_this_plane_allsess" which includes svm variables for each mouse, (for each plane, for each area, and for each depth) and will be used for plotting. + +This script will call the following scripts to make all the plots related to svm analysis: +"svm_images_plots_eachMouse" to make plots for each mouse. +"svm_images_plots_setVars_sumMice.py" and "svm_images_plots_sumMice.py" which set vars and make average plots across mice (for each cre line). +"svm_images_plots_compare_ophys_stages.py" to make comparison of the decoding performance across ophys stages (or experience levels if using matched cells). + +Note, this script is similar to part of omissions_traces_peaks_plots_setVars_ave.py. + The variable svm_this_plane_allsess here is basically a combination of the following 2 vars in omissions_traces_peaks_plots_setVars_ave.py: + trace_peak_allMice : includes traces and peak measures for all planes of all sessions, for each mouse. + pooled_trace_peak_allMice : includes layer- and area-pooled vars, for each mouse. + +This script also sets some of the session-averaged vars per mouse (in var "svm_this_plane_allsess") , which will be used in eachMouse plots; + # note: those vars are also set in svm_plots_setVars_sumMice.py (in var "svm_this_plane_allsess_sessAvSd". I didn't take them out of here, bc below will be used for making eachMouse plots. Codes in svm_plots_setVars_sumMice.py are compatible with omissions code, and will be used for making sumMice plots. + + +NOTE: This code is the new version that replaced the old "svm_images_plots_setVars.py". It works for both when the svm was run on the whole session or when it was run on multiple blocks during the session. +It will create plots for each stage (ophy1, 2, etc). If you want average plots across stages, you need to modify line 60 of code "svm_images_plots_setVars_sumMice_blocks.py" so we dont get only a given stage out of svm_this_plane_allsess0 + + +Created on Tue Oct 20 13:56:00 2020 +@author: farzaneh +""" + +''' +Relevant parts of different scripts, for quantifying response amplitudes: + +# average across cv samples # size perClassErrorTrain_data_allFrs: nSamples x nFrames +av_train_data = 100-np.nanmean(perClassErrorTrain_data_allFrs, axis=0) # numFrames + + +# concatenate CA traces for training, testing, shfl, and chance data, each a column in the matrix below; to compute their peaks all at once. +CA_traces = np.vstack((av_train_data, av_test_data, av_test_shfl, av_test_chance)).T # times x 4 +# print(CA_traces.shape) + +peak_amp_trainTestShflChance = np.nanmean(CA_traces[time_win_frames], axis=0) + + +# peak_amp_trainTestShflChance +y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['peak_amp_trainTestShflChance'] # 8 * number_of_session_for_the_mouse +peak_amp_trTsShCh_this_plane_allsess_allp = set_y_this_plane_allsess(y, num_sessions) # size: (8 x num_sessions x 4) # 4 for train, Test, Shfl, and Chance + + +aa = svm_this_plane_allsess['peak_amp_trTsShCh_this_plane_allsess_allp'].values # num_all_mice; # size of each element : 8 x num_sessions x 4 +aar = np.array([np.reshape(aa[ic], (aa[ic].shape[0] * aa[ic].shape[1] , aa[ic].shape[2]), order='F') for ic in range(len(aa))]) # aar.shape # num_all_mice; # size of each element : (8 x num_sessions) x 4 +a0 = np.concatenate((aar)) # (8*sum(num_sess_per_mouse)) x 4 # 8 planes of 1 session, then 8 planes of next session, and so on +pa_all = np.reshape(a0, (num_planes, int(a0.shape[0]/num_planes), a0.shape[-1]), order='F') # 8 x sum(num_sess_per_mouse) x 4 # each row is one plane, all sessions + + +pa_all = svm_allMice_sessPooled['peak_amp_allPlanes'].values[0] # 8 x pooledSessNum x 4 (trTsShCh) + +top = np.nanmean(pa_all[:, cre_all[0,:]==cre], axis=1) +top_sd = np.nanstd(pa_all[:, cre_all[0,:]==cre], axis=1) / np.sqrt(sum(cre_all[0,:]==cre)) + + +# testing data +ax1.errorbar(x, top[inds_v1, 1], yerr=top_sd[inds_v1, 1], fmt=fmt_now, markersize=3, capsize=3, label=lab1, color=cols_area_now[1]) +ax1.errorbar(x + xgap_areas, top[inds_lm, 1], yerr=top_sd[inds_lm, 1], fmt=fmt_now, markersize=3, capsize=3, label=lab2, color=cols_area_now[0]) + +# shuffled data +ax1.errorbar(x, top[inds_v1, 2], yerr=top_sd[inds_v1, 2], fmt=fmt_now, markersize=3, capsize=3, color='gainsboro') # label='V1', # gray +ax1.errorbar(x + xgap_areas, top[inds_lm, 2], yerr=top_sd[inds_lm, 2], fmt=fmt_now, markersize=3, capsize=3, color='gainsboro') # label='LM', # skyblue + +''' + +import os +import numpy as np +import pandas as pd +import re +import datetime +import copy +import sys +import numpy.ma as ma +import seaborn as sns + +from general_funs import * + +import visual_behavior.data_access.loading as loading +from visual_behavior.ophys.response_analysis.response_analysis import ResponseAnalysis + +dir_server_me = '/allen/programs/braintv/workgroups/nc-ophys/Farzaneh' +dir0 = '/home/farzaneh/OneDrive/Analysis' + + +#%% Set the following vars + +project_codes = ['VisualBehavior'], ['VisualBehaviorTask1B'], ['VisualBehaviorMultiscope'] # pooled project codes for the paper: ['VisualBehavior'], ['VisualBehaviorTask1B'], ['VisualBehaviorMultiscope'] # if making plots for multiple project codes: ['VisualBehavior'], ['VisualBehaviorMultiscope'] # if making plots for a single project code: ['VisualBehaviorTask1B'] # all project codes: 'VisualBehaviorMultiscope', 'VisualBehaviorTask1B', 'VisualBehavior', 'VisualBehaviorMultiscope4areasx2d' + +dosavefig = 1 # 0 + +to_decode = 'next' # 'current': decode current image. # 'previous': decode previous image. # 'next': decode next image. +trial_type = 'omissions' # 'baseline_vs_nobaseline' # 'omissions' # 'changes' # 'changes_vs_nochanges' # 'hits_vs_misses' # 'images'# what trials to use for SVM analysis # the population activity of these trials at time time_win will be used to decode the image identity of flashes that occurred at their time 0 (if to_decode='current') or 750ms before (if to_decode='previous'). # eg 'omissions' means to use omission-aligned traces # 'baseline_vs_nobaseline' # decode activity at each frame vs. baseline (ie the frame before omission unless use_spont_omitFrMinus1 = 1 (see below)) +# Note: when trial_type is 'hits_vs_misses' or 'changes_vs_nochanges', to_decode will be 'current' and wont really make sense. +# in all other cases, we decode "to_decode" image from "trial_type", e.g. we decode 'current' image from 'changes' (ie change-aligned traces) + +use_matched_cells = 0 # set to either 0 or 123 : analyze all cells of an experiment. 123: analyze cells matched in all experience levels (familiar, novel 1 , novel >1); 12: cells matched in familiar and novel 1. 23: cells matched in novel 1 and novel >1. 13: cells matched in familiar and novel >1 + +use_events = True # True # False #whether to run the analysis on detected events (inferred spikes) or dff traces. +svm_blocks = np.nan #-101 #-1: divide trials based on engagement # -101: use only engaged epochs for svm analysis # number of trial blocks to divide the session to, and run svm on. # set to np.nan to run svm analysis on the whole session + +engagement_pupil_running = 0 # applicable when svm_blocks=-1 # np.nan or 0,1,2 for engagement, pupil, running: which metric to use to define engagement? +baseline_subtract = 0 #1 # subtract the baseline (CA average during baseline, ie before time 0) from the evoked CA (classification accuracy) + +summary_which_comparison = [3, 4, 6] #'all' # an array of session numbers: [3, 4, 6] or the following strings: # 'novelty' # 'engagement' # 'all' # determins sessions to use for plotting summary of ophys stages in svm_images_plots_compare_ophys_stages.py # 'novelty' will use [1,3,4,6] # 'engagement' will use [1,2,3] # 'all' will use [1,2,3,4,5,6] +fmt = '.pdf' # '.png' # '.svg' + +sigval = .05 # value for ttest significance + + + +#%% The following vars we usually don't change, but you can if you want to. + +plot_svm_weights = 0 +plot_single_mouse = 0 # if 1, make plots for each mouse + +# the following 3 vars will be used for plots to correlate classification accuracy with behavioral strategy, and only if trial_type =='changes_vs_nochanges' or trial_type =='hits_vs_misses' +pool_all_stages = True #True +fit_reg = False # lmplots: add the fitted line to the catter plot or not +superimpose_all_cre = False # plot all cre lines on the same figure +plot_testing_shufl = 0 # if 0 correlate testing data with strategy dropout index; if 1, correlated shuffled data with strategy dropout index + +use_spont_omitFrMinus1 = 1 # applicable when trial_type='baseline_vs_nobaseline' # if 0, classify omissions against randomly picked spontanoues frames (the initial gray screen); if 1, classify omissions against the frame right before the omission + +# Note: in the cases below, we are decoding baseline from no-baseline , hits from misses, and changes from no-changes, respectively. +# since we are not decoding images, to_decode really doesnt mean anything (when decoding images, to_decode means current/next/previous image) and we just set it to 'current' so it takes some value. +if trial_type == 'baseline_vs_nobaseline' or trial_type == 'hits_vs_misses' or trial_type == 'changes_vs_nochanges': + to_decode = 'current' + use_balanced_trials = 1 #only effective when num_classes=2 #if 1, use same number of trials for each class; only applicable when we have 2 classes (binary classification). +else: # decoding images + use_balanced_trials = 0 #1 #only effective when num_classes=2 #if 1, use same number of trials for each class; only applicable when we have 2 classes (binary classification). + + +# NOTE: below should match the plots_init code. or better you can load +''' +if use_events: + time_win = [0, .4] +else: + time_win = [0, .55] # 'frames_svm' # set time_win to a string (any string) to use frames_svm as the window of quantification. # time window relative to trial onset to quantify image signal. Over this window class accuracy traces will be averaged. +if trial_type == 'baseline_vs_nobaseline': + time_win = [0, .75] # we use the entire time after omission because the omission responses slowly go up +''' + +same_num_neuron_all_planes = 0 #1 # if 1, use the same number of neurons for all planes to train svm + +# cre2ana_all = 'slc', 'sst', 'vip' +use_same_experiments_dff_events = False #True # use the same set of experiments for both events and dff analysis (Note: for this to work you need to get both ea_evs and ev_dff; for this run the code until line ~300 twice once setting use_events to True and once to False.) + + + + +#%% Initialize variables + +e = 'events_' if use_events else '' + +if trial_type=='changes_vs_nochanges': # change, then no-change will be concatenated + svmn = f'{e}svm_decode_changes_from_nochanges' +elif trial_type=='hits_vs_misses': + svmn = f'{e}svm_decode_hits_from_misses' +elif trial_type == 'baseline_vs_nobaseline': + svmn = f'{e}svm_decode_baseline_from_nobaseline' #f'{e}svm_gray_omit' #svm_decode_baseline_from_nobaseline + if use_spont_omitFrMinus1==0: + svmn = svmn + '_spontFrs' +else: + svmn = f'{e}svm_decode_{to_decode}_image_from_{trial_type}' # 'svm_gray_omit' + + +if use_matched_cells==123: + svmn = svmn + '_matched_cells_FN1N2' #Familiar, N1, N+1 +elif use_matched_cells==12: + svmn = svmn + '_matched_cells_FN1' +elif use_matched_cells==23: + svmn = svmn + '_matched_cells_N1Nn' +elif use_matched_cells==13: + svmn = svmn + '_matched_cells_FNn' + + +if svm_blocks==-101: # run svm analysis only on engaged trials; redifine df_data only including the engaged rows + svmn = f'{svmn}_only_engaged' + +if use_balanced_trials: + svmn = f'{svmn}_equalTrs' + +print(svmn) + + +dir_now = svmn #'omit_across_sess' +if use_events: + dir_now = 'svm_' + svmn[len('events_svm_'):] + '_events' # so all the folders start with svm + +if svm_blocks==-1: + dir_now = os.path.join(dir_now, f'engaged_disengaged_blocks') +elif svm_blocks==-101: + dir_now = os.path.join(dir_now, f'only_engaged') +elif ~np.isnan(svm_blocks): + dir_now = os.path.join(dir_now, f'trial_blocks') + +dd = os.path.join(dir0, 'svm', dir_now) +if not os.path.exists(dd): + os.makedirs(dd) + +now = (datetime.datetime.now()).strftime("%Y%m%d_%H%M%S") + + + +#%% Set vars related to plotting + +get_ipython().magic(u'matplotlib inline') # %matplotlib inline + +cols_area = ['b', 'k'] # first plot V1 (in black, index 1) then LM (in blue, index 0) +cols_depth = ['b', 'c', 'g', 'r'] #colorOrder(num_depth) #a.shape[0]) # depth1_area2 +alph = .3 # for plots, transparency of errorbars +bb = (.92, .7) # (.9, .7) + +ylabel = '% Classification accuracy' + +if trial_type=='baseline_vs_nobaseline' or trial_type=='omissions': + xlabel = 'Time from omission (sec)' #'Time rel. trial onset (sec)' +elif trial_type=='changes' or trial_type=='changes_vs_nochanges': + xlabel = 'Time from image change (sec)' +else: + xlabel = 'Time from image (sec)' + + + +############################################################################## +############################################################################## +############################################################################## +#%% Load and concatenate all_sess from all cre lines and all sessions +############################################################################## +############################################################################## +############################################################################## + +#%% +dir_svm = os.path.join(dir_server_me, 'SVM') +if same_num_neuron_all_planes: + dir_svm = os.path.join(dir_svm, 'same_num_neurons_all_planes') +if ~np.isnan(svm_blocks): + dir_svm = os.path.join(dir_svm, f'trial_blocks') + + + + +#%% +if svm_blocks==-101: + br = [np.nan] +elif ~np.isnan(svm_blocks): + if svm_blocks==-1: # divide trials into blocks based on the engagement state + svmb = 2 + else: + svmb = svm_blocks + br = range(svmb) +else: + br = [np.nan] +print(br) + +project_codes_all = copy.deepcopy(project_codes) + + +##################################################################################### +#%% Follow this script by "svm_images_plots_setVars_sumMice.py" to set vars for making average plots across mice (for each cre line). +##################################################################################### + +if len(project_codes_all)==1: + + #%% Set frames_svm, samps_bef and samps_aft + # Note: trials df has a much longer time_trace (goes up to 4.97) compared to stimulus df (goes up to .71), so frames_svm ends up being 1 element longer for trials df (ie when decoding hits from misses) compared to stimulus df (ie when decoding the images) + if project_codes != ['VisualBehaviorMultiscope']: + frames_svm = np.arange(-15,23) + num_planes = 1 + num_depth = 1 + else: + frames_svm = np.arange(-5,8) + num_planes = 8 + num_depth = 4 + + if trial_type=='hits_vs_misses': # frames_svm[-1] = frames_svm[-1] + 1 + frames_svm = np.concatenate((frames_svm, [frames_svm[-1] + 1])) + + # numFrames = samps_bef + samps_aft + frames_svm = np.array(frames_svm) + + samps_bef = -frames_svm[0] # np.argwhere(trace_time==0)[0][0] # 5 + samps_aft = len(frames_svm)-samps_bef #8 + print(samps_bef, samps_aft) + + # if trial_type=='hits_vs_misses': + # samps_aft = samps_aft + 1 + + + #%% + cols_each = colorOrder(num_planes) + + + + #%% Set svm vars for each plane across all sessions (for each mouse) + if project_codes != ['VisualBehaviorMultiscope']: # remove area/layer pooled columns + columns0 = ['mouse_id', 'cre', 'mouse_id_exp', 'cre_exp', 'block', 'session_ids', 'experience_levels', 'session_stages', 'session_labs', 'num_sessions_valid', 'area_this_plane_allsess_allp', 'depth_this_plane_allsess_allp', \ + 'area', 'depth', 'plane', \ + 'n_neurons_this_plane_allsess_allp', 'n_trials_this_plane_allsess_allp', \ + 'av_meanX_avSess_eachP', 'sd_meanX_avSess_eachP', \ + 'av_test_data_this_plane_allsess_allp', 'av_test_shfl_this_plane_allsess_allp', \ + 'av_test_data_avSess_eachP', 'sd_test_data_avSess_eachP', 'av_test_shfl_avSess_eachP', 'sd_test_shfl_avSess_eachP', \ + 'av_train_data_avSess_eachP', 'sd_train_data_avSess_eachP', \ + 'av_n_neurons_avSess_eachP', 'sd_n_neurons_avSess_eachP', 'av_n_trials_avSess_eachP', 'sd_n_trials_avSess_eachP', \ + 'distinct_areas', \ + 'peak_amp_trTsShCh_this_plane_allsess_allp', \ + 'av_peak_amp_trTsShCh_avSess_eachP', 'sd_peak_amp_trTsShCh_avSess_eachP', \ + ] + + else: + columns0 = ['mouse_id', 'cre', 'mouse_id_exp', 'cre_exp', 'block', 'session_ids', 'experience_levels', 'session_stages', 'session_labs', 'num_sessions_valid', 'area_this_plane_allsess_allp', 'depth_this_plane_allsess_allp', \ + 'area', 'depth', 'plane', \ + 'n_neurons_this_plane_allsess_allp', 'n_trials_this_plane_allsess_allp', \ + 'av_meanX_avSess_eachP', 'sd_meanX_avSess_eachP', \ + 'av_test_data_this_plane_allsess_allp', 'av_test_shfl_this_plane_allsess_allp', \ + 'av_test_data_avSess_eachP', 'sd_test_data_avSess_eachP', 'av_test_shfl_avSess_eachP', 'sd_test_shfl_avSess_eachP', \ + 'av_train_data_avSess_eachP', 'sd_train_data_avSess_eachP', \ + 'av_n_neurons_avSess_eachP', 'sd_n_neurons_avSess_eachP', 'av_n_trials_avSess_eachP', 'sd_n_trials_avSess_eachP', \ + 'av_test_data_pooled_sesss_planes_eachArea', 'av_test_shfl_pooled_sesss_planes_eachArea', 'meanX_pooled_sesss_planes_eachArea', \ + 'num_sessions_valid_eachArea', 'distinct_areas', 'cre_pooled_sesss_planes_eachArea', \ + 'av_test_data_pooled_sesss_areas_eachDepth', 'av_test_shfl_pooled_sesss_areas_eachDepth', 'meanX_pooled_sesss_areas_eachDepth', \ + 'cre_pooled_sesss_areas_eachDepth', 'depth_pooled_sesss_areas_eachDepth', \ + 'peak_amp_trTsShCh_this_plane_allsess_allp', \ + 'av_peak_amp_trTsShCh_avSess_eachP', 'sd_peak_amp_trTsShCh_avSess_eachP', \ + 'peak_amp_trTsShCh_pooled_sesss_planes_eachArea', \ + 'peak_amp_trTsShCh_pooled_sesss_areas_eachDepth', \ + ] + + if same_num_neuron_all_planes: + columns = np.concatenate((columns0, ['n_neurons_svm_trained_this_plane_allsess_allp', 'av_n_neurons_svm_trained_avSess_eachP', 'sd_n_neurons_svm_trained_avSess_eachP'])) + else: + columns = columns0 + + + ##################################### + #%% Set svm_this_plane_allsess + ##################################### + + + ######### set svm_this_plane_allsess + + exec(open('svm_images_plots_setVars2.py').read()) + + svm_this_plane_allsess0 = copy.deepcopy(svm_this_plane_allsess) + + + ######### set svm_allMice_sessPooled and svm_allMice_sessAvSd + # note: svm_allMice_sessPooled will be used to set summary_vars_all, which is a key paramter in svm_images_plots_compare_ophys_stages.py) + exec(open('svm_images_plots_setVars_sumMice.py').read()) + + svm_allMice_sessPooled0 = copy.deepcopy(svm_allMice_sessPooled) + svm_allMice_sessAvSd0 = copy.deepcopy(svm_allMice_sessAvSd) + + + ######### set vars to make decoding timecourse plots, mouse-averaged, for each ophys stage + # also set summary_vars_all (a df that includes response amplitude, computed from svm_allMice_sessPooled) which will be used in svm_images_plots_compare_ophys_stages + exec(open('svm_images_plots_setVars_sumMice2.py').read()) + + # make mouse-averaged plots + # it gets called in svm_images_plots_setVars_sumMice2.py +# exec(open('svm_images_plots_sumMice.py').read()) + + + ######### compare quantifications across ophys stages + exec(open('svm_images_plots_compare_ophys_stages.py').read()) + + + + ############################################################ + #%% Plot svm weight distributions + + if plot_svm_weights and project_codes == ['VisualBehaviorMultiscope']: + + ifr = [4,6] + plt.figure(figsize = (10,6)) + icre = 0 + for cren in ['Slc17a7-IRES2-Cre', 'Sst-IRES-Cre', 'Vip-IRES-Cre']: + icre = icre+1 + bb = all_sess[all_sess['cre']==cren]; + c = np.concatenate((bb['av_w_data'].values), axis=(1)) # (8, 730, 13) + # cc = c[:,:,ifr] # frame after image onset + cc = c[:,:,ifr[1]] - c[:,:,ifr[0]] + + a = cc.flatten() # pool all the 8 decoders + # a = np.nanmean(cc, axis=0); # get average of the 8 decoders + # a = cc[di] # only take one decoder + + print(bb.shape, a.shape) + + # plot weights + plt.subplot(2, 3, icre) + plt.hist(a, 50) #, density=True); + plt.xlabel('svm weights'); plt.ylabel('number of neurons'); + plt.title(f'{cren[:3]}, mean={np.nanmean(a):.4f}') + + # plot absolute weights + plt.subplot(2, 3, icre+3) + plt.hist(np.abs(a), 50) #, density=True); + plt.xlabel('svm absolute weights'); plt.ylabel('number of neurons'); + plt.title(f'{cren[:3]}, mean={np.nanmean(np.abs(a)):.4f}') + + plt.subplots_adjust(wspace=0.5, hspace=0.5) + + plt.suptitle(f'frame {ifr}, 8 decoders pooled') + plt.suptitle(f'Average of 8 decoders') + # plt.suptitle(f'Decoder {di}') + + + + + ### plot distributions for individual decoders (the 8 decoders) + ''' + ifr = 4 #6 + for di in range(8): + plt.figure(figsize = (10,6)) + icre = 0 + for cren in ['Slc17a7-IRES2-Cre', 'Sst-IRES-Cre', 'Vip-IRES-Cre']: + icre = icre+1 + bb = all_sess[all_sess['cre']==cren]; + c = np.concatenate((bb['av_w_data'].values), axis=(1)) # (8, 730, 13) + cc = c[:,:,ifr] # frame after image onset + # cc = c[:,:,6] - c[:,:,4] + + a = cc.flatten() # pool all the 8 decoders + # a = np.nanmean(cc, axis=0); # get average of the 8 decoders + a = cc[di] # only take one decoder + + print(bb.shape, a.shape) + + # plot weights + plt.subplot(2, 3, icre) + plt.hist(a, 50) #, density=True); + plt.xlabel('svm weights'); plt.ylabel('number of neurons'); + plt.title(f'{cren[:3]}, mean={np.nanmean(a):.4f}') + + # plot absolute weights + plt.subplot(2, 3, icre+3) + plt.hist(np.abs(a), 50) #, density=True); + plt.xlabel('svm absolute weights'); plt.ylabel('number of neurons'); + plt.title(f'{cren[:3]}, mean={np.nanmean(np.abs(a)):.4f}') + + plt.subplots_adjust(wspace=0.5, hspace=0.5) + + plt.suptitle(f'frame {ifr}, 8 decoders pooled') + plt.suptitle(f'Average of 8 decoders') + plt.suptitle(f'Decoder {di}') + ''' + + + + +##################################################################################### +##################################################################################### +##################################################################################### +##################################################################################### +##################################################################################### +##################################################################################### +##################################################################################### +##################################################################################### +##################################################################################### +##################################################################################### + + +else: # pooling data across multiple project codes + + ##################################################################################### + #%% Set svm_allMice_sessPooled_allprojects and svm_allMice_sessAvSd_allprojects + + all_sess0_allprojects = [] + svm_allMice_sessPooled_allprojects = [] + svm_allMice_sessAvSd_allprojects = [] + + for project_codes in project_codes_all: + + print(f'==============================\n==============================\n==============================') + print(f'\nRunning project {project_codes}\n') + + #%% Set frames_svm, samps_bef and samps_aft + # Note: trials df has a much longer time_trace (goes up to 4.97) compared to stimulus df (goes up to .71), so frames_svm ends up being 1 element longer for trials df (ie when decoding hits from misses) compared to stimulus df (ie when decoding the images) + if project_codes != ['VisualBehaviorMultiscope']: + frames_svm = np.arange(-15,23) + num_planes = 1 + num_depth = 1 + else: + frames_svm = np.arange(-5,8) + num_planes = 8 + num_depth = 4 + + if trial_type=='hits_vs_misses': # frames_svm[-1] = frames_svm[-1] + 1 + frames_svm = np.concatenate((frames_svm, [frames_svm[-1] + 1])) + + frames_svm = np.array(frames_svm) + + samps_bef = -frames_svm[0] # np.argwhere(trace_time==0)[0][0] # 5 + samps_aft = len(frames_svm)-samps_bef #8 + print(samps_bef, samps_aft) + + + #%% + cols_each = colorOrder(num_planes) + + #%% Set svm vars for each plane across all sessions (for each mouse) + if project_codes != ['VisualBehaviorMultiscope']: # remove area/layer pooled columns + columns0 = ['mouse_id', 'cre', 'mouse_id_exp', 'cre_exp', 'block', 'session_ids', 'experience_levels', 'session_stages', 'session_labs', 'num_sessions_valid', 'area_this_plane_allsess_allp', 'depth_this_plane_allsess_allp', \ + 'area', 'depth', 'plane', \ + 'n_neurons_this_plane_allsess_allp', 'n_trials_this_plane_allsess_allp', \ + 'av_meanX_avSess_eachP', 'sd_meanX_avSess_eachP', \ + 'av_test_data_this_plane_allsess_allp', 'av_test_shfl_this_plane_allsess_allp', \ + 'av_test_data_avSess_eachP', 'sd_test_data_avSess_eachP', 'av_test_shfl_avSess_eachP', 'sd_test_shfl_avSess_eachP', \ + 'av_train_data_avSess_eachP', 'sd_train_data_avSess_eachP', \ + 'av_n_neurons_avSess_eachP', 'sd_n_neurons_avSess_eachP', 'av_n_trials_avSess_eachP', 'sd_n_trials_avSess_eachP', \ + 'distinct_areas', \ + 'peak_amp_trTsShCh_this_plane_allsess_allp', \ + 'av_peak_amp_trTsShCh_avSess_eachP', 'sd_peak_amp_trTsShCh_avSess_eachP', \ + ] + + else: + columns0 = ['mouse_id', 'cre', 'mouse_id_exp', 'cre_exp', 'block', 'session_ids', 'experience_levels', 'session_stages', 'session_labs', 'num_sessions_valid', 'area_this_plane_allsess_allp', 'depth_this_plane_allsess_allp', \ + 'area', 'depth', 'plane', \ + 'n_neurons_this_plane_allsess_allp', 'n_trials_this_plane_allsess_allp', \ + 'av_meanX_avSess_eachP', 'sd_meanX_avSess_eachP', \ + 'av_test_data_this_plane_allsess_allp', 'av_test_shfl_this_plane_allsess_allp', \ + 'av_test_data_avSess_eachP', 'sd_test_data_avSess_eachP', 'av_test_shfl_avSess_eachP', 'sd_test_shfl_avSess_eachP', \ + 'av_train_data_avSess_eachP', 'sd_train_data_avSess_eachP', \ + 'av_n_neurons_avSess_eachP', 'sd_n_neurons_avSess_eachP', 'av_n_trials_avSess_eachP', 'sd_n_trials_avSess_eachP', \ + 'av_test_data_pooled_sesss_planes_eachArea', 'av_test_shfl_pooled_sesss_planes_eachArea', 'meanX_pooled_sesss_planes_eachArea', \ + 'num_sessions_valid_eachArea', 'distinct_areas', 'cre_pooled_sesss_planes_eachArea', \ + 'av_test_data_pooled_sesss_areas_eachDepth', 'av_test_shfl_pooled_sesss_areas_eachDepth', 'meanX_pooled_sesss_areas_eachDepth', \ + 'cre_pooled_sesss_areas_eachDepth', 'depth_pooled_sesss_areas_eachDepth', \ + 'peak_amp_trTsShCh_this_plane_allsess_allp', \ + 'av_peak_amp_trTsShCh_avSess_eachP', 'sd_peak_amp_trTsShCh_avSess_eachP', \ + 'peak_amp_trTsShCh_pooled_sesss_planes_eachArea', \ + 'peak_amp_trTsShCh_pooled_sesss_areas_eachDepth', \ + ] + + if same_num_neuron_all_planes: + columns = np.concatenate((columns0, ['n_neurons_svm_trained_this_plane_allsess_allp', 'av_n_neurons_svm_trained_avSess_eachP', 'sd_n_neurons_svm_trained_avSess_eachP'])) + else: + columns = columns0 + + ##################################### + #%% Loads and concatenates all_sess from all cre lines into a df called all_sess0. Also sets svm_this_plane_allsess. + ##################################### + + exec(open('svm_images_plots_setVars2.py').read()) + + svm_this_plane_allsess0 = copy.deepcopy(svm_this_plane_allsess) + + + ######### set svm_allMice_sessPooled and svm_allMice_sessAvSd + # note: svm_allMice_sessPooled will be used to set summary_vars_all, which is a key paramter in svm_images_plots_compare_ophys_stages.py) + exec(open('svm_images_plots_setVars_sumMice.py').read()) + + all_sess0_allprojects.append(all_sess0) + svm_allMice_sessPooled_allprojects.append(svm_allMice_sessPooled) + svm_allMice_sessAvSd_allprojects.append(svm_allMice_sessAvSd) + + + + + #################################################### + #%% make svm_df which is a proper pandas table including svm response amplitude results for each experiment ################## + # these dfs will be used to make summary plots across experience levels, and also for doing stats. + + # note svm_df is redefined in: svm_images_plots_compare_experience_levels.py; there it pools all project codes and changes some column names. + + svm_df_allpr = [] + resp_amp_sum_df_allpr = [] # we dont really use this; instead we set it in "svm_images_plots_setVars_sumMice3_resp_sum" for all projects codes pooled (ie ave and sd of resp amp across all project codes) + for ipc in range(len(project_codes_all)): + + project_code = project_codes_all[ipc] + all_sess0 = all_sess0_allprojects[ipc] + svm_allMice_sessPooled0 = svm_allMice_sessPooled_allprojects[ipc] + + exec(open('svm_images_plots_setVars_sumMice3_svmdf.py').read()) + + svm_df_allpr.append(svm_df) + resp_amp_sum_df_allpr.append(resp_amp_sum_df) + + + ################## set resp_amp_sum_df: it includes the average of response amplitude across all experiments of all projects ################## + + exec(open('svm_images_plots_setVars_sumMice3_resp_sum.py').read()) + + # use below if you want to make area, depth summary plots for all pojects pooled. + # note we are doing it only for 'VisualBehaviorMultiscope' data + # set set resp_amp_sum_df_area & set resp_amp_sum_df_depth; they include summary CA values for each area, and each binned depth respectively + exec(open('svm_images_plots_setVars_sumMice3_resp_sum_area_depth.py').read()) + + + ################## compare quantifications across experience levels ################## + + exec(open('svm_images_plots_compare_experience_levels.py').read()) + + # make summary plots for area, depth comparison + # note we are doing it only for 'VisualBehaviorMultiscope' data + exec(open('svm_images_plots_compare_experience_levels_area_depth.py').read()) + + + ################## plot decoding traces for each experience level ################## + exec(open('svm_images_plots_compare_traces_experience_levels.py').read()) + + + ###################################################### + #%% set summary_vars_all, a dataframe that includes response amplitude (computed from svm_allMice_sessPooled); it will be used in svm_images_plots_compare_ophys_stages.py + + summary_vars_allpr = [] + for ipc in range(len(project_codes_all)): + + svm_allMice_sessPooled0 = svm_allMice_sessPooled_allprojects[ipc] + svm_allMice_sessAvSd0 = svm_allMice_sessAvSd_allprojects[ipc] + + project_codes = project_codes_all[ipc] + + exec(open('svm_images_plots_setVars_sumMice2.py').read()) + + summary_vars_allpr.append(summary_vars_all) + + + ################## compare quantifications across ophys stages ################## + + # pool summary_vars_all of the 2 projects + + summary_vars_all = pd.concat((summary_vars_allpr)) + summary_vars_all.shape + + exec(open('svm_images_plots_compare_ophys_stages.py').read()) + + + + + + + ##################################### + #%% Pool data from both project codes + ##################################### + + # svm_allMice_sessPooled0_vb.iloc[0]['av_test_shfl_allPlanes'].shape + # (1, 34, 38) + # svm_allMice_sessPooled0_vbm.iloc[0]['av_test_shfl_allPlanes'].shape + # (8, 21, 13) + + # svm_allMice_sessPooled0_vb.iloc[0]['peak_amp_allPlanes'].shape + # (1, 34, 4) + # svm_allMice_sessPooled0_vbm.iloc[0]['peak_amp_allPlanes'].shape + # (8, 21, 4) + + + #%% turn the variables into a single long vector, independent of the area/depth + ''' + # for each project code: concatenate data from all planes and sessions + pa_allpr = [] + for ipc in range(len(project_codes_all)): + +# svm_allMice_sessPooled_allprojects[ipc].iloc[0]['peak_amp_allPlanes'].shape + pa_now = np.vstack(svm_allMice_sessPooled_allprojects[ipc].iloc[0]['peak_amp_allPlanes']) # you are doing iloc[0] so you are taking data only from one session + print(pa_now.shape) + + pa_allpr.append(pa_now) + + + # now concatenate data from all projects + pa_pooled_projects = np.concatenate((pa_allpr), axis=0) # pooled_session_planes_projects x 4 + pa_pooled_projects.shape + ''' + \ No newline at end of file diff --git a/visual_behavior/decoding_population/svm_images_plots_setVars2.py b/visual_behavior/decoding_population/svm_images_plots_setVars2.py new file mode 100644 index 000000000..e8e049151 --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_setVars2.py @@ -0,0 +1,1132 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Gets called in svm_images_plots_setVars.py (Read the comments in that script for more info.) + +Loads and concatenates all_sess from all cre lines into a df called all_sess0 +Also sets svm_this_plane_allsess. + +Created on Tue Oct 20 13:56:00 2020 +@author: farzaneh +""" + +##################################################################### +##################################################################### +#%% Define functions to set vars needed for plotting + +def set_y_this_plane_allsess(y, num_sessions, takeAve=0): # set takeAve to 1 for meanX_allFrs (so we average across neurons) + + #%% Get data from a given plane across all sessions (assuming that the same order of planes exist in all sessions, ie for instance plane n is always the ith experiment in all sessions.) + # PERHAPS just forget about all of this below and do a reshape, you can double check reshape by doing the same thing on plane, area, depth + + y_this_plane_allsess_allp = [] + for iplane in range(num_planes): # iplane=0 + + ##### get data from a given plane across all sessions + y_this_plane_allsess = y.at[iplane] # num_sess + + # when the mouse had only one session, we need the following to take care of the shape of y_this_plane_allsess + if np.shape(y_this_plane_allsess)==(): # type(y_this_plane_allsess) == int: --> this didnt work bc populatin_sizes_to_try is of type numpy.int64 + if type(y_this_plane_allsess) == str: + y_this_plane_allsess = np.array([y_this_plane_allsess]) + else: + y_this_plane_allsess = np.array([np.float(y_this_plane_allsess)]) + + if num_sessions < 2: + y_this_plane_allsess = y_this_plane_allsess[np.newaxis,:] +# print(np.shape(y_this_plane_allsess), y_this_plane_allsess.dtype) + + + # If y_this_plane_allsess is not a vector, take average across the 2nd dimension + if takeAve==1: + nonNan_sess = np.array([np.sum(~np.isnan(y_this_plane_allsess[isess])) for isess in range(num_sessions)]) + len_trace = np.shape(y.values[0])[0] #len(y.values[0]) #y[0].shape + aa = np.full((num_sessions, len_trace), np.nan) # [] + for isess in range(num_sessions): # isess = 0 + if nonNan_sess[isess] > 0: + aa[isess] = np.mean(y_this_plane_allsess[isess], axis = 1) + y_this_plane_allsess = aa #np.array(aa) + + y_this_plane_allsess = np.vstack(y_this_plane_allsess) # num_sess x nFrames +# print(np.shape(y_this_plane_allsess), y_this_plane_allsess.dtype) + + + y_this_plane_allsess_allp.append(y_this_plane_allsess) # .squeeze() +# y_this_plane_allsess_allp.at[iplane] = area, depth, y_this_plane_allsess + + y_this_plane_allsess_allp = np.array(y_this_plane_allsess_allp) + + return y_this_plane_allsess_allp + + + + +def pool_sesss_planes_eachArea(area, y): + #%% Pool all sessions and layers for each area, do this for each mouse + + # area: ['LM', 'LM', 'LM', 'LM', 'VISp', 'VISp', 'VISp', 'VISp', 'LM', 'LM', 'LM', 'LM', 'VISp', 'VISp', 'VISp', 'VISp'] # (8*num_sessions) + # y : (8*num_sessions) x time or # (8*num_sessions) + + # set area indeces +# area = trace_peak_allMice.iloc[im]['area'] # (8*num_sessions) + distinct_areas, i_areas = np.unique(area, return_inverse=True) + # print(distinct_areas) + if len(distinct_areas) > 2: + sys.exit('There should not be more than two areas!! Fix the area names!') + + # below has size: num_areas x (num_layers_per_area x num_sessions) x nFrames_upsampled + # so, 2 x (4 x num_sessions) x nFrames_upsampled + # For each area, first take all the layers of session 1, then take all the layers of session 2 + y_pooled_sesss_planes_eachArea = np.array([y[i_areas == ida] for ida in range(len(distinct_areas))]) # 2 x (8/2 x num_sessions) x nFrames_upsampled + + return y_pooled_sesss_planes_eachArea, distinct_areas, i_areas + + + + + +def pool_sesss_areas_eachDepth(planes_allsess, y, num_depth=4): + #%% For each layer (depth), pool data across sessions and areas + + # planes_allsess: [0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7] # (8*num_sessions) + # y: (8*num_sessions) x time or (8*num_sessions) + # num_depth: 4 + + y_pooled_sesss_areas_eachDepth = [] + for idepth in range(num_depth): # idepth = 0 + # merge data with the same depth across 2 areas + # For each depth, first take all the areas of session 1, then take all the areas of session 2 + b = np.logical_or(planes_allsess==idepth, planes_allsess==idepth + num_depth) + a = y[b] #np.array([t[b]]).squeeze() # (2 x num_sess) x nFrames_upsampled + y_pooled_sesss_areas_eachDepth.append(a) + y_pooled_sesss_areas_eachDepth = np.array(y_pooled_sesss_areas_eachDepth) # 4 x (2 x num_sess) x nFrames_upsampled # 4 is the number of distinct depths: depth1_area2 + + return y_pooled_sesss_areas_eachDepth + + + + +############################################################################################## +############################################################################################## + + +svm_this_plane_allsess = pd.DataFrame([], columns=columns) +cntall = 0 # index of svm_this_plane_allsess df; not really important if it starts at 1 or 0. + +for iblock in br: # iblock=0 ; iblock=np.nan + +# svm_allMice_sessPooled_block_name = f'svm_allMice_sessPooled_block{iblock}' +# svm_allMice_sessAvSd_block_name = f'svm_allMice_sessAvSd_block{iblock}' + +# allSessName_block_name = f'allSessName_block{iblock}' # not sure if we need this anymore + + ############################################################################## + ############################################################################## + #%% Read all_see h5 file made in svm_main_post (by calling svm_init) + # all cre lines, a given block; (a given frames_svm; latest files saved) + ############################################################################## + ############################################################################## + +# a = f'(.*)_frames{frames_svm[0]}to{frames_svm[-1]}' # {cre2ana} + + allSessName = [] +# for cre2ana in cre2ana_all: # cre2ana = cre2ana_all[0] + + b = '_'.join(project_codes) + a = f'frames{frames_svm[0]}to{frames_svm[-1]}' +# a = f'{cre2ana}_frames{frames_svm[0]}to{frames_svm[-1]}' + + if ~np.isnan(svm_blocks) and svm_blocks!=-101: + if svm_blocks==-1: # divide trials into blocks based on the engagement state + word = 'engaged' + else: + word = 'block' + + a = f'{a}_{word}{iblock}' + + name = f'all_sess_{svmn}_{a}_{b}_.' +# name = f'all_sess_{svmn}_{a}_(.*){analysis_date}_.' # analysis_date = 20210108 + # print(name) + + allSessName_thisCre, h5_files = all_sess_set_h5_fileName(name, dir_svm, all_files=0) # all_files=1 + allSessName.append(allSessName_thisCre) + + print(f'\n{len(allSessName_thisCre)} all_sess files found!\n') + +# exec(allSessName_block_name + " = allSessName") + + + #%% Set block number, use the last allsess file ... this needs work. + + # a = h5_files[0].find('block') + # if a!=-1: + # iblock = h5_files[0][a+5] + # print(f'Analyzing block {iblock}') + # else: + # iblock = np.nan + + + + ######################################################################### + ######################################################################### + ######################################################################### + #%% Load all_sess dataframe for all cre lines, for a given block + ######################################################################### + ######################################################################### + ######################################################################### + + all_sess = pd.DataFrame() + for ia in range(len(allSessName)): + print(f'Loading: {allSessName[ia]}') + all_sess_now = pd.read_hdf(allSessName[ia], key='all_sess') #'svm_vars') + all_sess = pd.concat([all_sess, all_sess_now]) +# all_sess +# all_sess.keys() +# print(len(all_sess)) +# print(len(all_sess)/8) + + all_sess0 = copy.deepcopy(all_sess) + + + ####################################################################################### + #%% Remove mesoscope sessions with unusual frame duration; note this is a temporary solution. We will later interpolated their traces. + ####################################################################################### + + if project_codes == ['VisualBehaviorMultiscope']: + s = sum(all_sess0['frame_dur']>.1) + ss = all_sess0[all_sess0['frame_dur']>.1]['session_id'].unique() + if s>0: + print(all_sess0[all_sess0['frame_dur']>.1][['session_id','experiment_id', 'date', 'frame_dur']]) + print(f'\n\n{s} mesoscope experiments, {ss.shape[0]} sessions, have unusual frame duration; excluding them!!') + + print(all_sess0.shape) + a0 = all_sess0['session_id'].isin(ss) #[1050231786, 1050597678, 1051107431]) + if sum(a0)>0: + print(f'\n\n\n Removing {sum(a0)} mesoscope experiments with unusual frame duration; note this is a temporary solution\n\n\n') + all_sess0 = all_sess0[~a0] + print(all_sess0.shape) + + + ####################################################################################### + session_ids = all_sess0['session_id'].unique() + print(f'\n {session_ids.shape[0]} sessions found!') + + input_vars = pd.read_hdf(allSessName[ia], key='input_vars') + time_win = input_vars.iloc[0]['time_win'] + print(f'\n{time_win}: time window that was used for response quantification.\n') + + + + #%% Fix nan values of mouse_ids/date/stage/cre (some invalid experiments of a session have nan for mouse_id; this will cause problem later; here we replace them by the mouse_id of a valid experiment of that same session) + + for sess in session_ids: # sess = session_ids[0] + this_sess = all_sess0['session_id']==sess + + mouse_id = all_sess0[this_sess]['mouse_id'].values + nans = np.array([type(m)==float for m in mouse_id]) # nans are float + v = np.argwhere(nans==False).flatten() # valid experiments + + date = all_sess0[this_sess]['date'].values + stage = all_sess0[this_sess]['stage'].values + cre = all_sess0[this_sess]['cre'].values + exp_level = all_sess0[this_sess]['experience_level'].values + + if len(v)>0: + v = v[0] # take the mouse_id, date and stage from the 1st valid experiment. + all_sess0.loc[this_sess, 'mouse_id'] = mouse_id[v] + all_sess0.loc[this_sess, 'date'] = date[v] + all_sess0.loc[this_sess, 'stage'] = stage[v] + all_sess0.loc[this_sess, 'cre'] = cre[v] + all_sess0.loc[this_sess, 'experience_level'] = exp_level[v] + + else: + print(f'Session {sess}: all experiments are invalid') + + +# all_sess0[['cre', 'stage']].groupby(['stage', 'cre']).count() + all_sess0[['cre', 'stage', 'experience_level', 'mouse_id', 'session_id', 'experiment_id']].groupby(['experience_level', 'cre']).count() + + + ################################################################### + #%% Set time trace (timestamps for the decoding trace) + ################################################################### + + frame_dur = all_sess0['frame_dur'].mode().values[0] + print(f'frame duration: {frame_dur}') + + if type(time_win)==str: + time_win = (frames_svm*frame_dur)[[0,-1]] + + # set the entire time_trace for the flash-aligned traces, on which we applied frames_svm to get svm results. + samps_bef_time = (samps_bef+1) * frame_dur # 1 is added bc below we do np.arange(0,-samps_bef), so we get upto one value below samps_bef + samps_aft_time = samps_aft * frame_dur # frames_after_omission in svm_main # we trained the classifier until 30 frames after omission + time_trace0 = np.unique(np.concatenate((np.arange(0, -samps_bef_time, -frame_dur)[0:samps_bef+1], np.arange(0, samps_aft_time, frame_dur)[0:samps_aft]))) + + # set trace_time corresponding to svm traces + rt = np.arange(samps_bef+frames_svm[0] , min(len(time_trace0), samps_bef+frames_svm[-1]+1)) +# rt = samps_bef+frames_svm + time_trace = time_trace0[rt] + + + + ################################################################### + #%% Set the stage and experience level for each session in all_sess + + session_stage_df = pd.DataFrame([], columns=['session_id', 'stage', 'experience_level']) + stages_all_sess = [] + explevel_all_sess = [] + for isess in range(len(session_ids)): # sess = session_ids[0] + sess = session_ids[isess] + stages = all_sess0[all_sess0['session_id']==sess]['stage'].values + explev = all_sess0[all_sess0['session_id']==sess]['experience_level'].values + + ts = [type(sg) for sg in stages] + su = stages[np.in1d(ts, str)] # take the non-nan experiments for the stage value + eu = explev[np.in1d(ts, str)] + if len(su)>0: # not all experiments are nan. + sun = su[0] + eun = eu[0] + else: + sun = '' + eun = '' + + session_stage_df.at[isess,:] = [sess, sun, eun] + stages_all_sess.append(sun) + explevel_all_sess.append(eun) + + stages_all_sess = np.array(stages_all_sess) + explevel_all_sess = np.array(explevel_all_sess) + + session_stage_df.groupby(['stage']).count() + session_stage_df.groupby(['experience_level']).count() + + + + #%% Number of invalid sessions + + a = sum(stages_all_sess=='') + print(f"{a} sessions ({a*8} experiments, if mesoscope) have all experiments as NaN! These need further evaluation for why their svm files dont exist!") + + + + #%% Number of invalid experiments + + ea = [all_sess0['av_test_data'].values[i][0] for i in range(len(all_sess0))] # the 1st element of av_test_data for each experiment; if nan, then invalid experiment. + en_ids = all_sess0['experiment_id'][np.isnan(ea)] # experiment id of invalid experiments +# valid_exps = ~np.isnan(ea) + + print(f"{sum(np.isnan(ea))} / {len(all_sess0)} experiments are NaN!\nTheir experiment ids:\n{en_ids}") + + if use_events: + ea_evs = copy.deepcopy(ea) + else: + ea_dff = copy.deepcopy(ea) + + + if use_same_experiments_dff_events: + if ('ea_evs' in locals() and 'ea_dff' in locals())==False: + sys.exit('Set both ea_evs and ea_dff before proceeding!') + + + + ############################################################################## + ############################################################################## + # Run this part after both ea_evs and ea_dff are set. + + all_sess00 = copy.deepcopy(all_sess0) + + #%% Use the same set of experiments for both events and dff analysis + + if use_same_experiments_dff_events: + + ea_ids = all_sess00['experiment_id'].values + + #### set valid exps in both dff and events analyses + # valid exps in dff + valid_exps_dff = ~np.isnan(ea_dff) + # valid exps in events + valid_exps_evs = ~np.isnan(ea_evs) + # get the common valid exps + valid_exps_dff_evs = np.logical_and(valid_exps_dff, valid_exps_evs) + # get the common valid exps ids + ea_ids_valid_common = ea_ids[valid_exps_dff_evs] + + + #%% Add a valid column to all_sess00, and only set those rows to valid that are valid in both dff and events analysis + + all_sess00['valid'] = False + + all_sess00.loc[valid_exps_dff_evs, 'valid'] = True + # all_sess00.loc[valid_exps, 'valid'] = True + # all_sess00.loc[valid_exps_dff, 'valid'] = True + # all_sess00.loc[valid_exps_evs, 'valid'] = True + + + + #%% Set svm class accuracy vars to nan for all invalid experiments; then run it on both events and dff ; and comapre the figures; also add stuff to the code to take care of common exp finding. + + c = ['av_train_data', 'av_test_data', 'av_test_shfl', + 'av_test_chance', 'sd_train_data', 'sd_test_data', 'sd_test_shfl', + 'sd_test_chance'] + + a = all_sess00[all_sess00['valid']==False][c] + for i in range(len(a)): + a.iloc[i] = [np.full((len(frames_svm)), np.nan)] + + + #%% IMPORTANT: resetting the value of all_sess0 + + all_sess0.loc[all_sess00['valid']==False, c] = a + + + ### the new number of invalid experiments + ea = [all_sess0['av_test_data'].values[i][0] for i in range(len(all_sess0))] # the 1st element of av_test_data for each experiment; if nan, then invalid experiment. + en_ids = all_sess0['experiment_id'][np.isnan(ea)] # experiment id of invalid experiments + # valid_exps = ~np.isnan(ea) + + print(f"{sum(np.isnan(ea))} / {len(all_sess0)} experiments are NaN!\nTheir experiment ids:\n{en_ids}") + + + + ############################################################################## + #%% Set the exposure_number (or better to call "retake_number") for each experiment + # this part is all commented and moved to the end of this page; grab it if you ever need it! + ############################################################################## + + + ############################################################################## + #%% Correlate classification accuracy with behavioral strategy + + if trial_type =='changes_vs_nochanges' or trial_type =='hits_vs_misses' or trial_type == 'baseline_vs_nobaseline': + + exec(open('svm_images_plots_corr_beh_strategy.py').read()) + + ############################################################################## + + + + + + + + ############################################################################################################################################################ + ############################################################################################################################################################ + ############################################################################################################################################################ + # Now get those experiments that belong to a given ophys stage, and make plots for them. + ############################################################################################################################################################ + ############################################################################################################################################################ + ############################################################################################################################################################ + #%% + for session_numbers in [[1],[2],[3],[4],[5],[6]]: # 1 to 6 # ophys session stage corresponding to project_codes that we will make plots for. +# session_numbers = [1] + + #%% If analyzing novel sessions, only take sessions that include the 1st presentation of the novel session (ie the ones without a retake of session ophys-3) +# if np.in1d(4, session_numbers): # novel sessions +# exposure_number_2an = 0 # # only take those rows of all_sess that are the 1st exposure of the mouse to the novel session +# else: +# exposure_number_2an = np.nan + + ''' + ###### NOTE: here we redefine all_sess ###### + #%% If analyzing novel sessions, remove the 2nd retakes; only analyze the 1st exposures. + if exposure_number_2an is not np.nan: # if novel session: + print(all_sess0.shape) + ### BELOW does not work! because we get exposure_number from experiment_table, but somehow some of the experiments in all_sess are missing from exp_table; so we need to make exposure_number the same size as all_sess and perhaps using some large value for the missing experiments so they will get filtered out below. Or, we can set to nan the extra rows in all_sess which are missing from exp_table (note we cannot remove them because we want to keep the 8 experiments of each session!). + all_sess = all_sess0[exposure_number==exposure_number_2an] + print(f'Only analyzing the 1st exposure to the novel session: {len(all_sess)} sessions!') + else: + all_sess = copy.deepcopy(all_sess0) + print(f'Not analyzing novel session 1, so including all sessions with any exposure_number!') + print(all_sess.shape) + ''' + +# print(f'\nFor now including all sessions with any exposure_number!\n') +# all_sess = copy.deepcopy(all_sess0) + + + ############################################################################## + ############################################################################## + #%% Get those session ids (those rows of all_sess) that belong to a given stage (eg. ophys 1, identified by session_numbers) + ############################################################################## + ############################################################################## + + l = stages_all_sess + stage_inds_all = [] + + for ise in range(len(session_numbers)): # ise=0 + + print(f'\n\n') + s = session_numbers[ise] + name = f'OPHYS_{s}_.' + + # return index of the rows in all_sess that belong to a given stage + regex = re.compile(name) + stage_inds = [i for i in range(len(l)) if type(re.match(regex, l[i]))!=type(None)] + print(f'{len(stage_inds)} sessions are in stage {name}') + + stage_inds_all.append(stage_inds) + + if len(stage_inds)==0: + print(f'\tskipping this stage') # no sessions in {name} + + else: + stage_inds_all = np.concatenate((stage_inds_all)) + # print(f'Total of {len(stage_inds_all)} sessions in stage {name}') + + session_ids_this_stage = session_ids[stage_inds_all] + + # find stage values that are nan and change them to '' + # l = all_sess['stage'].values + # nans = np.array([type(ll)==float for ll in l]) + # l[nans] = '' + + + #%% Set all_sess only for a given stage + + # print(all_sess0.shape) + # a = np.logical_and(all_sess0['valid'], np.in1d(all_sess0['session_id'], session_ids_this_stage)) + a = np.in1d(all_sess0['session_id'], session_ids_this_stage) + + all_sess = all_sess0[a] + + print(f'Final size of all_sess: {all_sess.shape}') + print(f"Existing cre lines: {all_sess['cre'].unique()}") + + + #%% Define all_sess_2an, ie the final all_sess to be analyzed + + all_sess_2an = all_sess + + + + + + #%% Take care of sessions with unusual frame duration!!! + # make sure below works! + ''' + frame_durs = all_sess['frame_dur'].values + rmv = np.logical_or(frame_durs < .089, frame_durs > .1) + if sum(rmv)>0: + print('take a look at these sessions, and add them to set_sessions_valid, line 178 to be excluded.') + sys.exit(f'\n\nRemoving {sum(rmv)} sessions with unexpected frame duration!!\n\n') + all_sess = all_sess[~rmv] + + #%% + print(np.shape(all_sess)) + all_sess.iloc[:2] + ''' + + ## Load input_vars + ''' + f = allSessName[0] # take input_vars from the 1st cre lines + input_vars = pd.read_hdf(f, key='input_vars') ## Load input_vars dataframe + + samps_bef = input_vars['samps_bef'].iloc[0] + samps_aft = input_vars['samps_aft'].iloc[0] + same_num_neuron_all_planes = input_vars['same_num_neuron_all_planes'].iloc[0] + time_win = input_vars['time_win'].iloc[0] + # bl_percentile = input_vars['bl_percentile'].iloc[0] + ''' + + + + ###################################################################################################### + #%% Set a number of useful variables + ###################################################################################################### + + #%% + # below moved up + ''' + frame_dur = all_sess['frame_dur'].mode().values[0] + print(f'frame duration: {frame_dur}') + + if type(time_win)==str: + time_win = (frames_svm*frame_dur)[[0,-1]] + + # set the entire time_trace for the flash-aligned traces, on which we applied frames_svm to get svm results. + samps_bef_time = (samps_bef+1) * frame_dur # 1 is added bc below we do np.arange(0,-samps_bef), so we get upto one value below samps_bef + samps_aft_time = samps_aft * frame_dur # frames_after_omission in svm_main # we trained the classifier until 30 frames after omission + time_trace0 = np.unique(np.concatenate((np.arange(0, -samps_bef_time, -frame_dur)[0:samps_bef+1], np.arange(0, samps_aft_time, frame_dur)[0:samps_aft]))) + + # set trace_time corresponding to svm traces + rt = np.arange(samps_bef+frames_svm[0] , min(len(time_trace0), samps_bef+frames_svm[-1]+1)) +# rt = samps_bef+frames_svm + time_trace = time_trace0[rt] + ''' + + xlim = [time_trace[0], time_trace[-1]] #[-1.2, 2.25] # [-13, 24] + + + # set x tick marks + xmj = np.round(np.unique(np.concatenate((np.arange(0, time_trace[0], -.1), np.arange(0, time_trace[-1], .1)))), 2) + xmn = [] #np.arange(-.5, time_trace[-1], 1) + xmjn = [xmj, xmn] + + + # set the time of flashes and grays for the imaging traces ### note: you should remove 0 from flashes_win_trace_index_unq_time, because at time 0, there is no flash, there is omission!! + flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, flashes_win_trace_index_unq, grays_win_trace_index_unq = \ + flash_gray_onset_relOmit(samps_bef, samps_aft, frame_dur) + + + #%% + all_mice_id = np.sort(all_sess['mouse_id'].unique()) + # remove nans: this should be for sessions whose all experiments are invalid + all_mice_id = all_mice_id[[~np.isnan(all_mice_id[i]) for i in range(len(all_mice_id))]] + + print(f'There are {len(all_mice_id)} mice in this stage.') + + ''' + mouse_trainHist_all = pd.DataFrame([], columns=['mouse_id', 'date', 'session_id', 'stage']) # total number of sessions x 3 + for cnt, i in enumerate(all_mice_id): + m = all_sess[all_sess.mouse_id==i].mouse_id.values + s = all_sess[all_sess.mouse_id==i].stage.values + d = all_sess[all_sess.mouse_id==i].date.values + ss = all_sess[all_sess.mouse_id==i].session_id.values + + # take data from the 1st experiment of each session (because date and stage are common across all experiments of each session) + mouse_trainHist = pd.DataFrame([], columns=['mouse_id', 'date', 'session_id', 'stage']) + for ii in np.arange(0,len(m),8): + mouse_trainHist.at[ii, ['mouse_id', 'date', 'session_id', 'stage']] = m[ii] , d[ii] , ss[ii] , s[ii] # m.iloc[np.arange(0,len(m),8)].values , d.iloc[np.arange(0,len(d),8)].values , s.iloc[np.arange(0,len(s),8)].values + + mouse_trainHist_all = mouse_trainHist_all.append(mouse_trainHist) + + print(mouse_trainHist_all) + ''' + + + #%% Set plane indices for each area (V1 and LM) + # I think you can just move this section all the way up, outside the loop. + + distinct_areas, i_areas = np.unique(all_sess[all_sess['mouse_id']==all_mice_id[0]]['area'].values, return_inverse=True) # take this info from any mouse ... it doesn't matter... we go with mouse 0 + i_areas = i_areas[range(num_planes)] + # distinct_areas = np.array(['VISl', 'VISp']) + # i_areas = np.array([0, 0, 0, 0, 1, 1, 1, 1]) + + if len(distinct_areas)>1: # project_codes == ['VisualBehaviorMultiscope'] or + # v1 : shown as VISp + v1_ai = np.argwhere([distinct_areas[i].find('p')!=-1 for i in range(len(distinct_areas))]).squeeze() + # LM : shown as VISl or LM + lm_ai = np.argwhere([(distinct_areas[i].find('l')!=-1 or distinct_areas[i].find('L')!=-1) for i in range(len(distinct_areas))]).squeeze() + + inds_v1 = np.argwhere(i_areas==v1_ai).squeeze() + inds_lm = np.argwhere(i_areas==lm_ai).squeeze() + + else: # scientifica when there is only 1 area + if distinct_areas[0] == 'VISp': + inds_v1 = [0] + inds_lm = [np.nan] + areas_title = ['VISp'] + + elif distinct_areas[0] == 'VISl': + inds_lm = [0] + inds_v1 = [np.nan] + areas_title = ['VISl'] + +# print('V1 plane indeces: ', inds_v1) # [4, 5, 6, 7] +# print('LM plane indeces: ', inds_lm) # [0, 1, 2, 3] + #inds_lm = np.arange(num_depth) # we can get these from the following vars: distinct_areas and i_areas[range(num_planes)] + #inds_v1 = np.arange(num_depth, num_planes) + + + + ############################################################################################## + ############################################################################################## + ############################################################################################## + ############################################################################################## + + + #%% Set svm vars for each plane across all sessions (for each mouse) + ''' + columns0 = ['mouse_id', 'cre', 'mouse_id_exp', 'cre_exp', 'block', 'session_stages', 'session_labs', 'num_sessions_valid', 'area_this_plane_allsess_allp', 'depth_this_plane_allsess_allp', \ + 'area', 'depth', 'plane', \ + 'n_neurons_this_plane_allsess_allp', 'n_trials_this_plane_allsess_allp', \ + 'av_meanX_avSess_eachP', 'sd_meanX_avSess_eachP', \ + 'av_test_data_this_plane_allsess_allp', 'av_test_shfl_this_plane_allsess_allp', \ + 'av_test_data_avSess_eachP', 'sd_test_data_avSess_eachP', 'av_test_shfl_avSess_eachP', 'sd_test_shfl_avSess_eachP', \ + 'av_train_data_avSess_eachP', 'sd_train_data_avSess_eachP', \ + 'av_n_neurons_avSess_eachP', 'sd_n_neurons_avSess_eachP', 'av_n_trials_avSess_eachP', 'sd_n_trials_avSess_eachP', \ + 'av_test_data_pooled_sesss_planes_eachArea', 'av_test_shfl_pooled_sesss_planes_eachArea', 'meanX_pooled_sesss_planes_eachArea', \ + 'num_sessions_valid_eachArea', 'distinct_areas', 'cre_pooled_sesss_planes_eachArea', \ + 'av_test_data_pooled_sesss_areas_eachDepth', 'av_test_shfl_pooled_sesss_areas_eachDepth', 'meanX_pooled_sesss_areas_eachDepth', \ + 'cre_pooled_sesss_areas_eachDepth', 'depth_pooled_sesss_areas_eachDepth', \ + 'peak_amp_trTsShCh_this_plane_allsess_allp', \ + 'av_peak_amp_trTsShCh_avSess_eachP', 'sd_peak_amp_trTsShCh_avSess_eachP', \ + 'peak_amp_trTsShCh_pooled_sesss_planes_eachArea', \ + 'peak_amp_trTsShCh_pooled_sesss_areas_eachDepth', \ + ] + + if same_num_neuron_all_planes: + columns = np.concatenate((columns0, ['n_neurons_svm_trained_this_plane_allsess_allp', 'av_n_neurons_svm_trained_avSess_eachP', 'sd_n_neurons_svm_trained_avSess_eachP'])) + else: + columns = columns0 + + svm_this_plane_allsess = pd.DataFrame([], columns=columns) + ''' + + # for a given stage, if there are sessions in all_sess, now loop over mice based on the order in all_mice_id + # Note: if you want to use all sessions (not just those in all_sess_2n), replace all_sess_2n with all_sess below, also uncomment the currerntly commented out defintion of session_stages + + ### in svm_this_plane_allsess, each row is for one stage, includes data from all sessions that belong to that stage, also from all planes; in the following format: 1st session of that given stage: all planes; then 2nd session of that given stage: all planes; and so on. + + for im in range(len(all_mice_id)): # im=0 + + cntall = cntall+1 + mouse_id = all_mice_id[im] + + if sum((all_sess_2an['mouse_id']==mouse_id).values) <= 0: + print(f'mouse {im} doesnt have data!') + + else: #sum((all_sess_2an['mouse_id']==mouse_id).values) > 0: # make sure there is data for this mouse, for the specific session: A, B, etc that you care about + print(f'\nanalyzing mouse {mouse_id}') + # svm_this_plane_allsess.at[cntall, 'block'] = iblock + + + ################################################ + + all_sess_2an_this_mouse = all_sess_2an[all_sess_2an['mouse_id']==mouse_id] +# cre = all_sess_2an_this_mouse['cre'].iloc[0] + + cre = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['cre'].iloc[0] + cre = cre[:cre.find('-')] # remove the IRES-Cre part + + session_ids_now = all_sess_2an_this_mouse['session_id'].values + + session_stages = all_sess_2an_this_mouse['stage'].values[np.arange(0, all_sess_2an_this_mouse.shape[0], num_planes)] + # session_stages = mouse_trainHist_all[mouse_trainHist_all['mouse_id']==mouse_id]['stage'].values + num_sessions = len(session_stages) # some planes for some sessions could be nan (because they had fewer neurons than 3 (svm_min_neurs)), so below we will get the accurate number of sessions for each plane separately + # print(cre, num_sessions) + + experience_levels = all_sess_2an_this_mouse['experience_level'].values[np.arange(0, all_sess_2an_this_mouse.shape[0], num_planes)] + + ######## Set session labels (stage names are too long) + # session_beg_inds = np.concatenate(([0], np.cumsum(num_trs_each_sess[:-1])+1)) + session_labs = [] + for ibeg in range(num_sessions): + a = str(session_stages[ibeg]) + us = np.argwhere([a[ich]=='_' for ich in range(len(a))]).flatten() # index of underscores + en = us[-1].squeeze() + 6 + txt = str(session_stages[ibeg][15:]) # session_stages[ibeg][8:en] + txt = txt[0:min(3, len(txt))] + + sn = a[us[0]+1: us[1]+1] # stage number + txt = sn + txt + session_labs.append(txt) + + + #### replicate cre to the number of sessions #### + cre_exp = np.full((num_planes*num_sessions), cre) + mouse_id_exp = np.full((num_planes*num_sessions), mouse_id) + + areas = all_sess_2an_this_mouse['area'] # pooled: (8*num_sessions) + depths = all_sess_2an_this_mouse['depth'] # pooled: (8*num_sessions) + planes = all_sess_2an_this_mouse.index.values # pooled: (8*num_sessions) + + + ######### Get data from a given plane across all sessions ######### + # remember y is a pandas series; do y.values + + # area + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['area']#.values # num_sess + np.shape(y.values) + area_this_plane_allsess_allp = set_y_this_plane_allsess(y, num_sessions) # size: (8 x num_sessions x 1) # 8 is number of planes; nFrames_upsampled is the length of the upsampled time array # Get data from a given plane across all sessions + + # depth + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['depth']#.values # num_sess + depth_this_plane_allsess_allp = set_y_this_plane_allsess(y, num_sessions) # size: (8 x num_sessions x 1) # 8 is number of planes; nFrames_upsampled is the length of the upsampled time array # Get data from a given plane across all sessions + + # num_neurons + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['n_neurons']#.values + n_neurons_this_plane_allsess_allp = set_y_this_plane_allsess(y, num_sessions) # size: (8 x num_sessions x 1) + # print(n_neurons_this_plane_allsess_allp) + + # population size used for svm training + if same_num_neuron_all_planes: + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['population_sizes_to_try']#.values # 8 * number_of_session_for_the_mouse + n_neurons_svm_trained_this_plane_allsess_allp = set_y_this_plane_allsess(y, num_sessions) # size: (8 x num_sessions x nFrames_upsampled) + # print(n_neurons_svm_trained_this_plane_allsess_allp) + + # num_trials + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['n_trials']#.values + n_trials_this_plane_allsess_allp = set_y_this_plane_allsess(y, num_sessions) # size: (8 x num_sessions x 1) + + + # peak_amp_trainTestShflChance + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['peak_amp_trainTestShflChance'] # 8 * number_of_session_for_the_mouse + peak_amp_trTsShCh_this_plane_allsess_allp = set_y_this_plane_allsess(y, num_sessions) # size: (8 x num_sessions x 4) # 4 for train, Test, Shfl, and Chance + + # baseline + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['bl_pre0'] # 8 * number_of_session_for_the_mouse + bl_pre0_this_plane_allsess_allp = set_y_this_plane_allsess(y, num_sessions) # size: (8 x num_sessions x 4) # 4 for train, Test, Shfl, and Chance + + if baseline_subtract: # subtract the baseline (CA average during baseline, ie before time 0) from the evoked CA (classification accuracy) + peak_amp_trTsShCh_this_plane_allsess_allp = peak_amp_trTsShCh_this_plane_allsess_allp - bl_pre0_this_plane_allsess_allp + if im==0: + print(f'Subtracting out baseline to quantify class accuracy.') + + + # av_test_data + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['av_test_data']#.values # 8 * number_of_session_for_the_mouse; each experiment: nFrames_interpolated + av_test_data_this_plane_allsess_allp = set_y_this_plane_allsess(y, num_sessions) # size: (8 x num_sessions x nFrames_upsampled) # 8 is number of planes; nFrames_upsampled is the length of the upsampled time array # Get data from a given plane across all sessions + # print(im, av_test_data_this_plane_allsess_allp.shape) + + # av_test_shfl + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['av_test_shfl']#.values # 8 * number_of_session_for_the_mouse; each experiment: nFrames_interpolated + av_test_shfl_this_plane_allsess_allp = set_y_this_plane_allsess(y, num_sessions) # size: (8 x num_sessions x nFrames_upsampled) + + # av_train_data + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['av_train_data']#.values # 8 * number_of_session_for_the_mouse; each experiment: nFrames_interpolated + av_train_data_this_plane_allsess_allp = set_y_this_plane_allsess(y, num_sessions) # size: (8 x num_sessions x nFrames_upsampled) # 8 is number of planes; nFrames_upsampled is the length of the upsampled time array # Get data from a given plane across all sessions + # print(im, av_test_data_this_plane_allsess_allp.shape) + + # meanX + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['meanX_allFrs']#.values # 8 * number_of_session_for_the_mouse; each experiment: nFrames_interpolated x n_neurons + # remember, below also takes average across neurons + meanX_this_plane_allsess_allp = set_y_this_plane_allsess(y, num_sessions, takeAve=1) # size: (8 x num_sessions x nFrames_upsampled) # 8 is number of planes; nFrames_upsampled is the length of the upsampled time array # Get data from a given plane across all sessions + + + # some planes for some sessions could be nan (because they had fewer neurons than 3 (svm_min_neurs)), so lets get the accurate number of sessions for each plane separately + num_sessions_valid = np.sum(~np.isnan(n_neurons_this_plane_allsess_allp), axis=1).squeeze() # 8 (shows for each plane the number of non nan sessions) + + + + ############################################################ + ######### For each plane, average vars across days ######### + ############################################################ + # note: vars below are also set in svm_plots_setVars_sumMice.py. I didn't take them out of here, bc below will be used for making eachMouse plots. Codes in svm_plots_setVars_sumMice.py are compatible with omissions code, and will be used for making sumMice plots. + + # depth + a = depth_this_plane_allsess_allp # size: (8 x num_sessions x 1) + av_depth_avSess_eachP = np.nanmean(a,axis=1).squeeze() # num_planes + sd_depth_avSess_eachP = np.nanstd(a,axis=1).squeeze() / np.sqrt(num_sessions_valid) # num_planes # st error across sessions, for each plane + + # num_neurons + a = n_neurons_this_plane_allsess_allp # size: (8 x num_sessions x 1) + av_n_neurons_avSess_eachP = np.nanmean(a,axis=1).squeeze() # num_planes + sd_n_neurons_avSess_eachP = np.nanstd(a,axis=1).squeeze() / np.sqrt(num_sessions_valid) # num_planes # st error across sessions, for each plane + + # population size used for svm training + if same_num_neuron_all_planes: + a = n_neurons_svm_trained_this_plane_allsess_allp # size: (8 x num_sessions x 1) + av_n_neurons_svm_trained_avSess_eachP = np.nanmean(a,axis=1).squeeze() # num_planes + sd_n_neurons_svm_trained_avSess_eachP = np.nanstd(a,axis=1).squeeze() / np.sqrt(num_sessions_valid) # num_planes # st error across sessions, for each plane + + # num_trials + a = n_trials_this_plane_allsess_allp # size: (8 x num_sessions x 1) + av_n_trials_avSess_eachP = np.nanmean(a,axis=1).squeeze() # num_planes + sd_n_trials_avSess_eachP = np.nanstd(a,axis=1).squeeze() / np.sqrt(num_sessions_valid) # num_planes # st error across sessions, for each plane + + + if project_codes != ['VisualBehaviorMultiscope']: + sqnv = np.sqrt(num_sessions_valid) + else: + sqnv = np.sqrt(num_sessions_valid)[:, np.newaxis] + + # av_test_data + a = av_test_data_this_plane_allsess_allp # size: (8 x num_sessions x nFrames_upsampled) + av_test_data_avSess_eachP = np.nanmean(a,axis=1) # num_planes x nFrames_upsampled (interpolated times) + sd_test_data_avSess_eachP = np.nanstd(a,axis=1) / sqnv # num_planes x nFrames_upsampled # st error across sessions, for each plane + + # av_test_shfl + a = av_test_shfl_this_plane_allsess_allp # size: (8 x num_sessions x nFrames_upsampled) + av_test_shfl_avSess_eachP = np.nanmean(a,axis=1) # num_planes x nFrames_upsampled (interpolated times) + sd_test_shfl_avSess_eachP = np.nanstd(a,axis=1) / sqnv # num_planes x nFrames_upsampled # st error across sessions, for each plane + + # av_train_data + a = av_train_data_this_plane_allsess_allp # size: (8 x num_sessions x nFrames_upsampled) + av_train_data_avSess_eachP = np.nanmean(a,axis=1) # num_planes x nFrames_upsampled (interpolated times) + sd_train_data_avSess_eachP = np.nanstd(a,axis=1) / sqnv # num_planes x nFrames_upsampled # st error across sessions, for each plane + + # meanX_allFrs + a = meanX_this_plane_allsess_allp # size: (8 x num_sessions x nFrames_upsampled) + av_meanX_avSess_eachP = np.nanmean(a,axis=1) # num_planes x nFrames_upsampled (interpolated times) + sd_meanX_avSess_eachP = np.nanstd(a,axis=1) / sqnv # num_planes x nFrames_upsampled # st error across sessions, for each plane + + # peak_amp_trTsShCh + a = peak_amp_trTsShCh_this_plane_allsess_allp # size: (8 x num_sessions x 4) + av_peak_amp_trTsShCh_avSess_eachP = np.nanmean(a,axis=1).squeeze() # num_planes x 4 + sd_peak_amp_trTsShCh_avSess_eachP = np.nanstd(a,axis=1).squeeze() / sqnv # num_planes x 4 # st error across sessions, for each plane + + + ####################################################################### + ######### For each area, pool data across sessions and depths ######### + ####################################################################### + # 2 x (4 x num_sessions) + + if project_codes == ['VisualBehaviorMultiscope']: + + ''' + # Note: use the codes below if you want to use the same codes as in "omissions_traces_peaks_plots_setVars_ave.py" + + area = all_sess_2an_this_mouse['area'].values + + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['peak_amp_trainTestShflChance']#.values # 8 * number_of_session_for_the_mouse; each experiment: nFrames_interpolated; + t = np.vstack(y) # (8*num_sessions) x num_frames # this is similar to the following var in the omissions code: t = trace_peak_allMice.iloc[im]['trace'] # (8*num_sessions) x time + + trace_pooled_sesss_planes_eachArea, distinct_areas, i_areas = pool_sesss_planes_eachArea(area, t) + + # sanity check that above is the same as what we set below + # np.sum(~np.equal(trace_pooled_sesss_planes_eachArea, peak_amp_trTsShCh_pooled_sesss_planes_eachArea)) + ''' + # NOTE: the reshape below (using order='F') moves in the following order: + # it first orders data from the 1st area in the following order + # data from all 4 depths for session 1, area 1 + # data from all 4 depths for session 2, area 1 + # data from all 4 depths for session 3, area 1 .... (then the same thing repeats for the 2nd area) + # + # data from all 4 depths for session 1, area 2 + # data from all 4 depths for session 2, area 2 + # data from all 4 depths for session 3, area 2 + + # you used to not use order='F' in the reshape below, so it was 1st all sessions for one depth, then all sessions for the other depth, etc + # but on Apr 13 2020 you added order='F' to make it consistent with omissions plots, which uses function pool_sesss_planes_eachArea. + + a = area_this_plane_allsess_allp # 8 x num_sessions x 1 + a = np.reshape(a, (a.shape[0] * a.shape[1], a.shape[2]), order='F') # (8 x num_sessions) x 1 # do this to make sure things are exactly the same as how you do for the arrays below (reshape is confusing in python!!) + distinct_areas, i_areas = np.unique(a, return_inverse=True) + # print(distinct_areas) + if len(distinct_areas) > 2: + sys.exit('There cannot be more than two areas!! Fix the area names!') + + + area = all_sess_2an_this_mouse['area'].values + + t = cre_exp # (8*num_sessions) + cre_pooled_sesss_planes_eachArea,_,_ = pool_sesss_planes_eachArea(area, t) # 2 x (4 x num_sessions) + + # av_test_data, each area + a = av_test_data_this_plane_allsess_allp # 8 x num_sessions x nFrames_upsampled + av_test_data_pooled_sesss_planes = np.reshape(a, (a.shape[0] * a.shape[1], a.shape[2]), order='F') # size: (8 x num_sessions) x nFrames_upsampled + # below has size: num_areas x (num_layers_per_area x num_sessions) x nFrames_upsampled + # so, 2 x (4 x num_sessions) x nFrames_upsampled + av_test_data_pooled_sesss_planes_eachArea = np.array([av_test_data_pooled_sesss_planes[i_areas == ida] for ida in range(len(distinct_areas))]) # 2 x (8/2 x num_sessions) x nFrames_upsampled + + # av_test_shfl + a = av_test_shfl_this_plane_allsess_allp + av_test_shfl_pooled_sesss_planes = np.reshape(a, (a.shape[0] * a.shape[1], a.shape[2]), order='F') # size: (8 x num_sessions) x nFrames_upsampled + # below has size: num_areas x (num_layers_per_area x num_sessions) x nFrames_upsampled + # so, 2 x (4 x num_sessions) x nFrames_upsampled + av_test_shfl_pooled_sesss_planes_eachArea = np.array([av_test_shfl_pooled_sesss_planes[i_areas == ida] for ida in range(len(distinct_areas))]) # 2 x (8/2 x num_sessions) x nFrames_upsampled + + # meanX_allFrs + a = meanX_this_plane_allsess_allp + meanX_pooled_sesss_planes = np.reshape(a, (a.shape[0] * a.shape[1], a.shape[2]), order='F') # size: (8 x num_sessions) x nFrames_upsampled + # below has size: num_areas x (num_layers_per_area x num_sessions) x nFrames_upsampled + # so, 2 x (4 x num_sessions) x nFrames_upsampled + meanX_pooled_sesss_planes_eachArea = np.array([meanX_pooled_sesss_planes[i_areas == ida] for ida in range(len(distinct_areas))]) # 2 x (8/2 x num_sessions) x nFrames_upsampled + + # peak_amp_trTsShCh + a = peak_amp_trTsShCh_this_plane_allsess_allp # 8 x num_sessions x 4 + peak_amp_trTsShCh_pooled_sesss_planes = np.reshape(a, (a.shape[0] * a.shape[1], a.shape[2]), order='F') # size: (8 x num_sessions) x 4 + # below has size: num_areas x (num_layers_per_area x num_sessions) x 4 + # so, 2 x (4 x num_sessions) x 4 + peak_amp_trTsShCh_pooled_sesss_planes_eachArea = np.array([peak_amp_trTsShCh_pooled_sesss_planes[i_areas == ida] for ida in range(len(distinct_areas))]) # 2 x (8/2 x num_sessions) x 4 + + # num_sessions_valid_eachArea + # note: we are redefining "i_areas" below. + a = area_this_plane_allsess_allp[:,0,0] # 8 + distinct_areas, i_areas = np.unique(a, return_inverse=True) + num_sessions_valid_eachArea = np.array([num_sessions_valid[i_areas == ida] for ida in range(len(distinct_areas))]) # 2 x 4 # area x depth_per_area + + + ############################################################################### + ######### For each layer (depth), pool data across sessions and areas ######### + ############################################################################### + + ### Note: "xxx_pooled_sesss_areas_eachDepth" vars below have size: # 4depths x (2areas x num_sess) + # (2areas x num_sess) are pooled in this way: + # first all areas of session 1, then all areas of session 2, etc + + # the first 4 depths are for one area and the 2nd four depths are for the other area, but lets code it, just in case: + # depth1_area2 = 4 # index of the 1st depth of the 2nd area + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['area'].values + distinct_areas, i_areas = np.unique(y, return_inverse=True) + depth1_area2 = np.argwhere(i_areas).squeeze()[0] # 4 # index of the 1st depth of the 2nd area + if depth1_area2!=4: + sys.exit('Because the 8 planes are in the following order: area 1 (4 planes), then area 2 (another 4 planes), we expect depth1_area2 to be 4! What is wrong?!') + + + planes_allsess = planes # (8*num_sessions) + depth = depths.values + + t = cre_exp # (8*num_sessions) + cre_pooled_sesss_areas_eachDepth = pool_sesss_areas_eachDepth(planes_allsess, t, depth1_area2) # 4 x (2 x num_sess) + + t = depth + depth_pooled_sesss_areas_eachDepth = pool_sesss_areas_eachDepth(planes_allsess, t, num_depth=4) # 4 x (2 x num_sessions) # each row is for a depth and shows values from the two areas of all the sessions + + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['av_test_data']#.values # 8 * number_of_session_for_the_mouse; each experiment: nFrames_interpolated + t = np.vstack(y) # (8*num_sessions) x num_frames # this is similar to the following var in the omissions code: t = trace_peak_allMice.iloc[im]['trace'] # (8*num_sessions) x time + av_test_data_pooled_sesss_areas_eachDepth = pool_sesss_areas_eachDepth(planes_allsess, t, depth1_area2) # 4 x (2 x num_sess) x nFrames_upsampled # 4 is the number of distinct depths: depth1_area2 + + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['av_test_shfl']#.values # 8 * number_of_session_for_the_mouse; each experiment: nFrames_interpolated + t = np.vstack(y) # (8*num_sessions) x num_frames # this is similar to the following var in the omissions code: t = trace_peak_allMice.iloc[im]['trace'] # (8*num_sessions) x time + av_test_shfl_pooled_sesss_areas_eachDepth = pool_sesss_areas_eachDepth(planes_allsess, t, depth1_area2) # 4 x (2 x num_sess) x nFrames_upsampled # 4 is the number of distinct depths: depth1_area2 + + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['peak_amp_trainTestShflChance']#.values # 8 * number_of_session_for_the_mouse; each experiment: nFrames_interpolated + t = np.vstack(y) # (8*num_sessions) x 4 # this is similar to the following var in the omissions code: t = trace_peak_allMice.iloc[im]['trace'] # (8*num_sessions) x time + peak_amp_trTsShCh_pooled_sesss_areas_eachDepth = pool_sesss_areas_eachDepth(planes_allsess, t, depth1_area2) # 4 x (2 x num_sess) x 4(train,test,shuffle,chance) # 4 is the number of distinct depths: depth1_area2 + + # for mouse 440631, code below gives error bc one of the sessions doesnt have valid neurons, and is just a vector of nans (1 dimensional) + # so, we go with the old method for setting meanX_pooled_sesss_areas_eachDepth + # the only difference would be that now (2areas x num_sess) are pooled in this way: + # first all sessions of one area, then all sessions of the other area are concatenated. + # but it doesnt matter bc we use meanX_pooled_sesss_areas_eachDepth only for eachMouse plots, where we average across areas and sessions (so the order of areas and sessions doesnt matter.) + ''' + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id]['meanX_allFrs']#.values # 8 * number_of_session_for_the_mouse; each experiment: nFrames_interpolated + # take average across neurons: # (8*num_sessions) x num_frames + t = np.array([np.nanmean(y.values[inn], axis=1) for inn in range(len(y.values))]) + meanX_pooled_sesss_areas_eachDepth = pool_sesss_areas_eachDepth(planes_allsess, t, depth1_area2) # 4 x (2 x num_sess) x nFrames_upsampled # 4 is the number of distinct depths: depth1_area2 + ''' + y = all_sess_2an[all_sess_2an['mouse_id']==mouse_id].index.values # (pooled: num_planes x num_sessions) + p = np.reshape(y, (num_planes, num_sessions), order='F') # num_planes x num_sessions + + # meanX + meanX_pooled_sesss_areas_eachDepth = [] + for idepth in range(depth1_area2): # idepth = 0 + # merge data with the same depth from 2 areas + b = np.logical_or(p==idepth, p==idepth + depth1_area2) + a = np.array([meanX_this_plane_allsess_allp[b]]).squeeze() # (2 x num_sess) x nFrames_upsampled + meanX_pooled_sesss_areas_eachDepth.append(a) + meanX_pooled_sesss_areas_eachDepth = np.array(meanX_pooled_sesss_areas_eachDepth) # 4 x (2 x num_sess) x nFrames_upsampled # 4 is the number of distinct depths: depth1_area2 + + + + ############################################################### + # areas.values, depth.values, plane, + svm_this_plane_allsess.at[cntall, columns0] = \ + mouse_id, cre, mouse_id_exp, cre_exp, iblock, session_ids_now, experience_levels, session_stages, session_labs, num_sessions_valid, area_this_plane_allsess_allp, depth_this_plane_allsess_allp, \ + areas.values, depths.values, planes, \ + n_neurons_this_plane_allsess_allp, n_trials_this_plane_allsess_allp, \ + av_meanX_avSess_eachP, sd_meanX_avSess_eachP, \ + av_test_data_this_plane_allsess_allp, av_test_shfl_this_plane_allsess_allp,\ + av_test_data_avSess_eachP, sd_test_data_avSess_eachP, av_test_shfl_avSess_eachP, sd_test_shfl_avSess_eachP, av_train_data_avSess_eachP, sd_train_data_avSess_eachP,\ + av_n_neurons_avSess_eachP, sd_n_neurons_avSess_eachP, av_n_trials_avSess_eachP, sd_n_trials_avSess_eachP,\ + av_test_data_pooled_sesss_planes_eachArea, av_test_shfl_pooled_sesss_planes_eachArea, meanX_pooled_sesss_planes_eachArea, \ + num_sessions_valid_eachArea, distinct_areas, cre_pooled_sesss_planes_eachArea, \ + av_test_data_pooled_sesss_areas_eachDepth, av_test_shfl_pooled_sesss_areas_eachDepth, meanX_pooled_sesss_areas_eachDepth, \ + cre_pooled_sesss_areas_eachDepth, depth_pooled_sesss_areas_eachDepth, \ + peak_amp_trTsShCh_this_plane_allsess_allp, \ + av_peak_amp_trTsShCh_avSess_eachP, sd_peak_amp_trTsShCh_avSess_eachP,\ + peak_amp_trTsShCh_pooled_sesss_planes_eachArea,\ + peak_amp_trTsShCh_pooled_sesss_areas_eachDepth + + + else: # scientifica data (visual behavior); doesnt include any area/layer pooled data + ############################################################### + # areas.values, depth.values, plane, + svm_this_plane_allsess.at[cntall, columns0] = \ + mouse_id, cre, mouse_id_exp, cre_exp, iblock, session_ids_now, experience_levels, session_stages, session_labs, num_sessions_valid, area_this_plane_allsess_allp, depth_this_plane_allsess_allp, \ + areas.values, depths.values, planes, \ + n_neurons_this_plane_allsess_allp, n_trials_this_plane_allsess_allp, \ + av_meanX_avSess_eachP, sd_meanX_avSess_eachP, \ + av_test_data_this_plane_allsess_allp, av_test_shfl_this_plane_allsess_allp,\ + av_test_data_avSess_eachP, sd_test_data_avSess_eachP, av_test_shfl_avSess_eachP, sd_test_shfl_avSess_eachP, av_train_data_avSess_eachP, sd_train_data_avSess_eachP,\ + av_n_neurons_avSess_eachP, sd_n_neurons_avSess_eachP, av_n_trials_avSess_eachP, sd_n_trials_avSess_eachP,\ + distinct_areas, \ + peak_amp_trTsShCh_this_plane_allsess_allp, \ + av_peak_amp_trTsShCh_avSess_eachP, sd_peak_amp_trTsShCh_avSess_eachP + + + + if same_num_neuron_all_planes: + svm_this_plane_allsess.at[cntall, ['n_neurons_svm_trained_this_plane_allsess_allp']] = [n_neurons_svm_trained_this_plane_allsess_allp] + svm_this_plane_allsess.at[cntall, ['av_n_neurons_svm_trained_avSess_eachP']] = [av_n_neurons_svm_trained_avSess_eachP] + svm_this_plane_allsess.at[cntall, ['sd_n_neurons_svm_trained_avSess_eachP']] = [sd_n_neurons_svm_trained_avSess_eachP] + + + # done with setting svm_this_plane_allsess for each mouse of a given ophys session and a given block (for iblock; for isession; for imouse) +# print(svm_this_plane_allsess.shape) +# print(f'\n') + + + # done with setting svm_this_plane_allsess for all mice of a given ophys session and a given block (for iblock; for isession; for imouse) + print(svm_this_plane_allsess.shape) + print(f'\n') +# svm_this_plane_allsess + + #%% + ##################################################################################### + ####################################### PLOTS ####################################### + ##################################################################################### + ''' + if np.isnan(svm_blocks): + + # Follow this script by "svm_images_plots_eachMouse" to make plots for each mouse. + if plot_single_mouse: + exec(open('svm_images_plots_eachMouse.py').read()) + + # Follow this script by "svm_images_plots_setVars_sumMice.py" to set vars for making average plots across mice (for each cre line). + exec(open('svm_images_plots_setVars_sumMice.py').read()) + exec(open('svm_images_plots_sumMice.py').read()) + + # assign the vars sessPooled and sessAvSd to var names specific to each block + # exec(svm_allMice_sessPooled_block_name + " = svm_allMice_sessPooled") + # exec(svm_allMice_sessAvSd_block_name + " = svm_allMice_sessAvSd") + + # svm_allMice_sessPooled = eval(f'svm_allMice_sessPooled_block{iblock}') + + # svm_allMice_sessPooled_block0 + # svm_allMice_sessAvSd_block0 + ''' + + + +print(svm_this_plane_allsess.shape) +svm_this_plane_allsess + + + + + + + + + +#%% Set the exposure_number (or better to call "retake_number") for each experiment +# this part is all commented and moved at the end of this page; grab it if you ever need it! +""" +experiments_table = loading.get_filtered_ophys_experiment_table(include_failed_data=True) + +estbl = experiments_table.index +es = all_sess0['experiment_id'].values + +# try: +# exposure_number = experiments_table[np.in1d(estbl, es)]['session_type_exposure_number'].values +# # print(f'exposure numbers: {np.unique(exposure_number)}') +# except Exception as E: +# print('exposure_number does not exist in experiments_table!! For now it is fine because we are not really using exposure_number') +# print(E) + + +#%% Are all experiments in all_sess also in experiment_table; this should always be the case, unless experiment_table changes later bc of some qc related thing! + +a = sum(~np.in1d(es, estbl)) +if a!=0: # print(f'All experiments in all_sess exist in experiment_table, as expected') + sys.exit(f'\n{a} experiments in all_sess do NOT exist in experiment_table; uncanny!') + + + ### make exposure_number the same size as all_sess and use some large value for the missing experiments so they will get filtered out below. + # turn exposure_number to a df so we know which element belongs to which experiment, add additional rows for the experiments in all_sess that are not in exposure_number, and set their value to a ridiculus value like 100. + + # i dont think the method below is useful, bc still we cant apply exposure_number onto all_sess ... + ''' + ### set svm outputs of all_sess experiments missing from exp_table to nan + print(f'NOTE: Turning their SVM outputs to nan!\n') + +# 'meanX_allFrs', 'stdX_allFrs', 'av_train_data', 'av_test_data', 'av_test_shfl', +# 'av_test_chance', 'sd_train_data', 'sd_test_data', 'sd_test_shfl', +# 'sd_test_chance', 'peak_amp_trainTestShflChance', 'av_w_data', 'av_b_data' + +# all_sess_missing_from_estable = all_sess0[~np.in1d(es, estbl)] +# aa = np.argwhere(~np.in1d(es, estbl)) + + all_sess0.at[~np.in1d(es, estbl), 'av_train_data'] = [np.full((all_sess0.iloc[0]['av_test_data'].shape), np.nan)] + all_sess0.at[~np.in1d(es, estbl), 'av_test_data'] = [np.full((all_sess0.iloc[0]['av_test_data'].shape), np.nan)] + all_sess0.at[~np.in1d(es, estbl), 'av_test_shfl'] = [np.full((all_sess0.iloc[0]['av_test_shfl'].shape), np.nan)] + all_sess0.at[~np.in1d(es, estbl), 'av_test_chance'] = [np.full((all_sess0.iloc[0]['av_test_shfl'].shape), np.nan)] + all_sess0.at[~np.in1d(es, estbl), 'peak_amp_trainTestShflChance'] = [np.full((all_sess0.iloc[0]['peak_amp_trainTestShflChance'].shape), np.nan)] + all_sess0.at[~np.in1d(es, estbl), 'meanX_allFrs'] = [np.full((all_sess0.iloc[0]['meanX_allFrs'].shape), np.nan)] + ''' +############################################################################## +############################################################################## +""" \ No newline at end of file diff --git a/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice.py b/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice.py new file mode 100644 index 000000000..1bc77748d --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice.py @@ -0,0 +1,384 @@ +""" +Set svm_allMice_sessPooled and svm_allMice_sessAvSd. (note: svm_allMice_sessPooled will be used to set summary_vars_all, which is a key paramter in svm_images_plots_compare_ophys_stages.py) + +Run "svm_images_plots_setVars.py" to set vars needed here, mainly svm_this_plane_allsess. + +This script sets vars that will be used for making summary plots across mice. + +Follow this script by "svm_images_plots_setVars_sumMice2.py" to set summary_vars_all (which will be used in svm_images_plots_compare_ophys_stages.py), and make summary plots across mice (if len(project_codes_all)==1). + + +Note, this script is similar to part of omissions_traces_peaks_plots_setVars_ave.py, which is related to setting vars for making summary plots across mice. +Here, we set vars that are similar to the following vars in script omissions_traces_peaks_plots_setVars_ave.py: + svm_allMice_sessPooled (similar to trace_peak_allMice_sessPooled): includes vars pooled across all sessions of all mice (for each plane, each area, and each depth); # use this to make summary mouse plots, by averaging across pooled sessions of all mice. + svm_allMice_sessAvSd (similar to trace_peak_allMice_sessAvSd): includes vars pooled across all sessions of all mice (for each plane, each area, and each depth); # use this to make summary mouse plots, by averaging across mice (each mouse is here averaged across sessions). + (note: some of the vars in "svm_allMice_sessAvSd" are also set in svm_plots_setVars.py (in var "svm_this_plane_allsess") . I didn't take them out of there, bc they will be used for making eachMouse plots. "svm_allMice_sessAvSd" is compatible with omissions code, and will be used for making sumMice plots.) + + +Created on Wed Oct 21 15:14:05 2020 +@author: farzaneh + +""" + +print(svm_this_plane_allsess0.shape) + +stages_all = (np.array([svm_this_plane_allsess0['session_labs'].values[i][0][0] for i in range(svm_this_plane_allsess0.shape[0])])).astype(int) +blocks_all = svm_this_plane_allsess0['block'].values # weird: 70 block 0s, and 69 block 1s ... you need to figure out why some experiments have failed! + + +#%% Loop through svm_this_plane_allsess0 and get those rows of it that belong to a given session stage and block; for each one set svm_allMice_sessPooled and svm_allMice_sessAvSd + +####### Set svm_allMice_sessPooled ####### +if project_codes != ['VisualBehaviorMultiscope']: # remove area/layer pooled columns + indexes = ['cre_allPlanes', 'mouse_id_allPlanes', 'session_ids', 'area_allPlanes', 'depth_allPlanes', 'block_all', 'experience_levels', 'session_labs', \ + 'av_test_data_allPlanes', 'av_test_shfl_allPlanes', 'peak_amp_allPlanes'] +else: + indexes = ['cre_allPlanes', 'mouse_id_allPlanes', 'session_ids', 'area_allPlanes', 'depth_allPlanes', 'block_all', 'experience_levels', 'session_labs', \ + 'av_test_data_allPlanes', 'av_test_shfl_allPlanes', 'peak_amp_allPlanes', \ + 'cre_eachArea', 'av_test_data_eachArea', 'av_test_shfl_eachArea', 'peak_amp_eachArea', \ + 'cre_eachDepth', 'depth_eachDepth', 'av_test_data_eachDepth', 'av_test_shfl_eachDepth', 'peak_amp_eachDepth'] + +svm_allMice_sessPooled = pd.DataFrame([], columns=indexes) + + +####### Set svm_allMice_sessAvSd ####### +if project_codes != ['VisualBehaviorMultiscope']: # remove area/layer pooled columns + cols0 = ['mouse_id', 'cre', 'block', 'session_ids', 'session_stages', 'session_labs', 'area', 'depth', 'plane', \ + 'av_depth_avSess_eachP', 'sd_depth_avSess_eachP', 'av_n_neurons_avSess_eachP', 'sd_n_neurons_avSess_eachP', \ + 'av_n_trials_avSess_eachP', 'sd_n_trials_avSess_eachP', 'av_test_data_avSess_eachP', 'sd_test_data_avSess_eachP', 'av_test_shfl_avSess_eachP', 'sd_test_shfl_avSess_eachP', \ + 'av_peak_amp_trTsShCh_avSess_eachP', 'sd_peak_amp_trTsShCh_avSess_eachP'] + +else: + cols0 = ['mouse_id', 'cre', 'block', 'session_ids', 'session_stages', 'session_labs', 'area', 'depth', 'plane', \ + 'av_depth_avSess_eachP', 'sd_depth_avSess_eachP', 'av_n_neurons_avSess_eachP', 'sd_n_neurons_avSess_eachP', \ + 'av_n_trials_avSess_eachP', 'sd_n_trials_avSess_eachP', 'av_test_data_avSess_eachP', 'sd_test_data_avSess_eachP', 'av_test_shfl_avSess_eachP', 'sd_test_shfl_avSess_eachP', \ + 'av_peak_amp_trTsShCh_avSess_eachP', 'sd_peak_amp_trTsShCh_avSess_eachP', \ + 'num_sessLayers_valid_eachArea', 'av_test_data_pooledSessPlanes_eachArea', 'sd_test_data_pooledSessPlanes_eachArea', 'av_test_shfl_pooledSessPlanes_eachArea', 'sd_test_shfl_pooledSessPlanes_eachArea', \ + 'av_pao_trTsShCh_pooledSessPlanes_eachArea', 'sd_pao_trTsShCh_pooledSessPlanes_eachArea', \ + 'num_sessAreas_valid_eachDepth', 'depth_ave', \ + 'av_test_data_pooledSessAreas_eachDepth', 'sd_test_data_pooledSessAreas_eachDepth', 'av_test_shfl_pooledSessAreas_eachDepth', 'sd_test_shfl_pooledSessAreas_eachDepth', \ + 'av_pao_trTsShCh_pooledSessAreas_eachDepth', 'sd_pao_trTsShCh_pooledSessAreas_eachDepth'] + +if same_num_neuron_all_planes: + cols = np.concatenate((cols0, ['av_n_neurons_svm_trained_avSess_eachP', 'sd_n_neurons_svm_trained_avSess_eachP'])) +else: + cols = cols0 +svm_allMice_sessAvSd = pd.DataFrame([], columns=cols) + + +if ~np.isnan(svm_blocks) and svm_blocks!=-101: + br = np.unique(blocks_all) +else: + br = [np.nan] + + + + +######################################################## +cntall = 0 +cntall2 = 0 + +for istage in np.unique(stages_all): # istage=1 + for iblock in br: # iblock=0 ; iblock=np.nan + + if ~np.isnan(svm_blocks) and svm_blocks!=-101: # block by block analysis + svm_this_plane_allsess = svm_this_plane_allsess0[np.logical_and(stages_all==istage , blocks_all==iblock)] + else: + svm_this_plane_allsess = svm_this_plane_allsess0[stages_all==istage] + + + cntall = cntall + 1 + + #%% ########################################################################################## + ############### Set svm_allMice_sessPooled to make average plots of pooled data across mice sessions ############# + ################ (each plane individually, no pooling across areas or layers) ########################### + ############################################################################################## + + # Remember each row of svm_this_plane_allsess is for each mouse; below we combine data from all mice + + #%% Pool all sessions of all mice + # pandas series "svm_allMice_sessPooled" is created that includes all the important vars below. + # use this to make summary mouse plots, by averaging across pooled sessions of all mice. + + a0 = np.concatenate((svm_this_plane_allsess['cre_exp']).values) # (8*sum(num_sess_per_mouse)) # 8 planes of 1 session, then 8 planes of next session, and so on + cre_all = np.reshape(a0, (num_planes, int(a0.shape[0]/num_planes)), order='F') # 8 x sum(num_sess_per_mouse) # each row is one plane, all sessions + + + a0 = np.concatenate((svm_this_plane_allsess['mouse_id_exp']).values) # (8*sum(num_sess_per_mouse)) # 8 planes of 1 session, then 8 planes of next session, and so on + mouse_id_all = np.reshape(a0, (num_planes, int(a0.shape[0]/num_planes)), order='F') # 8 x sum(num_sess_per_mouse) # each row is one plane, all sessions + + + a0 = np.concatenate((svm_this_plane_allsess['session_ids']).values) + session_ids_all = np.reshape(a0, (num_planes, int(a0.shape[0]/num_planes)), order='F') # 8 x sum(num_sess_per_mouse) # each row is one plane, all sessions + + + aa = svm_this_plane_allsess['area_this_plane_allsess_allp'].values + # aa.shape # num_all_mice; # size of each element : 8 x num_sessions x 1 + # For each element of aa, make array sizes similar to those in omissions_traces_peaks_plots_setVars_ave.py: + # concatenate planes of all sessions (1st, all planes of session 1, then all planes of session 2, etc.) + aar = np.array([np.reshape(aa[ic], (aa[ic].shape[0] * aa[ic].shape[1] , aa[ic].shape[2]), order='F') for ic in range(len(aa))]) + # aar.shape # num_all_mice; # size of each element : (8 x num_sessions) x 1 + a0 = np.concatenate((aar)) # (8*sum(num_sess_per_mouse)) # 8 planes of 1 session, then 8 planes of next session, and so on + area_all = np.reshape(a0, (num_planes, int(a0.shape[0]/num_planes)), order='F') # 8 x sum(num_sess_per_mouse) # each row is one plane, all sessions + + + aa = svm_this_plane_allsess['depth_this_plane_allsess_allp'].values # num_all_mice; # size of each element : 8 x num_sessions x 1 + aar = np.array([np.reshape(aa[ic], (aa[ic].shape[0] * aa[ic].shape[1] , aa[ic].shape[2]), order='F') for ic in range(len(aa))]) # aar.shape # num_all_mice; # size of each element : (8 x num_sessions) x 1 + a0 = np.concatenate((aar)) # (8*sum(num_sess_per_mouse)) # 8 planes of 1 session, then 8 planes of next session, and so on + depth_all = np.reshape(a0, (num_planes, int(a0.shape[0]/num_planes)), order='F') # 8 x sum(num_sess_per_mouse) # each row is + + + session_labs_all = np.unique(np.concatenate((svm_this_plane_allsess['session_labs']).values)) + block_all = np.unique(svm_this_plane_allsess['block'].values) + + experience_levels_all = np.concatenate((svm_this_plane_allsess['experience_levels']).values) # num_sessions +# experience_levels_all = np.unique(np.concatenate((svm_this_plane_allsess['experience_levels']).values)) + + print(session_labs_all, np.unique(experience_levels_all)) + + + ########## individual planes ########## + + aa = svm_this_plane_allsess['av_test_data_this_plane_allsess_allp'].values # num_all_mice; # size of each element : 8 x num_sessions x n_frs + aar = np.array([np.reshape(aa[ic], (aa[ic].shape[0] * aa[ic].shape[1] , aa[ic].shape[2]), order='F') for ic in range(len(aa))]) # aar.shape # num_all_mice; # size of each element : (8 x num_sessions) x n_frs + a0 = np.concatenate((aar)) # (8*sum(num_sess_per_mouse)) x n_frs # 8 planes of 1 session, then 8 planes of next session, and so on + ts_all = np.reshape(a0, (num_planes, int(a0.shape[0]/num_planes), a0.shape[-1]), order='F') # 8 x sum(num_sess_per_mouse) x n_frs # each row is one plane, all sessions + # aa = np.reshape(np.concatenate((svm_this_plane_allsess['plane'].values)), (num_planes, int(a0.shape[0]/num_planes)), order='F') + + aa = svm_this_plane_allsess['av_test_shfl_this_plane_allsess_allp'].values # num_all_mice; # size of each element : 8 x num_sessions x n_frs + aar = np.array([np.reshape(aa[ic], (aa[ic].shape[0] * aa[ic].shape[1] , aa[ic].shape[2]), order='F') for ic in range(len(aa))]) # aar.shape # num_all_mice; # size of each element : (8 x num_sessions) x n_frs + a0 = np.concatenate((aar)) # (8*sum(num_sess_per_mouse)) x n_frs # 8 planes of 1 session, then 8 planes of next session, and so on + sh_all = np.reshape(a0, (num_planes, int(a0.shape[0]/num_planes), a0.shape[-1]), order='F') # 8 x sum(num_sess_per_mouse) x n_frs # each row is one plane, all sessions + + aa = svm_this_plane_allsess['peak_amp_trTsShCh_this_plane_allsess_allp'].values # num_all_mice; # size of each element : 8 x num_sessions x 4 + aar = np.array([np.reshape(aa[ic], (aa[ic].shape[0] * aa[ic].shape[1] , aa[ic].shape[2]), order='F') for ic in range(len(aa))]) # aar.shape # num_all_mice; # size of each element : (8 x num_sessions) x 4 + a0 = np.concatenate((aar)) # (8*sum(num_sess_per_mouse)) x 4 # 8 planes of 1 session, then 8 planes of next session, and so on + pa_all = np.reshape(a0, (num_planes, int(a0.shape[0]/num_planes), a0.shape[-1]), order='F') # 8 x sum(num_sess_per_mouse) x 4 # each row is one plane, all sessions + + + + if project_codes == ['VisualBehaviorMultiscope']: + ########## Each area: layers pooled ########## + + cre_all_eachArea = np.concatenate((svm_this_plane_allsess['cre_pooled_sesss_planes_eachArea'].values), axis=1) # 2 x (4*sum(num_sess_per_mouse)) + ts_all_eachArea = np.concatenate((svm_this_plane_allsess['av_test_data_pooled_sesss_planes_eachArea'].values), axis=1) # 2 x (4*sum(num_sess_per_mouse)) x 1270 + sh_all_eachArea = np.concatenate((svm_this_plane_allsess['av_test_shfl_pooled_sesss_planes_eachArea'].values), axis=1) # 2 x (4*sum(num_sess_per_mouse)) x 1270 + pao_all_eachArea = np.concatenate((svm_this_plane_allsess['peak_amp_trTsShCh_pooled_sesss_planes_eachArea'].values), axis=1) # 2 x (4*sum(num_sess_per_mouse)) x 4(train,test,shuffle,chance) + + + ########## Each layer: areas pooled ########## svm_this_plane_allsess['trace_pooled_eachDepth'] + + cre_all_eachDepth = np.concatenate((svm_this_plane_allsess['cre_pooled_sesss_areas_eachDepth'].values), axis=1) # 4 x (2*sum(num_sess_per_mouse)) + ts_all_eachDepth = np.concatenate((svm_this_plane_allsess['av_test_data_pooled_sesss_areas_eachDepth'].values), axis=1) # 4 x (2*sum(num_sess_per_mouse)) x 1270 + sh_all_eachDepth = np.concatenate((svm_this_plane_allsess['av_test_shfl_pooled_sesss_areas_eachDepth'].values), axis=1) # 4 x (2*sum(num_sess_per_mouse)) x 1270 + pao_all_eachDepth = np.concatenate((svm_this_plane_allsess['peak_amp_trTsShCh_pooled_sesss_areas_eachDepth'].values), axis=1) # 4 x (2*sum(num_sess_per_mouse)) x 4(train,test,shuffle,chance) + + depth_all_eachDepth = np.concatenate((svm_this_plane_allsess['depth_pooled_sesss_areas_eachDepth'].values), axis=1) # 4 x (2*sum(num_sess_per_mouse)) + + + ''' + ########### Make a pandas series to keep the pooled session data of all mice ########### + + svm_allMice_sessPooled = pd.Series([cre_all, mouse_id_all, area_all, depth_all, block_all, session_labs_all, \ + ts_all, sh_all, pa_all, \ + cre_all_eachArea, ts_all_eachArea, sh_all_eachArea, pao_all_eachArea, \ + cre_all_eachDepth, depth_all_eachDepth, ts_all_eachDepth, sh_all_eachDepth, pao_all_eachDepth],\ + index=indexes) + ''' + + svm_allMice_sessPooled.at[cntall, indexes] = cre_all, mouse_id_all, session_ids_all, area_all, depth_all, block_all, experience_levels_all, session_labs_all, \ + ts_all, sh_all, pa_all, \ + cre_all_eachArea, ts_all_eachArea, sh_all_eachArea, pao_all_eachArea, \ + cre_all_eachDepth, depth_all_eachDepth, ts_all_eachDepth, sh_all_eachDepth, pao_all_eachDepth + + else: + + arrvars = cre_all, mouse_id_all, session_ids_all, area_all, depth_all, block_all, experience_levels_all, session_labs_all, ts_all, sh_all, pa_all + for iar in range(len(indexes)): + svm_allMice_sessPooled.at[cntall, indexes[iar]] = arrvars[iar] + + # not sure why but below fails... +# svm_allMice_sessPooled.at[cntall, indexes] = cre_all, mouse_id_all, session_ids_all, \ +# area_all, depth_all, block_all, session_labs_all, ts_all, sh_all, pa_all + + + print(svm_allMice_sessPooled.shape) +# print(svm_allMice_sessPooled) + + + + + ###################################################################### + ###################################################################### + ###################################################################### + #%% Set svm_allMice_sessAvSd: session-averaged data for each mouse; note we dont use svm_allMice_sessAvSd in svm_images_plots_compare_ophys_stages.py + # pandas dataFrame "svm_allMice_sessAvSd" is created to keep the important vars below + # use this to make summary mouse plots, by averaging across mice (each mouse is here averaged across sessions). + ###################################################################### + ###################################################################### + ###################################################################### + + for im in range(len(svm_this_plane_allsess)): # im=0 + + cntall2 = cntall2 + 1 + + #%% + mouse_id = svm_this_plane_allsess.iloc[im]['mouse_id'] + cre = svm_this_plane_allsess.iloc[im]['cre'] + session_stages = svm_this_plane_allsess.iloc[im]['session_stages'] + session_labs = svm_this_plane_allsess.iloc[im]['session_labs'] + num_sessions = len(session_stages) + block = svm_this_plane_allsess.iloc[im]['block'] + session_ids_now = svm_this_plane_allsess.iloc[im]['session_ids'] + + ################################################################ + #%% Session-averaged, each plane ; omission-aligned traces + ################################################################ + ######### For each plane, average vars across days ######### + # note: some of the vars below are also set in svm_plots_setVars.py (in var "svm_this_plane_allsess") . I didn't take them out of there, bc they will be used for making eachMouse plots. Below is compatible with omissions code, and will be used for making sumMice plots. + + num_sessions_valid = svm_this_plane_allsess.iloc[im]['num_sessions_valid'] + + a0 = svm_this_plane_allsess.iloc[im]['area'] + areas = np.reshape(a0, (num_planes, num_sessions), order='F') # 8 x num_sessions # each row is one plane, all sessions + a0 = svm_this_plane_allsess.iloc[im]['depth'] + depths = np.reshape(a0, (num_planes, num_sessions), order='F') # 8 x num_sessions # each row is one plane, all sessions + a0 = svm_this_plane_allsess.iloc[im]['plane'] + planes = np.reshape(a0, (num_planes, num_sessions), order='F') # 8 x num_sessions # each row is one plane, all sessions + + # depth + a = svm_this_plane_allsess.iloc[im]['depth_this_plane_allsess_allp'] # size: (8 x num_sessions x 1) + av_depth_avSess_eachP = np.nanmean(a,axis=1).squeeze() # num_planes + sd_depth_avSess_eachP = np.nanstd(a,axis=1).squeeze() / np.sqrt(num_sessions_valid) # num_planes # st error across sessions, for each plane + + # num_neurons + a = svm_this_plane_allsess.iloc[im]['n_neurons_this_plane_allsess_allp'] # size: (8 x num_sessions x 1) + av_n_neurons_avSess_eachP = np.nanmean(a,axis=1).squeeze() # num_planes + sd_n_neurons_avSess_eachP = np.nanstd(a,axis=1).squeeze() / np.sqrt(num_sessions_valid) # num_planes # st error across sessions, for each plane + + # population size used for svm training + if same_num_neuron_all_planes: + a = svm_this_plane_allsess.iloc[im]['n_neurons_svm_trained_this_plane_allsess_allp'] # size: (8 x num_sessions x 1) + av_n_neurons_svm_trained_avSess_eachP = np.nanmean(a,axis=1).squeeze() # num_planes + sd_n_neurons_svm_trained_avSess_eachP = np.nanstd(a,axis=1).squeeze() / np.sqrt(num_sessions_valid) # num_planes # st error across sessions, for each plane + + # num_omissions + a = svm_this_plane_allsess.iloc[im]['n_trials_this_plane_allsess_allp'] # size: (8 x num_sessions x 1) + av_n_trials_avSess_eachP = np.nanmean(a,axis=1).squeeze() # num_planes + sd_n_trials_avSess_eachP = np.nanstd(a,axis=1).squeeze() / np.sqrt(num_sessions_valid) # num_planes # st error across sessions, for each plane + + + if project_codes != ['VisualBehaviorMultiscope']: + sqnv = np.sqrt(num_sessions_valid) + else: + sqnv = np.sqrt(num_sessions_valid)[:, np.newaxis] + + # av_test_data + a = svm_this_plane_allsess.iloc[im]['av_test_data_this_plane_allsess_allp'] # size: (8 x num_sessions x nFrames_upsampled) + av_test_data_avSess_eachP = np.nanmean(a,axis=1) # num_planes x nFrames_upsampled (interpolated times) + sd_test_data_avSess_eachP = np.nanstd(a,axis=1) / sqnv # num_planes x nFrames_upsampled # st error across sessions, for each plane + + # av_test_shfl + a = svm_this_plane_allsess.iloc[im]['av_test_shfl_this_plane_allsess_allp'] # size: (8 x num_sessions x nFrames_upsampled) + av_test_shfl_avSess_eachP = np.nanmean(a,axis=1) # num_planes x nFrames_upsampled (interpolated times) + sd_test_shfl_avSess_eachP = np.nanstd(a,axis=1) / sqnv # num_planes x nFrames_upsampled # st error across sessions, for each plane + + + # peak_amp_trTsShCh + a = svm_this_plane_allsess.iloc[im]['peak_amp_trTsShCh_this_plane_allsess_allp'] # size: (8 x num_sessions x 4) + av_peak_amp_trTsShCh_avSess_eachP = np.nanmean(a,axis=1).squeeze() # num_planes x 4 + sd_peak_amp_trTsShCh_avSess_eachP = np.nanstd(a,axis=1).squeeze() / sqnv # num_planes x 4 # st error across sessions, for each plane + + + if project_codes == ['VisualBehaviorMultiscope']: + ################################################################ + #%% Data per area: pooled across sessions and layers for each area + # Question 1: is there a difference between areas (V1 vs LM) # for each mouse pool across sessions and layers (for each area) + + # Get the total number of valid sessions and layers for each area + num_sessions_valid_eachArea = svm_this_plane_allsess.iloc[im]['num_sessions_valid_eachArea'] + num_sessLayers_valid_eachArea = np.sum(num_sessions_valid_eachArea, axis=1) + + # Average across layers and sessions for each area + # test_data + a = svm_this_plane_allsess.iloc[im]['av_test_data_pooled_sesss_planes_eachArea'] # 2 x (4 x num_sessions) x nFrames_upsampled + av_test_data_pooledSessPlanes_eachArea = np.nanmean(a, axis=1) # 2 x nFrames_upsampled + sd_test_data_pooledSessPlanes_eachArea = np.nanstd(a, axis=1) / np.sqrt(num_sessLayers_valid_eachArea)[:,np.newaxis] # 2 x nFrames_upsampled + + # test_shfl + a = svm_this_plane_allsess.iloc[im]['av_test_shfl_pooled_sesss_planes_eachArea'] # 2 x (4 x num_sessions) x nFrames_upsampled + av_test_shfl_pooledSessPlanes_eachArea = np.nanmean(a, axis=1) # 2 x nFrames_upsampled + sd_test_shfl_pooledSessPlanes_eachArea = np.nanstd(a, axis=1) / np.sqrt(num_sessLayers_valid_eachArea)[:,np.newaxis] # 2 x nFrames_upsampled + + + # peak_amp + a = svm_this_plane_allsess.iloc[im]['peak_amp_trTsShCh_pooled_sesss_planes_eachArea'] # 2 x (4 x num_sessions) x 4(train, test, shuffle, chance) + # num_sessLayers_valid_eachArea = a.shape[1] + av_pao_trTsShCh_pooledSessPlanes_eachArea = np.nanmean(a, axis=1) # 2 x 4 + sd_pao_trTsShCh_pooledSessPlanes_eachArea = np.nanstd(a, axis=1) / np.sqrt(num_sessLayers_valid_eachArea)[:,np.newaxis] # 2 x 4(train, test, shuffle, chance) + + + ################################################################ + #%% Data per depth: pooled across sessions and areas for each depth + # Question 2: is there a difference between superficial and deep layers # for each mouse pool across sessions and area (for each layer)... also pool 2 superifical (deep) layers into 1 + + # set average depth across sessions and areas + d = svm_this_plane_allsess.iloc[im]['depth_pooled_sesss_areas_eachDepth'] # 4 x (2 x num_sessions) + depth_ave = np.mean(d, axis=1) # average across areas and sessions + # b, _,_ = pool_sesss_planes_eachArea(area, area) + + # Get the total number of valid sessions and layers for each depth + num_sessAreas_valid_eachDepth = np.sum(num_sessions_valid_eachArea, axis=0) + + # Average across areas and sessions for each depth + # test_data + a = svm_this_plane_allsess.iloc[im]['av_test_data_pooled_sesss_areas_eachDepth'] # 4 x (2 x num_sessions) x nFrames_upsampled + av_test_data_pooledSessAreas_eachDepth = np.nanmean(a, axis=1) # 4 x nFrames_upsampled + sd_test_data_pooledSessAreas_eachDepth = np.nanstd(a, axis=1) / np.sqrt(num_sessAreas_valid_eachDepth)[:,np.newaxis] # 4 x nFrames_upsampled + + # test_shfl + a = svm_this_plane_allsess.iloc[im]['av_test_shfl_pooled_sesss_areas_eachDepth'] # 4 x (2 x num_sessions) x nFrames_upsampled + av_test_shfl_pooledSessAreas_eachDepth = np.nanmean(a, axis=1) # 4 x nFrames_upsampled + sd_test_shfl_pooledSessAreas_eachDepth = np.nanstd(a, axis=1) / np.sqrt(num_sessAreas_valid_eachDepth)[:,np.newaxis] # 4 x nFrames_upsampled + + + # peak_amp + a = svm_this_plane_allsess.iloc[im]['peak_amp_trTsShCh_pooled_sesss_areas_eachDepth'] # 4 x (2 x num_sessions) x 4(train, test, shuffle, chance) + # num_sessLayers_valid_eachArea = a.shape[1] + av_pao_trTsShCh_pooledSessAreas_eachDepth = np.nanmean(a, axis=1) # 4 x 4 + sd_pao_trTsShCh_pooledSessAreas_eachDepth = np.nanstd(a, axis=1) / np.sqrt(num_sessAreas_valid_eachDepth)[:,np.newaxis] # 4 x 4(train, test, shuffle, chance) + + + #%% Keep vars (session averaged, each plane, also eachArea, eachDepth vars) for all mice + + svm_allMice_sessAvSd.at[cntall2, cols0] = \ + mouse_id, cre, block, session_ids_now, session_stages, session_labs, areas, depths, planes, \ + av_depth_avSess_eachP, sd_depth_avSess_eachP, av_n_neurons_avSess_eachP, sd_n_neurons_avSess_eachP, \ + av_n_trials_avSess_eachP, sd_n_trials_avSess_eachP, av_test_data_avSess_eachP, sd_test_data_avSess_eachP, av_test_shfl_avSess_eachP, sd_test_shfl_avSess_eachP, \ + av_peak_amp_trTsShCh_avSess_eachP, sd_peak_amp_trTsShCh_avSess_eachP, \ + num_sessLayers_valid_eachArea, av_test_data_pooledSessPlanes_eachArea, sd_test_data_pooledSessPlanes_eachArea, av_test_shfl_pooledSessPlanes_eachArea, sd_test_shfl_pooledSessPlanes_eachArea, \ + av_pao_trTsShCh_pooledSessPlanes_eachArea, sd_pao_trTsShCh_pooledSessPlanes_eachArea, \ + num_sessAreas_valid_eachDepth, depth_ave, \ + av_test_data_pooledSessAreas_eachDepth, sd_test_data_pooledSessAreas_eachDepth, av_test_shfl_pooledSessAreas_eachDepth, sd_test_shfl_pooledSessAreas_eachDepth, \ + av_pao_trTsShCh_pooledSessAreas_eachDepth, sd_pao_trTsShCh_pooledSessAreas_eachDepth + + else: + + #%% Keep vars (session averaged, each plane, also eachArea, eachDepth vars) for all mice + + svm_allMice_sessAvSd.at[cntall2, cols0] = \ + mouse_id, cre, block, session_ids_now, session_stages, session_labs, areas, depths, planes, \ + av_depth_avSess_eachP, sd_depth_avSess_eachP, av_n_neurons_avSess_eachP, sd_n_neurons_avSess_eachP, \ + av_n_trials_avSess_eachP, sd_n_trials_avSess_eachP, av_test_data_avSess_eachP, sd_test_data_avSess_eachP, av_test_shfl_avSess_eachP, sd_test_shfl_avSess_eachP, \ + av_peak_amp_trTsShCh_avSess_eachP, sd_peak_amp_trTsShCh_avSess_eachP + + + if same_num_neuron_all_planes: + svm_allMice_sessAvSd.at[cntall2, ['av_n_neurons_svm_trained_avSess_eachP']] = [av_n_neurons_svm_trained_avSess_eachP] + svm_allMice_sessAvSd.at[cntall2, ['sd_n_neurons_svm_trained_avSess_eachP']] = [sd_n_neurons_svm_trained_avSess_eachP] + + print(svm_allMice_sessAvSd.shape) +# svm_allMice_sessAvSd + + + diff --git a/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice2.py b/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice2.py new file mode 100644 index 000000000..f7527e2f7 --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice2.py @@ -0,0 +1,321 @@ +""" +Gets called in svm_images_plots_setVars.py + +Sets summary_vars_all, a dataframe that includes response amplitude (computed from svm_allMice_sessPooled); it will be used in svm_images_plots_compare_ophys_stages.py + +If len(project_codes_all)==1, it calls svm_images_plots_sumMice.py to make mouse-averaged plots for each ophys stage. + +Vars needed here are set in "svm_images_plots_setVars_sumMice.py" + + +Created on Wed Oct 21 15:22:05 2020 +@author: farzaneh + +""" + +import matplotlib.pyplot as plt +import matplotlib.gridspec as gridspec +import matplotlib.ticker as ticker +from matplotlib.ticker import (MultipleLocator, FormatStrFormatter, AutoMinorLocator) +import seaborn +import sys + +from general_funs import * + +import warnings +import matplotlib.cbook +warnings.filterwarnings("ignore",category=matplotlib.cbook.mplDeprecation) + + +#%% +stages_allp = (np.array([svm_allMice_sessPooled0['session_labs'].values[i][0][0] for i in range(svm_allMice_sessPooled0.shape[0])])).astype(int) +if ~np.isnan(svm_blocks) and svm_blocks!=-101: + blocks_allp = (np.array([svm_allMice_sessPooled0['block_all'].values[i][0] for i in range(svm_allMice_sessPooled0.shape[0])])).astype(int) +else: + blocks_allp = (np.array([svm_allMice_sessPooled0['block_all'].values[i][0] for i in range(svm_allMice_sessPooled0.shape[0])])) + + +stages_alla = (np.array([svm_allMice_sessAvSd0['session_labs'].values[i][0][0] for i in range(svm_allMice_sessAvSd0.shape[0])])).astype(int) +blocks_alla = svm_allMice_sessAvSd0['block'].values + +cre_all = svm_allMice_sessPooled0['cre_allPlanes'].values[0] +cre_lines = np.unique(cre_all) +cre_lineso = copy.deepcopy(cre_lines) + + +if ~np.isnan(svm_blocks) and svm_blocks!=-101: + if svm_blocks==-1: # divide trials into blocks based on the engagement state + svmb = 2 + else: + svmb = svm_blocks + br = range(svmb) +else: + br = [np.nan] + + +if baseline_subtract: # subtract the baseline (CA average during baseline, ie before time 0) from the evoked CA (classification accuracy) + ylabs = '% Class accuracy rel. baseline' #'Amplitude' +else: + ylabs = '% Classification accuracy' #'Amplitude' + + + +#%% Make sure for each mouse we have data from both blocks +''' +for istage in np.unique(stages_all): # istage=1 + for iblock in br: # iblock=0 ; iblock=np.nan + if ~np.isnan(svm_blocks): + svm_this_plane_allsess = svm_this_plane_allsess0[np.logical_and(stages_all==istage , blocks_all==iblock)] + else: + svm_this_plane_allsess = svm_this_plane_allsess0[stages_all==istage] +''' + +if ~np.isnan(svm_blocks) and svm_blocks!=-101: # svm was run on blocks + + for istage in np.unique(stages_all): # istage=1 + a = svm_allMice_sessPooled0[stages_allp==istage] + if len(a) != len(br): + print(f'data from both blocks dont exist for stage {istage}!') +# sys.exit(f'data from both blocks dont exist for stage {istage}!') + + else: + mice_blocks = [] + for iblock in br: + b = np.unique(a[a['block_all']==iblock]['mouse_id_allPlanes'].values[0]) + mice_blocks.append(b) + + mice_blocks = np.array(mice_blocks) + + d0 = np.setdiff1d(mice_blocks[0], mice_blocks[1]) # mouse exists in block0 but not block1 + d1 = np.setdiff1d(mice_blocks[1], mice_blocks[0]) # mouse exists in block1 but not block0 + + if len(d0)>0: # ~np.equal(mice_blocks[0], mice_blocks[1]).all() + print(f'Stage {istage}, mouse {d0} is missing from block 1!') + print('\tsetting this mouse values in block0 to nan') + this_stage_this_block = a.iloc[0] # block 0 + this_mouse_ind = this_stage_this_block['mouse_id_allPlanes'][0,:]==d0 # mouse_id for each session (of plane 0) + +# aa = this_stage_this_block['av_test_data_allPlanes'] # num_planes x num_sessions x num_frames +# aa[:, this_mouse_ind,:] = np.nan +# aa = this_stage_this_block['av_test_shfl_allPlanes'] # num_planes x num_sessions x num_frames +# aa[:, this_mouse_ind,:] = np.nan + + svm_allMice_sessPooled0[stages_allp==istage].iloc[0]['av_test_data_allPlanes'][:, this_mouse_ind,:] = np.nan + svm_allMice_sessPooled0[stages_allp==istage].iloc[0]['av_test_shfl_allPlanes'][:, this_mouse_ind,:] = np.nan + + # remember you also need to do the same thing for svm_allMice_sessAvSd0, but we are not using it below so i'll pass for now! + + if len(d1)>0: + print(f'Stage {istage}, mouse {d1} is missing from block 0!') + print('\tsetting this mouse values in block1 to nan') + this_stage_this_block = a.iloc[1] # block 1 + this_mouse_ind = this_stage_this_block['mouse_id_allPlanes'][0,:]==d0 # mouse_id for each session (of plane 0) + +# aa = this_stage_this_block['av_test_data_allPlanes'] # num_planes x num_sessions x num_frames +# aa[:, this_mouse_ind,:] = np.nan +# aa = this_stage_this_block['av_test_shfl_allPlanes'] # num_planes x num_sessions x num_frames +# aa[:, this_mouse_ind,:] = np.nan + + svm_allMice_sessPooled0[stages_allp==istage].iloc[1]['av_test_data_allPlanes'][:, this_mouse_ind,:] = np.nan + svm_allMice_sessPooled0[stages_allp==istage].iloc[1]['av_test_shfl_allPlanes'][:, this_mouse_ind,:] = np.nan + + if len(br)>2: + sys.exit('above needs work; setdiff1d works on 2 arrays; perhaps loop through arrays!') + + + +########################################################################################## +########################################################################################## +#%% SUMMARY ACROSS MICE +########################################################################################## +########################################################################################## +############# Set summary_vars_all, a dataframe that includes response amplitude (computed from svm_allMice_sessPooled); it will be used in svm_images_plots_compare_ophys_stages.py +############# Also plot traces averaged across mice of the same cre line ################ +########################################################################################## +########################################################################################## + +cols_sum = ['stage', 'experience_level', 'cre', 'block', 'depth_ave', 'resp_amp'] +summary_vars_all = pd.DataFrame([], columns=cols_sum) + +xgap_areas = .3 +linestyle_all = ['solid', 'dashed'] # for block 0 and 1 +fmt_all = ['o', 'x'] +cols_area_all = [cols_area , ['skyblue', 'dimgray']] + +cntn = 0 +for istage in np.unique(stages_all): # istage=1 + for cre in ['Slc17a7', 'Sst', 'Vip']: # cre = 'Slc17a7' + + ############################### + plt.figure(figsize=(8,11)) + + ##### traces ##### + gs1 = gridspec.GridSpec(1,2) #(3, 2)#, width_ratios=[3, 1]) + gs1.update(bottom=.73, top=0.9, left=0.05, right=0.95, wspace=.8) + # + gs2 = gridspec.GridSpec(1,2) #(3, 2)#, width_ratios=[3, 1]) + gs2.update(bottom=.45, top=0.62, left=0.05, right=0.95, wspace=.8) + + ##### Response measures; each depth ##### + # subplots of flash responses + gs3 = gridspec.GridSpec(1,2) #, width_ratios=[3, 1]) + gs3.update(bottom=.22, top=0.35, left=0.05, right=0.55, wspace=.55, hspace=.5) + + ##### Response measures; compare areas (pooled depths) ##### + # subplots of flash responses + gs5 = gridspec.GridSpec(1,2) #, width_ratios=[3, 1]) + gs5.update(bottom=.22, top=0.35, left=0.7, right=0.95, wspace=.55, hspace=.5) + +# plt.suptitle('%s, %d mice, %d total sessions: %s' %(cre, thisCre_mice_num, thisCre_pooledSessNum, session_labs_all), fontsize=14) + + + #%% + h1v1 = [] + h1lm = [] + h1a = [] + h1d = [] + lims_v1lm = [] + + for iblock in br: # np.unique(blocks_all): # iblock=0 ; iblock=np.nan + + if ~np.isnan(svm_blocks) and svm_blocks!=-101: + svm_allMice_sessPooled = svm_allMice_sessPooled0[np.logical_and(stages_allp==istage , blocks_allp==iblock)] + svm_allMice_sessAvSd = svm_allMice_sessAvSd0[np.logical_and(stages_alla==istage , blocks_alla==iblock)] + # svm_allMice_sessPooled = eval(f'svm_allMice_sessPooled_block{iblock}') + # svm_allMice_sessAvSd = eval(f'svm_allMice_sessAvSd_block{iblock}') + + linestyle_now = linestyle_all[iblock] + cols_area_now = cols_area_all[iblock] + fmt_now = fmt_all[iblock] + + else: + svm_allMice_sessPooled = svm_allMice_sessPooled0[stages_allp==istage] + svm_allMice_sessAvSd = svm_allMice_sessAvSd0[stages_alla==istage] + + linestyle_now = linestyle_all[0] + cols_area_now = cols_area_all[0] + fmt_now = fmt_all[0] + + + ############################### + if len(svm_allMice_sessPooled)==0: # eg when dividing blocks by engagement metric (svm_blocks=-1), we wont have data for passive sessions. + thisCre_pooledSessNum = 0 + print(f'\nThere is no data for {cre}, stage {istage} block {iblock}!\n') + + else: # there is data + + cre_all = svm_allMice_sessPooled['cre_allPlanes'].values[0] + cre_lines = np.unique(cre_all) + mouse_id_all = svm_allMice_sessPooled['mouse_id_allPlanes'].values[0] + + # cre = 'Sst' #cre_lines[icre] + thisCre_pooledSessNum = sum(cre_all[0,:]==cre) # number of pooled sessions for this cre line + thisCre_mice = mouse_id_all[0, cre_all[0,:]==cre] + thisCre_mice_num = len(np.unique(thisCre_mice)) + + + if svm_blocks==-1: + lab_b = f'e{iblock}' # engagement + else: + lab_b = f'b{iblock}' # block + + + if thisCre_pooledSessNum < 1: + print(f'There are no sessions for stage {istage}, mouse {cre}, block {iblock}') + + else: + ############################### + #%% Set vars + a_all = svm_allMice_sessPooled['area_allPlanes'].values[0] # 8 x pooledSessNum + d_all = svm_allMice_sessPooled['depth_allPlanes'].values[0] # 8 x pooledSessNum + session_labs_all = svm_allMice_sessPooled['session_labs'].values[0] + + ts_all = svm_allMice_sessPooled['av_test_data_allPlanes'].values[0] # 8 x pooledSessNum x 80 + sh_all = svm_allMice_sessPooled['av_test_shfl_allPlanes'].values[0] # 8 x pooledSessNum x 80 + + pa_all = svm_allMice_sessPooled['peak_amp_allPlanes'].values[0] # 8 x pooledSessNum x 4 (trTsShCh) + + + if project_codes == ['VisualBehaviorMultiscope']: + cre_eachArea = svm_allMice_sessPooled['cre_eachArea'].values[0] # 2 x (4*sum(num_sess_per_mouse)) + ts_eachArea = svm_allMice_sessPooled['av_test_data_eachArea'].values[0] # 2 x (4*sum(num_sess_per_mouse)) x 80 + sh_eachArea = svm_allMice_sessPooled['av_test_shfl_eachArea'].values[0] # 2 x (4*sum(num_sess_per_mouse)) x 80 + pa_eachArea = svm_allMice_sessPooled['peak_amp_eachArea'].values[0] # 2 x (4*sum(num_sess_per_mouse)) x 4 (trTsShCh) + + cre_eachDepth = svm_allMice_sessPooled['cre_eachDepth'].values[0] # 4 x (2*sum(num_sess_per_mouse)) + depth_eachDepth = svm_allMice_sessPooled['depth_eachDepth'].values[0] # 4 x (2*sum(num_sess_per_mouse)) + ts_eachDepth = svm_allMice_sessPooled['av_test_data_eachDepth'].values[0] # 4 x (2*sum(num_sess_per_mouse)) x 80 + sh_eachDepth = svm_allMice_sessPooled['av_test_shfl_eachDepth'].values[0] # 4 x (2*sum(num_sess_per_mouse)) x 80 + + depth_ave = np.mean(depth_eachDepth[:, cre_eachDepth[0,:]==cre], axis=1).astype(float) # 4 # average across areas and sessions + + else: + depth_ave = np.mean(d_all[:,cre_all[0,:]==cre], axis=1).astype(float) # 4 # average across areas and sessions + + + ################################# + #%% Keep summary vars for all ophys stages + + cntn = cntn+1 + # depth_ave = np.mean(depth_eachDepth[:, cre_eachDepth[0,:]==cre], axis=1).astype(float) # 4 # average across areas and sessions + pallnow = pa_all[:, cre_all[0,:]==cre] + + summary_vars_all.at[cntn, cols_sum] = istage, exp_level, cre, iblock, depth_ave, pallnow + + + + #################################################################################### + #################################################################################### + #%% Plot session-averaged traces for each plane; 2 subplots: 1 per area + #################################################################################### + #################################################################################### + + #%% + # Average across all pooled sessions for each plane # remember some experiments might be nan (because they were not valid, we keep all 8 experiments to make indexing easy) + a = ts_all[:, cre_all[0,:]==cre] # 8 x thisCre_pooledSessNum x 80 + av_ts_eachPlane = np.nanmean(a, axis=1) # 8 x 80 + sd_ts_eachPlane = np.nanstd(a, axis=1) / np.sqrt(a.shape[1]) # 8 x 80 + + a = sh_all[:, cre_all[0,:]==cre] # 8 x thisCre_pooledSessNum x 80 + av_sh_eachPlane = np.nanmean(a, axis=1) # 8 x 80 + sd_sh_eachPlane = np.nanstd(a, axis=1) / np.sqrt(a.shape[1]) # 8 x 80 + + areas = a_all[:, cre_all[0,:]==cre] # 8 x thisCre_pooledSessNum + depths = d_all[:, cre_all[0,:]==cre] # 8 x thisCre_pooledSessNum + + lims = np.array([np.nanmin(av_sh_eachPlane - sd_sh_eachPlane), np.nanmax(av_ts_eachPlane + sd_ts_eachPlane)]) + lims[0] = lims[0] - np.diff(lims) / 20. + lims[1] = lims[1] + np.diff(lims) / 20. + + lims_v1lm.append(lims) + + + + ################################################################ + ##############%% Plot averages of all mice in each cell line ################### + ################################################################ + + plots_make_finalize = [1,0] # make the plot + + if len(project_codes_all)==1: + exec(open('svm_images_plots_sumMice.py').read()) + + + + ################################################################ + ################################################################ + if thisCre_pooledSessNum > 0: # done with both blocks of a given ophys stage; now add labels etc to the plot + + plots_make_finalize = [0,1] + + if len(project_codes_all)==1: + exec(open('svm_images_plots_sumMice.py').read()) + + + + + + + + + diff --git a/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice3_resp_sum.py b/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice3_resp_sum.py new file mode 100644 index 000000000..9143627de --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice3_resp_sum.py @@ -0,0 +1,165 @@ +""" +Gets called in svm_images_plots_setVars.py + +Here, we use svm_df from all projects to set resp_amp_sum_df, a df that includes the mean and stdev of decoding magnitude (aka response amplitude) across all experiments of all sessions + +Vars needed here are set in svm_images_plots_setVars_sumMice3_svmdf.py + +Created on Fri Oct 29 22:02:05 2021 +@author: farzaneh + +""" + +################################################################################################ +### Create a dataframe: resp_amp_sum_df, that includes the mean and sterr of response amplitude across all experiments of all sessions +################################################################################################ + +svm_df_all = pd.concat(svm_df_allpr) # concatenate data from all project codes +# svm_df_all = svm_df_allpr[2] # run the code below for a single project code +print(len(svm_df_all)) + +exp_level_all = svm_df_all['experience_levels'].unique() +cresdf = svm_df_all['cre_allPlanes'].unique() +resp_amp_sum_df = pd.DataFrame() + +cnt = -1 +for cre in cresdf: # cre = cresdf[0] + for i in range(len(exp_level_all)): # i=0 + cnt = cnt+1 + + # svm_df for a given cre and experience level + thiscre = svm_df_all[svm_df_all['cre_allPlanes']==cre] + thiscre = thiscre[thiscre['experience_levels']==exp_level_all[i]] + print(len(thiscre)) + + depthav = thiscre['depth_allPlanes'].mean() +# areasu = thiscre['area_allPlanes'].unique() + ampall = np.vstack(thiscre['peak_amp_allPlanes_allExp']) # ampall.shape # exp x 4 # pooled_experiments x 4_trTsShCh + nexp = sum(~np.isnan(ampall[:,1])) + + # testing data + testav = np.nanmean(ampall[:,1]) + testsd = np.nanstd(ampall[:,1]) / np.sqrt(nexp) #ampall[:,1].shape[0]) + + # shuffled + shflav = np.nanmean(ampall[:,2]) + shflsd = np.nanstd(ampall[:,2]) / np.sqrt(nexp) # ampall[:,2].shape[0] + + # create the summary df + resp_amp_sum_df.at[cnt, 'cre'] = cre + resp_amp_sum_df.at[cnt, 'experience_level'] = exp_level_all[i] + resp_amp_sum_df.at[cnt, 'depth_av'] = depthav + resp_amp_sum_df.at[cnt, 'n_experiments'] = nexp + + resp_amp_sum_df.at[cnt, 'test_av'] = testav + resp_amp_sum_df.at[cnt, 'test_sd'] = testsd + resp_amp_sum_df.at[cnt, 'shfl_av'] = shflav + resp_amp_sum_df.at[cnt, 'shfl_sd'] = shflsd + +resp_amp_sum_df +# [areasu for x in resp_amp_sum_df['cre']] + + + + + + + +################################################################################################ +### The following will be used for making area & depth comparison plots: +### Create dataframes: resp_amp_sum_df_depth & resp_amp_sum_df_area. +### they include the mean and sterr of response amplitude across all experiments of all sessions with the same binned depth (resp_amp_sum_df_depth), or the same area (resp_amp_sum_df_area). +################################################################################################ + +resp_amp_sum_df_depth = pd.DataFrame() +resp_amp_sum_df_area = pd.DataFrame() +# cnt = -1 +cntd = -1 +cnta = -1 +for cre in cresdf: # cre = cresdf[0] + for i in range(len(exp_level_all)): # i=0 +# cnt = cnt+1 + + # svm_df for a given cre and experience level + thiscre = svm_df_all[svm_df_all['cre_allPlanes']==cre] + thiscre = thiscre[thiscre['experience_levels']==exp_level_all[i]] + print(len(thiscre)) + + + # area + area_all = thiscre['area_allPlanes'].values + + # binned depth + binned_depth_all = thiscre['binned_depth'].values + + # testing data + test_all = np.array([thiscre[ 'peak_amp_allPlanes_allExp'].iloc[ii][1] for ii in range(len(thiscre))]) + + # shuffled data + shfl_all = np.array([thiscre[ 'peak_amp_allPlanes_allExp'].iloc[ii][2] for ii in range(len(thiscre))]) + + # number of experiments + nexp = sum(~np.isnan(test_all)) + + + ############################## + # create a dataframe for the above vars + df = pd.DataFrame() + + df['area'] = area_all + df['binned_depth'] = binned_depth_all + df['test'] = test_all + df['shfl'] = shfl_all + + # binned depth + # average classification accuracies across experiments with the same binned depth; do this for both testing and shuffle data + ave_test_shfl_binned_depth = df.groupby('binned_depth').mean() + # ste (note that count function does not count NaN vals) + ne = df.groupby('binned_depth').count()['test'].values # number of experiments for each area + nee = np.vstack([ne, ne]).T # set it in a format that can be used to divide std by. + ste_test_shfl_binned_depth = df.groupby('binned_depth').std() / np.sqrt(nee) + + # area + # average classification accuracies across experiments with the same area; do this for both testing and shuffle data + ave_test_shfl_area = df.groupby('area').mean() + # ste + ne = df.groupby('area').count()['test'].values # number of experiments for each area + nee = np.vstack([ne, ne]).T # set it in a format that can be used to divide std by. + ste_test_shfl_area = df[['area', 'test', 'shfl']].groupby('area').std() / np.sqrt(nee) + + + ############################## + # set a df like resp_amp_sum_df, but each row will be a given cre, exp level, binned_depth + # set another df just like this one, but for areas + + # binned depth + # cntd = -1 + for j in range(ave_test_shfl_binned_depth.shape[0]): # loop through the 4 binned depths + cntd = cntd + 1 + + resp_amp_sum_df_depth.at[cntd, 'cre'] = cre + resp_amp_sum_df_depth.at[cntd, 'experience_level'] = exp_level_all[i] + + resp_amp_sum_df_depth.at[cntd, 'binned_depth'] = ave_test_shfl_binned_depth.index[j] + resp_amp_sum_df_depth.at[cntd, 'test_av'] = ave_test_shfl_binned_depth['test'].iloc[j] + resp_amp_sum_df_depth.at[cntd, 'shfl_av'] = ave_test_shfl_binned_depth['shfl'].iloc[j] + resp_amp_sum_df_depth.at[cntd, 'test_sd'] = ste_test_shfl_binned_depth['test'].iloc[j] + resp_amp_sum_df_depth.at[cntd, 'shfl_sd'] = ste_test_shfl_binned_depth['shfl'].iloc[j] + + + # area + # cnta = -1 + for j in range(ave_test_shfl_area.shape[0]): # loop through the 2 areas + cnta = cnta + 1 + + resp_amp_sum_df_area.at[cnta, 'cre'] = cre + resp_amp_sum_df_area.at[cnta, 'experience_level'] = exp_level_all[i] + + resp_amp_sum_df_area.at[cnta, 'area'] = ave_test_shfl_area.index[j] + resp_amp_sum_df_area.at[cnta, 'test_av'] = ave_test_shfl_area['test'].iloc[j] + resp_amp_sum_df_area.at[cnta, 'shfl_av'] = ave_test_shfl_area['shfl'].iloc[j] + resp_amp_sum_df_area.at[cnta, 'test_sd'] = ste_test_shfl_area['test'].iloc[j] + resp_amp_sum_df_area.at[cnta, 'shfl_sd'] = ste_test_shfl_area['shfl'].iloc[j] + + + \ No newline at end of file diff --git a/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice3_resp_sum_area_depth.py b/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice3_resp_sum_area_depth.py new file mode 100644 index 000000000..085a8e0cf --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice3_resp_sum_area_depth.py @@ -0,0 +1,190 @@ +""" +Gets called in svm_images_plots_setVars.py + +Here, we use svm_df from all projects to set resp_amp_sum_df for area and depth comparison. The dfs include the mean and stdev of decoding magnitude (aka response amplitude) across all experiments of all sessions with the same binned depth or the same brain area. + +We also compute ttest and p-value between areas/ depth for each experience level and cre line. + +svm_images_plots_compare_experience_levels_area_depth.py will use the vars set here to make plots. + +Vars needed here are set in svm_images_plots_setVars_sumMice3_svmdf.py + +Created on Fri Oct 29 22:02:05 2021 +@author: farzaneh + +""" + +import scipy.stats as st + +################################################################################################ +### Create a dataframe: resp_amp_sum_df, that includes the mean and sterr of response amplitude across all experiments of all sessions +################################################################################################ + +# svm_df_all = pd.concat(svm_df_allpr) # concatenate data from all project codes + +####### get svm_df only for mesoscope data; because we make area/depth plots only for ms data. + +svm_df_ms = svm_df_allpr[2] # run the code below for a single project code +print(len(svm_df_ms)) + +exp_level_all = svm_df_ms['experience_levels'].unique() + +cres = ['Slc17a7', 'Sst', 'Vip'] + +################################################################################################ +### The following will be used for making area & depth comparison plots: +### Create dataframes: resp_amp_sum_df_depth & resp_amp_sum_df_area. +### they include the mean and sterr of response amplitude across all experiments of all sessions with the same binned depth (resp_amp_sum_df_depth), or the same area (resp_amp_sum_df_area). +################################################################################################ + +p_depth = np.full((len(cres), len(exp_level_all)), np.nan) # p value for superficial vs deep layer comparison of class accuracy +p_area = np.full((len(cres), len(exp_level_all)), np.nan) # p value for V1 vs LM area comparison of class accuracy +p_depth_area_df = pd.DataFrame() +resp_amp_sum_df_depth = pd.DataFrame() +resp_amp_sum_df_area = pd.DataFrame() +icre = -1 +cnt = -1 +cntd = -1 +cnta = -1 +for cre in cres: # cre = cres[0] + icre = icre+1 + for i in range(len(exp_level_all)): # i=0 + cnt = cnt+1 + + # svm_df for a given cre and experience level + thiscre = svm_df_ms[svm_df_ms['cre_allPlanes']==cre] + thiscre = thiscre[thiscre['experience_levels']==exp_level_all[i]] + print(len(thiscre)) + + + # area + area_all = thiscre['area_allPlanes'].values + + # binned depth + binned_depth_all = thiscre['binned_depth'].values + + # testing data + test_all = np.array([thiscre[ 'peak_amp_allPlanes_allExp'].iloc[ii][1] for ii in range(len(thiscre))]) + + # shuffled data + shfl_all = np.array([thiscre[ 'peak_amp_allPlanes_allExp'].iloc[ii][2] for ii in range(len(thiscre))]) + + # number of experiments + nexp = sum(~np.isnan(test_all)) + + + ############################## + # create a dataframe for the above vars + dff = pd.DataFrame() + + dff['area'] = area_all + + # use 4 binned depth +# dff['binned_depth'] = binned_depth_all + + # create 2 binned depths: <200 and >200um; we will just label them as 100 and 300um depth. + bd2 = binned_depth_all + bd2[binned_depth_all<200] = 100 + bd2[binned_depth_all>200] = 300 + dff['binned_depth'] = bd2 + + dff['test'] = test_all + dff['shfl'] = shfl_all + + ############################## + # compute ttest and p-value between areas/ depth for each experience level and cre line + + # depth + a_amp = np.vstack(dff[dff['binned_depth']==100]['test']).flatten() + b_amp = np.vstack(dff[dff['binned_depth']==300]['test']).flatten() + + print(a_amp.shape, b_amp.shape) + print(sum(~np.isnan(a_amp)), sum(~np.isnan(b_amp))) + + _, p = st.ttest_ind(a_amp, b_amp, nan_policy='omit') #, axis=1, equal_var=equal_var) + p_depth[icre, i] = p + + + # area + a_amp = np.vstack(dff[dff['area']=='VISl']['test']).flatten() + b_amp = np.vstack(dff[dff['area']=='VISp']['test']).flatten() + + print(a_amp.shape, b_amp.shape) + print(sum(~np.isnan(a_amp)), sum(~np.isnan(b_amp))) + + _, p = st.ttest_ind(a_amp, b_amp, nan_policy='omit') #, axis=1, equal_var=equal_var) + p_area[icre, i] = p + + + # set a df to keep p values + p_depth_area_df.at[cnt, 'cre'] = cre + p_depth_area_df.at[cnt, 'exp_level'] = exp_level_all[i] + + p_depth_area_df.at[cnt, 'p_depth'] = p_depth[icre, i] + p_depth_area_df.at[cnt, 'p_area'] = p_area[icre, i] + +# df_new = pd.concat([p_depth_area_df, pd.DataFrame(p_depth)], axis=1) + + ############################## + # compute averages across experiments with the same depth/are + + # binned depth + # average classification accuracies across experiments with the same binned depth; do this for both testing and shuffle data + ave_test_shfl_binned_depth = dff.groupby('binned_depth').mean() + # ste (note that count function does not count NaN vals) + ne = dff.groupby('binned_depth').count()['test'].values # number of experiments for each area + nee = np.vstack([ne, ne]).T # set it in a format that can be used to divide std by. + ste_test_shfl_binned_depth = dff.groupby('binned_depth').std() / np.sqrt(nee) + + # area + # average classification accuracies across experiments with the same area; do this for both testing and shuffle data + ave_test_shfl_area = dff.groupby('area').mean() + # ste + ne = dff.groupby('area').count()['test'].values # number of experiments for each area + nee = np.vstack([ne, ne]).T # set it in a format that can be used to divide std by. + ste_test_shfl_area = dff[['area', 'test', 'shfl']].groupby('area').std() / np.sqrt(nee) + + + ############################## + # set a df like resp_amp_sum_df, but each row will be a given cre, exp level, binned_depth + # set another df just like this one, but for areas + + # binned depth + # cntd = -1 + for j in range(ave_test_shfl_binned_depth.shape[0]): # loop through the 4 binned depths + cntd = cntd + 1 + + resp_amp_sum_df_depth.at[cntd, 'cre'] = cre + resp_amp_sum_df_depth.at[cntd, 'experience_level'] = exp_level_all[i] + + resp_amp_sum_df_depth.at[cntd, 'binned_depth'] = ave_test_shfl_binned_depth.index[j] + resp_amp_sum_df_depth.at[cntd, 'test_av'] = ave_test_shfl_binned_depth['test'].iloc[j] + resp_amp_sum_df_depth.at[cntd, 'shfl_av'] = ave_test_shfl_binned_depth['shfl'].iloc[j] + resp_amp_sum_df_depth.at[cntd, 'test_sd'] = ste_test_shfl_binned_depth['test'].iloc[j] + resp_amp_sum_df_depth.at[cntd, 'shfl_sd'] = ste_test_shfl_binned_depth['shfl'].iloc[j] + + + # area + # cnta = -1 + for j in range(ave_test_shfl_area.shape[0]): # loop through the 2 areas + cnta = cnta + 1 + + resp_amp_sum_df_area.at[cnta, 'cre'] = cre + resp_amp_sum_df_area.at[cnta, 'experience_level'] = exp_level_all[i] + + resp_amp_sum_df_area.at[cnta, 'area'] = ave_test_shfl_area.index[j] + resp_amp_sum_df_area.at[cnta, 'test_av'] = ave_test_shfl_area['test'].iloc[j] + resp_amp_sum_df_area.at[cnta, 'shfl_av'] = ave_test_shfl_area['shfl'].iloc[j] + resp_amp_sum_df_area.at[cnta, 'test_sd'] = ste_test_shfl_area['test'].iloc[j] + resp_amp_sum_df_area.at[cnta, 'shfl_sd'] = ste_test_shfl_area['shfl'].iloc[j] + + +#%% Add sig columns to p_depth_area_df + +p_depth_area_df['sig_depth'] = p_depth_area_df['p_depth']<=sigval +p_depth_area_df.loc[p_depth_area_df['sig_depth']==False, 'sig_depth'] = np.nan + +p_depth_area_df['sig_area'] = p_depth_area_df['p_area']<=sigval +p_depth_area_df.loc[p_depth_area_df['sig_area']==False, 'sig_area'] = np.nan + + diff --git a/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice3_svmdf.py b/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice3_svmdf.py new file mode 100644 index 000000000..f3e4dd80e --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_setVars_sumMice3_svmdf.py @@ -0,0 +1,225 @@ +""" +Gets called in svm_images_plots_setVars.py + +Here, we set svm_df, a proper pandas table, that will be used to make summary plots for experience levels in svm_images_plots_compare_ophys_experience_levels.py + +Created on Fri Oct 29 22:02:05 2021 +@author: farzaneh + +""" + + +if project_code == ['VisualBehaviorMultiscope']: + num_planes = 8 +else: + num_planes = 1 + + +########################################################################################## +########################################################################################## +############# Create svm_df, a proper pandas table ####################################### +############# we will use it to make summary plots for experience levels ################ +########################################################################################## +########################################################################################## + +#%% Function to concatenate data in svm_allMice_sessPooled0 in the following way: +# concatenate data from plane 1 all sessions, then plane 2 all sessions, then plane 3 all sessions,..., then plane 8 all sessions. Therefore, first data from one area (the first 4 planes), then data from another area (the last 4 planes) + +def concatall(df, col): + # df = svm_allMice_sessPooled0.copy() + # col = 'av_test_data_allPlanes' + # df[col].iloc[0].shape # sess or planes x sess or planes x sess x time (it must have ) + + df = df.copy() + + if np.ndim(df[col].iloc[0])==1: # data is for all sessions but only 1 plane; we need to replicate it so the size becomes planes x sessions + if project_code == ['VisualBehaviorMultiscope']: + for i in range(df.shape[0]): #i=0 + df[col].iloc[i] = [df[col].iloc[i][:] for j in range(8)] # planes x sess + else: + for i in range(df.shape[0]): #i=0 + df[col].iloc[i] = df[col].iloc[i][np.newaxis,:] # 1 x sess + + a = np.concatenate((df[col].iloc[0])) +# print(a.shape) + for i in np.arange(1, df.shape[0]): #i=0 + a = np.concatenate((a, np.concatenate((df[col].iloc[i])))) + print(a.shape) + a = list(a) # we do this because the matrix that we want to assign to a column of df at once has to be a LIST… it cannot be an array. + + return(a) + + + + +################################################ +################################################ +################################################ +################################################ +#%% bin depths into 4 groups, and add a corresponding column to df + +def add_binned_depth_column(df, depth_col='depth_allPlanes'): + """ + for a dataframe with column 'depth', created by the function add_depth_per_container, + bin the depth values into 100um bins and assign the mean depth for each bin + :param df: + :return: + """ + df.loc[:, 'binned_depth'] = None + + indices = df[(df[depth_col] < 100)].index.values + df.loc[indices, 'binned_depth'] = 75 + + indices = df[(df[depth_col] >= 100) & + (df[depth_col] < 200)].index.values + df.loc[indices, 'binned_depth'] = 175 + + indices = df[ + (df[depth_col] >= 200) & (df[depth_col] < 300)].index.values + df.loc[indices, 'binned_depth'] = 275 + + indices = df[ + (df[depth_col] >= 300) & (df[depth_col] < 500)].index.values + df.loc[indices, 'binned_depth'] = 375 + + return df + + + + + + +################################################ +################################################ +################################################ +################################################ +#%% Initiate svm_df out of svm_allMice_sessPooled0. The idea is to create a proper pandas table out of the improper table svm_allMice_sessPooled0!!! Proper because each entry is for one experiment! +# rows in svm_df are like: plane 1 all sessions, then plane 2 all sessions, etc + +svm_df = pd.DataFrame() +cnt = -1 +for i in range(svm_allMice_sessPooled0.shape[0]): #i=0 # go through each row of svm_allMice_sessPooled0, ie an ophys stage + nsess = len(svm_allMice_sessPooled0['experience_levels'].iloc[i]) + for iplane in range(num_planes): #iplane=0 + for isess in range(nsess): #isess=0 + cnt = cnt + 1 + svm_df.at[cnt, 'project_code'] = project_code + session_id = svm_allMice_sessPooled0['session_ids'].iloc[i][iplane, isess] + experiment_id = all_sess0[all_sess0['session_id']==session_id]['experiment_id'].iloc[iplane] + + svm_df.at[cnt, 'session_id'] = session_id + svm_df.at[cnt, 'experiment_id'] = experiment_id + svm_df.at[cnt, 'session_labs'] = svm_allMice_sessPooled0['session_labs'].iloc[i][0] + +# svm_df.head(300) + + +################################################ +#%% For the rest of the columns we create an entire array/matrix and then add it to the df; as opposed to looping over each value: + +#%% Array columns; ie each entry in df is 1 element + +# create arrays/matrices for each column of df +cre_allPlanes_allExp = concatall(svm_allMice_sessPooled0, 'cre_allPlanes') +mouse_id_allPlanes_allExp = concatall(svm_allMice_sessPooled0, 'mouse_id_allPlanes') +area_allPlanes_allExp = concatall(svm_allMice_sessPooled0, 'area_allPlanes') +depth_allPlanes_allExp = concatall(svm_allMice_sessPooled0, 'depth_allPlanes') +experience_level_allExp = concatall(svm_allMice_sessPooled0, 'experience_levels') +# create matrix columns +av_test_data_allPlanes_allExp = concatall(svm_allMice_sessPooled0, 'av_test_data_allPlanes') +av_test_shfl_allPlanes_allExp = concatall(svm_allMice_sessPooled0, 'av_test_shfl_allPlanes') +peak_amp_allPlanes_allExp = concatall(svm_allMice_sessPooled0, 'peak_amp_allPlanes') +# session_id_allExp = concatall(svm_allMice_sessPooled0, 'session_ids') +# session_labs_allExp = concatall(svm_allMice_sessPooled0, 'session_labs') # we cant use it with the function concatall because svm_allMice_sessPooled0['session_labs'] is only for 1 session. + +# now add columns at once to svm_df +svm_df['cre_allPlanes'] = cre_allPlanes_allExp +svm_df['mouse_id_allPlanes'] = mouse_id_allPlanes_allExp +svm_df['area_allPlanes'] = area_allPlanes_allExp +svm_df['depth_allPlanes'] = depth_allPlanes_allExp +svm_df = add_binned_depth_column(svm_df) +svm_df['experience_levels'] = experience_level_allExp +svm_df['av_test_data_allPlanes'] = av_test_data_allPlanes_allExp +svm_df['av_test_shfl_allPlanes'] = av_test_shfl_allPlanes_allExp +svm_df['peak_amp_allPlanes_allExp'] = peak_amp_allPlanes_allExp + +# svm_df #.head(300) +print(np.shape(svm_df)) + +svm_df0 = copy.deepcopy(svm_df) + +# svm_allMice_sessPooled0.keys() + + + +""" +Gets called in svm_images_plots_setVars.py + +Here, we use svm_df from all projects to set resp_amp_sum_df, a df that includes the mean and stdev of decoding magnitude (aka response amplitude) across all experiments of all sessions + +Vars needed here are set in svm_images_plots_setVars_sumMice3_svmdf.py + +Created on Fri Oct 29 22:02:05 2021 +@author: farzaneh + +""" + + + +### Note, when pooling across projects, we dont really use below. We call the codes below in a separate script, which sets resp_amp_sum_df for svm_df_allpr (ie svm_df pooled across all project codes) +# but we still need to keep this part because it gets called in line 582 of svm_images_plots_setVars.py. + +################################################################################################ +### Create a dataframe: resp_amp_sum_df, that includes the mean and stdev of response amplitude across all experiments of all sessions +################################################################################################ + +exp_level_all = svm_df['experience_levels'].unique() +cresdf = svm_df['cre_allPlanes'].unique() +resp_amp_sum_df = pd.DataFrame() + +cnt = -1 +for cre in cresdf: # cre = cresdf[0] + for i in range(len(exp_level_all)): # i=0 + cnt = cnt+1 + + # svm_df for a given cre and experience level + thiscre = svm_df[svm_df['cre_allPlanes']==cre] + thiscre = thiscre[thiscre['experience_levels']==exp_level_all[i]] + print(len(thiscre)) + + depthav = thiscre['depth_allPlanes'].mean() +# areasu = thiscre['area_allPlanes'].unique() + ampall = np.vstack(thiscre['peak_amp_allPlanes_allExp']) # ampall.shape # exp x 4 # pooled_experiments x 4_trTsShCh + nexp = sum(~np.isnan(ampall[:,1])) + + # testing data + testav = np.nanmean(ampall[:,1]) + testsd = np.nanstd(ampall[:,1]) / np.sqrt(nexp) #ampall[:,1].shape[0]) + + # shuffled + shflav = np.nanmean(ampall[:,2]) + shflsd = np.nanstd(ampall[:,2]) / np.sqrt(nexp) # ampall[:,2].shape[0] + + # create the summary df + resp_amp_sum_df.at[cnt, 'cre'] = cre + resp_amp_sum_df.at[cnt, 'experience_level'] = exp_level_all[i] + resp_amp_sum_df.at[cnt, 'depth_av'] = depthav + resp_amp_sum_df.at[cnt, 'n_experiments'] = nexp + + resp_amp_sum_df.at[cnt, 'test_av'] = testav + resp_amp_sum_df.at[cnt, 'test_sd'] = testsd + resp_amp_sum_df.at[cnt, 'shfl_av'] = shflav + resp_amp_sum_df.at[cnt, 'shfl_sd'] = shflsd + +resp_amp_sum_df +# [areasu for x in resp_amp_sum_df['cre']] + + + + + + + + + + diff --git a/visual_behavior/decoding_population/svm_images_plots_sumMice.py b/visual_behavior/decoding_population/svm_images_plots_sumMice.py new file mode 100644 index 000000000..877cfb1c2 --- /dev/null +++ b/visual_behavior/decoding_population/svm_images_plots_sumMice.py @@ -0,0 +1,425 @@ +""" +Gets called in svm_images_plots_setVars.py. + +Vars needed here are set in "svm_images_plots_setVars_sumMice.py" +Make summary plots across mice (each cre line) for the svm analysis. + +Created on Wed Oct 21 15:22:05 2020 +@author: farzaneh + +""" + + +if plots_make_finalize[0] == 1: + + ################################################################ + ############################### V1 ############################### + # h1v1 = [] + if ~np.isnan(inds_v1[0]): + for iplane in inds_v1: # iplane=inds_v1[0] # iplane=0 + + ax = plt.subplot(gs1[0]) # plt.subplot(2,1,2) + + area = areas[iplane] # num_sess + if project_codes == ['VisualBehaviorMultiscope']: + depth = depths[iplane] # num_sess + else: + depth = depth_ave[0] + lab = '%dum' %(np.mean(depth)) + if ~np.isnan(svm_blocks) and svm_blocks!=-101: + lab = f'{lab},{lab_b}' + + h1_0 = plt.plot(time_trace, av_ts_eachPlane[iplane], color=cols_depth[iplane-num_planes], label=(lab), markersize=3.5, linestyle=linestyle_now)[0] + h2 = plt.plot(time_trace, av_sh_eachPlane[iplane], color='gray', label='shfl', markersize=3.5)[0] + + # errorbars (standard error across cv samples) + ''' + plt.fill_between(time_trace, av_ts_eachPlane[iplane] - sd_ts_eachPlane[iplane], av_ts_eachPlane[iplane] + sd_ts_eachPlane[iplane], alpha=alph, edgecolor=cols_depth[iplane-num_planes], facecolor=cols_depth[iplane-num_planes]) + plt.fill_between(time_trace, av_sh_eachPlane[iplane] - sd_sh_eachPlane[iplane], av_sh_eachPlane[iplane] + sd_sh_eachPlane[iplane], alpha=alph, edgecolor='gray', facecolor='gray') + ''' + h1v1.append(h1_0) + + + + ################################################################ + ############################### LM ############################### + # h1lm = [] + if ~np.isnan(inds_lm[0]): + for iplane in inds_lm: #range(4): # iplane = 0 + ax = plt.subplot(gs1[1]) # plt.subplot(2,1,1) + + area = areas[iplane] # num_sess + if project_codes == ['VisualBehaviorMultiscope']: + depth = depths[iplane] # num_sess + else: + depth = depth_ave[0] + lab = '%dum' %(np.mean(depth)) + if ~np.isnan(svm_blocks) and svm_blocks!=-101: + lab = f'{lab},{lab_b}' + + h1_0 = plt.plot(time_trace, av_ts_eachPlane[iplane], color=cols_depth[iplane], label=(lab), markersize=3.5, linestyle=linestyle_now)[0] + h2 = plt.plot(time_trace, av_sh_eachPlane[iplane], color='gray', label='shfl', markersize=3.5)[0] + + # errorbars (standard error across cv samples) + ''' + plt.fill_between(time_trace, av_ts_eachPlane[iplane] - sd_ts_eachPlane[iplane], av_ts_eachPlane[iplane] + sd_ts_eachPlane[iplane], alpha=alph, edgecolor=cols_depth[iplane], facecolor=cols_depth[iplane]) + plt.fill_between(time_trace, av_sh_eachPlane[iplane] - sd_sh_eachPlane[iplane], av_sh_eachPlane[iplane] + sd_sh_eachPlane[iplane], alpha=alph, edgecolor='gray', facecolor='gray') + ''' + h1lm.append(h1_0) + + + + + if project_codes == ['VisualBehaviorMultiscope']: + ################################################################ + #%% Plot traces per area (pooled across sessions and layers for each area) + # Question 1: is there a difference between areas (V1 vs LM) # for each mouse pool across sessions and layers (for each area) + ################################################################ + + # trace: average across all pooled sessions for each plane + a = ts_eachArea[:, cre_eachArea[0,:]==cre] # 2 x (4*thisCre_pooledSessNum) x 80 + av_ts_pooled_eachArea = np.nanmean(a, axis=1) # 2 x 80 + sd_ts_pooled_eachArea = np.nanstd(a, axis=1) / np.sqrt(a.shape[1]) # 2 x 80 + + a = sh_eachArea[:, cre_eachArea[0,:]==cre] # 2 x (4*thisCre_pooledSessNum) x 80 + av_sh_pooled_eachArea = np.nanmean(a, axis=1) # 2 x 80 + sd_sh_pooled_eachArea = np.nanstd(a, axis=1) / np.sqrt(a.shape[1]) # 2 x 80 + + ################## + ax = plt.subplot(gs2[0]) + # ax = plt.subplot(gs1[2,0]) + plt.title('Sessions and layers pooled', fontsize=13, y=1) + + # h1a = [] + for iarea in [1,0]: # first plot V1 then LM #range(a.shape[0]): + lab = '%s' %(distinct_areas[iarea]) + if ~np.isnan(svm_blocks) and svm_blocks!=-101: + lab = f'{lab},{lab_b}' + + h1_0 = plt.plot(time_trace, av_ts_pooled_eachArea[iarea], color = cols_area_now[iarea], label=(lab), markersize=3.5, linestyle=linestyle_now)[0] + h2 = plt.plot(time_trace, av_sh_pooled_eachArea[iarea], color='gray', label='shfl', markersize=3.5)[0] + + ''' + plt.fill_between(time_trace, av_ts_pooled_eachArea[iarea] - sd_ts_pooled_eachArea[iarea] , \ + av_ts_pooled_eachArea[iarea] + sd_ts_pooled_eachArea[iarea], alpha=alph, edgecolor=cols_area_now[iarea], facecolor=cols_area_now[iarea]) + plt.fill_between(time_trace, av_sh_pooled_eachArea[iarea] - sd_sh_pooled_eachArea[iarea] , \ + av_sh_pooled_eachArea[iarea] + sd_sh_pooled_eachArea[iarea], alpha=alph, edgecolor='gray', facecolor='gray') + ''' + h1a.append(h1_0) + ''' + lims = np.array([np.nanmin(av_sh_pooled_eachArea - sd_sh_pooled_eachArea), \ + np.nanmax(av_ts_pooled_eachArea + sd_ts_pooled_eachArea)]) + lims[0] = lims[0] - np.diff(lims) / 20. + lims[1] = lims[1] + np.diff(lims) / 20. + ''' + lims = [] + + + ################################################################ + #%% Plot traces per depth (pooled across sessions and areas for each depth) + # Question 2: is there a difference between superficial and deep layers # for each mouse pool across sessions and area (for each layer)... also pool 2 superifical (deep) layers into 1 + ################################################################ + + # trace: average across all pooled sessions for each plane + a = ts_eachDepth[:, cre_eachDepth[0,:]==cre] # 4 x (2*thisCre_pooledSessNum) x 80 + av_ts_pooled_eachDepth = np.nanmean(a, axis=1) # 4 x 80 + sd_ts_pooled_eachDepth = np.nanstd(a, axis=1) / np.sqrt(a.shape[1]) # 4 x 80 + + a = sh_eachDepth[:, cre_eachDepth[0,:]==cre] # 4 x (2*thisCre_pooledSessNum) x 80 + av_sh_pooled_eachDepth = np.nanmean(a, axis=1) # 4 x 80 + sd_sh_pooled_eachDepth = np.nanstd(a, axis=1) / np.sqrt(a.shape[1]) # 4 x 80 + + depth_ave = np.mean(depth_eachDepth[:, cre_eachDepth[0,:]==cre], axis=1).astype(float) # 4 # average across areas and sessions + + + ################## + ax = plt.subplot(gs2[1]) + # ax = plt.subplot(gs1[2,1]) + plt.title('Sessions and areas pooled', fontsize=13, y=1) + + # h1d = [] + for idepth in range(a.shape[0]): + lab = '%d um' %(depth_ave[idepth]) + if ~np.isnan(svm_blocks) and svm_blocks!=-101: + lab = f'{lab},{lab_b}' + + h1_0 = plt.plot(time_trace, av_ts_pooled_eachDepth[idepth], color = cols_depth[idepth], label=(lab), markersize=3.5, linestyle=linestyle_now)[0] + h2 = plt.plot(time_trace, av_sh_pooled_eachDepth[idepth], color='gray', label='shfl', markersize=3.5)[0] # gray + ''' + plt.fill_between(time_trace, av_ts_pooled_eachDepth[idepth] - sd_ts_pooled_eachDepth[idepth] , \ + av_ts_pooled_eachDepth[idepth] + sd_ts_pooled_eachDepth[idepth], alpha=alph, edgecolor=cols_depth[idepth], facecolor=cols_depth[idepth]) + plt.fill_between(time_trace, av_sh_pooled_eachDepth[idepth] - sd_sh_pooled_eachDepth[idepth] , \ + av_sh_pooled_eachDepth[idepth] + sd_sh_pooled_eachDepth[idepth], alpha=alph, edgecolor='gray', facecolor='gray') + ''' + h1d.append(h1_0) + + ''' + lims = np.array([np.nanmin(av_sh_pooled_eachDepth - sd_sh_pooled_eachDepth), \ + np.nanmax(av_ts_pooled_eachDepth + sd_ts_pooled_eachDepth)]) + lims[0] = lims[0] - np.diff(lims) / 20. + lims[1] = lims[1] + np.diff(lims) / 20. + ''' + lims = [] + + + + #################################################################################### + #################################################################################### + #%% Plot response amplitude + # per depth; two areas in two subplots + #################################################################################### + #################################################################################### + + ## remember svm peak quantification vars are for training, testing, shuffle, and chance data: trTsShCh + + xlabs = 'Depth (um)' + x = np.arange(num_depth) + xticklabs = np.round(depth_ave).astype(int) + + + ######################################################## + #%% Image responses + + # left plot: omission, response amplitude + # if baseline_subtract: # subtract the baseline (CA average during baseline, ie before time 0) from the evoked CA (classification accuracy) + # ylabs = '% Class accuracy rel. baseline' #'Amplitude' + # else: + # ylabs = '% Classification accuracy' #'Amplitude' + # x = np.arange(num_depth) + lab1 = 'V1' + if ~np.isnan(svm_blocks) and svm_blocks!=-101: + lab1 = f'{lab1},{lab_b}' + lab2 = 'LM' + if ~np.isnan(svm_blocks) and svm_blocks!=-101: + lab2 = f'{lab2},{lab_b}' + + top = np.nanmean(pa_all[:, cre_all[0,:]==cre], axis=1) + top_sd = np.nanstd(pa_all[:, cre_all[0,:]==cre], axis=1) / np.sqrt(sum(cre_all[0,:]==cre)) + + ax1 = plt.subplot(gs3[0]) + + # testing data + ax1.errorbar(x, top[inds_v1, 1], yerr=top_sd[inds_v1, 1], fmt=fmt_now, markersize=3, capsize=3, label=lab1, color=cols_area_now[1]) + ax1.errorbar(x + xgap_areas, top[inds_lm, 1], yerr=top_sd[inds_lm, 1], fmt=fmt_now, markersize=3, capsize=3, label=lab2, color=cols_area_now[0]) + + # shuffled data + ax1.errorbar(x, top[inds_v1, 2], yerr=top_sd[inds_v1, 2], fmt=fmt_now, markersize=3, capsize=3, color='gainsboro') # label='V1', # gray + ax1.errorbar(x + xgap_areas, top[inds_lm, 2], yerr=top_sd[inds_lm, 2], fmt=fmt_now, markersize=3, capsize=3, color='gainsboro') # label='LM', # skyblue + + # plt.hlines(0, 0, len(x)-1, linestyle=':') + ax1.set_xticks(x) + ax1.set_xticklabels(xticklabs, rotation=45) + ax1.tick_params(labelsize=10) + plt.xlim([-.5, len(x)-.5]) + plt.xlabel(xlabs, fontsize=12) + # plt.ylim(lims0) + # ax1.set_ylabel('%s' %(ylabs), fontsize=12) + # plt.title('%s' %(ylabs), fontsize=12) + # plt.title('Flash', fontsize=13.5, y=1) + ylim = plt.gca().get_ylim(); text_y = ylim[1] + np.diff(ylim)/3 + plt.ylabel(ylabs, fontsize=12) #, labelpad=35) # , rotation=0 + # plt.text(3.2, text_y, 'Omission', fontsize=15) + # ax1.legend(loc=3, bbox_to_anchor=(-.1, 1, 2, .1), ncol=2, frameon=False, mode='expand', borderaxespad=0, fontsize=12, handletextpad=.5) # handlelength=1, + + # plt.legend(loc='center left', bbox_to_anchor=(.97,.8), frameon=False, handlelength=1, fontsize=12) + + # plt.legend(loc='center left', bbox_to_anchor=bb, frameon=False, handlelength=1, fontsize=12) + plt.grid(False) # plt.box(on=None) # plt.axis(True) + seaborn.despine()#left=True, bottom=True, right=False, top=False) + + + + + #################################################################################### + #################################################################################### + #%% Plot response amplitude + # pooled layers; compare two areas + #################################################################################### + #################################################################################### + + xlabs = 'Area' + x = np.arange(len(distinct_areas)) + xticklabs = distinct_areas[[1,0]] # so we plot V1 first, then LM + + + ######################################################## + #%% Image responses + + # left: omission, response amplitude + # if baseline_subtract: # subtract the baseline (CA average during baseline, ie before time 0) from the evoked CA (classification accuracy) + # ylabs = '% Class accuracy rel. baseline' #'Amplitude' + # else: + # ylabs = '% Classification accuracy' + # xlabs = 'Area' + # x = np.arange(len(distinct_areas)) + # xticklabs = xticklabs + lab = 'data' + # lab = f'{lab},{lab_b}' + if ~np.isnan(svm_blocks) and svm_blocks!=-101: + lab = f'{lab_b}' + + top = np.nanmean(pa_eachArea[:, cre_eachArea[0,:]==cre], axis=1)[[1,0]] + top_sd = np.nanstd(pa_eachArea[:, cre_eachArea[0,:]==cre], axis=1)[[1,0]] / np.sqrt(sum(cre_eachArea[0,:]==cre)) + + ax1 = plt.subplot(gs5[0]) + + # testing data + ax1.errorbar(x, top[:,1], yerr=top_sd[:,1], fmt=fmt_now, markersize=3, capsize=3, color=cols_area_now[1], label=lab) + + # shuffled data + ax1.errorbar(x, top[:,2], yerr=top_sd[:,2], fmt=fmt_now, markersize=3, capsize=3, color='gainsboro') # gray # , label='shfl' + + # plt.hlines(0, 0, len(x)-1, linestyle=':') + ax1.set_xticks(x) + ax1.set_xticklabels(xticklabs, rotation=45) + ax1.tick_params(labelsize=10) + plt.xlim([-.5, len(x)-.5]) + plt.xlabel(xlabs, fontsize=12) + # plt.ylim(lims0) + # ax1.set_ylabel('%s' %(ylabs), fontsize=12) + # plt.title('%s' %(ylabs), fontsize=12) + # plt.title('Flash', fontsize=13.5, y=1) + ylim = plt.gca().get_ylim(); text_y = ylim[1] + np.diff(ylim)/3 + plt.ylabel(ylabs, fontsize=12) #, labelpad=30) # , rotation=0 + # plt.text(3.2, text_y, 'Omission', fontsize=15) + # ax1.legend(loc=3, bbox_to_anchor=(-.1, 1, 2, .1), ncol=2, frameon=False, mode='expand', borderaxespad=0, fontsize=12, handletextpad=.5) # handlelength=1, + + # plt.legend(loc='center left', bbox_to_anchor=bb, frameon=False, handlelength=1, fontsize=12) + + plt.grid(False) # plt.box(on=None) # plt.axis(True) + seaborn.despine()#left=True, bottom=True, right=False, top=False) + + + + + + + + + + +################################################################ +################################################################ +# if thisCre_pooledSessNum > 0: # done with both blocks of a given ophys stage + +if plots_make_finalize[1] == 1: + + plt.suptitle('%s, %d mice, %d total sessions: %s' %(cre, thisCre_mice_num, thisCre_pooledSessNum, session_labs_all), fontsize=14) + + + #%% Add title, lines, ticks and legend to all plots + + if project_codes == ['VisualBehaviorMultiscope']: + a = areas[[inds_v1[0], inds_lm[0]], 0] + else: + a = areas_title + + plt.subplot(gs1[0]) +# lims = lims_v1lm + lims = [np.min(np.min(lims_v1lm, axis=1)), np.max(np.max(lims_v1lm, axis=1))] + # i commented below bc for hits_vs_misses it was plotting a weird yellow box, and i didnt spend enough time to figure out why it happens only for hits_vs_misses + plot_flashLines_ticks_legend(lims, h1v1, flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, time_trace, xmjn=xmjn, bbox_to_anchor=bb, ylab=ylabel) + plt.xlim(xlim); + plt.title(a[0], fontsize=13, y=1); # np.unique(area) + # mark time_win: the window over which the response quantification (peak or mean) was computed + lims = plt.gca().get_ylim(); + plt.hlines(lims[1], time_win[0], time_win[1], color='gray') +# plt.ylim([9.9, 60.1]) + + + if ~np.isnan(inds_lm[0]): + plt.subplot(gs1[1]) +# lims = lims_v1lm + # i commented below bc for hits_vs_misses it was plotting a weird yellow box, and i didnt spend enough time to figure out why it happens only for hits_vs_misses + plot_flashLines_ticks_legend(lims, h1lm, flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, time_trace, xmjn=xmjn, ylab=ylabel) + # plt.ylabel('') + plt.xlim(xlim); + plt.title(a[1], fontsize=13, y=1) + # mark time_win: the window over which the response quantification (peak or mean) was computed + lims = plt.gca().get_ylim(); + plt.hlines(lims[1], time_win[0], time_win[1], color='gray') +# plt.hlines(lims[1], flash_win[0], flash_win[1], color='green') + + + + if project_codes == ['VisualBehaviorMultiscope']: + # add flash lines, ticks and legend + plt.subplot(gs2[0]) + lims = [] + # i commented below bc for hits_vs_misses it was plotting a weird yellow box, and i didnt spend enough time to figure out why it happens only for hits_vs_misses + plot_flashLines_ticks_legend(lims, h1a, flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, time_trace, xmjn=xmjn, bbox_to_anchor=bb, ylab=ylabel) + # plt.ylabel('') + plt.xlim(xlim); + # mark time_win: the window over which the response quantification (peak or mean) was computed + lims = plt.gca().get_ylim(); + plt.hlines(lims[1], time_win[0], time_win[1], color='gray') +# plt.hlines(lims[1], flash_win[0], flash_win[1], color='green') + + + plt.subplot(gs2[1]) + lims = [] + # i commented below bc for hits_vs_misses it was plotting a weird yellow box, and i didnt spend enough time to figure out why it happens only for hits_vs_misses + plot_flashLines_ticks_legend(lims, h1d, flashes_win_trace_index_unq_time, grays_win_trace_index_unq_time, time_trace, xmjn=xmjn, bbox_to_anchor=bb, ylab=ylabel) + # plt.ylabel('') + plt.xlim(xlim); + # plt.ylim([10, 55]); # use the same y axis scale for all cell types + # mark time_win: the window over which the response quantification (peak or mean) was computed + lims = plt.gca().get_ylim(); + plt.hlines(lims[1], time_win[0], time_win[1], color='gray') +# plt.hlines(lims[1], flash_win[0], flash_win[1], color='green') + + + + plt.subplot(gs3[0]) + plt.legend(loc='center left', bbox_to_anchor=(.97,.8), frameon=False, handlelength=1, fontsize=12) + + + + plt.subplot(gs5[0]) + plt.legend(loc='center left', bbox_to_anchor=bb, frameon=False, handlelength=1, fontsize=12) + + + + ################################################################ + ################################################################ + #%% + if dosavefig: + # set figure name +# snn = [str(sn) for sn in session_numbers] +# snn = '_'.join(snn) + snn = istage + whatSess = f'_ophys{snn}' + +# fgn = f'_frames{frames_svm[0]}to{frames_svm[-1]}{whatSess}' + fgn = f'{whatSess}' + if same_num_neuron_all_planes: + fgn = fgn + '_sameNumNeursAllPlanes' + # if ~np.isnan(svm_blocks): + # fgn = fgn + f'_block{iblock}' + + if svm_blocks==-1: + word = 'engaged_disengaged_blocks_' + elif svm_blocks==-101: + word = 'only_engaged_' + elif ~np.isnan(svm_blocks): + word = 'blocks_' + else: + word = '' + + if use_events: + word = word + 'events' + + fgn = f'{fgn}_{word}_frames{frames_svm[0]}to{frames_svm[-1]}' + fgn = fgn + '_ClassAccur' +# if project_codes == ['VisualBehavior']: + fgn = f'{fgn}_{project_codes[0]}' + + nam = f'{cre[:3]}_aveMice_aveSessPooled{fgn}_{now}' + fign = os.path.join(dir0, 'svm', dir_now, nam+fmt) + print(fign) + + + plt.savefig(fign, bbox_inches='tight') # , bbox_extra_artists=(lgd,) + + +