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

Allow for "makecpt" style colormap functionality in grdimage and colobar #372

Open
MarkWieczorek opened this issue Nov 6, 2019 · 12 comments
Labels
help wanted Helping hands are appreciated question Further information is requested
Milestone

Comments

@MarkWieczorek
Copy link
Contributor

In classic gmt the function makecpt is used to create a "cpt" file that acts as a color map for plotting data in grdimage and in plotting a colorbar.

In its present state, pygmt does not (to the best of my knowledge) allow for creating a custom colormap for use in both grdimage and colorbar, which greatly limits the utility of pygmt. Such functionality could be achieved in the following way:

fig.makecpt(limits=[min, max], cmap=..., transparency=False, cpt='name of temporary output cpt file')
fig.grdimage(cpt='name of temporary cpt file')
fig.colorbar(cpt='name of temporary cpt file')

In practice, a single image could have several cpt files associated with it.

@weiji14 weiji14 added the question Further information is requested label Nov 6, 2019
@weiji14
Copy link
Member

weiji14 commented Nov 6, 2019

It's not very well documented, but we do have a makecpt function as of #329. It actually works via pygmt.makecpt rather than fig.makecpt. Also GMT6 modern mode (which PyGMT uses) allows you to create a hidden Color Palette Table (CPT) and use it in subsequent commands automatically (see https://docs.generic-mapping-tools.org/6.0/makecpt.html#note-on-cpts-in-modern-mode) so we don't actually need to set the cpt in grdimage/colorbar (if this sounds confusing, let me know).

The way you would do this in your code snippet then is as follows:

pygmt.makecpt(series=[min, max], cmap=...)
fig.grdimage(...)
fig.colorbar(...)

@MarkWieczorek
Copy link
Contributor Author

After playing around with pygmt.makecpt, I have run into two problems.

  1. After you create a colormap with makecpt, it is not possible to change the session colormap to a different one. Creating a new colormap has no effect on any subsequent figure. The only way to make a new image with a different colormap is to kill the python kernel and start over again. This occurs with both the terminal and notebook environments.

  2. makecpt gives you the option to save the generated colormap to a file, however, it would be more useful if you could instead save it to a python variable, and then specify this variable in subsequent calls to grdimage and colorbar. It is hard for me to imagine the case where you would want to save the cpt data to a file.

@weiji14
Copy link
Member

weiji14 commented Nov 8, 2019

I agree that pygmt.makecpt could definitely be a lot better, it's not intuitive the way things work.

Point 1: . Right now if you want to change to another colormap, you'll need to call makecpt after fig = pygmt.Figure() like so:

fig = pygmt.Figure()
pygmt.makecpt(cmap="geo")
fig.grdimage(,,,)
fig.show()

fig = pygmt.Figure()
pygmt.makecpt(cmap="oleron")
fig.grdimage(,,,)
fig.show()

rather than this:

pygmt.makecpt(cmap="geo")
fig = pygmt.Figure()
fig.grdimage(,,,)
fig.show()

pygmt.makecpt(cmap="oleron")
fig = pygmt.Figure()
fig.grdimage(,,,)
fig.show()

The first one creates a cpt specifically for the figure, whereas the second one creates a session colormap as you said that can't be overridden.

Point 2. This would definitely be a better way. and what you're asking for here I think is similar to what was tried in #126.

@MarkWieczorek
Copy link
Contributor Author

MarkWieczorek commented Nov 8, 2019

Here is my suggestion on how to resolve this problem:

  1. pygmt.makecpt() creates a default colormap, to be used when one is not specified. Regardless, you should have the option of changing the default (unlike the present behavior).

  2. Create the method pygmt.Figure.makecpt() which creates a custom colormap for the specified figure. This would be used as

fig = pygmt.Figure()
fig.makecpt()
fig.grdimage()
...

@EJFielding
Copy link

EJFielding commented Nov 8, 2019

I have not yet tried the new modern mode in GMT 6, but I read the note that @weiji14 linked. It seems that GMT 6 uses "hidden" files to store potentially several colormaps with a hierarchy of scope for different parts of the figure. I understand that PyGMT is keeping things simple, so supporting a hierarchy of colormaps with different scope might be too much. It still seems like it is very confusing to not be able to change the session colormap for each figure, as Mark found.

