diff --git a/notebooks/01_exploration.ipynb b/notebooks/01_exploration.ipynb
index 7d3e2d5..0430e6f 100644
--- a/notebooks/01_exploration.ipynb
+++ b/notebooks/01_exploration.ipynb
@@ -17,13 +17,8 @@
},
{
"cell_type": "code",
- "execution_count": 10,
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-19T02:55:24.823837Z",
- "start_time": "2018-12-19T02:55:16.373122Z"
- }
- },
+ "execution_count": null,
+ "metadata": {},
"outputs": [],
"source": [
"# Enable autoreloading of our modules. \n",
@@ -36,14 +31,8 @@
},
{
"cell_type": "code",
- "execution_count": 11,
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-19T02:55:24.844241Z",
- "start_time": "2018-12-19T02:55:24.823837Z"
- },
- "scrolled": true
- },
+ "execution_count": null,
+ "metadata": {},
"outputs": [],
"source": [
"from IPython.core.debugger import set_trace\n",
@@ -80,36 +69,13 @@
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": null,
"metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-19T02:57:41.855174Z",
- "start_time": "2018-12-19T02:57:13.770371Z"
- },
"pixiedust": {
"displayParams": {}
- },
- "scrolled": false
- },
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Importing waves.csv\n",
- "Importing tides.csv\n",
- "Importing profiles.csv\n",
- "Importing sites.csv\n",
- "Importing profile_features_crest_toes.csv\n",
- "Importing impacts_forecasted_foreshore_slope_sto06.csv\n",
- "Importing impacts_forecasted_mean_slope_sto06.csv\n",
- "Importing impacts_observed.csv\n",
- "Importing twl_foreshore_slope_sto06.csv\n",
- "Importing twl_mean_slope_sto06.csv\n",
- "Done!\n"
- ]
}
- ],
+ },
+ "outputs": [],
"source": [
"def df_from_csv(csv, index_col, data_folder='../data/interim'):\n",
" print('Importing {}'.format(csv))\n",
@@ -142,12 +108,7 @@
},
{
"cell_type": "markdown",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-11-27T23:02:57.631306Z",
- "start_time": "2018-11-27T23:02:57.615263Z"
- }
- },
+ "metadata": {},
"source": [
"## Profile/timeseries dashboard"
]
@@ -163,33 +124,14 @@
},
{
"cell_type": "code",
- "execution_count": 14,
+ "execution_count": null,
"metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-19T02:59:16.919983Z",
- "start_time": "2018-12-19T02:59:15.659950Z"
- },
"code_folding": [
408
],
"hide_input": false
},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "a209da7c5b98416990efed34f38e82f0",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "VBox(children=(VBox(children=(HTML(value='Filter by observed and predicted impacts:'), HBox(children=(V…"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
+ "outputs": [],
"source": [
"# Create widgets for filtering by observed and forecasted impacts\n",
"filter_title = widgets.HTML(\n",
@@ -665,13 +607,8 @@
},
{
"cell_type": "code",
- "execution_count": 9,
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-18T21:44:39.877356Z",
- "start_time": "2018-12-18T21:44:39.864319Z"
- }
- },
+ "execution_count": null,
+ "metadata": {},
"outputs": [],
"source": [
"df_sites.site_no.to_csv('temp.csv')"
@@ -680,12 +617,7 @@
{
"cell_type": "markdown",
"metadata": {
- "ExecuteTime": {
- "end_time": "2018-11-22T22:52:36.039701Z",
- "start_time": "2018-11-22T22:52:36.035189Z"
- },
- "hide_input": true,
- "scrolled": true
+ "hide_input": true
},
"source": [
"## Confusion matrix\n",
@@ -694,32 +626,12 @@
},
{
"cell_type": "code",
- "execution_count": 15,
+ "execution_count": null,
"metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-19T03:23:53.913428Z",
- "start_time": "2018-12-19T03:23:52.722678Z"
- },
"code_folding": [],
- "hide_input": false,
- "scrolled": false
+ "hide_input": false
},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "6693731b472f4a9987be65ae4d528530",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "VBox(children=(VBox(children=(HTML(value='Filter by beach:'), SelectMultiple(index=(0, 1, 2, 3, 4, 5, 6…"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
+ "outputs": [],
"source": [
"# Create colorscale\n",
"rdylgr_cmap = matplotlib.cm.get_cmap('RdYlGn')\n",
@@ -823,12 +735,7 @@
{
"cell_type": "code",
"execution_count": null,
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-11T22:17:29.215527Z",
- "start_time": "2018-12-11T22:16:56.023Z"
- }
- },
+ "metadata": {},
"outputs": [],
"source": [
"# To output to file\n",
@@ -841,12 +748,7 @@
},
{
"cell_type": "markdown",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-03T23:02:47.179180Z",
- "start_time": "2018-12-03T23:02:46.367273Z"
- }
- },
+ "metadata": {},
"source": [
"## Identify sites with no results"
]
@@ -861,26 +763,9 @@
},
{
"cell_type": "code",
- "execution_count": 57,
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-13T02:09:10.914191Z",
- "start_time": "2018-12-13T02:09:09.913622Z"
- }
- },
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "The following sites have no slope defined in the twl csv file:\n",
- "['ENTRA0078', 'ENTRA0079', 'MANNING0109']\n",
- "\n",
- "The following sites have no R_high defined in the twl csv file:\n",
- "['ENTRA0078', 'ENTRA0079', 'MANNING0109']\n"
- ]
- }
- ],
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
"source": [
"df_twls = twls['forecasted']['mean_slope_sto06']\n",
"\n",
@@ -904,1062 +789,9 @@
},
{
"cell_type": "code",
- "execution_count": 58,
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-13T02:09:14.785919Z",
- "start_time": "2018-12-13T02:09:14.520986Z"
- },
- "scrolled": false
- },
- "outputs": [
- {
- "data": {
- "text/html": [
- "
\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " | \n",
- " prestorm_swash_vol | \n",
- " poststorm_swash_vol | \n",
- " swash_vol_change | \n",
- " swash_pct_change | \n",
- " prestorm_dune_face_vol | \n",
- " poststorm_dune_face_vol | \n",
- " dune_face_vol_change | \n",
- " dune_face_pct_change | \n",
- " storm_regime | \n",
- "
\n",
- " \n",
- " site_id | \n",
- " | \n",
- " | \n",
- " | \n",
- " | \n",
- " | \n",
- " | \n",
- " | \n",
- " | \n",
- " | \n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " AVOCAn0009 | \n",
- " 4.5783 | \n",
- " 0.1110 | \n",
- " 4.4673 | \n",
- " 97.5750 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " AVOCAs0001 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " AVOCAs0002 | \n",
- " 97.9463 | \n",
- " 26.6638 | \n",
- " 71.2825 | \n",
- " 72.7771 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " AVOCAs0003 | \n",
- " 70.7306 | \n",
- " 40.2020 | \n",
- " 30.7232 | \n",
- " 43.4369 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " AVOCAs0004 | \n",
- " 98.2859 | \n",
- " 45.4986 | \n",
- " 52.6330 | \n",
- " 53.5509 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " AVOCAs0005 | \n",
- " 95.5841 | \n",
- " 54.9753 | \n",
- " 40.5733 | \n",
- " 42.4478 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " AVOCAs0006 | \n",
- " 113.0441 | \n",
- " 67.8912 | \n",
- " 45.2582 | \n",
- " 40.0359 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " AVOCAs0007 | \n",
- " 65.3283 | \n",
- " 44.2821 | \n",
- " 21.4544 | \n",
- " 32.8409 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " AVOCAs0008 | \n",
- " 52.3933 | \n",
- " 45.2243 | \n",
- " 7.1728 | \n",
- " 13.6904 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " BILG0001 | \n",
- " 20.3405 | \n",
- " 7.6207 | \n",
- " 12.7198 | \n",
- " 62.5344 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " BILG0002 | \n",
- " 156.4205 | \n",
- " 98.1716 | \n",
- " 58.1659 | \n",
- " 37.1856 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " BOAT0001 | \n",
- " 23.8361 | \n",
- " 23.6865 | \n",
- " -0.0926 | \n",
- " -0.3885 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " BOAT0002 | \n",
- " 38.8398 | \n",
- " 14.0819 | \n",
- " 24.7579 | \n",
- " 63.7436 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " BOAT0003 | \n",
- " 73.6809 | \n",
- " 17.8545 | \n",
- " 55.8264 | \n",
- " 75.7678 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " BOAT0004 | \n",
- " 73.1954 | \n",
- " 23.1583 | \n",
- " 50.0372 | \n",
- " 68.3610 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " BOAT0005 | \n",
- " 53.5122 | \n",
- " 22.4537 | \n",
- " 31.0585 | \n",
- " 58.0400 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " BOOM0001 | \n",
- " 236.4540 | \n",
- " 218.4918 | \n",
- " 20.8725 | \n",
- " 8.8273 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " CATHIE0024 | \n",
- " 63.6452 | \n",
- " 38.4261 | \n",
- " 25.2191 | \n",
- " 39.6245 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " CATHIE0026 | \n",
- " 75.1334 | \n",
- " 43.7179 | \n",
- " 31.0940 | \n",
- " 41.3851 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " CRESn0069 | \n",
- " 37.5896 | \n",
- " 8.3495 | \n",
- " 29.2401 | \n",
- " 77.7877 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " DEEWHYn0008 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " DEEWHYn0009 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " DEEWHYs0005 | \n",
- " 62.3514 | \n",
- " 24.9797 | \n",
- " 37.3716 | \n",
- " 59.9372 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " DEEWHYs0008 | \n",
- " 1.0688 | \n",
- " 1.3640 | \n",
- " 0.0000 | \n",
- " 0.0000 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " DIAMONDn0023 | \n",
- " 67.9416 | \n",
- " 21.1812 | \n",
- " 46.7603 | \n",
- " 68.8244 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " DIAMONDs0006 | \n",
- " 74.9357 | \n",
- " 42.4382 | \n",
- " 32.2536 | \n",
- " 43.0416 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " DIAMONDs0007 | \n",
- " 153.7639 | \n",
- " 127.9469 | \n",
- " 26.1595 | \n",
- " 17.0128 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " DUNBn0031 | \n",
- " 36.5301 | \n",
- " 6.3289 | \n",
- " 30.2012 | \n",
- " 82.6748 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " DUNBn0055 | \n",
- " 189.5283 | \n",
- " 134.2760 | \n",
- " 56.7139 | \n",
- " 29.9237 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " ELIZA0002 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- " ... | \n",
- "
\n",
- " \n",
- " STOCNs0170 | \n",
- " 198.2785 | \n",
- " 216.6368 | \n",
- " -18.6067 | \n",
- " -9.3841 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCNs0175 | \n",
- " 136.2126 | \n",
- " 114.1715 | \n",
- " 22.4984 | \n",
- " 16.5171 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCNs0179 | \n",
- " 67.7795 | \n",
- " 45.3981 | \n",
- " 22.3815 | \n",
- " 33.0210 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCNs0180 | \n",
- " 166.0813 | \n",
- " 149.5195 | \n",
- " 15.3441 | \n",
- " 9.2389 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCNs0181 | \n",
- " 90.1147 | \n",
- " 98.9808 | \n",
- " -9.1107 | \n",
- " -10.1102 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCNs0182 | \n",
- " 67.8622 | \n",
- " 86.0118 | \n",
- " -18.1671 | \n",
- " -26.7705 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCNs0183 | \n",
- " 125.9085 | \n",
- " 137.7342 | \n",
- " -12.6233 | \n",
- " -10.0257 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCNs0184 | \n",
- " 146.6586 | \n",
- " 123.5371 | \n",
- " 23.2603 | \n",
- " 15.8602 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCNs0185 | \n",
- " 141.5421 | \n",
- " 142.7279 | \n",
- " -1.2619 | \n",
- " -0.8915 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCNs0186 | \n",
- " 115.9148 | \n",
- " 123.1507 | \n",
- " -7.8392 | \n",
- " -6.7629 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCNs0187 | \n",
- " 126.5519 | \n",
- " 147.4371 | \n",
- " -22.4452 | \n",
- " -17.7359 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCNs0188 | \n",
- " 345.5234 | \n",
- " 353.8766 | \n",
- " -11.3322 | \n",
- " -3.2797 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCNs0189 | \n",
- " 171.6354 | \n",
- " 134.9192 | \n",
- " 35.8697 | \n",
- " 20.8988 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCNs0190 | \n",
- " 151.4113 | \n",
- " 116.6381 | \n",
- " 35.0161 | \n",
- " 23.1264 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCS0014 | \n",
- " 98.4991 | \n",
- " 57.3495 | \n",
- " 40.9006 | \n",
- " 41.5238 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " STOCS0043 | \n",
- " 36.4256 | \n",
- " 11.7208 | \n",
- " 24.7048 | \n",
- " 67.8225 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0005 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0015 | \n",
- " 56.2724 | \n",
- " 16.0428 | \n",
- " 40.2296 | \n",
- " 71.4908 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0016 | \n",
- " 97.8849 | \n",
- " 39.8432 | \n",
- " 58.0417 | \n",
- " 59.2958 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0017 | \n",
- " 36.5683 | \n",
- " 8.5380 | \n",
- " 28.0303 | \n",
- " 76.6520 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0018 | \n",
- " 42.1423 | \n",
- " 10.5498 | \n",
- " 31.5925 | \n",
- " 74.9662 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0019 | \n",
- " 39.6097 | \n",
- " 9.2404 | \n",
- " 30.3693 | \n",
- " 76.6714 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0020 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0021 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0022 | \n",
- " 1.1034 | \n",
- " 0.4478 | \n",
- " 0.6556 | \n",
- " 59.4166 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0023 | \n",
- " 4.4796 | \n",
- " 0.3356 | \n",
- " 4.1440 | \n",
- " 92.5081 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0024 | \n",
- " 61.8478 | \n",
- " 31.3007 | \n",
- " 30.5470 | \n",
- " 49.3907 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0025 | \n",
- " 45.9707 | \n",
- " 14.6125 | \n",
- " 31.3582 | \n",
- " 68.2134 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0026 | \n",
- " 32.8591 | \n",
- " 12.9479 | \n",
- " 19.9112 | \n",
- " 60.5957 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- " WAMBE0027 | \n",
- " 26.4132 | \n",
- " 18.7142 | \n",
- " 7.6990 | \n",
- " 29.1484 | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- " NaN | \n",
- "
\n",
- " \n",
- "
\n",
- "
242 rows × 9 columns
\n",
- "
"
- ],
- "text/plain": [
- " prestorm_swash_vol poststorm_swash_vol swash_vol_change \\\n",
- "site_id \n",
- "AVOCAn0009 4.5783 0.1110 4.4673 \n",
- "AVOCAs0001 NaN NaN NaN \n",
- "AVOCAs0002 97.9463 26.6638 71.2825 \n",
- "AVOCAs0003 70.7306 40.2020 30.7232 \n",
- "AVOCAs0004 98.2859 45.4986 52.6330 \n",
- "AVOCAs0005 95.5841 54.9753 40.5733 \n",
- "AVOCAs0006 113.0441 67.8912 45.2582 \n",
- "AVOCAs0007 65.3283 44.2821 21.4544 \n",
- "AVOCAs0008 52.3933 45.2243 7.1728 \n",
- "BILG0001 20.3405 7.6207 12.7198 \n",
- "BILG0002 156.4205 98.1716 58.1659 \n",
- "BOAT0001 23.8361 23.6865 -0.0926 \n",
- "BOAT0002 38.8398 14.0819 24.7579 \n",
- "BOAT0003 73.6809 17.8545 55.8264 \n",
- "BOAT0004 73.1954 23.1583 50.0372 \n",
- "BOAT0005 53.5122 22.4537 31.0585 \n",
- "BOOM0001 236.4540 218.4918 20.8725 \n",
- "CATHIE0024 63.6452 38.4261 25.2191 \n",
- "CATHIE0026 75.1334 43.7179 31.0940 \n",
- "CRESn0069 37.5896 8.3495 29.2401 \n",
- "DEEWHYn0008 NaN NaN NaN \n",
- "DEEWHYn0009 NaN NaN NaN \n",
- "DEEWHYs0005 62.3514 24.9797 37.3716 \n",
- "DEEWHYs0008 1.0688 1.3640 0.0000 \n",
- "DIAMONDn0023 67.9416 21.1812 46.7603 \n",
- "DIAMONDs0006 74.9357 42.4382 32.2536 \n",
- "DIAMONDs0007 153.7639 127.9469 26.1595 \n",
- "DUNBn0031 36.5301 6.3289 30.2012 \n",
- "DUNBn0055 189.5283 134.2760 56.7139 \n",
- "ELIZA0002 NaN NaN NaN \n",
- "... ... ... ... \n",
- "STOCNs0170 198.2785 216.6368 -18.6067 \n",
- "STOCNs0175 136.2126 114.1715 22.4984 \n",
- "STOCNs0179 67.7795 45.3981 22.3815 \n",
- "STOCNs0180 166.0813 149.5195 15.3441 \n",
- "STOCNs0181 90.1147 98.9808 -9.1107 \n",
- "STOCNs0182 67.8622 86.0118 -18.1671 \n",
- "STOCNs0183 125.9085 137.7342 -12.6233 \n",
- "STOCNs0184 146.6586 123.5371 23.2603 \n",
- "STOCNs0185 141.5421 142.7279 -1.2619 \n",
- "STOCNs0186 115.9148 123.1507 -7.8392 \n",
- "STOCNs0187 126.5519 147.4371 -22.4452 \n",
- "STOCNs0188 345.5234 353.8766 -11.3322 \n",
- "STOCNs0189 171.6354 134.9192 35.8697 \n",
- "STOCNs0190 151.4113 116.6381 35.0161 \n",
- "STOCS0014 98.4991 57.3495 40.9006 \n",
- "STOCS0043 36.4256 11.7208 24.7048 \n",
- "WAMBE0005 NaN NaN NaN \n",
- "WAMBE0015 56.2724 16.0428 40.2296 \n",
- "WAMBE0016 97.8849 39.8432 58.0417 \n",
- "WAMBE0017 36.5683 8.5380 28.0303 \n",
- "WAMBE0018 42.1423 10.5498 31.5925 \n",
- "WAMBE0019 39.6097 9.2404 30.3693 \n",
- "WAMBE0020 NaN NaN NaN \n",
- "WAMBE0021 NaN NaN NaN \n",
- "WAMBE0022 1.1034 0.4478 0.6556 \n",
- "WAMBE0023 4.4796 0.3356 4.1440 \n",
- "WAMBE0024 61.8478 31.3007 30.5470 \n",
- "WAMBE0025 45.9707 14.6125 31.3582 \n",
- "WAMBE0026 32.8591 12.9479 19.9112 \n",
- "WAMBE0027 26.4132 18.7142 7.6990 \n",
- "\n",
- " swash_pct_change prestorm_dune_face_vol \\\n",
- "site_id \n",
- "AVOCAn0009 97.5750 NaN \n",
- "AVOCAs0001 NaN NaN \n",
- "AVOCAs0002 72.7771 NaN \n",
- "AVOCAs0003 43.4369 NaN \n",
- "AVOCAs0004 53.5509 NaN \n",
- "AVOCAs0005 42.4478 NaN \n",
- "AVOCAs0006 40.0359 NaN \n",
- "AVOCAs0007 32.8409 NaN \n",
- "AVOCAs0008 13.6904 NaN \n",
- "BILG0001 62.5344 NaN \n",
- "BILG0002 37.1856 NaN \n",
- "BOAT0001 -0.3885 NaN \n",
- "BOAT0002 63.7436 NaN \n",
- "BOAT0003 75.7678 NaN \n",
- "BOAT0004 68.3610 NaN \n",
- "BOAT0005 58.0400 NaN \n",
- "BOOM0001 8.8273 NaN \n",
- "CATHIE0024 39.6245 0.0 \n",
- "CATHIE0026 41.3851 NaN \n",
- "CRESn0069 77.7877 NaN \n",
- "DEEWHYn0008 NaN NaN \n",
- "DEEWHYn0009 NaN NaN \n",
- "DEEWHYs0005 59.9372 NaN \n",
- "DEEWHYs0008 0.0000 NaN \n",
- "DIAMONDn0023 68.8244 NaN \n",
- "DIAMONDs0006 43.0416 NaN \n",
- "DIAMONDs0007 17.0128 NaN \n",
- "DUNBn0031 82.6748 NaN \n",
- "DUNBn0055 29.9237 NaN \n",
- "ELIZA0002 NaN NaN \n",
- "... ... ... \n",
- "STOCNs0170 -9.3841 NaN \n",
- "STOCNs0175 16.5171 NaN \n",
- "STOCNs0179 33.0210 NaN \n",
- "STOCNs0180 9.2389 NaN \n",
- "STOCNs0181 -10.1102 NaN \n",
- "STOCNs0182 -26.7705 NaN \n",
- "STOCNs0183 -10.0257 NaN \n",
- "STOCNs0184 15.8602 NaN \n",
- "STOCNs0185 -0.8915 NaN \n",
- "STOCNs0186 -6.7629 NaN \n",
- "STOCNs0187 -17.7359 NaN \n",
- "STOCNs0188 -3.2797 NaN \n",
- "STOCNs0189 20.8988 NaN \n",
- "STOCNs0190 23.1264 NaN \n",
- "STOCS0014 41.5238 NaN \n",
- "STOCS0043 67.8225 NaN \n",
- "WAMBE0005 NaN NaN \n",
- "WAMBE0015 71.4908 NaN \n",
- "WAMBE0016 59.2958 NaN \n",
- "WAMBE0017 76.6520 NaN \n",
- "WAMBE0018 74.9662 NaN \n",
- "WAMBE0019 76.6714 NaN \n",
- "WAMBE0020 NaN NaN \n",
- "WAMBE0021 NaN NaN \n",
- "WAMBE0022 59.4166 NaN \n",
- "WAMBE0023 92.5081 NaN \n",
- "WAMBE0024 49.3907 NaN \n",
- "WAMBE0025 68.2134 NaN \n",
- "WAMBE0026 60.5957 NaN \n",
- "WAMBE0027 29.1484 NaN \n",
- "\n",
- " poststorm_dune_face_vol dune_face_vol_change \\\n",
- "site_id \n",
- "AVOCAn0009 NaN NaN \n",
- "AVOCAs0001 NaN NaN \n",
- "AVOCAs0002 NaN NaN \n",
- "AVOCAs0003 NaN NaN \n",
- "AVOCAs0004 NaN NaN \n",
- "AVOCAs0005 NaN NaN \n",
- "AVOCAs0006 NaN NaN \n",
- "AVOCAs0007 NaN NaN \n",
- "AVOCAs0008 NaN NaN \n",
- "BILG0001 NaN NaN \n",
- "BILG0002 NaN NaN \n",
- "BOAT0001 NaN NaN \n",
- "BOAT0002 NaN NaN \n",
- "BOAT0003 NaN NaN \n",
- "BOAT0004 NaN NaN \n",
- "BOAT0005 NaN NaN \n",
- "BOOM0001 NaN NaN \n",
- "CATHIE0024 0.0 0.0 \n",
- "CATHIE0026 NaN NaN \n",
- "CRESn0069 NaN NaN \n",
- "DEEWHYn0008 NaN NaN \n",
- "DEEWHYn0009 NaN NaN \n",
- "DEEWHYs0005 NaN NaN \n",
- "DEEWHYs0008 NaN NaN \n",
- "DIAMONDn0023 NaN NaN \n",
- "DIAMONDs0006 NaN NaN \n",
- "DIAMONDs0007 NaN NaN \n",
- "DUNBn0031 NaN NaN \n",
- "DUNBn0055 NaN NaN \n",
- "ELIZA0002 NaN NaN \n",
- "... ... ... \n",
- "STOCNs0170 NaN NaN \n",
- "STOCNs0175 NaN NaN \n",
- "STOCNs0179 NaN NaN \n",
- "STOCNs0180 NaN NaN \n",
- "STOCNs0181 NaN NaN \n",
- "STOCNs0182 NaN NaN \n",
- "STOCNs0183 NaN NaN \n",
- "STOCNs0184 NaN NaN \n",
- "STOCNs0185 NaN NaN \n",
- "STOCNs0186 NaN NaN \n",
- "STOCNs0187 NaN NaN \n",
- "STOCNs0188 NaN NaN \n",
- "STOCNs0189 NaN NaN \n",
- "STOCNs0190 NaN NaN \n",
- "STOCS0014 NaN NaN \n",
- "STOCS0043 NaN NaN \n",
- "WAMBE0005 NaN NaN \n",
- "WAMBE0015 NaN NaN \n",
- "WAMBE0016 NaN NaN \n",
- "WAMBE0017 NaN NaN \n",
- "WAMBE0018 NaN NaN \n",
- "WAMBE0019 NaN NaN \n",
- "WAMBE0020 NaN NaN \n",
- "WAMBE0021 NaN NaN \n",
- "WAMBE0022 NaN NaN \n",
- "WAMBE0023 NaN NaN \n",
- "WAMBE0024 NaN NaN \n",
- "WAMBE0025 NaN NaN \n",
- "WAMBE0026 NaN NaN \n",
- "WAMBE0027 NaN NaN \n",
- "\n",
- " dune_face_pct_change storm_regime \n",
- "site_id \n",
- "AVOCAn0009 NaN NaN \n",
- "AVOCAs0001 NaN NaN \n",
- "AVOCAs0002 NaN NaN \n",
- "AVOCAs0003 NaN NaN \n",
- "AVOCAs0004 NaN NaN \n",
- "AVOCAs0005 NaN NaN \n",
- "AVOCAs0006 NaN NaN \n",
- "AVOCAs0007 NaN NaN \n",
- "AVOCAs0008 NaN NaN \n",
- "BILG0001 NaN NaN \n",
- "BILG0002 NaN NaN \n",
- "BOAT0001 NaN NaN \n",
- "BOAT0002 NaN NaN \n",
- "BOAT0003 NaN NaN \n",
- "BOAT0004 NaN NaN \n",
- "BOAT0005 NaN NaN \n",
- "BOOM0001 NaN NaN \n",
- "CATHIE0024 NaN NaN \n",
- "CATHIE0026 NaN NaN \n",
- "CRESn0069 NaN NaN \n",
- "DEEWHYn0008 NaN NaN \n",
- "DEEWHYn0009 NaN NaN \n",
- "DEEWHYs0005 NaN NaN \n",
- "DEEWHYs0008 NaN NaN \n",
- "DIAMONDn0023 NaN NaN \n",
- "DIAMONDs0006 NaN NaN \n",
- "DIAMONDs0007 NaN NaN \n",
- "DUNBn0031 NaN NaN \n",
- "DUNBn0055 NaN NaN \n",
- "ELIZA0002 NaN NaN \n",
- "... ... ... \n",
- "STOCNs0170 NaN NaN \n",
- "STOCNs0175 NaN NaN \n",
- "STOCNs0179 NaN NaN \n",
- "STOCNs0180 NaN NaN \n",
- "STOCNs0181 NaN NaN \n",
- "STOCNs0182 NaN NaN \n",
- "STOCNs0183 NaN NaN \n",
- "STOCNs0184 NaN NaN \n",
- "STOCNs0185 NaN NaN \n",
- "STOCNs0186 NaN NaN \n",
- "STOCNs0187 NaN NaN \n",
- "STOCNs0188 NaN NaN \n",
- "STOCNs0189 NaN NaN \n",
- "STOCNs0190 NaN NaN \n",
- "STOCS0014 NaN NaN \n",
- "STOCS0043 NaN NaN \n",
- "WAMBE0005 NaN NaN \n",
- "WAMBE0015 NaN NaN \n",
- "WAMBE0016 NaN NaN \n",
- "WAMBE0017 NaN NaN \n",
- "WAMBE0018 NaN NaN \n",
- "WAMBE0019 NaN NaN \n",
- "WAMBE0020 NaN NaN \n",
- "WAMBE0021 NaN NaN \n",
- "WAMBE0022 NaN NaN \n",
- "WAMBE0023 NaN NaN \n",
- "WAMBE0024 NaN NaN \n",
- "WAMBE0025 NaN NaN \n",
- "WAMBE0026 NaN NaN \n",
- "WAMBE0027 NaN NaN \n",
- "\n",
- "[242 rows x 9 columns]"
- ]
- },
- "execution_count": 58,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
"source": [
"df_impacts = impacts['observed']\n",
"df_no_obs_impacts = df_impacts[df_impacts.storm_regime.isnull()]\n",
@@ -2000,253 +832,9 @@
},
{
"cell_type": "code",
- "execution_count": 74,
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-13T02:37:07.225965Z",
- "start_time": "2018-12-13T02:37:07.213921Z"
- }
- },
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "231 sites have no dune crests:\n",
- "AVOCAn0009\n",
- "AVOCAs0001\n",
- "AVOCAs0002\n",
- "AVOCAs0003\n",
- "AVOCAs0004\n",
- "AVOCAs0005\n",
- "AVOCAs0006\n",
- "AVOCAs0007\n",
- "AVOCAs0008\n",
- "BILG0001\n",
- "BILG0002\n",
- "BOAT0001\n",
- "BOAT0002\n",
- "BOAT0003\n",
- "BOAT0004\n",
- "BOAT0005\n",
- "BOOM0001\n",
- "CATHIE0026\n",
- "CRESn0069\n",
- "DEEWHYn0008\n",
- "DEEWHYn0009\n",
- "DEEWHYs0005\n",
- "DEEWHYs0008\n",
- "DIAMONDs0006\n",
- "DIAMONDs0007\n",
- "ENTRA0005\n",
- "ENTRA0006\n",
- "ENTRA0077\n",
- "ENTRA0078\n",
- "ENTRA0079\n",
- "FOST0003\n",
- "GRANTSn0004\n",
- "GRANTSn0005\n",
- "GRANTSn0006\n",
- "GRANTSn0007\n",
- "GRANTSn0008\n",
- "GRANTSn0009\n",
- "GRANTSn0021\n",
- "GRANTSs0014\n",
- "HARGs0003\n",
- "HARGs0004\n",
- "HARGs0005\n",
- "HARR0056\n",
- "LHOUSE0001\n",
- "LHOUSE0002\n",
- "LHOUSE0003\n",
- "LHOUSE0004\n",
- "LHOUSE0012\n",
- "LHOUSE0013\n",
- "LHOUSEs0015\n",
- "MACM0008\n",
- "MACM0012\n",
- "MACM0013\n",
- "MACM0014\n",
- "MACM0015\n",
- "MACM0016\n",
- "MANNING0001\n",
- "MANNING0002\n",
- "MANNING0003\n",
- "MANNING0004\n",
- "MANNING0005\n",
- "MANNING0101\n",
- "MANNING0102\n",
- "MANNING0103\n",
- "MANNING0104\n",
- "MANNING0105\n",
- "MANNING0106\n",
- "MANNING0107\n",
- "MANNING0108\n",
- "MANNING0109\n",
- "MONA0001\n",
- "MONA0002\n",
- "MONA0003\n",
- "MONA0014\n",
- "MONA0015\n",
- "MONA0016\n",
- "MONA0017\n",
- "MONA0018\n",
- "MONA0019\n",
- "MONA0020\n",
- "MONA0021\n",
- "NAMB0027\n",
- "NAMB0041\n",
- "NARRA0001\n",
- "NARRA0028\n",
- "NARRA0035\n",
- "NINEMn0050\n",
- "OLDBAR0035\n",
- "PEARLn0001\n",
- "PEARLn0002\n",
- "PEARLn0003\n",
- "PEARLn0004\n",
- "PEARLs0003\n",
- "PEARLs0004\n",
- "PEARLs0005\n",
- "STOCNn0012\n",
- "STOCNn0013\n",
- "STOCNn0014\n",
- "STOCNn0015\n",
- "STOCNn0016\n",
- "STOCNn0017\n",
- "STOCNn0018\n",
- "STOCNn0019\n",
- "STOCNn0020\n",
- "STOCNn0021\n",
- "STOCNn0022\n",
- "STOCNn0023\n",
- "STOCNn0024\n",
- "STOCNn0025\n",
- "STOCNn0026\n",
- "STOCNn0027\n",
- "STOCNn0028\n",
- "STOCNn0029\n",
- "STOCNn0030\n",
- "STOCNn0031\n",
- "STOCNn0032\n",
- "STOCNn0033\n",
- "STOCNn0034\n",
- "STOCNn0035\n",
- "STOCNn0036\n",
- "STOCNn0037\n",
- "STOCNn0038\n",
- "STOCNn0039\n",
- "STOCNn0044\n",
- "STOCNn0059\n",
- "STOCNn0062\n",
- "STOCNn0063\n",
- "STOCNn0064\n",
- "STOCNn0065\n",
- "STOCNs0022\n",
- "STOCNs0025\n",
- "STOCNs0026\n",
- "STOCNs0031\n",
- "STOCNs0045\n",
- "STOCNs0048\n",
- "STOCNs0049\n",
- "STOCNs0053\n",
- "STOCNs0055\n",
- "STOCNs0056\n",
- "STOCNs0057\n",
- "STOCNs0058\n",
- "STOCNs0059\n",
- "STOCNs0060\n",
- "STOCNs0061\n",
- "STOCNs0062\n",
- "STOCNs0073\n",
- "STOCNs0079\n",
- "STOCNs0088\n",
- "STOCNs0089\n",
- "STOCNs0090\n",
- "STOCNs0091\n",
- "STOCNs0092\n",
- "STOCNs0093\n",
- "STOCNs0094\n",
- "STOCNs0095\n",
- "STOCNs0096\n",
- "STOCNs0097\n",
- "STOCNs0098\n",
- "STOCNs0099\n",
- "STOCNs0100\n",
- "STOCNs0101\n",
- "STOCNs0102\n",
- "STOCNs0103\n",
- "STOCNs0104\n",
- "STOCNs0105\n",
- "STOCNs0106\n",
- "STOCNs0107\n",
- "STOCNs0108\n",
- "STOCNs0109\n",
- "STOCNs0110\n",
- "STOCNs0111\n",
- "STOCNs0112\n",
- "STOCNs0113\n",
- "STOCNs0114\n",
- "STOCNs0115\n",
- "STOCNs0116\n",
- "STOCNs0117\n",
- "STOCNs0118\n",
- "STOCNs0119\n",
- "STOCNs0120\n",
- "STOCNs0121\n",
- "STOCNs0122\n",
- "STOCNs0123\n",
- "STOCNs0124\n",
- "STOCNs0125\n",
- "STOCNs0126\n",
- "STOCNs0127\n",
- "STOCNs0128\n",
- "STOCNs0137\n",
- "STOCNs0141\n",
- "STOCNs0144\n",
- "STOCNs0150\n",
- "STOCNs0155\n",
- "STOCNs0156\n",
- "STOCNs0157\n",
- "STOCNs0158\n",
- "STOCNs0159\n",
- "STOCNs0160\n",
- "STOCNs0167\n",
- "STOCNs0168\n",
- "STOCNs0169\n",
- "STOCNs0170\n",
- "STOCNs0175\n",
- "STOCNs0179\n",
- "STOCNs0180\n",
- "STOCNs0181\n",
- "STOCNs0182\n",
- "STOCNs0183\n",
- "STOCNs0184\n",
- "STOCNs0185\n",
- "STOCNs0186\n",
- "STOCNs0187\n",
- "STOCNs0188\n",
- "STOCNs0189\n",
- "STOCNs0190\n",
- "STOCS0014\n",
- "STOCS0043\n",
- "WAMBE0005\n",
- "WAMBE0015\n",
- "WAMBE0016\n",
- "WAMBE0017\n",
- "WAMBE0018\n",
- "WAMBE0019\n",
- "WAMBE0020\n",
- "WAMBE0021\n",
- "WAMBE0022\n",
- "WAMBE0023\n",
- "WAMBE0024\n",
- "WAMBE0025\n",
- "WAMBE0026\n",
- "WAMBE0027\n"
- ]
- }
- ],
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
"source": [
"df_no_crests = df_profile_features_crest_toes.query('profile_type==\"prestorm\" & (dune_crest_x != dune_crest_x)')\n",
"print('{} sites have no dune crests:'.format(len(df_no_crests)))\n",
diff --git a/notebooks/04_profile_picker.ipynb b/notebooks/04_profile_picker.ipynb
deleted file mode 100644
index ce31898..0000000
--- a/notebooks/04_profile_picker.ipynb
+++ /dev/null
@@ -1,743 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-05T00:54:50.235522Z",
- "start_time": "2018-12-05T00:54:42.731587Z"
- }
- },
- "outputs": [],
- "source": [
- "import pandas as pd\n",
- "import os\n",
- "import numpy.ma as ma\n",
- "\n",
- "import numpy\n",
- "from pyearth import Earth\n",
- "from matplotlib import pyplot\n",
- "\n",
- "np.random.seed(2017)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-05T00:54:54.936556Z",
- "start_time": "2018-12-05T00:54:50.271465Z"
- }
- },
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Importing profiles.csv\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "C:\\Users\\z5189959\\Desktop\\nsw-2016-storm-impact\\.venv\\lib\\site-packages\\numpy\\lib\\arraysetops.py:522: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison\n",
- " mask |= (ar1 == a)\n"
- ]
- }
- ],
- "source": [
- "def df_from_csv(csv, index_col, data_folder='../data/interim'):\n",
- " print('Importing {}'.format(csv))\n",
- " return pd.read_csv(os.path.join(data_folder,csv), index_col=index_col)\n",
- "\n",
- "df_profiles = df_from_csv('profiles.csv', index_col=[0, 1, 2])"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-04T23:49:04.770025Z",
- "start_time": "2018-12-04T23:49:04.265699Z"
- }
- },
- "source": [
- "## Try using pyearth"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 73,
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-05T01:54:00.320555Z",
- "start_time": "2018-12-05T01:53:58.905803Z"
- },
- "code_folding": [
- 5,
- 20,
- 31,
- 40
- ],
- "scrolled": false
- },
- "outputs": [
- {
- "data": {
- "image/png": "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\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "needs_background": "light"
- },
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[ { 'slope': -0.06617795750241562,\n",
- " 'type': 'land',\n",
- " 'x_end': 63.0,\n",
- " 'x_start': 40.5,\n",
- " 'z_end': 9.943990321404,\n",
- " 'z_mean': 9.20564731619437,\n",
- " 'z_start': 8.348161899068224},\n",
- " { 'slope': -0.09424321140128608,\n",
- " 'x_end': 69.0,\n",
- " 'x_start': 63.0,\n",
- " 'z_end': 10.532233612481347,\n",
- " 'z_mean': 10.310033111599461,\n",
- " 'z_start': 10.062895267627406},\n",
- " { 'slope': 0.07278057230588836,\n",
- " 'x_end': 96.0,\n",
- " 'x_start': 69.0,\n",
- " 'z_end': 9.071344271845113,\n",
- " 'z_mean': 9.942154478828064,\n",
- " 'z_start': 10.600758995514095},\n",
- " { 'slope': 0.010222110457455531,\n",
- " 'x_end': 105.0,\n",
- " 'x_start': 96.0,\n",
- " 'z_end': 8.940005362742282,\n",
- " 'z_mean': 8.960960594412768,\n",
- " 'z_start': 9.032076613769703},\n",
- " { 'slope': -0.006783434031405405,\n",
- " 'x_end': 171.0,\n",
- " 'x_start': 105.0,\n",
- " 'z_end': 9.377956662680647,\n",
- " 'z_mean': 9.12742372282666,\n",
- " 'z_start': 8.933411617025225},\n",
- " { 'slope': 0.04487864391014401,\n",
- " 'x_end': 177.0,\n",
- " 'x_start': 171.0,\n",
- " 'z_end': 9.159019876027982,\n",
- " 'z_mean': 9.312931484934994,\n",
- " 'z_start': 9.382296403384132},\n",
- " { 'slope': 0.28077356578561746,\n",
- " 'x_end': 198.0,\n",
- " 'x_start': 177.0,\n",
- " 'z_end': 3.9204468853264824,\n",
- " 'z_mean': 6.663384763062234,\n",
- " 'z_start': 9.046622396024778},\n",
- " { 'slope': 0.08534897213040515,\n",
- " 'x_end': 204.0,\n",
- " 'x_start': 198.0,\n",
- " 'z_end': 3.3242471595653202,\n",
- " 'z_mean': 3.4936366209579663,\n",
- " 'z_start': 3.754184455095742},\n",
- " { 'slope': 0.02118839446027552,\n",
- " 'type': 'berm',\n",
- " 'x_end': 252.0,\n",
- " 'x_start': 204.0,\n",
- " 'z_end': 2.11417905440144,\n",
- " 'z_mean': 2.7099232730105225,\n",
- " 'z_start': 3.26349144192863},\n",
- " { 'slope': 0.06273209072355844,\n",
- " 'type': 'foreshore',\n",
- " 'x_end': 285.5,\n",
- " 'x_start': 252.0,\n",
- " 'z_end': 0.0614306329519847,\n",
- " 'z_mean': 1.0727411577535628,\n",
- " 'z_start': 2.070753280242818}]\n"
- ]
- },
- {
- "data": {
- "image/png": "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\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "needs_background": "light"
- },
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[ { 'slope': -0.006232531713848901,\n",
- " 'type': 'land',\n",
- " 'x_end': 87.0,\n",
- " 'x_start': 54.0,\n",
- " 'z_end': 18.907362973310256,\n",
- " 'z_mean': 18.226859544431967,\n",
- " 'z_start': 18.244707421270647},\n",
- " { 'slope': 0.10048504940215892,\n",
- " 'x_end': 90.0,\n",
- " 'x_start': 87.0,\n",
- " 'z_end': 18.81114066206634,\n",
- " 'z_mean': 18.95124513461371,\n",
- " 'z_start': 19.011103385573893},\n",
- " { 'slope': 0.7867562476656698,\n",
- " 'x_end': 105.0,\n",
- " 'x_start': 90.0,\n",
- " 'z_end': 8.264119331473214,\n",
- " 'z_mean': 13.443236505259332,\n",
- " 'z_start': 18.482680684877423},\n",
- " { 'slope': 0.138231538826561,\n",
- " 'x_end': 108.0,\n",
- " 'x_start': 105.0,\n",
- " 'z_end': 7.625424767531349,\n",
- " 'z_mean': 7.719382219664138,\n",
- " 'z_start': 7.899377829775406},\n",
- " { 'slope': -0.24669278691155727,\n",
- " 'x_end': 111.0,\n",
- " 'x_start': 108.0,\n",
- " 'z_end': 8.25183247996525,\n",
- " 'z_mean': 8.037437899312298,\n",
- " 'z_start': 7.767262334494268},\n",
- " { 'slope': -0.022224358740496428,\n",
- " 'x_end': 138.0,\n",
- " 'x_start': 111.0,\n",
- " 'z_end': 8.805851879663944,\n",
- " 'z_mean': 8.69776858676918,\n",
- " 'z_start': 8.321441165942321},\n",
- " { 'slope': 0.011690412029154119,\n",
- " 'x_end': 174.0,\n",
- " 'x_start': 138.0,\n",
- " 'z_end': 8.399119455457473,\n",
- " 'z_mean': 8.591198407135863,\n",
- " 'z_start': 8.769268316237742},\n",
- " { 'slope': 0.06596545786924302,\n",
- " 'x_end': 183.0,\n",
- " 'x_start': 174.0,\n",
- " 'z_end': 7.84469125226732,\n",
- " 'z_mean': 8.148131103000907,\n",
- " 'z_start': 8.376950179198564},\n",
- " { 'slope': 0.19014969366205653,\n",
- " 'x_end': 213.0,\n",
- " 'x_start': 183.0,\n",
- " 'z_end': 2.9990666738937883,\n",
- " 'z_mean': 5.087790707786215,\n",
- " 'z_start': 7.748699573256347},\n",
- " { 'slope': 0.012096582737314357,\n",
- " 'type': 'berm',\n",
- " 'x_end': 219.0,\n",
- " 'x_start': 213.0,\n",
- " 'z_end': 2.9163517442302123,\n",
- " 'z_mean': 2.9347601110839676,\n",
- " 'z_start': 2.975348176164513},\n",
- " { 'slope': 0.03056014910314705,\n",
- " 'x_end': 255.0,\n",
- " 'x_start': 219.0,\n",
- " 'z_end': 2.050738949067936,\n",
- " 'z_mean': 2.653057687157337,\n",
- " 'z_start': 2.927273834441084},\n",
- " { 'slope': 0.06806395674070564,\n",
- " 'type': 'foreshore',\n",
- " 'x_end': 285.5,\n",
- " 'x_start': 255.0,\n",
- " 'z_end': 0.04691924522162938,\n",
- " 'z_mean': 1.100297110086715,\n",
- " 'z_start': 2.0068617905167647}]\n"
- ]
- },
- {
- "data": {
- "image/png": "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\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "needs_background": "light"
- },
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[ { 'slope': 0.0008328773436106309,\n",
- " 'type': 'berm',\n",
- " 'x_end': 58.0,\n",
- " 'x_start': 37.0,\n",
- " 'z_end': 1.8572595562110041,\n",
- " 'z_mean': 1.8943805115420846,\n",
- " 'z_start': 1.910394386927169},\n",
- " { 'slope': -0.021220543877635122,\n",
- " 'type': 'berm',\n",
- " 'x_end': 138.0,\n",
- " 'x_start': 58.0,\n",
- " 'z_end': 3.5977328867797485,\n",
- " 'z_mean': 2.7247048500781106,\n",
- " 'z_start': 1.8468598845719795},\n",
- " { 'slope': -0.06381773295732189,\n",
- " 'x_end': 142.0,\n",
- " 'x_start': 138.0,\n",
- " 'z_end': 3.8359998018824712,\n",
- " 'z_mean': 3.741723519647647,\n",
- " 'z_start': 3.6479493664613014},\n",
- " { 'slope': -0.016157748520191067,\n",
- " 'x_end': 157.0,\n",
- " 'x_start': 142.0,\n",
- " 'z_end': 4.169920934351783,\n",
- " 'z_mean': 4.013083138991948,\n",
- " 'z_start': 3.8843177342116757},\n",
- " { 'slope': -0.1322171985012303,\n",
- " 'x_end': 177.0,\n",
- " 'x_start': 157.0,\n",
- " 'z_end': 6.427354838550462,\n",
- " 'z_mean': 5.4360212510513115,\n",
- " 'z_start': 4.223480595415142},\n",
- " { 'slope': 0.34782985777944603,\n",
- " 'x_end': 193.0,\n",
- " 'x_start': 177.0,\n",
- " 'z_end': 1.3683244048034364,\n",
- " 'z_mean': 3.876447007928749,\n",
- " 'z_start': 6.295019014555152},\n",
- " { 'slope': 0.06019958288565148,\n",
- " 'type': 'foreshore',\n",
- " 'x_end': 213.5,\n",
- " 'x_start': 193.0,\n",
- " 'z_end': 0.06618164722605435,\n",
- " 'z_mean': 0.6722026822899186,\n",
- " 'z_start': 1.1980470061124415}]\n"
- ]
- }
- ],
- "source": [
- "from scipy.signal import savgol_filter\n",
- "import re\n",
- "from scipy.stats import linregress\n",
- "import warnings\n",
- "warnings.simplefilter(action='ignore', category=FutureWarning)\n",
- "\n",
- "def get_breakpoints(model, min_distance=20):\n",
- " # Get breakpoints\n",
- " breakpoints = []\n",
- " for line in model.summary().split('\\n'):\n",
- " # Get unpruned lines\n",
- " if 'No' in line and 'None' not in line:\n",
- " # Get break points\n",
- " m = re.search(\"h\\(x0-(\\d*\\.?\\d+)\\)\", line)\n",
- " if m:\n",
- " breakpoints.append(float(m.groups()[0]))\n",
- " m = re.search(\"h\\((\\d*\\.?\\d+)-x0\\)\", line)\n",
- " if m:\n",
- " breakpoints.append(float(m.groups()[0]))\n",
- " return sorted(list(set(breakpoints)))\n",
- " \n",
- "def get_segments(breakpoints, x_min, x_max):\n",
- " segments = []\n",
- " breakpoints = [x_min] + breakpoints + [x_max]\n",
- "\n",
- " for x1, x2 in zip(breakpoints, breakpoints[1:]):\n",
- " segments.append({\n",
- " 'x_start': x1,\n",
- " 'x_end': x2\n",
- " })\n",
- " return segments \n",
- "\n",
- "def get_segment_slopes(segments, x, z):\n",
- " for segment in segments:\n",
- " mask = ma.masked_where((segment['x_start'] < x) & (x < segment['x_end']),x ).mask\n",
- " segment['z_mean'] = np.mean(z[mask])\n",
- " segment['z_start'] = np.mean(z[mask][0])\n",
- " segment['z_end'] = np.mean(z[mask][-1])\n",
- " segment['slope'] = -linregress(x[mask], z[mask]).slope\n",
- " return segments\n",
- " \n",
- "def classify_segments(segments, x,z):\n",
- " \n",
- " # Most seaward slope must be foreshore\n",
- " segments[-1]['type'] = 'foreshore'\n",
- " \n",
- " # Most landward slope must be land\n",
- " segments[0]['type'] = 'land'\n",
- " \n",
- " # Segments with really high slopes must be structures\n",
- " for seg in segments:\n",
- " if seg['slope'] > 2.0:\n",
- " seg['type'] = 'structure'\n",
- " \n",
- " # Segments with large change of slope and \n",
- " # Segment with max slope should be dune face\n",
- "# dune_face_idx = [n for n, seg in enumerate(segments) if seg['slope']==max(x['slope'] for x in segments)][0]\n",
- "# segments[dune_face_idx]['type'] = 'dune_face'\n",
- " \n",
- " # Pick out berms \n",
- " for seg in segments:\n",
- " if (-0.03 < seg['slope'] < 0.03 # berms should be relatively flat\n",
- " and 0 < seg['z_mean'] < 4 # berms should be located between 0-4 m AHD\n",
- " ): # berms should be seaward of dune face\n",
- " seg['type'] = 'berm'\n",
- " \n",
- "# slope = None\n",
- "# for seg in reversed(segments):\n",
- "# if slope is None:\n",
- "# continue\n",
- "# elif slope - 0.03 < seg['slope'] < slope + 0.03:\n",
- "# seg['type'] = 'foreshore'\n",
- "# else:\n",
- "# break\n",
- " \n",
- " return segments\n",
- "\n",
- "def get_piecewise_linear_model(x,z):\n",
- " #Fit an Earth model\n",
- " model = Earth(penalty=3,thresh=0.0005)\n",
- " model.fit(x,z)\n",
- " return model\n",
- "\n",
- "def plot_profile_classification(site_id, profile_type):\n",
- " df_profile = df_profiles.query(\"site_id == '{}' and profile_type == '{}'\".format(site_id, profile_type))\n",
- " x = np.array(df_profile.index.get_level_values('x').tolist())\n",
- " z = np.array(df_profile.z.tolist()) \n",
- " \n",
- " nan_mask = ma.masked_invalid(z).mask\n",
- " x = x[~nan_mask]\n",
- " z_unfiltered = z[~nan_mask]\n",
- " z = savgol_filter(z_unfiltered, 51, 3)\n",
- " \n",
- " model = get_piecewise_linear_model(x,z)\n",
- " breakpoints = get_breakpoints(model)\n",
- " segments = get_segments(breakpoints, x_min=x.min(), x_max=x.max())\n",
- " segments = get_segment_slopes(segments, x=x, z=z)\n",
- "# segments = merge_similar_segments(segments)\n",
- " segments = classify_segments(segments, x=x, z=z)\n",
- " \n",
- " pyplot.figure()\n",
- " pyplot.plot(x,z_unfiltered, color='0.5',marker='.', alpha=.2, ms=10,linestyle=\"None\")\n",
- "\n",
- " # Plot different segments\n",
- " foreshore_segments = [x for x in segments if x.get('type') == 'foreshore']\n",
- " for seg in foreshore_segments:\n",
- " pyplot.plot([seg['x_start'], seg['x_end']],\n",
- " [seg['z_start'], seg['z_end']],\n",
- " linewidth=4, \n",
- " color='b')\n",
- "\n",
- " land_segments = [x for x in segments if x.get('type') == 'land']\n",
- " for seg in land_segments:\n",
- " pyplot.plot([seg['x_start'], seg['x_end']],\n",
- " [seg['z_start'], seg['z_end']],\n",
- " linewidth=4, \n",
- " color='g')\n",
- "\n",
- " berm_segments = [x for x in segments if x.get('type') == 'berm']\n",
- " for seg in berm_segments:\n",
- " pyplot.plot([seg['x_start'], seg['x_end']],\n",
- " [seg['z_start'], seg['z_end']],\n",
- " linewidth=4, \n",
- " color='y')\n",
- "\n",
- " dune_face_segments = [x for x in segments if x.get('type') == 'dune_face']\n",
- " for seg in dune_face_segments:\n",
- " pyplot.plot([seg['x_start'], seg['x_end']],\n",
- " [seg['z_start'], seg['z_end']],\n",
- " linewidth=4, \n",
- " color='r')\n",
- " \n",
- " structure_segments = [x for x in segments if x.get('type') == 'structure']\n",
- " for seg in structure_segments:\n",
- " pyplot.plot([seg['x_start'], seg['x_end']],\n",
- " [seg['z_start'], seg['z_end']],\n",
- " linewidth=4, \n",
- " color='m')\n",
- " \n",
- " unclassified_segments = [x for x in segments if x.get('type') is None]\n",
- " for seg in unclassified_segments:\n",
- " pyplot.plot([seg['x_start'], seg['x_end']],\n",
- " [seg['z_start'], seg['z_end']],\n",
- " linewidth=4, \n",
- " color='0.4')\n",
- "\n",
- " pyplot.xlabel('x (m)')\n",
- " pyplot.ylabel('z (m AHD)')\n",
- " pyplot.title('{} profile at {}'.format(profile_type, site_id))\n",
- " pyplot.show()\n",
- "\n",
- " import pprint\n",
- " pp = pprint.PrettyPrinter(indent=4)\n",
- " pp.pprint(segments)\n",
- "\n",
- "plot_profile_classification('NARRA0018', 'prestorm')\n",
- "plot_profile_classification('NARRA0019', 'prestorm')\n",
- "plot_profile_classification('CRESn0017', 'poststorm')"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "heading_collapsed": true
- },
- "source": [
- "## Try lmfit"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "hidden": true
- },
- "outputs": [],
- "source": []
- },
- {
- "cell_type": "code",
- "execution_count": 26,
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-05T01:13:41.773484Z",
- "start_time": "2018-12-05T01:13:27.230746Z"
- },
- "code_folding": [
- 0
- ],
- "hidden": true,
- "scrolled": true
- },
- "outputs": [
- {
- "data": {
- "image/png": "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\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "needs_background": "light"
- },
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[Model]]\n",
- " Model(piecewise_linear)\n",
- "[[Fit Statistics]]\n",
- " # fitting method = ampgo, with L-BFGS-B as local solver\n",
- " # function evals = 79866\n",
- " # data points = 491\n",
- " # variables = 8\n",
- " chi-square = 65.4379204\n",
- " reduced chi-square = 0.13548224\n",
- " Akaike info crit = -973.533027\n",
- " Bayesian info crit = -939.961474\n",
- "[[Variables]]\n",
- " x0: 62.1499306 (init = 40.5)\n",
- " x1: 181.207436 (init = 40.5)\n",
- " x2: 196.301872 (init = 40.5)\n",
- " b: 5.81709441 (init = 0)\n",
- " k1: 0.06544372 (init = 0)\n",
- " k2: -0.07421739 (init = 0)\n",
- " k3: -0.32199700 (init = 0)\n",
- " k4: 0.29325377 (init = 0)\n",
- "\n"
- ]
- }
- ],
- "source": [
- "from lmfit import Model, Parameters\n",
- "\n",
- "def get_data():\n",
- " site_id='NARRA0018'\n",
- " profile_type='prestorm'\n",
- " df_profile = df_profiles.query(\"site_id == '{}' and profile_type == '{}'\".format(site_id, profile_type))\n",
- " x = np.array(df_profile.index.get_level_values('x').tolist())\n",
- " z = np.array(df_profile.z.tolist()) \n",
- "\n",
- " nan_mask = ma.masked_invalid(z).mask\n",
- " x = x[~nan_mask]\n",
- " z = z[~nan_mask]\n",
- " return x,z\n",
- "\n",
- "# def piecewise_linear(x, x0, x1, b, k1, k2, k3):\n",
- "# condlist = [x < x0, (x >= x0) & (x < x1), x >= x1]\n",
- "# funclist = [lambda x: k1*x + b, lambda x: k1*x + b + k2*(x-x0), lambda x: k1*x + b + k2*(x-x0) + k3*(x - x1)]\n",
- "# return np.piecewise(x, condlist, funclist)\n",
- "\n",
- "# x,z = get_data()\n",
- "\n",
- "# fmodel = Model(piecewise_linear)\n",
- "# params = Parameters()\n",
- "# params.add('x0', value=0, vary=True, min=min(x), max=max(x))\n",
- "# params.add('x1', value=0, vary=True, min=min(x), max=max(x))\n",
- "# params.add('b', value=0, vary=True)\n",
- "# params.add('k1', value=0, vary=True, min=-0.01, max=0.01)\n",
- "# params.add('k2', value=0, vary=True, min=-0.1, max=-0.5)\n",
- "# params.add('k3', value=0, vary=True, min=0.1, max=0.5)\n",
- "\n",
- "def piecewise_linear(x, x0, x1, x2, b, k1, k2, k3,k4):\n",
- " condlist = [x < x0, (x >= x0) & (x < x1), (x >= x1) & (x < x2), x >= x2]\n",
- " funclist = [lambda x: k1*x + b, lambda x: k1*x + b + k2*(x-x0), lambda x: k1*x + b + k2*(x-x0) + k3*(x - x1), lambda x: k1*x + b + k2*(x-x0) + k3*(x - x1) +k4*(x-x2)]\n",
- " return np.piecewise(x, condlist, funclist)\n",
- "\n",
- "x,z = get_data()\n",
- "\n",
- "fmodel = Model(piecewise_linear)\n",
- "params = Parameters()\n",
- "params.add('x0', value=0, vary=True, min=min(x), max=max(x))\n",
- "params.add('x1', value=0, vary=True, min=min(x), max=max(x))\n",
- "params.add('x2', value=0, vary=True, min=min(x), max=max(x))\n",
- "params.add('b', value=0, vary=True)\n",
- "params.add('k1', value=0, vary=True, min=-0.5, max=0.5)\n",
- "params.add('k2', value=0, vary=True, min=-0.5, max=0.5)\n",
- "params.add('k3', value=0, vary=True, min=-0.5, max=0.5)\n",
- "params.add('k4', value=0, vary=True, min=-0.5, max=0.5)\n",
- "\n",
- "\n",
- "result = fmodel.fit(z, params, x=x,method='ampgo')\n",
- "\n",
- "\n",
- "pyplot.figure()\n",
- "pyplot.plot(x,z, color='0.5',marker='.', alpha=.2, ms=10,linestyle=\"None\")\n",
- "pyplot.plot(x,result.best_fit, color='r')\n",
- "pyplot.show()\n",
- "print(result.fit_report())"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Try spline"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 65,
- "metadata": {
- "ExecuteTime": {
- "end_time": "2018-12-05T01:49:30.968871Z",
- "start_time": "2018-12-05T01:49:30.648994Z"
- },
- "code_folding": [
- 2
- ]
- },
- "outputs": [
- {
- "data": {
- "image/png": "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\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "needs_background": "light"
- },
- "output_type": "display_data"
- }
- ],
- "source": [
- "from scipy.signal import savgol_filter\n",
- "\n",
- "def get_data():\n",
- " site_id='NARRA0018'\n",
- " profile_type='prestorm'\n",
- " df_profile = df_profiles.query(\"site_id == '{}' and profile_type == '{}'\".format(site_id, profile_type))\n",
- " x = np.array(df_profile.index.get_level_values('x').tolist())\n",
- " z = np.array(df_profile.z.tolist()) \n",
- "\n",
- " nan_mask = ma.masked_invalid(z).mask\n",
- " x = x[~nan_mask]\n",
- " z = z[~nan_mask]\n",
- " return x,z\n",
- "\n",
- "x,z = get_data()\n",
- "\n",
- "z_filtered = savgol_filter(z, 31, 3)\n",
- "\n",
- "\n",
- "pyplot.figure()\n",
- "pyplot.plot(x,z, color='0.5',marker='.', alpha=.2, ms=10,linestyle=\"None\")\n",
- "pyplot.plot(x,z_filtered, color='r')\n",
- "pyplot.show()\n"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.6.7"
- },
- "toc": {
- "base_numbering": 1,
- "nav_menu": {},
- "number_sections": true,
- "sideBar": true,
- "skip_h1_title": false,
- "title_cell": "Table of Contents",
- "title_sidebar": "Contents",
- "toc_cell": false,
- "toc_position": {},
- "toc_section_display": true,
- "toc_window_display": false
- },
- "varInspector": {
- "cols": {
- "lenName": 16,
- "lenType": 16,
- "lenVar": 40
- },
- "kernels_config": {
- "python": {
- "delete_cmd_postfix": "",
- "delete_cmd_prefix": "del ",
- "library": "var_list.py",
- "varRefreshCmd": "print(var_dic_list())"
- },
- "r": {
- "delete_cmd_postfix": ") ",
- "delete_cmd_prefix": "rm(",
- "library": "var_list.r",
- "varRefreshCmd": "cat(var_dic_list()) "
- }
- },
- "types_to_exclude": [
- "module",
- "function",
- "builtin_function_or_method",
- "instance",
- "_Feature"
- ],
- "window_display": false
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/notebooks/04a_profile_picker_superseded.ipynb b/notebooks/04a_profile_picker_superseded.ipynb
new file mode 100644
index 0000000..bbb228c
--- /dev/null
+++ b/notebooks/04a_profile_picker_superseded.ipynb
@@ -0,0 +1,407 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import os\n",
+ "import numpy.ma as ma\n",
+ "\n",
+ "import numpy\n",
+ "from pyearth import Earth\n",
+ "from matplotlib import pyplot\n",
+ "\n",
+ "np.random.seed(2017)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def df_from_csv(csv, index_col, data_folder='../data/interim'):\n",
+ " print('Importing {}'.format(csv))\n",
+ " return pd.read_csv(os.path.join(data_folder,csv), index_col=index_col)\n",
+ "\n",
+ "df_profiles = df_from_csv('profiles.csv', index_col=[0, 1, 2])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Try using pyearth"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "code_folding": [
+ 5,
+ 20,
+ 31,
+ 40
+ ]
+ },
+ "outputs": [],
+ "source": [
+ "from scipy.signal import savgol_filter\n",
+ "import re\n",
+ "from scipy.stats import linregress\n",
+ "import warnings\n",
+ "warnings.simplefilter(action='ignore', category=FutureWarning)\n",
+ "\n",
+ "def get_breakpoints(model, min_distance=20):\n",
+ " # Get breakpoints\n",
+ " breakpoints = []\n",
+ " for line in model.summary().split('\\n'):\n",
+ " # Get unpruned lines\n",
+ " if 'No' in line and 'None' not in line:\n",
+ " # Get break points\n",
+ " m = re.search(\"h\\(x0-(\\d*\\.?\\d+)\\)\", line)\n",
+ " if m:\n",
+ " breakpoints.append(float(m.groups()[0]))\n",
+ " m = re.search(\"h\\((\\d*\\.?\\d+)-x0\\)\", line)\n",
+ " if m:\n",
+ " breakpoints.append(float(m.groups()[0]))\n",
+ " return sorted(list(set(breakpoints)))\n",
+ " \n",
+ "def get_segments(breakpoints, x_min, x_max):\n",
+ " segments = []\n",
+ " breakpoints = [x_min] + breakpoints + [x_max]\n",
+ "\n",
+ " for x1, x2 in zip(breakpoints, breakpoints[1:]):\n",
+ " segments.append({\n",
+ " 'x_start': x1,\n",
+ " 'x_end': x2\n",
+ " })\n",
+ " return segments \n",
+ "\n",
+ "def get_segment_slopes(segments, x, z):\n",
+ " for segment in segments:\n",
+ " mask = ma.masked_where((segment['x_start'] < x) & (x < segment['x_end']),x ).mask\n",
+ " segment['z_mean'] = np.mean(z[mask])\n",
+ " segment['z_start'] = np.mean(z[mask][0])\n",
+ " segment['z_end'] = np.mean(z[mask][-1])\n",
+ " segment['slope'] = -linregress(x[mask], z[mask]).slope\n",
+ " return segments\n",
+ " \n",
+ "def classify_segments(segments, x,z):\n",
+ " \n",
+ " # Most seaward slope must be foreshore\n",
+ " segments[-1]['type'] = 'foreshore'\n",
+ " \n",
+ " # Most landward slope must be land\n",
+ " segments[0]['type'] = 'land'\n",
+ " \n",
+ " # Segments with really high slopes must be structures\n",
+ " for seg in segments:\n",
+ " if seg['slope'] > 2.0:\n",
+ " seg['type'] = 'structure'\n",
+ " \n",
+ " # Segments with large change of slope and \n",
+ " # Segment with max slope should be dune face\n",
+ "# dune_face_idx = [n for n, seg in enumerate(segments) if seg['slope']==max(x['slope'] for x in segments)][0]\n",
+ "# segments[dune_face_idx]['type'] = 'dune_face'\n",
+ " \n",
+ " # Pick out berms \n",
+ " for seg in segments:\n",
+ " if (-0.03 < seg['slope'] < 0.03 # berms should be relatively flat\n",
+ " and 0 < seg['z_mean'] < 4 # berms should be located between 0-4 m AHD\n",
+ " ): # berms should be seaward of dune face\n",
+ " seg['type'] = 'berm'\n",
+ " \n",
+ "# slope = None\n",
+ "# for seg in reversed(segments):\n",
+ "# if slope is None:\n",
+ "# continue\n",
+ "# elif slope - 0.03 < seg['slope'] < slope + 0.03:\n",
+ "# seg['type'] = 'foreshore'\n",
+ "# else:\n",
+ "# break\n",
+ " \n",
+ " return segments\n",
+ "\n",
+ "def get_piecewise_linear_model(x,z):\n",
+ " #Fit an Earth model\n",
+ " model = Earth(penalty=3,thresh=0.0005)\n",
+ " model.fit(x,z)\n",
+ " return model\n",
+ "\n",
+ "def plot_profile_classification(site_id, profile_type):\n",
+ " df_profile = df_profiles.query(\"site_id == '{}' and profile_type == '{}'\".format(site_id, profile_type))\n",
+ " x = np.array(df_profile.index.get_level_values('x').tolist())\n",
+ " z = np.array(df_profile.z.tolist()) \n",
+ " \n",
+ " nan_mask = ma.masked_invalid(z).mask\n",
+ " x = x[~nan_mask]\n",
+ " z_unfiltered = z[~nan_mask]\n",
+ " z = savgol_filter(z_unfiltered, 51, 3)\n",
+ " \n",
+ " model = get_piecewise_linear_model(x,z)\n",
+ " breakpoints = get_breakpoints(model)\n",
+ " segments = get_segments(breakpoints, x_min=x.min(), x_max=x.max())\n",
+ " segments = get_segment_slopes(segments, x=x, z=z)\n",
+ "# segments = merge_similar_segments(segments)\n",
+ " segments = classify_segments(segments, x=x, z=z)\n",
+ " \n",
+ " pyplot.figure()\n",
+ " pyplot.plot(x,z_unfiltered, color='0.5',marker='.', alpha=.2, ms=10,linestyle=\"None\")\n",
+ "\n",
+ " # Plot different segments\n",
+ " foreshore_segments = [x for x in segments if x.get('type') == 'foreshore']\n",
+ " for seg in foreshore_segments:\n",
+ " pyplot.plot([seg['x_start'], seg['x_end']],\n",
+ " [seg['z_start'], seg['z_end']],\n",
+ " linewidth=4, \n",
+ " color='b')\n",
+ "\n",
+ " land_segments = [x for x in segments if x.get('type') == 'land']\n",
+ " for seg in land_segments:\n",
+ " pyplot.plot([seg['x_start'], seg['x_end']],\n",
+ " [seg['z_start'], seg['z_end']],\n",
+ " linewidth=4, \n",
+ " color='g')\n",
+ "\n",
+ " berm_segments = [x for x in segments if x.get('type') == 'berm']\n",
+ " for seg in berm_segments:\n",
+ " pyplot.plot([seg['x_start'], seg['x_end']],\n",
+ " [seg['z_start'], seg['z_end']],\n",
+ " linewidth=4, \n",
+ " color='y')\n",
+ "\n",
+ " dune_face_segments = [x for x in segments if x.get('type') == 'dune_face']\n",
+ " for seg in dune_face_segments:\n",
+ " pyplot.plot([seg['x_start'], seg['x_end']],\n",
+ " [seg['z_start'], seg['z_end']],\n",
+ " linewidth=4, \n",
+ " color='r')\n",
+ " \n",
+ " structure_segments = [x for x in segments if x.get('type') == 'structure']\n",
+ " for seg in structure_segments:\n",
+ " pyplot.plot([seg['x_start'], seg['x_end']],\n",
+ " [seg['z_start'], seg['z_end']],\n",
+ " linewidth=4, \n",
+ " color='m')\n",
+ " \n",
+ " unclassified_segments = [x for x in segments if x.get('type') is None]\n",
+ " for seg in unclassified_segments:\n",
+ " pyplot.plot([seg['x_start'], seg['x_end']],\n",
+ " [seg['z_start'], seg['z_end']],\n",
+ " linewidth=4, \n",
+ " color='0.4')\n",
+ "\n",
+ " pyplot.xlabel('x (m)')\n",
+ " pyplot.ylabel('z (m AHD)')\n",
+ " pyplot.title('{} profile at {}'.format(profile_type, site_id))\n",
+ " pyplot.show()\n",
+ "\n",
+ " import pprint\n",
+ " pp = pprint.PrettyPrinter(indent=4)\n",
+ " pp.pprint(segments)\n",
+ "\n",
+ "plot_profile_classification('NARRA0018', 'prestorm')\n",
+ "plot_profile_classification('NARRA0019', 'prestorm')\n",
+ "plot_profile_classification('CRESn0017', 'poststorm')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "heading_collapsed": true
+ },
+ "source": [
+ "## Try lmfit"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "hidden": true
+ },
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "code_folding": [
+ 0
+ ],
+ "hidden": true
+ },
+ "outputs": [],
+ "source": [
+ "from lmfit import Model, Parameters\n",
+ "\n",
+ "def get_data():\n",
+ " site_id='NARRA0018'\n",
+ " profile_type='prestorm'\n",
+ " df_profile = df_profiles.query(\"site_id == '{}' and profile_type == '{}'\".format(site_id, profile_type))\n",
+ " x = np.array(df_profile.index.get_level_values('x').tolist())\n",
+ " z = np.array(df_profile.z.tolist()) \n",
+ "\n",
+ " nan_mask = ma.masked_invalid(z).mask\n",
+ " x = x[~nan_mask]\n",
+ " z = z[~nan_mask]\n",
+ " return x,z\n",
+ "\n",
+ "# def piecewise_linear(x, x0, x1, b, k1, k2, k3):\n",
+ "# condlist = [x < x0, (x >= x0) & (x < x1), x >= x1]\n",
+ "# funclist = [lambda x: k1*x + b, lambda x: k1*x + b + k2*(x-x0), lambda x: k1*x + b + k2*(x-x0) + k3*(x - x1)]\n",
+ "# return np.piecewise(x, condlist, funclist)\n",
+ "\n",
+ "# x,z = get_data()\n",
+ "\n",
+ "# fmodel = Model(piecewise_linear)\n",
+ "# params = Parameters()\n",
+ "# params.add('x0', value=0, vary=True, min=min(x), max=max(x))\n",
+ "# params.add('x1', value=0, vary=True, min=min(x), max=max(x))\n",
+ "# params.add('b', value=0, vary=True)\n",
+ "# params.add('k1', value=0, vary=True, min=-0.01, max=0.01)\n",
+ "# params.add('k2', value=0, vary=True, min=-0.1, max=-0.5)\n",
+ "# params.add('k3', value=0, vary=True, min=0.1, max=0.5)\n",
+ "\n",
+ "def piecewise_linear(x, x0, x1, x2, b, k1, k2, k3,k4):\n",
+ " condlist = [x < x0, (x >= x0) & (x < x1), (x >= x1) & (x < x2), x >= x2]\n",
+ " funclist = [lambda x: k1*x + b, lambda x: k1*x + b + k2*(x-x0), lambda x: k1*x + b + k2*(x-x0) + k3*(x - x1), lambda x: k1*x + b + k2*(x-x0) + k3*(x - x1) +k4*(x-x2)]\n",
+ " return np.piecewise(x, condlist, funclist)\n",
+ "\n",
+ "x,z = get_data()\n",
+ "\n",
+ "fmodel = Model(piecewise_linear)\n",
+ "params = Parameters()\n",
+ "params.add('x0', value=0, vary=True, min=min(x), max=max(x))\n",
+ "params.add('x1', value=0, vary=True, min=min(x), max=max(x))\n",
+ "params.add('x2', value=0, vary=True, min=min(x), max=max(x))\n",
+ "params.add('b', value=0, vary=True)\n",
+ "params.add('k1', value=0, vary=True, min=-0.5, max=0.5)\n",
+ "params.add('k2', value=0, vary=True, min=-0.5, max=0.5)\n",
+ "params.add('k3', value=0, vary=True, min=-0.5, max=0.5)\n",
+ "params.add('k4', value=0, vary=True, min=-0.5, max=0.5)\n",
+ "\n",
+ "\n",
+ "result = fmodel.fit(z, params, x=x,method='ampgo')\n",
+ "\n",
+ "\n",
+ "pyplot.figure()\n",
+ "pyplot.plot(x,z, color='0.5',marker='.', alpha=.2, ms=10,linestyle=\"None\")\n",
+ "pyplot.plot(x,result.best_fit, color='r')\n",
+ "pyplot.show()\n",
+ "print(result.fit_report())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Try spline"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "code_folding": [
+ 2
+ ]
+ },
+ "outputs": [],
+ "source": [
+ "from scipy.signal import savgol_filter\n",
+ "\n",
+ "def get_data():\n",
+ " site_id='NARRA0018'\n",
+ " profile_type='prestorm'\n",
+ " df_profile = df_profiles.query(\"site_id == '{}' and profile_type == '{}'\".format(site_id, profile_type))\n",
+ " x = np.array(df_profile.index.get_level_values('x').tolist())\n",
+ " z = np.array(df_profile.z.tolist()) \n",
+ "\n",
+ " nan_mask = ma.masked_invalid(z).mask\n",
+ " x = x[~nan_mask]\n",
+ " z = z[~nan_mask]\n",
+ " return x,z\n",
+ "\n",
+ "x,z = get_data()\n",
+ "\n",
+ "z_filtered = savgol_filter(z, 31, 3)\n",
+ "\n",
+ "\n",
+ "pyplot.figure()\n",
+ "pyplot.plot(x,z, color='0.5',marker='.', alpha=.2, ms=10,linestyle=\"None\")\n",
+ "pyplot.plot(x,z_filtered, color='r')\n",
+ "pyplot.show()\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.7"
+ },
+ "toc": {
+ "base_numbering": 1,
+ "nav_menu": {},
+ "number_sections": true,
+ "sideBar": true,
+ "skip_h1_title": false,
+ "title_cell": "Table of Contents",
+ "title_sidebar": "Contents",
+ "toc_cell": false,
+ "toc_position": {},
+ "toc_section_display": true,
+ "toc_window_display": false
+ },
+ "varInspector": {
+ "cols": {
+ "lenName": 16,
+ "lenType": 16,
+ "lenVar": 40
+ },
+ "kernels_config": {
+ "python": {
+ "delete_cmd_postfix": "",
+ "delete_cmd_prefix": "del ",
+ "library": "var_list.py",
+ "varRefreshCmd": "print(var_dic_list())"
+ },
+ "r": {
+ "delete_cmd_postfix": ") ",
+ "delete_cmd_prefix": "rm(",
+ "library": "var_list.r",
+ "varRefreshCmd": "cat(var_dic_list()) "
+ }
+ },
+ "types_to_exclude": [
+ "module",
+ "function",
+ "builtin_function_or_method",
+ "instance",
+ "_Feature"
+ ],
+ "window_display": false
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/notebooks/04b_profile_picker.ipynb b/notebooks/04b_profile_picker.ipynb
new file mode 100644
index 0000000..160904f
--- /dev/null
+++ b/notebooks/04b_profile_picker.ipynb
@@ -0,0 +1,1374 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Beach profile classifier\n",
+ "Using RANSAC algorithm"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "heading_collapsed": true
+ },
+ "source": [
+ "## Setup notebook"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "hidden": true
+ },
+ "outputs": [],
+ "source": [
+ "# Enable autoreloading of our modules. \n",
+ "# Most of the code will be located in the /src/ folder, \n",
+ "# and then called from the notebook.\n",
+ "%matplotlib inline\n",
+ "%reload_ext autoreload\n",
+ "%autoreload"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "hidden": true
+ },
+ "outputs": [],
+ "source": [
+ "from IPython.core.debugger import set_trace\n",
+ "\n",
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "import os\n",
+ "import decimal\n",
+ "import plotly\n",
+ "import plotly.graph_objs as go\n",
+ "import plotly.plotly as py\n",
+ "import plotly.tools as tls\n",
+ "import plotly.figure_factory as ff\n",
+ "from plotly import tools\n",
+ "import plotly.io as pio\n",
+ "from scipy import stats\n",
+ "import math\n",
+ "import matplotlib\n",
+ "from matplotlib import cm\n",
+ "import colorlover as cl\n",
+ "import numpy.ma as ma\n",
+ "\n",
+ "from ipywidgets import widgets, Output\n",
+ "from IPython.display import display, clear_output, Image, HTML\n",
+ "\n",
+ "from sklearn.metrics import confusion_matrix\n",
+ "\n",
+ "import numpy as np\n",
+ "from matplotlib import pyplot as plt\n",
+ "\n",
+ "from sklearn import linear_model, datasets"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "hidden": true
+ },
+ "outputs": [],
+ "source": [
+ "# Matplot lib default settings\n",
+ "plt.rcParams[\"figure.figsize\"] = (10,3)\n",
+ "plt.rcParams['axes.grid']=True\n",
+ "plt.rcParams['grid.alpha'] = 0.5\n",
+ "plt.rcParams['grid.color'] = \"grey\"\n",
+ "plt.rcParams['grid.linestyle'] = \"--\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "heading_collapsed": true
+ },
+ "source": [
+ "## Import data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "hidden": true
+ },
+ "outputs": [],
+ "source": [
+ "def df_from_csv(csv, index_col, data_folder='../data/interim'):\n",
+ " print('Importing {}'.format(csv))\n",
+ " return pd.read_csv(os.path.join(data_folder,csv), index_col=index_col)\n",
+ "\n",
+ "df_waves = df_from_csv('waves.csv', index_col=[0, 1])\n",
+ "df_tides = df_from_csv('tides.csv', index_col=[0, 1])\n",
+ "df_profiles = df_from_csv('profiles.csv', index_col=[0, 1, 2])\n",
+ "df_sites = df_from_csv('sites.csv', index_col=[0])\n",
+ "df_profile_features_crest_toes = df_from_csv('profile_features_crest_toes.csv', index_col=[0,1])\n",
+ "\n",
+ "# Note that the forecasted data sets should be in the same order for impacts and twls\n",
+ "impacts = {\n",
+ " 'forecasted': {\n",
+ " 'foreshore_slope_sto06': df_from_csv('impacts_forecasted_foreshore_slope_sto06.csv', index_col=[0]),\n",
+ " 'mean_slope_sto06': df_from_csv('impacts_forecasted_mean_slope_sto06.csv', index_col=[0]),\n",
+ " },\n",
+ " 'observed': df_from_csv('impacts_observed.csv', index_col=[0])\n",
+ " }\n",
+ "\n",
+ "\n",
+ "twls = {\n",
+ " 'forecasted': {\n",
+ " 'foreshore_slope_sto06': df_from_csv('twl_foreshore_slope_sto06.csv', index_col=[0, 1]),\n",
+ " 'mean_slope_sto06':df_from_csv('twl_mean_slope_sto06.csv', index_col=[0, 1]),\n",
+ " }\n",
+ "}\n",
+ "print('Done!')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Implement algorithm"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Get profile data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_profile_data(site, profile_type, df_profiles):\n",
+ " \"\"\"\n",
+ " Returns a list of x and z coordinates for a given profile.\n",
+ " \"\"\"\n",
+ "\n",
+ " # Get x and z coorindates of profile\n",
+ " x = df_profiles.loc[(site, profile_type)].index.values\n",
+ " z = df_profiles.loc[(site, profile_type)].z.values\n",
+ "\n",
+ " # Get land limit\n",
+ " land_lim = df_profiles.loc[(site, 'poststorm')].land_lim.loc[0]\n",
+ "\n",
+ " # Remove nan values\n",
+ " m = ma.masked_invalid(z)\n",
+ " x = x[~m.mask]\n",
+ " z = z[~m.mask]\n",
+ "\n",
+ "# # Remove landwards of landlim\n",
+ "# mask = ma.masked_where(x < land_lim, x)\n",
+ "# x = x[~mask.mask]\n",
+ "# z = z[~mask.mask]\n",
+ "\n",
+ " return x, z\n",
+ "\n",
+ "\n",
+ "# Load profile data\n",
+ "# site = 'WAMBE0010'\n",
+ "# site = 'NINEMs0048'\n",
+ "# site = 'NAMB0013'\n",
+ "# site = 'AVOCAn0009'\n",
+ "# site = 'GRANTSs0014'\n",
+ "site = 'NARRA0001'\n",
+ "profile_type = 'prestorm'\n",
+ "x, z = get_profile_data(site, profile_type, df_profiles)\n",
+ "\n",
+ "print('x = {} ...'.format(x[0:5]))\n",
+ "print('z = {} ...'.format(z[0:5]))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "hide_input": true
+ },
+ "outputs": [],
+ "source": [
+ "\n",
+ "\n",
+ "\n",
+ "# # n_samples = 1000\n",
+ "# # n_outliers = 50\n",
+ "\n",
+ "\n",
+ "# # X, y, coef = datasets.make_regression(n_samples=n_samples, n_features=1,\n",
+ "# # n_informative=1, noise=10,\n",
+ "# # coef=True, random_state=0)\n",
+ "\n",
+ "# # # Add outlier data\n",
+ "# # np.random.seed(0)\n",
+ "# # X[:n_outliers] = 3 + 0.5 * np.random.normal(size=(n_outliers, 1))\n",
+ "# # y[:n_outliers] = -3 + 10 * np.random.normal(size=n_outliers)\n",
+ "\n",
+ "# # # Fit line using all data\n",
+ "# # lr = linear_model.LinearRegression()\n",
+ "# # lr.fit(X, y)\n",
+ "\n",
+ "# # Robustly fit linear model with RANSAC algorithm\n",
+ "# ransac = linear_model.RANSACRegressor()\n",
+ "# ransac.fit(x, z)\n",
+ "# inlier_mask = ransac.inlier_mask_\n",
+ "# outlier_mask = np.logical_not(inlier_mask)\n",
+ "\n",
+ "# # Predict data of estimated models\n",
+ "# line_x = np.arange(x.min(), x.max())[:, np.newaxis]\n",
+ "# line_y_ransac = ransac.predict(line_x)\n",
+ "\n",
+ "# lw = 2\n",
+ "# plt.scatter(x[inlier_mask], z[inlier_mask], color='yellowgreen', marker='.',\n",
+ "# label='Inliers')\n",
+ "# plt.scatter(x[outlier_mask], z[outlier_mask], color='gold', marker='.',\n",
+ "# label='Outliers')\n",
+ "# plt.plot(line_x, line_y_ransac, color='cornflowerblue', linewidth=lw,\n",
+ "# label='RANSAC regressor')\n",
+ "# plt.legend(loc='lower right')\n",
+ "# plt.xlabel(\"Input\")\n",
+ "# plt.ylabel(\"Response\")\n",
+ "# plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Fit linear interpolated spline to profile\n",
+ "- Linear interpolated spline used to simplify the profile.\n",
+ "- Need to do a bit of optimization to calculate the best smoothing parameter for the profile."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "code_folding": [
+ 4,
+ 11,
+ 20,
+ 25,
+ 30,
+ 42,
+ 92
+ ]
+ },
+ "outputs": [],
+ "source": [
+ "from scipy.interpolate import UnivariateSpline\n",
+ "from scipy.interpolate import interp1d\n",
+ "\n",
+ "\n",
+ "def pairwise(iterable):\n",
+ " \"s -> (s0,s1), (s1,s2), (s2, s3), ...\"\n",
+ " a, b = itertools.tee(iterable)\n",
+ " next(b, None)\n",
+ " return zip(a, b)\n",
+ "\n",
+ "\n",
+ "def xz(x_start, x_end, x, z):\n",
+ " \"\"\"\n",
+ " Returns a list of x coordinates and z coorindates which lie between x_start and x_end\n",
+ " \"\"\"\n",
+ " x_seg = [val for val in x if x_start <= val <= x_end]\n",
+ " z_seg = [z_val for x_val, z_val in zip(x, z) if x_start <= x_val <= x_end]\n",
+ " return x_seg, z_seg\n",
+ "\n",
+ "\n",
+ "def get_slope(x, z):\n",
+ " slope, intercept, r_value, p_value, std_err = linregress(x, z)\n",
+ " return slope\n",
+ "\n",
+ "\n",
+ "def get_r_squared(x, z):\n",
+ " slope, intercept, r_value, p_value, std_err = linregress(x, z)\n",
+ " return r_value**2\n",
+ "\n",
+ "\n",
+ "def rolling_std(a, w):\n",
+ " \"\"\"\n",
+ " Calculates a rolling window standard deviation\n",
+ " https://stackoverflow.com/a/40773366\n",
+ " \"\"\"\n",
+ " a = np.array(a)\n",
+ " nrows = a.size - w + 1\n",
+ " n = a.strides[0]\n",
+ " a2D = np.lib.stride_tricks.as_strided(a, shape=(nrows, w), strides=(n, n))\n",
+ " return np.std(a2D, 1)\n",
+ "\n",
+ "\n",
+ "def iterate_over_smoothing_params(x, z):\n",
+ " \"\"\"\n",
+ " Finds the best smoothing parameter for a linear interpolated spline. \n",
+ " Checks a number of smoothing factors, and then tries to minimize the \n",
+ " number of knots (changepoints) while retaining decent match to the \n",
+ " original profile.\n",
+ " \"\"\"\n",
+ "\n",
+ " # Store the results of our iterations in a list of dictionaries\n",
+ " results = []\n",
+ "\n",
+ " # Iterate through different value of smoothing parameters\n",
+ " s_vals = [x for x in np.arange(0, 10, 0.01)]\n",
+ "\n",
+ " r2_vals = []\n",
+ " n_knots = []\n",
+ " s_vals_to_keep = []\n",
+ "\n",
+ " # Iterate backwards just to make further calcultions more easier.\n",
+ " for s_val in s_vals[::-1]:\n",
+ "\n",
+ " # Fit spline to profile using the s_val for this iteration\n",
+ " # k=1 is used to force linear line segments between knots\n",
+ " s = UnivariateSpline(x, z, s=s_val, k=1)\n",
+ " xs = np.linspace(x[0], x[-1], 1000)\n",
+ " zs = s(xs)\n",
+ "\n",
+ " # Find knots\n",
+ " x_knots = s.get_knots()\n",
+ " z_knots = s(x_knots)\n",
+ "\n",
+ " # Get number of knots\n",
+ " n = len(s.get_knots())\n",
+ "\n",
+ " # If we've already recorded data about this number of knots, just skip.\n",
+ " # Need to also, only have increasing results for spline interpolation\n",
+ " if n in [x['n'] for x in results\n",
+ " ] or n < max([x['n'] for x in results], default=0):\n",
+ " continue\n",
+ "\n",
+ " # Get r2, how well does the simplification fit the original profile?\n",
+ " # Create interp model from the knots at our original points.\n",
+ " f = interp1d(x_knots, z_knots)\n",
+ " z_lin = f(x)\n",
+ " r2 = get_r_squared(z, z_lin)\n",
+ "\n",
+ " results.append({'n': n, 's': s_val, 'r2': r2})\n",
+ " return results\n",
+ "\n",
+ "\n",
+ "def find_best_smoothing_param(results, min_std=0.0002):\n",
+ " \"\"\"\n",
+ " Given a list of smoothing parameters and their fits, determine what the best smoothing parameter is.\n",
+ " Larger min_std = more smoothing\n",
+ " \"\"\"\n",
+ "\n",
+ " # Get the 2nd derivate of the n_knots vs r2_vals.\n",
+ " y_spl = UnivariateSpline([x['n'] for x in results],\n",
+ " [x['r2'] for x in results],\n",
+ " s=0)\n",
+ " y_spl_2d = y_spl.derivative(n=2)\n",
+ " y_spl_2d_vals = y_spl_2d([x['n'] for x in results])\n",
+ "\n",
+ " # Get a rolling standard deviation of the derivative\n",
+ " std = rolling_std(y_spl_2d_vals, w=3)\n",
+ "\n",
+ " # Best smoothing parameter will be when the standard deviation stops changing\n",
+ " best_i = np.argmax(std < min_std)\n",
+ " best_s = results[best_i]['s']\n",
+ " return best_s\n",
+ "\n",
+ "\n",
+ "def simplify_profile(x, z, site):\n",
+ " results = iterate_over_smoothing_params(x, z)\n",
+ " best_s = find_best_smoothing_param(results)\n",
+ "\n",
+ " # Fit spline to profile\n",
+ " s = UnivariateSpline(x, z, s=best_s, k=1)\n",
+ " xs = np.linspace(x[0], x[-1], 1000)\n",
+ " zs = s(xs)\n",
+ "\n",
+ " # Find knots\n",
+ " x_knots = s.get_knots()\n",
+ " z_knots = s(x_knots)\n",
+ "\n",
+ " # Plot for checking\n",
+ " plt.title('{}: Linear spline simplification'.format(site))\n",
+ " plt.xlabel('Distance (m)')\n",
+ " plt.ylabel('Elevation (m AHD)')\n",
+ " plt.plot(x, z, 'k.-', label='Raw profile')\n",
+ " plt.plot(\n",
+ " xs, zs, 'r-', label='Interpolated profile (s={:.2f})'.format(best_s))\n",
+ " plt.plot(\n",
+ " x_knots,\n",
+ " z_knots,\n",
+ " 'ro',\n",
+ " markersize=8,\n",
+ " markeredgewidth=1.5,\n",
+ " markeredgecolor='orange',\n",
+ " label='Interpolated knots (n={})'.format(len(x_knots)))\n",
+ " plt.legend(loc='best')\n",
+ "# plt.show()\n",
+ "\n",
+ " return x_knots, z_knots, best_s\n",
+ "\n",
+ "\n",
+ "x_knots, z_knots, best_s = simplify_profile(x, z, site)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "code_folding": [
+ 0
+ ]
+ },
+ "outputs": [],
+ "source": [
+ "def get_x_z_from_knots(x_knots, z_knots):\n",
+ " # Fit spline to profile\n",
+ " s = UnivariateSpline(x_knots, z_knots, s=0, k=1)\n",
+ " xs = np.linspace(x_knots[0], x_knots[-1], 1000)\n",
+ " zs = s(xs)\n",
+ " return xs, zs\n",
+ "\n",
+ "def simplify_segments_with_same_slopes(x_knots, x, z, site, best_s):\n",
+ " \"\"\"\n",
+ " Removes knots which have similar slopes on either side. \n",
+ " This is an extra simplifcation as the linear splines may still include\n",
+ " some nodes that aren't required.\n",
+ " \"\"\"\n",
+ " removed_x_knots = []\n",
+ " while True:\n",
+ " for x_knot1, x_knot2, x_knot3 in zip(x_knots[0:-2], x_knots[1:-1], x_knots[2:]):\n",
+ "\n",
+ " # Get slope of segment behind point at x_knot2\n",
+ " x_seg, z_seg = xz(x_knot1, x_knot2, x, z)\n",
+ " slope1 = get_slope(x_seg, z_seg)\n",
+ "\n",
+ " # Get slope of line in front of point at x_knot2\n",
+ " x_seg, z_seg = xz(x_knot2, x_knot3, x, z)\n",
+ " slope2 = get_slope(x_seg, z_seg)\n",
+ "\n",
+ " slope_diff = abs(slope1 - slope2)\n",
+ "\n",
+ " # Also check if points are too close together\n",
+ " if x_knot3 - x_knot1 < 3: # m\n",
+ " too_close = True\n",
+ " else:\n",
+ " too_close = False\n",
+ " \n",
+ " # Good, the slopes are different on each side, keep checking\n",
+ " if slope_diff > 0.01 and too_close == False:\n",
+ " continue\n",
+ " # Else bad, slopes are the same so we have to remove this point\n",
+ " else:\n",
+ " print('Knot at x={} removed (slope_diff={:.3f})'.format(\n",
+ " x_knot2, slope_diff))\n",
+ " x_knots = np.delete(x_knots, np.where(x_knots == x_knot2), axis=0)\n",
+ " removed_x_knots.append(x_knot2)\n",
+ " break\n",
+ "\n",
+ " else:\n",
+ " print(\"All segments have different slopes\")\n",
+ " x_knots_simplified = x_knots\n",
+ " z_knots_simplified = [\n",
+ " z_val for x_val, z_val in zip(x, z) if x_val in x_knots_simplified\n",
+ " ]\n",
+ " break\n",
+ " \n",
+ " # Find z location of our removed knots\n",
+ " removed_z_knots = [\n",
+ " z_val for x_val, z_val in zip(x, z) if x_val in removed_x_knots\n",
+ " ]\n",
+ " \n",
+ " # Get the new interpolated spline from our simplified knots\n",
+ " xs, zs = get_x_z_from_knots(x_knots_simplified, z_knots_simplified)\n",
+ " \n",
+ " # Plot for checking\n",
+ "# plt.title('{}: Linear spline simplification by comparing slopes'.format(site))\n",
+ "# plt.xlabel('Distance (m)')\n",
+ "# plt.ylabel('Elevation (m AHD)')\n",
+ "# plt.plot(x, z, 'k.-', label='Raw profile')\n",
+ "# plt.plot(\n",
+ "# xs, zs, 'r-', label='Interpolated profile (s={:.2f})'.format(best_s))\n",
+ "# plt.plot(\n",
+ "# x_knots_simplified,\n",
+ "# z_knots_simplified,\n",
+ "# 'ro',\n",
+ "# markersize=8,\n",
+ "# markeredgewidth=1.5,\n",
+ "# markeredgecolor='orange',\n",
+ "# label='Interpolated knots (n={})'.format(len(x_knots)))\n",
+ "# plt.plot(\n",
+ "# removed_x_knots,\n",
+ "# removed_z_knots,\n",
+ "# 'ro',\n",
+ "# markersize=10,\n",
+ "# markeredgewidth=2.5,\n",
+ "# markerfacecolor=\"None\",\n",
+ "# markeredgecolor='orange',\n",
+ "# label='Removed knots (n={})'.format(len(removed_x_knots)))\n",
+ "# plt.legend(loc='best')\n",
+ "# plt.show()\n",
+ "\n",
+ " return x_knots_simplified,z_knots_simplified\n",
+ "\n",
+ "x_knots, z_knots = simplify_segments_with_same_slopes(x_knots, x, z, site, best_s)\n",
+ "xs, zs = get_x_z_from_knots(x_knots, z_knots)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "code_folding": [
+ 1
+ ]
+ },
+ "outputs": [],
+ "source": [
+ "## BACKUP\n",
+ "def find_crest_and_toes(x,z,x_knots,best_s):\n",
+ "\n",
+ " # Get a cubic spline so we can have continuous second order deriviates for our profile\n",
+ "# spl = interpolate.splrep(x, z, k=4,t=x_knots[1:-1])\n",
+ " spl = interpolate.splrep(x, z, k=3,s=best_s)\n",
+ "\n",
+ " xx = np.linspace(x[0], x[-1], 1000)\n",
+ " zz = interpolate.splev(xx, spl)\n",
+ " zz_d1 = interpolate.splev(xx, spl, der=1)\n",
+ " zz_d2 = interpolate.splev(xx, spl, der=2)\n",
+ " zz_d3 = interpolate.splev(xx, spl, der=3)\n",
+ "\n",
+ " try:\n",
+ " # Find dune crest by looking at elevation\n",
+ " peaks_crest, props_crest = find_peaks(zz, height=3, prominence=0.5)\n",
+ " \n",
+ " # Save potential crests\n",
+ " x_potential_crests = xx[peaks_crest]\n",
+ " z_potential_crests = zz[peaks_crest]\n",
+ "\n",
+ " # Take most seaward peak as dune crest\n",
+ " i_crest = peaks_crest[-1]\n",
+ " x_crest = xx[i_crest]\n",
+ " z_crest = zz[i_crest]\n",
+ "\n",
+ " print('Found {} potential dune crests from elevation'.format(len(peaks_crest)))\n",
+ "\n",
+ " except:\n",
+ " print('No crests found from elevation')\n",
+ " x_crest = np.nan\n",
+ " z_crest = np.nan\n",
+ " pass\n",
+ "\n",
+ " try:\n",
+ " if np.isnan(x_crest) and np.isnan(x_crest):\n",
+ " # Find dune crest by looking at 2nd deriviate\n",
+ " # Multiply by -1 since crest will have a negative 2nd derivative and we want to find peaks (i.e. positive)\n",
+ " peaks_crest, props_crest = find_peaks(zz_d2*-1, height=0.02,width=0)\n",
+ " \n",
+ " \n",
+ " # Save potential crests\n",
+ " x_potential_crests = xx[peaks_crest]\n",
+ " z_potential_crests = zz[peaks_crest]\n",
+ " print('Found {} potential dune crests from 2nd derivitive'.format(len(peaks_crest)))\n",
+ "\n",
+ " # Take peak with biggest height\n",
+ " i_biggest_crest = np.argmax(props_crest['peak_heights'])\n",
+ " i_crest = peaks_crest[i_biggest_crest]\n",
+ "# x_crest = xx[i_crest]\n",
+ "# z_crest = zz[i_crest]\n",
+ "\n",
+ " # Then take the left base of that peak\n",
+ " x_crest = xx[props_crest['left_bases'][i_biggest_crest]]\n",
+ " z_crest= zz[props_crest['left_bases'][i_biggest_crest]]\n",
+ "\n",
+ "\n",
+ " except:\n",
+ " # Take crest as location with maximum elevation\n",
+ " i_crest = np.argmax(zz)\n",
+ " x_crest = xx[i_crest]\n",
+ " z_crest = zz[i_crest]\n",
+ " print('No crest found, taking maximum elevation as crest')\n",
+ "\n",
+ " try:\n",
+ " # Find due toe\n",
+ " peaks_toe, props_toe = find_peaks(zz_d2, height=0, prominence=0.02)\n",
+ "# peaks_toe, props_toe = find_peaks(zz_d2, height=-3, prominence=0.00)\n",
+ "\n",
+ " # Save potential crests\n",
+ " x_potential_toes = xx[peaks_toe]\n",
+ " z_potential_toes = zz[peaks_toe]\n",
+ "\n",
+ " # Remove toes which are behind dune crest\n",
+ " heights_toe = props_toe['peak_heights'][peaks_toe > i_crest]\n",
+ " peaks_toe = peaks_toe[peaks_toe > i_crest]\n",
+ "\n",
+ " # Remove toes that are less than 0.5m in height from dune crest\n",
+ "\n",
+ " mask = z_crest-0.5>zz[peaks_toe]\n",
+ " heights_toe = heights_toe[mask]\n",
+ " peaks_toe = peaks_toe[mask]\n",
+ "\n",
+ " # Take toe with biggest 2nd derivative height\n",
+ " i_toe = peaks_toe[np.argmax(heights_toe)]\n",
+ " x_toe = xx[i_toe]\n",
+ " z_toe = zz[i_toe]\n",
+ " print('Found {} potential dune toes from 2nd derivitive'.format(len(peaks_toe)))\n",
+ "\n",
+ "# # The above method usually results in a toe value which is slightly too high up.\n",
+ "# # We can improve this by moving the toe seaward to the next negative peak in the third\n",
+ "# # derivative of elevation\n",
+ "# peaks_toe_d3, props_toe_d3 = find_peaks(zz_d3*-1, height=0.03, prominence=0.02)\n",
+ "\n",
+ "# # Filter everything landward of the previous toe position, then take the first (most landward) peak\n",
+ "# mask = xx[peaks_toe_d3] > x_toe\n",
+ "# peaks_toe_d3 = peaks_toe_d3[mask]\n",
+ "\n",
+ "# if peaks_toe_d3.size != 0:\n",
+ "# print('Adjusting toe position based on d3')\n",
+ "# x_toe = xx[peaks_toe_d3[0]]\n",
+ "# z_toe = zz[peaks_toe_d3[0]]\n",
+ "\n",
+ "# # Move toe forward to based on the third derivative of elevation\n",
+ "# print('Adjusting toe position based on d3')\n",
+ "# mask = (zz_d3 > -0.0008) & (xx > x_toe) & (np.r_[np.diff(zz_d3)[0],np.diff(zz_d3)] > 0)\n",
+ "# x_toe = xx[mask][1]\n",
+ "# z_toe = zz[mask][1]\n",
+ "\n",
+ " except:\n",
+ " x_toe = np.nan\n",
+ " z_toe = np.nan\n",
+ " print('No toe found')\n",
+ " \n",
+ " return xx,zz, zz_d1,zz_d2,zz_d3,x_crest,z_crest, x_toe,z_toe, x_potential_crests,z_potential_crests, x_potential_toes,z_potential_toes"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "code_folding": [
+ 126
+ ]
+ },
+ "outputs": [],
+ "source": [
+ "def find_crest_and_toes(x,z,x_knots,best_s):\n",
+ "\n",
+ " # Get a cubic spline so we can have continuous second order deriviates for our profile\n",
+ "# spl = interpolate.splrep(x, z, k=4,t=x_knots[1:-1])\n",
+ " spl = interpolate.splrep(x, z, k=3,s=best_s)\n",
+ "\n",
+ " xx = np.linspace(x[0], x[-1], 1000)\n",
+ " zz = interpolate.splev(xx, spl)\n",
+ " zz_d1 = interpolate.splev(xx, spl, der=1)\n",
+ " zz_d2 = interpolate.splev(xx, spl, der=2)\n",
+ " zz_d3 = interpolate.splev(xx, spl, der=3)\n",
+ "\n",
+ " # Find the biggest slopes\n",
+ " peaks, props = find_peaks(zz_d1*-1, height=0.15, width=0,prominence=0.1)\n",
+ "\n",
+ " if len(peaks) != 0:\n",
+ "\n",
+ " x_potential_crests =[xx[val] for val in props['left_bases']]\n",
+ " x_potential_toes =[xx[val] for val in props['right_bases']]\n",
+ " x_potential_heights = [val for val in props['peak_heights']]\n",
+ " x_potential_face_center = xx[peaks]\n",
+ "\n",
+ " # Put a limit on how when a slope ends.\n",
+ " # Dune faces has to be steeper than this value\n",
+ "# min_slope = -0.10\n",
+ "\n",
+ " x_new_potential_crests = []\n",
+ " x_new_potential_toes = []\n",
+ " z_new_potential_crests = []\n",
+ " z_new_potential_toes = []\n",
+ " dune_heights = []\n",
+ " slopes = []\n",
+ "\n",
+ " for x_crest, x_center, x_toe,height in zip(x_potential_crests, x_potential_face_center, x_potential_toes,x_potential_heights):\n",
+ " print('Checking x_crest={:.2f}m,x_center={:.2f}m,x_toe={:.2f}m'.format(x_crest, x_center, x_toe))\n",
+ "\n",
+ " min_slope = height/-6\n",
+ " # Check the land side of the dune face\n",
+ " land_mask = ((x_crest<=xx)&(xx<=x_center))\n",
+ " land_slope_okay = zz_d1[land_mask] min_dune_ele) & (np.array(dune_heights) > min_dune_height )\n",
+ "\n",
+ " slopes = np.array(slopes)[mask]\n",
+ " dune_heights = np.array(dune_heights)[mask] \n",
+ " x_potential_crests = np.array(x_new_potential_crests)[mask]\n",
+ " x_potential_toes = np.array(x_new_potential_toes)[mask]\n",
+ " z_potential_crests = np.array(z_new_potential_crests)[mask]\n",
+ " z_potential_toes = np.array(z_new_potential_toes)[mask]\n",
+ "\n",
+ "# # Select dune by largest dune height\n",
+ "# i_dune = np.argmax(dune_heights)\n",
+ "\n",
+ " ## TODO Throws error if x_potential_crests is empty\n",
+ "\n",
+ " # Select dune by most seaward\n",
+ " i_dune = np.argmax(x_potential_crests)\n",
+ "\n",
+ "\n",
+ " \n",
+ "# # Select dune by biggest slope\n",
+ "# i_dune =np.argmax(slopes*-1)\n",
+ " x_crest = x_potential_crests[i_dune]\n",
+ " x_toe = x_potential_toes[i_dune]\n",
+ " z_crest = z_potential_crests[i_dune]\n",
+ " z_toe = z_potential_toes[i_dune]\n",
+ "\n",
+ " # try:\n",
+ " # # Find dune crest by looking at elevation\n",
+ " # peaks_crest, props_crest = find_peaks(zz, height=3, prominence=0.5)\n",
+ "\n",
+ " # # Save potential crests\n",
+ " # x_potential_crests = xx[peaks_crest]\n",
+ " # z_potential_crests = zz[peaks_crest]\n",
+ "\n",
+ " # # Take most seaward peak as dune crest\n",
+ " # i_crest = peaks_crest[-1]\n",
+ " # x_crest = xx[i_crest]\n",
+ " # z_crest = zz[i_crest]\n",
+ "\n",
+ " # print('Found {} potential dune crests from elevation'.format(len(peaks_crest)))\n",
+ "\n",
+ " # except:\n",
+ " # print('No crests found from elevation')\n",
+ " # x_crest = np.nan\n",
+ " # z_crest = np.nan\n",
+ " # pass\n",
+ "\n",
+ " # try:\n",
+ " # if np.isnan(x_crest) and np.isnan(x_crest):\n",
+ " # # Find dune crest by looking at 2nd deriviate\n",
+ " # # Multiply by -1 since crest will have a negative 2nd derivative and we want to find peaks (i.e. positive)\n",
+ " # peaks_crest, props_crest = find_peaks(zz_d2*-1, height=0.02,width=0)\n",
+ "\n",
+ "\n",
+ " # # Save potential crests\n",
+ " # x_potential_crests = xx[peaks_crest]\n",
+ " # z_potential_crests = zz[peaks_crest]\n",
+ " # print('Found {} potential dune crests from 2nd derivitive'.format(len(peaks_crest)))\n",
+ "\n",
+ " # # Take peak with biggest height\n",
+ " # i_biggest_crest = np.argmax(props_crest['peak_heights'])\n",
+ " # i_crest = peaks_crest[i_biggest_crest]\n",
+ " # # x_crest = xx[i_crest]\n",
+ " # # z_crest = zz[i_crest]\n",
+ "\n",
+ " # # Then take the left base of that peak\n",
+ " # x_crest = xx[props_crest['left_bases'][i_biggest_crest]]\n",
+ " # z_crest= zz[props_crest['left_bases'][i_biggest_crest]]\n",
+ "\n",
+ "\n",
+ " # except:\n",
+ " # # Take crest as location with maximum elevation\n",
+ " # i_crest = np.argmax(zz)\n",
+ " # x_crest = xx[i_crest]\n",
+ " # z_crest = zz[i_crest]\n",
+ " # print('No crest found, taking maximum elevation as crest')\n",
+ "\n",
+ " # try:\n",
+ " # # Find due toe\n",
+ " # peaks_toe, props_toe = find_peaks(zz_d2, height=0, prominence=0.02)\n",
+ " # # peaks_toe, props_toe = find_peaks(zz_d2, height=-3, prominence=0.00)\n",
+ "\n",
+ " # # Save potential crests\n",
+ " # x_potential_toes = xx[peaks_toe]\n",
+ " # z_potential_toes = zz[peaks_toe]\n",
+ "\n",
+ " # # Remove toes which are behind dune crest\n",
+ " # heights_toe = props_toe['peak_heights'][peaks_toe > i_crest]\n",
+ " # peaks_toe = peaks_toe[peaks_toe > i_crest]\n",
+ "\n",
+ " # # Remove toes that are less than 0.5m in height from dune crest\n",
+ "\n",
+ " # mask = z_crest-0.5>zz[peaks_toe]\n",
+ " # heights_toe = heights_toe[mask]\n",
+ " # peaks_toe = peaks_toe[mask]\n",
+ "\n",
+ " # # Take toe with biggest 2nd derivative height\n",
+ " # i_toe = peaks_toe[np.argmax(heights_toe)]\n",
+ " # x_toe = xx[i_toe]\n",
+ " # z_toe = zz[i_toe]\n",
+ " # print('Found {} potential dune toes from 2nd derivitive'.format(len(peaks_toe)))\n",
+ "\n",
+ " # # # The above method usually results in a toe value which is slightly too high up.\n",
+ " # # # We can improve this by moving the toe seaward to the next negative peak in the third\n",
+ " # # # derivative of elevation\n",
+ " # # peaks_toe_d3, props_toe_d3 = find_peaks(zz_d3*-1, height=0.03, prominence=0.02)\n",
+ "\n",
+ " # # # Filter everything landward of the previous toe position, then take the first (most landward) peak\n",
+ " # # mask = xx[peaks_toe_d3] > x_toe\n",
+ " # # peaks_toe_d3 = peaks_toe_d3[mask]\n",
+ "\n",
+ " # # if peaks_toe_d3.size != 0:\n",
+ " # # print('Adjusting toe position based on d3')\n",
+ " # # x_toe = xx[peaks_toe_d3[0]]\n",
+ " # # z_toe = zz[peaks_toe_d3[0]]\n",
+ "\n",
+ " # # # Move toe forward to based on the third derivative of elevation\n",
+ " # # print('Adjusting toe position based on d3')\n",
+ " # # mask = (zz_d3 > -0.0008) & (xx > x_toe) & (np.r_[np.diff(zz_d3)[0],np.diff(zz_d3)] > 0)\n",
+ " # # x_toe = xx[mask][1]\n",
+ " # # z_toe = zz[mask][1]\n",
+ "\n",
+ " # except:\n",
+ " # x_toe = np.nan\n",
+ " # z_toe = np.nan\n",
+ " # print('No toe found')\n",
+ "\n",
+ " \n",
+ " else:\n",
+ " # Take crest as location with maximum elevation\n",
+ " i_crest = np.argmax(zz)\n",
+ " x_crest = xx[i_crest]\n",
+ " z_crest = zz[i_crest]\n",
+ " x_potential_crests = np.nan\n",
+ " z_potential_crests = np.nan\n",
+ " print('No crest found, taking maximum elevation as crest')\n",
+ " \n",
+ " x_toe = np.nan\n",
+ " z_toe = np.nan\n",
+ " x_potential_toes=np.nan\n",
+ " z_potential_toes=np.nan\n",
+ " \n",
+ " # Check if toe is necessary. If slope of the dune face is similar to the median slope seaward of the dune\n",
+ " # toe, let's remove the dune toe\n",
+ " try:\n",
+ " if np.isnan(x_toe) == False:\n",
+ " dune_slope =(z_crest - z_toe) / (x_crest - x_toe)\n",
+ " median_foreshore_slope = np.median(zz_d1[xx > x_toe])\n",
+ " std_foreshore_slope = np.std(zz_d1[xx>x_toe])\n",
+ " print('foreshore_std:{:.4f}'.format(std_foreshore_slope))\n",
+ " print('foreshore_med_slope:{:.4f}'.format(median_foreshore_slope))\n",
+ " print('dune_slope:{:.4f}'.format(dune_slope))\n",
+ " if abs(dune_slope - median_foreshore_slope) < 0.075 and std_foreshore_slope <0.025:\n",
+ " x_toe = np.nan\n",
+ " z_toe = np.nan\n",
+ " except:\n",
+ " pass\n",
+ " \n",
+ " return xx,zz, zz_d1,zz_d2,zz_d3,x_crest,z_crest, x_toe,z_toe, x_potential_crests,z_potential_crests, x_potential_toes,z_potential_toes \n",
+ " \n",
+ " \n",
+ "def plot_profile(site, x,z, xx,zz, zz_d1,zz_d2,zz_d3,x_crest,z_crest, x_toe,z_toe, x_potential_crests,z_potential_crests, x_potential_toes,z_potential_toes):\n",
+ " plt.figure(figsize=(10,12))\n",
+ " plt.subplot(411)\n",
+ " plt.plot(x, z, label='raw')\n",
+ " plt.plot(xx,zz,label='interpolated')\n",
+ " plt.plot(x_potential_crests,z_potential_crests,'rv',markersize=10,fillstyle='none',label='Dune crest (potential)')\n",
+ " plt.plot(x_potential_toes,z_potential_toes,'r^',markersize=10,fillstyle='none',label='Dune toe (potential)')\n",
+ " plt.plot(x_crest,z_crest,'rv',markersize=10,label='Dune crest (x={:.2f} m, z={:.2f} m)'.format(x_crest,z_crest))\n",
+ " plt.plot(x_toe,z_toe,'r^',markersize=10,label='Dune toe (x={:.2f} m, z={:.2f} m)'.format(x_toe,z_toe))\n",
+ " plt.title('{}: elevations'.format(site))\n",
+ " plt.legend(loc='best')\n",
+ "\n",
+ " plt.subplot(412)\n",
+ " d1 = np.diff(zz) / np.diff(xx)\n",
+ " plt.plot(xx, zz_d1)\n",
+ " plt.axvline(x_crest,color='red', label='Dune crest')\n",
+ " plt.axvline(x_toe,color='red', label='Dune toe')\n",
+ " # plt.ylim([-0.2,0.2])\n",
+ " plt.title('first derivative - slope')\n",
+ "\n",
+ " plt.subplot(413)\n",
+ " d2 = np.diff(d1) / np.diff(xx[1:])\n",
+ " plt.plot(xx, zz_d2)\n",
+ " plt.axvline(x_crest,color='red', label='Dune crest')\n",
+ " plt.axvline(x_toe,color='red', label='Dune toe')\n",
+ " plt.title('second derivative - change in slope')\n",
+ "# plt.ylim([-0.025,0.025])\n",
+ "\n",
+ " plt.subplot(414)\n",
+ " plt.plot(xx, zz_d3)\n",
+ " plt.axvline(x_crest,color='red', label='Dune crest')\n",
+ " plt.axvline(x_toe,color='red', label='Dune toe')\n",
+ " plt.title('third derivative')\n",
+ "# plt.ylim([-0.0025,0.0025])\n",
+ "\n",
+ " plt.tight_layout()\n",
+ " plt.show()\n",
+ "\n",
+ "# xx,zz, x_crest,z_crest, x_toe,z_toe, x_potential_crests,z_potential_crests, x_potential_toes,z_potential_toes = find_crest_and_toes(x,z,x_knots)\n",
+ "\n",
+ "# plot_profile(site, x,z, xx,zz, x_crest,z_crest, x_toe,z_toe, x_potential_crests,z_potential_crests, x_potential_toes,z_potential_toes)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "code_folding": []
+ },
+ "outputs": [],
+ "source": [
+ "def get_crests_and_toes(site, profile_type, df_profiles):\n",
+ " x, z = get_profile_data(site, profile_type, df_profiles)\n",
+ " x_knots, z_knots, best_s = simplify_profile(x, z, site)\n",
+ " x_knots, z_knots = simplify_segments_with_same_slopes(x_knots, x, z, site, best_s)\n",
+ "# xs, zs = get_x_z_from_knots(x_knots, z_knots)\n",
+ " xx,zz, zz_d1,zz_d2,zz_d3,x_crest,z_crest, x_toe,z_toe, x_potential_crests,z_potential_crests, x_potential_toes,z_potential_toes = find_crest_and_toes(x,z,x_knots,best_s)\n",
+ "\n",
+ " plot_profile(site, x,z, xx,zz, zz_d1,zz_d2,zz_d3,x_crest,z_crest, x_toe,z_toe, x_potential_crests,z_potential_crests, x_potential_toes,z_potential_toes)\n",
+ "\n",
+ " \n",
+ "# site = 'WAMBE0010'\n",
+ "# site = 'NINEMs0048'\n",
+ "# site = 'NAMB0013'\n",
+ "# site = 'AVOCAn0009'\n",
+ "# site = 'GRANTSs0014'\n",
+ "site = 'NARRA0001'\n",
+ "\n",
+ "import random\n",
+ "site = random.sample(df_profiles.index.get_level_values('site_id').unique().tolist(), 1)[0]\n",
+ "\n",
+ "print(site)\n",
+ "# site='NSHORE_s0014'\n",
+ "get_crests_and_toes(site,'prestorm', df_profiles)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Find berms \n",
+ "for x_knot1, x_knot2, in zip(x_knots[0:-2], x_knots[1:-1]):\n",
+ " \n",
+ " # Berms are only located seaward of the dune toe (but sometimes dune toe is undefined, so use dune crest)\n",
+ " if x_knot1 < x_crest:\n",
+ " continue\n",
+ " \n",
+ " # Get slope of segment\n",
+ " x_seg, z_seg = xz(x_knot1, x_knot2, x, z)\n",
+ " slope = get_slope(x_seg, z_seg)\n",
+ " z_mean = np.mean(z_seg)\n",
+ " width = x_knot2 - x_knot1\n",
+ " \n",
+ " if slope > -0.01:\n",
+ " print('{:.1f}m wide berm at x={:.1f}m to x={:.1f}m at z={:.1f}m'.format(width, x_knot1, x_knot2, z_mean))\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "hide_input": true
+ },
+ "outputs": [],
+ "source": [
+ "# def reject_outliers(data, m = 5):\n",
+ "# d = np.abs(data - np.median(data))\n",
+ "# mdev = np.median(d)\n",
+ "# s = d/mdev if mdev else 0.\n",
+ "# return ma.masked_where(s > m, data)\n",
+ "\n",
+ "# def hampel(vals_orig, k=7, t0=3):\n",
+ "# '''\n",
+ "# vals: pandas series of values from which to remove outliers\n",
+ "# k: size of window (including the sample; 7 is equal to 3 on either side of value)\n",
+ "# '''\n",
+ "# #Make copy so original not edited\n",
+ "# vals_orig = pd.Series(vals_orig)\n",
+ "# vals=vals_orig.copy() \n",
+ "# #Hampel Filter\n",
+ "# L= 1.4826\n",
+ "# rolling_median=vals.rolling(k).median()\n",
+ "# difference=np.abs(rolling_median-vals)\n",
+ "# median_abs_deviation=difference.rolling(k).median()\n",
+ "# threshold= t0 *L * median_abs_deviation\n",
+ "# outlier_idx=difference>threshold\n",
+ "# vals[outlier_idx]=np.nan\n",
+ "# return(vals.tolist())\n",
+ "\n",
+ "# # Remove segements where slopes are too high, indicative of a structure\n",
+ "# segments = [xz(x1, x2,x,z) for (x1, x2) in pairwise(x_knots_simplified)]\n",
+ "# slopes = np.array([get_slope(x1,x2) for x1,x2 in segments])\n",
+ "# mask = reject_outliers(np.array(slopes))\n",
+ "# x_knots_filtered = x_knots_simplified[np.append(True,~mask.mask)]\n",
+ "# z_knots_filtered = [z_val for x_val, z_val in zip(x,z) if x_val in x_knots_filtered]\n",
+ "\n",
+ "\n",
+ "\n",
+ "# # Hampel filter based on z values\n",
+ "# mask = ma.masked_invalid(hampel(z_knots_filtered))\n",
+ "# x_knots_filtered = x_knots_filtered[~mask.mask]\n",
+ "# z_knots_filtered = [z_val for x_val, z_val in zip(x,z) if x_val in x_knots_filtered]\n",
+ "\n",
+ "\n",
+ "\n",
+ "# # plt.figure(figsize=(10,5))\n",
+ "# # plt.plot(x_knots_simplified, np.append(slopes[0],slopes), '.-')\n",
+ "# # plt.plot(x_knots_simplified[np.append(True,~mask.mask)], np.append(slopes[~mask.mask][0], slopes[~mask.mask]), '.-')\n",
+ "# # # plt.plot(xs, zs)\n",
+ "# # # plt.plot(x_knots_filtered, z_knots_filtered,'.',markersize=15)\n",
+ "# # plt.show()\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "# plt.figure(figsize=(10,5))\n",
+ "# plt.plot(x, z, '.-')\n",
+ "# plt.plot(xs, zs)\n",
+ "# plt.plot(x_knots_filtered, z_knots_filtered,'.',markersize=15)\n",
+ "# plt.show()\n",
+ "# z_knots_filtered"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Find dune crests"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "code_folding": [
+ 18
+ ]
+ },
+ "outputs": [],
+ "source": [
+ "from scipy.signal import find_peaks\n",
+ "\n",
+ "\n",
+ "def crest_by_deriv_2(z):\n",
+ " \"\"\"\n",
+ " Try get crest elevation by taking the difference in 2nd derivative of elevation.\n",
+ " \"\"\"\n",
+ "\n",
+ " z = savgol_filter(z, 15, 3, mode='nearest')\n",
+ " deriv_2_diff = np.diff(np.gradient(z)) * -1\n",
+ "\n",
+ " # Ensure same size arrays for plotting\n",
+ " deriv_2_diff = np.insert(deriv_2_diff, 0, deriv_2_diff[0])\n",
+ " med = np.median(deriv_2_diff)\n",
+ " std = np.std(deriv_2_diff)\n",
+ " peaks, peak_props = find_peaks(deriv_2_diff, height=med+std*2, distance=10)\n",
+ " return peaks, peak_props, deriv_2_diff\n",
+ "\n",
+ "\n",
+ "def crest_by_elevation_peaks(z, min_dune_prominence=1.0):\n",
+ " # Try find peaks in elevation\n",
+ " peaks, peak_props = find_peaks(z, distance=10, prominence=min_dune_prominence)\n",
+ " return peaks, peak_props\n",
+ "\n",
+ "\n",
+ "def get_dune_crest(x, z, xs,zs, x_knots, z_knots, site):\n",
+ " \n",
+ " peaks, peak_props = crest_by_elevation_peaks(z)\n",
+ " \n",
+ " if peaks.size != 0:\n",
+ " # Choose crest by most landward peak\n",
+ " x_crest = x[peaks[-1]]\n",
+ " z_crest = z[peaks[-1]]\n",
+ " \n",
+ " # If no peaks in elevation are found, find by maximum second derivative\n",
+ " else:\n",
+ " peaks, peak_props, deriv_2_diff = crest_by_deriv_2(z)\n",
+ " \n",
+ " plt.title(\n",
+ " '{}: Difference of 2nd derivative in elevation'.format(site))\n",
+ " plt.xlabel('Distance (m)')\n",
+ " plt.ylabel('Diff(2nd Derivative Elevation)')\n",
+ " plt.plot(x, deriv_2_diff)\n",
+ "\n",
+ " \n",
+ " if peaks.size!= 0:\n",
+ "\n",
+ " # Choose crest by highest peak in diff of 2nd derivative\n",
+ " i_best = np.argmax(peak_props['peak_heights'])\n",
+ " x_crest = x[peaks[i_best]]\n",
+ " z_crest = z[peaks[i_best]]\n",
+ " plt.plot(\n",
+ " x[peaks],\n",
+ " deriv_2_diff[peaks],\n",
+ " 'o',\n",
+ " markersize=20,\n",
+ " fillstyle='none')\n",
+ " plt.show() \n",
+ " \n",
+ " else:\n",
+ " plt.show() \n",
+ " # If no peaks in diff of 2nd derivative are found, take landward most point\n",
+ " if peaks.size == 0:\n",
+ " x_crest = x_knots[0]\n",
+ " z_crest = z_knots[0]\n",
+ "\n",
+ " # Move crest to closest knot\n",
+ " idx_crest = min(range(len(x_knots)), key=lambda i: abs(x_knots[i]-x_crest))\n",
+ " x_crest = x_knots[idx_crest]\n",
+ " z_crest = z_knots[idx_crest]\n",
+ " \n",
+ " # Plot for checking\n",
+ " plt.title('{}: Find dune crest by peak in diff 2nd deriv'.format(site))\n",
+ " plt.xlabel('Distance (m)')\n",
+ " plt.ylabel('Elevation (m AHD)')\n",
+ " plt.plot(x, z, 'k.-', label='Raw profile')\n",
+ " plt.plot(\n",
+ " xs,\n",
+ " zs,\n",
+ " 'r-',\n",
+ " label='Interpolated profile (s={:.2f})'.format(best_s))\n",
+ " plt.plot(\n",
+ " x_knots,\n",
+ " z_knots,\n",
+ " 'ro',\n",
+ " markersize=8,\n",
+ " markeredgewidth=1.5,\n",
+ " markeredgecolor='orange',\n",
+ " label='Interpolated knots (n={})'.format(len(x_knots)))\n",
+ " plt.plot(\n",
+ " x_crest,\n",
+ " z_crest,\n",
+ " 'bv',\n",
+ " markersize=10,\n",
+ " label='Dune crest (selected) (x={:.1f}m,z={:.1f}m)'.format(x_crest,z_crest))\n",
+ " plt.plot(\n",
+ " x[peaks],\n",
+ " z[peaks],\n",
+ " 'o',\n",
+ " markersize=10,\n",
+ " fillstyle='none',\n",
+ " label='Dune crest (potential)')\n",
+ "\n",
+ " plt.legend(loc='best')\n",
+ " plt.show()\n",
+ " \n",
+ " return x_crest, z_crest\n",
+ " \n",
+ "x_crest, z_crest = get_dune_crest(x, z, xs,zs, x_knots, z_knots, site)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Get toe by second derivative\n",
+ "def toe_by_deriv_2(z):\n",
+ " \"\"\"\n",
+ " Try get crest elevation by taking the difference in 2nd derivative of elevation.\n",
+ " \"\"\"\n",
+ "\n",
+ " z = savgol_filter(z,11, 3, mode='nearest')\n",
+ " deriv_2_diff = np.diff(np.gradient(z))\n",
+ "\n",
+ " # Ensure same size arrays for plotting\n",
+ " deriv_2_diff = np.insert(deriv_2_diff, 0, deriv_2_diff[0])\n",
+ " med = np.median(deriv_2_diff)\n",
+ " std = np.std(deriv_2_diff)\n",
+ " peaks, peak_props = find_peaks(deriv_2_diff, height=max(0.01,med+std*3), distance=10)\n",
+ " return peaks, peak_props, deriv_2_diff\n",
+ "\n",
+ "def get_dune_toe(x, z, xs,zs, x_crest,z_crest,x_knots, z_knots, site):\n",
+ " peaks, peak_props, deriv_2_diff = toe_by_deriv_2(z)\n",
+ "\n",
+ " plt.title('{}: Difference of 2nd derivative in elevation'.format(site))\n",
+ " plt.xlabel('Distance (m)')\n",
+ " plt.ylabel('Diff(2nd Derivative Elevation)')\n",
+ " plt.plot(x, deriv_2_diff)\n",
+ " \n",
+ " if peaks.size!= 0:\n",
+ " \n",
+ " # Remove peaks which are behind the crest\n",
+ " # TODO What happens if all peaks are removed?\n",
+ " mask = ma.masked_where(x[peaks] <= x_crest, x[peaks])\n",
+ " peaks = peaks[~mask.mask]\n",
+ "\n",
+ " if peaks.size!= 0:\n",
+ " # Choose toe by highest peak in diff of 2nd derivative\n",
+ " i_best = np.argmax(peak_props['peak_heights'])\n",
+ " x_toe = x[peaks[i_best]][0]\n",
+ " z_toe = z[peaks[i_best]][0]\n",
+ "# # Move crest to closest knot\n",
+ "# idx_toe = min(range(len(x_knots)), key=lambda i: abs(x_knots[i]-x_toe))\n",
+ "# x_toe = x_knots[idx_toe]\n",
+ "# z_toe = z_knots[idx_toe]\n",
+ "\n",
+ " plt.plot(\n",
+ " x[peaks],\n",
+ " deriv_2_diff[peaks],\n",
+ " 'o',\n",
+ " markersize=20,\n",
+ " fillstyle='none')\n",
+ " plt.show()\n",
+ " else:\n",
+ " x_toe = np.nan\n",
+ " z_toe = np.nan\n",
+ " plt.show()\n",
+ "\n",
+ " # Plot for checking\n",
+ " plt.title('{}: Find dune crest by peak in diff 2nd deriv'.format(site))\n",
+ " plt.xlabel('Distance (m)')\n",
+ " plt.ylabel('Elevation (m AHD)')\n",
+ " plt.plot(x, z, 'k.-', label='Raw profile')\n",
+ " plt.plot(\n",
+ " xs,\n",
+ " zs,\n",
+ " 'r-',\n",
+ " label='Interpolated profile (s={:.2f})'.format(best_s))\n",
+ " plt.plot(\n",
+ " x_knots,\n",
+ " z_knots,\n",
+ " 'ro',\n",
+ " markersize=8,\n",
+ " markeredgewidth=1.5,\n",
+ " markeredgecolor='orange',\n",
+ " label='Interpolated knots (n={})'.format(len(x_knots)))\n",
+ " plt.plot(\n",
+ " x_crest,\n",
+ " z_crest,\n",
+ " 'bv',\n",
+ " markersize=10,\n",
+ " label='Dune crest(x={:.1f} m,z={:.1f} m)'.format(x_crest,z_crest))\n",
+ " plt.plot(\n",
+ " x_toe,\n",
+ " z_toe,\n",
+ " 'b^',\n",
+ " markersize=10,\n",
+ " label='Dune toe (x={:.1f} m,z={:.1f} m)'.format(x_toe,z_toe))\n",
+ "\n",
+ " plt.legend(loc='best')\n",
+ " plt.show()\n",
+ " return x_toe, z_toe\n",
+ "x_toe, z_toe = get_dune_toe(x, z, xs,zs, x_crest,z_crest,x_knots, z_knots, site)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def find_dune_crest_and_toe(site, profile_type, df_profiles):\n",
+ " x, z = get_profile_data(site, profile_type, df_profiles)\n",
+ " x_knots, z_knots = simplify_profile(x, z, site)\n",
+ " x_knots, z_knots = simplify_segments_with_same_slopes(x_knots, x, z, site)\n",
+ " xs, zs = get_x_z_from_knots(x_knots, z_knots)\n",
+ " x_crest, z_crest = get_dune_crest(x, z, xs,zs, x_knots, z_knots, site)\n",
+ " x_toe, z_toe = get_dune_toe(x, z, xs,zs, x_crest,z_crest,x_knots, z_knots, site)\n",
+ " \n",
+ "find_dune_crest_and_toe('ENTRA0004', 'prestorm', df_profiles)\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "hide_input": false,
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.6"
+ },
+ "toc": {
+ "base_numbering": 1,
+ "nav_menu": {},
+ "number_sections": true,
+ "sideBar": true,
+ "skip_h1_title": false,
+ "title_cell": "Table of Contents",
+ "title_sidebar": "Contents",
+ "toc_cell": false,
+ "toc_position": {},
+ "toc_section_display": true,
+ "toc_window_display": false
+ },
+ "varInspector": {
+ "cols": {
+ "lenName": 16,
+ "lenType": 16,
+ "lenVar": 40
+ },
+ "kernels_config": {
+ "python": {
+ "delete_cmd_postfix": "",
+ "delete_cmd_prefix": "del ",
+ "library": "var_list.py",
+ "varRefreshCmd": "print(var_dic_list())"
+ },
+ "r": {
+ "delete_cmd_postfix": ") ",
+ "delete_cmd_prefix": "rm(",
+ "library": "var_list.r",
+ "varRefreshCmd": "cat(var_dic_list()) "
+ }
+ },
+ "types_to_exclude": [
+ "module",
+ "function",
+ "builtin_function_or_method",
+ "instance",
+ "_Feature"
+ ],
+ "window_display": false
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/notebooks/05_twl_exceedence.ipynb b/notebooks/05_twl_exceedence.ipynb
new file mode 100644
index 0000000..848a527
--- /dev/null
+++ b/notebooks/05_twl_exceedence.ipynb
@@ -0,0 +1,362 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# TWL Exceedance"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Setup notebook"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Enable autoreloading of our modules. \n",
+ "# Most of the code will be located in the /src/ folder, \n",
+ "# and then called from the notebook.\n",
+ "%matplotlib inline\n",
+ "%reload_ext autoreload\n",
+ "%autoreload"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from IPython.core.debugger import set_trace\n",
+ "\n",
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "import os\n",
+ "import decimal\n",
+ "import plotly\n",
+ "import plotly.graph_objs as go\n",
+ "import plotly.plotly as py\n",
+ "import plotly.tools as tls\n",
+ "import plotly.figure_factory as ff\n",
+ "from plotly import tools\n",
+ "import plotly.io as pio\n",
+ "from scipy import stats\n",
+ "import math\n",
+ "import matplotlib\n",
+ "from matplotlib import cm\n",
+ "import colorlover as cl\n",
+ "\n",
+ "from ipywidgets import widgets, Output\n",
+ "from IPython.display import display, clear_output, Image, HTML\n",
+ "\n",
+ "from sklearn.metrics import confusion_matrix"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Import data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def df_from_csv(csv, index_col, data_folder='../data/interim'):\n",
+ " print('Importing {}'.format(csv))\n",
+ " return pd.read_csv(os.path.join(data_folder,csv), index_col=index_col)\n",
+ "\n",
+ "df_waves = df_from_csv('waves.csv', index_col=[0, 1])\n",
+ "df_tides = df_from_csv('tides.csv', index_col=[0, 1])\n",
+ "df_profiles = df_from_csv('profiles.csv', index_col=[0, 1, 2])\n",
+ "df_sites = df_from_csv('sites.csv', index_col=[0])\n",
+ "df_profile_features_crest_toes = df_from_csv('profile_features_crest_toes.csv', index_col=[0,1])\n",
+ "\n",
+ "# Note that the forecasted data sets should be in the same order for impacts and twls\n",
+ "impacts = {\n",
+ " 'forecasted': {\n",
+ " 'foreshore_slope_sto06': df_from_csv('impacts_forecasted_foreshore_slope_sto06.csv', index_col=[0]),\n",
+ " 'mean_slope_sto06': df_from_csv('impacts_forecasted_mean_slope_sto06.csv', index_col=[0]),\n",
+ " },\n",
+ " 'observed': df_from_csv('impacts_observed.csv', index_col=[0])\n",
+ " }\n",
+ "\n",
+ "\n",
+ "twls = {\n",
+ " 'forecasted': {\n",
+ " 'foreshore_slope_sto06': df_from_csv('twl_foreshore_slope_sto06.csv', index_col=[0, 1]),\n",
+ " 'mean_slope_sto06':df_from_csv('twl_mean_slope_sto06.csv', index_col=[0, 1]),\n",
+ " }\n",
+ "}\n",
+ "print('Done!')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Calculate vertical distribution of wave count\n",
+ "For each site, calculate how many waves reached a certain elevation (store as a binned histogram)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Helper functions\n",
+ "def find_nearest(array, value):\n",
+ " array = np.asarray(array)\n",
+ " idx = np.nanargmin((np.abs(array - value)))\n",
+ " return array[idx], idx"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df_profile_features_crest_toes.loc[(site_id,'prestorm'),'dune_toe_z']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "data = []\n",
+ "for site_id, df_site_twl in twls['forecasted']['mean_slope_sto06'].groupby('site_id'):\n",
+ " \n",
+ " twl_eles_per_wave = []\n",
+ " \n",
+ " # Iterate through each timestamp and calculate the number of waves at each interavl.\n",
+ " # THIS LOOP IS SLOW\n",
+ " for row in df_site_twl.itertuples():\n",
+ " \n",
+ " distribution = stats.norm(loc=row.tide+row.setup, scale=row.S_total/4) # CHECK\n",
+ "\n",
+ " # Total number of waves we expect in this period\n",
+ " n_waves = int(3600 / row.Tp) # Check that we have 1 hour\n",
+ " \n",
+ " # Get z elevation of each wave twl in this hour and append to list\n",
+ " twl_eles_per_wave.extend([distribution.ppf(1-x/n_waves) for x in range(1,n_waves+1)])\n",
+ " \n",
+ " # Remove nans and infs # CHECK WHY INF\n",
+ " twl_eles_per_wave = list(np.asarray(twl_eles_per_wave)[np.isfinite(twl_eles_per_wave)])\n",
+ " \n",
+ " # Sort wave twl z elevations in descending list\n",
+ " twl_eles_per_wave.sort(reverse=True) \n",
+ " \n",
+ " # Get index of closest value of dune toe. This is the number of waves that exceeded the the dune toe\n",
+ " try:\n",
+ " _, idx = find_nearest(twl_eles_per_wave, dune_toe_z)\n",
+ " except:\n",
+ " continue\n",
+ " \n",
+ " # Get forecasted and observed impacts\n",
+ " forecasted_regime = impacts['forecasted']['mean_slope_sto06'].loc[site_id,'storm_regime']\n",
+ " observed_regime = impacts['observed'].loc[site_id,'storm_regime']\n",
+ " \n",
+ " counts, bin_edges = np.histogram(twl_eles_per_wave, bins=100) \n",
+ " \n",
+ " data.append({\n",
+ " 'site_id': site_id,\n",
+ " 'forecasted_regime': forecasted_regime,\n",
+ " 'observed_regime': observed_regime,\n",
+ " 'n_waves_exceeding_dune_toe': idx,\n",
+ " 'n_waves': [x for x in range(0,500,1)],\n",
+ " 'truncated_twl_levels': [twl_eles_per_wave[x] for x in range(0,500,1)],\n",
+ " 'truncated_dune_toe_z': df_profile_features_crest_toes.loc[(site_id,'prestorm'),'dune_toe_z'],\n",
+ " 'full_counts': counts,\n",
+ " 'full_bin_edges': bin_edges,\n",
+ " })\n",
+ " \n",
+ " print('Done {}'.format(site_id))\n",
+ "\n",
+ "data_twl = data\n",
+ "# df = pd.DataFrame(data)\n",
+ "# df = df.set_index('site_id')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "counts, bin_edges = np.histogram (data_twl[0]['twl_levels'], bins=50) "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "list(np.asarray(twl_eles_per_wave)[~np.isfinite(twl_eles_per_wave)])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig = tools.make_subplots(\n",
+ " rows=2,\n",
+ " cols=2,\n",
+ " specs=[[{}, {}], [{}, {}]],\n",
+ " subplot_titles=('Swash/Swash', 'Swash/Collision', \n",
+ " 'Collision/Swash', 'Collision/Collision'),\n",
+ " shared_xaxes=True, shared_yaxes=True,)\n",
+ "\n",
+ "data = []\n",
+ "for site in data_twl:\n",
+ " if site['forecasted_regime'] == 'swash' and site[\n",
+ " 'observed_regime'] == 'swash':\n",
+ " x_col = 1\n",
+ " y_col = 1\n",
+ " elif site['forecasted_regime'] == 'collision' and site[\n",
+ " 'observed_regime'] == 'collision':\n",
+ " x_col = 2\n",
+ " y_col = 2\n",
+ " elif site['forecasted_regime'] == 'swash' and site[\n",
+ " 'observed_regime'] == 'collision':\n",
+ " x_col = 2\n",
+ " y_col = 1\n",
+ " elif site['forecasted_regime'] == 'collision' and site[\n",
+ " 'observed_regime'] == 'swash':\n",
+ " x_col = 1\n",
+ " y_col = 2\n",
+ " else:\n",
+ " continue\n",
+ "\n",
+ " fig.append_trace(\n",
+ " go.Scattergl(\n",
+ " x=[x - site['dune_toe_z'] for x in site['twl_levels']],\n",
+ " y=site['n_waves'],\n",
+ " name=site['site_id'],\n",
+ " line = dict(\n",
+ " color = ('rgba(22, 22, 22, 0.2)'),\n",
+ " width = 0.5,)),\n",
+ " x_col,\n",
+ " y_col)\n",
+ "\n",
+ "# layout = go.Layout(\n",
+ "# xaxis=dict(domain=[0, 0.45]),\n",
+ "# yaxis=dict(\n",
+ "# domain=[0, 0.45],\n",
+ "# type='log',\n",
+ "# ),\n",
+ "# xaxis2=dict(domain=[0.55, 1]),\n",
+ "# xaxis4=dict(domain=[0.55, 1], anchor='y4'),\n",
+ "# yaxis3=dict(\n",
+ "# domain=[0.55, 1],\n",
+ "# type='log',\n",
+ "# ),\n",
+ "# yaxis4=dict(\n",
+ "# domain=[0.55, 1],\n",
+ "# anchor='x4',\n",
+ "# type='log',\n",
+ "# ))\n",
+ "\n",
+ "fig['layout'].update(showlegend=False, title='Specs with Subplot Title',height=800,)\n",
+ "\n",
+ "for ax in ['yaxis','yaxis2']:\n",
+ "# fig['layout'][ax]['type']='log'\n",
+ " fig['layout'][ax]['range']= [0,100]\n",
+ "\n",
+ "for ax in ['xaxis', 'xaxis2']:\n",
+ " fig['layout'][ax]['range']= [-1,1]\n",
+ "\n",
+ "go.FigureWidget(fig)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig['layout']['yaxis']"
+ ]
+ }
+ ],
+ "metadata": {
+ "hide_input": false,
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.6"
+ },
+ "toc": {
+ "base_numbering": 1,
+ "nav_menu": {},
+ "number_sections": true,
+ "sideBar": true,
+ "skip_h1_title": false,
+ "title_cell": "Table of Contents",
+ "title_sidebar": "Contents",
+ "toc_cell": false,
+ "toc_position": {},
+ "toc_section_display": true,
+ "toc_window_display": false
+ },
+ "varInspector": {
+ "cols": {
+ "lenName": 16,
+ "lenType": 16,
+ "lenVar": 40
+ },
+ "kernels_config": {
+ "python": {
+ "delete_cmd_postfix": "",
+ "delete_cmd_prefix": "del ",
+ "library": "var_list.py",
+ "varRefreshCmd": "print(var_dic_list())"
+ },
+ "r": {
+ "delete_cmd_postfix": ") ",
+ "delete_cmd_prefix": "rm(",
+ "library": "var_list.r",
+ "varRefreshCmd": "cat(var_dic_list()) "
+ }
+ },
+ "types_to_exclude": [
+ "module",
+ "function",
+ "builtin_function_or_method",
+ "instance",
+ "_Feature"
+ ],
+ "window_display": false
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/notebooks/06_change_in_slope.ipynb b/notebooks/06_change_in_slope.ipynb
new file mode 100644
index 0000000..2caa57d
--- /dev/null
+++ b/notebooks/06_change_in_slope.ipynb
@@ -0,0 +1,356 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Check change in mean slope\n",
+ "- Check the effect of changes in prestorm and poststorm mean slope.\n",
+ "- If there is a large berm, the prestorm mean slope (between dune toe and MHW) could be too small, and underpredict wave runup and TWL.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Setup notebook"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Enable autoreloading of our modules. \n",
+ "# Most of the code will be located in the /src/ folder, \n",
+ "# and then called from the notebook.\n",
+ "%matplotlib inline\n",
+ "%reload_ext autoreload\n",
+ "%autoreload"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from IPython.core.debugger import set_trace\n",
+ "\n",
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "import os\n",
+ "\n",
+ "import plotly\n",
+ "import plotly.graph_objs as go\n",
+ "import plotly.plotly as py\n",
+ "import plotly.tools as tools\n",
+ "import plotly.figure_factory as ff\n",
+ "import plotly.io as pio\n",
+ "\n",
+ "import itertools\n",
+ "\n",
+ "import matplotlib\n",
+ "from matplotlib import cm\n",
+ "import colorlover as cl\n",
+ "\n",
+ "from ipywidgets import widgets, Output\n",
+ "from IPython.display import display, clear_output, Image, HTML\n",
+ "\n",
+ "from sklearn.metrics import confusion_matrix"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Import data\n",
+ "Import our data into pandas Dataframes for the analysis. Data files are `.csv` files which are stored in the `./data/interim/` folder."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def df_from_csv(csv, index_col, data_folder='../data/interim'):\n",
+ " print('Importing {}'.format(csv))\n",
+ " return pd.read_csv(os.path.join(data_folder,csv), index_col=index_col)\n",
+ "\n",
+ "df_waves = df_from_csv('waves.csv', index_col=[0, 1])\n",
+ "df_tides = df_from_csv('tides.csv', index_col=[0, 1])\n",
+ "df_profiles = df_from_csv('profiles.csv', index_col=[0, 1, 2])\n",
+ "df_sites = df_from_csv('sites.csv', index_col=[0])\n",
+ "df_profile_features_crest_toes = df_from_csv('profile_features_crest_toes.csv', index_col=[0,1])\n",
+ "\n",
+ "# Note that the forecasted data sets should be in the same order for impacts and twls\n",
+ "impacts = {\n",
+ " 'forecasted': {\n",
+ " 'foreshore_slope_sto06': df_from_csv('impacts_forecasted_foreshore_slope_sto06.csv', index_col=[0]),\n",
+ " 'mean_slope_sto06': df_from_csv('impacts_forecasted_mean_slope_sto06.csv', index_col=[0]),\n",
+ " },\n",
+ " 'observed': df_from_csv('impacts_observed.csv', index_col=[0])\n",
+ " }\n",
+ "\n",
+ "\n",
+ "twls = {\n",
+ " 'forecasted': {\n",
+ " 'foreshore_slope_sto06': df_from_csv('twl_foreshore_slope_sto06.csv', index_col=[0, 1]),\n",
+ " 'mean_slope_sto06':df_from_csv('twl_mean_slope_sto06.csv', index_col=[0, 1]),\n",
+ " }\n",
+ "}\n",
+ "print('Done!')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Plot prestorm vs poststorm mean slopes\n",
+ "Prestorm slopes have already been calculated as part of the TWL forecasting, however we'll need to extract the poststorm mean slopes from our profiles at each site."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Prestorm slopes are easy as we have already calculated this as part of the \n",
+ "df_slopes_prestorm = twls['forecasted']['mean_slope_sto06'].groupby('site_id').head(1).reset_index().set_index(['site_id']).beta.to_frame()\n",
+ "\n",
+ "# Get x and z at mhw (z=0.7m) for each site\n",
+ "z_mhw = 0.7\n",
+ "mhw_poststorm = []\n",
+ "for site, df in df_profiles.xs('poststorm', level='profile_type').groupby('site_id'):\n",
+ " df = df.dropna(subset=['z'])\n",
+ " df = df.iloc[(df['z']-z_mhw).abs().argsort().head(1)].reset_index()\n",
+ " df = df.iloc[0]\n",
+ " mhw_poststorm.append({\n",
+ " 'site_id': df.site_id,\n",
+ " 'x_mhw': df.x,\n",
+ " 'z_mhw': df.z\n",
+ " })\n",
+ "# break\n",
+ "df_mhw_poststorm = pd.DataFrame(mhw_poststorm)\n",
+ "df_mhw_poststorm = df_mhw_poststorm.set_index('site_id')\n",
+ "\n",
+ "# Get x and z at poststorm dune toe for each site\n",
+ "df_dune_toe_poststorm = df_profile_features_crest_toes.xs('poststorm', level='profile_type')[['dune_toe_x','dune_toe_z']]\n",
+ "\n",
+ "# Join df for mhw and dune toe\n",
+ "df = df_mhw_poststorm.join(df_dune_toe_poststorm)\n",
+ "df['beta'] = -(df['dune_toe_z'] - df['z_mhw']) / (df['dune_toe_x'] -df['x_mhw'])\n",
+ "df_slopes_poststorm = df['beta'].to_frame()\n",
+ "\n",
+ "# Count how many nans\n",
+ "print('Number of nans: {}'.format(df_slopes_poststorm.beta.isna().sum()))\n",
+ "\n",
+ "# Display dataframe\n",
+ "print('df_slopes_poststorm:')\n",
+ "df_slopes_poststorm"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now, let's join our post storm slopes, prestorm slopes, observed and forecasted impacts into one data frame to make it easier to plot."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "dfs = [df_slopes_poststorm.rename(columns={'beta':'poststorm_beta'}),\n",
+ " df_slopes_prestorm.rename(columns={'beta':'prestorm_beta'}),\n",
+ " impacts['observed']['storm_regime'].to_frame().rename(columns={'storm_regime': 'observed_regime'}),\n",
+ " impacts['forecasted']['mean_slope_sto06']['storm_regime'].to_frame().rename(columns={'storm_regime': 'forecasted_regime'})\n",
+ " ]\n",
+ "\n",
+ "df = pd.concat(dfs, axis='columns')\n",
+ "df"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df_data.index"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Plot our data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig = tools.make_subplots(\n",
+ " rows=2,\n",
+ " cols=2,\n",
+ " specs=[[{}, {}], [{}, {}]],\n",
+ " subplot_titles=('Swash/Swash', 'Swash/Collision', \n",
+ " 'Collision/Swash', 'Collision/Collision'),\n",
+ " shared_xaxes=True, shared_yaxes=True,)\n",
+ "\n",
+ "\n",
+ "# Loop through combinations of observed/forecasted swash/collision\n",
+ "data = []\n",
+ "for forecasted_regime, observed_regime in itertools.product(['swash','collision'],repeat=2):\n",
+ " \n",
+ " # Get data for this combination \n",
+ " query = 'forecasted_regime==\"{}\" & observed_regime==\"{}\"'.format(forecasted_regime, observed_regime)\n",
+ " df_data = df.query(query)\n",
+ " print(query)\n",
+ " \n",
+ " \n",
+ " # Determine which subplot to plot results in\n",
+ " if forecasted_regime == 'swash' and observed_regime == 'swash':\n",
+ " x_col = 1\n",
+ " y_col = 1\n",
+ " elif forecasted_regime == 'collision' and observed_regime == 'collision':\n",
+ " x_col = 2\n",
+ " y_col = 2\n",
+ " elif forecasted_regime == 'swash' and observed_regime == 'collision':\n",
+ " x_col = 2\n",
+ " y_col = 1\n",
+ " elif forecasted_regime == 'collision' and observed_regime == 'swash':\n",
+ " x_col = 1\n",
+ " y_col = 2\n",
+ " else:\n",
+ " print('something went wrong')\n",
+ " continue\n",
+ "\n",
+ " fig.append_trace(\n",
+ " go.Scatter(\n",
+ " x=df_data.prestorm_beta,\n",
+ " y=df_data.poststorm_beta,\n",
+ " text = df_data.index.tolist(),\n",
+ " hoverinfo = 'text',\n",
+ " mode = 'markers',\n",
+ " line = dict(\n",
+ " color = ('rgba(22, 22, 22, 0.2)'),\n",
+ " width = 0.5,)),\n",
+ " x_col,\n",
+ " y_col)\n",
+ "\n",
+ "# layout = go.Layout(\n",
+ "# xaxis=dict(domain=[0, 0.45]),\n",
+ "# yaxis=dict(\n",
+ "# domain=[0, 0.45],\n",
+ "# type='log',\n",
+ "# ),\n",
+ "# xaxis2=dict(domain=[0.55, 1]),\n",
+ "# xaxis4=dict(domain=[0.55, 1], anchor='y4'),\n",
+ "# yaxis3=dict(\n",
+ "# domain=[0.55, 1],\n",
+ "# type='log',\n",
+ "# ),\n",
+ "# yaxis4=dict(\n",
+ "# domain=[0.55, 1],\n",
+ "# anchor='x4',\n",
+ "# type='log',\n",
+ "# ))\n",
+ "\n",
+ "fig['layout'].update(showlegend=False, title='Specs with Subplot Title',height=800,)\n",
+ "\n",
+ "for ax in ['yaxis','yaxis2']:\n",
+ "# fig['layout'][ax]['type']='log'\n",
+ " fig['layout'][ax]['range']= [0,0.2]\n",
+ "\n",
+ "for ax in ['xaxis', 'xaxis2']:\n",
+ " fig['layout'][ax]['range']= [0,0.2]\n",
+ "\n",
+ "go.FigureWidget(fig)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Looking at the above plot:\n",
+ "- In general, we can see that the prestorm mean slope is flatter than the poststorm mean slope. This can be explained by the presence of prestorm berms, which increase the prestorm mean slope. During the storm, these berms get eroded and decrease the slope.\n",
+ "- **Collision/Collision**: Where we observe and predict collision, we see steeper prestorm slopes. This is to be expected since larger slopes will generate more runup and higher TWLs.\n",
+ "- **Swash/Collision**: Where we predict collision but observe swash, we can see that the prestorm mean slopes >0.1 generate high TWLs. \n",
+ "\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "hide_input": false,
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.6"
+ },
+ "toc": {
+ "base_numbering": 1,
+ "nav_menu": {},
+ "number_sections": true,
+ "sideBar": true,
+ "skip_h1_title": false,
+ "title_cell": "Table of Contents",
+ "title_sidebar": "Contents",
+ "toc_cell": false,
+ "toc_position": {},
+ "toc_section_display": true,
+ "toc_window_display": false
+ },
+ "varInspector": {
+ "cols": {
+ "lenName": 16,
+ "lenType": 16,
+ "lenVar": 40
+ },
+ "kernels_config": {
+ "python": {
+ "delete_cmd_postfix": "",
+ "delete_cmd_prefix": "del ",
+ "library": "var_list.py",
+ "varRefreshCmd": "print(var_dic_list())"
+ },
+ "r": {
+ "delete_cmd_postfix": ") ",
+ "delete_cmd_prefix": "rm(",
+ "library": "var_list.r",
+ "varRefreshCmd": "cat(var_dic_list()) "
+ }
+ },
+ "types_to_exclude": [
+ "module",
+ "function",
+ "builtin_function_or_method",
+ "instance",
+ "_Feature"
+ ],
+ "window_display": false
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}