0
votes

i'm trying to plot an heatmap on a triangular surface, the coordinates and "heat values" are obtained with the methog shown on page staff.aist.go.jp/a.noda/programs/ternary/ternary-en.html.

so, i process the data and obtain a data file in the form:

x y val

where x and y are values between 0 and 1, and val is an integer representing the frequency i need to show.

the data file is this: http://tinyurl.com/lqsqtvv

and the plot script is this:

#!/usr/bin/gnuplot

reset

set terminal pngcairo size 640,480
set output 'heat_map_triangle.png'

set border linewidth 0
unset tics
set bmargin 3
set lmargin 3
set rmargin 3
set tmargin 3

set dgrid3d
set pm3d map
#set pm3d ftriangles
set pm3d interpolate 0,0
set pm3d at bs

set label 'Y' at 0, -0.03 center
set label 'Z' at 1, -0.03 center
set label 'X' at 0.5, 0.886 center

set style line 1 lt 1 lw 3 pt -1 ps 1

# x
set arrow 1 from 0,0 to 1, 0.0 nohead linestyle 1

# z
set arrow 11 from 1, 0 to 0.50, 0.866 nohead linestyle 1

# y
set arrow 21 from 0.50, 0.866 to 0,0 nohead linestyle 1

splot "./triangle.out" using 1:2:3

so, i'm getting out this plot

that is not exactly what i wanted...

i can't understand how to tell pm3d not to fill zones that are not in the data file (e.g. outside the triangle) and why the triangle top edge is taller than the heatmap.

it there a way to plot the data the way i want it?

in pm3d documentation it says that it can leave empty spaces, but how?

thanks

2

2 Answers

2
votes

Ultimately, for pm3d to work, gnuplot requires that the data be on some sort of grid "mesh". The mesh needs to composed of quadrillaterals, but that is the only stipulation. e.g., your gridpoints could be arranged like this:

 1
        2
                 3
 4      5        6     10
                 9
        8
 7

In this case, gnuplot will create a quadrilateral from points 1-2-4-5 and points 2-3-5-6, etc. etc. Gnuplot will color the quadrilateral depending on the corners2color option of pm3d. By default, it uses the average of the 4 values on the corners of the cells.

To put this in a datafile, you'd want to the datafile coordinates like this:

 x1   y1   z1
 x2   y2   z2
 x3   y3   z3
 x10  y10  z10

 x4   y4   z4
 x5   y5   z5
 x6   y6   z6
 x10  y10  z10

 x7   y7   z7
 x8   y8   z8
 x9   y9   z8
 x10  y10  z10

Notice how I left a blank line between horizontal "scans" across the data. (Of course, we could have structured the datafile to take vertical "scans" across the data as well). I also repeated a point at the right vertex of my triangle to give it a sharp point. This isn't strictly necessary, but I wanted to demonstrate it was possible.

Your data isn't in that form and normally, gnuplot would give you an error complaining that your data wasn't gridded. however, you've added the line set dgrid3d which tells gnuplot that your data isn't on a grid and that gnuplot should use an inverse distance weighting function to interpolate your data onto a grid. Unfortunately, gnuplot creates a regular (rectangular) grid and there is no way to tell it to create some other kind of grid. Ultimately, you need to figure out how to beat your data into this form.

0
votes

If you were prepared to use R, and the ggtern library, the following could be achieved:

Output

Which was done with the following code:

#Load library
library(ggtern)

#Load the data
df <- read.table("./data.txt")
colnames(df) = c("x","y","Value")

#Put in ternary coordinates
df.new <- data.frame(transform_cart_to_tern(data=df),Value=df$Value)
df.new <- df.new[order(df.new$Value),]
df.new <- df.new[which(df.new$Value > 0),]

#Plot the diagram
ggtern(data=df.new,aes(y=T,x=L,z=R)) + 
  geom_point(aes(color=Value,alpha=Value)) + 
  scale_color_gradient(low="transparent",high="red") + 
  guides(alpha="none") + 
  theme_rgbw() +
  theme(legend.position=c(0,1),legend.justification=c(0,1)) +
  labs(title="Example Density Plot",color="Frequency")