File size: 25,858 Bytes
3c83daf
 
 
 
 
 
 
 
 
016f6e2
 
3c83daf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
016f6e2
3c83daf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
import os
import json
import datetime
import streamlit as st
import streamlit.components.v1 as components
import re
import warnings
import traceback



warnings.filterwarnings("ignore")

# os.environ['SDK_CLIENT_HOST'] = 'https://pre-engine-aiearth.aliyun.com'
import aie


default_map_html = '''
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>IPyWidget export</title>
</head>
<body>


<!-- Load require.js. Delete this if your page already loads require.js -->
<script src="https://g.alicdn.com/aie/jp-notebook/0.1.15/static/components/jquery/dist/jquery.min.js"></script>
<link rel="stylesheet" href="https://g.alicdn.com/aie/jp-notebook/0.1.15/static/components/jquery/dist/jquery-ui.min.css">
<script src="https://g.alicdn.com/aie/jp-notebook/0.1.15/static/components/jquery/dist/jquery-ui.min.js"></script>
<script src="https://g.alicdn.com/aie/jp-notebook/0.1.15/static/components/requirejs/require.js"></script>
<script src="https://g.alicdn.com/aie/jp-notebook/0.1.15/static/components/moment/min/moment.min.js"></script>
<link href="https://g.alicdn.com/aie/jp-notebook/0.1.15/static/build/theme.css" rel="stylesheet">

<style>
  #map {
    height: 100% !important;
  }
  .map-trigger {
    display: none;
  }
</style>

<script type="application/vnd.jupyter.widget-state+json">
{"version_major": 2, "version_minor": 0, "state": {"94ea4efec6cf44c3bfdae7ea872b2ec3": {"model_name": "LeafletMapStyleModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {}}, "397323d9da4942d79ae7a5c917d300e0": {"model_name": "LeafletMapStyleModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {"cursor": "move"}}, "f481ac800c3746f78f47085d05ae63b0": {"model_name": "LeafletLayerGroupModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {"base": true, "layers": ["IPY_MODEL_36a8e8e546534e548e65cdda5aba81c6", "IPY_MODEL_b0dce2566b604debb38b19c9f25833cd"], "name": "\u7ebf\u753b\u5730\u56fe", "options": []}}, "36a8e8e546534e548e65cdda5aba81c6": {"model_name": "LeafletTDTLayerModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {"base": true, "key": "2d585d36d89ab86049e29f6f10364dc3", "options": ["attribution", "bounds", "detect_retina", "key", "max_native_zoom", "max_zoom", "min_native_zoom", "min_zoom", "no_wrap", "proj", "subdomains", "tile_size", "tms", "zoom_offset"], "proj": "c", "subdomains": ["0", "1", "2", "3", "4", "5", "6", "7"], "url": "https://t{s}.tianditu.gov.cn/vec_{proj}/wmts?layer=vec&style=default&tilematrixset={proj}&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk={key}", "zoom_offset": 1}}, "b0dce2566b604debb38b19c9f25833cd": {"model_name": "LeafletTDTLayerModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {"base": true, "key": "2d585d36d89ab86049e29f6f10364dc3", "options": ["attribution", "bounds", "detect_retina", "key", "max_native_zoom", "max_zoom", "min_native_zoom", "min_zoom", "no_wrap", "proj", "subdomains", "tile_size", "tms", "zoom_offset"], "proj": "c", "subdomains": ["0", "1", "2", "3", "4", "5", "6", "7"], "url": "https://t{s}.tianditu.gov.cn/cva_{proj}/wmts?layer=cva&style=default&tilematrixset={proj}&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk={key}", "zoom_offset": 1}}, "d12e84fcb7c84ef08e01fd06cff095b0": {"model_name": "LeafletLayerGroupModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {"base": true, "layers": ["IPY_MODEL_7a8015a60adb47b4b047f9013b77f21d", "IPY_MODEL_622608fb288f43d08511308cf829d853"], "name": "\u9065\u611f\u5730\u56fe", "options": []}}, "7a8015a60adb47b4b047f9013b77f21d": {"model_name": "LeafletTDTLayerModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {"base": true, "key": "2d585d36d89ab86049e29f6f10364dc3", "options": ["attribution", "bounds", "detect_retina", "key", "max_native_zoom", "max_zoom", "min_native_zoom", "min_zoom", "no_wrap", "proj", "subdomains", "tile_size", "tms", "zoom_offset"], "proj": "c", "subdomains": ["0", "1", "2", "3", "4", "5", "6", "7"], "url": "https://t{s}.tianditu.gov.cn/img_{proj}/wmts?layer=img&style=default&tilematrixset={proj}&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk={key}", "zoom_offset": 1}}, "622608fb288f43d08511308cf829d853": {"model_name": "LeafletTDTLayerModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {"base": true, "key": "2d585d36d89ab86049e29f6f10364dc3", "options": ["attribution", "bounds", "detect_retina", "key", "max_native_zoom", "max_zoom", "min_native_zoom", "min_zoom", "no_wrap", "proj", "subdomains", "tile_size", "tms", "zoom_offset"], "proj": "c", "subdomains": ["0", "1", "2", "3", "4", "5", "6", "7"], "url": "https://t{s}.tianditu.gov.cn/cia_{proj}/wmts?layer=cia&style=default&tilematrixset={proj}&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk={key}", "zoom_offset": 1}}, "50ebd50ae88c4b1f805d489b9b30523d": {"model_name": "LayoutModel", "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "state": {"height": "600px", "width": "100%"}}, "03b29492f1cb40429e461a12468e7e30": {"model_name": "LeafletMapStyleModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {}}, "350441dafd5b4772bb1a67f9fee4c49c": {"model_name": "LeafletMapModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {"_dom_classes": [], "center": [39.916668, 116.383331], "controls": ["IPY_MODEL_4025e26e20e745609ea8d442f4747020", "IPY_MODEL_07a7ab3bb9f54361ab752f3e0d779487", "IPY_MODEL_562b3406280e489c955781f8361e49f5", "IPY_MODEL_a14f44ef9941473c801376919b07ab08", "IPY_MODEL_4e83034b92eb447ca7982055140df1ef"], "crs": {"name": "EPSG4326", "custom": false}, "default_style": "IPY_MODEL_94ea4efec6cf44c3bfdae7ea872b2ec3", "dragging_style": "IPY_MODEL_397323d9da4942d79ae7a5c917d300e0", "layers": ["IPY_MODEL_f481ac800c3746f78f47085d05ae63b0", "IPY_MODEL_d12e84fcb7c84ef08e01fd06cff095b0"], "layout": "IPY_MODEL_50ebd50ae88c4b1f805d489b9b30523d", "options": ["bounce_at_zoom_limits", "box_zoom", "center", "close_popup_on_click", "double_click_zoom", "dragging", "fullscreen", "inertia", "inertia_deceleration", "inertia_max_speed", "interpolation", "keyboard", "keyboard_pan_offset", "keyboard_zoom_offset", "max_zoom", "min_zoom", "prefer_canvas", "scroll_wheel_zoom", "tap", "tap_tolerance", "touch_zoom", "world_copy_jump", "zoom", "zoom_animation_threshold", "zoom_delta", "zoom_snap", "zoom_start"], "style": "IPY_MODEL_03b29492f1cb40429e461a12468e7e30", "zoom": 3.0}}, "4025e26e20e745609ea8d442f4747020": {"model_name": "LeafletZoomControlModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {"options": ["position", "zoom_in_text", "zoom_in_title", "zoom_out_text", "zoom_out_title"]}}, "07a7ab3bb9f54361ab752f3e0d779487": {"model_name": "LeafletLayersControlModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {"options": ["position"], "position": "topright"}}, "562b3406280e489c955781f8361e49f5": {"model_name": "LeafletScaleControlModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {"options": ["imperial", "max_width", "metric", "position", "update_when_idle"], "position": "bottomleft"}}, "a14f44ef9941473c801376919b07ab08": {"model_name": "LeafletFullScreenControlModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {"options": ["position"]}}, "4e83034b92eb447ca7982055140df1ef": {"model_name": "LeafletMeasureControlModel", "model_module": "jupyter-leaflet", "model_module_version": "^0.15.1", "state": {"_custom_units": {}, "active_color": "orange", "options": ["active_color", "capture_z_index", "completed_color", "popup_options", "position", "primary_area_unit", "primary_length_unit", "secondary_area_unit", "secondary_length_unit"], "popup_options": {"className": "leaflet-measure-resultpopup", "autoPanPadding": [10, 10]}, "position": "bottomleft", "primary_length_unit": "kilometers"}}}}
</script>
<script type="application/vnd.jupyter.widget-view+json">
{"version_major": 2, "version_minor": 0, "model_id": "350441dafd5b4772bb1a67f9fee4c49c"}
</script>

<script>
  (function() {
    function addWidgetsRenderer() {
      var mimeElement = document.querySelector('script[type="application/vnd.jupyter.widget-view+json"]');
      var scriptElement = document.createElement('script');
      var widgetRendererSrc = "https://g.alicdn.com/aie/jp-notebook/0.1.15/@jupyter-widgets/html-manager/embed-amd.js";
      var widgetState;

      try {
        widgetState = mimeElement && JSON.parse(mimeElement.innerHTML);

        if (widgetState && (widgetState.version_major < 2 || !widgetState.version_major)) {
          widgetRendererSrc = 'https://g.alicdn.com/aie/jp-notebook/0.1.15/jupyter-js-widgets@*/dist/embed.js';
        }
      } catch(e) {}

      scriptElement.src = widgetRendererSrc;
      document.body.appendChild(scriptElement);
    }

    document.addEventListener('DOMContentLoaded', addWidgetsRenderer);
  }());
    window.API_SERVER_CONSOLE="https://engine-aiearth.aliyun.com";
</script>

<div id="map"></div>

</body>
</html>
'''

