GPlates / gplately

GPlately is a Python package to interrogate tectonic plate reconstructions.
https://gplates.github.io/gplately/
GNU General Public License v2.0
56 stars 13 forks source link

plotting artefacts in Orthographic projection #191

Open michaelchin opened 3 months ago

michaelchin commented 3 months ago

Steps to reproduce:

  1. set projection to "projection=ccrs.Orthographic(central_longitude = -165, central_latitude=15))"
  2. use Muller2019 model
  3. call gplately gplot.plot_all_topologies()

I seems the Cartopy cannot handle some polygons properly in Orthographic projection. We need to find out what kind of polygons caused this problem and how to avoid it.

336353449-61a8e0b9-961d-40e6-973a-7de5a5ae9763

michaelchin commented 3 months ago

As we can see, those two straight lines are not showing in GPlates.

Screenshot 2024-06-12 at 10 10 26 AM Screenshot 2024-06-12 at 10 12 48 AM
michaelchin commented 3 months ago

This Issue was a part of #183. Create a separate Issue for better tracking.

michaelchin commented 3 months ago

336799577-401597ba-2ba0-4c07-ad17-fc05d5c6f2f9 (1)

Screenshot 2024-06-13 at 4 48 33 PM
michaelchin commented 3 months ago

Just tried to plot with pygplates directly, no artefacts. So the artefacts must be introduced by gplately code. Bug confirmed.

See the map below plotted without using gplately. No line artefacts.

Screenshot 2024-06-25 at 4 20 18 PM
michaelchin commented 3 months ago

In fact, the artefacts came from different places. I have found two possible places.

https://github.com/GPlates/gplately/blob/4237ca04e9791e774ff1e90b94e69eb74a6931ad/gplately/geometry.py#L165

https://github.com/GPlates/gplately/blob/4237ca04e9791e774ff1e90b94e69eb74a6931ad/gplately/utils/plot_utils.py#L380-L394

michaelchin commented 3 months ago

@brmather do you know who is the author of above code?

jcannon-gplates commented 3 months ago

Just tried to plot with pygplates directly, no artefacts

I wonder if it's related to the pygplates.DateLineWrapper in pygplates_to_shapely(). Judging from the above screenshots I don't think so though.

Also, I'm not sure if dateline wrapping is needed for 3D globe projections (like orthographic)? Only because it's meant for wrapping to the dateline on a flat 2D projection. Although it probably doesn't hurt to 2D wrap on a 3D projection - I guess worst case is a polygon that crosses the dateline - it would get split into two, with a vertical line (along the dateline = central meridian + 180). But that probably wouldn't explain the artefacts you're seeing.

michaelchin commented 3 months ago

Just tried to plot with pygplates directly, no artefacts

I wonder if it's related to the pygplates.DateLineWrapper in pygplates_to_shapely(). Judging from the above screenshots I don't think so though.

Also, I'm not sure if dateline wrapping is needed for 3D globe projections (like orthographic)? Only because it's meant for wrapping to the dateline on a flat 2D projection. Although it probably doesn't hurt to 2D wrap on a 3D projection - I guess worst case is a polygon that crosses the dateline - it would get split into two, with a vertical line (along the dateline = central meridian + 180). But that probably wouldn't explain the artefacts you're seeing.

Thanks John. I have checked in my debug code here https://github.com/GPlates/gplately/commit/9f085925056e7ed67928bbc77e99f15c0c1b9149 in "191-plotting-artefacts-in-orthographic-projection" branch

If you go to tests-dir/unittest/ and run ./test_plot.py, you can see the artefacts are gone. So I guess the artefacts must have been produced in the skipped code.

Screenshot 2024-06-26 at 2 46 42 PM
jcannon-gplates commented 3 months ago

So I guess the artefacts must have been produced in the skipped code.

Thanks, it does look like it's in the section that does dateline wrapping. I'll take a look and see.

jcannon-gplates commented 3 months ago

Actually, after testing your debug branch, I don't think it's the pyGPlates dateline wrapping after all.

If I comment out this line then the plot still looks good (ie, with dateline wrapping enabled), but if I also comment out this line then the spurious lines reappear.

So I think the bug is probably in the _fill_all_edges() function somewhere. I'm not exactly sure what that function does, but it appears to fix up polygon edges that are near the projection boundary (which in the case of orthographic projection would be a circle). I guess this is somewhat similar to pygplates.DatelineWrapper (which clips polygons/polylines to the latitude-longitude rectangle boundary, but only for 2D maps, not 3D globes). But I'm not sure how it differs to _fill_all_edges(). As in, do you need them both, or just one of them?

michaelchin commented 3 months ago

Actually, after testing your debug branch, I don't think it's the pyGPlates dateline wrapping after all.

