Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add_lat_lon_tick_labels crashes for PlateCarre(central_longitude=180) #213

Closed
senesis opened this issue Feb 11, 2024 · 3 comments
Closed
Assignees
Labels
bug Something isn't working support Support request opened by outside user/collaborator

Comments

@senesis
Copy link

senesis commented Feb 11, 2024

Describe the bug
add_lat_lon_ticklabels crashes for PlateCarre(central_longitude=180), while there is no issue if central_longitude=0.
And by the way, when NOT calling add_lat_lon_ticklabels, the labels doesn't take account of the value of central_longitude !

To Reproduce
Execute this code, setting central_longitude first to 0, then to 180. And also one more time commenting out the call to add_lat_lon_ticklabels

import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.feature as cfeature
import geocat.viz as gv

fig = plt.figure(figsize=(6, 3))
projection = ccrs.PlateCarree(central_longitude=180)
ax = plt.axes(projection=projection)
ax.add_feature(cfeature.LAND, color='silver',zorder=1)

ax.xaxis.set_visible(True)
ax.yaxis.set_visible(True)

gv.add_lat_lon_ticklabels(ax)

plt.show();

Screenshots
Here is the crash report for central_longitude=180.

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/IPython/core/formatters.py:340, in BaseFormatter.__call__(self, obj)
    338     pass
    339 else:
--> 340     return printer(obj)
    341 # Finally look for special method names
    342 method = get_real_method(obj, self.print_method)

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/IPython/core/pylabtools.py:152, in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    149     from matplotlib.backend_bases import FigureCanvasBase
    150     FigureCanvasBase(fig)
--> 152 fig.canvas.print_figure(bytes_io, **kw)
    153 data = bytes_io.getvalue()
    154 if fmt == 'svg':

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/backend_bases.py:2342, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2336     renderer = _get_renderer(
   2337         self.figure,
   2338         functools.partial(
   2339             print_method, orientation=orientation)
   2340     )
   2341     with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2342         self.figure.draw(renderer)
   2344 if bbox_inches:
   2345     if bbox_inches == "tight":

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/artist.py:95, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     93 @wraps(draw)
     94 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 95     result = draw(artist, renderer, *args, **kwargs)
     96     if renderer._rasterizing:
     97         renderer.stop_rasterizing()

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/artist.py:72, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     69     if artist.get_agg_filter() is not None:
     70         renderer.start_filter()
---> 72     return draw(artist, renderer)
     73 finally:
     74     if artist.get_agg_filter() is not None:

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/figure.py:3175, in Figure.draw(self, renderer)
   3172         # ValueError can occur when resizing a window.
   3174 self.patch.draw(renderer)
-> 3175 mimage._draw_list_compositing_images(
   3176     renderer, self, artists, self.suppressComposite)
   3178 for sfig in self.subfigs:
   3179     sfig.draw(renderer)

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/image.py:131, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    129 if not_composite or not has_images:
    130     for a in artists:
--> 131         a.draw(renderer)
    132 else:
    133     # Composite any adjacent images together
    134     image_group = []

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/artist.py:72, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     69     if artist.get_agg_filter() is not None:
     70         renderer.start_filter()
---> 72     return draw(artist, renderer)
     73 finally:
     74     if artist.get_agg_filter() is not None:

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:535, in GeoAxes.draw(self, renderer, **kwargs)
    530         self.imshow(img, extent=extent, origin=origin,
    531                     transform=factory.crs, *factory_args[1:],
    532                     **factory_kwargs)
    533 self._done_img_factory = True
--> 535 return super().draw(renderer=renderer, **kwargs)

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/artist.py:72, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     69     if artist.get_agg_filter() is not None:
     70         renderer.start_filter()
---> 72     return draw(artist, renderer)
     73 finally:
     74     if artist.get_agg_filter() is not None:

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/axes/_base.py:3064, in _AxesBase.draw(self, renderer)
   3061 if artists_rasterized:
   3062     _draw_rasterized(self.figure, artists_rasterized, renderer)
-> 3064 mimage._draw_list_compositing_images(
   3065     renderer, self, artists, self.figure.suppressComposite)
   3067 renderer.close_group('axes')
   3068 self.stale = False

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/image.py:131, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    129 if not_composite or not has_images:
    130     for a in artists:
--> 131         a.draw(renderer)
    132 else:
    133     # Composite any adjacent images together
    134     image_group = []

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/artist.py:72, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     69     if artist.get_agg_filter() is not None:
     70         renderer.start_filter()