label_text_tmpl='''
<style>
    .filter-label {{
        font-size: 14px;
        #font-family: "sans serif";
        vertical-align: middle;
        color: #e8eaed;
        padding-top: 2px;
    }}
</style>
<div class="filter-label">
{LABEL_TEXT}
</div>
'''

secondary_label_text_tmpl='''
<style>
    .filter-label {{
        font-size: 12px;
        #font-family: "sans serif";
        vertical-align: middle;
        color: rgb(232, 234, 237, 0.699999988079071);
        padding-top: 2px;
        white-space:nowrap;
    }}
</style>
<div class="filter-label">
{LABEL_TEXT}
</div>
'''

page_title_text_tmpl='''
<style>
    .page_title {{
        font-size: 18px;
        // font-family: "sans serif";
        // vertical-align: middle;
        color: rgb(232, 234, 237, 0.699999988079071);
        font-weight: 600;
    }}

    .page_desc {{
        font-size: 14px;
        //font-family: "sans serif";
        //vertical-align: middle;
        color: rgb(232, 234, 237, 0.699999988079071);
        //font-weight: 600;
        margin-top: 12px;
    }}
</style>
<div class="page_title">
{TITLE_TEXT}
</div>
<div class="page_desc">
{DESC_TEXT}
</div>
'''