If I comment out this line then the plot still looks good (ie, with dateline wrapping enabled), but if I also comment out this line then the spurious lines reappear.

So I think the bug is probably in the _fill_all_edges() function somewhere. I'm not exactly sure what that function does, but it appears to fix up polygon edges that are near the projection boundary (which in the case of orthographic projection would be a circle). I guess this is somewhat similar to pygplates.DatelineWrapper (which clips polygons/polylines to the latitude-longitude rectangle boundary, but only for 2D maps, not 3D globes). But I'm not sure how it differs to _fill_all_edges(). As in, do you need them both, or just one of them?

Thanks John. When I skipped dateline wrapping, one of the spurious lines is gone. See the screenshot below.

Screenshot 2024-07-02 at 4 44 28 PM

When I skipped [_fill_all_edges()], both of the lines are gone.

I guess you are right. The root cause may be in [_fill_all_edges()] and the dateline wrapping only make it worse(produced one more artefact line).

I am not sure what the [_fill_all_edges()] does. I guess it has something to do with that cartopy cannot handle certain polygons properly near the map boundary??????

jcannon-gplates commented 3 months ago

When I skipped dateline wrapping, one of the spurious lines is gone. See the screenshot below.

I'm not quite sure which other line you mean? There's an image above for 59Ma, but this is 52Ma (ie, you and I are now discussing plots at 52Ma). Maybe you noticed the other line in the 59Ma image?

By the way, I discovered I also needed to install PyQt6 in order for tests-dir/unittest/test_plot.py to display the plot and avoid the error message UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown (I'm on Windows 11).

michaelchin commented 3 months ago

I'm not quite sure which other line you mean? There's an image above for 59Ma, but this is 52Ma (ie, you and I are now discussing plots at 52Ma). Maybe you noticed the other line in the 59Ma image?

See the screenshot at https://github.com/GPlates/gplately/issues/191#issuecomment-2161829841. There are two bad lines. If I skipped dateline wrapping, one of them was gone.

michaelchin commented 3 months ago

By the way, I discovered I also needed to install PyQt6 in order for tests-dir/unittest/test_plot.py to display the plot and avoid the error message UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown (I'm on Windows 11).

thanks for letting me know this. I don't have a Windows now. I will borrow a Windows and try it when I am in office.

jcannon-gplates commented 3 months ago

See the screenshot at #191 (comment). There are two bad lines. If I skipped dateline wrapping, one of them was gone.

Oh yeah, you're right, I missed that somehow.

I guess you are right. The root cause may be in [_fill_all_edges()] and the dateline wrapping only make it worse(produced one more artefact line).

Yeah that must be what happened - the dateline wrapping changed the data enough to trigger the bug in _fill_all_edges() to generate the extra spurious line. Enabling dateline wrapping but disabling _fill_all_edges() works. So yeah, I think the problem lies in _fill_all_edges().

I am not sure what the [_fill_all_edges()] does. I guess it has something to do with that cartopy cannot handle certain polygons properly near the map boundary??????

I guess whoever wrote that function might be able to help. I couldn't tell who originally wrote it (using 'blame' and 'git log') - it just shows you.

michaelchin commented 3 months ago

I guess whoever wrote that function might be able to help. I couldn't tell who originally wrote it (using 'blame' and 'git log') - it just shows you.

I moved the code from plot.py to plot_utils.py because plot.py was getting too large. And plot.py has a long history....

michaelchin commented 2 months ago

By the way, I discovered I also needed to install PyQt6 in order for tests-dir/unittest/test_plot.py to display the plot and avoid the error message UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown (I'm on Windows 11).

thanks for letting me know this. I don't have a Windows now. I will borrow a Windows and try it when I am in office.

I will add these comments to the test scripts.

Screenshot 2024-07-04 at 11 52 19 AM
jcannon-gplates commented 2 months ago

I moved the code from plot.py to plot_utils.py because plot.py was getting too large. And plot.py has a long history....

Ah right, I see that @cpalfonso added _fill_all_edges() in dcc9499. So he might have a better idea.

michaelchin commented 2 months ago

I moved the code from plot.py to plot_utils.py because plot.py was getting too large. And plot.py has a long history....

Ah right, I see that @cpalfonso added _fill_all_edges() in dcc9499. So he might have a better idea.

Hi @cpalfonso, Do you have time to help us with this?

michaelchin commented 1 month ago

https://github.com/GPlates/gplately/issues/256 may be related to this issue

michaelchin commented 1 month ago

I moved the code from plot.py to plot_utils.py because plot.py was getting too large. And plot.py has a long history....

Ah right, I see that @cpalfonso added _fill_all_edges() in dcc9499. So he might have a better idea.

Hi @cpalfonso, Do you have time to help us with this?

Hi @jcannon-gplates

I don't think we should wait any longer.