---> 72     return draw(artist, renderer)
     73 finally:
     74     if artist.get_agg_filter() is not None:

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/axis.py:1388, in Axis.draw(self, renderer, *args, **kwargs)
   1385     return
   1386 renderer.open_group(__name__, gid=self.get_gid())
-> 1388 ticks_to_draw = self._update_ticks()
   1389 tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer)
   1391 for tick in ticks_to_draw:

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/axis.py:1275, in Axis._update_ticks(self)
   1270 """
   1271 Update ticks (position and labels) using the current data interval of
   1272 the axes.  Return the list of ticks that will be drawn.
   1273 """
   1274 major_locs = self.get_majorticklocs()
-> 1275 major_labels = self.major.formatter.format_ticks(major_locs)
   1276 major_ticks = self.get_major_ticks(len(major_locs))
   1277 self.major.formatter.set_locs(major_locs)

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/ticker.py:218, in Formatter.format_ticks(self, values)
    216 """Return the tick labels for all the ticks at once."""
    217 self.set_locs(values)
--> 218 return [self(value, i) for i, value in enumerate(values)]

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/matplotlib/ticker.py:218, in <listcomp>(.0)
    216 """Return the tick labels for all the ticks at once."""
    217 self.set_locs(values)
--> 218 return [self(value, i) for i, value in enumerate(values)]

File /net/nfs/tools/Users/SU/jservon/spirit-2021.11_envs/20240209/lib/python3.10/site-packages/cartopy/mpl/ticker.py:75, in _PlateCarreeFormatter.__call__(self, value, pos)
     71     # Round the transformed value using a given precision for display
     72     # purposes. Transforms can introduce minor rounding errors that
     73     # make the tick values look bad, these need to be accounted for.
     74     f = 1. / self._transform_precision
---> 75     projected_value = round(f * projected_value) / f
     77 else:
     78 
     79     # There is no projection so we assume it is already PlateCarree
     80     projected_value = value

ValueError: cannot convert float NaN to integer

<Figure size 600x300 with 1 Axes>

OS:
see #210

Environment
see #210

@senesis senesis added bug Something isn't working support Support request opened by outside user/collaborator labels Feb 11, 2024
@kafitzgerald
Copy link
Collaborator

Thanks again for the note here.

It looks like my recommendation from the prior issue (#210) isn't as robust as I'd hoped and probably not a great way to handle that situation. I'll update the conversation there to reflect this in a moment.

However, gv.set_axes_limits_and_ticks should do the trick as shown below and hopefully be more robust. Setting ticks via the recommended methods in cartopy should also work.

import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.feature as cfeature
import geocat.viz as gv

fig = plt.figure(figsize=(6, 3))
projection = ccrs.PlateCarree(central_longitude=180)
ax = plt.axes(projection=projection)
ax.add_feature(cfeature.LAND, color='silver',zorder=1)

gv.set_axes_limits_and_ticks(ax,
                             xticks=[-180,-90,0,90,180],
                             yticks=[-90,0,90])

gv.add_lat_lon_ticklabels(ax)

plt.show()

I'm going to close this issue for now and follow up on the original issue, but please feel free to reopen if you have questions and/or this doesn't address your problem.

@kafitzgerald kafitzgerald self-assigned this Feb 12, 2024
@senesis
Copy link
Author

senesis commented Feb 13, 2024

From the documentation, gv.add_lat_lon_ticklabels() is a : "Utility function to make plots look like NCL plots by adding latitude, longitude tick labels"

Its baseline use is to avoid having to compute the set of tick locations. So, the solution you propose does not meet that requirement.

So I am afraid that this issue cannot be closed.

@kafitzgerald
Copy link
Collaborator

Sorry for the confusion.

Certainly the description and documentation is at the very least is misleading as it stands regarding add_major_minor_ticks and add_lat_lon_ticklabels and the need to set ticks prior to using these functions (as described in your issue #210). Ideally we would address this in the code as well so additional steps are not needed. This should be addressed by that issue.

This particular issue #213 though seemed to relate to the crash/error from the combination of my original suggestion and the projection described above which can be addressed by the updated suggestion here and in #210. My intent with closing this issue was to indicate that this was now a duplicate of #210 rather than its own issue not necessarily that it had been fully addressed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working support Support request opened by outside user/collaborator
Projects
None yet
Development

No branches or pull requests

2 participants