예제 #1
0
    def __init__(self, mapdata):
        '''initialize a SubwayMap object
        Args:
            mapdata (SubwayMapData): container-class for stations and lines dataframes with implemented observer pattern.
                                    This is necessary for data binding of the view to the viewmodel.
        '''
        Stream.__init__(self)

        #create an initial map
        stations, lines = mapdata.stationsdf, mapdata.linesdf
        self.pipe = Pipe(data=[])
        self.subway_map = gv.Path(lines, vdims=['color']).opts(
            projection=crs.LambertConformal(),
            height=800,
            width=800,
            color='color') * gv.DynamicMap(self.callback, streams=[self.pipe])
        self.pipe.send(stations)

        #bind changes in the stationsdf to pipe.send
        mapdata.bind_to_stationsdf(self.pipe.send)
        self.mapdata = mapdata
예제 #2
0
    def __init__(self, stations):
        self.default_departure_station = 'Zürich HB'
        self.default_arrival_station = 'Zürich, Auzelg'
        self.default_departure_id = id_from_name(
            stations, self.default_departure_station)
        self.default_arrival_id = id_from_name(stations,
                                               self.default_arrival_station)
        zurich = stations.loc[self.default_departure_id]
        self.stations = stations
        self.station_names = list(self.stations['station_name'])

        self.default_arrival_time = datetime.datetime.fromisoformat(
            '2019-05-06 12:30:00')
        self.default_min_success_probability = 0
        self.tiles = gv.tile_sources.CartoLight()
        self.unselected_hover = HoverTool(tooltips=[('', '@station_name')])
        self.departure_hover = HoverTool(tooltips=[('Departure Station',
                                                    '@station_name')])
        self.arrival_hover = HoverTool(tooltips=[('Arrival Station',
                                                  '@station_name')])

        self.departure_station_widget = pn.widgets.AutocompleteInput(
            name='Departure Station',
            value=self.default_departure_station,
            options=self.station_names)
        self.arrival_station_widget = pn.widgets.AutocompleteInput(
            name='Arrival Station',
            value=self.default_arrival_station,
            options=self.station_names)
        self.arrival_time_widget = pn.widgets.DatetimeInput(
            name='Arrival Time', value=self.default_arrival_time)
        self.min_probability_widget = pn.widgets.FloatSlider(
            name='Minium Success Probability',
            start=0.0,
            end=1.0,
            value=self.default_min_success_probability)

        self.departure_tap_stream = hv.streams.SingleTap(
            x=stations.loc[self.default_departure_id, 'lat'],
            y=stations.loc[self.default_departure_id,
                           'lon']).rename(x='departure_lat', y='departure_lon')

        self.arrival_tap_stream = hv.streams.DoubleTap(
            x=stations.loc[self.default_arrival_id, 'lat'],
            y=stations.loc[self.default_arrival_id,
                           'lon']).rename(x='arrival_lat', y='arrival_lon')

        self.departure_tap_stream.add_subscriber(
            lambda departure_lat, departure_lon: set_to_closest_station(
                self.stations, self.departure_station_widget, departure_lat,
                departure_lon))
        self.arrival_tap_stream.add_subscriber(
            lambda arrival_lat, arrival_lon: set_to_closest_station(
                self.stations, self.arrival_station_widget, arrival_lat,
                arrival_lon))
        self.departure_station_widget.link(
            self.departure_tap_stream,
            callbacks={'value': self._update_stream})
        self.arrival_station_widget.link(
            self.arrival_tap_stream, callbacks={'value': self._update_stream})

        self.station_map = gv.DynamicMap(
            self._station_map(),
            streams=[self.departure_tap_stream, self.arrival_tap_stream])
        self.widgets = pn.Column(self.departure_station_widget,
                                 self.arrival_station_widget,
                                 self.arrival_time_widget,
                                 self.min_probability_widget)

        self.interface = pn.Row(pn.Spacer(height=600),
                                pn.Column(self.widgets, max_width=400),
                                self.station_map)
예제 #3
0
 def view(self):
     return (gv.DynamicMap(self.callback) * self.boxes).options(active_tools=['wheel_zoom'])
