hytest-org / hytest

https://hytest-org.github.io/hytest/
22 stars 12 forks source link

Setting extent of map to CONUS #499

Open lluddenusgs opened 3 months ago

lluddenusgs commented 3 months ago

reference this is completing functionality initially proposed in work done on #476

alaws-USGS commented 2 months ago

Adding thoughts and pseudo code for accomplishing this.

We want to think of the map extent as its own object. So, our initial extent is going to be the continental US (CONUS). This can be derived using:

conus_bbox = states.geometry.total_bounds

But if we want this to update based on interactions made with the widgets?

Currently, if a state(s) is/are selected with state_selector, it updates both the display_states and display_points functions (in that order), which brings the extent of the map to the selected state(s) and clips the points returned by display_points to the same extents.

The streamgage_input is what is throwing a wrench into this as it filters what is returned by display_points but does nothing to filtering in display_states. It seems like a refactor is in order to accomplish this.

  1. Rename display_map to display_basemap

    def display_basemap(map: str) -> gv.WMTS:
    '''
    Display a basemap, based on the string input to select a base input to overlay beneath the state boundaries polygons object. 
    
    Parameters:
        map(str): A string for a base map Defaults to `map_selector.value`.
    
    Returns:
        gv.WMTS: A Tile source type from the GeoViews library.
    '''
    
    basemap = base_map_options[map]
    return basemap
  2. Write new display_map

    def display_map(basemap: str, state_list: list[str], streamgauge_ids: str) -> gv.Overlay:
    """
    Docstrings
    """
    
    # move plot_opts dictionary to here
    plot_opts = {......}
    
    # create basemap
    basemap = display_basemap(basemap)
    
    # if streamguage_ids are entered, we can just return the basemap and points 
    if streamgauge_ids:
        # Use current logic from `if ids:` to create a gv.Points object
    
        # return (basemap * gv.Points object).opts(**plot_opts)
    
    # else `state_list` can be passed to `display_states`and `display_points`
    else:
        # pass `state_list` to functions and create_objects
    
        # return (basemap * displayed_states * displayed_points).opts(**plot_opts)

If this doesn't snap to the geometries using framewise = True in the plot_opts then set the xlim and ylim programmatically using the Geodataframe.geometry.total_bounds for whichever geometry you need the bounds from.

  1. Rewrite display_points function as only the clip is needed and none of the if/else statements.
  2. Remove all of the displayed_** variables outside the context of display_map
  3. Create displayed_map and use pn.rx to bind the three widgets to it