Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gnuplot: how to set custom non linear scales

Tags:

gnuplot

is there any possibility for using non linear scales with self defined break of slope points? For example: i want the half of the y-scale shows the range [0:1] and the other half [1:5] and i do not want to use logarithmic scale.

The best thing would be the possibility to provide a mapping function. Sure one could directly map the function results but then the labes will not fit to the actual data.

Is there any possiblilty? I searched a bit but iam not sure if i missed something or if it is not possible.

like image 639
vlad_tepesch Avatar asked Sep 20 '13 14:09

vlad_tepesch


2 Answers

This can be done with set link, which is available only in the 4.7 development version.

The following script does the mapping, but the labels are on the y2-axis:

reset
f(x) = x <= 1 ? x : 1 + (x-1)*4
i(x) = x <= 1 ? x : (x-1)/4.0 + 1
set link y2 via f(y) inverse i(y)

unset ytics
set y2tics mirror

set xrange[0:5]
set yrange[0:2]
plot x axes x1y2

Result with 4.7:

enter image description here

With some offset, you can move the labels from the y2-axis to the y-axis:

reset
set terminal pngcairo size 800,500
set output 'output.png'

f(x) = x <= 1 ? x : 1 + (x-1)*4
i(x) = x <= 1 ? x : (x-1)/4.0 + 1
set link y2 via f(y) inverse i(y)

unset ytics
set lmargin at screen 0.1
set rmargin at screen 0.95
set y2tics mirror offset graph -1.04 right
# set y2tics add (0.5)
set my2tics 2
set y2tics add ('' 0.25 1, '' 0.75 1)
set ylabel 'ylabel' offset -4

set xrange[0:5]
set yrange[0:2]
plot x axes x1y2

That's quite ugly, but it works. It requires just a little fiddling with the left and right margins and the y2tics offset.

EDIT: I added minor tics, with a higher frequency between 0 and 1. I think it might be useful to add one label for 0.5 to show that the scale is linear, but with a different gradient (in which case you also might want to set y2tics format '%.1f' to have one decimal digit for all labels). However, this tic would also appear as a major tics, because using labels for minor tics is not supported, yet.

The result is: enter image description here

like image 124
Christoph Avatar answered Sep 24 '22 02:09

Christoph


You have a couple of options to accomplish that kind of plot. I will use these sample data:

0 0
1 0.5
2 0.6
3 1
4 1.5
5 0.5
6 2.5
7 5
8 2

Multiplot method

Here you just make two plots of the same data on top of each other. Note that where the data cross the border of the plots there is a joint in the line (if you plot a line).

This is a little more complicated than the mapping method below.

#!/usr/bin/env gnuplot

reset

set terminal pdfcairo enhanced color lw 3 size 3,2 font 'Arial,14'
set output 'output.pdf'

set style data linespoints

set title 'my plot'
set key top left

set multiplot layout 2,1

### first (top) plot
# play with margins to ensure top and bottom plots are same size
set bmargin 0
set tmargin 2.5
# also that left margin is same with/without y label
set lmargin 6

set yrange [1:5]

unset xtics
set ytics 1 out scale 0.5 nomirror

# remove bottom line of border
set border 14

plot 'data.dat' pt 7 title 'my data'

### second (bottom) plot
unset title

# set margins to match first plot
set bmargin 2.5
set tmargin 0

set yrange [0:1]

# this offset along with the label offset compresses the bottom whitespace
set xtics out scale 0.5 nomirror offset 0,0.4

# create and place labels where they will be visible
set xlabel 'x label' offset 0,0.8
set ylabel 'y label' offset 1,3

# remove top line of border
set border 11
plot 'data.dat' pt 7 notitle

unset multiplot

reset

Result:

enter image description here

Mapping method

Here we create a mapping function and manipulate the y labels to match. Note there is no joint in the line, which may or may not be what you want.

#!/usr/bin/env gnuplot

reset

set terminal pdfcairo enhanced color lw 3 size 3,2 font 'Arial,14'
set output 'output2.pdf'

set style data linespoints

set key top left

set title 'my plot'
set xlabel 'x label'
set ylabel 'y label'

# mapping function
map(x) = x <= 1.0 ? x : (x-1.0)/4.0 + 1.0

# upper y bound is set by (5-1.0)/4.0 + 1.0
set yrange [0:2]
# y labels create illusion
set ytics out scale 0.5 nomirror \
  ("0" 0, "1" 1, "2" 1.25, "3" 1.5, "4" 1.75, "5" 2)
set xtics out scale 0.5 nomirror

plot 'data.dat' u 1:(map($2)) pt 7 title 'my data'

reset

Result:

enter image description here

like image 29
andyras Avatar answered Sep 22 '22 02:09

andyras