예제 #4
0
파일: api.py 프로젝트: pmav99/Thalassa
def get_timeseries(source, data, dataset, ymin, ymax, fmt):
    '''
    get time series plots
    '''
    #initialize timeseries_data
    if data.init is False:
        #find the maximum side length
        x, y = dataset['SCHISM_hgrid_node_x'].data, dataset[
            'SCHISM_hgrid_node_y'].data
        e1, e2, e3 = dataset['SCHISM_hgrid_face_nodes'].data.T
        s1 = abs((x[e1] - x[e2]) + 1j * (y[e1] - y[e2])).max()
        s2 = abs((x[e2] - x[e3]) + 1j * (y[e2] - y[e3])).max()
        s3 = abs((x[e3] - x[e1]) + 1j * (y[e3] - y[e1])).max()

        #save data
        data.sx, data.sy, data.x0, data.y0 = x, y, x.mean(), y.mean()
        data.mdist = np.max([s1, s2, s3])
        data.time = dataset['time'].data
        data.xys = []
        data.elev = []
        data.curve = []
        data.init = True

    def get_plot_point(x, y):
        if None not in [x, y]:
            add_remove_pts(x, y, data, dataset, fmt)

        if ((x is None) or (y is None)) and len(data.xys) == 0:
            xys = [(data.x0, data.y0)]
            hpoint = gv.Points(xys).opts(show_legend=False, visible=False)
            htext = gv.HoloMap({
                i: gv.Text(*xy, '{}'.format(i + 1)).opts(show_legend=False,
                                                         visible=False)
                for i, xy in enumerate(xys)
            }).overlay()
        else:
            xys = data.xys
            hpoint = gv.Points(xys).opts(color='r', size=3, show_legend=False)
            htext = gv.HoloMap({
                i: gv.Text(*xy, '{}'.format(i + 1)).opts(show_legend=False,
                                                         color='k',
                                                         fontsize=3)
                for i, xy in enumerate(xys)
            }).overlay()
        return hpoint * htext

    def get_plot_curve(x, y):
        mdist, mdata = extract_timeseries(x, y, data.sx, data.sy, dataset)
        if mdist > data.mdist:
            mdata = mdata * np.nan
        hdynamic = hv.Curve((data.time, mdata)).opts(color='k',
                                                     line_width=2,
                                                     line_dash='dotted')
        hcurve = hv.HoloMap({
            'dynamic': hdynamic,
            **{(i + 1): k
               for i, k in enumerate(data.curve)}
        }).overlay()
        return hcurve

    hpoint = gv.DynamicMap(get_plot_point,
                           streams=[DoubleTap(source=source, transient=True)])
    hcurve = gv.DynamicMap(get_plot_curve,
                           streams=[
                               PointerXY(x=data.x0, y=data.y0, source=source)
                           ]).opts(height=400,
                                   legend_cols=len(data.xys) + 1,
                                   legend_position='top',
                                   ylim=(float(ymin), float(ymax)),
                                   responsive=True,
                                   align='end',
                                   active_tools=["pan", "wheel_zoom"])

    return hpoint, hcurve
예제 #5
0
 def map_view(self):
     return self.tiles * gv.DynamicMap(self.update_map_values)
예제 #6
0
    def view(self):
        warnings.warn(
            'WMTS class is deprecated and will be removed in a future release.'
        )

        return gv.DynamicMap(self.element)
