{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# milliPillar Pillar Analysis\n", "\n", "## Last Updated: 8/18/21\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2021-08-18T20:01:40.686500Z", "start_time": "2021-08-18T20:01:39.901179Z" } }, "outputs": [], "source": [ "# Import necessary packages\n", "import os\n", "import glob\n", "import matplotlib.pyplot as plt\n", "import matplotlib.image \n", "import matplotlib.patches\n", "import dlib\n", "import numpy as np\n", "import pandas as pd\n", "import scipy.signal\n", "from pathlib import Path \n", "import warnings\n", "from pandas import ExcelWriter\n", "\n", "warnings.filterwarnings(\"ignore\", category=RuntimeWarning)\n", "\n", "plt.ion()\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2021-08-18T20:01:40.701908Z", "start_time": "2021-08-18T20:01:40.687887Z" } }, "outputs": [], "source": [ "# Select Data to Analyze \n", "main_folder = ''\n", "\n", "# Create a List of .csv Files\n", "file_list = glob.glob(main_folder + \"*csv\")\n", "file_list.sort()\n", "\n", "# Set Frame Rate in FPS\n", "frame_rate = 20\n", "\n", "# Set Pixel to Micron Conversion Factor\n", "microns_per_pixel = 6.5\n", "\n", "# Set the Unloaded Distance Between the Pillar Heads (in microns)\n", "unloaded_distance = 3000\n", "\n", "# Can change this to select from a pop up window" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2021-08-18T20:01:40.717076Z", "start_time": "2021-08-18T20:01:40.702909Z" } }, "outputs": [], "source": [ "# Load Regimen Excel File\n", "regimen_file = ''\n", "regimen = pd.read_excel(regimen_file)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2021-08-18T20:01:40.733100Z", "start_time": "2021-08-18T20:01:40.718078Z" } }, "outputs": [], "source": [ "# Makes sure all CSV files are in the proper configuration \n", "\n", "# Create a List of .csv Files\n", "csv_list = glob.glob(main_folder + \"*.csv\")\n", "csv_names = []\n", "for x in csv_list: \n", " csv_names.append(os.path.splitext(os.path.basename(x))[0]) \n", " \n", "csv_left = glob.glob(main_folder + \"*_left.csv\")\n", "csv_left_names = []\n", "for x in csv_left: \n", " csv_left_names.append(os.path.splitext(os.path.basename(x))[0])\n", " \n", "csv_right = glob.glob(main_folder + \"*_right.csv\")\n", "csv_right_names = []\n", "for x in csv_right: \n", " csv_right_names.append(os.path.splitext(os.path.basename(x))[0])\n", "\n", "# Create a list of .csv files in the correct format \n", "with_left = []\n", "for x in csv_left_names: \n", " with_left.append((os.path.splitext(os.path.basename(x))[0]).replace(\"_left\", \"\"))\n", "with_right = []\n", "for x in csv_right_names: \n", " with_right.append((os.path.splitext(os.path.basename(x))[0]).replace(\"_right\", \"\"))\n", "\n", "correct_csv = list(set.intersection(set(with_left), set(with_right)))\n", "\n", "\n", "# Corrects remaining .csv files and adds them to the list \n", "to_process = list((set(csv_names) - set(csv_right_names)) - set(csv_left_names))\n", "\n", "for x in to_process: \n", " data = data = pd.read_csv(os.path.join(main_folder, x + \".csv\"))\n", "\n", " left_x = data.loc[:, 'Left X']\n", " left_y = data.loc[:, 'Left Y']\n", " right_x = data.loc[:, 'Right X']\n", " right_y = data.loc[:, 'Right Y'] \n", "\n", " left = {'X' : left_x, 'Y': left_y}\n", " left_df = pd.DataFrame(data=left)\n", " right = {'X' : right_x, 'Y' : right_y}\n", " right_df = pd.DataFrame(data=right) \n", "\n", " left_name = os.path.join(main_folder, x + \"_left.csv\")\n", " right_name = os.path.join(main_folder, x + \"_right.csv\")\n", "\n", " left_df.to_csv(left_name)\n", " right_df.to_csv(right_name)\n", "\n", " correct_csv.append(x)\n", "\n", "# Makes list unique and sort\n", "correct_csv = list(set(correct_csv))\n", "correct_csv.sort()\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2021-08-18T20:01:40.749126Z", "start_time": "2021-08-18T20:01:40.734101Z" } }, "outputs": [], "source": [ "correct_csv" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2021-08-18T20:01:40.765131Z", "start_time": "2021-08-18T20:01:40.750128Z" } }, "outputs": [], "source": [ "def load_trace(current_tissue):\n", "\n", " # Display Tissue Name\n", " print(\"Processing Tissue {}\".format(current_tissue))\n", "\n", " # Load Plot Tissue Trace\n", " left_file = os.path.join(main_folder, current_tissue + \"_left.csv\")\n", " right_file = os.path.join(main_folder, current_tissue + \"_right.csv\")\n", " left_data = pd.read_csv(left_file)\n", " right_data = pd.read_csv(right_file) \n", "\n", " # Create New Dataframe \n", " left_x = left_data.loc[:, 'X']\n", " left_y = left_data.loc[:, 'Y']\n", " right_x = right_data.loc[:, 'X']\n", " right_y = right_data.loc[:, 'Y'] \n", " data = {'Left X':left_x, 'Left Y':left_y, 'Right X':right_x, 'Right Y':right_y}\n", " data = pd.DataFrame(data=data)\n", "\n", "\n", " # Add Time Column to DF\n", " time = np.arange(0,(data.shape[0])/frame_rate,(1/frame_rate))\n", " data['Time'] = time\n", "\n", " #Add distance to DF\n", " x_diff = right_x - left_x\n", " y_diff = right_y - left_y \n", " x_diff_sq = np.square(x_diff)\n", " y_diff_sq = np.square(y_diff)\n", " sum_sq = x_diff_sq + y_diff_sq\n", " distance = np.sqrt(sum_sq)\n", " data['Distance'] = distance\n", " \n", " # Add Deflection Column to DF\n", " # Note: deflection refers to the total pillar deflection\n", " deflection = unloaded_distance - (distance * microns_per_pixel)\n", " data['Deflection'] = deflection\n", "\n", " # Plot Deflection\n", " data.plot(x = 'Time', y='Deflection',kind='line', legend=False)\n", " plt.title('Tissue {} Original Full Trace'.format(current_tissue))\n", " plt.ylabel(\"Deflection (Microns)\")\n", " plt.xlabel(\"Time (s)\");\n", " \n", " # Select Spontaneous Beating Region\n", " sp_start = regimen.loc[regimen['Region'] == \"Spontaneous\", 'First Frame'][0]\n", " sp_stop = regimen.loc[regimen['Region'] == \"Spontaneous\", 'Last Frame'][0]\n", " spontaneous = data.iloc[sp_start:sp_stop]\n", " x = spontaneous.loc[:,'Deflection']\n", "\n", " # Determine Baseline Correction Based on Minima for Each Second in Spontaneous Region\n", " seconds = np.arange(sp_start, sp_stop, frame_rate)\n", " num = len(seconds)\n", " mins_deflection = np.zeros(num)\n", " idxs = np.zeros(num)\n", " maxs_distance = np.zeros(num)\n", " for i, x in enumerate(seconds):\n", " min_val = spontaneous.loc[x:(x+frame_rate)].loc[:,'Deflection'].min()\n", " min_index = spontaneous.loc[x:(x+frame_rate)].loc[:,'Deflection'].idxmin()\n", " max_distance = spontaneous.loc[x:(x+frame_rate)].loc[:,'Distance'].max()\n", " mins_deflection[i] = min_val\n", " idxs[i] = min_index\n", " maxs_distance[i] = max_distance\n", "\n", " baseline_deflection_avg = np.mean(mins_deflection)\n", " baseline_distance_avg = np.mean(maxs_distance)\n", "\n", " # Calculate Active Deflection Based on Baseline\n", " active_deflection = data.loc[:,'Deflection'] - baseline_deflection_avg\n", " data['Active Deflection'] = active_deflection\n", "\n", " # Define Passive Tension and Length\n", " passive_tension = baseline_deflection_avg\n", " passive_length = baseline_distance_avg\n", "\n", " # Calculate Velocity and Add to Data\n", " velocity = (pd.Series(data=deflection).diff())/(1/frame_rate)\n", " data['Velocity'] = velocity\n", "\n", " # Differentiate Contraction and Relaxation Velocity \n", " data['Contraction Velocity'] = velocity\n", " data['Contraction Velocity'][data['Contraction Velocity']<0]=0\n", " data['Relaxation Velocity'] = velocity \n", " data['Relaxation Velocity'][data['Relaxation Velocity']>0]=0\n", " data['Relaxation Velocity'] = abs(data['Relaxation Velocity'])\n", "\n", " # Replace all NaNs with 0 \n", " data = data.fillna(0)\n", "\n", " # Calculate Max Values \n", " max_contraction_velocity = max(data['Contraction Velocity'])\n", " max_relaxation_velocity = max(data['Relaxation Velocity'])\n", " max_deflection = max(data['Deflection'])\n", " max_active_deflection = max(data['Active Deflection'])\n", "\n", " # Create Dict for Results \n", "\n", " results = { 'Tissue':[current_tissue], \n", " 'Passive Tension':[passive_tension], \n", " 'Passive Length':[passive_length], \n", " 'Max Contraction Velocity':[max_contraction_velocity], \n", " 'Max Relaxation Velocity':[max_relaxation_velocity], \n", " 'Max Deflection':[max_deflection], \n", " 'Max Active Deflection':[max_active_deflection]}\n", "\n", " return data, results\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2021-08-18T20:01:40.781155Z", "start_time": "2021-08-18T20:01:40.766132Z" } }, "outputs": [], "source": [ "def region_contractility(data, tissue, start, stop, set_freq, region_name):\n", " \n", " # Select and Plot Trace Region\n", " region = data.iloc[start:stop]\n", " region.plot(x='Time',y='Active Deflection', kind ='line', legend=False)\n", " plt.title('Tissue {} {} Region'.format(tissue, region_name))\n", " plt.ylabel(\"Active Deflection (Microns)\")\n", " plt.xlabel(\"Time (s)\");\n", "\n", " # Find Range of Signal in Region \n", " max_region = max(region.loc[:,'Active Deflection'])\n", " min_region = min(region.loc[:,'Active Deflection'])\n", " range_region = max_region - min_region\n", "\n", " max_deflection = max(region.loc[:,'Deflection']) \n", "\n", " # Change set_freq for regions without stimulation \n", " if set_freq == 0: \n", " set_freq = 2\n", " else: \n", " set_freq = set_freq\n", "\n", " # Find Peaks in 2nd Half of Region \n", " half_start = int(start + (stop - start)/2)\n", " x_half = region.loc[half_start:stop,'Active Deflection']\n", " x_half_deflection = region.loc[half_start:stop,'Deflection']\n", " peaks, _ = scipy.signal.find_peaks(x_half, distance= ((1/set_freq) * frame_rate)*0.9, height=0, prominence = (range_region/2))\n", " num_peaks = len(peaks)\n", " \n", " # Plot Region Trace with Overlaid Peaks \n", " plt.plot((peaks + half_start)/frame_rate, x_half[peaks + half_start], \"X\")\n", "\n", "\n", " # Determine Amplitude and Deflection of Region Using 2nd Half Peaks\n", " mean_amplitude = np.mean(x_half[peaks + half_start])\n", " mean_deflection = np.mean(x_half_deflection[peaks + half_start])\n", "\n", " # Repeat Peak Finding for Velocity\n", "\n", " # Contraction Velocity \n", " region.plot(x='Time',y='Velocity', kind ='line', legend=False)\n", " plt.title('Tissue {} {} Region'.format(tissue, region_name))\n", " plt.ylabel(\"Velocity (Microns/S)\")\n", " plt.xlabel(\"Time (s)\");\n", "\n", " # Find Range of Velocity in Region \n", " max_contraction_velocity = max(region.loc[:,'Contraction Velocity'])\n", " min_contraction_velocity = min(region.loc[:,'Contraction Velocity'])\n", " range_region = max_contraction_velocity - min_contraction_velocity\n", "\n", " # Find Velocity Peaks in Region \n", " con_vel_peaks, _ = scipy.signal.find_peaks(region.loc[:,'Contraction Velocity'], distance= ((1/set_freq) * frame_rate)*0.9, height=0, prominence = (range_region/2))\n", " \n", " # Plot Region Trace with Overlaid Peaks \n", " plt.plot((con_vel_peaks + start)/frame_rate, region.loc[:,'Contraction Velocity'][start + con_vel_peaks], \"X\")\n", "\n", " # Determine Contraction Velocity of Region Using 2nd Half Peaks\n", " mean_contraction_velocity = np.mean(region.loc[:,'Contraction Velocity'][start + con_vel_peaks])\n", "\n", " #Relaxation Velocity\n", "\n", " # Find Range of Relaxation Velocity in Region \n", " max_relaxation_velocity = max(region.loc[:,'Relaxation Velocity'])\n", " min_relaxation_velocity = min(region.loc[:,'Relaxation Velocity'])\n", " range_region = max_relaxation_velocity - min_relaxation_velocity\n", "\n", " # Find Peaks in Region \n", " relax_vel_peaks, _ = scipy.signal.find_peaks(region.loc[:,'Relaxation Velocity'], distance= ((1/set_freq) * frame_rate)*0.9, height=0, prominence = (range_region/2))\n", " \n", " # Plot Region Trace with Overlaid Peaks \n", " plt.plot((relax_vel_peaks + start)/frame_rate, region.loc[:,'Relaxation Velocity'][start + relax_vel_peaks], \"X\")\n", "\n", "\n", " # Determine Relaxation Velocity of Region Using 2nd Half Peaks\n", " mean_relaxation_velocity = np.mean(region.loc[:,'Relaxation Velocity'][start + relax_vel_peaks])\n", "\n", " # Determine Region Beat Frequency\n", " front = peaks[1:num_peaks]\n", " back = peaks[0:(num_peaks-1)]\n", " periods = front - back \n", " periods = periods / frame_rate\n", " freqs = np.reciprocal(periods)\n", " freq = np.mean(freqs)\n", " \n", " # Determine Max Frequency in Region \n", " if len(freqs) > 0:\n", " max_freq = max(freqs)\n", " else: \n", " max_freq = 0\n", "\n", " # Create list of variables and names for export\n", " variables = [[tissue], [freq], [max_freq], [mean_deflection], [max_deflection], [mean_amplitude], [max_region], [mean_contraction_velocity], [max_contraction_velocity],\n", " [mean_relaxation_velocity], [max_relaxation_velocity]]\n", " headers_general = ['Tissue', 'Frequency', 'Max Frequency', 'Mean Deflection', 'Max Deflection', 'Mean Active Deflection', 'Max Active Deflection', \n", " 'Mean Contraction Velocity', 'Max Contraction Velocity', 'Mean Relaxation Velocity', 'Max Relaxation Velocity']\n", "\n", " # Creates a dict of results \n", " results = dict(zip(headers_general,variables))\n", " \n", " # Returns the Results Dict\n", " return results\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2021-08-18T20:02:10.265116Z", "start_time": "2021-08-18T20:01:40.782154Z" } }, "outputs": [], "source": [ "results_dict = {}\n", "region_names = [] \n", "count = 0 \n", "for x in correct_csv: \n", " data, results = load_trace(x)\n", " tissue = x\n", "\n", " if count==0:\n", " results_overall = pd.DataFrame(results);\n", " else: \n", " results_to_add = pd.DataFrame(results)\n", " results_overall = results_overall.append(results_to_add);\n", " \n", " del results\n", "\n", " for i, row in regimen.iterrows():\n", " start = int(row['First Frame'])\n", " stop = int(row['Last Frame'])\n", " set_freq = row['Freq (Hz)']\n", " region_name = (str(row['Region']) + \" \" + str(set_freq) + \" Hz\")\n", "\n", " results = region_contractility(data, tissue, start, stop, set_freq, region_name)\n", " region_results = pd.DataFrame(results)\n", "\n", " if count == 0: \n", " results_dict[region_name] = region_results\n", " region_names.append(region_name)\n", " else: \n", " results_dict[region_name] = results_dict[region_name].append(region_results)\n", "\n", " # Change count flag \n", " count = 1\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2021-08-18T20:02:10.441078Z", "start_time": "2021-08-18T20:02:10.266117Z" } }, "outputs": [], "source": [ "# Save results to Excel sheet\n", "xlsx_file = os.path.join(main_folder, \"Analysis.xlsx\")\n", "writer = ExcelWriter(xlsx_file)\n", "\n", "# Save 'Overall' results to excel \n", "results_overall.to_excel(writer, sheet_name = 'Overall')\n", "\n", "# Cycle through results for each region \n", "print(region_names)\n", "for x in region_names:\n", " results_dict[x].to_excel(writer, sheet_name = x)\n", " \n", "writer.save()\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2021-08-18T20:02:10.457102Z", "start_time": "2021-08-18T20:02:10.442079Z" } }, "outputs": [], "source": [ "def excitation_threshold(): \n", " \n", " # Select the ET Region \n", " ET_region = regimen.loc[regimen['Region'] == \"ET\"]\n", " \n", " # Iterate Through All Conditions in ET Region \n", " for i, row in ET_region.iterrows():\n", " start = int(row['First Frame'])\n", " stop = int(row['Last Frame'])\n", " set_freq = row['Freq (Hz)']\n", " region_name = (str(row['Region']) + \" \" + str(row['Voltage (V)']) + \" Volt\")\n", " \n", " # Run Region Contractility Function \n", " peaks, mean_amplitude, mean_deflection, freq, max_freq = region_contractility(start, stop, set_freq, region_name)\n", " \n", " # Print Results \n", " print(\"Tissue {} {} Region Frequency is {} Hz\".format(tissue, region_name, freq))\n", " \n", " # Save to CSV? \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2021-08-18T20:02:10.473135Z", "start_time": "2021-08-18T20:02:10.458103Z" } }, "outputs": [], "source": [ "def mcr_ffr(): \n", " MCR_FFR_region = regimen.loc[regimen['Region'] == \"FFR\"]\n", " mcr_ffr_results = []\n", " labels = ['Region Name', 'Frequency', 'Max Frequency', 'Amplitude', 'Deflection']\n", " for i, row in MCR_FFR_region.iterrows():\n", " start = int(row['First Frame'])\n", " stop = int(row['Last Frame'])\n", " set_freq = row['Freq (Hz)']\n", " region_name = (str(row['Region']) + \" \" + str(set_freq) + \" Hz\")\n", " \n", " # Run Region Contractility Function \n", " peaks, mean_amplitude, mean_deflection, freq, max_freq = region_contractility(start, stop, set_freq, region_name)\n", " results = [region_name, freq, max_freq, mean_amplitude, mean_deflection]\n", " mcr_ffr_results.append(dict(zip(labels, results)))\n", " \n", " # Print Results \n", " print(\"Tissue {} {} MCR/FFR Region Frequency is {} Hz\".format(tissue, region_name, freq))\n", " print(\"Tissue {} {} MCR/FFR Region Max Frequency is {} Hz\".format(tissue, region_name, max_freq))\n", " print(\"Tissue {} {} MCR/FFR Region Amplitude is {} Pixels\".format(tissue, region_name, mean_amplitude))\n", " \n", " # Save to CSV? \n", " display(pd.DataFrame(mcr_ffr_results))\n" ] } ], "metadata": { "interpreter": { "hash": "92acebc2cac67854bc57ea04b591980844d50c54480c4b305db492fc3c6159ee" }, "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.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }