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

Feature labels on top of map #1666

Conversation

eirik-mortensen
Copy link
Contributor

@eirik-mortensen eirik-mortensen commented Oct 15, 2020

Introduction

This pull request is based on the issue #1642: Add capability for non-inline grid labels to appear inside map

Rationale

As a satellite image provider I need to minimize the size of images and meet the customers requirements on how products shall be presented.

Implications

With this change all non-inline labels will be shown on top of the map and not outside. This occurs if x-, y- or both padding are negative. All labels that is shown outside the map is removed.

Input

top = 49.3457868  # north lat
left = -124.7844079  # west long
right = -66.9513812  # east long
bottom = 24.7433195  # south lat
plt.figure(figsize=(35, 35))
for i, proj in enumerate(TEST_PROJS, 1):
    if isinstance(proj, tuple):
       proj, kwargs = proj
    else:
       kwargs = {}
        ax = plt.subplot(7, 4, i, projection=proj(**kwargs))
        try:
            ax.set_extent([left, right, bottom, top], crs=ccrs.PlateCarree())
        except Exception:
            pass
        ax.set_title(proj, y=1.075)
        if ccrs.PROJ4_VERSION[:2] == (5, 0) and proj in (
            ccrs.Orthographic,
            ccrs.AlbersEqualArea,
            ccrs.Geostationary,
            ccrs.NearsidePerspective,
        ):
            # Above projections are broken, so skip labels.
            # Add gridlines anyway to minimize image differences.
            ax.gridlines()
        else:
            gl = ax.gridlines(draw_labels=True, clip_on=True)
            gl.xpadding = -5
            gl.ypadding = -5
        ax.coastlines(resolution="110m")
plt.subplots_adjust(wspace=0.35, hspace=0.35)

Code is the same as in the unit test.

Output

gridliner_labels_intersect_map

Note

  • I cant seem to figure out why a couple of the numbers in Mollweide, Sinusoidal and InterruptedGoodeHomolosine do intersect with the map bbox.
  • Unit test provided
  • All test passes

lib/cartopy/mpl/gridliner.py Outdated Show resolved Hide resolved
lib/cartopy/mpl/gridliner.py Outdated Show resolved Hide resolved
lib/cartopy/tests/mpl/test_gridliner.py Outdated Show resolved Hide resolved
@@ -365,3 +363,39 @@ def test_gridliner_line_limits():
for path in paths:
assert (np.min(path.vertices, axis=0) >= (xlim[0], ylim[0])).all()
assert (np.max(path.vertices, axis=0) <= (xlim[1], ylim[1])).all()

@pytest.mark.natural_earth

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E302 expected 2 blank lines, found 1

lib/cartopy/mpl/gridliner.py Outdated Show resolved Hide resolved
lib/cartopy/tests/mpl/test_gridliner.py Outdated Show resolved Hide resolved
@stefraynaud
Copy link
Contributor