예제 #7
0
def explore(
    cyclonic=None,
    anticyclonic=None,
    hover_info=["segment", "track"],
    tiles=None,
    background_func=None,
    dynamic=False,
    date_widget="calendar",
):
    """explore NetworkObservations of cyclonic and/or anticyclonic

    :param cyclonic: cyclonic dataset, defaults to None
    :type cyclonic: :py:class:`~py_eddy_tracker.observations.network.NetworkObservations`, optional
    :param anticyclonic: anticyclonic dataset, defaults to None
    :type anticyclonic: :py:class:`~py_eddy_tracker.observations.network.NetworkObservations`, optional
    :param hover_info: list of data to show on hover, defaults to ["segment", "track"]
    :type hover_info: list, optional
    :param tiles: if specified, plot data over web tiles. like :py:class:`geoviews.source_tiles.EsriImagery`, defaults to None
    :type tiles: :py:class:`geoviews.element.geo.WMTS`, optional
    :param background_func: python function, takes as param a date and return a `xr.Dataset`, defaults to None
    :type background_func: callable, optional
    :param dynamic: if True, use :py:class:`~holoviews.operation.datashader.regrid` to delay plot of `background_func`, defaults to False
    :type dynamic: bool, optional
    :param date_widget: widget for date. if not calendar, it will be a radio, defaults to "calendar"
    :type date_widget: str, optional
    :return: bokeh plot


    .. note::

        the param `background_func` should return a :py:class :`~xarray.Dataset` with variables "lon", "lat"
        and "Grid_0001" for the data.
        The name of data should be on attribute "long_name" of Grid_0001, and "units" if wanted

       example of function :

        .. code-block:: python

            def date2dataset(date):

                fichier = f"/tmp/global_{date.strftime('%Y%m%d')}.nc"

                with xr.open_dataset(fichier) as ds:
                    ds = ds.rename({"longitude": "lon", "latitude": "lat", "adt": "Grid_0001"})
                    ds.Grid_0001.attrs["long_name"] = "adt
                    ds['lon'] = np.where(ds.lon > 180, ds.lon - 360, ds.lon)
                    ds = ds.sortby("lon").load()

                return ds
    """

    if cyclonic is None and anticyclonic is None:
        raise NotImplementedError("please specify cyclonic or anticyclonic")

    # if cyclonic or anticyclonic is not declared, only use one
    datasets = [(d, color)
                for d, color in [(cyclonic,
                                  "deepskyblue"), (anticyclonic, "red")]
                if d is not None]

    # compute every date with data
    datasets_unique = [np.unique(d.time) for d, _ in datasets]
    unique = np.unique(np.concatenate(datasets_unique))

    if date_widget == "calendar":
        now = datetime.date(1950, 1, 1) + datetime.timedelta(int(unique[0]))
        pn_date = pn.widgets.DatePicker(
            name="date",
            value=now,
            width=200,
            enabled_dates=(np.datetime64("1950-01-01") +
                           unique.astype("timedelta64[D]")).tolist(),
        )
        widget_date = pn_date
    else:

        pn_date = pn.widgets.DiscretePlayer(name="date",
                                            options=unique.tolist(),
                                            value=unique[0])

        @pn.depends(pn_date_value=pn_date.param.value)
        def plot_date(pn_date_value):
            return pn.pane.HTML(
                f"<h1>date = {np.datetime64('1950-01-01')+np.timedelta64(pn_date_value)}</h1>"
            )

        widget_date = pn.Row(pn_date, plot_date)

    @pn.depends(pn_date_value=pn_date.param.value)
    def update_all(pn_date_value):
        if isinstance(pn_date_value, datetime.date):
            # si on a choisi le widget DatePicker
            pn_date_value = (pn_date_value - datetime.date(1950, 1, 1)).days

        hv_polygons = []
        hv_exterieur = []

        for (d, color), d_unique in zip(datasets, datasets_unique):

            mask = d.time == pn_date_value
            sub_lon = ((d.contour_lon_s[mask] + 180) % 360) - 180
            sub_lat = d.contour_lat_s[mask]

            sub_data = np.moveaxis(np.array([sub_lon, sub_lat]), [0], [2])
            polygons = [Polygon(poly) for poly in sub_data]

            dct_data = {name: d[name][mask] for name in hover_info}
            dct_data["geometry"] = polygons
            gpd = geopandas.GeoDataFrame(dct_data)

            opts_common = dict(responsive=True)
            hv_polygons.append(
                gv.Polygons(gpd, vdims=hover_info).opts(line_color=color,
                                                        **opts_common))

            sub_lon = ((d.contour_lon_e[mask] + 180) % 360) - 180
            sub_lat = d.contour_lat_e[mask]

            _lon = flatten_line_matrix(sub_lon)
            _lat = flatten_line_matrix(sub_lat)
            hv_exterieur.append(
                gv.Path([np.array([_lon, _lat]).T]).opts(color=color,
                                                         alpha=0.70,
                                                         line_dash="dashed",
                                                         **opts_common))

        return gv.Overlay([*hv_polygons, *hv_exterieur]).opts(responsive=True,
                                                              tools=["hover"])

    if background_func is not None:

        @pn.depends(pn_date_value=pn_date.param.value)
        def update_fond(pn_date_value):

            if isinstance(pn_date_value, datetime.date):
                # si on a choisi le widget DatePicker
                date = pn_date_value
            else:
                date = datetime.datetime(
                    1950, 1, 1) + datetime.timedelta(days=int(pn_date_value))
            ds = background_func(date)

            info = ds.Grid_0001.units if hasattr(ds.Grid_0001, "units") else ""

            return gv.Image(
                (ds.lon, ds.lat, ds.Grid_0001.T),
                kdims=["lon", "lat"],
                vdims=[ds.Grid_0001.long_name],
            ).opts(responsive=True, tools=["hover"], clabel=info)

        if dynamic:
            fond = regrid(hv.DynamicMap(update_fond)).opts(height=500,
                                                           responsive=True)
        else:
            fond = hv.DynamicMap(update_fond).opts(responsive=True)

        if tiles is not None:
            visu = gv.Overlay([
                tiles,
                fond,
                gv.DynamicMap(update_all),
            ]).collate()
        else:
            visu = gv.Overlay([
                fond,
                gv.feature.land(scale="50m").opts(
                    responsive=True, line_color="black",
                    fill_color="darkgray"),  # , data_aspect=0.7),
                gv.DynamicMap(update_all),
            ]).collate()

        return pn.Column(widget_date,
                         visu,
                         sizing_mode="stretch_both",
                         min_height=600,
                         min_width=400)

    else:
        if tiles is not None:
            visu = gv.Overlay([tiles, gv.DynamicMap(update_all)]).collate()
        else:
            visu = gv.Overlay([
                gv.feature.land(scale="50m").opts(
                    responsive=True,
                    line_color="black",
                    fill_color="darkgray",
                    data_aspect=1,
                ),
                gv.DynamicMap(update_all),
            ]).collate()

    return pn.Column(widget_date,
                     visu,
                     sizing_mode="stretch_both",
                     min_height=600,
                     min_width=400)
예제 #8
0
 def view(self):
     return (gv.DynamicMap(self.callback) * self.boxes)
예제 #9
0
 def update_tiles(self):
     return self.tiles * gv.DynamicMap(self.update_poly)