diff --git a/geoviews/plotting/bokeh/callbacks.py b/geoviews/plotting/bokeh/callbacks.py index a1bdab56..1ec24844 100644 --- a/geoviews/plotting/bokeh/callbacks.py +++ b/geoviews/plotting/bokeh/callbacks.py @@ -96,8 +96,8 @@ def project_ranges(cb, msg, attributes): extents = x0, y0, x1, y1 x0, y0, x1, y1 = project_extents(extents, plot.projection, plot.current_frame.crs) - if plot._unwrap_lons and -180 <= x0 < 0 or -180 <= x1 < 0: - x0, x1 = x0 + 360, x1 + 360 + if plot._unwrap_lons and (-180 <= x0 < 0 or -180 <= x1 < 0): + x1 += 360 if x0 > x1: x0, x1 = x1, x0 coords = {'x_range': (x0, x1), 'y_range': (y0, y1)} diff --git a/geoviews/plotting/bokeh/plot.py b/geoviews/plotting/bokeh/plot.py index 20d1a118..d44017d0 100644 --- a/geoviews/plotting/bokeh/plot.py +++ b/geoviews/plotting/bokeh/plot.py @@ -6,7 +6,7 @@ from bokeh.models.tools import BoxZoomTool, WheelZoomTool from cartopy.crs import GOOGLE_MERCATOR, Mercator, PlateCarree, _CylindricalProjection from holoviews.core.dimension import Dimension -from holoviews.core.util import dimension_sanitizer +from holoviews.core.util import dimension_sanitizer, match_spec from holoviews.plotting.bokeh.element import ElementPlot, OverlayPlot as HvOverlayPlot from ...element import Shape, _Element, is_geographic @@ -104,14 +104,27 @@ def _update_ranges(self, element, ranges): ax_range.end = mid + min_interval/2. ax_range.min_interval = min_interval - def _set_unwrap_lons(self, element): + def _set_unwrap_lons(self, element, ranges): + """ + Check whether the lons should be transformed from 0, 360 to -180, 180 + """ if isinstance(self.geographic, _CylindricalProjection): - x1, x2 = element.range(0) - self._unwrap_lons = 0 <= x1 <= 360 and 0 <= x2 <= 360 + xdim = element.get_dimension(0) + x_range = ranges.get(xdim.name, {}).get('data') + if x_range: + x0, x1 = x_range + else: + x0, x1 = element.range(0) + # x0, depending on the step/interval, can be slightly less than 0, + # e.g. lon=np.arange(0, 360, 10) -> x0 = -5 from (step 10 / 2) + # other projections likely will not fall within this range + self._unwrap_lons = -90 <= x0 <= 360 and 180 <= x1 <= 540 def initialize_plot(self, ranges=None, plot=None, plots=None, source=None): opts = {} if isinstance(self, HvOverlayPlot) else {'source': source} fig = super().initialize_plot(ranges, plot, plots, **opts) + style_element = self.current_frame.last if self.batched else self.current_frame + el_ranges = match_spec(style_element, self.current_ranges) if self.current_ranges else {} if self.geographic and self.show_bounds and not self.overlaid: from . import GeoShapePlot shape = Shape(self.projection.boundary, crs=self.projection).options(fill_alpha=0) @@ -119,13 +132,14 @@ def initialize_plot(self, ranges=None, plot=None, plots=None, source=None): overlaid=True, renderer=self.renderer) shapeplot.geographic = False shapeplot.initialize_plot(plot=fig) - self._set_unwrap_lons(self.current_frame) + self._set_unwrap_lons(style_element, el_ranges) return fig def update_frame(self, key, ranges=None, element=None): - if element is not None: - self._set_unwrap_lons(element) super().update_frame(key, ranges=ranges, element=element) + style_element = self.current_frame.last if self.batched else self.current_frame + el_ranges = match_spec(style_element, self.current_ranges) if self.current_ranges else {} + self._set_unwrap_lons(style_element, el_ranges) def _postprocess_hover(self, renderer, source): super()._postprocess_hover(renderer, source)