holoviz / hvplot

A high-level plotting API for pandas, dask, xarray, and networkx built on HoloViews
https://hvplot.holoviz.org
BSD 3-Clause "New" or "Revised" License
1.14k stars 108 forks source link

AttributeError: 'list' object has no attribute 'xy' when wrong crs is assigned. #595

Open SimchaGD opened 3 years ago

SimchaGD commented 3 years ago

This issue is related to my stackoverflow post here: https://stackoverflow.com/questions/67139335/hvplot-attributeerror-list-object-has-no-attribute-xy

When I was using hvplot with pandas. This was my code:

import geopandas as gpd
import hvplot.pandas
coords = gpd.read_file('gemeente_2019_v2.shp')
coords.hvplot(geo = True)

the error I got was:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~\.conda\envs\jh-open\lib\site-packages\IPython\core\formatters.py in __call__(self, obj, include, exclude)
    968 
    969             if method is not None:
--> 970                 return method(include=include, exclude=exclude)
    971             return None
    972         else:

~\.conda\envs\jh-open\lib\site-packages\holoviews\core\dimension.py in _repr_mimebundle_(self, include, exclude)
   1315         combined and returned.
   1316         """
-> 1317         return Store.render(self)
   1318 
   1319 

~\.conda\envs\jh-open\lib\site-packages\holoviews\core\options.py in render(cls, obj)
   1403         data, metadata = {}, {}
   1404         for hook in hooks:
-> 1405             ret = hook(obj)
   1406             if ret is None:
   1407                 continue

~\.conda\envs\jh-open\lib\site-packages\holoviews\ipython\display_hooks.py in pprint_display(obj)
    280     if not ip.display_formatter.formatters['text/plain'].pprint:
    281         return None
--> 282     return display(obj, raw_output=True)
    283 
    284 

~\.conda\envs\jh-open\lib\site-packages\holoviews\ipython\display_hooks.py in display(obj, raw_output, **kwargs)
    250     elif isinstance(obj, (CompositeOverlay, ViewableElement)):
    251         with option_state(obj):
--> 252             output = element_display(obj)
    253     elif isinstance(obj, (Layout, NdLayout, AdjointLayout)):
    254         with option_state(obj):

~\.conda\envs\jh-open\lib\site-packages\holoviews\ipython\display_hooks.py in wrapped(element)
    144         try:
    145             max_frames = OutputSettings.options['max_frames']
--> 146             mimebundle = fn(element, max_frames=max_frames)
    147             if mimebundle is None:
    148                 return {}, {}

~\.conda\envs\jh-open\lib\site-packages\holoviews\ipython\display_hooks.py in element_display(element, max_frames)
    190         return None
    191 
--> 192     return render(element)
    193 
    194 

~\.conda\envs\jh-open\lib\site-packages\holoviews\ipython\display_hooks.py in render(obj, **kwargs)
     66         renderer = renderer.instance(fig='png')
     67 
---> 68     return renderer.components(obj, **kwargs)
     69 
     70 

~\.conda\envs\jh-open\lib\site-packages\holoviews\plotting\renderer.py in components(self, obj, fmt, comm, **kwargs)
    408                 doc = Document()
    409                 with config.set(embed=embed):
--> 410                     model = plot.layout._render_model(doc, comm)
    411                 if embed:
    412                     return render_model(model, comm)

~\.conda\envs\jh-open\lib\site-packages\panel\viewable.py in _render_model(self, doc, comm)
    425         if comm is None:
    426             comm = state._comm_manager.get_server_comm()
--> 427         model = self.get_root(doc, comm)
    428 
    429         if config.embed:

~\.conda\envs\jh-open\lib\site-packages\panel\viewable.py in get_root(self, doc, comm, preprocess)
    482         """
    483         doc = init_doc(doc)
--> 484         root = self._get_model(doc, comm=comm)
    485         if preprocess:
    486             self._preprocess(root)

~\.conda\envs\jh-open\lib\site-packages\panel\layout\base.py in _get_model(self, doc, root, parent, comm)
    111         if root is None:
    112             root = model
--> 113         objects = self._get_objects(model, [], doc, root, comm)
    114         props = dict(self._init_params(), objects=objects)
    115         model.update(**self._process_param_change(props))

~\.conda\envs\jh-open\lib\site-packages\panel\layout\base.py in _get_objects(self, model, old_objects, doc, root, comm)
    101             else:
    102                 try:
--> 103                     child = pane._get_model(doc, root, model, comm)
    104                 except RerenderError:
    105                     return self._get_objects(model, current_objects[:i], doc, root, comm)

~\.conda\envs\jh-open\lib\site-packages\panel\pane\holoviews.py in _get_model(self, doc, root, parent, comm)
    237             plot = self.object
    238         else:
--> 239             plot = self._render(doc, comm, root)
    240 
    241         plot.pane = self

~\.conda\envs\jh-open\lib\site-packages\panel\pane\holoviews.py in _render(self, doc, comm, root)
    302                 kwargs['comm'] = comm
    303 
--> 304         return renderer.get_plot(self.object, **kwargs)
    305 
    306     def _cleanup(self, root):

