0
votes

I try to plot two horizontal lines in a coordinate system using GNUPlot. The two lines represent average values in two datasets. Each dataset has the following constants: max, min and average. The same logic is to be applied to both datasets, so we can simply focus at one of them.

The output should be a 800 x 800 PNG image. They share the X axis, but their Y axis is different from each other in terms of the ranges' values and unit of measurement. Naturally, the numerical values of the two lines can vary arbitrarily. More precisely, I need to plot the two lines at, say, y = 300 and y = 500 in pixel coordinates, regardless of the value of average.

As far I as can tell, there is no way to tell GNUPlot to plot something at a specific pixel coordinate. However, I do believe it is possible to to it indirectly by adjusting the ranges to appropriate values. After poking around in GNUPlot, I managed to find proper values. When the proper range values are set, I think the datapoints in the set should be plotted nicely such that they fit into the graph. Now I need a general approach for any values.

I have the following GNUPlot script with arbitrary values for two horizontal lines:

set term png size 800, 800
set multiplot layout 1, 1

# Green line
min_green = 0
max_green = 50
set size 1,1
set ytics 20
set yrange [min_green : max_green]
avg_green = 22
plot avg_green linecolor rgb "green"

# Blue line
min_blue = 10
max_blue = 70
set size 1,1
set ytics 20
set yrange [min_blue : max_blue]
avg_blue = 14
plot avg_blue linecolor rgb "blue"

Use it like this: gnuplot -p script > plot.png

I need two procedure that looks something like this:

range_min = get_new_min_range(pixel_target_y, min, max, avg)
range_max = get_new_max_range(pixel_target_y, min, max, avg)

The ranges is put into set yrange in GNUPlot. The green line must be at y = 500 and the blue line must be at y = 300 (this is the pixel_target_y patameter). Any help is greatly appreciated!

1
You can use set arrow nohead to plot your line. Then you have access to different coordinate systems like screen for coordinates relative to the canvas (window size), or graph for coordinates relative to your plot area.Christoph

1 Answers

1
votes

Let me try to repeat in my words if I understood your question correctly: You want to plot two datasets where the average (or mean) of each datasets have a fixed y-pixel-(or screen) position within the output graph (independent of data values and graph margins), correct?

For this you need the gnuplot variables GPVAL_TERM_YMIN and GPVAL_TERM_YMAX. In order to get these values you have to plot a dummy graph first. Then you need to do some calculations to get the proper range. As you can see in the result from 3 different plots: the green and blue lines are independent of x-labels or graph titles.

Code:

### have average lines at fixed pixel position within the plot
reset session

myTermSizeX = 800
myTermSizeY = 800
set term pngcairo size myTermSizeX, myTermSizeY
myOutputFile = "Output.png"
set output myOutputFile

myFixY1 = 500
myFixY2 = 300

set title "Some graph title"
set xlabel "x-Axis title"

# create some test data
set table $Data1
    plot '+' u 1:(rand(0)*50+40) smooth bezier
unset table
set table $Data2
    plot '+' u 1:(rand(0)*40+10) smooth bezier
unset table

stats $Data1 u 2 name 'Data1' nooutput
stats $Data2 u 2 name 'Data2' nooutput
print Data1_min, Data1_mean, Data1_max
print Data2_min, Data2_mean, Data2_max

# dummy plot to get GPVAL_TERM_YMIN, GPVAL_TERM_YMAX
plot x

R_grph1 = real(myFixY1 - GPVAL_TERM_YMIN)/(GPVAL_TERM_YMAX - GPVAL_TERM_YMIN)
R_grph2 = real(myFixY2 - GPVAL_TERM_YMIN)/(GPVAL_TERM_YMAX - GPVAL_TERM_YMIN)

R_data1 = (Data1_mean - Data1_min)/(Data1_max-Data1_min)
R_data2 = (Data2_mean - Data2_min)/(Data2_max-Data2_min)

if (R_data1 > R_grph1) {
    Y1min = Data1_min
    Y1max = (Data1_mean - Data1_min)/R_grph1 + Data1_min
}
else {
    Y1max = Data1_max
    Y1min = Data1_max - (Data1_max - Data1_mean)/(1-R_grph1)
}
print Y1min,Y1max

if (R_data2 > R_grph2) {
    Y2min = Data2_min
    Y2max = (Data2_mean - Data2_min)/R_grph2 + Data2_min}
else {
    Y2max = Data2_max
    Y2min = Data2_max - (Data2_max - Data2_mean)/(1-R_grph2)
}
print Y2min,Y2max

set yrange [Y1min:Y1max]
set ytics nomirror
set y2range [Y2min:Y2max]
set y2tics nomirror

set output myOutputFile   # it seems you have to specify the output again
set key top center

plot \
    $Data1 u 1:2 axes x1y1 w lp pt 7 lc rgb "red" ti "Data1", \
    Data1_mean axes x1y1 w l lw 2 lc rgb  "green" ti "Data1 mean", \
    Data1_min axes x1y1 lt 0 not, \
    Data1_max axes x1y1 lt 0 not, \
    $Data2 u 1:2 axes x1y2 w lp pt 7 lc rgb "orange" ti "Data2", \
    Data2_mean axes x1y2 w l lw 2 lc rgb  "blue" ti "Data2 mean", \
    Data2_min axes x1y2 lt 0 not, \
    Data2_max axes x1y2 lt 0 not

set output
### end of code

Result:

enter image description here