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

Circular colorbar for azimuthal data #3638

Open
YaraRossi opened this issue Nov 20, 2024 · 12 comments
Open

Circular colorbar for azimuthal data #3638

YaraRossi opened this issue Nov 20, 2024 · 12 comments
Labels
feature request New feature wanted

Comments

@YaraRossi
Copy link

Description of the desired feature

For various datasets a linear colorbar is appropriate. However when azimuthal data is plotted [0 - 360°] is would make sense to have a circular colorbar that actually represents the direction the data is plotted. This could either be set on the side of the plot or as an inset. At the moment I don't think this exists yet and my only work around would be to save a *.png figure and then add it to the pygmt plot through fig.image() function.

An example is the direction of tilt. It's possible to visualize this with vectors, but when the directions get more heterogeneous it gets messy. This is an example of where the direction of the ground tilt is visualized according to azimuth. The linear colorbar is confusing, as the colors are actually continuous and azimuthal.

Screenshot 2024-11-20 at 14 42 17

the colorbar (colorcircle?) should be something like this:

Screenshot 2024-11-20 at 14 43 26

Are you willing to help implement and maintain this feature?

Yes

@YaraRossi YaraRossi added the feature request New feature wanted label Nov 20, 2024
Copy link

welcome bot commented Nov 20, 2024

👋 Thanks for opening your first issue here! Please make sure you filled out the template with as much detail as possible. You might also want to take a look at our contributing guidelines and code of conduct.

@weiji14
Copy link
Member

weiji14 commented Nov 20, 2024

I'm not sure if there's a way to get a circular colorbar, but GMT/PyGMT does have cyclic colormaps listed at https://docs.generic-mapping-tools.org/6.5/reference/cpts.html#id4, and if you use those, there will be a circle/cycle symbol that denotes it is cyclic:

import pygmt

fig = pygmt.Figure()
pygmt.makecpt(cmap="SCM/corkO", series=[0, 360, 45], continuous=True)
fig.colorbar(cmap=True, region=[0,2,4,8], projection="X10c")
fig.show()

produces

cyclic_colorbar

If you want an actual circular colorbar though, that would need to be done in upstream GMT repo https://github.com/GenericMappingTools/gmt, or another workaround.

@YaraRossi
Copy link
Author

Thanks for the input. However, I think to understand the data better and faster, and actual circle would be really helpful. I now made a workaround that creates a *.png file with the circular colorbar. That figure can afterwards be inserted into the pygmt figure through fig.image(). Attached is an example file and the figure with the real data. In case anyone else needs the same feature.

Example file:
Circular_colormap_example.txt

Figure:
Screenshot 2024-11-20 at 18 36 01

@weiji14
Copy link
Member

weiji14 commented Nov 21, 2024

Yes, I agree that a circular colorbar would be more appropriate for your case. Also, thanks for sharing your code!

That said, I would advise you to use a proper cyclic colormap, because the current one has a discontinuity at 0 degree / North (the color jumps from green to blue abruptly). Since you are already using a Scientific Colour Map (tofino), you might want to consider one of the cyclic colormaps at https://www.fabiocrameri.ch/colourmaps/ where the transition from 359degrees to 1 degree is smoother. Specifically romaO, bamO, brocO, corkO, or vikO

image

@seisman
Copy link
Member

seisman commented Nov 21, 2024

In PyGMT, the circular colorbar can be done by plotting wedges via Figure.plot with style="W".

@yvonnefroehlich
Copy link
Member

Some time ago I created a circular colorbar in PyGMT:
https://github.com/yvonnefroehlich/gmt-pygmt-plotting/pull/23/files

@YaraRossi
Copy link
Author

Thank you weiji14 you are right, that looks much better!

@YaraRossi
Copy link
Author

thank you for sharing your code yvonnefroehlich, I'll check it out!

@michaelgrund
Copy link
Member

michaelgrund commented Nov 22, 2024

As @seisman mentioned it's also easy to do that by plotting wedges within a 360° range @YaraRossi. Also adding a hole in the center without needing any transparency is straightforward.

Much easier compared to what I did during my PhD 😅😅😅 https://github.com/michaelgrund/GMT-plotting/blob/main/009_paper_GR2020/pygmt_jn_fig_s10/GR_2020_Fig_S10.ipynb.

I experimented with wedges the last few weeks and maybe it's worth to consider if we want to implement some high level functions like circular colorbars, pie charts, doughnut plots etc. based on using wedges with plot. I hope I have time to expand my POCs during the holiday season.

Added the potential functions to the list in #2797.

import pygmt
import numpy as np