~\.conda\envs\jh-open\lib\site-packages\holoviews\plotting\bokeh\renderer.py in get_plot(self_or_cls, obj, doc, renderer, **kwargs)
     71         combining the bokeh model with another plot.
     72         """
---> 73         plot = super(BokehRenderer, self_or_cls).get_plot(obj, doc, renderer, **kwargs)
     74         if plot.document is None:
     75             plot.document = Document() if self_or_cls.notebook_context else curdoc()

~\.conda\envs\jh-open\lib\site-packages\holoviews\plotting\renderer.py in get_plot(self_or_cls, obj, doc, renderer, comm, **kwargs)
    241             init_key = tuple(v if d is None else d for v, d in
    242                              zip(plot.keys[0], defaults))
--> 243             plot.update(init_key)
    244         else:
    245             plot = obj

~\.conda\envs\jh-open\lib\site-packages\holoviews\plotting\plot.py in update(self, key)
    980     def update(self, key):
    981         if len(self) == 1 and ((key == 0) or (key == self.keys[0])) and not self.drawn:
--> 982             return self.initialize_plot()
    983         item = self.__getitem__(key)
    984         self.traverse(lambda x: setattr(x, '_updated', True))

~\.conda\envs\jh-open\lib\site-packages\geoviews\plotting\bokeh\plot.py in initialize_plot(self, ranges, plot, plots, source)
    111     def initialize_plot(self, ranges=None, plot=None, plots=None, source=None):
    112         opts = {} if isinstance(self, HvOverlayPlot) else {'source': source}
--> 113         fig = super(GeoPlot, self).initialize_plot(ranges, plot, plots, **opts)
    114         if self.geographic and self.show_bounds and not self.overlaid:
    115             from . import GeoShapePlot

~\.conda\envs\jh-open\lib\site-packages\holoviews\plotting\bokeh\element.py in initialize_plot(self, ranges, plot, plots, source)
   1394         # Initialize plot, source and glyph
   1395         if plot is None:
-> 1396             plot = self._init_plot(key, style_element, ranges=ranges, plots=plots)
   1397             self._init_axes(plot)
   1398         else:

~\.conda\envs\jh-open\lib\site-packages\holoviews\plotting\bokeh\element.py in _init_plot(self, key, element, plots, ranges)
    492         subplots = list(self.subplots.values()) if self.subplots else []
    493 
--> 494         axis_types, labels, plot_ranges = self._axes_props(plots, subplots, element, ranges)
    495         xlabel, ylabel, _ = labels
    496         x_axis_type, y_axis_type = axis_types

~\.conda\envs\jh-open\lib\site-packages\holoviews\plotting\bokeh\element.py in _axes_props(self, plots, subplots, element, ranges)
    403         # Get the Element that determines the range and get_extents
    404         range_el = el if self.batched and not isinstance(self, OverlayPlot) else element
--> 405         l, b, r, t = self.get_extents(range_el, ranges)
    406         if self.invert_axes:
    407             l, b, r, t = b, l, t, r

~\.conda\envs\jh-open\lib\site-packages\geoviews\plotting\plot.py in get_extents(self, element, ranges, range_type)
     71             extents = None
     72         else:
---> 73             extents = project_extents(extents, element.crs, proj)
     74         return (np.NaN,)*4 if not extents else extents

~\.conda\envs\jh-open\lib\site-packages\geoviews\util.py in project_extents(extents, src_proj, dest_proj, tol)
     95             geom_in_src_proj = geom_clipped_to_dest_proj
     96         try:
---> 97             geom_in_crs = dest_proj.project_geometry(geom_in_src_proj, src_proj)
     98         except ValueError:
     99             src_name =type(src_proj).__name__

~\.conda\envs\jh-open\lib\site-packages\cartopy\crs.py in project_geometry(self, geometry, src_crs)
    216             raise ValueError('Unsupported geometry '
    217                              'type {!r}'.format(geom_type))
--> 218         return getattr(self, method_name)(geometry, src_crs)
    219 
    220     def _project_point(self, point, src_crs):

~\.conda\envs\jh-open\lib\site-packages\cartopy\crs.py in _project_polygon(self, polygon, src_crs)
    352             is_ccw = True
    353         else:
--> 354             is_ccw = polygon.exterior.is_ccw
    355         # Project the polygon exterior/interior rings.
    356         # Each source ring will result in either a ring, or one or more

~\.conda\envs\jh-open\lib\site-packages\shapely\geometry\polygon.py in is_ccw(self)
     86     def is_ccw(self):
     87         """True is the ring is oriented counter clock-wise"""
---> 88         return bool(self.impl['is_ccw'](self))
     89 
     90     @property

~\.conda\envs\jh-open\lib\site-packages\shapely\algorithms\cga.py in is_ccw_op(ring)
     12     """Predicate implementation"""
     13     def is_ccw_op(ring):
---> 14         return signed_area(ring) >= 0.0
     15     return is_ccw_op
     16 

~\.conda\envs\jh-open\lib\site-packages\shapely\algorithms\cga.py in signed_area(ring)
      4     algorithm at: https://web.archive.org/web/20080209143651/http://cgafaq.info:80/wiki/Polygon_Area
      5     """
----> 6     xs, ys = ring.coords.xy
      7     xs.append(xs[1])
      8     ys.append(ys[1])

AttributeError: 'list' object has no attribute 'xy'

:Polygons   [Longitude,Latitude]

It was fixed by changing the CRS. If a more clear error message was given, I think I could fix this problem on my own.

I have not looked at the source code, but might it be possible to convert the crs to a default when such error appears?

maximlt commented 2 years ago

This looks similar to https://github.com/holoviz/hvplot/issues/738 but I don't think quite the same issue.

This works even if it takes a very long time to render:

coords.hvplot(geo=True, crs=cartopy.crs.epsg(coords.crs.to_epsg()))

I have to better understand how hvPlot handles geo/crs, and we should make it simple to user.