123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580 |
- #!/usr/bin/env python
- # coding: utf-8
- import sys
- import os
- import io
- import subprocess
- import numpy as np
- import pandas as pd
- import matplotlib as mpl
- import matplotlib.pyplot as plt
- import scipy.stats as sps
- import scipy.io.wavfile as siowav
- import scipy.signal as sps
- os.makedirs("../output", exist_ok=True)
- ###
- # Global plot settings
- mpl.rcParams["font.family"] = "TeX Gyre Pagella"
- mpl.rcParams["font.size"] = 8
- rst_column_width = 3.3
- rst_total_width = 7
- ###
- # Animals
- ordered_deaf_pups = ["b3", "b5", "b8"]
- deaf_pups = set(ordered_deaf_pups)
- ordered_hearing_pups = ["b2", "b4", "b7"]
- hearing_pups = set(ordered_hearing_pups)
- all_pups = deaf_pups.union(hearing_pups)
- bat_birthdates = pd.DataFrame([("b2", "2017/01/26"),
- ("b4", "2017/01/30"),
- ("b7", "2017/02/08"),
- ("b3", "2017/01/29"),
- ("b5", "2017/02/02"),
- ("b8", "2017/02/08")], columns=["bat", "birthdate"])
- bat_birthdates["birthdate"] = pd.to_datetime(bat_birthdates["birthdate"])
- bat_birthdates.set_index("bat", inplace=True)
- ###
- # Group colors and identity markers
- group_colors = dict(hearing="#e1be6a", deaf="#40b0a6")
- bat_colors = {**{bat: group_colors["deaf"] for bat in deaf_pups},
- **{bat: group_colors["hearing"] for bat in hearing_pups}}
- bat_colors["b4"] = "#9b803e"
- bat_markers = dict(zip(sorted(all_pups), ["P", "o", "*", "s", "X", "D"]))
- ###
- # Load data for juveniles
- pup_sessions = pd.read_csv("../pup_sessions.csv",
- index_col=0, parse_dates=["start_time"])
- pup_calls = pd.read_csv("../pup_calls.csv",
- index_col=[0, 1], parse_dates=["start_time"], na_values=["--"])
- # filter out mothers
- pup_calls = pup_calls[pup_calls["calling_bat"].isin(all_pups)].reset_index()
- # determine ages (in full days) of the calling bats
- birth_dates = bat_birthdates.loc[pup_calls["calling_bat"]]["birthdate"].reset_index(drop=True)
- ages = pup_calls["start_time"] - birth_dates
- pup_calls["calling_bat_age_in_days"] = ages.dt.days
- pup_calls["calling_bat_age_in_weeks"] = ages.dt.days // 7
- pup_calls["call_rms"] = pup_calls["call_rms"] + 55
- pup_calls["calling_bat_deaf"] = pup_calls["calling_bat_deaf"] != 0
- ###
- # Load data for adults
- def single_value(values):
- value_set = set(values)
- if len(value_set) != 1:
- raise ValueError("non-unity set")
- return next(iter(value_set))
- adult_calls = pd.read_csv("../adult_calls.csv",
- parse_dates=["start_time"],
- na_values=["--"],
- dtype=dict(group="category", session_id="int"),
- index_col=["session_id", "call_id"])
- adult_calls["recording_day"] = adult_calls["start_time"].dt.date
- adult_calls["call_rms"] -= adult_calls["call_rms"].min()
- adult_sessions = pd.read_csv("../adult_sessions.csv",
- parse_dates=["start_time"],
- dtype=dict(group="category"),
- index_col=0)
- adult_recording_days = adult_sessions[["group"]] \
- .groupby(adult_sessions["start_time"].dt.date) \
- .agg(single_value)
- adult_recording_days.index.name = "recording_day"
- ###
- # Data that is excluded from the analysis
- # 1. Possible echolocation calls (3 ms or shorter)
- pup_calls = pup_calls[pup_calls["call_duration"] > 3e-3]
- adult_calls = adult_calls[adult_calls["call_duration"] > 3e-3]
- # 2. Sessions that are shorter than 20 minutes
- session_gaps = pup_sessions.sort_values("start_time")["start_time"].diff()
- new_index = session_gaps.index.insert(0, -1)
- new_index = new_index[:-1]
- session_gaps.index = new_index
- session_gaps.drop(-1, inplace=True)
- ids_to_drop = session_gaps[session_gaps < pd.Timedelta(20, "m")].index
- pup_calls = pup_calls[~pup_calls["session_id"].isin(ids_to_drop)]
- pup_sessions = pup_sessions.drop(ids_to_drop)
- ###
- # Last two recordings with mother for pups that have more than others
- # (to ensure the same total recording time for each individual)
- sorted_pup_mother_sessions = pup_sessions[pup_sessions["animal2"].str.startswith("m")] \
- .sort_values("start_time")
- session_counts_with_mothers = sorted_pup_mother_sessions["animal1"].value_counts()
- num_sessions_to_drop = session_counts_with_mothers - session_counts_with_mothers.min()
- ids_to_drop = set()
- for bat, drop_count in num_sessions_to_drop.iteritems():
- if drop_count == 0:
- continue
- this_bat_sessions = sorted_pup_mother_sessions[sorted_pup_mother_sessions["animal1"] == bat]
- ids_to_drop = ids_to_drop.union(this_bat_sessions.tail(drop_count).index)
- pup_calls = pup_calls[~pup_calls["session_id"].isin(ids_to_drop)]
- pup_sessions = pup_sessions.drop(index=ids_to_drop)
- ###
- # Mark pre-deafening calls and sessions
- sorted_pup_mother_sessions = pup_sessions[pup_sessions["animal2"].str.startswith("m")] \
- .sort_values("start_time")
- pup_calls["before_deafening"] = False
- pup_sessions["before_deafening"] = False
- for pup, sessions in sorted_pup_mother_sessions.groupby("animal1"):
- first_id = sessions.index[0]
- pup_sessions.loc[first_id, "before_deafening"] = True
- pup_calls.loc[pup_calls["session_id"] == first_id, "before_deafening"] = True
- ###
- # Compute activity statistics (separately for pups before and after deafening)
- calls_per_pup_and_session = pup_calls.reset_index() \
- .groupby(["calling_bat", "session_id"])[["calling_bat"]].count() \
- / (20*6) # per 10 seconds
- calls_per_pup_and_session.columns = ["calls_per_10s"]
- calls_per_pup_and_session.reset_index(inplace=True)
- session_dates = pup_sessions.loc[calls_per_pup_and_session["session_id"]]["start_time"]
- birth_dates = bat_birthdates.loc[calls_per_pup_and_session["calling_bat"]]["birthdate"]
- calls_per_pup_and_session["calling_bat_age_in_days"] = \
- (session_dates.reset_index(drop=True) - birth_dates.reset_index(drop=True)).dt.days
- calls_per_pup_and_session["calling_bat_age_in_weeks"] = \
- calls_per_pup_and_session["calling_bat_age_in_days"] // 7
- calls_per_pup_and_session = \
- pd.merge(calls_per_pup_and_session, pup_sessions[["before_deafening"]],
- left_on="session_id", right_index=True,)
- calls_per_pup_and_session.loc[:, "calling_bat_deaf"] = \
- calls_per_pup_and_session["calling_bat"].isin(deaf_pups)
- dfs = []
- for before_deafening in [False, True]:
- mask = pup_calls["before_deafening"]
- if not before_deafening:
- mask = ~mask
- gr = pup_calls[mask].groupby(["calling_bat", "calling_bat_age_in_weeks"])
- gr = gr[["call_duration", "mean_aperiodicity", "f0_mean", "call_rms"]]
- params_per_pup_and_week = gr.median()
- params_per_pup_and_week["calls_this_week"] = gr.size()
- mask = calls_per_pup_and_session["before_deafening"]
- if not before_deafening:
- mask = ~mask
- gr = calls_per_pup_and_session[mask].groupby(["calling_bat", "calling_bat_age_in_weeks"])
- params_per_pup_and_week["calls_per_10s"] = gr["calls_per_10s"].mean()
- params_per_pup_and_week.reset_index(inplace=True)
- params_per_pup_and_week["before_deafening"] = before_deafening
- dfs.append(params_per_pup_and_week)
- params_per_pup_and_week = pd.concat(dfs)
- gr = adult_calls.groupby(["group", "session_id"], observed=True)
- calls_per_adult_group_and_session = gr.size().to_frame(name="calls_per_10s").reset_index()
- ###
- # Quantities of extracted data
- print("Total calls by pups: {}\nCalls by deaf pups: {} ({:.1f} %)\nCalls by hearing pups: {} ({:.1f} %)".format(
- len(pup_calls),
- np.sum(pup_calls["calling_bat_deaf"]),
- np.sum(pup_calls["calling_bat_deaf"]) / len(pup_calls) * 100,
- np.sum(~pup_calls["calling_bat_deaf"]),
- np.sum(~pup_calls["calling_bat_deaf"] / len(pup_calls) * 100)))
- print("Total calls by adults: {}\nCalls by deaf adults: {} ({:.1f} %)\nCalls by hearing adults: {} ({:.1f} %)".format(
- len(adult_calls),
- np.sum(adult_calls["group"] == "deaf"),
- np.sum(adult_calls["group"] == "deaf") / len(adult_calls) * 100,
- np.sum(adult_calls["group"] == "hearing"),
- np.sum(adult_calls["group"] == "hearing") / len(adult_calls) * 100))
- ###
- # Run the statistical evaluation
- pup_calls.to_csv("../output/pup_calls_for_model.csv", index=False)
- calls_per_pup_and_session.to_csv("../output/pup_activity_for_model.csv", index=False)
- subprocess.run(["Rscript", "analysis.R"])
- ###
- # Load the p-value table generated by R
- pup_ps = pd.read_csv("../output/pup_model_results.csv", index_col="parameter")
- ###
- # Development trajectory of call parameters
- def plot_trajectories(ax, values, parameter, scale):
- line_artists = {}
- for bat, df in values.groupby("calling_bat"):
- bat_color, bat_marker = bat_colors[bat], bat_markers[bat]
- line_artist, = ax.plot(df["calling_bat_age_in_weeks"] + 1, df[parameter] * scale,
- c=bat_color, linewidth=0.8)
- ax.plot(df["calling_bat_age_in_weeks"] + 1, df[parameter] * scale,
- c=bat_color, marker=bat_marker, markersize=5, clip_on=False,
- markerfacecolor="none", linestyle="")
- line_artists[bat] = line_artist
- return line_artists
- def plot_histograms(ax, values, parameter, scale, y_range,
- p_values=None):
- data = {}
- if "group" in values:
- for group, hearing in [("deaf", False), ("hearing", True)]:
- data[hearing] = (values.loc[values["group"] == group, parameter] * scale).values
- else:
- for hearing, df in values.groupby(values["calling_bat"].isin(hearing_pups)):
- data[hearing] = (df[parameter] * scale).values
- ax.hist([data[True], data[False]], density=True,
- range=y_range, bins=15,
- color=[group_colors["hearing"], group_colors["deaf"]],
- orientation="horizontal", rwidth=0.85)
- if p_values is not None:
- p = p_values.loc[parameter, "p_group_adjusted"]
- if p < 0.05:
- ax.annotate("*", (0.5, 0.6),
- xycoords="axes fraction",
- ha="center")
- def plot_individual_boxplots(ax, values, parameter, scale,
- annotate=False, p_values=None):
- data = []
- bat_groups = []
- bats = []
- for group, individuals in [("deaf", ordered_deaf_pups),
- ("hearing", ordered_hearing_pups)]:
- for bat in individuals:
- data.append(scale * values.loc[values["calling_bat"] == bat, parameter].dropna().values)
- bats.append(bat)
- bat_groups.append(group)
- artists = ax.boxplot(data, vert=True, manage_ticks=False, showfliers=False,
- widths=0.2, positions=np.arange(len(data)) * 0.3,
- patch_artist=True,
- boxprops=dict(linewidth=0.5),
- whiskerprops=dict(linewidth=0.5),
- medianprops=dict(linewidth=1, color="#8c1010"),
- capprops=dict(linewidth=0.5))
- for artist, bat in zip(artists["boxes"], bats):
- artist.set_facecolor(bat_colors[bat])
- if annotate:
- for i, (bat_group, bat) in enumerate(zip(bat_groups, bats)):
- xy_top = artists["whiskers"][2 * i + 1].get_xydata()[1]
- ax.plot(xy_top[0], xy_top[1] + 10, marker=bat_markers[bat],
- c=bat_colors[bat], markerfacecolor="none",
- markersize=3, markeredgewidth=0.5)
- if p_values is not None:
- p = p_values.loc[parameter, "p_group_adjusted"]
- if p < 0.05:
- ax.annotate("*", (0.5, 0.9),
- xycoords="axes fraction",
- ha="center")
- # In[35]:
- def plot_pooled_boxplots(ax, values, parameter, scale):
- data = []
- for group in ["deaf", "hearing"]:
- data.append(scale * values.loc[values["group"] == group, parameter].dropna().values)
- artists = ax.boxplot(data, vert=True, manage_ticks=False, showfliers=False,
- widths=0.75, positions=np.arange(len(data)),
- patch_artist=True,
- boxprops=dict(linewidth=0.5),
- whiskerprops=dict(linewidth=0.5),
- medianprops=dict(linewidth=1, color="#8c1010"),
- capprops=dict(linewidth=0.5))
- for artist, group in zip(artists["boxes"], ["deaf", "hearing"]):
- artist.set_facecolor(group_colors[group])
- call_parameters = [("calls_per_10s", 1, "Vocal activity\n[calls/10 s]", (0, 100), 20),
- ("call_rms", 1, "Amplitude\n[dB]", (0, 54), 12),
- ("call_duration", 1e3, "Duration\n[ms]", (0, 80), 20),
- ("f0_mean", 1e-3, "Fundamental\nfrequency [kHz]", (0, 40), 10),
- ("mean_aperiodicity", 1, "Aperiodicity\n[1]", (0, 1), 0.25)]
- fig_width = rst_total_width
- fig_height = 0.7 * fig_width
- left_margin, right_margin = 0.75, 0.1
- bottom_margin, top_margin = 0.45, 0.45
- spacing = 0.2
- row_height = (fig_height - bottom_margin - top_margin - (len(call_parameters) - 1) * spacing) / len(call_parameters)
- pup_boxplot_width = 0.5
- extra_adult_spacing = 0.1
- adult_boxplot_width = 0.2
- trajectory_width = (fig_width - left_margin - right_margin
- - 2 * pup_boxplot_width - adult_boxplot_width
- - 3 * spacing - 2 * extra_adult_spacing)
- fig = plt.figure(figsize=(fig_width, fig_height))
- roman_numerals = ["I", "II", "III", "IV", "V"]
- for i, (parameter, scale, y_label, y_range, y_tick_interval) in enumerate(reversed(call_parameters)):
- early_ax = fig.add_axes([left_margin / fig_width,
- (bottom_margin + i * (row_height + spacing)) / fig_height,
- pup_boxplot_width / fig_width,
- row_height / fig_height])
- late_ax = fig.add_axes([(left_margin + pup_boxplot_width + spacing) / fig_width,
- (bottom_margin + i * (row_height + spacing)) / fig_height,
- pup_boxplot_width / fig_width,
- row_height / fig_height])
- adult_ax = fig.add_axes([(left_margin + 2 * pup_boxplot_width
- + 2 * spacing + extra_adult_spacing) / fig_width,
- (bottom_margin + i * (row_height + spacing)) / fig_height,
- adult_boxplot_width / fig_width,
- row_height / fig_height])
- trajectory_ax = fig.add_axes([(left_margin + 2 * pup_boxplot_width
- + adult_boxplot_width + 3 * spacing
- + 2 * extra_adult_spacing) / fig_width,
- (bottom_margin + i * (row_height + spacing)) / fig_height,
- trajectory_width / fig_width,
- row_height / fig_height])
- overall_ax = fig.add_axes([left_margin / fig_width,
- (bottom_margin + i * (row_height + spacing)) / fig_height,
- (fig_width - left_margin - right_margin) / fig_width,
- row_height / fig_height], frameon=False)
- overall_ax.set_xticks([])
- overall_ax.set_yticks([])
- if parameter == "calls_per_10s":
- df = calls_per_pup_and_session
- else:
- df = pup_calls
- plot_individual_boxplots(early_ax,
- df.query("before_deafening"),
- parameter, scale,
- annotate=(i == len(call_parameters) - 1),
- p_values=None)
- plot_individual_boxplots(late_ax,
- df.query("not before_deafening"),
- parameter, scale,
- annotate=(i == len(call_parameters) - 1),
- p_values=pup_ps)
- if parameter == "calls_per_10s":
- df = calls_per_adult_group_and_session
- else:
- df = adult_calls
- plot_pooled_boxplots(adult_ax, df, parameter, scale)
- adult_ax.set_xlim(-0.75, 1.75)
- plot_trajectories(trajectory_ax,
- params_per_pup_and_week.query("not before_deafening "
- "and calling_bat_age_in_weeks <= 24"),
- parameter, scale)
- trajectory_ax.xaxis.set_major_locator(mpl.ticker.MultipleLocator(4))
- trajectory_ax.set_xlim(2, 25)
- trajectory_ax.spines["left"].set_position(("outward", 3))
- if i == 0:
- trajectory_ax.set_xlabel("Week of age")
- trajectory_ax.xaxis.set_major_formatter(
- mpl.ticker.FuncFormatter(lambda x, pos: "{}th".format(int(x))))
- else:
- for ax in [early_ax, late_ax, trajectory_ax]:
- ax.set_xticklabels([])
- if i == len(call_parameters) - 1:
- early_ax.set_title("a)\n< 2 weeks\n", fontsize=8)
- late_ax.set_title("b)\n2–25 weeks\n", fontsize=8)
- adult_ax.set_title("c)\n2 years\n", fontsize=8)
- trajectory_ax.set_title("d)\nDevelopment trajectory of median parameter values"
- "\nat 2–25 weeks of age", fontsize=8)
- early_ax.annotate("hearing",
- xy=(0, 1), xycoords="axes fraction",
- xytext=(5, -10), textcoords="offset points",
- verticalalignment="top", horizontalalignment="left",
- color=group_colors["hearing"])
- early_ax.annotate("deafened",
- xy=(0, 1), xycoords="axes fraction",
- xytext=(5, 0), textcoords="offset points",
- verticalalignment="top", horizontalalignment="left",
- color=group_colors["deaf"])
- for ax in [early_ax, late_ax, adult_ax, trajectory_ax]:
- if ax is adult_ax and parameter == "calls_per_10s":
- ax.set_ylim(0, 400)
- ax.yaxis.set_major_locator(mpl.ticker.MultipleLocator(100))
- else:
- ax.set_ylim(y_range[0], y_range[1])
- ax.yaxis.set_major_locator(mpl.ticker.MultipleLocator(y_tick_interval))
- for spine in ["right", "top"]:
- ax.spines[spine].set_visible(False)
- ax.spines["bottom"].set_position(("outward", 3))
- for ax in [late_ax, adult_ax, trajectory_ax]:
- if (ax is not adult_ax and ax is not trajectory_ax) or parameter != "calls_per_10s":
- ax.set_yticklabels([])
- for ax in [early_ax, late_ax, adult_ax]:
- ax.set_xticks([])
- ax.spines["bottom"].set_visible(False)
- early_ax.set_ylabel(y_label)
- early_ax.yaxis.set_label_coords(-0.32 / pup_boxplot_width, 0.5)
- overall_ax.set_ylabel(roman_numerals[-i - 1],
- rotation="0",
- verticalalignment="center",
- labelpad=49)
- fig.savefig("../output/main_figure.pdf")
- ###
- # Parameter tables
- per_session_parameters = [("call_rms", 1, "Amplitude [dB]"),
- ("call_duration", 1e3, "Duration [ms]"),
- ("f0_min", 1e-3, "Minimum fundamental frequency [kHz]"),
- ("f0_mean", 1e-3, "Mean fundamental frequency [kHz]"),
- ("f0_max", 1e-3, "Maximum fundamental frequency [kHz]"),
- ("f0_start", 1e-3, "Fundamental frequency at call onset [kHz]"),
- ("f0_end", 1e-3, "Fundamental frequency at end of call [kHz]"),
- ("f_min", 1e-3, "Minimum frequency [kHz]"),
- ("f_max", 1e-3, "Maximum frequency [kHz]"),
- ("bandwidth", 1e-3, "Bandwidth [kHz]"),
- ("spectral_centroid", 1e-3, "Spectral centroid frequency [kHz]"),
- ("mean_aperiodicity", 1, "Aperiodicity [1]")]
- adult_calls.loc[:, "bandwidth"] = adult_calls["f_max"] - adult_calls["f_min"]
- pup_calls.loc[:, "bandwidth"] = pup_calls["f_max"] - pup_calls["f_min"]
- def q25(series):
- return series.quantile(0.25)
- def q75(series):
- return series.quantile(0.75)
- adult_groups = adult_calls[[p[0] for p in per_session_parameters] + ["group"]].groupby("group")
- adult_summary = adult_groups.agg([q25, "median", q75, "mean", "std"])
- pup_groups = pup_calls.loc[~pup_calls["before_deafening"],
- [p[0] for p in per_session_parameters] + ["calling_bat_deaf"]].groupby("calling_bat_deaf")
- pup_summary = pup_groups.agg([q25, "median", q75, "mean", "std"])
- pre_deafening_pup_groups = pup_calls.loc[pup_calls["before_deafening"],
- [p[0] for p in per_session_parameters] + ["calling_bat_deaf"]].groupby("calling_bat_deaf")
- pre_deafening_pup_summary = pre_deafening_pup_groups.agg([q25, "median", q75, "mean", "std"])
- per_session_parameters.insert(0, ("calls_per_10s", 1, "Vocal activity [calls/10 s]"))
- adult_activity_summary = calls_per_adult_group_and_session.groupby("group")[["calls_per_10s"]] \
- .agg([q25, "median", q75, "mean", "std"])
- adult_summary = pd.concat([adult_activity_summary, adult_summary], axis=1)
- pup_activity_summary = calls_per_pup_and_session \
- .query("not before_deafening") \
- .groupby("calling_bat_deaf")[["calls_per_10s"]] \
- .agg([q25, "median", q75, "mean", "std"])
- pup_summary = pd.concat([pup_activity_summary, pup_summary], axis=1)
- pre_deafening_pup_activity_summary = calls_per_pup_and_session \
- .query("before_deafening") \
- .groupby("calling_bat_deaf")[["calls_per_10s"]] \
- .agg([q25, "median", q75, "mean", "std"])
- pre_deafening_pup_summary = \
- pd.concat([pre_deafening_pup_activity_summary, pre_deafening_pup_summary], axis=1)
- pup_summary.rename({False: "hearing", True: "deaf"}, inplace=True)
- pre_deafening_pup_summary.rename({False: "hearing", True: "deaf"}, inplace=True)
- for group in ["hearing", "deaf"]:
- adult_summary.loc[group, ("count", "total")] = \
- (adult_calls["group"] == group).sum()
- pup_summary.loc[group, ("count", "total")] = \
- ((pup_calls["calling_bat_deaf"] == (group == "deaf"))
- & (~pup_calls["before_deafening"])).sum()
- pre_deafening_pup_summary.loc[group, ("count", "total")] = \
- ((pup_calls["calling_bat_deaf"] == (group == "deaf"))
- & (pup_calls["before_deafening"])).sum()
- def write_parameters_table(summary, p_values):
- fout = io.StringIO()
- print("<!DOCTYPE html><body><table>", file=fout)
- print("<tr><th></th><th colspan='2'>Hearing ({} vocalisations)</th><th colspan='2'>Deaf ({} vocalisations)</th>".format(
- int(summary.loc["hearing", ("count", "total")]),
- int(summary.loc["deaf", ("count", "total")])), file=fout, sep="")
- if p_values is not None:
- print("<th colspan='3'>p < 0.05 (ANOVA)</th>", file=fout, sep="")
- print("</tr>", file=fout)
- print("<tr><th></th>{}".format("<th>Median (1st & 3rd quartile)</th><th>Mean ± std. dev.</th>" * 2), file=fout, end="")
- if p_values is not None:
- print("<th>Deafened/hearing</th><th>Age</th><th>Interaction</th>", file=fout, end="")
- print("</tr>", file=fout)
- for parameter_name, scale, parameter_description in per_session_parameters:
- print("<tr><th>{}</th>".format(parameter_description), file=fout, end="")
- test_data = []
- for group in ["hearing", "deaf"]:
- print("<td>{:.2f} ({:.2f}–{:.2f})</td>".format(
- summary.loc[group, (parameter_name, "median")] * scale,
- summary.loc[group, (parameter_name, "q25")] * scale,
- summary.loc[group, (parameter_name, "q75")] * scale),
- file=fout, end="")
- print("<td>{:.2f} ± {:.2f}</td>".format(
- summary.loc[group, (parameter_name, "mean")] * scale,
- summary.loc[group, (parameter_name, "std")] * scale),
- file=fout, end="")
- if p_values is not None:
- for p_name in ["p_group_adjusted", "p_age_adjusted", "p_interaction_adjusted"]:
- p = p_values.loc[parameter_name, p_name]
- if p < 0.05:
- print("<td>*</td>", file=fout, end="")
- else:
- print("<td>{:.2f}</td>".format(p), file=fout, end="")
- print("</tr>", file=fout)
- print("</table></body>", file=fout)
- return fout.getvalue()
- parameters_table = write_parameters_table(adult_summary, None)
- with open("../output/adult_parameters_table.html", "wt") as fout:
- print(parameters_table, file=fout, end="")
- parameters_table = write_parameters_table(pup_summary, pup_ps)
- with open("../output/pup_parameters_table.html", "wt") as fout:
- print(parameters_table, file=fout, end="")
- parameters_table = write_parameters_table(pre_deafening_pup_summary, None)
- with open("../output/pre_deafening_pup_parameters_table.html", "wt") as fout:
- print(parameters_table, file=fout, end="")
- print("Done, output files written to ../output/.")
|