def colorbar_az(cmap = "romaO", center_x = 1, center_y = 1, radius_inner = 1.5, radius_outer = 2.5):
    
    values = np.full(360, 1)
    # calc fraction within full circle
    fracs = [value / 360 * 100 for value in values]
    
    # scale colormap
    pygmt.makecpt(cmap=cmap, series=[0, len(values)-1, 1])
    
    start_angle = 0

    for i, frac in enumerate(fracs):
        end_angle = start_angle + (frac / 100) * 360
        fig.plot(x = center_x, 
                 y = center_y, 
                 style = f"w{radius_outer}/{start_angle}/{end_angle}+i{radius_inner}", 
                 zvalue = i, 
                 fill = "+z", 
                 cmap = True
                )
        start_angle = end_angle


fig = pygmt.Figure()

fig.coast(
    region=[-125, -122, 47, 49],
    projection="M6c",
    land="grey",
    water="lightblue",
    shorelines=True,
    frame="a",
)

colorbar_az(center_x = -123, center_y = 48)

fig.show()

plot_cbar_az

@yvonnefroehlich
Copy link
Member

yvonnefroehlich commented Nov 22, 2024

Just checking this out - nice approach to use wedges (with inner diameter) here! Thanks for sharing your ideas and codes @seisman and @michaelgrund! Would suggest to create a NumPy array with all wedges before plotting to make the code faster (similiar as I did for the rotated recangles, which I use in my code).

import numpy as np
import pygmt

def colorbar_az(cmap="romaO", center_x=0, center_y=0, diameter_inner=1.5, diameter_outer=2.5):
    
    values = np.full(360, 1)
    # calc fraction within full circle
    fracs = [value / 360 * 100 for value in values]
    
    # scale colormap
    pygmt.makecpt(cmap=cmap, series=[0, len(values)-1, 1])
    
    # Create a Numpy array with all wedges
    start_angle = 0
    data_wedges = np.zeros([360, 6])
    for i, frac in enumerate(fracs):
        end_angle = start_angle + (frac / 100) * 360
        data_wedge_temp = np.array([
            center_x, center_y, start_angle, diameter_outer, start_angle, end_angle,
        ])
        data_wedges[i,:] = data_wedge_temp
        start_angle = end_angle
    
    # Plot all wedges with one call of Figure.plot()
    fig.plot(data=data_wedges, style=f"w+i{diameter_inner}c", cmap=True)

@seisman
Copy link
Member

seisman commented Nov 22, 2024

This is another simplified version based on @yvonnefroehlich's script:

import numpy as np
import pygmt

def colorbar_az(cmap="romaO", x0=0, y0=0, diameter_inner=1.5, diameter_outer=2.5, step=1.0):
    pygmt.makecpt(cmap=cmap, series=[0, 360])

    angles = np.arange(0, 360, step)
    # Create the data for the wedges
    data_wedges = np.column_stack([
        np.full_like(angles, x0),  # x
        np.full_like(angles, y0),  # y
        angles,  # For color
        angles,  # start_angle
        angles + step  # end_angle
    ])

    # Plot the all wedges with one call of Figure.plot()
    fig.plot(data=data_wedges, style=f"w{diameter_outer}c+i{diameter_inner}c", cmap=True)

fig = pygmt.Figure()
fig.basemap(region=[-5, 5, -5, 5], frame=True, projection="X10c/10c")
colorbar_az()
fig.show()

@YaraRossi
Copy link
Author

YaraRossi commented Nov 22, 2024

I added another variable that allows to rotate the color, so that 0 can be defined where ever people need it. Additionally, it would be great to have lables for example E, N, W, S, but I couldn't manage to locate them next to the wedges automatically. With fig.text() they stayed in the cartesian coordinate system.

import numpy as np
import pygmt

def colorbar_az( fig="fig", cmap="romaO", x0=0, y0=0, diameter_inner=1.5, diameter_outer=2.5, step=1.0,start_azimuth = "0:East, 90:North, 180:West, 270:South"):

    pygmt.makecpt(cmap=cmap, series=[0, 360])

    angles = np.arange(0, 360, step)
    # Create the data for the wedges
    data_wedges = np.column_stack([
        np.full_like(angles, x0),  # x
        np.full_like(angles, y0),  # y
        angles,  # For color
        angles + start_azimuth,  # start_angle
        angles + step + start_azimuth  # end_angle
    ])

    # Plot the all wedges with one call of Figure.plot()
    fig.plot(data=data_wedges, style=f"w{diameter_outer}c+i{diameter_inner}c", cmap=True)

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

No branches or pull requests

5 participants