In think a special keyword like ìnsidemust be added toGridliner.initto activate this behavior of labels, and considerself.xpaddingandself.ypadding` as always positive.
I added this feature to my local version of PR #1537, which is finally a major revision of the labelling system that solves numerous issues.

@eirik-mortensen
Copy link
Contributor Author

Ok. So you have implemented this functionality in your branch stefraynaud:bug_label_visibility? I also need the feature where labels outside of map is removed completely. Since i use bbox_inches="tight", pad_inches=0, to remove borders when saving images output.

What is your suggestion on how we proceed?

@eirik-mortensen
Copy link
Contributor Author

@stefraynaud, I will just use my local solution until you have rolled out your PRs. You have a timeline for the next release?

lib/cartopy/mpl/gridliner.py Outdated Show resolved Hide resolved
lib/cartopy/mpl/gridliner.py Outdated Show resolved Hide resolved
gl.ypadding = -5
ax.coastlines(resolution="110m")
plt.subplots_adjust(wspace=0.35, hspace=0.35)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

W391 blank line at end of file

@stefraynaud
Copy link
Contributor

@Emsterr Except a few tests I must add, I mostly dépends on the CI success and on the review process.

@stefraynaud
Copy link
Contributor

@Emsterr You should push forward this PR to make it merged as soon as possible.

@eirik-mortensen
Copy link
Contributor Author

@stefraynaud sorry I'm a bit confused, what do you mean 'push forward'? isn't it ready to be merged?

# Non-inline must not run through the outline.
elif not outline_path.intersects_path(this_path):
elif not outline_path.intersects_path(this_path,
filled=is_filled):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about adding the boolean tests directly into the argument here instead of creating another variable?



@pytest.mark.natural_earth
@ImageTesting([grid_label_intersect_map_image],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need another 1 MB image comparison test? Or can this be checked by comparing against the positions of the labels and whether they are visible or not?

Or maybe just a single smaller image would be fine.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that could work. I'll make some new test tomorrow.

img[:, :, 0:3] = old_img
# Put an alpha channel in if the image was masked.
if not np.any(alpha):
alpha = 1
img[:, :, 3] = np.ma.filled(alpha, fill_value=0) * \
(~np.any(old_img.mask, axis=2))
(~np.any(old_img.mask, axis=2))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E127 continuation line over-indented for visual indent

lib/cartopy/mpl/gridliner.py Outdated Show resolved Hide resolved
lib/cartopy/mpl/gridliner.py Outdated Show resolved Hide resolved
@eirik-mortensen eirik-mortensen force-pushed the feature_labels_on_top_of_map branch from 0ee38fe to e0a05d8 Compare December 22, 2020 12:40
@EirikMortensen
Copy link

EirikMortensen commented Dec 22, 2020

@greglucas i did some changes based on stefraynaud feedback.

The user should only operate padding values as positive and adjust labels inside with the class input parameter.

However, in the class the _x/_ypadding is set to negative if labels_inside is true. The same goes for the initial value _x/_ypadding.

Copy link
Contributor

@greglucas greglucas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused now. Why can't we allow negative values in the padding? What if I want x labels inside, but ylabels outside the plot? I guess it seems to me that if I want inside_labels, then I should add a negative padding. So, then in this code I assume it you could actually do the test
if xpadding < 0 then inside_x_labels = True and make all your adjustments later based on that? So, rather than adding a new keyword argument, we could just implicitly determine that based on whether the padding arguments are positive or negative?

@eirik-mortensen
Copy link
Contributor Author

@greglucas i do agree with you. As you mention in your comment, I inital implemented this with the possibility to operate with negative input values, but as stefraynaud sugested (and had implemented in his solution) i changed it.

I will revert to the previous implementation and remove the labels_inside input variable.

As you mention, Regarding the x and y padding, What if I want x labels inside, but ylabels outside the plot?, should the padding top/bottom and left/right be adjusted as one, or is it a solution to seperate all of them. Example where you want bottom to be inside but not top.

x_top_padding, x_bottom_padding...

It would give more freedom, but, I think its a bit cumbersome and messy to seperate all sides.

Suggestions?

@stefraynaud
Copy link
Contributor

I think that we code that is compute the effective padding must revisited to reach the requested behavior:
https://github.com/emsterr/cartopy/blob/e0a05d8bd4082474bcbcbf024a2d57312188edd2/lib/cartopy/mpl/gridliner.py#L736

dx = ypadding * np.cos(angle * np.pi / 180)
dy = xpadding * np.sin(angle * np.pi / 180)

Only the xpadding must be used as a distance for xlabels and only the ypadding must be used as a distance for ylabels.

# For xlabels
dx = xpadding * np.cos(angle * np.pi / 180)
dy = xpadding * np.sin(angle * np.pi / 180)

# For ylabels
dx = ypadding * np.cos(angle * np.pi / 180)
dy = ypadding * np.sin(angle * np.pi / 180)

I also have to take this into account in my PR.
My two cents.

@eirik-mortensen
Copy link
Contributor Author

@stefraynaud, with the implementation i had where negative padding was possible, the behaviour was as expected.

What will differ with this implementation?

# For xlabels
dx = xpadding * np.cos(angle * np.pi / 180)
dy = xpadding * np.sin(angle * np.pi / 180)

# For ylabels
dx = ypadding * np.cos(angle * np.pi / 180)
dy = ypadding * np.sin(angle * np.pi / 180)

@stefraynaud
Copy link
Contributor

@Emsterr I have trouble to find the implementation you had and I suspect that I misunderstood the meaning of x and y padding. So sorry for the noise and I will also update my PR accordingly.

@eirik-mortensen
Copy link
Contributor Author

No worries, i squased my commits to the later implementation, so its not in the branch. I will implement the former solution again.

eirik-mortensen added a commit to eirik-mortensen/cartopy that referenced this pull request Jan 13, 2021
@eirik-mortensen eirik-mortensen force-pushed the feature_labels_on_top_of_map branch from e0a05d8 to 175570c Compare January 13, 2021 14:22
assert gl.xpadding == 10 and gl.ypadding == 10
gl.xpadding = gl.ypadding = -5
assert gl.xpadding == -5 and gl.ypadding == -5

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

W391 blank line at end of file

@eirik-mortensen eirik-mortensen force-pushed the feature_labels_on_top_of_map branch from 175570c to a21ec88 Compare January 13, 2021 14:25
@eirik-mortensen
Copy link
Contributor Author

@stefraynaud God morning. Did you get a PR regarding negative padding into v0.19?

@stefraynaud
Copy link
Contributor

Hi @Emsterr my PR includes it and I'm about to update the baseline images once my ssh connexion is allowed.
However, I'm not sure it's gonna be included in 0.19.

@eirik-mortensen
Copy link
Contributor Author

@stefraynaud
Ok, from my perspective it would be good to get either yours or mine PR into v0.19 so i can remove my fork that is used by my software. Dont think i need to change to much if your version is merged.

As long as one of the PRs gets in i can take my shoulders down.

@greglucas, whats your thought on this?

@smartlixx
Copy link
Contributor

V0.19 has been released. You should aim at V0.20.

@eirik-mortensen
Copy link
Contributor Author

that's unfortunate. Hopefully it will take a shorter amount of time from v0.19 to v0.20 as from v0.18 to v0.19.

@greglucas Are there any plans on increasing the amount of releases in the near future?

@greglucas
Copy link
Contributor

Yeah, I'd like to get to about a 6 month release schedule to more closely track other package's nominal release schedule as well. But, it all depends on volunteer hours submitting and reviewing PRs and we can't guarantee anything for the schedules.

@QuLogic
Copy link
Member

QuLogic commented Sep 10, 2021

Closed by #1537

@QuLogic QuLogic closed this Sep 10, 2021
@QuLogic
Copy link
Member

QuLogic commented Sep 10, 2021

OK, I'm not actually sure whether this really is replaced by #1537, but @stefraynaud included it in the list.

@stefraynaud
Copy link
Contributor

@QuLogic I confirm: a negative padding should do the trick.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants