gnuplot: how to set custom non linear scales
Asked Answered
L

2

7

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.

Loreenlorelei answered 20/9, 2013 at 14:20 Comment(3)
I think, the only way to do this automatically would be to use set link, which is available since 4.7, but my first tries didn't succeed: i(x) = x <= 1 ? x : 1 + (x-1)*4; f(x) = x <= 1 ? x : (x-1)/4.0 + 1; set link y2 via f(y) inverse i(y).Sperm
@Sperm i didn't understand how the link cmd could help. its the same if i specify set link y2 via y**2 inverse sqrt(y) and plot x axis x1y2 or if i directly use plot sqrt(x). In both cases the y axis scale displays the wrong dataLoreenlorelei
See my answer. This is the most 'handy' variant I can come up with.Sperm
S
7

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

Sperm answered 20/9, 2013 at 15:7 Comment(5)
Interesting answer--I would not have thought to use set link that way (not being familiar with the command).Vulgarian
one more problem: the axis title is drawn in the axis tics labes and the ne plus ultra would be if the m2tics frequency could be increased in the stretched drawn areaLoreenlorelei
@Loreenlorelei Sorry, don't get your question about the title. If you mean the ylabel, then you can also use an offset: set ylabel 'mylabel' offset -3, but you'll need to increase the lmargin for this. I don't think it is possible to increase the m2tics in the stretched area. But I'm thinking the whole time, if it wouldn't be rather straightforward to transfer this mapping stuff to a single axis, instead of linking. I'll have a look into the code...Sperm
@Loreenlorelei Well, of course you can add custom minor tics, see the edited answer :).Sperm
thanks. i got the ylabel offset by myself. also thanks for the editLoreenlorelei
V
3

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

Vulgarian answered 20/9, 2013 at 15:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.