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

Replacing GMT/PyGMT backend by pure Matplotlib backend #268

Merged
merged 35 commits into from
Aug 21, 2024
Merged

Conversation

thurinj
Copy link
Member

@thurinj thurinj commented Jun 11, 2024

This PR implements some major changes in MTUQ plotting system. I implemented an equivalent plotting function to all existing visualization methods currently implemented in MTUQ, apart from the attribute-mapping functions, which are still the minimal matplotlib implementation - PyGMT is still preferred for those (until I figure out a clean implementation based on Cartopy eventually, but it is not priority atm).

The significant change here is that I have replaced all the default behavior/default calls from GMT/PyGMT with these new Matplotlib methods.

Here are a few examples of the visualization:

note: For the depth and hypocenter search results, I used a local database, which is not very appropriate for the 2009 event, to avoid having to wait for the Syngine download for all these origins.
You should be able to reproduce all these by running the detailed example, depth and hypocenter search from the examples folder on this branch.

All the moment tensors are plotted with a custom method based on the direct computation of the radiation coefficient of the lower half-sphere of the beachball. The values are projected on the 2D plane, and the surface is built on a regular interpolated surface. The method implements a "level of detail" approach for the density of this approximation: a dense grid for the "big beachball" and a coarser grid for the small beachball displayed on the map and depth sections (as otherwise, it could take too long to plot the beachballs based on this direct approximation method).

I'd love to have feedback on this one if you have other events to test it on, etc, but I am confident we can push it as a new visualization backend.

thurinj added 27 commits May 7, 2024 17:43
Defining projection helper function for Lune and Sphere data visualization.
Define function to compute intermediate points along a line between specific coordinates pairs. This will make sure the arcs are correctly bent in the projected coordinate system (hammer projection).
Hard-coding lune arc coordinates for lambda1,2,3 = 0. Lines are populated by _compute_center_of_minimum_distance and plotted with _plot_lune_arcs using the hammer projection.
Hard-coding sphere meridians for W - S - E directions. Lines are populated by _compute_center_of_minimum_distance and plotted with _plot_sphere_arcs using the hammer projection. Labels are added with _plot_directions_text.
This function returns a figure and axes object with the lune frame, ready for plotting used by other functions.
It uses the helper functions previously defined, and the hammer projection function.
This function returns a figure and axes object with the unit sphere frame, ready for plotting used by other functions. As with the lune, It uses the helper functions previously defined, and the hammer projection function.
Pure matplotlib implementation of the Lune plot. It uses the pre-defined helper functions implemented in previous commits. The lune plot has three different modes, contour being the equivalent to the current GMT plot. colormesh and scatter mode are implemented with sampling method and polarity misfit, respectively.
Fairly similar in design to the lune plot backend. Disclaimer: it has been tested but not to the same extent as the lune plot. Main features seems stable, but I will review if anything comes up.
Implemented pure-matplotlib moment tensor plot. It is based on the computation of the radiation coefficient on a 3D half-sphere, and projected on the 2D plane with lambert azimuthal equal area projection.
Currently supports waveform plots and base beachball plot with station and piercing points.
…otlib

This commit integrates two different features:
Adding the option to input several moment tensors to plot on a map fashion (used in lune plot and depth plot).
Adding a "Level of detail" kind of optimization to adapt rendering speed depending on the size of the plotted beachball (single figure, or multiple beachball on a plot).
The plot requires using a double axes trick, as the beachball pattern are not converted into markers or symbol, they can be stretched if the axes are not the same order of magnitude.
A secondary axis with unit extent (-1,1 / -1,1) is overlayed on the base figure, and the coordinates of the points (depths/values) are re-scaled accordingly, so that the beachballs are always perfect circles.
…is feature branch

I wanted to have the feature branch with the new header modification. This is mostly as I will use the uq_matplotlib branch for the 2024 MTUQ SCOPED workshop, before opening a Pull Request.
Passed title back as a kwarg and added the possibility to modify the colorbar label (which I have set to l2_misfit as default value). Reproduces all the DetailedAnalysis.py plots.
Changed the call of _plot_force() to actually use the backend variable instead of the hardcoded _plot_force_gmt() function. Use the "levels" variable in the matplotlib backend instead of the fixed value as 126 (which was for testing purposes).
The beachball plot now support both the "Big beachball" mode as well as polarity plotting. Some functions from the beachball plotting engine have been moved to utilities.
With improvements mades on the beachball plot, the scaling factor of various figures were also updated, and should now be consistent regardless of the axes extents. (The scale being automatically adjusted to account for the axes extent).
This now takes advantage of the dedicated polarity mode of the matplotlib backend.
@thurinj thurinj requested a review from rmodrak June 11, 2024 00:57
Increased default marker size for better readability.
The latitude and longitude were swapped in scatter mode of moment tensor plot. I somehow circumvented the issue by also swapping the inputs which hid the discrepancy until this fix. All MT tradeoffs figures have been re-tested.
@rmodrak
Copy link
Member

rmodrak commented Jul 25, 2024

Hi Julien, Carl,

Thanks for this major reimplementation effort, which will bring significant benefits.

I have now looked through the source code, but yet not tried running anything myself.

Fow now, perhaps we could add an "under development" warning whenever the new matplotlib backends are called, and then go ahead and merge the pull request? Then after trying out the new backends for a few months, we could remove this warning. Does this sound okay?

thanks,
Ryan

PS I will go ahead and post the above verbatim to the GitHub later tonight (currently I'm locked out from it).

At some point later, I would like to iterate myself/coordinate with you on the following
      - use colorblind friendly colormaps

additional keyword arguments related to colorbar saturation
some possible tweaks to the underlying colormesh/contour/scatter calls
decide when it is appropriate to add gmt deprecation warnings

Added a warning message that displays when the script is used.

_plot_latlon_matplotlib has been moved to be right after _plot_depth_matplotlib.

Implemented warning message for beachball plotting.

Added a custom warning message for beachball plot, since it is not a "conventional" implementation a-la psmeca.
@thurinj
Copy link
Member Author

thurinj commented Aug 1, 2024

Hi @rmodrak ,

Thanks for reviewing the code. I agree with your suggestions for future improvement. The scatter-mode for the polarities mismatch is not using a colorblind friendly colorscale, so this is appropriate. For the others, as long as we are using Viridis, we should be okay.

I've added warning message for the matplotlib backend and a dedicated one for the beachball plot (since the whole concept of it is different from most of the code that use a psmeca based approach).

I've squashed commits to remove a PDF file that was included by mistake, hence the last force-push.

I added a parabola to the depth plot, with an estimate of the best fitting depth at the minimum of the parabola. It will print the best value and the ± error from a 5% uncertainty threshold.
…the 3D projection.

I originally had the axes for the sphere projection be separate from the moment tensor
@thurinj thurinj merged commit 078e165 into master Aug 21, 2024
1 check passed
@thurinj thurinj deleted the uq_matplotlib branch September 30, 2024 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants