diff --git a/figures/fig_invariance_full_Omocestus_rufipes.pdf b/figures/fig_invariance_full_Omocestus_rufipes.pdf index 2cc0df8..92c7cc3 100644 Binary files a/figures/fig_invariance_full_Omocestus_rufipes.pdf and b/figures/fig_invariance_full_Omocestus_rufipes.pdf differ diff --git a/figures/fig_invariance_short_Omocestus_rufipes.pdf b/figures/fig_invariance_short_Omocestus_rufipes.pdf index 71aa8ff..612818f 100644 Binary files a/figures/fig_invariance_short_Omocestus_rufipes.pdf and b/figures/fig_invariance_short_Omocestus_rufipes.pdf differ diff --git a/figures/fig_invariance_thresh_lp_single.pdf b/figures/fig_invariance_thresh_lp_single.pdf index 1e7cfa1..75af34a 100644 Binary files a/figures/fig_invariance_thresh_lp_single.pdf and b/figures/fig_invariance_thresh_lp_single.pdf differ diff --git a/main.aux b/main.aux index b418245..05bae50 100644 --- a/main.aux +++ b/main.aux @@ -246,52 +246,52 @@ \@writefile{toc}{\contentsline {subsection}{\numberline {3.1}Full-wave rectification \& lowpass filtering}{11}{}\protected@file@percent } \@writefile{lof}{\contentsline {figure}{\numberline {4}{\ignorespaces \textbf {Intensity invariance by logarithmic compression and adaptation is restricted by the noise floor.} Synthetic input $x_{\text {filt}}(t)$ consists of song component $s(t)$ scaled by $\alpha $ with (\textbf {c}{} and \textbf {d}) or without (\textbf {a}{} and \textbf {b}) additive noise component $\eta (t)$. Input $x_{\text {filt}}(t)$ is transformed into envelope $x_{\text {env}}(t)$, logarithmically compressed envelope $x_{\text {log}}(t)$, and intensity-adapted envelope $x_{\text {adapt}}(t)$. \textbf {Left}:~$x_{\text {env}}(t)$, $x_{\text {log}}(t)$, and $x_{\text {adapt}}(t)$ for different scales $\alpha $. \textbf {Right}:~Ratios of the standard deviation of $x_{\text {env}}(t)$, $x_{\text {log}}(t)$, and $x_{\text {adapt}}(t)$ relative to the respective reference standard deviation $\sigma _{\eta }$ for input $x_{\text {filt}}(t)=\eta (t)$. \textbf {a}{} and \textbf {b}:~Ideally, if $x_{\text {filt}}(t)=\alpha \cdot s(t)$, then $x_{\text {adapt}}(t)$ is intensity-invariant across all $\alpha $. \textbf {c}{} and \textbf {d}:~In practice, if $x_{\text {filt}}(t)=\alpha \cdot s(t)+\eta (t)$, the intensity invariance of $x_{\text {adapt}}(t)$ is limited to sufficiently large $\alpha $. Shaded area indicates saturation of $x_{\text {adapt}}(t)$ at $95\,\%$ curve span. }}{12}{}\protected@file@percent } \newlabel{fig:inv_rect-lp}{{4}{12}{}{}{}} -\@writefile{toc}{\contentsline {subsection}{\numberline {3.2}Logarithmic compression \& spike-frequency adaptation}{13}{}\protected@file@percent } +\@writefile{toc}{\contentsline {subsection}{\numberline {3.2}Logarithmic compression \& spike-frequency adaptation}{12}{}\protected@file@percent } \newlabel{eq:toy_env}{{11}{13}{}{}{}} \newlabel{eq:toy_log}{{12}{13}{}{}{}} \newlabel{eq:toy_highpass}{{13}{13}{}{}{}} \newlabel{eq:toy_snr}{{14}{13}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {5}{\ignorespaces \textbf {Intensity invariance by logarithmic compression and adaptation is restricted by the noise floor.} Synthetic input $x_{\text {filt}}(t)$ consists of song component $s(t)$ scaled by $\alpha $ with (\textbf {c}{} and \textbf {d}) or without (\textbf {a}{} and \textbf {b}) additive noise component $\eta (t)$. Input $x_{\text {filt}}(t)$ is transformed into envelope $x_{\text {env}}(t)$, logarithmically compressed envelope $x_{\text {log}}(t)$, and intensity-adapted envelope $x_{\text {adapt}}(t)$. \textbf {Left}:~$x_{\text {env}}(t)$, $x_{\text {log}}(t)$, and $x_{\text {adapt}}(t)$ for different scales $\alpha $. \textbf {Right}:~Ratios of the standard deviation of $x_{\text {env}}(t)$, $x_{\text {log}}(t)$, and $x_{\text {adapt}}(t)$ relative to the respective reference standard deviation $\sigma _{\eta }$ for input $x_{\text {filt}}(t)=\eta (t)$. \textbf {a}{} and \textbf {b}:~Ideally, if $x_{\text {filt}}(t)=\alpha \cdot s(t)$, then $x_{\text {adapt}}(t)$ is intensity-invariant across all $\alpha $. \textbf {c}{} and \textbf {d}:~In practice, if $x_{\text {filt}}(t)=\alpha \cdot s(t)+\eta (t)$, the intensity invariance of $x_{\text {adapt}}(t)$ is limited to sufficiently large $\alpha $. Shaded area indicates saturation of $x_{\text {adapt}}(t)$ at $95\,\%$ curve span. }}{15}{}\protected@file@percent } -\newlabel{fig:inv_log-hp}{{5}{15}{}{}{}} -\@writefile{toc}{\contentsline {subsection}{\numberline {3.3}Thresholding nonlinearity \& temporal averaging}{15}{}\protected@file@percent } -\@writefile{lof}{\contentsline {figure}{\numberline {6}{\ignorespaces \textbf {Intensity invariance by thresholding and temporal averaging depends on both the threshold value and the noise floor.} Synthetic input $x_{\text {adapt}}(t)$ consists of song component $s(t)$ scaled by $\alpha $ with additive noise component $\eta (t)$. Input $x_{\text {adapt}}(t)$ is transformed into kernel response $c_i(t)$, binary response $b_i(t)$, and feature $f_i(t)$. Threshold value $\Theta _i$ is set to multiples of the reference standard deviation $\sigma _{\eta }$ of $c_i(t)$ for input $x_{\text {adapt}}(t)=\eta (t)$. Darker colors correspond to higher $\Theta _i$. \textbf {Left}:~$x_{\text {adapt}}(t)$, $c_i(t)$, $b_i(t)$, and $f_i(t)$ for different scales $\alpha $ and threshold values $\Theta _i$. Left-most column is is the pure-noise reference. \textbf {Right}:~Average value of $f_i(t)$ during the song for the different $\Theta _i$. \textbf {a}:~Input $x_{\text {adapt}}(t)$. \textbf {b}-\textbf {d}:~$c_i(t)$, $b_i(t)$, and $f_i(t)$ for the different $\Theta _i$ based on the same $x_{\text {adapt}}(t)$ from \textbf {a}{}. \textbf {e}:~Average value of $f_i(t)$ during the song for the different $\Theta _i$ in \textbf {b}{}-\textbf {d}. }}{16}{}\protected@file@percent } -\newlabel{fig:inv_thresh-lp_single}{{6}{16}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {7}{\ignorespaces \textbf {Feature representation of different species-specific songs saturates at different points in feature space.} }}{17}{}\protected@file@percent } -\newlabel{fig:inv_thresh-lp_species}{{7}{17}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {8}{\ignorespaces \textbf {Step-wise emergence of intensity invariant song representation along the model pathway.} }}{18}{}\protected@file@percent } -\newlabel{fig:inv_full}{{8}{18}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {9}{\ignorespaces \textbf {Step-wise emergence of intensity invariant song representation along the model pathway.} }}{19}{}\protected@file@percent } -\newlabel{fig:inv_short}{{9}{19}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {10}{\ignorespaces \textbf {Step-wise emergence of intensity invariant song representation along the model pathway.} }}{20}{}\protected@file@percent } -\newlabel{fig:inv_field}{{10}{20}{}{}{}} -\newlabel{eq:pdf_split}{{15}{21}{}{}{}} -\newlabel{eq:feat_avg}{{16}{21}{}{}{}} -\newlabel{eq:feat_prop}{{17}{21}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {5}{\ignorespaces \textbf {Intensity invariance by logarithmic compression and adaptation is restricted by the noise floor.} Synthetic input $x_{\text {filt}}(t)$ consists of song component $s(t)$ scaled by $\alpha $ with (\textbf {c}{} and \textbf {d}) or without (\textbf {a}{} and \textbf {b}) additive noise component $\eta (t)$. Input $x_{\text {filt}}(t)$ is transformed into envelope $x_{\text {env}}(t)$, logarithmically compressed envelope $x_{\text {log}}(t)$, and intensity-adapted envelope $x_{\text {adapt}}(t)$. \textbf {Left}:~$x_{\text {env}}(t)$, $x_{\text {log}}(t)$, and $x_{\text {adapt}}(t)$ for different scales $\alpha $. \textbf {Right}:~Ratios of the standard deviation of $x_{\text {env}}(t)$, $x_{\text {log}}(t)$, and $x_{\text {adapt}}(t)$ relative to the respective reference standard deviation $\sigma _{\eta }$ for input $x_{\text {filt}}(t)=\eta (t)$. \textbf {a}{} and \textbf {b}:~Ideally, if $x_{\text {filt}}(t)=\alpha \cdot s(t)$, then $x_{\text {adapt}}(t)$ is intensity-invariant across all $\alpha $. \textbf {c}{} and \textbf {d}:~In practice, if $x_{\text {filt}}(t)=\alpha \cdot s(t)+\eta (t)$, the intensity invariance of $x_{\text {adapt}}(t)$ is limited to sufficiently large $\alpha $. Shaded area indicates saturation of $x_{\text {adapt}}(t)$ at $95\,\%$ curve span. }}{14}{}\protected@file@percent } +\newlabel{fig:inv_log-hp}{{5}{14}{}{}{}} +\@writefile{toc}{\contentsline {subsection}{\numberline {3.3}Thresholding nonlinearity \& temporal averaging}{14}{}\protected@file@percent } +\@writefile{lof}{\contentsline {figure}{\numberline {6}{\ignorespaces \textbf {Intensity invariance by thresholding and temporal averaging depends on both the threshold value and the noise floor.} Synthetic input $x_{\text {adapt}}(t)$ consists of song component $s(t)$ scaled by $\alpha $ with additive noise component $\eta (t)$. Input $x_{\text {adapt}}(t)$ is transformed into kernel response $c_i(t)$, binary response $b_i(t)$, and feature $f_i(t)$. Threshold value $\Theta _i$ is set to multiples of the reference standard deviation $\sigma _{\eta }$ of $c_i(t)$ for input $x_{\text {adapt}}(t)=\eta (t)$. Darker colors correspond to higher $\Theta _i$. \textbf {Left}:~$x_{\text {adapt}}(t)$, $c_i(t)$, $b_i(t)$, and $f_i(t)$ for different scales $\alpha $ and threshold values $\Theta _i$. Left-most column is is the pure-noise reference. \textbf {Right}:~Average value of $f_i(t)$ during the song for the different $\Theta _i$. \textbf {a}:~Input $x_{\text {adapt}}(t)$. \textbf {b}-\textbf {d}:~$c_i(t)$, $b_i(t)$, and $f_i(t)$ for the different $\Theta _i$ based on the same $x_{\text {adapt}}(t)$ from \textbf {a}{}. \textbf {e}:~Average value of $f_i(t)$ during the song for the different $\Theta _i$ in \textbf {b}{}-\textbf {d}. }}{15}{}\protected@file@percent } +\newlabel{fig:inv_thresh-lp_single}{{6}{15}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {7}{\ignorespaces \textbf {Feature representation of different species-specific songs saturates at different points in feature space.} }}{16}{}\protected@file@percent } +\newlabel{fig:inv_thresh-lp_species}{{7}{16}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {8}{\ignorespaces \textbf {Step-wise emergence of intensity invariant song representation along the model pathway.} }}{17}{}\protected@file@percent } +\newlabel{fig:inv_full}{{8}{17}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {9}{\ignorespaces \textbf {Step-wise emergence of intensity invariant song representation along the model pathway.} }}{18}{}\protected@file@percent } +\newlabel{fig:inv_short}{{9}{18}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {10}{\ignorespaces \textbf {Step-wise emergence of intensity invariant song representation along the model pathway.} }}{19}{}\protected@file@percent } +\newlabel{fig:inv_field}{{10}{19}{}{}{}} +\newlabel{eq:pdf_split}{{15}{20}{}{}{}} +\newlabel{eq:feat_avg}{{16}{20}{}{}{}} +\newlabel{eq:feat_prop}{{17}{20}{}{}{}} \abx@aux@cite{0}{stumpner1991auditory} \abx@aux@segm{0}{0}{stumpner1991auditory} -\@writefile{toc}{\contentsline {section}{\numberline {4}Discriminating species-specific song\\patterns in feature space}{22}{}\protected@file@percent } -\@writefile{toc}{\contentsline {section}{\numberline {5}Conclusions \& outlook}{22}{}\protected@file@percent } -\abx@aux@page{73}{22} -\@writefile{lof}{\contentsline {figure}{\numberline {11}{\ignorespaces \textbf {} }}{24}{}\protected@file@percent } -\newlabel{}{{11}{24}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {12}{\ignorespaces \textbf {} }}{24}{}\protected@file@percent } -\newlabel{}{{12}{24}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {13}{\ignorespaces \textbf {} }}{25}{}\protected@file@percent } -\newlabel{}{{13}{25}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {14}{\ignorespaces \textbf {} }}{25}{}\protected@file@percent } -\newlabel{}{{14}{25}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {15}{\ignorespaces \textbf {} }}{26}{}\protected@file@percent } -\newlabel{}{{15}{26}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {16}{\ignorespaces \textbf {} }}{26}{}\protected@file@percent } -\newlabel{}{{16}{26}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {17}{\ignorespaces \textbf {} }}{27}{}\protected@file@percent } -\newlabel{}{{17}{27}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {18}{\ignorespaces \textbf {} }}{27}{}\protected@file@percent } -\newlabel{}{{18}{27}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {19}{\ignorespaces \textbf {} }}{28}{}\protected@file@percent } -\newlabel{}{{19}{28}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {20}{\ignorespaces \textbf {} }}{28}{}\protected@file@percent } -\newlabel{}{{20}{28}{}{}{}} +\@writefile{toc}{\contentsline {section}{\numberline {4}Discriminating species-specific song\\patterns in feature space}{21}{}\protected@file@percent } +\@writefile{toc}{\contentsline {section}{\numberline {5}Conclusions \& outlook}{21}{}\protected@file@percent } +\abx@aux@page{73}{21} +\@writefile{lof}{\contentsline {figure}{\numberline {11}{\ignorespaces \textbf {} }}{23}{}\protected@file@percent } +\newlabel{}{{11}{23}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {12}{\ignorespaces \textbf {} }}{23}{}\protected@file@percent } +\newlabel{}{{12}{23}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {13}{\ignorespaces \textbf {} }}{24}{}\protected@file@percent } +\newlabel{}{{13}{24}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {14}{\ignorespaces \textbf {} }}{24}{}\protected@file@percent } +\newlabel{}{{14}{24}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {15}{\ignorespaces \textbf {} }}{25}{}\protected@file@percent } +\newlabel{}{{15}{25}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {16}{\ignorespaces \textbf {} }}{25}{}\protected@file@percent } +\newlabel{}{{16}{25}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {17}{\ignorespaces \textbf {} }}{26}{}\protected@file@percent } +\newlabel{}{{17}{26}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {18}{\ignorespaces \textbf {} }}{26}{}\protected@file@percent } +\newlabel{}{{18}{26}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {19}{\ignorespaces \textbf {} }}{27}{}\protected@file@percent } +\newlabel{}{{19}{27}{}{}{}} +\@writefile{lof}{\contentsline {figure}{\numberline {20}{\ignorespaces \textbf {} }}{27}{}\protected@file@percent } +\newlabel{}{{20}{27}{}{}{}} \gdef\svg@ink@ver@settings{{\m@ne }{inkscape}{\m@ne }} \abx@aux@read@bbl@mdfivesum{1380DC8C93D2855FDB132CC5A40AD52F} -\gdef \@abspage@last{28} +\gdef \@abspage@last{27} diff --git a/main.fdb_latexmk b/main.fdb_latexmk index 675ba9a..cee0d04 100644 --- a/main.fdb_latexmk +++ b/main.fdb_latexmk @@ -1,14 +1,14 @@ # Fdb version 4 -["biber main"] 1777306108.0762 "main.bcf" "main.bbl" "main" 1777386419.24746 0 +["biber main"] 1777306108.0762 "main.bcf" "main.bbl" "main" 1777482193.66376 0 "cite.bib" 1770904753.08918 27483 4290db0c91f7b5055e25472ef913f6b4 "" - "main.bcf" 1777386419.17153 112931 2a478116d80ebb1ada7083a24facd6e3 "pdflatex" + "main.bcf" 1777482193.58667 112931 2a478116d80ebb1ada7083a24facd6e3 "pdflatex" (generated) "main.bbl" "main.blg" (rewritten before read) -["pdflatex"] 1777386418.12295 "/home/hartling/phd/paper/paper_2025/main.tex" "main.pdf" "main" 1777386419.2477 0 +["pdflatex"] 1777482192.53139 "/home/hartling/phd/paper/paper_2025/main.tex" "main.pdf" "main" 1777482193.664 0 "/etc/texmf/web2c/texmf.cnf" 1761560044.43676 475 c0e671620eb5563b2130f56340a5fde8 "" - "/home/hartling/phd/paper/paper_2025/main.tex" 1777386417.06055 52848 d03d400499718a82a8b8f55d4d5355ff "" + "/home/hartling/phd/paper/paper_2025/main.tex" 1777448077.05934 52881 e18226ede44f18b9cf98e6344041bedb "" "/usr/share/texlive/texmf-dist/fonts/map/fontname/texfonts.map" 1577235249 3524 cb3e574dea2d1052e39280babc910dc8 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex7.tfm" 1246382020 1004 54797486969f23fa377b128694d548df "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex8.tfm" 1246382020 988 bdf658c3bfc2d96d3c8b02cfc1c94c20 "" @@ -152,29 +152,29 @@ "/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map" 1761648465.84635 5472669 54eaf61a88b6b7896ebd0dac973cb29c "" "/var/lib/texmf/web2c/pdftex/pdflatex.fmt" 1761648508 8213325 7fd20752ab46ff9aa583e4973d7433df "" "figures/fig_auditory_pathway.pdf" 1771593904.14638 1153923 3df8539421fd21dc866cc8d320bd9b1d "" - "figures/fig_feat_stages.pdf" 1774002994.98767 11091006 565fe951f1255c121429a060082398f5 "" + "figures/fig_feat_stages.pdf" 1777396808.63328 11308461 5755987275789763533a5fc1d513c564 "" "figures/fig_invariance_field.pdf" 1776952657.04263 9131898 e9d9acff1d03fdf60ddc9e32b87ae6c2 "" - "figures/fig_invariance_full_Omocestus_rufipes.pdf" 1776954098.39044 13431867 08ff6482ff81d2878ddba2a90d032d94 "" + "figures/fig_invariance_full_Omocestus_rufipes.pdf" 1777482172.74892 4818225 5f2fe96d50e95be5f3f2bc7369741c1f "" "figures/fig_invariance_log-hp_appendix.pdf" 1777378237.41292 537850 039c3b97fa1196f939cb46c7124692c2 "" - "figures/fig_invariance_log_hp.pdf" 1777378222.90508 854093 e6d668540eccb66e8d399bfd190b7fa5 "" + "figures/fig_invariance_log_hp.pdf" 1777397498.84496 856466 80c2296c4244a5028c5680207c983431 "" "figures/fig_invariance_rect-lp_appendix.pdf" 1777378650.4805 2034997 232e08d6eb888802d738123188aaa6f5 "" - "figures/fig_invariance_rect_lp.pdf" 1777378666.73529 651519 66d1a70ec3d2ef4d85023d858643c43b "" - "figures/fig_invariance_short_Omocestus_rufipes.pdf" 1776954155.39396 5547735 148c794495092c93fa8b9bf75411280a "" + "figures/fig_invariance_rect_lp.pdf" 1777397395.21512 660469 3064ce79d603e2b3a8a68bb8bf7545f8 "" + "figures/fig_invariance_short_Omocestus_rufipes.pdf" 1777482066.57016 1964661 2ae90963b46a336b33173463eb76bed0 "" "figures/fig_invariance_thresh-lp_noise_appendix.pdf" 1777378570.40754 1484986 42bec6aa96a984e1b2872daafbf7decf "" "figures/fig_invariance_thresh-lp_pure_appendix.pdf" 1777378581.6234 1387834 7815dfef418fdf540749fafb8a79ac6f "" - "figures/fig_invariance_thresh_lp_single.pdf" 1777378492.21857 860673 1258c9cd2032cb7efd174874acdb674d "" + "figures/fig_invariance_thresh_lp_single.pdf" 1777447653.9361 859309 caf82e9ed5fd0b299978dd54205eb29b "" "figures/fig_invariance_thresh_lp_species.pdf" 1777378512.7163 1607791 f0b47f0ad73ff3b1dd65eee81fb5abfb "" "figures/fig_kernel_sd_perc_field_appendix.pdf" 1777273985.83211 100184 e699513599b5828cd498b1621e1e79ee "" "figures/fig_kernel_sd_perc_full_appendix.pdf" 1777273971.01214 90770 e3ecb7db816fc5046b866a9b27a35193 "" "figures/fig_kernel_sd_perc_short_appendix.pdf" 1777273977.37413 91395 b7d8e68ba3a353986dbde11221d0051f "" "figures/fig_kernel_sd_perc_thresh_lp_appendix.pdf" 1777273964.75216 90770 9cb3f2324eea517a8412177ca3dba932 "" "figures/fig_noise_env_sd_conversion_appendix.pdf" 1776328774.43347 45466 c2be20312c1572203bdbeb9c8e32525e "" - "figures/fig_pre_stages.pdf" 1774002992.74268 449426 5762be15627fe5d8b6d108b7ea18db44 "" + "figures/fig_pre_stages.pdf" 1777396806.3563 441645 564c887858565a15dfbfa3487e8021e4 "" "figures/fig_saturation_log-hp_appendix.pdf" 1777378621.26288 28579 137855d03bab8dc5f6d31b70d404e082 "" - "main.aux" 1777386419.16553 18677 dd88739c1abced84fb71ddfe62ac02f2 "pdflatex" + "main.aux" 1777482193.58067 18677 56f36bb5fefb9703ee41dbf6e2b62286 "pdflatex" "main.bbl" 1777306108.74822 91039 1380dc8c93d2855fdb132cc5a40ad52f "biber main" - "main.run.xml" 1777386419.17253 2335 a049bc26a7f032e842ce55de5bc38328 "pdflatex" - "main.tex" 1777386417.06055 52848 d03d400499718a82a8b8f55d4d5355ff "" + "main.run.xml" 1777482193.58767 2335 a049bc26a7f032e842ce55de5bc38328 "pdflatex" + "main.tex" 1777448077.05934 52881 e18226ede44f18b9cf98e6344041bedb "" (generated) "main.aux" "main.bcf" diff --git a/main.log b/main.log index d172b23..5940816 100644 --- a/main.log +++ b/main.log @@ -1,4 +1,4 @@ -This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023/Debian) (preloaded format=pdflatex 2025.10.28) 28 APR 2026 16:26 +This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023/Debian) (preloaded format=pdflatex 2025.10.28) 29 APR 2026 19:03 entering extended mode restricted \write18 enabled. file:line:error style messages enabled. @@ -781,122 +781,121 @@ File: figures/fig_pre_stages.pdf Graphic file (type pdf) Package pdftex.def Info: figures/fig_pre_stages.pdf used on input line 428. (pdftex.def) Requested size: 483.69687pt x 241.84782pt. [7] [8 <./figures/fig_pre_stages.pdf>] -Overfull \hbox (42.89445pt too wide) in paragraph at lines 521--530 +Overfull \hbox (42.89445pt too wide) in paragraph at lines 522--531 \OT1/cmr/m/n/12 glion ([]; []; []). [] [9] - + File: figures/fig_feat_stages.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_feat_stages.pdf used on input line 542. +Package pdftex.def Info: figures/fig_feat_stages.pdf used on input line 543. (pdftex.def) Requested size: 483.69687pt x 241.84782pt. [10 <./figures/fig_feat_stages.pdf>] - + File: figures/fig_invariance_rect_lp.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_invariance_rect_lp.pdf used on input line 577. -(pdftex.def) Requested size: 483.69687pt x 498.70178pt. +Package pdftex.def Info: figures/fig_invariance_rect_lp.pdf used on input line 578. +(pdftex.def) Requested size: 483.69687pt x 483.85846pt. [11] +Overfull \vbox (23.76158pt too high) has occurred while \output is active [] -LaTeX Warning: Text page 12 contains only floats. - -[12 <./figures/fig_invariance_rect_lp.pdf>] [13] - + [12 <./figures/fig_invariance_rect_lp.pdf>] + File: figures/fig_invariance_log_hp.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_invariance_log_hp.pdf used on input line 676. +Package pdftex.def Info: figures/fig_invariance_log_hp.pdf used on input line 677. (pdftex.def) Requested size: 483.69687pt x 483.85846pt. - [14] - + [13] + File: figures/fig_invariance_thresh_lp_single.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_invariance_thresh_lp_single.pdf used on input line 707. +Package pdftex.def Info: figures/fig_invariance_thresh_lp_single.pdf used on input line 708. (pdftex.def) Requested size: 483.69687pt x 483.69566pt. - [15 <./figures/fig_invariance_log_hp.pdf>] - + [14 <./figures/fig_invariance_log_hp.pdf>] + File: figures/fig_invariance_thresh_lp_species.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_invariance_thresh_lp_species.pdf used on input line 737. +Package pdftex.def Info: figures/fig_invariance_thresh_lp_species.pdf used on input line 738. (pdftex.def) Requested size: 483.69687pt x 483.69566pt. - [16 <./figures/fig_invariance_thresh_lp_single.pdf>] [17 <./figures/fig_invariance_thresh_lp_species.pdf>] - + [15 <./figures/fig_invariance_thresh_lp_single.pdf>] [16 <./figures/fig_invariance_thresh_lp_species.pdf>] + File: figures/fig_invariance_full_Omocestus_rufipes.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_invariance_full_Omocestus_rufipes.pdf used on input line 747. +Package pdftex.def Info: figures/fig_invariance_full_Omocestus_rufipes.pdf used on input line 748. (pdftex.def) Requested size: 483.69687pt x 483.69566pt. - + File: figures/fig_invariance_short_Omocestus_rufipes.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_invariance_short_Omocestus_rufipes.pdf used on input line 757. +Package pdftex.def Info: figures/fig_invariance_short_Omocestus_rufipes.pdf used on input line 758. (pdftex.def) Requested size: 483.69687pt x 483.69566pt. - [18 + [17 <./figures/fig_invariance_full_Omocestus_rufipes.pdf>] - + File: figures/fig_invariance_field.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_invariance_field.pdf used on input line 767. +Package pdftex.def Info: figures/fig_invariance_field.pdf used on input line 768. (pdftex.def) Requested size: 483.69687pt x 483.69566pt. - [19 <./figures/fig_invariance_short_Omocestus_rufipes.pdf>] [20 <./figures/fig_invariance_field.pdf>] [21 + [18 <./figures/fig_invariance_short_Omocestus_rufipes.pdf>] [19 <./figures/fig_invariance_field.pdf>] [20 -] [22] - +] [21] + File: figures/fig_noise_env_sd_conversion_appendix.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_noise_env_sd_conversion_appendix.pdf used on input line 926. +Package pdftex.def Info: figures/fig_noise_env_sd_conversion_appendix.pdf used on input line 927. (pdftex.def) Requested size: 483.69687pt x 241.84782pt. - [23] - + [22] + File: figures/fig_invariance_rect-lp_appendix.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_invariance_rect-lp_appendix.pdf used on input line 935. +Package pdftex.def Info: figures/fig_invariance_rect-lp_appendix.pdf used on input line 936. (pdftex.def) Requested size: 483.69687pt x 241.84782pt. - + File: figures/fig_invariance_log-hp_appendix.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_invariance_log-hp_appendix.pdf used on input line 944. +Package pdftex.def Info: figures/fig_invariance_log-hp_appendix.pdf used on input line 945. (pdftex.def) Requested size: 483.69687pt x 241.84782pt. - [24 <./figures/fig_noise_env_sd_conversion_appendix.pdf> <./figures/fig_invariance_rect-lp_appendix.pdf>] - + [23 <./figures/fig_noise_env_sd_conversion_appendix.pdf> <./figures/fig_invariance_rect-lp_appendix.pdf>] + File: figures/fig_saturation_log-hp_appendix.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_saturation_log-hp_appendix.pdf used on input line 953. +Package pdftex.def Info: figures/fig_saturation_log-hp_appendix.pdf used on input line 954. (pdftex.def) Requested size: 483.69687pt x 241.84782pt. - + File: figures/fig_invariance_thresh-lp_pure_appendix.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_invariance_thresh-lp_pure_appendix.pdf used on input line 962. +Package pdftex.def Info: figures/fig_invariance_thresh-lp_pure_appendix.pdf used on input line 963. (pdftex.def) Requested size: 483.69687pt x 241.84782pt. - [25 <./figures/fig_invariance_log-hp_appendix.pdf> <./figures/fig_saturation_log-hp_appendix.pdf>] - + [24 <./figures/fig_invariance_log-hp_appendix.pdf> <./figures/fig_saturation_log-hp_appendix.pdf>] + File: figures/fig_invariance_thresh-lp_noise_appendix.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_invariance_thresh-lp_noise_appendix.pdf used on input line 971. +Package pdftex.def Info: figures/fig_invariance_thresh-lp_noise_appendix.pdf used on input line 972. (pdftex.def) Requested size: 483.69687pt x 241.84782pt. - + File: figures/fig_kernel_sd_perc_thresh_lp_appendix.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_kernel_sd_perc_thresh_lp_appendix.pdf used on input line 980. +Package pdftex.def Info: figures/fig_kernel_sd_perc_thresh_lp_appendix.pdf used on input line 981. (pdftex.def) Requested size: 483.69687pt x 241.84782pt. - [26 <./figures/fig_invariance_thresh-lp_pure_appendix.pdf> <./figures/fig_invariance_thresh-lp_noise_appendix.pdf>] - + [25 <./figures/fig_invariance_thresh-lp_pure_appendix.pdf> <./figures/fig_invariance_thresh-lp_noise_appendix.pdf>] + File: figures/fig_kernel_sd_perc_full_appendix.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_kernel_sd_perc_full_appendix.pdf used on input line 989. +Package pdftex.def Info: figures/fig_kernel_sd_perc_full_appendix.pdf used on input line 990. (pdftex.def) Requested size: 483.69687pt x 241.84782pt. - + File: figures/fig_kernel_sd_perc_short_appendix.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_kernel_sd_perc_short_appendix.pdf used on input line 998. +Package pdftex.def Info: figures/fig_kernel_sd_perc_short_appendix.pdf used on input line 999. (pdftex.def) Requested size: 483.69687pt x 241.84782pt. - [27 <./figures/fig_kernel_sd_perc_thresh_lp_appendix.pdf> <./figures/fig_kernel_sd_perc_full_appendix.pdf>] - + [26 <./figures/fig_kernel_sd_perc_thresh_lp_appendix.pdf> <./figures/fig_kernel_sd_perc_full_appendix.pdf>] + File: figures/fig_kernel_sd_perc_field_appendix.pdf Graphic file (type pdf) -Package pdftex.def Info: figures/fig_kernel_sd_perc_field_appendix.pdf used on input line 1007. +Package pdftex.def Info: figures/fig_kernel_sd_perc_field_appendix.pdf used on input line 1008. (pdftex.def) Requested size: 483.69687pt x 241.84782pt. - [28 <./figures/fig_kernel_sd_perc_short_appendix.pdf> <./figures/fig_kernel_sd_perc_field_appendix.pdf>] (./main.aux) + [27 <./figures/fig_kernel_sd_perc_short_appendix.pdf> <./figures/fig_kernel_sd_perc_field_appendix.pdf>] (./main.aux) *********** LaTeX2e <2023-11-01> patch level 1 L3 programming layer <2024-01-22> @@ -912,16 +911,16 @@ Package logreq Info: Writing requests to 'main.run.xml'. Here is how much of TeX's memory you used: 20849 strings out of 474222 452796 string characters out of 5748732 - 1937975 words of memory out of 5000000 + 1938975 words of memory out of 5000000 42839 multiletter control sequences out of 15000+600000 569394 words of font info for 79 fonts, out of 8000000 for 9000 1143 hyphenation exceptions out of 8191 94i,18n,93p,1499b,1740s stack positions out of 10000i,1000n,20000p,200000b,200000s -Output written on main.pdf (28 pages, 50733502 bytes). +Output written on main.pdf (27 pages, 38753439 bytes). PDF statistics: - 2373 PDF objects out of 2487 (max. 8388607) - 1080 compressed objects within 11 object streams + 2414 PDF objects out of 2487 (max. 8388607) + 1082 compressed objects within 11 object streams 0 named destinations out of 1000 (max. 500000) 113 words of extra memory for PDF output out of 10000 (max. 10000000) diff --git a/main.pdf b/main.pdf index 98a11d5..78cc990 100644 Binary files a/main.pdf and b/main.pdf differ diff --git a/main.synctex.gz b/main.synctex.gz index 98d4732..d76d2da 100644 Binary files a/main.synctex.gz and b/main.synctex.gz differ diff --git a/main.tex b/main.tex index b64e5ef..0f61a4e 100644 --- a/main.tex +++ b/main.tex @@ -509,6 +509,7 @@ the left of the two central lobes (odd kernels). These four major groups of Gabor kernels allow for the extraction of different types of signal features, such as the presence of peaks (even, $+$), troughs (even, $-$), onsets (odd, $+$), and offsets (odd, $-$) at various time scales. +% Add kernel normalization here. Following the convolutional template matching, each kernel-specific response $c_i(t)$ is passed through a shifted Heaviside step-function $\nl$ with threshold value $\thr$ to obtain a binary response diff --git a/python/fig_invariance_full.py b/python/fig_invariance_full.py index 43f4799..aba2d81 100644 --- a/python/fig_invariance_full.py +++ b/python/fig_invariance_full.py @@ -6,11 +6,11 @@ from thunderhopper.filetools import search_files from thunderhopper.modeltools import load_data from thunderhopper.filtertools import find_kern_specs from misc_functions import get_saturation, reduce_kernel_set, exclude_zero_scale,\ - divide_by_zero + divide_by_zero, x_dist, y_dist from color_functions import load_colors from plot_functions import hide_axis, reorder_by_sd, ylimits, super_xlabel, ylabel, title_subplot,\ plot_line, strip_zeros, time_bar, assign_colors,\ - letter_subplot, letter_subplots + letter_subplot, letter_subplots, hide_ticks from IPython import embed def plot_snippets(axes, time, snippets, ymin=None, ymax=None, **kwargs): @@ -21,15 +21,14 @@ def plot_snippets(axes, time, snippets, ymin=None, ymax=None, **kwargs): ymin=ymin, ymax=ymax, **kwargs)) return handles -def plot_curves(ax, scales, measures, fill_kwargs={}, compress=False, **kwargs): - if not compress or measures.ndim == 1: +def plot_curves(ax, scales, measures, **kwargs): + if measures.ndim == 1: handles = ax.plot(scales, measures, **kwargs) return handles, measures median_measure = np.nanmedian(measures, axis=1) - spread_measure = np.nanpercentile(measures, [25, 75], axis=1) line_handle = ax.plot(scales, median_measure, **kwargs)[0] - fill_handle = ax.fill_between(scales, *spread_measure, **fill_kwargs) - return [line_handle, fill_handle], median_measure + return line_handle, median_measure + # GENERAL SETTINGS: target_species = [ @@ -56,8 +55,8 @@ save_path = '../figures/fig_invariance_full.pdf' # ANALYSIS SETTINGS: exclude_zero = True -compress_kernels = True thresh_rel = np.array([0, 0.5, 1, 1.5, 2, 2.5, 3])[4] +percentiles = np.array([0, 100]) scale_subset_kwargs = dict( combis=[['measure'], stages], ) @@ -67,9 +66,9 @@ kern_subset_kwargs = dict( ) # SUBSET SETTINGS: -types = np.array([1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10]) +types = np.array([1, -1, 2, -2, 3, -3, 4, -4]) # types = [1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10] -sigmas = np.array([0.001, 0.002, 0.004, 0.008, 0.016, 0.032]) +sigmas = np.array([0.001, 0.002, 0.004, 0.008, 0.016]) # sigmas = [0.001, 0.002, 0.004, 0.008, 0.016, 0.032] kernels = None reduce_kernels = any(var is not None for var in [kernels, types, sigmas]) @@ -80,18 +79,19 @@ fig_kwargs = dict( ) super_grid_kwargs = dict( nrows=2, - ncols=1, + ncols=2, wspace=0, hspace=0, left=0, right=1, bottom=0, top=1, - height_ratios=[3, 2] + height_ratios=[1, 1] ) subfig_specs = dict( - snip=(0, 0), - big=(1, 0), + snip=(0, slice(None)), + raw=(1, 0), + base=(1, 1), ) snip_grid_kwargs = dict( nrows=len(stages), @@ -100,19 +100,31 @@ snip_grid_kwargs = dict( hspace=0.4, left=0.13, right=0.98, - bottom=0.08, + bottom=0.05, top=0.95 ) -big_grid_kwargs = dict( - nrows=1, - ncols=3, - wspace=0.4, - hspace=0, - left=snip_grid_kwargs['left'], - right=snip_grid_kwargs['right'], - bottom=0.13, - top=0.98 +raw_grid_kwargs = dict( + nrows=2, + ncols=1, + wspace=0, + hspace=0.15, + left=0.14, + right=0.9, + bottom=0.1, + top=0.95, + height_ratios=[0.8, 0.2] ) +base_grid_kwargs = dict( + nrows=4, + ncols=1, + wspace=0, + hspace=0.25, + left=raw_grid_kwargs['left'], + right=raw_grid_kwargs['right'], + bottom=raw_grid_kwargs['bottom'], + top=raw_grid_kwargs['top'], +) +inset_bounds = [1.01, 0, 0.95, 1] # PLOT SETTINGS: fs = dict( @@ -125,8 +137,8 @@ fs = dict( ) stage_colors = load_colors('../data/stage_colors.npz') kern_colors = dict( - conv=load_colors('../data/conv_colors_all.npz'), - feat=load_colors('../data/feat_colors_all.npz') + conv=load_colors('../data/conv_colors_subset.npz'), + feat=load_colors('../data/feat_colors_subset.npz') ) lw = dict( filt=0.25, @@ -135,9 +147,11 @@ lw = dict( inv=0.25, conv=0.25, feat=1, - big=3, + single=3, + swarm=1, plateau=1.5, legend=5, + dist=1 ) xlabels = dict( big='scale $\\alpha$', @@ -149,7 +163,8 @@ ylabels = dict( inv='$x_{\\text{adapt}}$\n$[\\text{dB}]$', conv='$c_i$\n$[\\text{dB}]$', feat='$f_i$', - big=['measure', 'rel. measure', 'norm. measure'] + raw=['$m$', '$\\mu_{f_i}$'], + base=['$m\\,/\\,m_{\\eta}$', '$\\sigma_{c_i}$', '$\\mu_{f_i}$', '$\\text{PDF}_{\\alpha}$'] ) xlab_big_kwargs = dict( y=0, @@ -166,10 +181,10 @@ ylab_snip_kwargs = dict( ma='center' ) ylab_big_kwargs = dict( - x=-0.2, + x=0, fontsize=fs['lab_norm'], ha='center', - va='bottom', + va='top', ) yloc = dict( filt=3000, @@ -194,17 +209,17 @@ letter_snip_kwargs = dict( fontsize=fs['letter'], ) letter_big_kwargs = dict( - x=0, + xref=0, y=1, ha='left', - va='bottom', + va='center', fontsize=fs['letter'], ) bar_time = 5 bar_kwargs = dict( dur=bar_time, - y0=-0.25, - y1=-0.1, + y0=-0.3, + y1=-0.15, xshift=1, color='k', lw=0, @@ -220,7 +235,7 @@ bar_kwargs = dict( leg_kwargs = dict( ncols=1, loc='upper left', - bbox_to_anchor=(0.05, 0.5, 0.5, 0.5), + bbox_to_anchor=(0.025, 0.5, 0.5, 0.5), frameon=False, prop=dict( size=20, @@ -240,6 +255,12 @@ leg_labels = dict( conv='$c_i$', feat='$f_i$' ) +dist_line_kwargs = dict( + lw=lw['dist'], +) +dist_fill_kwargs = dict( + lw=lw['dist'], +) plateau_settings = dict( low=0.05, high=0.95, @@ -313,23 +334,49 @@ for i, j in product(range(snip_grid.nrows), range(snip_grid.ncols)): time_bar(snip_axes[-1, -1], **bar_kwargs) letter_subplot(snip_subfig, 'a', ref=title, **letter_snip_kwargs) -# Prepare analysis axes: -big_subfig = fig.add_subfigure(super_grid[subfig_specs['big']]) -big_grid = big_subfig.add_gridspec(**big_grid_kwargs) -big_axes = np.zeros((big_grid.ncols,), dtype=object) -for i in range(big_grid.ncols): - ax = big_subfig.add_subplot(big_grid[0, i]) +# Prepare raw analysis axes: +raw_subfig = fig.add_subfigure(super_grid[subfig_specs['raw']]) +raw_grid = raw_subfig.add_gridspec(**raw_grid_kwargs) +raw_axes = np.zeros((raw_grid.nrows,), dtype=object) +for i in range(raw_grid.nrows): + ax = raw_subfig.add_subplot(raw_grid[i, 0]) ax.set_xlim(scales[0], scales[-1]) ax.set_xscale('symlog', linthresh=scales[1], linscale=0.5) - ax.set_yscale('symlog', linthresh=0.01, linscale=0.1) - ylabel(ax, ylabels['big'][i], **ylab_big_kwargs) - # if i < (big_grid.ncols - 1): - # ax.set_ylim(scales[0], scales[-1]) - # else: - # ax.set_ylim(0, 1) - big_axes[i] = ax -super_xlabel(xlabels['big'], big_subfig, big_axes[0], big_axes[-1], **xlab_big_kwargs) -letter_subplots(big_axes, 'bcd', **letter_big_kwargs) + ylabel(ax, ylabels['raw'][i], transform=raw_subfig.transSubfigure, **ylab_big_kwargs) + if i == 0: + ax.set_yscale('symlog', linthresh=0.001, linscale=0.1) + hide_ticks(ax, 'bottom') + else: + transform = raw_subfig.transSubfigure + ax.transAxes.inverted() + inset_x1 = transform.transform((inset_bounds[2], 0))[0] + inset_bounds[2] = inset_x1 - inset_bounds[0] + raw_inset = ax.inset_axes(inset_bounds) + raw_inset.axis('off') + raw_axes[i] = ax +letter_subplots(raw_axes, 'bc', ref=raw_subfig, **letter_big_kwargs) + +# Prepare base analysis axes: +base_subfig = fig.add_subfigure(super_grid[subfig_specs['base']]) +base_grid = base_subfig.add_gridspec(**base_grid_kwargs) +base_axes = np.zeros((base_grid.nrows,), dtype=object) +base_insets = np.zeros((base_grid.nrows - 1,), dtype=object) +for i in range(base_grid.nrows): + ax = base_subfig.add_subplot(base_grid[i, 0]) + ax.set_xlim(scales[0], scales[-1]) + ax.set_xscale('symlog', linthresh=scales[1], linscale=0.5) + ylabel(ax, ylabels['base'][i], transform=base_subfig.transSubfigure, **ylab_big_kwargs) + if i < base_grid_kwargs['nrows'] - 1: + ax.set_yscale('symlog', linthresh=0.01, linscale=0.1) + hide_ticks(ax, 'bottom') + if i in [1, 2]: + inset = ax.inset_axes(inset_bounds) + inset.set_yscale('symlog', linthresh=0.01, linscale=0.1) + inset.axis('off') + base_insets[i - 1] = inset + base_axes[i] = ax +letter_subplots(base_axes, 'defg', ref=base_subfig, **letter_big_kwargs) +super_xlabel(xlabels['big'], fig, raw_axes[-1], base_axes[-1], + left_fig=raw_subfig, right_fig=base_subfig, **xlab_big_kwargs) if True: # Plot filtered snippets: @@ -363,84 +410,114 @@ if True: reorder_by_sd(handles, data['snip_feat'][..., i]) # Plot analysis results: -crit_inds, crit_scales = {}, {} +crit_inds, crit_scales_single, crit_scales_swarm = {}, {}, {} +max_pdf = -np.inf leg_handles = [] for stage in stages: mkey = f'measure_{stage}' measure = data[mkey] color = stage_colors[stage] - fill_kwargs = dict(color=color, alpha=0.25) - # Plot raw intensity measure curve(s): - handles, curve = plot_curves(big_axes[0], scales, measure, fill_kwargs, - compress_kernels, c=color, lw=lw['big']) - if not compress_kernels and stage in ['conv', 'feat']: - assign_colors(handles, config['k_specs'][:, 0], kern_colors[stage]) + ## UNNORMALIZED MEASURE: + + # Plot single raw intensity curve (median where necessary): + handles, curve = plot_curves(raw_axes[0], scales, measure, c=color, lw=lw['single']) # Add stage-specific proxy legend artist: - leg_handles.append(big_axes[0].plot([], [], c=color, lw=lw['big'], - label=leg_labels[stage])[0]) + leg_handles.append(raw_axes[0].plot([], [], c=color, label=leg_labels[stage])[0]) + + # Plot curve swarm: + if stage == 'feat': + # Sync y-limits: + ylimits(measure, raw_axes[1], minval=0, pad=0.05) + raw_inset.set_ylim(raw_axes[1].get_ylim()) + # Plot swarm: + handles = raw_axes[1].plot(scales, measure, lw=lw['swarm']) + assign_colors(handles, config['k_specs'][:, 0], kern_colors[stage]) + reorder_by_sd(handles, measure) + # Plot distribution of saturation levels: + line_kwargs = dist_line_kwargs | dict(c=color) + fill_kwargs = dist_fill_kwargs | dict(color=color) + y_dist(raw_inset, measure[-1], nbins=75, log=False, + line_kwargs=line_kwargs, fill_kwargs=fill_kwargs) # Indicate saturation point(s): if stage in ['log', 'inv', 'conv', 'feat']: ind = get_saturation(curve, **plateau_settings)[1] crit_inds[stage] = ind - if compress_kernels or stage in ['log', 'inv']: - scale = scales[ind] - crit_scales[stage] = scale - big_axes[0].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, - transform=big_axes[0].get_xaxis_transform()) - big_axes[0].plot(scale, 0, mfc=color, mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, - transform=big_axes[0].get_xaxis_transform()) - big_axes[0].vlines(scale, big_axes[0].get_ylim()[0], curve[ind], - color=color, **plateau_line_kwargs) + scale = scales[ind] + crit_scales_single[stage] = scale + raw_axes[0].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, + transform=raw_axes[0].get_xaxis_transform()) + raw_axes[0].plot(scale, 0, mfc=color, mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, + transform=raw_axes[0].get_xaxis_transform()) + raw_axes[0].vlines(scale, raw_axes[0].get_ylim()[0], curve[ind], + color=color, **plateau_line_kwargs) + + ## NORMALIZED MEASURE: # Relate to noise baseline: measure = divide_by_zero(data[mkey], ref_data[stage]) - # Plot baseline-normalized ntensity measure curve(s): - handles, curve = plot_curves(big_axes[1], scales, measure, fill_kwargs, - compress_kernels, c=color, lw=lw['big']) - if not compress_kernels and stage in ['conv', 'feat']: + # Plot single baseline-normalized intensity curve (median where necessary): + handles, curve = plot_curves(base_axes[0], scales, measure, c=color, lw=lw['single']) + + # Plot curve swarm: + if stage in ['conv', 'feat']: + i0, i1 = (1, 0) if stage == 'conv' else (2, 1) + # Sync y-limits: + ylimits(measure, base_axes[i0], minval=0.9, pad=0.05) + base_insets[i1].set_ylim(base_axes[i0].get_ylim()) + # Plot swarm: + handles = base_axes[i0].plot(scales, measure, lw=lw['swarm']) assign_colors(handles, config['k_specs'][:, 0], kern_colors[stage]) + reorder_by_sd(handles, measure) + # Plot distribution of saturation levels: + line_kwargs = dist_line_kwargs | dict(c=color) + fill_kwargs = dist_fill_kwargs | dict(color=color) + y_dist(base_insets[i1], measure[-1], nbins=100, log=True, + line_kwargs=line_kwargs, fill_kwargs=fill_kwargs) + # Get and log distribution of saturation points: + inds = np.array(get_saturation(measure, **plateau_settings)[1]) + if np.isnan(inds).sum(): + inds = inds[~np.isnan(inds)].astype(int) + crit_scales_swarm[stage] = scales[inds] + if stage == 'feat': + # Plot distribution of saturation points on shared bins: + bin_lims = [0.01, 1.1 * max([s.max() for s in crit_scales_swarm.values()])] + for temp_stage, crit_scales in crit_scales_swarm.items(): + z = 3 if temp_stage == 'conv' else 2 + line_kwargs = dist_line_kwargs | dict(c=stage_colors[temp_stage], zorder=z) + fill_kwargs = dist_fill_kwargs | dict(color=stage_colors[temp_stage], alpha=0.25, zorder=z) + pdf = x_dist(base_axes[-1], crit_scales, nbins=75, limits=bin_lims, + log=True, line_kwargs=line_kwargs, fill_kwargs=fill_kwargs)[0] + max_pdf = max(max_pdf, pdf.max()) + base_axes[-1].set_ylim(0, max_pdf * 1.05) + # Add single curve saturation point: + for temp_stage, crit_scale in crit_scales_single.items(): + base_axes[-1].plot(crit_scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, + transform=base_axes[-1].get_xaxis_transform()) + base_axes[-1].plot(crit_scale, 0, mfc=stage_colors[temp_stage], mec='k', alpha=0.75, + zorder=6, **plateau_dot_kwargs, + transform=base_axes[-1].get_xaxis_transform()) # Indicate saturation point(s): if stage in ['log', 'inv', 'conv', 'feat']: ind = crit_inds[stage] - scale = crit_scales[stage] - if compress_kernels or stage in ['log', 'inv']: - big_axes[1].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, - transform=big_axes[1].get_xaxis_transform()) - big_axes[1].plot(scale, 0, mfc=color, mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, - transform=big_axes[1].get_xaxis_transform()) - big_axes[1].vlines(scale, big_axes[1].get_ylim()[0], curve[ind], - color=color, **plateau_line_kwargs) - if stage in ['filt', 'env']: - continue + scale = crit_scales_single[stage] + base_axes[0].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, + transform=base_axes[0].get_xaxis_transform()) + base_axes[0].plot(scale, 0, mfc=color, mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, + transform=base_axes[0].get_xaxis_transform()) + base_axes[0].vlines(scale, base_axes[0].get_ylim()[0], curve[ind], + color=color, **plateau_line_kwargs) - # Relate to curve maximum: - measure = data[mkey] / np.nanmax(data[mkey], axis=0) - - # Plot max-normalized ntensity measure curve(s): - handles, curve = plot_curves(big_axes[2], scales, measure, fill_kwargs, - compress_kernels, c=color, lw=lw['big']) - if not compress_kernels and stage in ['conv', 'feat']: - assign_colors(handles, config['k_specs'][:, 0], kern_colors[stage]) - - # Indicate saturation point(s): - if stage in ['log', 'inv', 'conv', 'feat']: - ind = crit_inds[stage] - scale = crit_scales[stage] - if compress_kernels or stage in ['log', 'inv']: - big_axes[2].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, - transform=big_axes[2].get_xaxis_transform()) - big_axes[2].plot(scale, 0, mfc=color, mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, - transform=big_axes[2].get_xaxis_transform()) - big_axes[2].vlines(scale, big_axes[2].get_ylim()[0], curve[ind], - color=color, **plateau_line_kwargs) +# Posthoc adjustments: +raw_axes[0].set_ylim(bottom=0.001) +base_axes[0].set_ylim(1, 100) # Add legend to first analysis axis: -legend = big_axes[0].legend(handles=leg_handles, **leg_kwargs) +legend = raw_axes[0].legend(handles=leg_handles, **leg_kwargs) [handle.set_lw(lw['legend']) for handle in legend.get_lines()] # Save graph: diff --git a/python/fig_invariance_full_backup.py b/python/fig_invariance_full_backup.py deleted file mode 100644 index 1d5d314..0000000 --- a/python/fig_invariance_full_backup.py +++ /dev/null @@ -1,426 +0,0 @@ -import plotstyle_plt -import numpy as np -import matplotlib.pyplot as plt -from itertools import product -from thunderhopper.filetools import search_files -from thunderhopper.modeltools import load_data -from thunderhopper.filtertools import find_kern_specs -from misc_functions import get_saturation -from color_functions import load_colors -from plot_functions import hide_axis, reorder_by_sd, ylimits, super_xlabel, ylabel, title_subplot,\ - plot_line, strip_zeros, time_bar, assign_colors,\ - letter_subplot, letter_subplots -from IPython import embed - -def plot_snippets(axes, time, snippets, ymin=None, ymax=None, **kwargs): - ymin, ymax = ylimits(snippets, minval=ymin, maxval=ymax, pad=0.05) - handles = [] - for i, ax in enumerate(axes): - handles.append(plot_line(ax, time, snippets[:, ..., i], - ymin=ymin, ymax=ymax, **kwargs)) - return handles - -def plot_curves(ax, scales, measures, fill_kwargs={}, **kwargs): - if measures.ndim == 1: - ax.plot(scales, measures, **kwargs)[0] - return measures - median_measure = np.median(measures, axis=1) - spread_measure = [np.percentile(measures, 25, axis=1), - np.percentile(measures, 75, axis=1)] - ax.plot(scales, median_measure, **kwargs)[0] - ax.fill_between(scales, *spread_measure, **fill_kwargs) - return median_measure - -def exclude_zero_scale(data, stages): - inds = data['scales'] > 0 - data['scales'] = data['scales'][inds] - for stage in stages: - data[f'mean_{stage}'] = data[f'mean_{stage}'][inds, ...] - return data - -def reduce_kernel_set(data, inds, keyword, stages=['conv', 'feat']): - for stage in stages: - key = f'{keyword}_{stage}' - data[key] = data[key][:, inds, ...] - return data - - -# GENERAL SETTINGS: -target_species = [ - 'Chorthippus_biguttulus', - 'Chorthippus_mollis', - 'Chrysochraon_dispar', - 'Euchorthippus_declivus', - 'Gomphocerippus_rufus', - 'Omocestus_rufipes', - 'Pseudochorthippus_parallelus', -][5] -example_file = { - 'Chorthippus_biguttulus': 'Chorthippus_biguttulus_GBC_94-17s73.1ms-19s977ms', - 'Chorthippus_mollis': 'Chorthippus_mollis_DJN_41_T28C-46s4.58ms-1m15s697ms', - 'Chrysochraon_dispar': 'Chrysochraon_dispar_DJN_26_T28C_DT-32s134ms-34s432ms', - 'Euchorthippus_declivus': 'Euchorthippus_declivus_FTN_79-2s167ms-2s563ms', - 'Gomphocerippus_rufus': 'Gomphocerippus_rufus_FTN_91-3-884ms-10s427ms', - 'Omocestus_rufipes': 'Omocestus_rufipes_DJN_32-40s724ms-48s779ms', - 'Pseudochorthippus_parallelus': 'Pseudochorthippus_parallelus_GBC_88-6s678ms-9s32.3ms' -}[target_species] -stages = ['filt', 'env', 'log', 'inv', 'conv', 'feat'] -raw_path = search_files(target_species, incl='unnormed', dir='../data/inv/full/condensed/')[0] -base_path = search_files(target_species, incl='base', dir='../data/inv/full/condensed/')[0] -range_path = search_files(target_species, incl='range', dir='../data/inv/full/condensed/')[0] -snip_path = search_files(example_file, dir='../data/inv/full/')[0] -save_path = '../figures/fig_invariance_full.pdf' - -# ANALYSIS SETTINGS: -exclude_zero = True - -# SUBSET SETTINGS: -types = np.array([1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10]) -sigmas = np.array([0.001, 0.002, 0.004, 0.008, 0.016, 0.032]) -# types = [1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10] -# sigmas = [0.001, 0.002, 0.004, 0.008, 0.016, 0.032] -kernels = np.array([ - [1, 0.002], - [-1, 0.002], - [2, 0.004], - [-2, 0.004], - [3, 0.032], - [-3, 0.032] -]) -kernels = None - -# GRAPH SETTINGS: -fig_kwargs = dict( - figsize=(32/2.54, 32/2.54), -) -super_grid_kwargs = dict( - nrows=2, - ncols=1, - wspace=0, - hspace=0, - left=0, - right=1, - bottom=0, - top=1, - height_ratios=[3, 2] -) -subfig_specs = dict( - snip=(0, 0), - big=(1, 0), -) -snip_grid_kwargs = dict( - nrows=len(stages), - ncols=None, - wspace=0.1, - hspace=0.4, - left=0.11, - right=0.98, - bottom=0.08, - top=0.95 -) -big_grid_kwargs = dict( - nrows=1, - ncols=3, - wspace=0.4, - hspace=0, - left=snip_grid_kwargs['left'], - right=snip_grid_kwargs['right'], - bottom=0.13, - top=0.98 -) - -# PLOT SETTINGS: -fs = dict( - lab_norm=16, - lab_tex=20, - letter=22, - tit_norm=16, - tit_tex=20, - bar=16, -) -colors = load_colors('../data/stage_colors.npz') -conv_colors = load_colors('../data/conv_colors_all.npz') -feat_colors = load_colors('../data/feat_colors_all.npz') -lw = dict( - filt=0.25, - env=0.25, - log=0.25, - inv=0.25, - conv=0.25, - feat=1, - big=3, - plateau=1.5, -) -xlabels = dict( - big='scale $\\alpha$', -) -ylabels = dict( - filt='$x_{\\text{filt}}$', - env='$x_{\\text{env}}$', - log='$x_{\\text{db}}$', - inv='$x_{\\text{adapt}}$', - conv='$c_i$', - feat='$f_i$', - big=['measure', 'rel. measure', 'norm. measure'] -) -xlab_big_kwargs = dict( - y=0, - fontsize=fs['lab_norm'], - ha='center', - va='bottom', -) -ylab_snip_kwargs = dict( - x=0, - fontsize=fs['lab_tex'], - rotation=0, - ha='left', - va='center' -) -ylab_big_kwargs = dict( - x=-0.2, - fontsize=fs['lab_norm'], - ha='center', - va='bottom', -) -yloc = dict( - filt=3000, - env=1000, - log=50, - inv=20, - conv=1, - feat=1, -) -title_kwargs = dict( - x=0.5, - yref=1, - ha='center', - va='top', - fontsize=fs['tit_norm'], -) -letter_snip_kwargs = dict( - x=0, - yref=0.5, - ha='left', - va='center', - fontsize=fs['letter'], -) -letter_big_kwargs = dict( - x=0, - y=1, - ha='left', - va='bottom', - fontsize=fs['letter'], -) -bar_time = 5 -bar_kwargs = dict( - dur=bar_time, - y0=-0.25, - y1=-0.1, - xshift=1, - color='k', - lw=0, - clip_on=False, - text_pos=(-0.1, 0.5), - text_str=f'${bar_time}\\,\\text{{s}}$', - text_kwargs=dict( - fontsize=fs['bar'], - ha='right', - va='center', - ) -) -plateau_settings = dict( - low=0.05, - high=0.95, - first=True, - last=True, - condense=None, -) -plateau_line_kwargs = dict( - lw=lw['plateau'], - ls='--', - zorder=1, -) -plateau_dot_kwargs = dict( - marker='o', - markersize=8, - markeredgewidth=1, - clip_on=False, -) - -# EXECUTION: - -# Load raw (unnormed) invariance data: -data, config = load_data(raw_path, files='scales', keywords='mean') -if exclude_zero: - data = exclude_zero_scale(data, stages) -scales = data['scales'] - -# Load snippet data: -snip, _ = load_data(snip_path, files='example_scales', keywords='snip') -t_full = np.arange(snip['snip_filt'].shape[0]) / config['rate'] -snip_scales = snip['example_scales'] - -# Optional kernel subset: -reduce_kernels = False -if any(var is not None for var in [kernels, types, sigmas]): - kern_inds = find_kern_specs(config['k_specs'], kernels, types, sigmas) - data = reduce_kernel_set(data, kern_inds, keyword='mean') - snip = reduce_kernel_set(snip, kern_inds, keyword='snip') - config['k_specs'] = config['k_specs'][kern_inds, :] - config['kernels'] = config['kernels'][:, kern_inds] - reduce_kernels = True - -# Adjust grid parameters: -snip_grid_kwargs['ncols'] = snip_scales.size - -# Prepare overall graph: -fig = plt.figure(**fig_kwargs) -super_grid = fig.add_gridspec(**super_grid_kwargs) - -# Prepare stage-specific snippet axes: -snip_subfig = fig.add_subfigure(super_grid[subfig_specs['snip']]) -snip_grid = snip_subfig.add_gridspec(**snip_grid_kwargs) -snip_axes = np.zeros((snip_grid.nrows, snip_grid.ncols), dtype=object) -for i, j in product(range(snip_grid.nrows), range(snip_grid.ncols)): - ax = snip_subfig.add_subplot(snip_grid[i, j]) - ax.set_xlim(t_full[0], t_full[-1]) - ax.yaxis.set_major_locator(plt.MultipleLocator(yloc[stages[i]])) - hide_axis(ax, 'bottom') - if i == 0: - title = title_subplot(ax, f'$\\alpha={strip_zeros(snip_scales[j])}$', - ref=snip_subfig, **title_kwargs) - if j == 0: - ylabel(ax, ylabels[stages[i]], **ylab_snip_kwargs, transform=snip_subfig.transSubfigure) - else: - hide_axis(ax, 'left') - snip_axes[i, j] = ax -time_bar(snip_axes[-1, -1], **bar_kwargs) -letter_subplot(snip_subfig, 'a', ref=title, **letter_snip_kwargs) - -# Prepare analysis axes: -big_subfig = fig.add_subfigure(super_grid[subfig_specs['big']]) -big_grid = big_subfig.add_gridspec(**big_grid_kwargs) -big_axes = np.zeros((big_grid.ncols,), dtype=object) -for i in range(big_grid.ncols): - ax = big_subfig.add_subplot(big_grid[0, i]) - ax.set_xlim(scales[0], scales[-1]) - ax.set_xscale('symlog', linthresh=scales[1], linscale=0.5) - ax.set_yscale('symlog', linthresh=0.01, linscale=0.1) - ylabel(ax, ylabels['big'][i], **ylab_big_kwargs) - if i < (big_grid.ncols - 1): - ax.set_ylim(scales[0], scales[-1]) - else: - ax.set_ylim(0, 1) - big_axes[i] = ax -super_xlabel(xlabels['big'], big_subfig, big_axes[0], big_axes[-1], **xlab_big_kwargs) -letter_subplots(big_axes, 'bcd', **letter_big_kwargs) - -if True: - # Plot filtered snippets: - plot_snippets(snip_axes[0, :], t_full, snip['snip_filt'], - c=colors['filt'], lw=lw['filt']) - - # Plot envelope snippets: - plot_snippets(snip_axes[1, :], t_full, snip['snip_env'], - ymin=0, c=colors['env'], lw=lw['env']) - - # Plot logarithmic snippets: - plot_snippets(snip_axes[2, :], t_full, snip['snip_log'], - c=colors['log'], lw=lw['log']) - - # Plot invariant snippets: - plot_snippets(snip_axes[3, :], t_full, snip['snip_inv'], - c=colors['inv'], lw=lw['inv']) - - # Plot kernel response snippets: - all_handles = plot_snippets(snip_axes[4, :], t_full, snip['snip_conv'], - c=colors['conv'], lw=lw['conv']) - for i, handles in enumerate(all_handles): - assign_colors(handles, config['k_specs'][:, 0], conv_colors) - reorder_by_sd(handles, snip['snip_conv'][..., i]) - - # Plot feature snippets: - all_handles = plot_snippets(snip_axes[5, :], t_full, snip['snip_feat'], - ymin=0, ymax=1, c=colors['feat'], lw=lw['feat']) - for i, handles in enumerate(all_handles): - assign_colors(handles, config['k_specs'][:, 0], feat_colors) - reorder_by_sd(handles, snip['snip_feat'][..., i]) -del snip - -# Remember saturation points: -crit_inds, crit_scales = {}, {} - -# Unnormed measures: -for stage in stages: - # Plot average intensity measure across recordings: - curve = plot_curves(big_axes[0], scales, data[f'mean_{stage}'].mean(axis=-1), - c=colors[stage], lw=lw['big'], - fill_kwargs=dict(color=colors[stage], alpha=0.25)) - # Indicate saturation point: - if stage in ['log', 'inv', 'conv', 'feat']: - ind = get_saturation(curve, **plateau_settings)[1] - scale = scales[ind] - big_axes[0].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, - transform=big_axes[0].get_xaxis_transform()) - big_axes[0].plot(scale, 0, mfc=colors[stage], mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, - transform=big_axes[0].get_xaxis_transform()) - big_axes[0].vlines(scale, big_axes[0].get_ylim()[0], curve[ind], - color=colors[stage], **plateau_line_kwargs) - # Log saturation point: - crit_inds[stage] = ind - crit_scales[stage] = scale -del data - -# Noise baseline-related measures: -data, _ = load_data(base_path, files='scales', keywords='mean') -if exclude_zero: - data = exclude_zero_scale(data, stages) -if reduce_kernels: - data = reduce_kernel_set(data, kern_inds, keyword='mean') -for stage in stages: - # Plot average intensity measure across recordings: - curve = plot_curves(big_axes[1], scales, data[f'mean_{stage}'].mean(axis=-1), - c=colors[stage], lw=lw['big'], - fill_kwargs=dict(color=colors[stage], alpha=0.25)) - # Indicate saturation point: - if stage in ['log', 'inv', 'conv', 'feat']: - ind, scale = crit_inds[stage], crit_scales[stage] - big_axes[1].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, - transform=big_axes[1].get_xaxis_transform()) - big_axes[1].plot(scale, 0, mfc=colors[stage], mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, - transform=big_axes[1].get_xaxis_transform()) - big_axes[1].vlines(scale, big_axes[1].get_ylim()[0], curve[ind], - color=colors[stage], **plateau_line_kwargs) -del data - -# Min-max normalized measures: -data, _ = load_data(range_path, files='scales', keywords='mean') -if exclude_zero: - data = exclude_zero_scale(data, stages) -if reduce_kernels: - data = reduce_kernel_set(data, kern_inds, keyword='mean') -for stage in ['log', 'inv', 'conv', 'feat']: - # Plot average intensity measure across recordings: - curve = plot_curves(big_axes[2], scales, data[f'mean_{stage}'].mean(axis=-1), - c=colors[stage], lw=lw['big'], - fill_kwargs=dict(color=colors[stage], alpha=0.25)) - - # Indicate saturation point: - if stage in ['log', 'inv', 'conv', 'feat']: - ind, scale = crit_inds[stage], crit_scales[stage] - big_axes[2].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, - transform=big_axes[2].get_xaxis_transform()) - big_axes[2].plot(scale, 0, mfc=colors[stage], mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, - transform=big_axes[2].get_xaxis_transform()) - big_axes[2].vlines(scale, big_axes[2].get_ylim()[0], curve[ind], - color=colors[stage], **plateau_line_kwargs) -del data - -# Save graph: -if save_path is not None: - file_name = save_path.replace('.pdf', f'_{target_species}.pdf') - fig.savefig(file_name) -plt.show() - -print('Done.') -embed() diff --git a/python/fig_invariance_short.py b/python/fig_invariance_short.py index f0cf6ea..1f31e83 100644 --- a/python/fig_invariance_short.py +++ b/python/fig_invariance_short.py @@ -5,11 +5,12 @@ from itertools import product from thunderhopper.filetools import search_files from thunderhopper.modeltools import load_data from thunderhopper.filtertools import find_kern_specs -from misc_functions import get_saturation +from misc_functions import get_saturation, reduce_kernel_set, exclude_zero_scale,\ + divide_by_zero, x_dist, y_dist from color_functions import load_colors -from plot_functions import hide_axis, ylimits, super_xlabel, ylabel, title_subplot,\ +from plot_functions import hide_axis, reorder_by_sd, ylimits, super_xlabel, ylabel, title_subplot,\ plot_line, strip_zeros, time_bar, assign_colors,\ - letter_subplot, letter_subplots, reorder_by_sd + letter_subplot, letter_subplots, hide_ticks from IPython import embed def plot_snippets(axes, time, snippets, ymin=None, ymax=None, **kwargs): @@ -20,29 +21,13 @@ def plot_snippets(axes, time, snippets, ymin=None, ymax=None, **kwargs): ymin=ymin, ymax=ymax, **kwargs)) return handles -def plot_curves(ax, scales, measures, fill_kwargs={}, **kwargs): +def plot_curves(ax, scales, measures, **kwargs): if measures.ndim == 1: - ax.plot(scales, measures, **kwargs)[0] - return measures + handles = ax.plot(scales, measures, **kwargs) + return handles, measures median_measure = np.nanmedian(measures, axis=1) - spread_measure = [np.nanpercentile(measures, 25, axis=1), - np.nanpercentile(measures, 75, axis=1)] - ax.plot(scales, median_measure, **kwargs)[0] - ax.fill_between(scales, *spread_measure, **fill_kwargs) - return median_measure - -def exclude_zero_scale(data, stages): - inds = data['scales'] > 0 - data['scales'] = data['scales'][inds] - for stage in stages: - data[f'mean_{stage}'] = data[f'mean_{stage}'][inds, ...] - return data - -def reduce_kernel_set(data, inds, keyword, stages=['conv', 'feat']): - for stage in stages: - key = f'{keyword}_{stage}' - data[key] = data[key][:, inds, ...] - return data + line_handle = ax.plot(scales, median_measure, **kwargs)[0] + return line_handle, median_measure # GENERAL SETTINGS: @@ -65,29 +50,28 @@ example_file = { 'Pseudochorthippus_parallelus': 'Pseudochorthippus_parallelus_GBC_88-6s678ms-9s32.3ms' }[target_species] stages = ['filt', 'env', 'inv', 'conv', 'feat'] -raw_path = search_files(target_species, incl='unnormed', dir='../data/inv/short/condensed/')[0] -base_path = search_files(target_species, incl='base', dir='../data/inv/short/condensed/')[0] -range_path = search_files(target_species, incl='range', dir='../data/inv/short/condensed/')[0] -snip_path = search_files(example_file, dir='../data/inv/short/')[0] +data_path = search_files(example_file, dir='../data/inv/short/')[0] save_path = '../figures/fig_invariance_short.pdf' # ANALYSIS SETTINGS: exclude_zero = True +thresh_rel = np.array([0, 0.5, 1, 1.5, 2, 2.5, 3])[4] +percentiles = np.array([0, 100]) +scale_subset_kwargs = dict( + combis=[['measure'], stages], +) +kern_subset_kwargs = dict( + combis=[['measure', 'snip'], ['conv', 'feat']], + keys=['thresh_abs'], +) # SUBSET SETTINGS: -types = np.array([1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10]) -sigmas = np.array([0.001, 0.002, 0.004, 0.008, 0.016, 0.032]) +types = np.array([1, -1, 2, -2, 3, -3, 4, -4]) # types = [1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10] +sigmas = np.array([0.001, 0.002, 0.004, 0.008, 0.016]) # sigmas = [0.001, 0.002, 0.004, 0.008, 0.016, 0.032] -kernels = np.array([ - [1, 0.002], - [-1, 0.002], - [2, 0.004], - [-2, 0.004], - [3, 0.032], - [-3, 0.032] -]) kernels = None +reduce_kernels = any(var is not None for var in [kernels, types, sigmas]) # GRAPH SETTINGS: fig_kwargs = dict( @@ -95,39 +79,52 @@ fig_kwargs = dict( ) super_grid_kwargs = dict( nrows=2, - ncols=1, + ncols=2, wspace=0, hspace=0, left=0, right=1, bottom=0, top=1, - height_ratios=[3, 2] + height_ratios=[1, 1] ) subfig_specs = dict( - snip=(0, 0), - big=(1, 0), + snip=(0, slice(None)), + raw=(1, 0), + base=(1, 1), ) snip_grid_kwargs = dict( nrows=len(stages), ncols=None, wspace=0.1, hspace=0.4, - left=0.11, + left=0.13, right=0.98, - bottom=0.08, + bottom=0.05, top=0.95 ) -big_grid_kwargs = dict( - nrows=1, - ncols=3, - wspace=0.4, - hspace=0, - left=snip_grid_kwargs['left'], - right=snip_grid_kwargs['right'], - bottom=0.13, - top=0.98 +raw_grid_kwargs = dict( + nrows=2, + ncols=1, + wspace=0, + hspace=0.15, + left=0.14, + right=0.9, + bottom=0.1, + top=0.95, + height_ratios=[0.8, 0.2] ) +base_grid_kwargs = dict( + nrows=3, + ncols=1, + wspace=0, + hspace=0.25, + left=raw_grid_kwargs['left'], + right=raw_grid_kwargs['right'], + bottom=raw_grid_kwargs['bottom'], + top=raw_grid_kwargs['top'], +) +inset_bounds = [1.01, 0, 0.95, 1] # PLOT SETTINGS: fs = dict( @@ -138,17 +135,22 @@ fs = dict( tit_tex=20, bar=16, ) -colors = load_colors('../data/stage_colors.npz') -conv_colors = load_colors('../data/conv_colors_all.npz') -feat_colors = load_colors('../data/feat_colors_all.npz') +stage_colors = load_colors('../data/stage_colors.npz') +kern_colors = dict( + conv=load_colors('../data/conv_colors_subset.npz'), + feat=load_colors('../data/feat_colors_subset.npz') +) lw = dict( filt=0.25, env=0.25, - conv=0.25, inv=0.25, + conv=0.25, feat=1, - big=3, + single=3, + swarm=1, plateau=1.5, + legend=5, + dist=1 ) xlabels = dict( big='scale $\\alpha$', @@ -159,7 +161,8 @@ ylabels = dict( inv='$x_{\\text{adapt}}$\n$[\\text{dB}]$', conv='$c_i$\n$[\\text{dB}]$', feat='$f_i$', - big=['measure', 'rel. measure', 'norm. measure'] + raw=['$m$', '$\\mu_{f_i}$'], + base=['$m\\,/\\,m_{\\eta}$', '$\\mu_{f_i}$', '$\\text{PDF}_{\\alpha}$'] ) xlab_big_kwargs = dict( y=0, @@ -168,23 +171,23 @@ xlab_big_kwargs = dict( va='bottom', ) ylab_snip_kwargs = dict( - x=0, + x=0.03, fontsize=fs['lab_tex'], rotation=0, - ha='left', - va='center' + ha='center', + va='center', ) ylab_big_kwargs = dict( - x=-0.2, + x=0, fontsize=fs['lab_norm'], ha='center', - va='bottom', + va='top', ) yloc = dict( filt=3000, env=1000, - inv=1000, - conv=30, + inv=500, + conv=10, feat=1, ) title_kwargs = dict( @@ -202,17 +205,17 @@ letter_snip_kwargs = dict( fontsize=fs['letter'], ) letter_big_kwargs = dict( - x=0, + xref=0, y=1, ha='left', - va='bottom', + va='center', fontsize=fs['letter'], ) bar_time = 5 bar_kwargs = dict( dur=bar_time, - y0=-0.25, - y1=-0.1, + y0=-0.3, + y1=-0.15, xshift=1, color='k', lw=0, @@ -225,6 +228,34 @@ bar_kwargs = dict( va='center', ) ) +leg_kwargs = dict( + ncols=1, + loc='upper left', + bbox_to_anchor=(0.025, 0.5, 0.5, 0.5), + frameon=False, + prop=dict( + size=20, + ), + borderpad=0, + borderaxespad=0, + handlelength=1, + columnspacing=1, + handletextpad=0.5, + labelspacing=0.1 +) +leg_labels = dict( + filt='$x_{\\text{filt}}$', + env='$x_{\\text{env}}$', + inv='$x_{\\text{adapt}}$', + conv='$c_i$', + feat='$f_i$' +) +dist_line_kwargs = dict( + lw=lw['dist'], +) +dist_fill_kwargs = dict( + lw=lw['dist'], +) plateau_settings = dict( low=0.05, high=0.95, @@ -246,24 +277,30 @@ plateau_dot_kwargs = dict( # EXECUTION: -# Load raw (unnormed) invariance data: -data, config = load_data(raw_path, files='scales', keywords='mean') -if exclude_zero: - data = exclude_zero_scale(data, stages) -scales = data['scales'] +# Load invariance data: +data, config = load_data(data_path, keywords=['snip', 'scales', 'measure', 'thresh']) +t_full = np.arange(data['snip_filt'].shape[0]) / config['rate'] -# Load snippet data: -snip, _ = load_data(snip_path, files='example_scales', keywords='snip') -t_full = np.arange(snip['snip_filt'].shape[0]) / config['rate'] -snip_scales = snip['example_scales'] - -# Optional kernel subset: -reduce_kernels = False -if any(var is not None for var in [kernels, types, sigmas]): +# Reduce kernels: +if reduce_kernels: kern_inds = find_kern_specs(config['k_specs'], kernels, types, sigmas) - data = reduce_kernel_set(data, kern_inds, keyword='mean') - snip = reduce_kernel_set(snip, kern_inds, keyword='snip') - reduce_kernels = True + data = reduce_kernel_set(data, kern_inds, **kern_subset_kwargs) + config['k_specs'] = config['k_specs'][kern_inds, :] + config['kernels'] = config['kernels'][:, kern_inds] + +# Reduce thresholds: +thresh_ind = np.nonzero(data['thresh_rel'] == thresh_rel)[0][0] +data['measure_feat'] = data['measure_feat'][:, :, thresh_ind] +data['snip_feat'] = data['snip_feat'][:, :, :, thresh_ind] + +# Remember pure-noise reference measures: +ref_data = {stage: data[f'measure_{stage}'][0, ...] for stage in stages} + +# Reduce scales: +if exclude_zero: + data = exclude_zero_scale(data, **scale_subset_kwargs) +scales = data['scales'] +snip_scales = data['example_scales'] # Adjust grid parameters: snip_grid_kwargs['ncols'] = snip_scales.size @@ -292,120 +329,170 @@ for i, j in product(range(snip_grid.nrows), range(snip_grid.ncols)): time_bar(snip_axes[-1, -1], **bar_kwargs) letter_subplot(snip_subfig, 'a', ref=title, **letter_snip_kwargs) -# Prepare analysis axes: -big_subfig = fig.add_subfigure(super_grid[subfig_specs['big']]) -big_grid = big_subfig.add_gridspec(**big_grid_kwargs) -big_axes = np.zeros((big_grid.ncols,), dtype=object) -for i in range(big_grid.ncols): - ax = big_subfig.add_subplot(big_grid[0, i]) +# Prepare raw analysis axes: +raw_subfig = fig.add_subfigure(super_grid[subfig_specs['raw']]) +raw_grid = raw_subfig.add_gridspec(**raw_grid_kwargs) +raw_axes = np.zeros((raw_grid.nrows,), dtype=object) +for i in range(raw_grid.nrows): + ax = raw_subfig.add_subplot(raw_grid[i, 0]) ax.set_xlim(scales[0], scales[-1]) ax.set_xscale('symlog', linthresh=scales[1], linscale=0.5) - ax.set_yscale('symlog', linthresh=0.01, linscale=0.1) - ylabel(ax, ylabels['big'][i], **ylab_big_kwargs) - if i < (big_grid.ncols - 1): - ax.set_ylim(scales[0], scales[-1]) + ylabel(ax, ylabels['raw'][i], transform=raw_subfig.transSubfigure, **ylab_big_kwargs) + if i == 0: + ax.set_yscale('symlog', linthresh=0.0001, linscale=0.1) + hide_ticks(ax, 'bottom') else: - ax.set_ylim(0, 1) - big_axes[i] = ax -super_xlabel(xlabels['big'], big_subfig, big_axes[0], big_axes[-1], **xlab_big_kwargs) -letter_subplots(big_axes, 'bcd', **letter_big_kwargs) + transform = raw_subfig.transSubfigure + ax.transAxes.inverted() + inset_x1 = transform.transform((inset_bounds[2], 0))[0] + inset_bounds[2] = inset_x1 - inset_bounds[0] + raw_inset = ax.inset_axes(inset_bounds) + raw_inset.axis('off') + raw_axes[i] = ax +letter_subplots(raw_axes, 'bc', ref=raw_subfig, **letter_big_kwargs) + +# Prepare base analysis axes: +base_subfig = fig.add_subfigure(super_grid[subfig_specs['base']]) +base_grid = base_subfig.add_gridspec(**base_grid_kwargs) +base_axes = np.zeros((base_grid.nrows,), dtype=object) +for i in range(base_grid.nrows): + ax = base_subfig.add_subplot(base_grid[i, 0]) + ax.set_xlim(scales[0], scales[-1]) + ax.set_xscale('symlog', linthresh=scales[1], linscale=0.5) + ylabel(ax, ylabels['base'][i], transform=base_subfig.transSubfigure, **ylab_big_kwargs) + if i < base_grid_kwargs['nrows'] - 1: + ax.set_yscale('symlog', linthresh=0.01, linscale=0.1) + hide_ticks(ax, 'bottom') + if i == 1: + base_inset = ax.inset_axes(inset_bounds) + base_inset.set_yscale('symlog', linthresh=0.01, linscale=0.1) + base_inset.axis('off') + base_axes[i] = ax +letter_subplots(base_axes, 'def', ref=base_subfig, **letter_big_kwargs) +super_xlabel(xlabels['big'], fig, raw_axes[-1], base_axes[-1], + left_fig=raw_subfig, right_fig=base_subfig, **xlab_big_kwargs) if True: # Plot filtered snippets: - plot_snippets(snip_axes[0, :], t_full, snip['snip_filt'], - c=colors['filt'], lw=lw['filt']) + plot_snippets(snip_axes[0, :], t_full, data['snip_filt'], + c=stage_colors['filt'], lw=lw['filt']) # Plot envelope snippets: - plot_snippets(snip_axes[1, :], t_full, snip['snip_env'], - ymin=0, c=colors['env'], lw=lw['env']) + plot_snippets(snip_axes[1, :], t_full, data['snip_env'], + ymin=0, c=stage_colors['env'], lw=lw['env']) - # Plot "adapted" snippets: - plot_snippets(snip_axes[2, :], t_full, snip['snip_inv'], - c=colors['inv'], lw=lw['inv']) + # Plot invariant snippets: + plot_snippets(snip_axes[2, :], t_full, data['snip_inv'], + c=stage_colors['inv'], lw=lw['inv']) # Plot kernel response snippets: - all_handles = plot_snippets(snip_axes[3, :], t_full, snip['snip_conv'], - c=colors['conv'], lw=lw['conv']) + all_handles = plot_snippets(snip_axes[3, :], t_full, data['snip_conv'], + c=stage_colors['conv'], lw=lw['conv']) for i, handles in enumerate(all_handles): - assign_colors(handles, config['k_specs'][:, 0], conv_colors) - reorder_by_sd(handles, snip['snip_conv'][..., i]) + assign_colors(handles, config['k_specs'][:, 0], kern_colors['conv']) + reorder_by_sd(handles, data['snip_conv'][..., i]) # Plot feature snippets: - all_handles = plot_snippets(snip_axes[4, :], t_full, snip['snip_feat'], - ymin=0, ymax=1, c=colors['feat'], lw=lw['feat']) + all_handles = plot_snippets(snip_axes[4, :], t_full, data['snip_feat'], + ymin=0, ymax=1, c=stage_colors['feat'], lw=lw['feat']) for i, handles in enumerate(all_handles): - assign_colors(handles, config['k_specs'][:, 0], feat_colors) - reorder_by_sd(handles, snip['snip_feat'][..., i]) -del snip + assign_colors(handles, config['k_specs'][:, 0], kern_colors['feat']) + reorder_by_sd(handles, data['snip_feat'][..., i]) -# Remember saturation points: -crit_inds, crit_scales = {}, {} - -# Unnormed measures: +# Plot analysis results: +leg_handles = [] for stage in stages: - # Plot average intensity measure across recordings: - curve = plot_curves(big_axes[0], scales, data[f'mean_{stage}'].mean(axis=-1), - c=colors[stage], lw=lw['big'], - fill_kwargs=dict(color=colors[stage], alpha=0.25)) + mkey = f'measure_{stage}' + measure = data[mkey] + color = stage_colors[stage] + + ## UNNORMALIZED MEASURE: + + # Plot single raw intensity curve (median where necessary): + handles, curve = plot_curves(raw_axes[0], scales, measure, c=color, lw=lw['single']) + + # Add stage-specific proxy legend artist: + leg_handles.append(raw_axes[0].plot([], [], c=color, label=leg_labels[stage])[0]) + + # Plot curve swarm: + if stage == 'feat': + # Sync y-limits: + ylimits(measure, raw_axes[1], minval=0, pad=0.05) + raw_inset.set_ylim(raw_axes[1].get_ylim()) + # Plot swarm: + handles = raw_axes[1].plot(scales, measure, lw=lw['swarm']) + assign_colors(handles, config['k_specs'][:, 0], kern_colors[stage]) + reorder_by_sd(handles, measure) + # Plot distribution of saturation levels: + line_kwargs = dist_line_kwargs | dict(c=color) + fill_kwargs = dist_fill_kwargs | dict(color=color) + y_dist(raw_inset, measure[-1], nbins=75, log=False, + line_kwargs=line_kwargs, fill_kwargs=fill_kwargs) + # Indicate saturation point: if stage == 'feat': - ind = get_saturation(curve, **plateau_settings)[1] - scale = scales[ind] - big_axes[0].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, - transform=big_axes[0].get_xaxis_transform()) - big_axes[0].plot(scale, 0, mfc=colors[stage], mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, - transform=big_axes[0].get_xaxis_transform()) - big_axes[0].vlines(scale, big_axes[0].get_ylim()[0], curve[ind], - color=colors[stage], **plateau_line_kwargs) - # Log saturation point: - crit_inds[stage] = ind - crit_scales[stage] = scale -del data + crit_ind = get_saturation(curve, **plateau_settings)[1] + crit_scale = scales[crit_ind] + raw_axes[0].plot(crit_scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, + transform=raw_axes[0].get_xaxis_transform()) + raw_axes[0].plot(crit_scale, 0, mfc=color, mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, + transform=raw_axes[0].get_xaxis_transform()) + raw_axes[0].vlines(crit_scale, raw_axes[0].get_ylim()[0], curve[crit_ind], + color=color, **plateau_line_kwargs) -# Noise baseline-related measures: -data, _ = load_data(base_path, files='scales', keywords='mean') -if exclude_zero: - data = exclude_zero_scale(data, stages) -if reduce_kernels: - data = reduce_kernel_set(data, kern_inds, keyword='mean') -for stage in stages: - # Plot average intensity measure across recordings: - curve = plot_curves(big_axes[1], scales, data[f'mean_{stage}'].mean(axis=-1), - c=colors[stage], lw=lw['big'], - fill_kwargs=dict(color=colors[stage], alpha=0.25)) - # Indicate saturation point: + ## NORMALIZED MEASURE: + + # Relate to noise baseline: + measure = divide_by_zero(data[mkey], ref_data[stage]) + + # Plot single baseline-normalized intensity curve (median where necessary): + handles, curve = plot_curves(base_axes[0], scales, measure, c=color, lw=lw['single']) + + # Plot curve swarm: if stage == 'feat': - ind, scale = crit_inds[stage], crit_scales[stage] - big_axes[1].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, - transform=big_axes[1].get_xaxis_transform()) - big_axes[1].plot(scale, 0, mfc=colors[stage], mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, - transform=big_axes[1].get_xaxis_transform()) - big_axes[1].vlines(scale, big_axes[1].get_ylim()[0], curve[ind], - color=colors[stage], **plateau_line_kwargs) -del data - -# Min-max normalized measures: -data, _ = load_data(range_path, files='scales', keywords='mean') -if exclude_zero: - data = exclude_zero_scale(data, stages) -if reduce_kernels: - data = reduce_kernel_set(data, kern_inds, keyword='mean') -for stage in ['feat']: - # Plot average intensity measure across recordings: - curve = plot_curves(big_axes[2], scales, data[f'mean_{stage}'].mean(axis=-1), - c=colors[stage], lw=lw['big'], - fill_kwargs=dict(color=colors[stage], alpha=0.25)) + # Sync y-limits: + ylimits(measure, base_axes[1], minval=0.9, pad=0.05) + base_inset.set_ylim(base_axes[1].get_ylim()) + # Plot swarm: + handles = base_axes[1].plot(scales, measure, lw=lw['swarm']) + assign_colors(handles, config['k_specs'][:, 0], kern_colors[stage]) + reorder_by_sd(handles, measure) + # Plot distribution of saturation levels: + line_kwargs = dist_line_kwargs | dict(c=color) + fill_kwargs = dist_fill_kwargs | dict(color=color) + y_dist(base_inset, measure[-1], nbins=100, log=True, + line_kwargs=line_kwargs, fill_kwargs=fill_kwargs) + # Plot distribution of saturation points: + inds = np.array(get_saturation(measure, **plateau_settings)[1]) + if np.isnan(inds).sum(): + inds = inds[~np.isnan(inds)].astype(int) + crit_scales = scales[inds] + bin_lims = [0.01, 1.1 * crit_scales.max()] + line_kwargs = dist_line_kwargs | dict(c=stage_colors['feat']) + fill_kwargs = dist_fill_kwargs | dict(color=stage_colors['feat']) + x_dist(base_axes[-1], crit_scales, nbins=75, limits=bin_lims, log=True, + line_kwargs=line_kwargs, fill_kwargs=fill_kwargs) + # Add single curve saturation point: + base_axes[-1].plot(crit_scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, + transform=base_axes[-1].get_xaxis_transform()) + base_axes[-1].plot(crit_scale, 0, mfc=stage_colors['feat'], mec='k', alpha=0.75, + zorder=6, **plateau_dot_kwargs, transform=base_axes[-1].get_xaxis_transform()) # Indicate saturation point: if stage == 'feat': - ind, scale = crit_inds[stage], crit_scales[stage] - big_axes[2].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, - transform=big_axes[2].get_xaxis_transform()) - big_axes[2].plot(scale, 0, mfc=colors[stage], mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, - transform=big_axes[2].get_xaxis_transform()) - big_axes[2].vlines(scale, big_axes[2].get_ylim()[0], curve[ind], - color=colors[stage], **plateau_line_kwargs) -del data + base_axes[0].plot(crit_scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, + transform=base_axes[0].get_xaxis_transform()) + base_axes[0].plot(crit_scale, 0, mfc=color, mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, + transform=base_axes[0].get_xaxis_transform()) + base_axes[0].vlines(crit_scale, base_axes[0].get_ylim()[0], curve[crit_ind], + color=color, **plateau_line_kwargs) + +# Posthoc adjustments: +raw_axes[0].set_ylim(bottom=0.0001) +base_axes[0].set_ylim(1, 100) + +# Add legend to first analysis axis: +legend = raw_axes[0].legend(handles=leg_handles, **leg_kwargs) +[handle.set_lw(lw['legend']) for handle in legend.get_lines()] # Save graph: if save_path is not None: diff --git a/python/fig_invariance_thresh-lp_single.py b/python/fig_invariance_thresh-lp_single.py index 87c8a08..a81bdf2 100644 --- a/python/fig_invariance_thresh-lp_single.py +++ b/python/fig_invariance_thresh-lp_single.py @@ -153,10 +153,10 @@ xlabels = dict( ) ylabels = dict( inv='$x_{\\text{adapt}}$\n$[\\text{dB}]$', - conv='$c_i$\n$[\\text{dB}]$', - bi='$b_i$', - feat='$f_i$', - big='$\\mu_{f_i}$', + conv='$c$\n$[\\text{dB}]$', + bi='$b$', + feat='$f$', + big='$\\mu_f$', ) xlab_alpha_kwargs = dict( y=0.5, @@ -366,7 +366,7 @@ for i in range(thresh_rel.size): low_box = axes[-1, 0].get_position() high_box = axes[0, 0].get_position() [hide_axis(ax, 'left') for ax in axes[1:, 1]] - super_ylabel(f'$\\Theta_i={strip_zeros(thresh_rel[i])}\\cdot\\sigma_{{\\eta}}$', + super_ylabel(f'$\\Theta={strip_zeros(thresh_rel[i])}\\cdot\\sigma_{{\\eta}}$', snip_subfig, axes[-1, 0], axes[0, 0], **ylab_super_kwargs) for (ax1, ax2), stage in zip(axes[:, :2], stages): ax1.yaxis.set_major_locator(plt.MultipleLocator(yloc[stage][0])) diff --git a/python/misc_functions.py b/python/misc_functions.py index ec5762d..1eefa80 100644 --- a/python/misc_functions.py +++ b/python/misc_functions.py @@ -112,6 +112,46 @@ def get_thresholds(data=None, path=None, perc=None, factor=None, factors = data['factors'][inds] return data['sds'] * factors, factors, data['percs'][inds, :] +def y_dist(ax, values, nbins=50, limits=None, log=False, cap=0.01, density=True, + line_kwargs={}, fill_kwargs={}): + # Get distribution: + if limits is None: + limits = np.array([np.nanmin(values), np.nanmax(values)]) + limits += np.array([-1.1, 1.1]) * (limits[1] - limits[0]) + if log: + limits[0] = max(limits[0], cap) + edges = np.geomspace(*limits, nbins + 1) + else: + edges = np.linspace(*limits, nbins + 1) + centers = edges[:-1] + np.diff(edges) / 2 + pdf, _ = np.histogram(values, bins=edges, density=density) + + # Plot distribution: + fill_handle = ax.fill_betweenx(centers, pdf.min(), pdf, **fill_kwargs) + line_handle = ax.plot(pdf, centers, **line_kwargs)[0] + ax.set_xlim(0, pdf.max() * 1.05) + return pdf, centers, line_handle, fill_handle + +def x_dist(ax, values, nbins=50, limits=None, log=False, cap=0.01, density=True, + line_kwargs={}, fill_kwargs={}): + # Get distribution: + if limits is None: + limits = np.array([np.nanmin(values), np.nanmax(values)]) + limits += np.array([-1.1, 1.1]) * (limits[1] - limits[0]) + if log: + limits[0] = max(limits[0], cap) + edges = np.geomspace(*limits, nbins + 1) + else: + edges = np.linspace(*limits, nbins + 1) + centers = edges[:-1] + np.diff(edges) / 2 + pdf, _ = np.histogram(values, bins=edges, density=density) + + # Plot distribution: + fill_handle = ax.fill_between(centers, pdf.min(), pdf, **fill_kwargs) + line_handle = ax.plot(centers, pdf, **line_kwargs)[0] + ax.set_ylim(0, pdf.max() * 1.05) + return pdf, centers,line_handle, fill_handle + def get_histogram(data, edges=None, nbins=50, pad=0.1, shared=True): if edges is None: axis = None if shared else 0 @@ -142,12 +182,15 @@ def get_kde(data, sigma, axis=None, n=1000, pad=10): def get_saturation(sigmoid, low=0.05, high=0.95, first=True, last=True, condense=None): + + unpack_inds = lambda inds: np.nan if inds.size == 0 else inds[-1] + if condense == 'norm' and sigmoid.ndim == 2: sigmoid = np.linalg.norm(sigmoid, axis=1) - min_value = sigmoid[0] if first else sigmoid.min(axis=0) - max_value = sigmoid[-1] if last else sigmoid.max(axis=0) - + min_value = sigmoid[0] if first else np.nanmin(sigmoid, axis=0) + max_value = sigmoid[-1] if last else np.nanmax(sigmoid, axis=0) + span = max_value - min_value low_value = min_value + low * span high_value = min_value + high * span @@ -155,14 +198,14 @@ def get_saturation(sigmoid, low=0.05, high=0.95, first=True, last=True, low_mask = sigmoid <= low_value high_mask = sigmoid <= high_value if sigmoid.ndim == 1: - low_ind = np.nonzero(low_mask)[0][-1] - high_ind = np.nonzero(high_mask)[0][-1] + low_ind = unpack_inds(np.nonzero(low_mask)[0]) + high_ind = unpack_inds(np.nonzero(high_mask)[0]) elif condense == 'all': - low_ind = np.nonzero(low_mask.all(axis=1))[0][-1] - high_ind = np.nonzero(high_mask.all(axis=1))[0][-1] + low_ind = unpack_inds(np.nonzero(low_mask.all(axis=1))[0]) + high_ind = unpack_inds(np.nonzero(high_mask.all(axis=1))[0]) else: low_ind, high_ind = [], [] for i in range(sigmoid.shape[1]): - low_ind.append(np.nonzero(low_mask[:, i])[0][-1]) - high_ind.append(np.nonzero(high_mask[:, i])[0][-1]) + low_ind.append(unpack_inds(np.nonzero(low_mask[:, i])[0])) + high_ind.append(unpack_inds(np.nonzero(high_mask[:, i])[0])) return low_ind, high_ind diff --git a/python/save_inv_data_full.py b/python/save_inv_data_full.py index 8e329b8..d10f298 100644 --- a/python/save_inv_data_full.py +++ b/python/save_inv_data_full.py @@ -16,7 +16,7 @@ target_species = [ 'Gomphocerippus_rufus', 'Omocestus_rufipes', 'Pseudochorthippus_parallelus', -][6] +][4] example_file = { 'Chorthippus_biguttulus': 'Chorthippus_biguttulus_GBC_94-17s73.1ms-19s977ms', 'Chorthippus_mollis': 'Chorthippus_mollis_DJN_41_T28C-46s4.58ms-1m15s697ms',