diff --git a/docs/src/notebooks/eoAPI_Maxar_Hawaii_demo.ipynb b/docs/src/notebooks/eoAPI_Maxar_Hawaii_demo.ipynb index 9627a1c..d3dca4f 100644 --- a/docs/src/notebooks/eoAPI_Maxar_Hawaii_demo.ipynb +++ b/docs/src/notebooks/eoAPI_Maxar_Hawaii_demo.ipynb @@ -49,7 +49,7 @@ }, { "cell_type": "code", - "execution_count": 142, + "execution_count": 1, "id": "9a912d28", "metadata": {}, "outputs": [], @@ -61,7 +61,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "id": "0ed3efb6", "metadata": {}, "outputs": [], @@ -89,7 +89,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "id": "a408f071", "metadata": {}, "outputs": [ @@ -97,7 +97,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Found 24 Collections\n" + "Found 29 Collections\n" ] } ], @@ -109,7 +109,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "1c4b7d1a", "metadata": { "scrolled": false @@ -120,7 +120,7 @@ "output_type": "stream", "text": [ "Collection names:\n", - "['MAXAR_Kahramanmaras_turkey_earthquake_23', 'MAXAR_BayofBengal_Cyclone_Mocha_May_23', 'MAXAR_southafrica_flooding22', 'MAXAR_Emilia_Romagna_Italy_flooding_may23', 'MAXAR_Gambia_flooding_8_11_2022', 'MAXAR_Hurricane_Fiona_9_19_2022', 'MAXAR_Hurricane_Ian_9_26_2022', 'MAXAR_Indonesia_Earthquake22', 'MAXAR_Kalehe_DRC_Flooding_5_8_23', 'MAXAR_Marshall_Fire_21_Update', 'MAXAR_New_Zealand_Flooding22', 'MAXAR_New_Zealand_Flooding23', 'MAXAR_Sudan_flooding_8_22_2022', 'MAXAR_afghanistan_earthquake22', 'MAXAR_cyclone_emnati22', 'MAXAR_ghana_explosion22', 'MAXAR_kentucky_flooding_7_29_2022', 'MAXAR_pakistan_flooding22', 'MAXAR_tonga_volcano21', 'MAXAR_volcano_indonesia21', 'MAXAR_yellowstone_flooding22', 'MAXAR_Maui_Hawaii_fires_Aug_23', 'MAXAR_NWT_Canada_Aug_23', 'MAXAR_shovi_georgia_landslide_8Aug23']\n" + "['MAXAR_BayofBengal_Cyclone_Mocha_May_23', 'MAXAR_Emilia_Romagna_Italy_flooding_may23', 'MAXAR_Gambia_flooding_8_11_2022', 'MAXAR_Marshall_Fire_21_Update', 'MAXAR_Hurricane_Fiona_9_19_2022', 'MAXAR_Hurricane_Ian_9_26_2022', 'MAXAR_Indonesia_Earthquake22', 'MAXAR_Kahramanmaras_turkey_earthquake_23', 'MAXAR_Kalehe_DRC_Flooding_5_8_23', 'MAXAR_volcano_indonesia21', 'MAXAR_New_Zealand_Flooding22', 'MAXAR_New_Zealand_Flooding23', 'MAXAR_Sudan_flooding_8_22_2022', 'MAXAR_afghanistan_earthquake22', 'MAXAR_cyclone_emnati22', 'MAXAR_ghana_explosion22', 'MAXAR_kentucky_flooding_7_29_2022', 'MAXAR_pakistan_flooding22', 'MAXAR_southafrica_flooding22', 'MAXAR_tonga_volcano21', 'MAXAR_yellowstone_flooding22', 'MAXAR_Maui_Hawaii_fires_Aug_23', 'MAXAR_NWT_Canada_Aug_23', 'MAXAR_shovi_georgia_landslide_8Aug23', 'MAXAR_Hurricane_Idalia_Florida_Aug23', 'MAXAR_Libya_Floods_Sept_2023', 'MAXAR_McDougallCreekWildfire_BC_Canada_Aug_23', 'MAXAR_Morocco_Earthquake_Sept_2023', 'UMBRA_2023']\n" ] } ], @@ -174,7 +174,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 5, "id": "98d8a28d", "metadata": {}, "outputs": [ @@ -182,17 +182,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "Collection Id: MAXAR_Kahramanmaras_turkey_earthquake_23\n", - "Spatial Extent: [35.32861203895262, 36.06630343440598, 38.45685512435119, 37.90150133428409]\n", - "Temporal Extent: ['2021-02-28T08:10:22Z', '2023-03-11T08:29:15Z']\n", + "Collection Id: MAXAR_BayofBengal_Cyclone_Mocha_May_23\n", + "Spatial Extent: [91.831615, 19.984656587012033, 92.97426268500965, 21.666101]\n", + "Temporal Extent: ['2023-01-03T04:30:17Z', '2023-03-14T04:30:25Z']\n", "{\n", - " \"id\": \"MAXAR_Kahramanmaras_turkey_earthquake_23\",\n", + " \"id\": \"MAXAR_BayofBengal_Cyclone_Mocha_May_23\",\n", " \"type\": \"Collection\",\n", " \"links\": [\n", " {\n", " \"rel\": \"items\",\n", " \"type\": \"application/geo+json\",\n", - " \"href\": \"https://stac.eoapi.dev/collections/MAXAR_Kahramanmaras_turkey_earthquake_23/items\"\n", + " \"href\": \"https://stac.eoapi.dev/collections/MAXAR_BayofBengal_Cyclone_Mocha_May_23/items\"\n", " },\n", " {\n", " \"rel\": \"parent\",\n", @@ -207,457 +207,43 @@ " {\n", " \"rel\": \"self\",\n", " \"type\": \"application/json\",\n", - " \"href\": \"https://stac.eoapi.dev/collections/MAXAR_Kahramanmaras_turkey_earthquake_23\"\n", + " \"href\": \"https://stac.eoapi.dev/collections/MAXAR_BayofBengal_Cyclone_Mocha_May_23\"\n", " }\n", " ],\n", " \"extent\": {\n", " \"spatial\": {\n", " \"bbox\": [\n", " [\n", - " 35.32861203895262,\n", - " 36.06630343440598,\n", - " 38.45685512435119,\n", - " 37.90150133428409\n", - " ],\n", - " [\n", - " 36.39431428595146,\n", - " 37.16743689744272,\n", - " 36.597739259691394,\n", - " 37.27632822643855\n", - " ],\n", - " [\n", - " 37.04960614445558,\n", - " 36.63191806453216,\n", - " 37.205072570194794,\n", - " 36.746574586631844\n", - " ],\n", - " [\n", - " 36.56528740012546,\n", - " 36.87524918186195,\n", - " 36.71349084791951,\n", - " 37.36166156925326\n", - " ],\n", - " [\n", - " 35.302597,\n", - " 36.960976,\n", - " 35.36398424807608,\n", - " 37.008584\n", - " ],\n", - " [\n", - " 35.31641318680286,\n", - " 36.960976,\n", - " 35.368635,\n", - " 37.008584\n", - " ],\n", - " [\n", - " 36.804077,\n", - " 36.465088,\n", - " 36.915894,\n", - " 36.554871\n", - " ],\n", - " [\n", - " 36.82959060906311,\n", - " 36.49276872321792,\n", - " 37.05643641437666,\n", - " 36.624878\n", - " ],\n", - " [\n", - " 36.984131,\n", - " 36.535095,\n", - " 37.095886,\n", - " 36.624878\n", - " ],\n", - " [\n", - " 37.015293359106195,\n", - " 36.59325358233272,\n", - " 37.155547,\n", - " 36.733161\n", - " ],\n", - " [\n", - " 40.14692993954917,\n", - " 37.856098,\n", - " 40.310497,\n", - " 37.980469\n", - " ],\n", - " [\n", - " 40.143822,\n", - " 37.856098,\n", - " 40.310497,\n", - " 37.980469\n", - " ],\n", - " [\n", - " 37.29845588418028,\n", - " 36.99314320511006,\n", - " 37.451239755133756,\n", - " 37.117494\n", - " ],\n", - " [\n", - " 37.29774464331677,\n", - " 36.9896650792383,\n", - " 37.457524034308584,\n", - " 37.117494\n", - " ],\n", - " [\n", - " 37.34847971373171,\n", - " 36.989585,\n", - " 37.481124,\n", - " 37.11508889563412\n", - " ],\n", - " [\n", - " 37.2976,\n", - " 36.98959965805714,\n", - " 37.47444448907068,\n", - " 37.015901889979396\n", - " ],\n", - " [\n", - " 36.19771383328533,\n", - " 36.289375731514305,\n", - " 36.244766,\n", - " 36.393881\n", - " ],\n", - " [\n", - " 36.120792028864706,\n", - " 36.14015655174187,\n", - " 36.229566,\n", - " 36.274482719340426\n", - " ],\n", - " [\n", - " 36.14285540815239,\n", - " 36.27356734921313,\n", - " 36.244766,\n", - " 36.393881\n", - " ],\n", - " [\n", - " 36.141868,\n", - " 36.26635032674398,\n", - " 36.244766,\n", - " 36.393881\n", - " ],\n", - " [\n", - " 36.098953,\n", - " 36.127932,\n", - " 36.244766,\n", - " 36.393881\n", - " ],\n", - " [\n", - " 36.564514,\n", - " 35.875122,\n", - " 36.675476,\n", - " 35.964905\n", - " ],\n", - " [\n", - " 36.624329,\n", - " 36.345093,\n", - " 36.735901,\n", - " 36.434875\n", - " ],\n", - " [\n", - " 38.265734,\n", - " 38.325282,\n", - " 38.364036,\n", - " 38.364057\n", - " ],\n", - " [\n", - " 36.902291,\n", - " 37.557316,\n", - " 36.958307,\n", - " 37.596933\n", - " ],\n", - " [\n", - " 36.219925,\n", - " 37.046738,\n", - " 36.2736536401914,\n", - " 37.09977\n", - " ],\n", - " [\n", - " 36.219925,\n", - " 37.046738,\n", - " 36.289395,\n", - " 37.09977\n", - " ],\n", - " [\n", - " 38.733704,\n", - " 37.115112,\n", - " 38.846497,\n", - " 37.204895\n", - " ],\n", - " [\n", - " 36.52492568949533,\n", - " 36.93517400388012,\n", - " 36.72863746116338,\n", - " 37.06533191094125\n", - " ],\n", - " [\n", - " 37.18508732537049,\n", - " 36.93624019118607,\n", - " 37.57628185978109,\n", - " 37.20300563112067\n", - " ],\n", - " [\n", - " 35.968135480519166,\n", - " 36.08290230501916,\n", - " 36.36857878735416,\n", - " 36.32611087960102\n", - " ],\n", - " [\n", - " 37.04960614445558,\n", - " 36.63191806453216,\n", - " 37.205072570194794,\n", - " 36.746574586631844\n", - " ],\n", - " [\n", - " 36.70782972919,\n", - " 37.31458599226506,\n", - " 37.094357387346356,\n", - " 37.6388459951458\n", - " ],\n", - " [\n", - " 36.074011762291256,\n", - " 36.99645281441965,\n", - " 36.43039951083553,\n", - " 37.135050489529895\n", - " ],\n", - " [\n", - " 38.70465012519544,\n", - " 37.07660046856506,\n", - " 38.893745912810424,\n", - " 37.27151792513816\n", - " ],\n", - " [\n", - " 36.75204714549616,\n", - " 36.50431672606769,\n", - " 36.99751367665573,\n", - " 36.68516122654125\n", - " ],\n", - " [\n", - " 38.06015901091088,\n", - " 38.21578061676832,\n", - " 38.514428711330694,\n", - " 38.47292570695286\n", - " ],\n", - " [\n", - " 36.75204714549616,\n", - " 36.50431672606769,\n", - " 36.99751367665573,\n", - " 36.68516122654125\n", - " ],\n", - " [\n", - " 36.036838063589464,\n", - " 36.4652144103136,\n", - " 36.27718132402165,\n", - " 36.722983669639376\n", - " ],\n", - " [\n", - " 35.83991709050044,\n", - " 35.9705643562241,\n", - " 36.10847691997119,\n", - " 36.17602181808681\n", - " ],\n", - " [\n", - " 37.2086027984948,\n", - " 36.881200182870394,\n", - " 37.44697269340033,\n", - " 37.26814965132743\n", - " ],\n", - " [\n", - " 36.907266976936285,\n", - " 36.91571544705779,\n", - " 37.196434355565295,\n", - " 37.75365980936115\n", - " ],\n", - " [\n", - " 36.66417067763287,\n", - " 36.893916206160746,\n", - " 36.94135503156023,\n", - " 37.75292284596646\n", - " ],\n", - " [\n", - " 36.101348035914086,\n", - " 36.76332547049597,\n", - " 36.35006037398585,\n", - " 37.41402735975632\n", - " ],\n", - " [\n", - " 36.28243347151518,\n", - " 35.885955,\n", - " 36.395818,\n", - " 35.91849849773082\n", - " ],\n", - " [\n", - " 36.21137593252559,\n", - " 36.255251436293435,\n", - " 36.395818,\n", - " 36.397033\n", - " ],\n", - " [\n", - " 36.202057998869144,\n", - " 36.085620089608526,\n", - " 36.395818,\n", - " 36.233179179599425\n", - " ],\n", - " [\n", - " 36.43724012011105,\n", - " 36.24764802911114,\n", - " 36.66897323882865,\n", - " 36.40705503478506\n", - " ],\n", - " [\n", - " 36.211769692001056,\n", - " 36.075668813861,\n", - " 36.44235468786762,\n", - " 36.252806635855656\n", - " ],\n", - " [\n", - " 36.01872866649527,\n", - " 36.35620582718621,\n", - " 36.3008169441504,\n", - " 36.81207927785697\n", - " ],\n", - " [\n", - " 36.44806059380522,\n", - " 36.22653163722294,\n", - " 36.66070588836183,\n", - " 36.40326083358293\n", - " ],\n", - " [\n", - " 37.14711752539602,\n", - " 37.37434549247727,\n", - " 37.33228793498362,\n", - " 37.49587783519038\n", - " ],\n", - " [\n", - " 37.127176401642046,\n", - " 37.30651913415134,\n", - " 37.45752114315339,\n", - " 37.692537568633696\n", - " ],\n", - " [\n", - " 36.875450454679346,\n", - " 36.896755071405416,\n", - " 37.1056071352593,\n", - " 37.76069174411886\n", - " ],\n", - " [\n", - " 36.6730422579986,\n", - " 36.89045223710193,\n", - " 36.91347807060852,\n", - " 37.78150025530812\n", - " ],\n", - " [\n", - " 37.12404392170605,\n", - " 37.35089079249487,\n", - " 37.35525581234215,\n", - " 37.5239390669561\n", - " ],\n", - " [\n", - " 36.72270807760239,\n", - " 37.65133933817404,\n", - " 36.9793372183526,\n", - " 37.79360976480217\n", - " ],\n", - " [\n", - " 36.53976967540979,\n", - " 36.94435109019758,\n", - " 36.720503605651295,\n", - " 37.09419588532061\n", - " ],\n", - " [\n", - " 36.479697307813865,\n", - " 37.09779831915633,\n", - " 36.67267878878018,\n", - " 37.2659270008341\n", - " ],\n", - " [\n", - " 38.2218091717765,\n", - " 37.38740327001574,\n", - " 38.405563602481934,\n", - " 37.53170888512031\n", + " 91.831615,\n", + " 19.984656587012033,\n", + " 92.97426268500965,\n", + " 21.666101\n", " ],\n", " [\n", - " 37.70435909472475,\n", - " 37.26157993157078,\n", - " 38.05014092021386,\n", - " 37.671077037448654\n", + " 92.75855246040959,\n", + " 19.982078842323997,\n", + " 92.89682495377032,\n", + " 20.514473160464657\n", " ],\n", " [\n", - " 38.073629038992614,\n", - " 37.6594826423537,\n", - " 38.47610470922022,\n", - " 37.822928477886215\n", - " ],\n", - " [\n", - " 37.41476153956851,\n", - " 37.317027074723,\n", - " 37.75820367105651,\n", - " 37.66896109246899\n", - " ],\n", - " [\n", - " 38.21853995071469,\n", - " 37.44943435925765,\n", - " 38.41192931836562,\n", - " 37.583882015377775\n", - " ],\n", - " [\n", - " 38.21733111168587,\n", - " 37.97251565108862,\n", - " 38.409942390844414,\n", - " 38.09743204047995\n", - " ],\n", - " [\n", - " 38.0536304324591,\n", - " 37.41090295448065,\n", - " 38.29096023713685,\n", - " 37.58653325515288\n", - " ],\n", - " [\n", - " 38.07315289705838,\n", - " 37.380707112687496,\n", - " 38.265428996422365,\n", - " 37.510271067760094\n", - " ],\n", - " [\n", - " 38.45306702857648,\n", - " 37.94082755698512,\n", - " 38.657175176272865,\n", - " 38.07998553098428\n", - " ],\n", - " [\n", - " 38.39407950596177,\n", - " 37.704004721321084,\n", - " 38.54284528399045,\n", - " 37.80549833312407\n", - " ],\n", - " [\n", - " 37.5349349182917,\n", - " 37.628945467548746,\n", - " 37.75370005291414,\n", - " 37.872636243463944\n", - " ],\n", - " [\n", - " 38.665964936097254,\n", - " 37.04277780314956,\n", - " 38.94765149264787,\n", - " 37.29842755492842\n", - " ],\n", - " [\n", - " 36.202057998869144,\n", - " 36.08390040008945,\n", - " 36.45085162597366,\n", - " 36.233179179599425\n", + " 91.831615,\n", + " 21.518411,\n", + " 91.957078,\n", + " 21.666101\n", " ]\n", " ]\n", " },\n", " \"temporal\": {\n", " \"interval\": [\n", " [\n", - " \"2021-02-28T08:10:22Z\",\n", - " \"2023-03-11T08:29:15Z\"\n", + " \"2023-01-03T04:30:17Z\",\n", + " \"2023-03-14T04:30:25Z\"\n", " ]\n", " ]\n", " }\n", " },\n", " \"license\": \"proprietary\",\n", - " \"description\": \"Maxar OpenData | Kahramanmaras turkey earthquake 23\",\n", + " \"description\": \"Maxar OpenData | BayofBengal Cyclone Mocha May 23\",\n", " \"item_assets\": {\n", " \"visual\": {\n", " \"type\": \"image/tiff; application=geotiff; profile=cloud-optimized\",\n", @@ -717,7 +303,7 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 6, "id": "5742ec61", "metadata": { "scrolled": true @@ -727,7 +313,9 @@ "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" + "</script>\n", + "</html>\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen>" ], "text/plain": [ - "" + "" ] }, - "execution_count": 62, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -866,7 +458,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 7, "id": "02f9b550", "metadata": {}, "outputs": [ @@ -874,7 +466,9 @@ "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" + "</script>\n", + "</html>\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen>" ], "text/plain": [ - "" + "" ] }, - "execution_count": 14, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -1015,7 +613,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 8, "id": "f425070c", "metadata": {}, "outputs": [ @@ -1050,7 +648,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 9, "id": "0870f7df", "metadata": {}, "outputs": [ @@ -1080,7 +678,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 10, "id": "992501d7", "metadata": {}, "outputs": [ @@ -1108,7 +706,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 11, "id": "7f77306d", "metadata": { "scrolled": false @@ -1118,7 +716,9 @@ "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" + "</script>\n", + "</html>\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen>" ], "text/plain": [ - "" + "" ] }, - "execution_count": 24, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -1236,7 +840,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 12, "id": "56ba6e0c", "metadata": {}, "outputs": [ @@ -1543,7 +1147,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 13, "id": "7f632955", "metadata": {}, "outputs": [ @@ -1628,7 +1232,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 14, "id": "0d9013bb", "metadata": { "scrolled": true @@ -1657,7 +1261,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 15, "id": "29652a32", "metadata": {}, "outputs": [ @@ -1695,7 +1299,7 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 16, "id": "f9430fa2", "metadata": {}, "outputs": [ @@ -1732,7 +1336,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 17, "id": "aca07238", "metadata": {}, "outputs": [ @@ -1841,7 +1445,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 18, "id": "e2a45bf1", "metadata": {}, "outputs": [ @@ -1863,7 +1467,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 19, "id": "481a9cae", "metadata": {}, "outputs": [ @@ -1881,7 +1485,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 20, "id": "8641fff2", "metadata": { "scrolled": false @@ -1935,7 +1539,10 @@ " \"green\",\n", " \"blue\"\n", " ],\n", + " \"driver\": \"GTiff\",\n", + " \"count\": 3,\n", " \"width\": 17408,\n", + " \"height\": 17408,\n", " \"overviews\": [\n", " 2,\n", " 4,\n", @@ -1943,10 +1550,7 @@ " 16,\n", " 32,\n", " 64\n", - " ],\n", - " \"count\": 3,\n", - " \"height\": 17408,\n", - " \"driver\": \"GTiff\"\n", + " ]\n", "}\n" ] } @@ -1975,7 +1579,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 21, "id": "b71ad07f", "metadata": { "scrolled": false @@ -1992,7 +1596,9 @@ "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" + "</script>\n", + "</html>\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen>" ], "text/plain": [ - "" + "" ] }, - "execution_count": 43, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -2124,7 +1734,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 22, "id": "97a2ac88", "metadata": { "scrolled": false @@ -2134,7 +1744,9 @@ "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" + "</script>\n", + "</html>\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen>" ], "text/plain": [ - "" + "" ] }, - "execution_count": 44, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -2280,7 +1896,7 @@ }, { "cell_type": "code", - "execution_count": 116, + "execution_count": 23, "id": "82cf41fe", "metadata": { "scrolled": false @@ -2343,15 +1959,15 @@ " \"undefined\",\n", " \"undefined\"\n", " ],\n", + " \"driver\": \"GTiff\",\n", " \"count\": 4,\n", - " \"height\": 2777,\n", " \"width\": 2777,\n", + " \"height\": 2777,\n", " \"overviews\": [\n", " 2,\n", " 4,\n", " 8\n", - " ],\n", - " \"driver\": \"GTiff\"\n", + " ]\n", "}\n" ] } @@ -2370,7 +1986,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 24, "id": "93af96d2", "metadata": {}, "outputs": [ @@ -2577,7 +2193,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 25, "id": "1f7c1de3", "metadata": {}, "outputs": [ @@ -2599,7 +2215,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 26, "id": "286f873b", "metadata": {}, "outputs": [ @@ -2607,7 +2223,9 @@ "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" + "</script>\n", + "</html>\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen>" ], "text/plain": [ - "" + "" ] }, - "execution_count": 56, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -2763,7 +2385,7 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 27, "id": "57c276ec", "metadata": {}, "outputs": [ @@ -2772,17 +2394,31 @@ "output_type": "stream", "text": [ "{\n", - " \"searchid\": \"c13976bc1e5dc7f3c2b4a64239871fc0\",\n", + " \"id\": \"c13976bc1e5dc7f3c2b4a64239871fc0\",\n", " \"links\": [\n", " {\n", " \"rel\": \"metadata\",\n", + " \"title\": \"Mosaic metadata\",\n", " \"type\": \"application/json\",\n", - " \"href\": \"https://raster.eoapi.dev/mosaic/c13976bc1e5dc7f3c2b4a64239871fc0/info\"\n", + " \"href\": \"https://raster.eoapi.dev/searches/c13976bc1e5dc7f3c2b4a64239871fc0/info\"\n", " },\n", " {\n", " \"rel\": \"tilejson\",\n", + " \"title\": \"Link for TileJSON\",\n", + " \"type\": \"application/json\",\n", + " \"href\": \"https://raster.eoapi.dev/searches/c13976bc1e5dc7f3c2b4a64239871fc0/tilejson.json\"\n", + " },\n", + " {\n", + " \"rel\": \"map\",\n", + " \"title\": \"Link for Map viewer\",\n", " \"type\": \"application/json\",\n", - " \"href\": \"https://raster.eoapi.dev/mosaic/c13976bc1e5dc7f3c2b4a64239871fc0/tilejson.json\"\n", + " \"href\": \"https://raster.eoapi.dev/searches/c13976bc1e5dc7f3c2b4a64239871fc0/map\"\n", + " },\n", + " {\n", + " \"rel\": \"wmts\",\n", + " \"title\": \"Link for WMTS\",\n", + " \"type\": \"application/json\",\n", + " \"href\": \"https://raster.eoapi.dev/searches/c13976bc1e5dc7f3c2b4a64239871fc0/WMTSCapabilities.xml\"\n", " }\n", " ]\n", "}\n" @@ -2795,7 +2431,7 @@ "enddate = \"2023-08-10T23:59:59Z\"\n", "\n", "mosaic = httpx.post(\n", - " \"https://raster.eoapi.dev/mosaic/register\",\n", + " \"https://raster.eoapi.dev/searches/register\",\n", " data=json.dumps(\n", " {\n", " \"filter-lang\": 'cql2-json',\n", @@ -2825,6 +2461,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "id": "6dd5f539", "metadata": {}, @@ -2882,7 +2519,7 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 32, "id": "1638c679", "metadata": {}, "outputs": [ @@ -2890,14 +2527,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'tilejson': '2.2.0', 'name': 'c13976bc1e5dc7f3c2b4a64239871fc0', 'version': '1.0.0', 'scheme': 'xyz', 'tiles': ['https://raster.eoapi.dev/mosaic/c13976bc1e5dc7f3c2b4a64239871fc0/tiles/WebMercatorQuad/{z}/{x}/{y}@1x?assets=visual'], 'minzoom': 12, 'maxzoom': 19, 'bounds': [-156.70182, 20.61864421171153, -156.23880228630824, 20.972368], 'center': [-156.4703111431541, 20.795506105855765, 12]}\n" + "{'tilejson': '2.2.0', 'name': 'db5a7f4dc6d5763bf955e80903e6a78d', 'version': '1.0.0', 'scheme': 'xyz', 'tiles': ['https://raster.eoapi.dev/searches/db5a7f4dc6d5763bf955e80903e6a78d/tiles/WebMercatorQuad/{z}/{x}/{y}?assets=visual'], 'minzoom': 12, 'maxzoom': 19, 'bounds': [-180.0, -85.05112877980655, 179.99999999999955, 85.0511287798066], 'center': [-2.2737367544323206e-13, 2.842170943040401e-14, 12]}\n" ] }, { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" + "</script>\n", + "</html>\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen>" ], "text/plain": [ - "" + "" ] }, - "execution_count": 61, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "mosaic_id = mosaic[\"searchid\"]\n", + "mosaic_id = mosaic[\"id\"]\n", "\n", "tilejson = httpx.get(\n", - " f\"https://raster.eoapi.dev/mosaic/{mosaic_id}/tilejson.json\",\n", + " f\"https://raster.eoapi.dev/searches/{mosaic_id}/tilejson.json\",\n", " params = (\n", " (\"assets\", \"visual\"), # THIS IS MANDATORY\n", " (\"minzoom\", 12),\n", @@ -3019,7 +2662,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": null, "id": "17edc413", "metadata": {}, "outputs": [ @@ -3076,7 +2719,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 30, "id": "d5e6f126", "metadata": {}, "outputs": [ @@ -3084,14 +2727,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'tilejson': '2.2.0', 'name': 'db5a7f4dc6d5763bf955e80903e6a78d', 'version': '1.0.0', 'scheme': 'xyz', 'tiles': ['https://raster.eoapi.dev/mosaic/db5a7f4dc6d5763bf955e80903e6a78d/tiles/WebMercatorQuad/{z}/{x}/{y}@1x?assets=visual'], 'minzoom': 12, 'maxzoom': 19, 'bounds': [-180.0, -85.0511287798066, 180.0, 85.0511287798066], 'center': [0.0, 0.0, 12]}\n" + "{'tilejson': '2.2.0', 'name': 'db5a7f4dc6d5763bf955e80903e6a78d', 'version': '1.0.0', 'scheme': 'xyz', 'tiles': ['https://raster.eoapi.dev/searches/db5a7f4dc6d5763bf955e80903e6a78d/tiles/WebMercatorQuad/{z}/{x}/{y}?assets=visual'], 'minzoom': 12, 'maxzoom': 19, 'bounds': [-180.0, -85.05112877980655, 179.99999999999955, 85.0511287798066], 'center': [-2.2737367544323206e-13, 2.842170943040401e-14, 12]}\n" ] }, { "data": { "text/html": [ "
Make this Notebook Trusted to load map: File -> Trust Notebook
" + "</script>\n", + "</html>\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen>" ], "text/plain": [ - "" + "" ] }, - "execution_count": 68, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mosaic = httpx.post(\n", - " \"https://raster.eoapi.dev/mosaic/register\",\n", + " \"https://raster.eoapi.dev/searches/register\",\n", " data=json.dumps(\n", " {\n", " \"filter-lang\": 'cql2-json',\n", @@ -3211,10 +2860,10 @@ " )\n", ").json()\n", "\n", - "mosaic_id = mosaic[\"searchid\"]\n", + "mosaic_id = mosaic[\"id\"]\n", "\n", "tilejson = httpx.get(\n", - " f\"https://raster.eoapi.dev/mosaic/{mosaic_id}/tilejson.json\",\n", + " f\"https://raster.eoapi.dev/searches/{mosaic_id}/tilejson.json\",\n", " params = (\n", " (\"assets\", \"visual\"), # THIS IS MANDATORY\n", " (\"minzoom\", 12),\n", @@ -3314,7 +2963,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.17" + "version": "3.10.5" } }, "nbformat": 4, diff --git a/docs/src/notebooks/eoAPI_Maxar_Kahramanmaras_demo.ipynb b/docs/src/notebooks/eoAPI_Maxar_Kahramanmaras_demo.ipynb index 46943ff..858cb33 100644 --- a/docs/src/notebooks/eoAPI_Maxar_Kahramanmaras_demo.ipynb +++ b/docs/src/notebooks/eoAPI_Maxar_Kahramanmaras_demo.ipynb @@ -52,7 +52,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 20, "id": "9a912d28", "metadata": {}, "outputs": [], @@ -64,7 +64,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 55, "id": "0ed3efb6", "metadata": {}, "outputs": [], @@ -90,7 +90,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 56, "id": "44105f25", "metadata": {}, "outputs": [ @@ -119,14 +119,14 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 57, "id": "02f9b550", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "65fefc42d97146b9962488cf87af07de", + "model_id": "71f6bfb05f2844f4a51e754e34cc7afc", "version_major": 2, "version_minor": 0 }, @@ -134,7 +134,7 @@ "Map(center=[36.983902384345036, 36.89273358165191], controls=(ZoomControl(options=['position', 'zoom_in_text',…" ] }, - "execution_count": 4, + "execution_count": 57, "metadata": {}, "output_type": "execute_result" } @@ -188,7 +188,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 58, "id": "f425070c", "metadata": {}, "outputs": [ @@ -223,7 +223,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 59, "id": "0870f7df", "metadata": {}, "outputs": [ @@ -254,7 +254,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 60, "id": "992501d7", "metadata": {}, "outputs": [ @@ -285,14 +285,14 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 61, "id": "7f77306d", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "2def97e8e551481082935449f9a6fa77", + "model_id": "1b3051a9025749f88686803e2b803ccf", "version_major": 2, "version_minor": 0 }, @@ -300,7 +300,7 @@ "Map(center=[36.983902384345036, 36.89273358165191], controls=(ZoomControl(options=['position', 'zoom_in_text',…" ] }, - "execution_count": 8, + "execution_count": 61, "metadata": {}, "output_type": "execute_result" } @@ -343,7 +343,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 62, "id": "56ba6e0c", "metadata": {}, "outputs": [ @@ -678,7 +678,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 63, "id": "7f632955", "metadata": {}, "outputs": [ @@ -768,7 +768,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 64, "id": "0d9013bb", "metadata": {}, "outputs": [ @@ -796,7 +796,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 65, "id": "021248b8", "metadata": {}, "outputs": [ @@ -839,7 +839,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 66, "id": "29652a32", "metadata": {}, "outputs": [ @@ -884,7 +884,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 67, "id": "aca07238", "metadata": {}, "outputs": [ @@ -977,7 +977,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 68, "id": "e2a45bf1", "metadata": {}, "outputs": [ @@ -1031,8 +1031,10 @@ " \"green\",\n", " \"blue\"\n", " ],\n", - " \"width\": 17408,\n", " \"driver\": \"GTiff\",\n", + " \"count\": 3,\n", + " \"width\": 17408,\n", + " \"height\": 17408,\n", " \"overviews\": [\n", " 2,\n", " 4,\n", @@ -1040,9 +1042,7 @@ " 16,\n", " 32,\n", " 64\n", - " ],\n", - " \"count\": 3,\n", - " \"height\": 17408\n", + " ]\n", "}\n", "visual 12 19\n", "ms_analytic 12 16\n", @@ -1084,7 +1084,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 69, "id": "b71ad07f", "metadata": {}, "outputs": [ @@ -1098,7 +1098,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "3272f8985af44e0189773f97e890e7b6", + "model_id": "75dfcb710d454c4e8f432e747a27621c", "version_major": 2, "version_minor": 0 }, @@ -1106,7 +1106,7 @@ "Map(center=[36.10519545142351, 36.404020998028585], controls=(ZoomControl(options=['position', 'zoom_in_text',…" ] }, - "execution_count": 16, + "execution_count": 69, "metadata": {}, "output_type": "execute_result" } @@ -1170,7 +1170,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 70, "id": "57c276ec", "metadata": {}, "outputs": [ @@ -1180,34 +1180,62 @@ "text": [ "Pre event Mosaic\n", "{\n", - " \"searchid\": \"9c2101bb56005850dcc6e95303586432\",\n", + " \"id\": \"9c2101bb56005850dcc6e95303586432\",\n", " \"links\": [\n", " {\n", " \"rel\": \"metadata\",\n", + " \"title\": \"Mosaic metadata\",\n", " \"type\": \"application/json\",\n", - " \"href\": \"https://raster.eoapi.dev/mosaic/9c2101bb56005850dcc6e95303586432/info\"\n", + " \"href\": \"https://raster.eoapi.dev/searches/9c2101bb56005850dcc6e95303586432/info\"\n", " },\n", " {\n", " \"rel\": \"tilejson\",\n", + " \"title\": \"Link for TileJSON\",\n", + " \"type\": \"application/json\",\n", + " \"href\": \"https://raster.eoapi.dev/searches/9c2101bb56005850dcc6e95303586432/tilejson.json\"\n", + " },\n", + " {\n", + " \"rel\": \"map\",\n", + " \"title\": \"Link for Map viewer\",\n", " \"type\": \"application/json\",\n", - " \"href\": \"https://raster.eoapi.dev/mosaic/9c2101bb56005850dcc6e95303586432/tilejson.json\"\n", + " \"href\": \"https://raster.eoapi.dev/searches/9c2101bb56005850dcc6e95303586432/map\"\n", + " },\n", + " {\n", + " \"rel\": \"wmts\",\n", + " \"title\": \"Link for WMTS\",\n", + " \"type\": \"application/json\",\n", + " \"href\": \"https://raster.eoapi.dev/searches/9c2101bb56005850dcc6e95303586432/WMTSCapabilities.xml\"\n", " }\n", " ]\n", "}\n", "\n", "Post event Mosaic\n", "{\n", - " \"searchid\": \"8aebe8860a92d2f7bc0cdad4d7d81acf\",\n", + " \"id\": \"8aebe8860a92d2f7bc0cdad4d7d81acf\",\n", " \"links\": [\n", " {\n", " \"rel\": \"metadata\",\n", + " \"title\": \"Mosaic metadata\",\n", " \"type\": \"application/json\",\n", - " \"href\": \"https://raster.eoapi.dev/mosaic/8aebe8860a92d2f7bc0cdad4d7d81acf/info\"\n", + " \"href\": \"https://raster.eoapi.dev/searches/8aebe8860a92d2f7bc0cdad4d7d81acf/info\"\n", " },\n", " {\n", " \"rel\": \"tilejson\",\n", + " \"title\": \"Link for TileJSON\",\n", + " \"type\": \"application/json\",\n", + " \"href\": \"https://raster.eoapi.dev/searches/8aebe8860a92d2f7bc0cdad4d7d81acf/tilejson.json\"\n", + " },\n", + " {\n", + " \"rel\": \"map\",\n", + " \"title\": \"Link for Map viewer\",\n", " \"type\": \"application/json\",\n", - " \"href\": \"https://raster.eoapi.dev/mosaic/8aebe8860a92d2f7bc0cdad4d7d81acf/tilejson.json\"\n", + " \"href\": \"https://raster.eoapi.dev/searches/8aebe8860a92d2f7bc0cdad4d7d81acf/map\"\n", + " },\n", + " {\n", + " \"rel\": \"wmts\",\n", + " \"title\": \"Link for WMTS\",\n", + " \"type\": \"application/json\",\n", + " \"href\": \"https://raster.eoapi.dev/searches/8aebe8860a92d2f7bc0cdad4d7d81acf/WMTSCapabilities.xml\"\n", " }\n", " ]\n", "}\n" @@ -1221,7 +1249,7 @@ "bounds = [36.83064386785452, 37.53123515817725, 37.03859654890988, 37.63167525356958]\n", "\n", "pre_mosaic = httpx.post(\n", - " \"https://raster.eoapi.dev/mosaic/register\",\n", + " \"https://raster.eoapi.dev/searches/register\",\n", " data=json.dumps(\n", " {\n", " \"filter-lang\": 'cql2-json',\n", @@ -1256,7 +1284,7 @@ ").json()\n", "\n", "post_mosaic = httpx.post(\n", - " \"https://raster.eoapi.dev/mosaic/register\",\n", + " \"https://raster.eoapi.dev/searches/register\",\n", " data=json.dumps(\n", " {\n", " \"filter-lang\": 'cql2-json',\n", @@ -1355,7 +1383,7 @@ "\n", "API Response:\n", "\n", - "The raster service will return a `searchid` hash (`mosaic id`), which we can use to construct a tile URL.\n", + "The raster service will return a `id` hash (`mosaic id`), which we can use to construct a tile URL.\n", "\n", "To create a valid tile URL, we will again need to pass an `assets` parameter to tell the tiler which assets we want to visualize. We can also set the min/max zoom limits to avoid underzooming (opening too many files) and overzooming.\n", "\n", @@ -1364,7 +1392,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 71, "id": "1638c679", "metadata": {}, "outputs": [ @@ -1372,13 +1400,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'tilejson': '2.2.0', 'name': 'Maxar Kahramanmaras - Pre event', 'version': '1.0.0', 'scheme': 'xyz', 'tiles': ['https://raster.eoapi.dev/mosaic/9c2101bb56005850dcc6e95303586432/tiles/WebMercatorQuad/{z}/{x}/{y}?assets=visual'], 'minzoom': 12, 'maxzoom': 19, 'bounds': [36.83064386785452, 37.53123515817725, 37.03859654890988, 37.63167525356958], 'center': [36.9346202083822, 37.58145520587342, 12]}\n" + "{'tilejson': '2.2.0', 'name': 'Maxar Kahramanmaras - Pre event', 'version': '1.0.0', 'scheme': 'xyz', 'tiles': ['https://raster.eoapi.dev/searches/9c2101bb56005850dcc6e95303586432/tiles/WebMercatorQuad/{z}/{x}/{y}?assets=visual'], 'minzoom': 12, 'maxzoom': 19, 'bounds': [36.83064386785452, 37.53123515817725, 37.03859654890988, 37.63167525356958], 'center': [36.9346202083822, 37.58145520587342, 12]}\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "924a36c6483e4f04b808d688cbf9d6bd", + "model_id": "346f211c9fac4b649d02b0b326adcc7c", "version_major": 2, "version_minor": 0 }, @@ -1386,16 +1414,16 @@ "Map(center=[37.58145520587342, 36.9346202083822], controls=(ZoomControl(options=['position', 'zoom_in_text', '…" ] }, - "execution_count": 18, + "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "mosaic_id = pre_mosaic[\"searchid\"]\n", + "mosaic_id = pre_mosaic[\"id\"]\n", "\n", "tilejson_pre = httpx.get(\n", - " f\"https://raster.eoapi.dev/mosaic/{mosaic_id}/tilejson.json\",\n", + " f\"https://raster.eoapi.dev/searches/{mosaic_id}/tilejson.json\",\n", " params = (\n", " (\"assets\", \"visual\"), # THIS IS MANDATORY\n", " (\"minzoom\", 12),\n", @@ -1436,7 +1464,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 72, "id": "c74df2f5", "metadata": {}, "outputs": [ @@ -1444,13 +1472,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'tilejson': '2.2.0', 'name': 'Maxar Kahramanmaras - Port event', 'version': '1.0.0', 'scheme': 'xyz', 'tiles': ['https://raster.eoapi.dev/mosaic/8aebe8860a92d2f7bc0cdad4d7d81acf/tiles/WebMercatorQuad/{z}/{x}/{y}?assets=visual'], 'minzoom': 12, 'maxzoom': 19, 'bounds': [36.83064386785452, 37.53123515817725, 37.03859654890988, 37.63167525356958], 'center': [36.9346202083822, 37.58145520587342, 12]}\n" + "{'tilejson': '2.2.0', 'name': 'Maxar Kahramanmaras - Port event', 'version': '1.0.0', 'scheme': 'xyz', 'tiles': ['https://raster.eoapi.dev/searches/8aebe8860a92d2f7bc0cdad4d7d81acf/tiles/WebMercatorQuad/{z}/{x}/{y}?assets=visual'], 'minzoom': 12, 'maxzoom': 19, 'bounds': [36.83064386785452, 37.53123515817725, 37.03859654890988, 37.63167525356958], 'center': [36.9346202083822, 37.58145520587342, 12]}\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "146a0b0664f949c593b5a5d58d48c0f8", + "model_id": "70ffff2868c946eda75493ad50c16dc8", "version_major": 2, "version_minor": 0 }, @@ -1458,16 +1486,16 @@ "Map(center=[37.58145520587342, 36.9346202083822], controls=(ZoomControl(options=['position', 'zoom_in_text', '…" ] }, - "execution_count": 19, + "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "mosaic_id = post_mosaic[\"searchid\"]\n", + "mosaic_id = post_mosaic[\"id\"]\n", "\n", "tilejson_post = httpx.get(\n", - " f\"https://raster.eoapi.dev/mosaic/{mosaic_id}/tilejson.json\",\n", + " f\"https://raster.eoapi.dev/searches/{mosaic_id}/tilejson.json\",\n", " params = (\n", " (\"assets\", \"visual\"), # THIS IS MANDATORY\n", " (\"minzoom\", 12),\n", @@ -1508,14 +1536,14 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 73, "id": "b8d900b4", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "9deeb7a0c43a44868cbc24271ee01dda", + "model_id": "3717d40b082a4258b9d1c3a42292d138", "version_major": 2, "version_minor": 0 }, @@ -1523,7 +1551,7 @@ "Map(center=[37.571788, 36.9191], controls=(ZoomControl(options=['position', 'zoom_in_text', 'zoom_in_title', '…" ] }, - "execution_count": 20, + "execution_count": 73, "metadata": {}, "output_type": "execute_result" } diff --git a/docs/src/notebooks/getting-started.ipynb b/docs/src/notebooks/getting-started.ipynb new file mode 100644 index 0000000..1d608a5 --- /dev/null +++ b/docs/src/notebooks/getting-started.ipynb @@ -0,0 +1,1678 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Getting Started with STAC and eoAPI\n", + "\n", + "## A Foundational Guide for Geospatial Data Analysis\n", + "\n", + "### Overview\n", + "\n", + "Welcome to this guide designed to introduce you to the world of SpatioTemporal Asset Catalog (STAC), Cloud Optimized Geotiffs (COGs), and eoAPI. This Jupyter Notebook aims to provide you with the foundational knowledge and practical skills necessary to effectively utilize these powerful tools in geospatial data management and analysis.\n", + "\n", + "### Context\n", + "\n", + "The notebook delves into the essentials of using eoAPI, offering insights into STAC and COGs. We will explore how eoAPI facilitates querying metadata and visualizing the underlying referenced data. All notebooks of the repository run within a specially configured cluster, integrating a deployed instance of eoAPI and JupyterHub to provide a seamless, hands-on experience.\n", + "\n", + "### STAC, COG, and eoAPI\n", + "\n", + "- **STAC**: We begin with an introduction to STAC, explaining its structure and critical role in damage assessment and risk management.\n", + "- **COG**: Next, we explore COGs and why they are pivotal in modern geospatial data handling.\n", + "- **eoAPI**: Finally, we discuss eoAPI, detailing its functionalities and importance in this ecosystem.\n", + "\n", + "In this notebook, we leverage Maxar's high-resolution satellite imagery, acquired explicitly for the M7.8 and M7.5 Kahramanmaras earthquakes in Turkey on February 6, 2023. This data, pivotal for emergency response and risk assessment, has been ingested into our instance of eoAPI deployed on the cluster. The imagery, available as Cloud Optimized Geotiffs (COGs) with accompanying STAC metadata, enables streamlined analysis and visualization of the earthquake's impact. Maxar's data, being analysis-ready and cloud-optimized, provides a rich resource for demonstrating the capabilities of eoAPI in handling large-scale geospatial datasets in a crisis context.\n", + "\n", + "This notebook is the foundational guide for eoAPI and associated resources. It is structured to guide you through these concepts, culminating in a hands-on demonstration of using eoAPI to query and visualize earth observation data." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## An Introduction to STAC\n", + "\n", + "### What is STAC (SpatioTemporal Asset Catalog)?\n", + "\n", + "The SpatioTemporal Asset Catalog (STAC) is a specification designed to standardize how geospatial data is organized and accessed. It's a community-driven standard developed collaboratively by experts and stakeholders in the geospatial data field. STAC provides a common language and structure for describing geospatial information, making it easier to index, discover, and manage spatial data across various platforms and systems. One of the critical features of STAC is its format: simple JSON objects, which are both human-readable and machine-processable, ensuring ease of use and broad accessibility.\n", + "\n", + "A fundamental aspect of STAC's design is its hierarchical organization, comprising Catalogs, Collections, and Items. At the highest level, **Catalogs** serve as containers that organize and provide access to Collections and Items. **Collections** represent a group of Items that share common properties, metadata, and structure, typically representing a dataset or a series of datasets. Within Collections, **Items** are individual pieces of data, each containing specific geospatial information, such as location and time. Crucially, each Item includes links to its Assets, which are the files associated with the data, such as imagery, thumbnails, or other related resources. These **Assets** are integral to the utility of each Item, providing the data required for analysis and visualization. This structured approach ensures a consistent and intuitive way to access and manage vast amounts of geospatial data, making STAC an efficient tool for data providers and users.\n", + "\n", + "### Why is STAC Important?\n", + "\n", + "STAC is critical in the modern earth observation stack, particularly for large-scale environmental monitoring, disaster response, and risk assessment scenarios. Its standardized, community-backed approach facilitates:\n", + "\n", + "- **Efficient Data Discovery**: Simplifying the finding of relevant geospatial data across vast datasets.\n", + "- **Interoperability**: Enabling different systems and tools to access and use geospatial data seamlessly.\n", + "- **Scalability**: Supporting the management of increasingly large and complex datasets is a common challenge in geospatial analysis.\n", + "- **Inclusivity and Collaboration**: STAC evolves through collective insights as a community-driven standard, ensuring it remains relevant and effective for various use cases.\n", + "\n", + "STAC's capabilities are invaluable in rapidly accessing and analyzing data for humanitarian aid, disaster relief, and risk management purposes.\n", + "\n", + "### How Can I Learn More?\n", + "\n", + "To deepen your understanding of STAC and its applications:\n", + "\n", + "- **STAC Specification**: Dive into the official [STAC Specification](https://stacspec.org/) for detailed documentation and standards.\n", + "- **STAC Index**: Explore the [STAC Index](https://stacindex.org/), a comprehensive resource listing STAC implementations, tools, and data catalogs, to get a better grasp of the ecosystem and its applications.\n", + "- **Developer Best Practices**: For a more technical perspective, review the [STAC Best Practices](https://github.com/radiantearth/stac-spec/blob/master/best-practices.md) on GitHub, offering in-depth guidance for developers working with STAC.\n", + "\n", + "As we progress through this notebook, we'll explore applying STAC principles using eoAPI in practical scenarios." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## An Introduction to COGs\n", + "\n", + "### What is a COG (Cloud Optimized Geotiff)?\n", + "\n", + "A Cloud Optimized GeoTIFF (COG) is a variant of the TIFF image format tailored explicitly for optimized access over a network. A raster format specifies a particular layout of internal data within the GeoTIFF specification, allowing for efficient, subsetted, or aggregated access. This format is designed to enable efficient workflows on the cloud by leveraging HTTP GET range requests for just the parts of the file needed. COGs are regular GeoTIFF files, making them backward compatible with other geospatial software but with an internal organization that enables more efficient data access and processing.\n", + "\n", + "### Why is COG Important?\n", + "\n", + "COGs represent a significant advancement in geospatial data handling, primarily due to:\n", + "\n", + "- **Efficient Imagery Data Access**: COG-aware software can stream just the portion of data it needs, significantly improving processing times and enabling real-time workflows that were previously not possible.\n", + "- **Internal Compression and Optimized Read Performance**: COGs are internally compressed, meaning the inner blocks in a GeoTIFF are already compressed. This internal compression allows COG readers to decompress only the specific portion of the file requested rather than the entire file.\n", + "- **Reduced Duplication of Data**: COGs enable diverse software to access a single file online, reducing the need to copy and cache data.\n", + "- **Legacy Compatibility**: Traditional GIS software can treat cloud-optimized geoTIFFs just like normal geoTIFFs, simplifying data management.\n", + "\n", + "### How Can I Learn More?\n", + "\n", + "For a deeper dive into COGs and to understand their implementation and usage:\n", + "\n", + "- **Official Documentation**: Visit the [COG website](https://www.cogeo.org/) for a comprehensive understanding of COGs and their implementation details.\n", + "- **Cloud Native Geospatial Formats Guide**: The [Cloud Native Geospatial Formats Guide](https://guide.cloudnativegeo.org/) offers detailed insights into COGs, including advanced details and working examples to help you grasp the practical applications of this format.\n", + "\n", + "In the following sections, we'll explore the practical application of COGs in conjunction with eoAPI, focusing on how they can be utilized for efficient geospatial data management and visualization." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## An Introduction to eoAPI\n", + "\n", + "### What is eoAPI?\n", + "\n", + "eoAPI is an open-source framework for accessing and utilizing Earth Observation (EO) data. It simplifies constructing a cloud-native EO infrastructure by providing sensible defaults for most EO and geospatial infrastructure needs. eoAPI is modular, allowing for easy customization to specific requirements. Its key features include:\n", + "\n", + "- **STAC Powered**: Utilizes a suite of STAC-focused technologies.\n", + "- **Sensible Defaults**: Facilitates seamless deployment, configuration, and customization.\n", + "- **Cloud Agnostic**: Capable of quick deployment and scaling of EO services anywhere.\n", + "\n", + "### Why is eoAPI Important?\n", + "\n", + "eoAPI addresses the challenge of making EO data easily discoverable, interoperable, ingestible, and optimized for integration into modern applications and decision-making tools. Simply put, it lowers the barrier of entry to earth observation data to a broader range of developers, scientists, and the general public. This is crucial for understanding our changing planet and maximizing the societal impact of EO data. eoAPI's framework supports end-to-end EO infrastructure, including data cataloging, searching, visualization, and access, making it a powerful tool for organizations leveraging geospatial data.\n", + "\n", + "### How Can I Learn More?\n", + "\n", + "To explore eoAPI further:\n", + "\n", + "- **Official Documentation and Guides**: Visit [eoAPI's website](https://eoapi.dev/) for comprehensive documentation and guides on deploying and using the framework.\n", + "- **GitHub Repository**: Check out the [eoAPI GitHub repository](https://github.com/developmentseed/eoapi) for source code, updates, and community contributions.\n", + "\n", + "We'll delve into effectively utilizing eoAPI with STAC and COGs as we proceed." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## eoAPI in Action - Kahramanmaras Earthquakes\n", + "\n", + "### Background\n", + "\n", + "This section will review the different [eoAPI](https://github.com/developmentseed/eoAPI) services using the latest Open data from Maxar acquired for the M7.8 and M7.5 Kahramanmaras earthquakes in Turkey on February 6, 2023. For more information on the event, visit [USGS' article](https://www.usgs.gov/news/featured-story/m78-and-m75-kahramanmaras-earthquake-sequence-near-nurdagi-turkey-turkiye)\n", + "\n", + "Maxar provides pre and post-event high-resolution satellite imagery in support of emergency planning, risk assessment, monitoring of staging areas and emergency response, damage assessment, and recovery. These images are generated using the Maxar ARD pipeline, tiled on an organized grid in analysis-ready cloud-optimized formats.\n", + "\n", + "Maxar releases open data for select sudden-onset major crisis events. In addition to making the formatted COG data freely available on AWS, they also add static STAC metadata alongside the images. Having the STAC items already created makes ingestion into the PgSTAC database easy because we don't have to produce the items ourselves and read the images.\n", + "\n", + "To learn more about ingesting the Maxar OpenData STAC catalog into PgSTAC, see https://github.com/vincentsarago/MAXAR_opendata_to_pgstac.\n", + "\n", + "### Structure of eoAPI in Action\n", + "\n", + "0. Setting Up\n", + "1. How to query STAC\n", + " - How to query Collections\n", + " - How to query Items\n", + "3. Visualizing an Asset\n", + "5. Comparing pre and post events\n", + " - Finding pre and post event Items\n", + " - Visualizing pre and post event Mosaics" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Setting Up\n", + "\n", + "Before we start querying the STAC endpoint, there are a few setup steps to ensure that our environment has all the necessary tools and libraries. This section will guide you through installing the required packages and importing essential modules.\n", + "\n", + "We must install two packages: **`httpx`** for making HTTP requests and **`ipyleaflet`** for interactive mapping in Jupyter notebooks.\n", + "\n", + "Run the following command in your Jupyter Notebook to install these packages:" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "import IPython\n", + "!python -m pip install httpx ipyleaflet\n", + "IPython.display.clear_output(wait=False)\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This command uses pip, Python's package installer, to download and install the **`httpx`** and **`ipyleaflet`** packages from the Python Package Index (PyPI).\n", + "\n", + "### Importing Modules\n", + "\n", + "After installing the necessary packages, we need to import some standard and installed modules that will be used throughout our queries. The following Python code imports these modules:" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "from datetime import datetime\n", + "import json\n", + "\n", + "import httpx\n", + "import ipyleaflet" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **`datetime`**: This module from Python's standard library works with dates and times. It's especially useful when dealing with time-based geospatial data.\n", + "- **`json`**: This module is used for JSON data handling. Since responses from STAC endpoints are typically in JSON format, this module is crucial for parsing and processing these responses.\n", + "- **`httpx`**: A powerful and user-friendly HTTP client for Python. We will use it to send requests to the STAC endpoint.\n", + "- **`ipyleaflet`**: A library for creating interactive maps in Jupyter notebooks. It's beneficial for visualizing geospatial data on a map.\n", + "\n", + "Ensure that all imports run successfully. Double-check that the required packages are installed correctly if there are any issues." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### How to Query STAC\n", + "\n", + "The SpatioTemporal Asset Catalog (STAC) provides a standardized way to expose geospatial data and metadata. This section will explore how to query the STAC endpoint.\n", + "\n", + "The demo eoAPI STAC endpoint available at:" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "stac_endpoint = \"https://stac.eoapi.dev\"" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### How to Query STAC Collections\n", + "\n", + "Collections in STAC represent higher-level groupings under which items (geospatial datasets) are associated. These collections are folders containing related items. To start querying, we'll focus on these collections to understand the types of data available.\n", + "\n", + "To query collections, we can use `httpx` to use a HTTP GET request to the **`/collections`** endpoint. To give you an overview of the STAC specification, here's what the first Collection of the requests looks like in its JSON format:" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'id': 'MAXAR_BayofBengal_Cyclone_Mocha_May_23',\n", + " 'type': 'Collection',\n", + " 'links': [{'rel': 'items',\n", + " 'type': 'application/geo+json',\n", + " 'href': 'https://stac.eoapi.dev/collections/MAXAR_BayofBengal_Cyclone_Mocha_May_23/items'},\n", + " {'rel': 'parent',\n", + " 'type': 'application/json',\n", + " 'href': 'https://stac.eoapi.dev/'},\n", + " {'rel': 'root',\n", + " 'type': 'application/json',\n", + " 'href': 'https://stac.eoapi.dev/'},\n", + " {'rel': 'self',\n", + " 'type': 'application/json',\n", + " 'href': 'https://stac.eoapi.dev/collections/MAXAR_BayofBengal_Cyclone_Mocha_May_23'}],\n", + " 'extent': {'spatial': {'bbox': [[91.831615,\n", + " 19.984656587012033,\n", + " 92.97426268500965,\n", + " 21.666101],\n", + " [92.75855246040959,\n", + " 19.982078842323997,\n", + " 92.89682495377032,\n", + " 20.514473160464657],\n", + " [91.831615, 21.518411, 91.957078, 21.666101]]},\n", + " 'temporal': {'interval': [['2023-01-03T04:30:17Z',\n", + " '2023-03-14T04:30:25Z']]}},\n", + " 'license': 'proprietary',\n", + " 'description': 'Maxar OpenData | BayofBengal Cyclone Mocha May 23',\n", + " 'item_assets': {'visual': {'type': 'image/tiff; application=geotiff; profile=cloud-optimized',\n", + " 'roles': ['visual'],\n", + " 'title': 'Visual Image'},\n", + " 'data-mask': {'type': 'application/geopackage+sqlite3',\n", + " 'roles': ['data-mask'],\n", + " 'title': 'Data Mask'},\n", + " 'ms_analytic': {'type': 'image/tiff; application=geotiff; profile=cloud-optimized',\n", + " 'roles': ['data'],\n", + " 'title': 'Multispectral Image'},\n", + " 'pan_analytic': {'type': 'image/tiff; application=geotiff; profile=cloud-optimized',\n", + " 'roles': ['data'],\n", + " 'title': 'Panchromatic Image'}},\n", + " 'stac_version': '1.0.0',\n", + " 'stac_extensions': ['https://stac-extensions.github.io/item-assets/v1.0.0/schema.json']}" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "collections = httpx.get(f\"{stac_endpoint}/collections\").json()\n", + "collections[\"collections\"][0]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, there are many more collections available through the STAC endpoint. We can list the available collections by their `id`:" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['MAXAR_BayofBengal_Cyclone_Mocha_May_23',\n", + " 'MAXAR_Emilia_Romagna_Italy_flooding_may23',\n", + " 'MAXAR_Gambia_flooding_8_11_2022',\n", + " 'MAXAR_Marshall_Fire_21_Update',\n", + " 'MAXAR_Hurricane_Fiona_9_19_2022',\n", + " 'MAXAR_Hurricane_Ian_9_26_2022',\n", + " 'MAXAR_Indonesia_Earthquake22',\n", + " 'MAXAR_Kahramanmaras_turkey_earthquake_23',\n", + " 'MAXAR_Kalehe_DRC_Flooding_5_8_23',\n", + " 'MAXAR_volcano_indonesia21',\n", + " 'MAXAR_New_Zealand_Flooding22',\n", + " 'MAXAR_New_Zealand_Flooding23',\n", + " 'MAXAR_Sudan_flooding_8_22_2022',\n", + " 'MAXAR_afghanistan_earthquake22',\n", + " 'MAXAR_cyclone_emnati22',\n", + " 'MAXAR_ghana_explosion22',\n", + " 'MAXAR_kentucky_flooding_7_29_2022',\n", + " 'MAXAR_pakistan_flooding22',\n", + " 'MAXAR_southafrica_flooding22',\n", + " 'MAXAR_tonga_volcano21',\n", + " 'MAXAR_yellowstone_flooding22',\n", + " 'MAXAR_Maui_Hawaii_fires_Aug_23',\n", + " 'MAXAR_NWT_Canada_Aug_23',\n", + " 'MAXAR_shovi_georgia_landslide_8Aug23',\n", + " 'MAXAR_Hurricane_Idalia_Florida_Aug23',\n", + " 'MAXAR_Libya_Floods_Sept_2023',\n", + " 'MAXAR_McDougallCreekWildfire_BC_Canada_Aug_23',\n", + " 'MAXAR_Morocco_Earthquake_Sept_2023',\n", + " 'UMBRA_2023']" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[c['id'] for c in collections[\"collections\"]]" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For the following steps, we will be using the Kahramanmaras Earthquake collection. \n", + "\n", + "A key feature of STAC is spatial and temporal extents. It is slightly intricate, but a collection can have multiple spatial and temporal extents. By convention, the first extent is supposed to encapsulate all sub-extents. For the temporal extents, the first data interval must cover the entire date interval of the sub-extents. For spatial extents, the first bounding box must cover all other bounding boxes for spatial extents.\n", + "\n", + "However, the Maxar Collections do not follow this convention for spatial extents. Let's illustrate the structure for spatial extents and display them on a map:" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of spatial extents: 72\n", + "First spatial extent bounding box: \n", + " [35.32861203895262, 36.06630343440598, 38.45685512435119, 37.90150133428409]\n" + ] + } + ], + "source": [ + "collection_id = \"MAXAR_Kahramanmaras_turkey_earthquake_23\"\n", + "\n", + "collection_info = httpx.get(f\"{stac_endpoint}/collections/{collection_id}\").json()\n", + "bboxes = collection_info[\"extent\"][\"spatial\"][\"bbox\"]\n", + "print(f\"Number of spatial extents: {len(bboxes)}\")\n", + "print(f\"First spatial extent bounding box: \\n {bboxes[0]}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "aa5137dff01f4ba4ab2037cda29314ca", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Map(center=[36.983902384345036, 36.89273358165191], controls=(ZoomControl(options=['position', 'zoom_in_text',…" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "geojson = {\n", + " \"type\": \"FeatureCollection\",\n", + " \"features\": [\n", + " {\n", + " 'type': 'Feature',\n", + " 'geometry': {\n", + " 'type': 'Polygon',\n", + " 'coordinates': [[\n", + " [bbox[0], bbox[1]],\n", + " [bbox[2], bbox[1]],\n", + " [bbox[2], bbox[3]],\n", + " [bbox[0], bbox[3]],\n", + " [bbox[0], bbox[1]],\n", + " ]]\n", + " },\n", + " 'properties': {}\n", + " }\n", + " for bbox in bboxes\n", + " ]\n", + "}\n", + "\n", + "mainbbox = collection_info[\"extent\"][\"spatial\"][\"bbox\"][0]\n", + "\n", + "m = ipyleaflet.leaflet.Map(\n", + " center=((mainbbox[1] + mainbbox[3]) / 2,(mainbbox[0] + mainbbox[2]) / 2),\n", + " zoom=7\n", + ")\n", + "\n", + "geo_json = ipyleaflet.leaflet.GeoJSON(data=geojson)\n", + "m.add_layer(geo_json)\n", + "m" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's take a look into the temporal extent of the collection. In the case of Maxar's collections, there is a single temporal extent:" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of temporal extents: 1\n", + "Temporal extent: \n", + " ['2021-02-28T08:10:22Z', '2023-03-11T08:29:15Z']\n" + ] + } + ], + "source": [ + "temporal_extents = collection_info[\"extent\"][\"temporal\"]['interval']\n", + "print(f\"Number of temporal extents: {len(temporal_extents)}\")\n", + "print(f\"Temporal extent: \\n {temporal_extents[0]}\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### How to Query STAC Items\n", + "\n", + "Querying items in STAC (SpatioTemporal Asset Catalog) involves accessing individual datasets within a collection. Each item in a STAC collection represents a distinct spatiotemporal asset, such as a satellite image or geographical survey data. These items are the fundamental units of STAC, containing metadata and links to the actual data.\n", + "\n", + "To begin querying items, we must use the `id` of the collection under which the items are defined. To query the Kahramanmaras collection's items, we will use the following URL:" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'https://stac.eoapi.dev/collections/MAXAR_Kahramanmaras_turkey_earthquake_23/items'" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "collection_id = \"MAXAR_Kahramanmaras_turkey_earthquake_23\"\n", + "turkey_items_url = f\"{stac_endpoint}/collections/{collection_id}/items\"\n", + "turkey_items_url" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + " To provide a practical insight into the STAC specification and how it structures item data, let's examine the first item returned from a typical request:" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Item attributes: \n", + " id, bbox, type, links, assets, geometry, collection, properties, stac_version, stac_extensions\n", + "{\n", + " \"id\": \"37_031133210001_10300100E49E8000\",\n", + " \"bbox\": [\n", + " 36.387245559111236,\n", + " 36.092041667396806,\n", + " 36.42079643694594,\n", + " 36.11834923545021\n", + " ],\n", + " \"type\": \"Feature\",\n", + " \"links\": [\n", + " {\n", + " \"rel\": \"collection\",\n", + " \"type\": \"application/json\",\n", + " \"href\": \"https://stac.eoapi.dev/collections/MAXAR_Kahramanmaras_turkey_earthquake_23\"\n", + " },\n", + " {\n", + " \"rel\": \"parent\",\n", + " \"type\": \"application/json\",\n", + " \"href\": \"https://stac.eoapi.dev/collections/MAXAR_Kahramanmaras_turkey_earthquake_23\"\n", + " },\n", + " {\n", + " \"rel\": \"root\",\n", + " \"type\": \"application/json\",\n", + " \"href\": \"https://stac.eoapi.dev/\"\n", + " },\n", + " {\n", + " \"rel\": \"self\",\n", + " \"type\": \"application/geo+json\",\n", + " \"href\": \"https://stac.eoapi.dev/collections/MAXAR_Kahramanmaras_turkey_earthquake_23/items/37_031133210001_10300100E49E8000\"\n", + " }\n", + " ],\n", + " \"assets\": {\n", + " \"visual\": {\n", + " \"href\": \"s3://maxar-opendata/events/Kahramanmaras-turkey-earthquake-23/ard/37/031133210001/2023-03-11/10300100E49E8000-visual.tif\",\n", + " \"type\": \"image/tiff; application=geotiff; profile=cloud-optimized\",\n", + " \"roles\": [\n", + " \"visual\"\n", + " ],\n", + " \"title\": \"Visual Image\",\n", + " \"eo:bands\": [\n", + " {\n", + " \"name\": \"BAND_R\",\n", + " \"common_name\": \"red\",\n", + " \"description\": \"Red\"\n", + " },\n", + " {\n", + " \"name\": \"BAND_G\",\n", + " \"common_name\": \"green\",\n", + " \"description\": \"Green\"\n", + " },\n", + " {\n", + " \"name\": \"BAND_B\",\n", + " \"common_name\": \"blue\",\n", + " \"description\": \"Blue\"\n", + " }\n", + " ],\n", + " \"alternate\": {\n", + " \"public\": {\n", + " \"href\": \"https://maxar-opendata.s3.amazonaws.com/events/Kahramanmaras-turkey-earthquake-23/ard/37/031133210001/2023-03-11/10300100E49E8000-visual.tif\",\n", + " \"title\": \"Public Access\"\n", + " }\n", + " },\n", + " \"proj:bbox\": [\n", + " 264843.75,\n", + " 3994843.75,\n", + " 270156.25,\n", + " 4000156.25\n", + " ],\n", + " \"proj:shape\": [\n", + " 17408,\n", + " 17408\n", + " ],\n", + " \"proj:transform\": [\n", + " 0.30517578125,\n", + " 0.0,\n", + " 264843.75,\n", + " 0.0,\n", + " -0.30517578125,\n", + " 4000156.25,\n", + " 0.0,\n", + " 0.0,\n", + " 1.0\n", + " ]\n", + " },\n", + " \"data-mask\": {\n", + " \"href\": \"s3://maxar-opendata/events/Kahramanmaras-turkey-earthquake-23/ard/37/031133210001/2023-03-11/10300100E49E8000-data-mask.gpkg\",\n", + " \"type\": \"application/geopackage+sqlite3\",\n", + " \"roles\": [\n", + " \"data-mask\"\n", + " ],\n", + " \"title\": \"Data Mask\",\n", + " \"alternate\": {\n", + " \"public\": {\n", + " \"href\": \"https://maxar-opendata.s3.amazonaws.com/events/Kahramanmaras-turkey-earthquake-23/ard/37/031133210001/2023-03-11/10300100E49E8000-data-mask.gpkg\",\n", + " \"title\": \"Public Access\"\n", + " }\n", + " }\n", + " },\n", + " \"ms_analytic\": {\n", + " \"href\": \"s3://maxar-opendata/events/Kahramanmaras-turkey-earthquake-23/ard/37/031133210001/2023-03-11/10300100E49E8000-ms.tif\",\n", + " \"type\": \"image/tiff; application=geotiff; profile=cloud-optimized\",\n", + " \"roles\": [\n", + " \"data\"\n", + " ],\n", + " \"title\": \"Multispectral Image\",\n", + " \"eo:bands\": [\n", + " {\n", + " \"name\": \"BAND_C\",\n", + " \"common_name\": \"coastal\",\n", + " \"description\": \"Coastal Blue\"\n", + " },\n", + " {\n", + " \"name\": \"BAND_B\",\n", + " \"common_name\": \"blue\",\n", + " \"description\": \"Blue\"\n", + " },\n", + " {\n", + " \"name\": \"BAND_G\",\n", + " \"common_name\": \"green\",\n", + " \"description\": \"Green\"\n", + " },\n", + " {\n", + " \"name\": \"BAND_Y\",\n", + " \"common_name\": \"yellow\",\n", + " \"description\": \"Yellow\"\n", + " },\n", + " {\n", + " \"name\": \"BAND_R\",\n", + " \"common_name\": \"red\",\n", + " \"description\": \"Red\"\n", + " },\n", + " {\n", + " \"name\": \"BAND_RE\",\n", + " \"common_name\": \"rededge\",\n", + " \"description\": \"Red Edge 1\"\n", + " },\n", + " {\n", + " \"name\": \"BAND_N\",\n", + " \"common_name\": \"nir08\",\n", + " \"description\": \"Near Infrared 1\"\n", + " },\n", + " {\n", + " \"name\": \"BAND_N2\",\n", + " \"common_name\": \"nir09\",\n", + " \"description\": \"Near Infrared 2\"\n", + " }\n", + " ],\n", + " \"alternate\": {\n", + " \"public\": {\n", + " \"href\": \"https://maxar-opendata.s3.amazonaws.com/events/Kahramanmaras-turkey-earthquake-23/ard/37/031133210001/2023-03-11/10300100E49E8000-ms.tif\",\n", + " \"title\": \"Public Access\"\n", + " }\n", + " },\n", + " \"proj:bbox\": [\n", + " 264843.75,\n", + " 3994843.75,\n", + " 270156.25,\n", + " 4000156.25\n", + " ],\n", + " \"proj:shape\": [\n", + " 2779,\n", + " 2779\n", + " ],\n", + " \"proj:transform\": [\n", + " 1.9116588700971573,\n", + " 0.0,\n", + " 264843.75,\n", + " 0.0,\n", + " -1.9116588700971573,\n", + " 4000156.25,\n", + " 0.0,\n", + " 0.0,\n", + " 1.0\n", + " ]\n", + " },\n", + " \"pan_analytic\": {\n", + " \"href\": \"s3://maxar-opendata/events/Kahramanmaras-turkey-earthquake-23/ard/37/031133210001/2023-03-11/10300100E49E8000-pan.tif\",\n", + " \"type\": \"image/tiff; application=geotiff; profile=cloud-optimized\",\n", + " \"roles\": [\n", + " \"data\"\n", + " ],\n", + " \"title\": \"Panchromatic Image\",\n", + " \"eo:bands\": [\n", + " {\n", + " \"name\": \"BAND_P\",\n", + " \"description\": \"Pan\"\n", + " }\n", + " ],\n", + " \"alternate\": {\n", + " \"public\": {\n", + " \"href\": \"https://maxar-opendata.s3.amazonaws.com/events/Kahramanmaras-turkey-earthquake-23/ard/37/031133210001/2023-03-11/10300100E49E8000-pan.tif\",\n", + " \"title\": \"Public Access\"\n", + " }\n", + " },\n", + " \"proj:bbox\": [\n", + " 264843.75,\n", + " 3994843.75,\n", + " 270156.25,\n", + " 4000156.25\n", + " ],\n", + " \"proj:shape\": [\n", + " 11116,\n", + " 11116\n", + " ],\n", + " \"proj:transform\": [\n", + " 0.4779147175242893,\n", + " 0.0,\n", + " 264843.75,\n", + " 0.0,\n", + " -0.4779147175242893,\n", + " 4000156.25,\n", + " 0.0,\n", + " 0.0,\n", + " 1.0\n", + " ]\n", + " }\n", + " },\n", + " \"geometry\": {\n", + " \"type\": \"Polygon\",\n", + " \"coordinates\": [\n", + " [\n", + " [\n", + " 36.387245559111236,\n", + " 36.11762172115687\n", + " ],\n", + " [\n", + " 36.38807914445892,\n", + " 36.09246165938945\n", + " ],\n", + " [\n", + " 36.40855030738972,\n", + " 36.09229578729594\n", + " ],\n", + " [\n", + " 36.420731654920246,\n", + " 36.092041667396806\n", + " ],\n", + " [\n", + " 36.42079643694594,\n", + " 36.11834923545021\n", + " ],\n", + " [\n", + " 36.387245559111236,\n", + " 36.11762172115687\n", + " ]\n", + " ]\n", + " ]\n", + " },\n", + " \"collection\": \"MAXAR_Kahramanmaras_turkey_earthquake_23\",\n", + " \"properties\": {\n", + " \"gsd\": 0.48,\n", + " \"quadkey\": \"031133210001\",\n", + " \"datetime\": \"2023-03-11T08:29:15Z\",\n", + " \"platform\": \"WV02\",\n", + " \"utm_zone\": 37,\n", + " \"grid:code\": \"MXRA-Z37-031133210001\",\n", + " \"proj:bbox\": [\n", + " 264843.75,\n", + " 3997237.548828125,\n", + " 267866.2109375,\n", + " 4000156.25\n", + " ],\n", + " \"proj:epsg\": 32637,\n", + " \"catalog_id\": \"10300100E49E8000\",\n", + " \"view:azimuth\": 175.5,\n", + " \"proj:geometry\": {\n", + " \"type\": \"Polygon\",\n", + " \"coordinates\": [\n", + " [\n", + " [\n", + " 264843.75,\n", + " 4000156.25\n", + " ],\n", + " [\n", + " 264843.75,\n", + " 3997362.6708984375\n", + " ],\n", + " [\n", + " 266686.70654296875,\n", + " 3997294.921875\n", + " ],\n", + " [\n", + " 267782.89794921875,\n", + " 3997237.548828125\n", + " ],\n", + " [\n", + " 267866.2109375,\n", + " 4000156.25\n", + " ],\n", + " [\n", + " 264843.75,\n", + " 4000156.25\n", + " ]\n", + " ]\n", + " ]\n", + " },\n", + " \"tile:data_area\": 8.5,\n", + " \"view:off_nadir\": 12.4,\n", + " \"tile:clouds_area\": 0.0,\n", + " \"view:sun_azimuth\": 152.0,\n", + " \"view:sun_elevation\": 46.5,\n", + " \"tile:clouds_percent\": 0,\n", + " \"ard_metadata_version\": \"0.0.1\",\n", + " \"view:incidence_angle\": 76.1\n", + " },\n", + " \"stac_version\": \"1.0.0\",\n", + " \"stac_extensions\": [\n", + " \"https://stac-extensions.github.io/view/v1.0.0/schema.json\",\n", + " \"https://stac-extensions.github.io/projection/v1.0.0/schema.json\",\n", + " \"https://stac-extensions.github.io/eo/v1.0.0/schema.json\",\n", + " \"https://stac-extensions.github.io/raster/v1.1.0/schema.json\",\n", + " \"https://stac-extensions.github.io/grid/v1.0.0/schema.json\",\n", + " \"https://stac-extensions.github.io/alternate-assets/v1.1.0/schema.json\"\n", + " ]\n", + "}\n" + ] + } + ], + "source": [ + "items = httpx.get(turkey_items_url).json() \n", + "print(f\"Item attributes: \\n {', '.join(items['features'][0].keys())}\")\n", + "print(json.dumps(items['features'][0], indent=4))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For our purposes, we are focusing on the essential components of a STAC item. Here's a concise description of the key elements that are most relevant:\n", + "\n", + "- ID (`id`): This is the unique identifier of the STAC item, crucial for referencing and retrieving the specific asset within its collection.\n", + "- Bounding Box (`bbox`): This field defines the geographical bounds of the item, typically as an array representing the minimum and maximum coordinates (longitude and latitude) that encompass the asset.\n", + "- Properties (`properties`): This segment contains important metadata about the item, such as the acquisition date, sensor type, and other descriptive information specific to the asset.\n", + "- Links (`links`): Links are an array of objects that provide hyperlinks related to the item. These links can direct to the item itself, its parent collection, related items, and other URLs for data access or further details.\n", + "- Assets (`assets`): Assets are pointers to the actual data files associated with the item, such as images or data files. They contain URLs and metadata for each file, enabling access to the spatial data.\n", + "\n", + "While these are the key components for our analysis, it's important to note that there are additional elements in the STAC item output, such as the STAC version (`stac_version`) and STAC extensions (`stac_extensions`). These provide information about the version of the STAC specification used and any extensions enabled for the item, respectively. " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Before diving into more advanced item queries, let's get a sens of the number of items within the collection. `STAC-FastAPI` will only return the first 10 items of collection by default:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Returned Items in JSON: 10\n" + ] + }, + { + "data": { + "text/plain": [ + "{'limit': 10, 'matched': 2115, 'returned': 10}" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "items = httpx.get(turkey_items_url).json()\n", + "print(f\"Returned Items in JSON: {len(items['features'])}\")\n", + "items['context']" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To retrieve the JSON of every item, we must incorporate the paging mechanism of `STAC-FastAPI` with the `limit` parameter. The mechanics are slightly intricate regarding retrieving the next link.\n", + "\n", + "\n", + "> *Note: if summary statistics like the number of items are important, you may enable the `context` variable within `PgSTAC.` With the option enabled, the `items['context']` will contain the number of `matched` Items.*" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Actual Number of Items: 2115\n" + ] + } + ], + "source": [ + "turkey_items = []\n", + "\n", + "url = turkey_items_url\n", + "while True:\n", + " items = httpx.get(url, params={\"limit\": 200}).json()\n", + " \n", + " turkey_items.extend(items[\"features\"])\n", + " next_link = list(filter(lambda link: link[\"rel\"] == \"next\", items[\"links\"]))\n", + " if next_link:\n", + " url = next_link[0][\"href\"]\n", + " else:\n", + " break\n", + "\n", + "print(f\"Actual Number of Items: {len(turkey_items)}\")\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With all the items, we can start visualizing some important details that will help with our pre and post event analysis. The code block below generates a heatmap of the STAC items where we fill the color of pre-event Items with Blue and post-event Items with Red. " + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "bd72e4f9defa439d8f58120c75efcbf4", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Map(center=[36.983902384345036, 36.89273358165191], controls=(ZoomControl(options=['position', 'zoom_in_text',…" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m = ipyleaflet.leaflet.Map(\n", + " center=((mainbbox[1] + mainbbox[3]) / 2,(mainbbox[0] + mainbbox[2]) / 2),\n", + " zoom=7\n", + ")\n", + "\n", + "event_date = datetime(2023, 2, 6, hour=0, minute=0)\n", + "\n", + "# Use a styling function to show where we have before/after items\n", + "def style_function(feature):\n", + " d = datetime.strptime(feature[\"properties\"][\"datetime\"], \"%Y-%m-%dT%H:%M:%SZ\")\n", + " return {\n", + " \"fillOpacity\": 0.1,\n", + " \"weight\": 0.1,\n", + " # Blue for pre-event / red for post-event\n", + " \"fillColor\": \"#0000ff\" if d < event_date else \"#ff0000\"\n", + " }\n", + "\n", + "geojson = ipyleaflet.leaflet.GeoJSON(data={\"type\": \"FeatureCollection\", \"features\": turkey_items}, style_callback=style_function)\n", + "m.add_layer(geojson)\n", + "m" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualizing an Asset\n", + "\n", + "So far, all we've been utilizing is the `stac-fastapi` endpoint to query Collections and Items. We will now dive into how to visualize some of the underlying data associated with Items.\n", + "\n", + "Here's where the magic with eoAPI happens. Within eoAPI capabilities, is a raster API that is directly connected to the `pgSTAC` database that contains our STAC metadata via `titiler-pgstac`. The raster service leverages `TiTiler` to help us visualize the associated assets of a single, or as we will see, multiple STAC items. The demo raster endpoint is accessible via:" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [], + "source": [ + "raster_endpoint = \"https://raster.eoapi.dev\"" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As previously mentionned, Items have an `asset` attribute which links to the underlying datasets and resources of the item. Let's revisit the assets of an item in our Turkey examples:" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['visual', 'data-mask', 'ms_analytic', 'pan_analytic']\n", + "{\n", + " \"href\": \"s3://maxar-opendata/events/Kahramanmaras-turkey-earthquake-23/ard/37/031133032132/2022-10-10/10300100DB913300-visual.tif\",\n", + " \"type\": \"image/tiff; application=geotiff; profile=cloud-optimized\",\n", + " \"roles\": [\n", + " \"visual\"\n", + " ],\n", + " \"title\": \"Visual Image\",\n", + " \"eo:bands\": [\n", + " {\n", + " \"name\": \"BAND_R\",\n", + " \"common_name\": \"red\",\n", + " \"description\": \"Red\"\n", + " },\n", + " {\n", + " \"name\": \"BAND_G\",\n", + " \"common_name\": \"green\",\n", + " \"description\": \"Green\"\n", + " },\n", + " {\n", + " \"name\": \"BAND_B\",\n", + " \"common_name\": \"blue\",\n", + " \"description\": \"Blue\"\n", + " }\n", + " ],\n", + " \"alternate\": {\n", + " \"public\": {\n", + " \"href\": \"https://maxar-opendata.s3.amazonaws.com/events/Kahramanmaras-turkey-earthquake-23/ard/37/031133032132/2022-10-10/10300100DB913300-visual.tif\",\n", + " \"title\": \"Public Access\"\n", + " }\n", + " },\n", + " \"proj:bbox\": [\n", + " 289843.75,\n", + " 4019843.75,\n", + " 295156.25,\n", + " 4025156.25\n", + " ],\n", + " \"proj:shape\": [\n", + " 17408,\n", + " 17408\n", + " ],\n", + " \"proj:transform\": [\n", + " 0.30517578125,\n", + " 0.0,\n", + " 289843.75,\n", + " 0.0,\n", + " -0.30517578125,\n", + " 4025156.25,\n", + " 0.0,\n", + " 0.0,\n", + " 1.0\n", + " ]\n", + "}\n", + "visual : image/tiff; application=geotiff; profile=cloud-optimized\n", + "data-mask : application/geopackage+sqlite3\n", + "ms_analytic : image/tiff; application=geotiff; profile=cloud-optimized\n", + "pan_analytic : image/tiff; application=geotiff; profile=cloud-optimized\n" + ] + } + ], + "source": [ + "item = items[\"features\"][0]\n", + "\n", + "print(list(item[\"assets\"].keys()))\n", + "print(json.dumps(item[\"assets\"][\"visual\"], indent=4))\n", + "\n", + "for name, asset in item[\"assets\"].items():\n", + " print(name, \": \", asset[\"type\"])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each Item of Maxar's collection has four assets, and three are cloud-optimized! Here's how we can use the raster API to visualize them.\n", + "\n", + "First, we must retrieve the Raster metadata for each Raster asset. The raster API will default filter non-raster datasets using the asset's `type` metadata. In the example below, we are fetching the metadata for the `visual`, `ms_analytic`, and `pan_analytic` because these assets have a cloud-optimized type:" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "ename": "ReadTimeout", + "evalue": "The read operation timed out", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTimeoutError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpcore/_exceptions.py:10\u001b[0m, in \u001b[0;36mmap_exceptions\u001b[0;34m(map)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[0;32m---> 10\u001b[0m \u001b[39myield\u001b[39;00m\n\u001b[1;32m 11\u001b[0m \u001b[39mexcept\u001b[39;00m \u001b[39mException\u001b[39;00m \u001b[39mas\u001b[39;00m exc: \u001b[39m# noqa: PIE786\u001b[39;00m\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpcore/_backends/sync.py:28\u001b[0m, in \u001b[0;36mSyncStream.read\u001b[0;34m(self, max_bytes, timeout)\u001b[0m\n\u001b[1;32m 27\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_sock\u001b[39m.\u001b[39msettimeout(timeout)\n\u001b[0;32m---> 28\u001b[0m \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_sock\u001b[39m.\u001b[39;49mrecv(max_bytes)\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/ssl.py:1259\u001b[0m, in \u001b[0;36mSSLSocket.recv\u001b[0;34m(self, buflen, flags)\u001b[0m\n\u001b[1;32m 1256\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mValueError\u001b[39;00m(\n\u001b[1;32m 1257\u001b[0m \u001b[39m\"\u001b[39m\u001b[39mnon-zero flags not allowed in calls to recv() on \u001b[39m\u001b[39m%s\u001b[39;00m\u001b[39m\"\u001b[39m \u001b[39m%\u001b[39m\n\u001b[1;32m 1258\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m\u001b[39m__class__\u001b[39m)\n\u001b[0;32m-> 1259\u001b[0m \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mread(buflen)\n\u001b[1;32m 1260\u001b[0m \u001b[39melse\u001b[39;00m:\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/ssl.py:1132\u001b[0m, in \u001b[0;36mSSLSocket.read\u001b[0;34m(self, len, buffer)\u001b[0m\n\u001b[1;32m 1131\u001b[0m \u001b[39melse\u001b[39;00m:\n\u001b[0;32m-> 1132\u001b[0m \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_sslobj\u001b[39m.\u001b[39;49mread(\u001b[39mlen\u001b[39;49m)\n\u001b[1;32m 1133\u001b[0m \u001b[39mexcept\u001b[39;00m SSLError \u001b[39mas\u001b[39;00m x:\n", + "\u001b[0;31mTimeoutError\u001b[0m: The read operation timed out", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[0;31mReadTimeout\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpx/_transports/default.py:60\u001b[0m, in \u001b[0;36mmap_httpcore_exceptions\u001b[0;34m()\u001b[0m\n\u001b[1;32m 59\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[0;32m---> 60\u001b[0m \u001b[39myield\u001b[39;00m\n\u001b[1;32m 61\u001b[0m \u001b[39mexcept\u001b[39;00m \u001b[39mException\u001b[39;00m \u001b[39mas\u001b[39;00m exc: \u001b[39m# noqa: PIE-786\u001b[39;00m\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpx/_transports/default.py:218\u001b[0m, in \u001b[0;36mHTTPTransport.handle_request\u001b[0;34m(self, request)\u001b[0m\n\u001b[1;32m 217\u001b[0m \u001b[39mwith\u001b[39;00m map_httpcore_exceptions():\n\u001b[0;32m--> 218\u001b[0m resp \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_pool\u001b[39m.\u001b[39;49mhandle_request(req)\n\u001b[1;32m 220\u001b[0m \u001b[39massert\u001b[39;00m \u001b[39misinstance\u001b[39m(resp\u001b[39m.\u001b[39mstream, typing\u001b[39m.\u001b[39mIterable)\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpcore/_sync/connection_pool.py:262\u001b[0m, in \u001b[0;36mConnectionPool.handle_request\u001b[0;34m(self, request)\u001b[0m\n\u001b[1;32m 261\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mresponse_closed(status)\n\u001b[0;32m--> 262\u001b[0m \u001b[39mraise\u001b[39;00m exc\n\u001b[1;32m 263\u001b[0m \u001b[39melse\u001b[39;00m:\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpcore/_sync/connection_pool.py:245\u001b[0m, in \u001b[0;36mConnectionPool.handle_request\u001b[0;34m(self, request)\u001b[0m\n\u001b[1;32m 244\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[0;32m--> 245\u001b[0m response \u001b[39m=\u001b[39m connection\u001b[39m.\u001b[39;49mhandle_request(request)\n\u001b[1;32m 246\u001b[0m \u001b[39mexcept\u001b[39;00m ConnectionNotAvailable:\n\u001b[1;32m 247\u001b[0m \u001b[39m# The ConnectionNotAvailable exception is a special case, that\u001b[39;00m\n\u001b[1;32m 248\u001b[0m \u001b[39m# indicates we need to retry the request on a new connection.\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 252\u001b[0m \u001b[39m# might end up as an HTTP/2 connection, but which actually ends\u001b[39;00m\n\u001b[1;32m 253\u001b[0m \u001b[39m# up as HTTP/1.1.\u001b[39;00m\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpcore/_sync/connection.py:96\u001b[0m, in \u001b[0;36mHTTPConnection.handle_request\u001b[0;34m(self, request)\u001b[0m\n\u001b[1;32m 94\u001b[0m \u001b[39mraise\u001b[39;00m ConnectionNotAvailable()\n\u001b[0;32m---> 96\u001b[0m \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_connection\u001b[39m.\u001b[39;49mhandle_request(request)\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpcore/_sync/http11.py:121\u001b[0m, in \u001b[0;36mHTTP11Connection.handle_request\u001b[0;34m(self, request)\u001b[0m\n\u001b[1;32m 120\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_response_closed()\n\u001b[0;32m--> 121\u001b[0m \u001b[39mraise\u001b[39;00m exc\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpcore/_sync/http11.py:99\u001b[0m, in \u001b[0;36mHTTP11Connection.handle_request\u001b[0;34m(self, request)\u001b[0m\n\u001b[1;32m 91\u001b[0m \u001b[39mwith\u001b[39;00m Trace(\n\u001b[1;32m 92\u001b[0m \u001b[39m\"\u001b[39m\u001b[39mreceive_response_headers\u001b[39m\u001b[39m\"\u001b[39m, logger, request, kwargs\n\u001b[1;32m 93\u001b[0m ) \u001b[39mas\u001b[39;00m trace:\n\u001b[1;32m 94\u001b[0m (\n\u001b[1;32m 95\u001b[0m http_version,\n\u001b[1;32m 96\u001b[0m status,\n\u001b[1;32m 97\u001b[0m reason_phrase,\n\u001b[1;32m 98\u001b[0m headers,\n\u001b[0;32m---> 99\u001b[0m ) \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_receive_response_headers(\u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs)\n\u001b[1;32m 100\u001b[0m trace\u001b[39m.\u001b[39mreturn_value \u001b[39m=\u001b[39m (\n\u001b[1;32m 101\u001b[0m http_version,\n\u001b[1;32m 102\u001b[0m status,\n\u001b[1;32m 103\u001b[0m reason_phrase,\n\u001b[1;32m 104\u001b[0m headers,\n\u001b[1;32m 105\u001b[0m )\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpcore/_sync/http11.py:164\u001b[0m, in \u001b[0;36mHTTP11Connection._receive_response_headers\u001b[0;34m(self, request)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[39mwhile\u001b[39;00m \u001b[39mTrue\u001b[39;00m:\n\u001b[0;32m--> 164\u001b[0m event \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_receive_event(timeout\u001b[39m=\u001b[39;49mtimeout)\n\u001b[1;32m 165\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39misinstance\u001b[39m(event, h11\u001b[39m.\u001b[39mResponse):\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpcore/_sync/http11.py:200\u001b[0m, in \u001b[0;36mHTTP11Connection._receive_event\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m 199\u001b[0m \u001b[39mif\u001b[39;00m event \u001b[39mis\u001b[39;00m h11\u001b[39m.\u001b[39mNEED_DATA:\n\u001b[0;32m--> 200\u001b[0m data \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_network_stream\u001b[39m.\u001b[39;49mread(\n\u001b[1;32m 201\u001b[0m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mREAD_NUM_BYTES, timeout\u001b[39m=\u001b[39;49mtimeout\n\u001b[1;32m 202\u001b[0m )\n\u001b[1;32m 204\u001b[0m \u001b[39m# If we feed this case through h11 we'll raise an exception like:\u001b[39;00m\n\u001b[1;32m 205\u001b[0m \u001b[39m#\u001b[39;00m\n\u001b[1;32m 206\u001b[0m \u001b[39m# httpcore.RemoteProtocolError: can't handle event type\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 210\u001b[0m \u001b[39m# perspective. Instead we handle this case distinctly and treat\u001b[39;00m\n\u001b[1;32m 211\u001b[0m \u001b[39m# it as a ConnectError.\u001b[39;00m\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpcore/_backends/sync.py:26\u001b[0m, in \u001b[0;36mSyncStream.read\u001b[0;34m(self, max_bytes, timeout)\u001b[0m\n\u001b[1;32m 25\u001b[0m exc_map: ExceptionMapping \u001b[39m=\u001b[39m {socket\u001b[39m.\u001b[39mtimeout: ReadTimeout, \u001b[39mOSError\u001b[39;00m: ReadError}\n\u001b[0;32m---> 26\u001b[0m \u001b[39mwith\u001b[39;00m map_exceptions(exc_map):\n\u001b[1;32m 27\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_sock\u001b[39m.\u001b[39msettimeout(timeout)\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/contextlib.py:153\u001b[0m, in \u001b[0;36m_GeneratorContextManager.__exit__\u001b[0;34m(self, typ, value, traceback)\u001b[0m\n\u001b[1;32m 152\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[0;32m--> 153\u001b[0m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mgen\u001b[39m.\u001b[39;49mthrow(typ, value, traceback)\n\u001b[1;32m 154\u001b[0m \u001b[39mexcept\u001b[39;00m \u001b[39mStopIteration\u001b[39;00m \u001b[39mas\u001b[39;00m exc:\n\u001b[1;32m 155\u001b[0m \u001b[39m# Suppress StopIteration *unless* it's the same exception that\u001b[39;00m\n\u001b[1;32m 156\u001b[0m \u001b[39m# was passed to throw(). This prevents a StopIteration\u001b[39;00m\n\u001b[1;32m 157\u001b[0m \u001b[39m# raised inside the \"with\" statement from being suppressed.\u001b[39;00m\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpcore/_exceptions.py:14\u001b[0m, in \u001b[0;36mmap_exceptions\u001b[0;34m(map)\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39misinstance\u001b[39m(exc, from_exc):\n\u001b[0;32m---> 14\u001b[0m \u001b[39mraise\u001b[39;00m to_exc(exc) \u001b[39mfrom\u001b[39;00m \u001b[39mexc\u001b[39;00m\n\u001b[1;32m 15\u001b[0m \u001b[39mraise\u001b[39;00m\n", + "\u001b[0;31mReadTimeout\u001b[0m: The read operation timed out", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[0;31mReadTimeout\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[49], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m item_id \u001b[39m=\u001b[39m item[\u001b[39m\"\u001b[39m\u001b[39mid\u001b[39m\u001b[39m\"\u001b[39m]\n\u001b[0;32m----> 3\u001b[0m info \u001b[39m=\u001b[39m httpx\u001b[39m.\u001b[39;49mget(\u001b[39mf\u001b[39;49m\u001b[39m\"\u001b[39;49m\u001b[39m{\u001b[39;49;00mraster_endpoint\u001b[39m}\u001b[39;49;00m\u001b[39m/collections/\u001b[39;49m\u001b[39m{\u001b[39;49;00mcollection_id\u001b[39m}\u001b[39;49;00m\u001b[39m/items/\u001b[39;49m\u001b[39m{\u001b[39;49;00mitem_id\u001b[39m}\u001b[39;49;00m\u001b[39m/info\u001b[39;49m\u001b[39m\"\u001b[39;49m)\u001b[39m.\u001b[39mjson()\n\u001b[1;32m 5\u001b[0m \u001b[39mprint\u001b[39m(json\u001b[39m.\u001b[39mdumps(info[\u001b[39m\"\u001b[39m\u001b[39mvisual\u001b[39m\u001b[39m\"\u001b[39m], indent\u001b[39m=\u001b[39m\u001b[39m4\u001b[39m))\n\u001b[1;32m 7\u001b[0m \u001b[39mfor\u001b[39;00m name, asset \u001b[39min\u001b[39;00m info\u001b[39m.\u001b[39mitems():\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpx/_api.py:189\u001b[0m, in \u001b[0;36mget\u001b[0;34m(url, params, headers, cookies, auth, proxies, follow_redirects, cert, verify, timeout, trust_env)\u001b[0m\n\u001b[1;32m 167\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mget\u001b[39m(\n\u001b[1;32m 168\u001b[0m url: URLTypes,\n\u001b[1;32m 169\u001b[0m \u001b[39m*\u001b[39m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 179\u001b[0m trust_env: \u001b[39mbool\u001b[39m \u001b[39m=\u001b[39m \u001b[39mTrue\u001b[39;00m,\n\u001b[1;32m 180\u001b[0m ) \u001b[39m-\u001b[39m\u001b[39m>\u001b[39m Response:\n\u001b[1;32m 181\u001b[0m \u001b[39m \u001b[39m\u001b[39m\"\"\"\u001b[39;00m\n\u001b[1;32m 182\u001b[0m \u001b[39m Sends a `GET` request.\u001b[39;00m\n\u001b[1;32m 183\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 187\u001b[0m \u001b[39m on this function, as `GET` requests should not include a request body.\u001b[39;00m\n\u001b[1;32m 188\u001b[0m \u001b[39m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 189\u001b[0m \u001b[39mreturn\u001b[39;00m request(\n\u001b[1;32m 190\u001b[0m \u001b[39m\"\u001b[39;49m\u001b[39mGET\u001b[39;49m\u001b[39m\"\u001b[39;49m,\n\u001b[1;32m 191\u001b[0m url,\n\u001b[1;32m 192\u001b[0m params\u001b[39m=\u001b[39;49mparams,\n\u001b[1;32m 193\u001b[0m headers\u001b[39m=\u001b[39;49mheaders,\n\u001b[1;32m 194\u001b[0m cookies\u001b[39m=\u001b[39;49mcookies,\n\u001b[1;32m 195\u001b[0m auth\u001b[39m=\u001b[39;49mauth,\n\u001b[1;32m 196\u001b[0m proxies\u001b[39m=\u001b[39;49mproxies,\n\u001b[1;32m 197\u001b[0m follow_redirects\u001b[39m=\u001b[39;49mfollow_redirects,\n\u001b[1;32m 198\u001b[0m cert\u001b[39m=\u001b[39;49mcert,\n\u001b[1;32m 199\u001b[0m verify\u001b[39m=\u001b[39;49mverify,\n\u001b[1;32m 200\u001b[0m timeout\u001b[39m=\u001b[39;49mtimeout,\n\u001b[1;32m 201\u001b[0m trust_env\u001b[39m=\u001b[39;49mtrust_env,\n\u001b[1;32m 202\u001b[0m )\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpx/_api.py:100\u001b[0m, in \u001b[0;36mrequest\u001b[0;34m(method, url, params, content, data, files, json, headers, cookies, auth, proxies, timeout, follow_redirects, verify, cert, trust_env)\u001b[0m\n\u001b[1;32m 42\u001b[0m \u001b[39m\u001b[39m\u001b[39m\"\"\"\u001b[39;00m\n\u001b[1;32m 43\u001b[0m \u001b[39mSends an HTTP request.\u001b[39;00m\n\u001b[1;32m 44\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 90\u001b[0m \u001b[39m```\u001b[39;00m\n\u001b[1;32m 91\u001b[0m \u001b[39m\"\"\"\u001b[39;00m\n\u001b[1;32m 92\u001b[0m \u001b[39mwith\u001b[39;00m Client(\n\u001b[1;32m 93\u001b[0m cookies\u001b[39m=\u001b[39mcookies,\n\u001b[1;32m 94\u001b[0m proxies\u001b[39m=\u001b[39mproxies,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 98\u001b[0m trust_env\u001b[39m=\u001b[39mtrust_env,\n\u001b[1;32m 99\u001b[0m ) \u001b[39mas\u001b[39;00m client:\n\u001b[0;32m--> 100\u001b[0m \u001b[39mreturn\u001b[39;00m client\u001b[39m.\u001b[39;49mrequest(\n\u001b[1;32m 101\u001b[0m method\u001b[39m=\u001b[39;49mmethod,\n\u001b[1;32m 102\u001b[0m url\u001b[39m=\u001b[39;49murl,\n\u001b[1;32m 103\u001b[0m content\u001b[39m=\u001b[39;49mcontent,\n\u001b[1;32m 104\u001b[0m data\u001b[39m=\u001b[39;49mdata,\n\u001b[1;32m 105\u001b[0m files\u001b[39m=\u001b[39;49mfiles,\n\u001b[1;32m 106\u001b[0m json\u001b[39m=\u001b[39;49mjson,\n\u001b[1;32m 107\u001b[0m params\u001b[39m=\u001b[39;49mparams,\n\u001b[1;32m 108\u001b[0m headers\u001b[39m=\u001b[39;49mheaders,\n\u001b[1;32m 109\u001b[0m auth\u001b[39m=\u001b[39;49mauth,\n\u001b[1;32m 110\u001b[0m follow_redirects\u001b[39m=\u001b[39;49mfollow_redirects,\n\u001b[1;32m 111\u001b[0m )\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpx/_client.py:814\u001b[0m, in \u001b[0;36mClient.request\u001b[0;34m(self, method, url, content, data, files, json, params, headers, cookies, auth, follow_redirects, timeout, extensions)\u001b[0m\n\u001b[1;32m 799\u001b[0m warnings\u001b[39m.\u001b[39mwarn(message, \u001b[39mDeprecationWarning\u001b[39;00m)\n\u001b[1;32m 801\u001b[0m request \u001b[39m=\u001b[39m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mbuild_request(\n\u001b[1;32m 802\u001b[0m method\u001b[39m=\u001b[39mmethod,\n\u001b[1;32m 803\u001b[0m url\u001b[39m=\u001b[39murl,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 812\u001b[0m extensions\u001b[39m=\u001b[39mextensions,\n\u001b[1;32m 813\u001b[0m )\n\u001b[0;32m--> 814\u001b[0m \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49msend(request, auth\u001b[39m=\u001b[39;49mauth, follow_redirects\u001b[39m=\u001b[39;49mfollow_redirects)\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpx/_client.py:901\u001b[0m, in \u001b[0;36mClient.send\u001b[0;34m(self, request, stream, auth, follow_redirects)\u001b[0m\n\u001b[1;32m 893\u001b[0m follow_redirects \u001b[39m=\u001b[39m (\n\u001b[1;32m 894\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mfollow_redirects\n\u001b[1;32m 895\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39misinstance\u001b[39m(follow_redirects, UseClientDefault)\n\u001b[1;32m 896\u001b[0m \u001b[39melse\u001b[39;00m follow_redirects\n\u001b[1;32m 897\u001b[0m )\n\u001b[1;32m 899\u001b[0m auth \u001b[39m=\u001b[39m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_build_request_auth(request, auth)\n\u001b[0;32m--> 901\u001b[0m response \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_send_handling_auth(\n\u001b[1;32m 902\u001b[0m request,\n\u001b[1;32m 903\u001b[0m auth\u001b[39m=\u001b[39;49mauth,\n\u001b[1;32m 904\u001b[0m follow_redirects\u001b[39m=\u001b[39;49mfollow_redirects,\n\u001b[1;32m 905\u001b[0m history\u001b[39m=\u001b[39;49m[],\n\u001b[1;32m 906\u001b[0m )\n\u001b[1;32m 907\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[1;32m 908\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m stream:\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpx/_client.py:929\u001b[0m, in \u001b[0;36mClient._send_handling_auth\u001b[0;34m(self, request, auth, follow_redirects, history)\u001b[0m\n\u001b[1;32m 926\u001b[0m request \u001b[39m=\u001b[39m \u001b[39mnext\u001b[39m(auth_flow)\n\u001b[1;32m 928\u001b[0m \u001b[39mwhile\u001b[39;00m \u001b[39mTrue\u001b[39;00m:\n\u001b[0;32m--> 929\u001b[0m response \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_send_handling_redirects(\n\u001b[1;32m 930\u001b[0m request,\n\u001b[1;32m 931\u001b[0m follow_redirects\u001b[39m=\u001b[39;49mfollow_redirects,\n\u001b[1;32m 932\u001b[0m history\u001b[39m=\u001b[39;49mhistory,\n\u001b[1;32m 933\u001b[0m )\n\u001b[1;32m 934\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[1;32m 935\u001b[0m \u001b[39mtry\u001b[39;00m:\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpx/_client.py:966\u001b[0m, in \u001b[0;36mClient._send_handling_redirects\u001b[0;34m(self, request, follow_redirects, history)\u001b[0m\n\u001b[1;32m 963\u001b[0m \u001b[39mfor\u001b[39;00m hook \u001b[39min\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_event_hooks[\u001b[39m\"\u001b[39m\u001b[39mrequest\u001b[39m\u001b[39m\"\u001b[39m]:\n\u001b[1;32m 964\u001b[0m hook(request)\n\u001b[0;32m--> 966\u001b[0m response \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_send_single_request(request)\n\u001b[1;32m 967\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[1;32m 968\u001b[0m \u001b[39mfor\u001b[39;00m hook \u001b[39min\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_event_hooks[\u001b[39m\"\u001b[39m\u001b[39mresponse\u001b[39m\u001b[39m\"\u001b[39m]:\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpx/_client.py:1002\u001b[0m, in \u001b[0;36mClient._send_single_request\u001b[0;34m(self, request)\u001b[0m\n\u001b[1;32m 997\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mRuntimeError\u001b[39;00m(\n\u001b[1;32m 998\u001b[0m \u001b[39m\"\u001b[39m\u001b[39mAttempted to send an async request with a sync Client instance.\u001b[39m\u001b[39m\"\u001b[39m\n\u001b[1;32m 999\u001b[0m )\n\u001b[1;32m 1001\u001b[0m \u001b[39mwith\u001b[39;00m request_context(request\u001b[39m=\u001b[39mrequest):\n\u001b[0;32m-> 1002\u001b[0m response \u001b[39m=\u001b[39m transport\u001b[39m.\u001b[39;49mhandle_request(request)\n\u001b[1;32m 1004\u001b[0m \u001b[39massert\u001b[39;00m \u001b[39misinstance\u001b[39m(response\u001b[39m.\u001b[39mstream, SyncByteStream)\n\u001b[1;32m 1006\u001b[0m response\u001b[39m.\u001b[39mrequest \u001b[39m=\u001b[39m request\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpx/_transports/default.py:217\u001b[0m, in \u001b[0;36mHTTPTransport.handle_request\u001b[0;34m(self, request)\u001b[0m\n\u001b[1;32m 203\u001b[0m \u001b[39massert\u001b[39;00m \u001b[39misinstance\u001b[39m(request\u001b[39m.\u001b[39mstream, SyncByteStream)\n\u001b[1;32m 205\u001b[0m req \u001b[39m=\u001b[39m httpcore\u001b[39m.\u001b[39mRequest(\n\u001b[1;32m 206\u001b[0m method\u001b[39m=\u001b[39mrequest\u001b[39m.\u001b[39mmethod,\n\u001b[1;32m 207\u001b[0m url\u001b[39m=\u001b[39mhttpcore\u001b[39m.\u001b[39mURL(\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 215\u001b[0m extensions\u001b[39m=\u001b[39mrequest\u001b[39m.\u001b[39mextensions,\n\u001b[1;32m 216\u001b[0m )\n\u001b[0;32m--> 217\u001b[0m \u001b[39mwith\u001b[39;00m map_httpcore_exceptions():\n\u001b[1;32m 218\u001b[0m resp \u001b[39m=\u001b[39m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_pool\u001b[39m.\u001b[39mhandle_request(req)\n\u001b[1;32m 220\u001b[0m \u001b[39massert\u001b[39;00m \u001b[39misinstance\u001b[39m(resp\u001b[39m.\u001b[39mstream, typing\u001b[39m.\u001b[39mIterable)\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/contextlib.py:153\u001b[0m, in \u001b[0;36m_GeneratorContextManager.__exit__\u001b[0;34m(self, typ, value, traceback)\u001b[0m\n\u001b[1;32m 151\u001b[0m value \u001b[39m=\u001b[39m typ()\n\u001b[1;32m 152\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[0;32m--> 153\u001b[0m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mgen\u001b[39m.\u001b[39;49mthrow(typ, value, traceback)\n\u001b[1;32m 154\u001b[0m \u001b[39mexcept\u001b[39;00m \u001b[39mStopIteration\u001b[39;00m \u001b[39mas\u001b[39;00m exc:\n\u001b[1;32m 155\u001b[0m \u001b[39m# Suppress StopIteration *unless* it's the same exception that\u001b[39;00m\n\u001b[1;32m 156\u001b[0m \u001b[39m# was passed to throw(). This prevents a StopIteration\u001b[39;00m\n\u001b[1;32m 157\u001b[0m \u001b[39m# raised inside the \"with\" statement from being suppressed.\u001b[39;00m\n\u001b[1;32m 158\u001b[0m \u001b[39mreturn\u001b[39;00m exc \u001b[39mis\u001b[39;00m \u001b[39mnot\u001b[39;00m value\n", + "File \u001b[0;32m~/.pyenv/versions/3.10.5/lib/python3.10/site-packages/httpx/_transports/default.py:77\u001b[0m, in \u001b[0;36mmap_httpcore_exceptions\u001b[0;34m()\u001b[0m\n\u001b[1;32m 74\u001b[0m \u001b[39mraise\u001b[39;00m\n\u001b[1;32m 76\u001b[0m message \u001b[39m=\u001b[39m \u001b[39mstr\u001b[39m(exc)\n\u001b[0;32m---> 77\u001b[0m \u001b[39mraise\u001b[39;00m mapped_exc(message) \u001b[39mfrom\u001b[39;00m \u001b[39mexc\u001b[39;00m\n", + "\u001b[0;31mReadTimeout\u001b[0m: The read operation timed out" + ] + } + ], + "source": [ + "item_id = item[\"id\"]\n", + "\n", + "info = httpx.get(f\"{raster_endpoint}/collections/{collection_id}/items/{item_id}/info\").json()\n", + "\n", + "print(json.dumps(info[\"visual\"], indent=4))\n", + "\n", + "for name, asset in info.items():\n", + " print(name, asset[\"minzoom\"], asset[\"maxzoom\"])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Of importance, the `/collections/{collectionId}/items/{itemId}/info` endpoint returns the information we need to create the necessary URLs for `TiTiler` which are:\n", + "- the datatype, \n", + "- the zoom levels,\n", + "- and the number of bands\n", + "\n", + "Here's how we can build and retrieve the tilejson with the raster endpoint:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'tilejson': '2.2.0',\n", + " 'version': '1.0.0',\n", + " 'scheme': 'xyz',\n", + " 'tiles': ['https://raster.eoapi.dev/collections/MAXAR_Kahramanmaras_turkey_earthquake_23/items/37_031133032132_10300100DB913300/tiles/WebMercatorQuad/{z}/{x}/{y}@1x?assets=visual'],\n", + " 'minzoom': 12,\n", + " 'maxzoom': 19,\n", + " 'bounds': [36.65808288486373,\n", + " 36.345093,\n", + " 36.717375426995574,\n", + " 36.34970381857705],\n", + " 'center': [36.68772915592965, 36.34739840928852, 12]}" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tilejson = httpx.get(\n", + " f\"{raster_endpoint}/collections/{collection_id}/items/{item_id}/tilejson.json\",\n", + " params = (\n", + " (\"assets\", \"visual\"), # THIS PARAMETER IS MANDATORY\n", + " (\"minzoom\", 12), # By default the tiler will use 0\n", + " (\"maxzoom\", 19), # By default the tiler will use 24\n", + " )\n", + ").json()\n", + "tilejson" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's visualize the asset on a map:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "8931b25e68d74ec490aab06ba7e2a91d", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Map(center=[36.34739840928852, 36.68772915592965], controls=(ZoomControl(options=['position', 'zoom_in_text', …" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bounds = tilejson[\"bounds\"]\n", + "m = ipyleaflet.leaflet.Map(\n", + " center=((bounds[1] + bounds[3]) / 2,(bounds[0] + bounds[2]) / 2),\n", + " zoom=12\n", + ")\n", + "\n", + "geo_json = ipyleaflet.leaflet.GeoJSON(\n", + " data=item,\n", + " style={\n", + " 'opacity': 1, 'dashArray': '9', 'fillOpacity': 0., 'weight': 4\n", + " }\n", + ")\n", + "m.add_layer(geo_json)\n", + "\n", + "tiles = ipyleaflet.leaflet.TileLayer(\n", + " url=tilejson[\"tiles\"][0],\n", + " min_zoom=tilejson[\"minzoom\"],\n", + " max_zoom=tilejson[\"maxzoom\"],\n", + " bounds=[\n", + " [bounds[1], bounds[0]],\n", + " [bounds[3], bounds[2]],\n", + "\n", + " ],\n", + ")\n", + "\n", + "m.add_layer(tiles)\n", + "\n", + "m" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Comparing imagery of pre and post events\n", + "\n", + "We've been building up to the grand finale of the notebook - comparing imagery before and after the Turkey earthquakes.\n", + "\n", + "We will use the STAC endpoint to query the images pre and post-event. Then, we will demonstrate how to visualize multiple assets together with Mosaics. Finally, we will create a map to visualize post and pre-events side-by-side. \n", + "\n", + "Here's an example of how we could create objects to store the pre and post-event STAC items:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Pre-event items: 229\n", + "Post-event items: 1886\n" + ] + } + ], + "source": [ + "event_date = datetime(2023, 2, 6, hour=0, minute=0)\n", + "\n", + "pre_items = list(\n", + " filter(\n", + " lambda item: datetime.strptime(item[\"properties\"][\"datetime\"], \"%Y-%m-%dT%H:%M:%SZ\") < event_date, \n", + " turkey_items\n", + " )\n", + ")\n", + "\n", + "post_items = list(\n", + " filter(\n", + " lambda item: datetime.strptime(item[\"properties\"][\"datetime\"], \"%Y-%m-%dT%H:%M:%SZ\") >= event_date, \n", + " turkey_items\n", + " )\n", + ")\n", + "print(\"Pre-event items:\", len(pre_items))\n", + "print(\"Post-event items:\", len(post_items))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Contrary to that single sliver of imagery we visualized with a single asset; we can create a *Mosaic* which combines Assets from multiple Items. The Raster API's true power is to make these virtual mosaics dynamically - merging various items on the fly! In fact, with the `pgSTAC` backend utilized by the Raster endpoint, we can use the filter extension to construct complex queries. \n", + "\n", + "For more information on filtering, you can visit the stac-fastapi documentation section on it [here](https://github.com/stac-api-extensions/filter).\n", + "\n", + "Under the hood, the process happens in two separate steps:\n", + "1. Registering the Raster Mosaic,\n", + "2. Creating a Valid tile URL\n", + "\n", + "Here's an example of Kahramanmaras, where we filter by the event date, the collection ID, and the city's bounds. First, we register the Mosaic with our specific filters:" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'id': '9c2101bb56005850dcc6e95303586432',\n", + " 'links': [{'rel': 'metadata',\n", + " 'title': 'Mosaic metadata',\n", + " 'type': 'application/json',\n", + " 'href': 'https://raster.eoapi.dev/searches/9c2101bb56005850dcc6e95303586432/info'},\n", + " {'rel': 'tilejson',\n", + " 'title': 'Link for TileJSON',\n", + " 'type': 'application/json',\n", + " 'href': 'https://raster.eoapi.dev/searches/9c2101bb56005850dcc6e95303586432/tilejson.json'},\n", + " {'rel': 'map',\n", + " 'title': 'Link for Map viewer',\n", + " 'type': 'application/json',\n", + " 'href': 'https://raster.eoapi.dev/searches/9c2101bb56005850dcc6e95303586432/map'},\n", + " {'rel': 'wmts',\n", + " 'title': 'Link for WMTS',\n", + " 'type': 'application/json',\n", + " 'href': 'https://raster.eoapi.dev/searches/9c2101bb56005850dcc6e95303586432/WMTSCapabilities.xml'}]}" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "event_date = \"2023-02-06T00:00:00Z\"\n", + "\n", + "# Let's focus on Kahramanmaraş city \n", + "bounds = [36.83064386785452, 37.53123515817725, 37.03859654890988, 37.63167525356958]\n", + "\n", + "pre_mosaic = httpx.post(\n", + " f\"{raster_endpoint}/searches/register\",\n", + " data=json.dumps(\n", + " {\n", + " \"filter-lang\": 'cql2-json',\n", + " \"filter\": {\n", + " \"op\": 'and', \n", + " \"args\": [\n", + " {\n", + " \"op\": \"in\", \n", + " \"args\": [{\"property\": \"collection\"}, [collection_id]]\n", + " },\n", + " {\n", + " \"op\": \"lt\", \n", + " \"args\": [\n", + " {\"property\": \"datetime\"}, event_date\n", + " ]\n", + " }\n", + " ],\n", + " },\n", + " \"sortby\": [\n", + " {\n", + " \"field\": \"tile:clouds_percent\",\n", + " \"direction\": \"asc\"\n", + " },\n", + " ],\n", + " \"metadata\":{\n", + " \"name\": \"Maxar Kahramanmaras - Pre event\",\n", + " \"bounds\": bounds,\n", + " }\n", + " \n", + " }\n", + " )\n", + ").json()\n", + "pre_mosaic" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, we can create a valid Tile URL using the `searchid` hash returned by the mosaic registration. Again, we will pass the assets parameter when creating the tile as well as our zoom levels to avoid over and under-zooming:" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'9c2101bb56005850dcc6e95303586432'" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mosaic_id = pre_mosaic[\"id\"]\n", + "mosaic_id\n", + "# tilejson_pre = httpx.get(\n", + "# f\"{raster_endpoint}/mosaic/{mosaic_id}/tilejson.json\",\n", + "# params = (\n", + "# (\"assets\", \"visual\"), # required parameter\n", + "# (\"minzoom\", 12),\n", + "# (\"maxzoom\", 19), \n", + "# )\n", + "# ).json()\n", + "# tilejson_pre" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "0d8b49841bee48489cd5cf2e59fe6f3d", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Map(center=[37.58145520587342, 36.9346202083822], controls=(ZoomControl(options=['position', 'zoom_in_text', '…" + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mosaic_id = pre_mosaic[\"id\"]\n", + "\n", + "tilejson_pre = httpx.get(\n", + " f\"{raster_endpoint}/searches/{mosaic_id}/tilejson.json\",\n", + " params = (\n", + " (\"assets\", \"visual\"), # required parameter\n", + " (\"minzoom\", 12),\n", + " (\"maxzoom\", 19), \n", + " )\n", + ").json()\n", + "\n", + "bounds = tilejson_pre[\"bounds\"]\n", + "m = ipyleaflet.leaflet.Map(\n", + " center=((bounds[1] + bounds[3]) / 2,(bounds[0] + bounds[2]) / 2),\n", + " zoom=12\n", + ")\n", + "\n", + "geo_json = ipyleaflet.leaflet.GeoJSON(\n", + " data={\"type\": \"FeatureCollection\", \"features\": pre_items}, \n", + " style={\n", + " \"fillOpacity\": 0,\n", + " \"weight\": 1,\n", + " },\n", + ")\n", + "m.add_layer(geo_json)\n", + "\n", + "tiles = ipyleaflet.leaflet.TileLayer(\n", + " url=tilejson_pre[\"tiles\"][0],\n", + " min_zoom=tilejson_pre[\"minzoom\"],\n", + " max_zoom=tilejson_pre[\"maxzoom\"],\n", + " bounds=[\n", + " [bounds[1], bounds[0]],\n", + " [bounds[3], bounds[2]],\n", + "\n", + " ],\n", + ")\n", + "\n", + "m.add_layer(tiles)\n", + "m" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A complete list of options for the mosaic endpoint is available in the documentation [here](https://stac-utils.github.io/titiler-pgstac/mosaic_endpoints/#tiles).\n", + "\n", + "Finally, we can visualize the pre and post-events simultaneously with leaflet's slider capability and creating another mosaic for post-events:" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "ename": "KeyError", + "evalue": "'searchid'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[61], line 36\u001b[0m\n\u001b[1;32m 1\u001b[0m post_mosaic \u001b[39m=\u001b[39m httpx\u001b[39m.\u001b[39mpost(\n\u001b[1;32m 2\u001b[0m \u001b[39mf\u001b[39m\u001b[39m\"\u001b[39m\u001b[39m{\u001b[39;00mraster_endpoint\u001b[39m}\u001b[39;00m\u001b[39m/searches/register\u001b[39m\u001b[39m\"\u001b[39m,\n\u001b[1;32m 3\u001b[0m data\u001b[39m=\u001b[39mjson\u001b[39m.\u001b[39mdumps(\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 33\u001b[0m )\n\u001b[1;32m 34\u001b[0m )\u001b[39m.\u001b[39mjson()\n\u001b[0;32m---> 36\u001b[0m mosaic_id \u001b[39m=\u001b[39m post_mosaic[\u001b[39m\"\u001b[39;49m\u001b[39msearchid\u001b[39;49m\u001b[39m\"\u001b[39;49m]\n\u001b[1;32m 38\u001b[0m tilejson_post \u001b[39m=\u001b[39m httpx\u001b[39m.\u001b[39mget(\n\u001b[1;32m 39\u001b[0m \u001b[39mf\u001b[39m\u001b[39m\"\u001b[39m\u001b[39m{\u001b[39;00mraster_endpoint\u001b[39m}\u001b[39;00m\u001b[39m/searches/\u001b[39m\u001b[39m{\u001b[39;00mmosaic_id\u001b[39m}\u001b[39;00m\u001b[39m/tilejson.json\u001b[39m\u001b[39m\"\u001b[39m,\n\u001b[1;32m 40\u001b[0m params \u001b[39m=\u001b[39m (\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 44\u001b[0m )\n\u001b[1;32m 45\u001b[0m )\u001b[39m.\u001b[39mjson()\n\u001b[1;32m 47\u001b[0m bounds \u001b[39m=\u001b[39m tilejson_pre[\u001b[39m\"\u001b[39m\u001b[39mbounds\u001b[39m\u001b[39m\"\u001b[39m]\n", + "\u001b[0;31mKeyError\u001b[0m: 'searchid'" + ] + } + ], + "source": [ + "post_mosaic = httpx.post(\n", + " f\"{raster_endpoint}/searches/register\",\n", + " data=json.dumps(\n", + " {\n", + " \"filter-lang\": 'cql2-json',\n", + " \"filter\": {\n", + " \"op\": 'and', \n", + " \"args\": [\n", + " {\n", + " \"op\": \"in\", \n", + " \"args\": [{\"property\": \"collection\"}, [collection_id]]\n", + " },\n", + " {\n", + " \"op\": \"ge\", \n", + " \"args\": [\n", + " {\"property\": \"datetime\"}, event_date\n", + " ]\n", + " }\n", + " ],\n", + " },\n", + " \"sortby\": [\n", + " {\n", + " \"field\": \"tile:clouds_percent\",\n", + " \"direction\": \"asc\"\n", + " },\n", + " ],\n", + " \"metadata\":{\n", + " \"name\": \"Maxar Kahramanmaras - Port event\",\n", + " \"bounds\": bounds,\n", + " }\n", + " \n", + " }\n", + " )\n", + ").json()\n", + "\n", + "mosaic_id = post_mosaic[\"id\"]\n", + "\n", + "tilejson_post = httpx.get(\n", + " f\"{raster_endpoint}/searches/{mosaic_id}/tilejson.json\",\n", + " params = (\n", + " (\"assets\", \"visual\"), # THIS IS MANDATORY\n", + " (\"minzoom\", 12),\n", + " (\"maxzoom\", 19), \n", + " )\n", + ").json()\n", + "\n", + "bounds = tilejson_pre[\"bounds\"]\n", + "before_layer = ipyleaflet.leaflet.TileLayer(\n", + " url=tilejson_pre[\"tiles\"][0],\n", + " min_zoom=tilejson_pre[\"minzoom\"],\n", + " max_zoom=tilejson_pre[\"maxzoom\"],\n", + " bounds=[\n", + " [bounds[1], bounds[0]],\n", + " [bounds[3], bounds[2]],\n", + " ],\n", + ")\n", + "\n", + "bounds = tilejson_post[\"bounds\"]\n", + "after_layer = ipyleaflet.leaflet.TileLayer(\n", + " url=tilejson_post[\"tiles\"][0],\n", + " min_zoom=tilejson_post[\"minzoom\"],\n", + " max_zoom=tilejson_post[\"maxzoom\"],\n", + " bounds=[\n", + " [bounds[1], bounds[0]],\n", + " [bounds[3], bounds[2]],\n", + " ],\n", + ")\n", + "\n", + "control = ipyleaflet.leaflet.SplitMapControl(left_layer=before_layer, right_layer=after_layer)\n", + "m.add_control(control)\n", + "\n", + "m" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "In this notebook, we've explored the essentials of STAC, COGs, and eoAPI, providing practical insights into their use in data analysis. Please further experiment with the techniques demonstrated here and explore the other notebooks in our [eoAPI](https://github.com/developmentseed/eoAPI) repository for more applications.\n", + "\n", + "I want to thank Vincent Sarago for his foundational work that inspired this notebook. Your feedback and contributions are highly valued; feel free to open an issue or submit a Pull Request on our GitHub repository.\n", + "\n", + "Thank you for your time, and I hope this notebook has sparked your interest in further exploring geospatial data analysis!" + ] + } + ], + "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.10.5" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +}