Spaces:
				
			
			
	
			
			
		Sleeping
		
	
	
	
			
			
	
	
	
	
		
		
		Sleeping
		
	
		Yao-Ting
		
	commited on
		
		
					Commit 
							
							·
						
						aa38f60
	
1
								Parent(s):
							
							1680358
								
Add map-plot into app
Browse filesResponse to #2.
- src/streamlit_app.py +134 -70
    	
        src/streamlit_app.py
    CHANGED
    
    | @@ -157,7 +157,7 @@ def get_lon(geometry): | |
| 157 | 
             
            # xaxis_title: x axis title
         | 
| 158 | 
             
            # yaxis_title: x axis title
         | 
| 159 | 
             
            config = {
         | 
| 160 | 
            -
                "title" : " | 
| 161 | 
             
                "xaxis_title" : "t-SNE Dimension 1",
         | 
| 162 | 
             
                "yaxis_title" : "t-SNE Dimension 2",
         | 
| 163 | 
             
            }
         | 
| @@ -200,7 +200,7 @@ color_dict_label = { | |
| 200 | 
             
                'Water': '#2c41e6',
         | 
| 201 | 
             
                'Trees': '#04541b',
         | 
| 202 | 
             
                'Crops': '#99e0ad',
         | 
| 203 | 
            -
                'Built area':  | 
| 204 | 
             
                'Bare ground': '#a68647',
         | 
| 205 | 
             
                'Rangeland': '#f7980a'
         | 
| 206 | 
             
            }
         | 
| @@ -244,19 +244,12 @@ points_json = json.dumps(points) | |
| 244 | 
             
            plot_html = f"""
         | 
| 245 | 
             
            <script src="https://cdn.plot.ly/plotly-2.18.1.min.js"></script>
         | 
| 246 | 
             
            <style>
         | 
| 247 | 
            -
              html, body {{
         | 
| 248 | 
            -
             | 
| 249 | 
            -
              }}
         | 
| 250 | 
            -
              #container {{
         | 
| 251 | 
            -
                display: flex;
         | 
| 252 | 
            -
                width: 100%;
         | 
| 253 | 
            -
                height: 100%;
         | 
| 254 | 
            -
              }}
         | 
| 255 | 
             
              #scatter-plot {{
         | 
| 256 | 
            -
             | 
| 257 | 
            -
             | 
| 258 | 
            -
                height: 100%;
         | 
| 259 | 
            -
              }}
         | 
| 260 | 
             
              #image-container {{
         | 
| 261 | 
             
                display: grid;
         | 
| 262 | 
             
                grid-template-columns: repeat(2, 1fr);
         | 
| @@ -268,22 +261,70 @@ plot_html = f""" | |
| 268 | 
             
                gap: 4px;
         | 
| 269 | 
             
                overflow: hidden;
         | 
| 270 | 
             
              }}
         | 
| 271 | 
            -
              #image-container img {{
         | 
| 272 | 
            -
                width: 100%;
         | 
| 273 | 
            -
                height: auto;
         | 
| 274 | 
            -
                max-height: 200px;
         | 
| 275 | 
            -
              }}
         | 
| 276 | 
             
            </style>
         | 
|  | |
| 277 | 
             
            <div id="container">
         | 
|  | |
| 278 | 
             
              <div id="scatter-plot"></div>
         | 
| 279 | 
             
              <div id="image-container"></div>
         | 
| 280 | 
             
            </div>
         | 
|  | |
| 281 | 
             
            <script>
         | 
| 282 | 
            -
              const points | 
| 283 | 
            -
              const cats | 
| 284 | 
            -
             | 
| 285 | 
            -
              //  | 
| 286 | 
            -
              const  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 287 | 
             
                const pts = points.filter(p=>p.category===cat);
         | 