label_text_component_height = 41


st.set_page_config(layout="wide")

# AIE数据集stac code
aie_dataset_category = [
"LANDSAT_LT05_T02_T1_L2"
,"LANDSAT_LE07_E02_T1_L2"
,"LANDSAT_LC08_C02_T1_L2"
,"LANDSAT_LC09_C02_T1_L2"
,"SENTINEL_MSIL2A"
]

# L5:1984-2011
# L7:1999-至今
# L8:2014-至今
# L9:2021-至今
# S2:2018-至今

# 数据集时间范围
dataset_timestamp = {
    "LANDSAT_LT05_T02_T1_L2": {"startDate": "1984-01-01", "endDate": "2011-12-31", "sampleStart": "2011-11-01", "sampleEnd": "2011-11-30"},
    "LANDSAT_LE07_E02_T1_L2": {"startDate": "1999-01-01", "endDate": "2021-12-31", "sampleStart": "2021-12-01", "sampleEnd": "2021-12-31"},
    "LANDSAT_LC08_C02_T1_L2": {"startDate": "2014-01-01", "endDate": "__NOW__", "sampleStart": "2023-02-01", "sampleEnd": "2023-03-28"},
    "LANDSAT_LC09_C02_T1_L2": {"startDate": "2021-01-01", "endDate": "__NOW__", "sampleStart": "2023-01-01", "sampleEnd": "2023-03-01"},
    "SENTINEL_MSIL2A": {"startDate": "2018-01-01", "endDate": "__NOW__", "sampleStart": "2023-03-01", "sampleEnd": "2023-03-28"}
}

