Ternary plots in GMT.jl

The ternary plots topic has been raised here several times. I’ve added ternary plots to GMT.jl. Unfortunately it’s still not yet possible to slant the ticks, which helps a lot in reading the graphs, as that it will have to wait until GMT itself can do it.

Several examples are shown here and a quick example can be obtained with:

ternary("@ternary.txt", labels=("Clay","Silt","Sand"), image=true, marker=:p, show=true)

10 Likes

These look great! Thanks

Can GMT.jl produce a ternary plot with lines by (smoothly) connecting given points? Note it is neither scatter plot nor contour plot, such as the plot below:

Interested also on how to do this with GMT.

Fyi, it is already possible to do something like it using TernaryPlots.jl, a package that seems to be at early stages:

The corresponding code is provided below:

using TernaryPlots

b = 0:0.01:0.3
c1 = (1 .- b).^3 .- 0.7^3
c2 = (1 .- 2*b).^2 .- 0.4^2
t1 = tern2cart.(1 .- b .- c1, b, c1)
t2 = tern2cart.(1 .- b .- c2, b, c2)

p = TernaryPlots.ternary_plot(title="TernaryPlots.jl",labels=(A="A", B="B", C="C"))
plot!(p, [t1...], lw=2, lc=:red)
plot!(p, [t2...], lw=2, lc=:blue)
2 Likes

OK, normally the ternary module in GMT (the C package) does not allow plotting lines. But symbols in GMT can be lots of things, including entities called decorated lines (see this example) and we can make use of them to plot lines.

You can now plot lines using this trick, but because it’s a trick the hard core GMT syntax must be used. Another problem I found is that apparently ternary in GMT.jl requires input data via a file. So please open an issue in GMT.jl requesting a proper friendly syntax to do this task. So far you’ll have to do this.

Save data in a text file (for example put this matrix [0.1 0.4 0.5; 0.2 0.0 0.8] in a file called “tern.dat”, one row per line) and use it as

ternary("tern.dat",  S="~n1:+sc0.01", par=(MAP_DEFAULT_PEN="1,red",), show=true)
  • The S=… is the trick to make a decorated line but one with an invisible small circle
  • the par=(MAP_DEFAULT_PEN="1,red",) tells it to plot a red line of 1p thickness. Omitting this option plots a 0.25p black line (the GMT default)

2 Likes

Thanks! I find the API of TernaryPlots.jl is more pleasing and the look is great.

Me too, and that’s why I said.

It turns out that a good improvement can be achieved with little changes, though I still need to find why it errors when one tries to add a Title.

With GMT.jl#master we can now expand a bit Rafael’s example

b = 0:0.01:0.3
c1 = (1 .- b).^3 .- 0.7^3
c2 = (1 .- 2*b).^2 .- 0.4^2
t1 = tern2cart([(1 .- b .- c1) b c1])    # Note that GMT.jl function expects a Mx3 matrix
t2 = tern2cart([(1 .- b .- c2) b c2])

ternary(labels=("A", "B", "C"))

plot!(t1, lw=2, lc=:red, ls="line& (a) &")	# line style -> fancy new stuff
plot!(t2, lw=2, lc=:blue)
text!(tern2cart([0.3 0.4 0.3]), text="Umbilicus", font=18, show=true)

3 Likes

How do we set the colorbar label? This

ternary(..., colorbar=true, show=true)

shows the plot and the colorbar, but I cannot find a way to set the label.

Also, I see here How to make a slope map — GMT Examples documentation that is possible to set that pointy highclip, is there an option for that in GMT.jl, including the lowclip?

OK, here’s how it works. The colorbar is a separate command that allows all parameter setting. But for convenience it can be embedded in imaging command (ternary in this case). That can be done by setting it to true, which uses default settings but accepts also being parametrized. i.e., we can use it like

ternary("@ternary.txt", labels=("Clay","Silt","Sand"), image=true, marker=:p, colorbar=frame=(xlabel="Label long", ylabel=:units), show=true)

or

make the plot with the two commands separately:

ternary("@ternary.txt", labels=("Clay","Silt","Sand"), image=true, marker=:p, figsize=10)
colorbar!(pos=(paper=true, anchor=(11,0), size=(8,0.5), justify=:BL, vertical=true),
               frame=(annot=:auto, ticks=:auto, xlabel="Label long", ylabel=:units), show=true)

Note that in the second case we must make the anchor and size play along with the figsize.

Regarding the second question, sorry but I didn’t get it. Basically we can control everything in GMT plots. Are you referring to the color scale?

1 Like

thanks a lot.

I mean the highclip(possibly set a color) and lowclip. Usually represented by a tip-triangle (up and down). See the ones in makie :smile: Colorbar | Makie highclip = :cyan, lowclip = :red Those color are used for values beyond the specified range

Also, I’m not using a file, but a matrix with 4 columns, and for some reason the image/countour are not being picked-up, fourth columns is not being taken as color for those primitives, but it does work for points. Does the txt file comes with some column-names? or

You can plot those triangles but then we must currently use the two commands call (ternary & colormap). Note the triangles=true

ternary("@ternary.txt", labels=("Clay","Silt","Sand"), image=true, marker=:p, figsize=10)
colorbar!(pos=(paper=true, anchor=(11,0), size=(8,0.5), justify=:BL, vertical=true, triangles=true),
               frame=(annot=:auto, ticks=:auto, xlabel="Label long", ylabel=:units), show=true)

But why are the triangles black & white? Because the GMT colormaps have the notion of background and foreground colors and those by default are black and white. And yes, we can change that but it requires that we manually create the colormap for this data limits (by default that is done automatically under the hood). To make those colors correspond to lowest and highest we do:

C = makecpt(range=(0,75), bg=true)

and now we do

ternary("@ternary.txt", labels=("Clay","Silt","Sand"), image=true, marker=:p, figsize=10, cmap=C)
colorbar!(pos=(paper=true, anchor=(11,0), size=(8,0.5), justify=:BL, vertical=true, triangles=true),
               frame=(annot=:auto, ticks=:auto, xlabel="Label long", ylabel=:units), show=true)

2 Likes

Don’t know why that is happening. Note that file used in this example has also only 4 columns

julia> gmtread("@ternary.txt")
BoundingBox: [0.0, 1.0, 0.0, 0.921, 0.0, 0.981, 1.041, 70.844]

1000×4 GMTdataset{Float64, 2}
 Row │ col.1  col.2  col.3   col.4
─────┼─────────────────────────────
   1 │  0.16  0.331  0.509   9.344
   2 │  0.22  0.625  0.158  39.156
   3 │  0.09  0.18   0.732   2.621
   4 │  0.66  0.258  0.078  12.062
...

and reading it first into a variable still works fine.

ternary(gmtread("@ternary.txt").data, labels=("Clay","Silt","Sand"), image=true, marker=:p, show=true)

thanks a million! this was really helpful :heart: !

With master version one can now do

ternary("@ternary.txt", labels=("Clay","Silt","Sand"), image=true, marker=:p,
             colorbar=(xlabel="Label long", ylabel=:units, triangles=true), show=true)