AlexisBRENON
AlexisBRENON

Reputation: 3079

Merge key entries in gnuplot

I would like to plot data with lines and points with different colors. It seems to exist different solutions:

However, none of them handle the key properly, showing only one entry with both the line and a point with different colors... Is there another way to achieve it?

This is minimal (non-)working example.

set key bottom right
plot '+' using 1:1 title "same data with different lines and points color" with lines lc 'blue', '' using 1:1 every 3 notitle with points ps 1.2 pt 7 lc 'red';

Kind regards, Alexis.

Upvotes: 1

Views: 1705

Answers (3)

theozh
theozh

Reputation: 25704

Having 3 different colors for a linespoints plot is certainly "non-standard" and as you noticed a challenge especially for the proper key.

Here is a suggestion without using multiplot. Personally, I would use multiplot only if absolutely necessary. Otherwise you will lose the benefits of automargin and autoscale and you have to deal with margins and ranges, etc. yourself as you did in your solution.

Since the automatic creation of the key is the problem, then "do-it-yourself".

Update: simplified plot command and legend at graph coordinates.

This suggestion draws the legend via labels and arrows. You give the position and distances of the legend in graph coordinates. The mix of points and linespoints within a for loop is taken from here.

Script: (works with gnuplot>=5.0.0, Jan. 2015)

### legend for plot with linespoints and different colors for line, fill and border
reset session

# no. lw  pt  colorLine  colorFill  colorBorder label
mySettings = '\
  1   2   5   0x00ff00   0xffff00   0xff0000     "x + 1"   \
  2   2   7   0x0000ff   0xff00ff   0x000000     "x^2 - 8" \
'  # end of settings

myLw(n)      = real(word(mySettings,n*7-5))   # linewidth
myPt(n)      =  int(word(mySettings,n*7-4))   # pointtype
cL(n)        =  int(word(mySettings,n*7-3))   # color line
cF(n)        =  int(word(mySettings,n*7-2))   # color fill
cB(n)        =  int(word(mySettings,n*7-1))   # color border
myLabel(n)   =      word(mySettings,n*7)      # label
myLt(n)      = n==1 ? 1 : -2
myPtL(v,i)   = i==1 ? 0     : i==2 ? myPt(v) : myPt(v)-1
myColor(v,i) = i==1 ? cL(v) : i==2 ? cF(v) : cB(v)
myPs         = 3   # fixed pointsize

# Legend position graph units
xPos = 0.05     # x-position
yPos = 0.95     # y-position
dy   = 0.07     # y distance
dx   = 0.025    # x length

set for [i=1:words(mySettings)/7] arrow from graph xPos-dx,yPos-(i-1)*dy to graph xPos+dx,yPos-(i-1)*dy \
    lw myLw(i) lc rgb myColor(i,1) nohead back
set for [i=1:2] for [j=2:3] label myLabel(i) at graph xPos,yPos-(i-1)*dy left offset 3,0 \
    point pt myPtL(i,j) ps myPs lc rgb myColor(i,j) lw myLw(i) front

set samples 11       # samples for functions
set key noautotitle
set grid x
set grid y

f1(x) = x + 1
f2(x) = x**2 - 8

plot for [i=1:3]        f1(x) w lp lt myLt(i) pt myPtL(1,i) ps (i>>1)*myPs lc rgb myColor(1,i) lw myLw(1), \
     for [i=1:3] [-5:5] f2(x) w lp lt myLt(i) pt myPtL(2,i) ps (i>>1)*myPs lc rgb myColor(2,i) lw myLw(2)
### end of script

Result:

enter image description here

Upvotes: 2

AlexisBRENON
AlexisBRENON

Reputation: 3079

Thanks ewcz for your answer, it is a first step toward the expected result. However, as you stated it, this is a little bit trickier to adapt it if you have multiple functions/data to display on the same plot.

Below is a minimal working example with two functions (and thus, two key entries) with a line, points, and points outline of different colors.

# These parameters are used to compute the spacing between entries of the key
pointSize = 1;
yticsScale = 1;
# We use the default spacing (1.25)
keySpacing = pointSize*yticsScale*1.25;

# Initial coordinate of the key
keyY = 4; # In character system
keyX = 0.87; # In graph system

# Just to generate data
set samples 20;
set xrange [-pi:pi];

set term pngcairo;
set output 'graph.png';
set xlabel "x"
set ylabel "y"

# Set the alignment (and thus the coordinate point) of the key
# Set the spacing to -1 to stack different (thanks to ewcz for the idea)
set key bottom right spacing -1

# Start a multiplot
set multiplot
# Make plots as big as possible
set origin 0,0
set size 1,1

# Set the key position
set key at graph keyX, character keyY