# aie_area_meta = {}


image_collection_reduce_funcs = [
"median",
"min",
"max",
"mosaic",
"mean"
]


def aie_init():
    token = os.environ.get("SDK_TOKEN")
    #token = "81921ae3af932cf35f1e56de4a8b1ca4"
    aie.Authenticate(token=token)
    aie.Initialize()


@st.cache_resource
def load_area_select_options():
    file_path = "./china-area.json"
    with open(file_path, 'r', encoding="utf-8") as reader:
        area_arr = json.loads(reader.read())
        area_dic = {}
        for item in area_arr:
            province_name = item['levelOneAreaName']
            city_name = item['levelTwoAreaName']
            district_name = item['areaName']
            if not province_name in area_dic:
                area_dic[province_name] = {}
            
            cities = area_dic[province_name]
            if not city_name in cities:
                cities[city_name] = {}
            
            districts = cities[city_name]
            if not district_name in districts:
                districts[district_name] = district_name
        
        print("tianxun area data init complete")
        return area_dic

@st.cache_resource
def load_dataset_info():
    file_path = "./aie_dataset_meta.json"
    with open(file_path, 'r', encoding="utf-8") as reader:
        _dataset = json.loads(reader.read())
        return _dataset



def page_reset_callback():
    st.session_state['dateset_picker'] = 'LANDSAT_LT05_T02_T1_L2'
    st.session_state['region_province_select'] = '北京市'
    st.session_state['region_city_select'] = '请选择城市'
    st.session_state['region_district_select'] = '请选择'
    st.session_state['time_picker'] = [datetime.date(2011, 1, 1), datetime.date(2011, 6, 30)]
    st.session_state['cloud_picker'] = '20%'
    st.session_state['reduce_picker'] = 'median'
    st.session_state['band_picker'] = []
    st.session_state['min_input'] = '8000'
    st.session_state['max_input'] = '13000'
    st.session_state['render_map_html'] = None