| 288 | 
             
                return {{
         | 
| 289 | 
             
                    x:         pts.map(p=>p.x),
         | 
| @@ -299,17 +340,24 @@ plot_html = f""" | |
| 299 | 
             
                    mode:      'markers',
         | 
| 300 | 
             
                    type:      'scatter',
         | 
| 301 | 
             
                    name:      cat,
         | 
| 302 | 
            -
                    marker: | 
|  | |
|  | |
|  | |
|  | |
| 303 | 
             
                    hovertemplate:
         | 
| 304 | 
             
                    `<b>ID:</b> %{{customdata[0]}}<br>` +
         | 
| 305 | 
             
                    `<b>x:</b> %{{x:.2f}}<br>` +
         | 
| 306 | 
             
                    `<b>y:</b> %{{y:.2f}}<br>` +
         | 
| 307 | 
             
                    `<b>lat:</b> %{{customdata[1]:.4f}}<br>` +
         | 
| 308 | 
            -
                    `<b>lon:</b> %{{customdata[2]:.4f}}<extra></extra | 
|  | |
|  | |
|  | |
| 309 | 
             
                }};
         | 
| 310 | 
             
              }});
         | 
| 311 | 
            -
             | 
| 312 | 
            -
              const  | 
| 313 | 
             
                hovermode: 'closest',
         | 
| 314 | 
             
                title:    {title_js},
         | 
| 315 | 
             
                xaxis:    {{
         | 
| @@ -343,50 +391,66 @@ plot_html = f""" | |
| 343 | 
             
                clickmode:'event+select',
         | 
| 344 | 
             
                legend: {{ font:{{ size:12 }}, x:1.01, y:0.5 }}
         | 
| 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 | 
             
            </script>
         | 
| 389 | 
             
            """
         | 
|  | |
|  | |
| 390 |  | 
| 391 | 
             
            # build up footer html
         | 
| 392 | 
             
            year = datetime.datetime.now().year
         | 
| @@ -410,5 +474,5 @@ footer_html = f""" | |
| 410 | 
             
            # embed into Streamlit 
         | 
| 411 | 
             
            col1, col2, col3 = st.columns([1, 5, 1])
         | 
| 412 | 
             
            with col2:
         | 
| 413 | 
            -
                 | 
| 414 | 
             
                st.markdown(footer_html, unsafe_allow_html=True)
         | 
|  | |
| 157 | 
             
            # xaxis_title: x axis title
         | 
| 158 | 
             
            # yaxis_title: x axis title
         | 
| 159 | 
             
            config = {
         | 
| 160 | 
            +
                "title" : "Visualization of EO-FM-Bench Embeddings",
         | 
| 161 | 
             
                "xaxis_title" : "t-SNE Dimension 1",
         | 
| 162 | 
             
                "yaxis_title" : "t-SNE Dimension 2",
         | 
| 163 | 
             
            }
         | 
|  | |
| 200 | 
             
                'Water': '#2c41e6',
         | 
| 201 | 
             
                'Trees': '#04541b',
         | 
| 202 | 
             
                'Crops': '#99e0ad',
         | 
| 203 | 
            +
                'Built area': "#111112",
         | 
| 204 | 
             
                'Bare ground': '#a68647',
         | 
| 205 | 
             
                'Rangeland': '#f7980a'
         | 
| 206 | 
             
            }
         | 
|  | |
| 244 | 
             
            plot_html = f"""
         | 
| 245 | 
             
            <script src="https://cdn.plot.ly/plotly-2.18.1.min.js"></script>
         | 
| 246 | 
             
            <style>
         | 
| 247 | 
            +
              html, body {{ margin:0; padding:0; height:100%; }}
         | 
| 248 | 
            +
              #container {{ display:flex; width:100%; height:100%; }}
         | 
| 249 | 
            +
              #map-plot, #scatter-plot {{ flex:1; padding:4px; box-sizing:border-box;margin-right:16px;}}
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
| 250 | 
             
              #scatter-plot {{
         | 
| 251 | 
            +
              margin-right:6px;
         | 
| 252 | 
            +
            }}
         | 
|  | |
|  | |
| 253 | 
             
              #image-container {{
         | 
| 254 | 
             
                display: grid;
         | 
| 255 | 
             
                grid-template-columns: repeat(2, 1fr);
         | 
|  | |
| 261 | 
             
                gap: 4px;
         | 
| 262 | 
             
                overflow: hidden;
         | 
| 263 | 
             
              }}
         | 
| 264 | 
            +
              #image-container img {{ width:100%; height:auto; max-height:200px; }}
         | 
|  | |
|  | |
|  | |
|  | |
| 265 | 
             
            </style>
         | 
| 266 | 
            +
             | 
| 267 | 
             
            <div id="container">
         | 
| 268 | 
            +
              <div id="map-plot"></div>
         | 
| 269 | 
             
              <div id="scatter-plot"></div>
         | 
| 270 | 
             
              <div id="image-container"></div>
         | 
| 271 | 
             
            </div>
         | 
| 272 | 
            +
             | 
| 273 | 
             
            <script>
         | 
| 274 | 
            +
              const points = {points_json};
         | 
| 275 | 
            +
              const cats   = Array.from(new Set(points.map(p=>p.category)));
         | 
| 276 | 
            +
             | 
| 277 | 
            +
              // 1) map traces
         | 
| 278 | 
            +
              const mapTraces = cats.map(cat => {{
         | 
| 279 | 
            +
                const pts = points.filter(p=>p.category===cat);
         | 
| 280 | 
            +
                return {{
         | 
| 281 | 
            +
                  type: 'scattermapbox',
         | 
| 282 | 
            +
                  mode: 'markers',
         | 
| 283 | 
            +
                  name: cat,
         | 
| 284 | 
            +
                    x:         pts.map(p=>p.x),
         | 
| 285 | 
            +
                    y:         pts.map(p=>p.y),
         | 
| 286 | 
            +
                    id:        pts.map(p=>p.id),
         | 
| 287 | 
            +
                    lat:       pts.map(p=>p.lat),
         | 
| 288 | 
            +
                    lon:       pts.map(p=>p.lon),
         | 
| 289 | 
            +
                    customdata:pts.map(p=>[
         | 
| 290 | 
            +
                                        p.id,        
         | 
| 291 | 
            +
                                        p.x,       
         | 
| 292 | 
            +
                                        p.y   
         | 
| 293 | 
            +
                                        ]),
         | 
| 294 | 
            +
                  marker: {{
         | 
| 295 | 
            +
                    color: pts.map(p=>p.color),
         | 
| 296 | 
            +
                    symbol: 'circle',
         | 
| 297 | 
            +
                    size: 8,
         | 
| 298 | 
            +
                    line: {{ color:'red', width:2 }}
         | 
| 299 | 
            +
                  }},
         | 
| 300 | 
            +
                  hovertemplate:
         | 
| 301 | 
            +
                    `<b>ID:</b> %{{customdata[0]}}<br>` +
         | 
| 302 | 
            +
                    `<b>x:</b> %{{customdata[1]:.4f}}<br>` +
         | 
| 303 | 
            +
                    `<b>y:</b> %{{customdata[2]:.4f}}<br>` +
         | 
| 304 | 
            +
                    `<b>lat:</b> %{{lat:.2f}}<br>` +
         | 
| 305 | 
            +
                    `<b>lon:</b> %{{lon:.2f}}<extra></extra>`,
         | 
| 306 | 
            +
                  selectedpoints: [],
         | 
| 307 | 
            +
                  selected:   {{ marker: {{ color:'lightblue', size: 10 }} }},
         | 
| 308 | 
            +
                  unselected: {{ marker: {{ opacity:0.2 }} }}
         | 
| 309 | 
            +
                }};
         | 
| 310 | 
            +
              }});
         | 
| 311 | 
            +
             | 
| 312 | 
            +
              const mapLayout = {{
         | 
| 313 | 
            +
                mapbox: {{
         | 
| 314 | 
            +
                  style: 'mapbox://styles/mapbox/satellite-streets-v11',  
         | 
| 315 | 
            +
                  center: {{ lon: 0, lat: 0 }},
         | 
| 316 | 
            +
                  zoom: 0,
         | 
| 317 | 
            +
                  accesstoken: 'pk.eyJ1IjoiY2xhcmtjZ2EteWF5YW8iLCJhIjoiY21jdDl0MDZoMDM3cjJscHBmcWpjbnhkaiJ9.YkEYejNsY5-r3DtESJ46kQ'
         | 
| 318 | 
            +
                }},
         | 
| 319 | 
            +
                clickmode: 'event+select',
         | 
| 320 | 
            +
                margin: {{ l:0,r:0,t:0,b:0 }},
         | 
| 321 | 
            +
              }};
         | 
| 322 | 
            +
             | 
| 323 | 
            +
              Plotly.newPlot('map-plot', mapTraces, mapLayout, {{responsive:true}});
         | 
| 324 | 
            +
             | 
| 325 | 
            +
             | 
| 326 | 
            +
              // 2) scatter traces: build one trace per category
         | 
| 327 | 
            +
              const scatterTraces = cats.map(cat => {{
         | 
| 328 | 
             
                const pts = points.filter(p=>p.category===cat);
         | 
| 329 | 
             
                return {{
         | 
| 330 | 
             
                    x:         pts.map(p=>p.x),
         | 
|  | |
| 340 | 
             
                    mode:      'markers',
         | 
| 341 | 
             
                    type:      'scatter',
         | 
| 342 | 
             
                    name:      cat,
         | 
| 343 | 
            +
                    marker: {{
         | 
| 344 | 
            +
                    color: pts.map(p=>p.color),
         | 
| 345 | 
            +
                    size: 5,
         | 
| 346 | 
            +
                    line: {{ color:'black', width:1 }}
         | 
| 347 | 
            +
                  }},
         | 
| 348 | 
             
                    hovertemplate:
         | 
| 349 | 
             
                    `<b>ID:</b> %{{customdata[0]}}<br>` +
         | 
| 350 | 
             
                    `<b>x:</b> %{{x:.2f}}<br>` +
         | 
| 351 | 
             
                    `<b>y:</b> %{{y:.2f}}<br>` +
         | 
| 352 | 
             
                    `<b>lat:</b> %{{customdata[1]:.4f}}<br>` +
         | 
| 353 | 
            +
                    `<b>lon:</b> %{{customdata[2]:.4f}}<extra></extra>`,
         | 
| 354 | 
            +
                  selectedpoints: [],
         | 
| 355 | 
            +
                  selected:   {{ marker: {{ color:'lightblue', size: 10}} }},
         | 
| 356 | 
            +
                  unselected: {{ marker: {{ opacity:0.2 }} }}
         | 
| 357 | 
             
                }};
         | 
| 358 | 
             
              }});
         | 
| 359 | 
            +
             | 
| 360 | 
            +
              const scatterLayout = {{
         | 
| 361 | 
             
                hovermode: 'closest',
         | 
| 362 | 
             
                title:    {title_js},
         | 
| 363 | 
             
                xaxis:    {{
         | 
|  | |
| 391 | 
             
                clickmode:'event+select',
         | 
| 392 | 
             
                legend: {{ font:{{ size:12 }}, x:1.01, y:0.5 }}
         | 
| 393 | 
             
              }};
         | 
| 394 | 
            +
             | 
| 395 | 
            +
              Plotly.newPlot('scatter-plot', scatterTraces, scatterLayout, {{responsive:true}});
         | 
| 396 | 
            +
             | 
| 397 | 
            +
             | 
| 398 | 
            +
              // 3) click handler
         | 
| 399 | 
            +
              function onPointClick(evt) {{
         | 
| 400 | 
            +
                const pt      = evt.points[0];
         | 
| 401 | 
            +
                const idx     = pt.pointIndex;
         | 
| 402 | 
            +
                const traceNo = pt.curveNumber;
         | 
| 403 | 
            +
             | 
| 404 | 
            +
                // highlight in both
         | 
| 405 | 
            +
                Plotly.restyle('map-plot',     {{ selectedpoints:[[idx]] }}, [traceNo]);
         | 
| 406 | 
            +
                Plotly.restyle('scatter-plot', {{ selectedpoints:[[idx]] }}, [traceNo]);
         | 
| 407 | 
            +
             | 
| 408 | 
            +
                // pull id from array
         | 
| 409 | 
            +
                const clickedId = Array.isArray(pt.customdata) 
         | 
| 410 | 
            +
                // if 
         | 
| 411 | 
            +
                ? pt.customdata[0]   
         | 
| 412 | 
            +
                //else
         | 
| 413 | 
            +
                : pt.customdata;
         | 
| 414 | 
            +
             | 
| 415 | 
            +
                // find the record 
         | 
| 416 | 
            +
                const record = points.find(p=>p.id===clickedId);
         | 
| 417 | 
            +
                if(!record) return;
         | 
| 418 | 
            +
             | 
| 419 | 
            +
                // show thumbnails
         | 
| 420 | 
            +
                const thumbs = record.thumbs;
         | 
| 421 | 
            +
                const dates  = record.dates_list;
         | 
| 422 | 
            +
                const cont   = document.getElementById('image-container');
         | 
| 423 | 
            +
                cont.innerHTML = '';
         | 
| 424 | 
            +
             | 
| 425 | 
            +
                thumbs.forEach((url,i) => {{
         | 
| 426 | 
            +
                  if (!url) return;
         | 
| 427 | 
            +
                  const card  = document.createElement('div');
         | 
| 428 | 
            +
                  card.style.textAlign    = 'center';
         | 
| 429 | 
            +
                  card.style.marginBottom = '8px';
         | 
| 430 | 
            +
             | 
| 431 | 
            +
                  const img   = document.createElement('img');
         | 
| 432 | 
            +
                  img.src     = url;
         | 
| 433 | 
            +
                  img.style.width     = '100%';
         | 
| 434 | 
            +
                  img.style.maxHeight = '180px';
         | 
| 435 | 
            +
             | 
| 436 | 
            +
                  const lbl   = document.createElement('p');
         | 
| 437 | 
            +
                  lbl.textContent    = dates[i];
         | 
| 438 | 
            +
                  lbl.style.color    = 'white';
         | 
| 439 | 
            +
                  lbl.style.margin   = '4px 0 0';
         | 
| 440 | 
            +
                  lbl.style.fontSize = '0.9em';
         | 
| 441 | 
            +
             | 
| 442 | 
            +
                  card.appendChild(img);
         | 
| 443 | 
            +
                  card.appendChild(lbl);
         | 
| 444 | 
            +
                  cont.appendChild(card);
         | 
| 445 | 
             
                }});
         | 
| 446 | 
            +
              }}
         | 
| 447 | 
            +
             | 
| 448 | 
            +
              document.getElementById('map-plot').on('plotly_click',     onPointClick);
         | 
| 449 | 
            +
              document.getElementById('scatter-plot').on('plotly_click', onPointClick);
         | 
| 450 | 
             
            </script>
         | 
| 451 | 
             
            """
         | 
| 452 | 
            +
            # embed into Streamlit 
         | 
| 453 | 
            +
            st_html(plot_html, height=500, width=2000, scrolling=False)
         | 
| 454 |  | 
| 455 | 
             
            # build up footer html
         | 
| 456 | 
             
            year = datetime.datetime.now().year
         | 
|  | |
| 474 | 
             
            # embed into Streamlit 
         | 
| 475 | 
             
            col1, col2, col3 = st.columns([1, 5, 1])
         | 
| 476 | 
             
            with col2:
         | 
| 477 | 
            +
                
         | 
| 478 | 
             
                st.markdown(footer_html, unsafe_allow_html=True)
         | 
