问题
Following this question, I have now a heatmap with custom colorbar. Now I need to put contour lines with labels. I have created the contour lines, but I can't figure out how to put them.
This is the plot I currently have:
Code to generate the plot:
reset
#Function map values on desired ranges. The values set to 90,95,99 are for later labelling
step(x) = (x < 20.0 ? 0 : (x < 50.0 ? 10 : (x < 75.0 ? 20 : (x < 90.0 ? 80 : (x < 95.0 ? 90 : (x < 97.5 ? 95 : (x < 99.0 ? 97 : (x < 99.5 ? 99 : (x < 99.9 ? 100 : 101 )))))))))
# enable 3D data read from a scattered data set in file
#71,46,10 are the number of different values for each axis X,Y,Z in "HeatMap_Test.txt" data file
#If values of dgrid3d are not set accordingly, weird contour values will be generated
set dgrid3d 71,46,10
set contour base # enable contour drawing
set cntrlabel font ",7"
set view 0,0 # if you want to see the graph from above (2D plot)
unset surface # do not plot the surface, only the contour
set cntrparam levels discrete 90,95,99 #set contours only on values 90,95 and 99
set table "contours.dat" #Name of the output file to write the table
splot "HeatMap_Test.txt" u 2:1:(step($3)) with lines notitle
unset table #Write table to file
reset
#Map the Z values to desired ranges
step(x) = (x < 20.0 ? 0 : (x < 50.0 ? 1 : (x < 75.0 ? 2 : (x < 90.0 ? 3 : (x < 95.0 ? 4 : (x < 97.5 ? 5 : (x < 99.0 ? 6 : (x < 99.5 ? 7 : (x < 99.9 ? 8 : 9 )))))))))
set palette maxcolors 10
set palette defined (0 "#333399", 1 "#3333f7", 2 "#3373ff", 3 "#33c6ff", 4 "#5affd2", 5 "#9cff8f", 6 "#dfff4c", 7 "#ffc733", 8 "#ff7a33", 9 "#e53333")
set cbrange [-0.5:9.5]
set cbtics nomirror
set cbtics ( ">99.9" 9, ">99.5" 8, ">99.0" 7, ">97.5" 6, ">95.0" 5, ">90.0" 4, ">75.0" 3, ">50.0" 2, ">20.0" 1, ">10.0" 0 )
set xrange [-30:40]
set yrange [ 25:70]
set xtics 5
set ytics 5
#set title " %"
set grid front linetype -1
set grid xtics lt 0 lw 1 lc rgb "#000000"
set grid ytics lt 0 lw 1 lc rgb "#000000"
plot "HeatMap_Test.txt" u 2:1:(step($3)) notitle pt 5 ps 2 lc palette, "world_10m.txt" notitle with lines ls 1 lc -1, "contours.dat" u 1:2 w l lw 2 lc 0 notitle
Here are the data files: HeatMap_Test.txt, world_10m.txt
The code works in GNUplot 4.6 and 5 (I am working under Linux)
To get the plot I want, I still have to do three things:
1) Label the contourlines (with 99, 95 and 90 from the inner to the outer lines)
2) Make the borderlines fit the plot (in the figure the heatmap goes over the borders)
3) Put a title (in this case a single '%') just on top of the colorbar. A dirty way to do it is to set a normal title and put spaces (there is a commented line in the code to do it), but I think there must be something better.
My idea of labelling the contour is like in this image:
Thank you for your help
回答1:
Let's start with number 3: A title for the colorbar.
You want to set the cblabel
on top of the colorbar. While I don't think that this can be done automatically, you can use an offset x,y
like this:
set cblabel "%" norotate offset -6, 9
Still a hack, but I think it is better than misusing the title.
Now number 2: Make the borderlines fit the plot.
The reason for going over the borderline is the (implicit) command plot with points pointsize 2
. The points which are plotted just on the border will overlap. I would suggest to replace the points with a splot pm3d
like this:
set pm3d explicit
set view map
splot "HeatMap_Test_2.txt" u 2:1:(0):(step($3)) notitle w pm3d lc palette , \
"world_10m.txt" u 1:2:(0) notitle with lines ls 1 lc rgb "#ffffff" , \
"contours.dat" u 1:2:(0) w l lw 2 lc rgb "#000000" notitle
To get this 3D splot to work, I did the following:
- add a dummy z column, the number
(0)
- format "HeadMap_test.txt" into blocks, which means to insert a blank line after each latitude scan
from:
...
25.00 38.00 15.9
25.00 39.00 5.3
25.00 40.00 1.6
26.00 -30.00 0.0
26.00 -29.00 0.3
26.00 -28.00 0.7
...
to:
...
25.00 38.00 15.9
25.00 39.00 5.3
25.00 40.00 1.6
26.00 -30.00 0.0
26.00 -29.00 0.3
26.00 -28.00 0.7
...
- And I had to adjust the first step function for finding the contours a little bit, I have decreased the values of the steps at 90, 95, and 99 a little bit
Like this:
step(x) = (x < 20.0 ? 0 : \
(x < 50.0 ? 10 : \
(x < 75.0 ? 20 : \
(x < 90.0 ? 80 : \
(x < 95.0 ? 89.999 : \
(x < 97.5 ? 94.999 : \
(x < 99.0 ? 97 : \
(x < 99.5 ? 98.999 : \
(x < 99.9 ? 100 : 101 )))))))))
Now, with pngcairo terminal and Gnuplot 4.6, we should have arrived here:
And number 1: Label the contourlines
I have not tried it, but maybe this post can help you.
回答2:
I finally got it, thanks to the answer of @maij, using the link he provided.
With issue number 3, I used @maij line with this parameters:
set cblabel "%" norotate offset -8, 12
With issue number 2, when plotting the heatmap, I had to change from
plot "HeatMap_Test.txt" u 2:1:(step($3)) notitle pt 5 ps 2 lc palette
to
plot "HeatMap_Test.txt" u 2:1:(step($3)) with image
Last, with issue number 1, to put the labels in the contour lines, I had to use an external awk script provided in the same link as before. I named the script draw_contourlines_label.sh, and the content of the script is:
#!/bin/bash
awk -v d=$2 -v w=$3 -v os=$4 'function abs(x) { return (x>=0?x:-x) }
{
if($0~/# Contour/) nr=0
if(nr==int(os+w/2) && d==0) {a[i]=$1; b[i]=$2; c[i]=$3;}
if(nr==int(os+w/2)-1 && d==0) {i++; x = $1; y = $2;}
if(nr==int(os+w/2)+1 && d==0) r[i]= 180.0*atan2(y-$2, x-$1)/3.14
if(abs(nr-os-w/2)>w/2 && d==1) print $0
nr++
}
END { if(d==0) {
for(j=1;j<=i;j++)
printf "set label %d \"%g\" at %g, %g centre front rotate by %d\n", j, c[j], a[j], b[j], r[j]
}
}' "$1"
This script has the following parameters:
#1 -> File with the contour data generated by GNUplot
#2 -> Flag. If it is '0', prints a script for GNUplot to add the labels in the plot. If it is '1', takes out the points of the contour lines so the lines of the contour plots do not go over the label
#3 -> Number of spaces for formatting the label
#4 -> Offset to move the white spaces for the labels (so they are not centered)
My result using wxt terminal is:
The result is:
The code to generate the plot is:
reset
#Function map values on desired ranges. The values set to 90,95,99 are for later labelling
step90(x) = (x < 20.0 ? 0 : (x < 50.0 ? 10 : (x < 75.0 ? 20 : (x < 90.0 ? 80 : (x < 95.0 ? 90 : (x < 97.5 ? 95 : (x < 99.0 ? 97 : (x < 99.5 ? 99 : (x < 99.9 ? 100 : 101 )))))))))
# enable 3D data read from a scattered data set in file
#71,46,10 are the number of different values for each axis X,Y,Z in "HeatMap_Test.txt" data file
#If values of dgrid3d are not set accordingly, weird contour values will be generated
set dgrid3d 71,46,10
set contour base # enable contour drawing
set view 0,0 # if you want to see the graph from above (2D plot)
unset surface # do not plot the surface, only the contour
set cntrparam levels discrete 90,95,99 #set contours only on values 90,95 and 99
set table "contours.dat" #Name of the output file to write the table
splot "HeatMap_Test.txt" u 2:1:(step90($3)) notitle
unset table #Write table to file
reset
#Map the Z values to desired ranges
step(x) = (x < 20.0 ? 0 : (x < 50.0 ? 1 : (x < 75.0 ? 2 : (x < 90.0 ? 3 : (x < 95.0 ? 4 : (x < 97.5 ? 5 : (x < 99.0 ? 6 : (x < 99.5 ? 7 : (x < 99.9 ? 8 : 9 )))))))))
set palette maxcolors 10
set palette defined (0 "#333399", 1 "#3333f7", 2 "#3373ff", 3 "#33c6ff", 4 "#5affd2", 5 "#9cff8f", 6 "#dfff4c", 7 "#ffc733", 8 "#ff7a33", 9 "#e53333")
set cbrange [-0.5:9.5]
set cbtics nomirror
set cbtics ( ">99.9" 9, ">99.5" 8, ">99.0" 7, ">97.5" 6, ">95.0" 5, ">90.0" 4, ">75.0" 3, ">50.0" 2, ">20.0" 1, ">10.0" 0 )
set cblabel "%" norotate offset -8, 12
set xrange [-30:40]
set yrange [ 25:70]
set xtics 5
set ytics 5
set grid front linetype -1
set grid xtics lt 0 lw 1 lc rgb "#000000"
set grid ytics lt 0 lw 1 lc rgb "#000000"
load "<./draw_contourlines_label.sh contours.dat 0 4 0"
plot "HeatMap_Test.txt" u 2:1:(step($3)) with image, "world_10m.txt" notitle with lines ls 1 lc -1, "<./draw_contourlines_label.sh contours.dat 1 3 0" u 1:2 w l lw 2 lc 0 notitle
NOTE: If the file "contours.dat" is computed with GNUplot 4.6.4, the labels do not appear in the same way. Once the file is computed, with version 4.6+ show the same plot.
We can also use @maij approach using splot function. To do this, we first need to change the step function as he stated, because otherwise it produced weird lines. I renamed the function to step3D, but it is exactly @maij posted above:
step(x) = (x < 20.0 ? 0 : \
(x < 50.0 ? 10 : \
(x < 75.0 ? 20 : \
(x < 90.0 ? 80 : \
(x < 95.0 ? 89.999 : \
(x < 97.5 ? 94.999 : \
(x < 99.0 ? 97 : \
(x < 99.5 ? 98.999 : \
(x < 99.9 ? 100 : 101 )))))))))
With splot, there is also the need to format the input file into blocks. I did with this simple awk script, which can be put directly in the splot command:
awk 'NF>=1 && $1!~/#/ && $1!=prev {print \"\"} {prev=$1;print}' HeatMap_Test.txt
In GNUplot 5+, when plotting the colobar percentages appeared half-cutted, and the x and y labels were too separated, so I had to manually tweak them to fit the screen with this commands:
set rmargin at screen 0.8
set lmargin at screen 0.08
set tmargin at screen 0.95
set xtics offset 0, screen 0.036
set ytics offset screen 0.008, 0
The contour lines are plotted with the same command, so the result we get is similar (only the contour lines change a bit due to the ranges):
The code to generate the plot is:
reset
#Function map values on desired ranges. The values set to 90,95,99 are for later labelling
step3D(x) = (x < 20.0 ? 0 : (x < 50.0 ? 10 : (x < 75.0 ? 20 : (x < 90.0 ? 80 : (x < 95.0 ? 89.999 : (x < 97.5 ? 94.999 : (x < 99.0 ? 97 : (x < 99.5 ? 98.999 : (x < 99.9 ? 100 : 101 )))))))))
# enable 3D data read from a scattered data set in file
#71,46,10 are the number of different values for each axis X,Y,Z in "HeatMap_Test.txt" data file
#If values of dgrid3d are not set accordingly, weird contour values will be generated
set dgrid3d 71,46,10
set contour base # enable contour drawing
set view 0,0 # if you want to see the graph from above (2D plot)
unset surface # do not plot the surface, only the contour
set cntrparam levels discrete 90,95,99 #set contours only on values 90,95 and 99
set table "contours.dat" #Name of the output file to write the table
splot "HeatMap_Test.txt" u 2:1:(step3D($3)) notitle
unset table #Write table to file
reset
#Map the Z values to desired ranges
step(x) = (x < 20.0 ? 0 : (x < 50.0 ? 1 : (x < 75.0 ? 2 : (x < 90.0 ? 3 : (x < 95.0 ? 4 : (x < 97.5 ? 5 : (x < 99.0 ? 6 : (x < 99.5 ? 7 : (x < 99.9 ? 8 : 9 )))))))))
set palette maxcolors 10
set palette defined (0 "#333399", 1 "#3333f7", 2 "#3373ff", 3 "#33c6ff", 4 "#5affd2", 5 "#9cff8f", 6 "#dfff4c", 7 "#ffc733", 8 "#ff7a33", 9 "#e53333")
set cbrange [-0.5:9.5]
set cbtics nomirror
set cbtics ( ">99.9" 9, ">99.5" 8, ">99.0" 7, ">97.5" 6, ">95.0" 5, ">90.0" 4, ">75.0" 3, ">50.0" 2, ">20.0" 1, ">10.0" 0 )
set cblabel "%" norotate offset -8, 11.5
set xrange [-30:40]
set yrange [ 25:70]
set xtics 5
set ytics 5
set grid front linetype -1
set grid xtics lt 0 lw 1 lc rgb "#000000"
set grid ytics lt 0 lw 1 lc rgb "#000000"
set rmargin at screen 0.8
set lmargin at screen 0.08
set tmargin at screen 0.95
set xtics offset 0, screen 0.036
set ytics offset screen 0.008, 0
set pm3d explicit
set view map
load "<./draw_contourlines_label.sh contours.dat 0 4 0"
splot "< awk 'NF>=1 && $1!~/#/ && $1!=prev {print \"\"} {prev=$1;print}' HeatMap_Test.txt" u 2:1:(0):(step($3)) notitle w pm3d lc palette ,"world_10m.txt" u 1:2:(0) notitle with lines ls 1 lc rgb "#ffffff", "<./draw_contourlines_label.sh contours.dat 1 3 0" u 1:2:(0) w l lw 2 lc rgb "#000000" notitle
NOTE: If you are a Windows user, you can also do this plot using the Cygwin's GNUplot version
来源:https://stackoverflow.com/questions/40916407/contour-lines-with-labels-in-heatmap-with-gnuplot