def page_components_render(ctr_panel, map_panel):
    with ctr_panel:
        hide_streamlit_menu = """
        <style>
        #MainMenu {visibility: hidden;}
        </style>

        """
        st.markdown(hide_streamlit_menu, unsafe_allow_html=True)

        area_selections = load_area_select_options()
        dataset_meta = load_dataset_info()

        # title
        components.html(page_title_text_tmpl.format(TITLE_TEXT="影像快速检索", DESC_TEXT="卫星影像数据获取是业务应用分析的第一步工作,基于平台现有Landsat和Sentinel系列卫星数据资源,根据用户选择的感兴趣行政区、时间范围、云量等参数,可快速获取覆盖区域内的已镶嵌和裁剪后的卫星数据。"), height=160)


        # 选择数据集类型
        dataset_label, dataset_select = st.columns([1.1, 3.9])
        # todo: 实在不行,label用html渲染
        with dataset_label:
            # st.text("数据类型")
            components.html(label_text_tmpl.format(LABEL_TEXT="数据类型"), height=label_text_component_height)
        
        with dataset_select:
            dataset_empty = st.empty()

            dataset = dataset_empty.selectbox(label="请选择数据类型", options=aie_dataset_category, key="dateset_picker", label_visibility="collapsed")

        # 区域过滤
        region_label, province_select, city_select  = st.columns([1.65,2.8,2.75])
        
        with region_label:
            # st.text("区域选择")
            components.html(label_text_tmpl.format(LABEL_TEXT="区域选择"), height=label_text_component_height)
        
        with province_select:
            region_province_options = [name for name in area_selections]
            region_province = st.selectbox(label="请选择省", options=region_province_options, key="region_province_select", label_visibility="collapsed")
        
        with city_select:
            region_city_options = []
            if region_province:
                region_city_options = [name for name in area_selections[region_province]]

            region_city_options_update = ['请选择'] + region_city_options
            region_city = st.selectbox(label="请选择市", options=region_city_options_update, key="region_city_select", label_visibility="collapsed")
        
        # 选择时间区间
        time_label, time_select = st.columns([1.1, 3.9])
        with time_label:
            # st.text("检索日期")
            components.html(label_text_tmpl.format(LABEL_TEXT="检索日期"), height=label_text_component_height)
        
        with time_select:
            try:
                min_time = datetime.date(2011, 1, 1)
                max_time = datetime.date(2011, 6, 30)
                sample_start_time = datetime.date(2011, 1, 1)
                sample_end_time = datetime.date(2011, 6, 30)
                if dataset and dataset in dataset_timestamp:
                    min_time = datetime.datetime.strptime(dataset_timestamp[dataset]['startDate'], '%Y-%m-%d')
                    if dataset_timestamp[dataset]['endDate'] == '__NOW__':
                        # max_time = datetime.date.today()
                        max_time = datetime.datetime.strptime(str(datetime.date.today()), '%Y-%m-%d')
                    else:
                        max_time = datetime.datetime.strptime(dataset_timestamp[dataset]['endDate'], '%Y-%m-%d')

                    # print(f"[DEBUG] {dataset} max_time = {max_time}, min_time = {min_time}")
                    sample_start_time = datetime.datetime.strptime(dataset_timestamp[dataset]['sampleStart'], '%Y-%m-%d')
                    sample_end_time = datetime.datetime.strptime(dataset_timestamp[dataset]['sampleEnd'], '%Y-%m-%d')


                start_date, end_date = st.date_input(label="Select image time range", min_value=min_time, max_value=max_time,value=[sample_start_time, sample_end_time], key="time_picker", label_visibility="collapsed")
            except Exception as e:
                print("date picker error. ignore")

        # 选择云量
        cloud_label, cloud_select = st.columns([1.1, 3.9])
        with cloud_label:
            # st.text("云量")
            components.html(label_text_tmpl.format(LABEL_TEXT="云  量"), height=label_text_component_height)
        
        with cloud_select:
            cloud_options = [ str(x) + "%" for x in range(0, 105, 5)]
            end_cloud = st.select_slider(
                '选择云量',
                options=cloud_options,
                key='cloud_picker',
                value='20%', label_visibility="collapsed")
        
        # 选择镶嵌方式
        crop_label, crop_select = st.columns([1.1, 3.9])
        with crop_label:
            #st.text("镶嵌方式")
            components.html(label_text_tmpl.format(LABEL_TEXT="镶嵌方式"), height=label_text_component_height)

        with crop_select:
            crop_type = st.selectbox(label="请选择镶嵌方式", options=image_collection_reduce_funcs, key="reduce_picker", label_visibility="collapsed")


        # 波段选择(默认填充前3个)
        band_label, band_select = st.columns([1.1, 3.9])
        with band_label:
            # st.text("波段选择")
            components.html(label_text_tmpl.format(LABEL_TEXT="波段选择"), height=label_text_component_height)
        
        with band_select:
            bands_option = []
            if dataset and dataset in dataset_meta:
                bands_option = [band_name for band_name in dataset_meta[dataset]['bands']]
            bands = st.multiselect("Select bands to display", options=bands_option, key="band_picker", label_visibility="collapsed", max_selections=3)


        minmax_label, min_label, min_select, max_label, max_select = st.columns([1.55, 1.22, 1.74, 1.23, 1.74])
        with min_label:
            # st.text("最小值")
            components.html(secondary_label_text_tmpl.format(LABEL_TEXT="最小值"), height=label_text_component_height)

        with min_select:
            default_min = 100
            if dataset and dataset in dataset_meta:
                default_min = dataset_meta[dataset]['min']
            min = st.text_input(label="Enter image min",value=str(default_min), key="min_input", label_visibility="collapsed")
            
        with max_label:
            #st.text("最大值")
            components.html(secondary_label_text_tmpl.format(LABEL_TEXT="最大值"), height=label_text_component_height)

        with max_select:
            default_max = 10000
            if dataset and dataset in dataset_meta:
                default_max = dataset_meta[dataset]['max']  
            max = st.text_input(label="Enter image max",value=str(default_max), key="max_input", label_visibility="collapsed")

        reset_btn, query_btn = st.columns([1, 2])
        with reset_btn:
            page_reset = st.button("重置", type='secondary', key='reset_btn', use_container_width=True, on_click=page_reset_callback)

        with query_btn:
            submit = st.button("检索", type='primary', key='submit_btn', use_container_width=True)

        # date_debug = str(dataset) + ", max_time = " + str(max_time) + ", min_time = " + str(min_time)
        # st.write(date_debug)

    if page_reset:
        with map_panel:
            components.html(default_map_html, height=780, scrolling=False)
        return 

    if submit:
        # 参数校验
        errMsg = None
        if not start_date or not end_date:
            errMsg = "请选择时间"
        elif start_date >= max_time.date():
            errMsg = "未检索到数据,请重新设置检索日期"
        elif not bands or len(bands) == 0:
            errMsg = "请选择波段"
        elif not min or not max:
            errMsg = "请输入最大最小值"
        else:
            try:
                ti = float(min)
                ta = float(max)
            except Exception as e:
                errMsg = "最大最小值只能为数字"


        if errMsg:
            aie_init()
            with ctr_panel:
                st.error(errMsg)

            with map_panel:
                components.html(default_map_html, height=780, scrolling=False)
                
            return

        if dataset:
            try:
                # 拼接AIE 数据查询SDK语句
                aie_init()
                image_collection = aie.ImageCollection(dataset)
                if start_date and end_date:
                    image_collection = image_collection.filterDate(start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d'))
                
                if region_province or region_city:
                    fc = aie.FeatureCollection('China_City')

                    if region_province:
                        fc = fc.filter(aie.Filter.eq('province', region_province))

                    if region_city and region_city != '请选择':
                        fc = fc.filter(aie.Filter.eq('city', region_city))


                    # 用选择的数据重新初始化map组件
                    aie_map = aie.Map(
                        center=fc.getCenter(),
                        height=800,
                        zoom=7
                    )

                    region_vis_params = {
                        'color': '#00FF00'
                    }
                    aie_map.addLayer(
                        fc,
                        region_vis_params,
                        '行政区划边界',
                        bounds=fc.getBounds()
                    )
                    image_collection = image_collection.filterBounds(fc.geometry())

                if end_cloud:
                    end_cloud_val = end_cloud.replace('%','')
                    image_collection = image_collection.filter(aie.Filter.lte('eo:cloud_cover', int(end_cloud_val)))


                if crop_type == 'median':
                    image_collection = image_collection.median()
                elif crop_type == 'min':
                    image_collection = image_collection.min()
                elif crop_type == 'max':
                    image_collection = image_collection.max()
                elif crop_type == 'mosaic':
                    image_collection = image_collection.mosaic()
                elif crop_type == 'mean':
                    image_collection = image_collection.mean()
                
                if region_province or region_city:
                    image_collection = image_collection.clipToCollection(fc)

                vis_params = {}
                if bands:
                    vis_params['bands'] = list(bands)

                if min and max:
                    vis_params['min'] = float(min)
                    vis_params['max'] = float(max)

                aie_map.addLayer(
                    image_collection,
                    vis_params,
                    dataset,
                    bounds=image_collection.getBounds()
                )

            except Exception as e:
                traceback.print_exc()
                with ctr_panel:
                    # st.error(e)
                    st.error("未检索到数据集信息, 请重新设置查询条件")

                with map_panel:
                    components.html(default_map_html, height=780, scrolling=False)
                        
                return
    

    with map_panel:
        # 对于未点击submit的情况, 直接读取静态html字符串来加快load速度
        if submit:
            map_html_source = aie_map.to_html()
            st.session_state['render_map_html'] = map_html_source
            components.html(map_html_source, height=780, scrolling=False)        
        else:
            display_template = default_map_html
            if 'render_map_html' in st.session_state and st.session_state['render_map_html']:
                display_template = st.session_state['render_map_html']

            components.html(display_template, height=780, scrolling=False)
        # components.html(default_map_html, height=800, scrolling=False)


row1_col1, row1_col2 = st.columns([0.8, 2.2])
page_components_render(row1_col1, row1_col2)