# Plot multiple times the same function with different styles.
# Make sure that all functions have a title (empty if necessary).
plot cos(x+pi) w l lc "light-red", \
     cos(x+pi) w p pt 5 ps 1.8 lc "dark-red" t ' ', \
     cos(x+pi) w p pt 5 ps 1.2 lc "red" t ' '
# Update key coordinates for the next plot
keyY = keyY + keySpacing

# Draw the key of the next plot at the new coordinates
set key at graph keyX, character keyY
plot cos(x) w l lc "light-blue", \
     cos(x) w p pt 7 ps 1.8 lc "dark-blue" t ' ', \
     cos(x) w p pt 7 ps 1.2 lc "blue" t ' ';

# That's all
unset multiplot
set output;

The resulting plot: A very nice plot

Hope that will help others.

Kind regards.

Alexis


Edit:

The previous code works if both functions/data have the same ranges (on x and y) allowing autoscale to work properly.

In the case of data where you do not know the ranges, you must compute it before plotting.

# Just to generate data
set samples 20;

# First data will be defined on [-pi:pi] with values between -1 and 1.
set table '1.dat'
plot [-pi:pi] cos(x)
unset table
# Second data will be defined on [-pi/2,pi/2] with values between 0 and -2
set table '2.dat'
plot [-pi/2:pi/2] 2*cos(x+pi)
unset table

# These parameters are used to compute the spacing between entries of the key
pointSize = 1;
yticsScale = 1;
keySpacingScale = 1.25; # Gnuplot default spacing
keySpacing = pointSize * yticsScale * keySpacingScale; # Spacing computation

set pointsize pointSize;
set ytics scale yticsScale;
set key spacing -1; # Make key entries overlapping (thanks ewcz for the idea)

# Initial coordinate of the key
keyY = 4.5; # In character system
keyX = 0.98; # In graph system

set term pngcairo;
set output 'graph.png';

# Remove redundant objects
# Borders, labels, tics will be drawn for each plot, this is not necessary as all plots will be stacked. So remove then.
set border 0
set tics textcolor "white" # Dirty tricks to keep plots aligned but to not show the tics
set xlabel " " # The same
set ylabel " " # The same

# Compute the ranges
min(v1, v2) = (v1 < v2) ? v1 : v2;
max(v1, v2) = (v1 > v2) ? v1 : v2;
# Get min and max for the data
stats [*:*] [*:*] '1.dat' name 'f1' nooutput;
stats [*:*] [*:*] '2.dat' name 'f2' nooutput;
# Get the range limits
xmin = min(f1_min_x, f2_min_x)
xmax = max(f1_max_x, f2_max_x)
ymin = min(f1_min_y, f2_min_y)
ymax = max(f1_max_y, f2_max_y)
# Autoscale the range to match all the data
set xrange [* < xmin:xmax < *] writeback
set yrange [* < ymin:ymax < *] writeback

# Start a multiplot
set multiplot
# Make plots as big as possible
set origin 0,0
set size 1,1

# Set the key
set key bottom right at graph keyX, character keyY

# Plot multiple times the same function with different styles.
# Make sure that all functions have a title (empty if necessary).
plot '1.dat' w l lc "light-red" t "cos(x)", \
          '' w p pt 5 ps 1.8 lc "dark-red" t ' ', \
          '' w p pt 5 ps 1.2 lc "red" t ' '

# Update key coordinates for the next plot
keyY = keyY + keySpacing
# Draw the key of the next plot at the new coordinates
set key at graph keyX, character keyY

# Display at least once the labels
set border
set tics textcolor "black"
set xlabel "x"
set ylabel "y"

# Disable ranges autoscaling
set xrange restore
set yrange restore

plot '2.dat' w l lc "light-blue" t "2cos(x+pi)", \
          '' w p pt 5 ps 1.8 lc "dark-blue" t ' ', \
          '' w p pt 5 ps 1.2 lc "blue" t ' '

# That's all
unset multiplot
set output;

One more time the resulting plots: Imgur

Kind regards,

Alexis

Upvotes: 1

ewcz
ewcz

Reputation: 13087

If your plot is not too complex, you could perhaps achieve this by playing with the spacing parameter of the legend. Setting spacing to -1 achieves that the labels/symbols overlap:

set terminal pngcairo enhanced
set output 'fig.png'

set xr [-pi/2:pi/2]
set yr [0:1]

set key at graph 0.95,graph 0.9 spacing -1

plot \
    cos(x) w l lc rgb 'dark-red' lw 2, \
    '-' w p lc rgb 'royalblue' pt 7 ps 2 t ' '
-1  0.540302
0   1
1   0.540302
e

which gives enter image description here

However, the disadvantage is that the setting is in a sense global - should the plot contain more functions/data files, everything would overlap. In order to use this "method" in this particular case, it would be necessary to invoke multiplot and create the keys separately.

Upvotes: 3

Related Questions