I often plot several datasets in a single figure with different colormaps for each one, and it sounds like the present implementation of PyGMT would make that impossible. I am not clear whether creating a new figure object clears what was plotted before or overlays it in PyGMT. If I were to try to do the plots that I do with mulitple colormaps in one figure, it would be something like this:

fig = pygmt.Figure()
fig.colormap()
fig.grdimage(,,,)
fig.colormap()
fig.grdimage(,,,)
fig.show()

@seisman
Copy link
Member

seisman commented Nov 8, 2019

I'm so confused about the discussions above. Could you give some examples which don't work as expected?

To me, the following script works as expected:

import pygmt

fig = pygmt.Figure()
pygmt.makecpt(cmap="etopo1")
fig.grdimage("@earth_relief_10m", projection="H10c", frame=True)
fig.colorbar(frame=True)

fig.shift_origin(yshift="10c")

pygmt.makecpt(cmap="earth")
fig.grdimage("@earth_relief_10m", projection="H10c", frame=True)
fig.colorbar(frame=True)
fig.savefig("map.pdf")

image

@MarkWieczorek
Copy link
Contributor Author

MarkWieczorek commented Nov 8, 2019

try this!

import pygmt
earth = pygmt.datasets.load_earth_relief()

pygmt.makecpt(cmap="roma", series=[-8000, 5000])
fig = pygmt.Figure()
fig.grdimage(earth, projection="H10c", frame=True)
fig.colorbar(frame=True)
fig.savefig('test.pdf')

pygmt.makecpt(cmap="viridis", series=[-8000, 5000])
fig = pygmt.Figure()
fig.grdimage(earth, projection="H10c", frame=True)
fig.colorbar(frame=True)
fig.savefig('test2.pdf')

Both images look exactly the same.

Edit: Also the "Y" option is undocumented. It is good to know that this exists.

@seisman
Copy link
Member

seisman commented Nov 8, 2019

@MarkWieczorek Yes, your example doesn't work as expected to me. I believe it's an upstream (i.e. the core GMT) bug, and I've opened an issue in GenericMappingTools/gmt#2006.

For your example, the current working solution is to put the pygmt.makecpt after fig = pygmt.Figure().

As for the "Y" option, it's equivalent to the -Y option for GMT command-line. Yes, it should be documented, but currently not. We also provide another function fig.shift_origin() to shift the plot origins in X or Y directions.

@EJFielding
Copy link

Below is an example of the kind of map that I was talking about. I used one colormap for the topography data and a different colormap for the SAR interferometry data in the same map. I made this with an older version of GMT several years ago.
ALOS2_D048_20150221-0502_v2_unw_m_3asec-N3-D048-map

Maybe this is too complicated to support in PyGMT.

@sbSHA
Copy link

sbSHA commented Jul 21, 2021

Hi I can not figure out like how to use custom colors for cmap in place of using the color master color palette? Is this possible? If yes then how one does that? I see that in gmt one can do that but how to do this in pygmt?
Thanks.

@seisman
Copy link
Member

seisman commented Jul 21, 2021

Hi I can not figure out like how to use custom colors for cmap in place of using the color master color palette? Is this possible? If yes then how one does that? I see that in gmt one can do that but how to do this in pygmt?

Do you mean using a custom CPT file or custom colors?

If you already have a custom CPT file in your current directory, you should be able to use it like cmap="my-custom.cpt".

Or if you want to define a CPT from a series of colors, cmap="red,blue,yellow" should work.

BTW, it would be better if you can ask further questions in the GMT Forum.

@sbSHA
Copy link

sbSHA commented Jul 22, 2021

Thanks very much. It worked. It was the second one cmap="red,blue,yellow".

@weiji14 weiji14 modified the milestones: 0.5.0, 0.6.0 Sep 30, 2021
@weiji14 weiji14 modified the milestones: 0.6.0, 1.0.0 Mar 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Helping hands are appreciated question Further information is requested
Projects
None yet
Development

No branches or pull requests

5 participants