I have some data (benchmarking results of k-selection algorithms) which has irregular x-values. I have them labeled explicitly (1, 50, 100, 500, 1000, 2500, and 5000).
Because these values are not linearly increasing (or exponentially increasing, although making the x-axis a logscale does improve things a bit, bug leaves a huge gap in between 1 and 50) they are oddly spread out and clumped together. Is there a way to scale the x-axis so that these data points are drawn at an even spacing?
Below is a sample of the grid spacing (labels and legends are not visible in the eps file, these are drawn later by the graphicx package) as well as the gnuplot commands I'm using.
set terminal epslatex
set xlabel 'k'
set ylabel 'seconds'
set tic scale 0
set key Left outside
set xtics rotate
set xtics ('1' 1, '50' 50, '100' 100, '500' 500, '1000' 1000, '2500' 2500, '5000' 5000)
set logscale y
set logscale x
set style data linespoints
set output 'selection.tex'
plot '../data/selection.dat' u 1:($2/1000) t 'Sort', \
'../data/selection.dat' u 1:($3/1000) t 'Partial Sort', \
'../data/selection.dat' u 1:($4/1000) t 'Heap', \
'../data/selection.dat' u 1:($5/1000) t 'Partial Heap', \
'../data/selection.dat' u 1:($6/1000) t 'Order Statistics'
The cleanest way to do it is to use the xticlabels command:
plot '../data/selection.dat' u ($2/1000):xticlabels(1) t 'Sort', \...
This takes the value from the first column and uses it as the x axis labels, while using the second column as data.
This is a bit like using the command
plot 'file' u 2
Which just plots the data from the second column against a dummy index (1,2,3,4...). This gives an even spacing to the data points, which seems to be what you want here.
Related
From this question it turned out that in some cases it might be desirable to align a subplot relative to another's plot axes coordinates.
If you check the gnuplot documentation, you will find that labels, arrows, objects (rectangles, polygons, circles, ...) can be positioned in different coordinate systems, i.e. axes, graph and screen (see help coordinates).
Subplots in a multiplot environment, however, (as far as I know) can only be aligned and sized relative to the screen, see help origin and help size.
Of course, you could always fiddle around with screen coordinates to find the desired positions, but when the size of the terminal or plot, axis labels or automargins might change you will have to start over again.
Question: How to align a subplot relative to the coordinates of another plot?
Aligning a subplot relative to another's plot coordinates is basically a "simple" transformation of coordinates, however, it's not too obvious how to do this in gnuplot.
I haven't found an example on the gnuplot homepage or elsewhere (this shouldn't mean it doesn't maybe exist somewhere), so I would like to share a way which should make life easier and somebody else might find it useful not to have to "reinvent the wheel".
Code:
### multiplots relative to other plots' axes coordinates
reset session
# function to store the current terminal values for later use
GetPlotParams(n) = sprintf("%g %g %g %g %g %g %g %g", \
GPVAL_X_MIN, \
GPVAL_X_MAX-GPVAL_X_MIN, \
GPVAL_Y_MIN, \
GPVAL_Y_MAX-GPVAL_Y_MIN, \
real(GPVAL_TERM_XMIN)/GPVAL_TERM_XSIZE*GPVAL_TERM_SCALE, \
real(GPVAL_TERM_YMIN)/GPVAL_TERM_YSIZE*GPVAL_TERM_SCALE, \
real(GPVAL_TERM_XMAX-GPVAL_TERM_XMIN)/GPVAL_TERM_XSIZE*GPVAL_TERM_SCALE, \
real(GPVAL_TERM_YMAX-GPVAL_TERM_YMIN)/GPVAL_TERM_YSIZE*GPVAL_TERM_SCALE ) \
# real() in order to avoid integer division
PosX(s,x) = word(s,5)+word(s,7)*(x-word(s,1))/word(s,2) # screen position of the subplot
PosY(s,y) = word(s,6)+word(s,8)*(y-word(s,3))/word(s,4)
SizeX(s,dx) = word(s,7)*dx/word(s,2) # screen size of a subplot
SizeY(s,dy) = word(s,8)*dy/word(s,4)
set multiplot
set title "First plot"
set xtics 1
set yrange[-100:100]
set ytics 20
set grid xtics, ytics
plot 25*sin(2*x)/x+10 w l lw 2 notitle
mp1 = GetPlotParams(0) # store parameters of 1st plot
# set white background for future plots
set object 1 rect from graph 0, graph 0 to graph 1, graph 1 behind fc "white"
set margins 0,0,0,0
unset xlabel
set format x ""
unset ylabel
set format y ""
set grid x2tics, ytics
# second plot
set title "2^{nd} plot at -9,30 rel. to first plot" offset 0,-0.5
set origin PosX(mp1,-9),PosY(mp1,30) # relative to plot1
set size SizeX(mp1,5),SizeY(mp1,50) # relative to plot1
plot 50*sin(x) w l lc "red" notitle
mp2 = GetPlotParams(0) # store parameters of 2nd plot
# third plot
set title "3^{rd} plot at 4,30 rel. to first"
set origin PosX(mp1,4),PosY(mp1,30) # relative to plot1
set size SizeX(mp1,5),SizeY(mp1,50) # relative to plot1
set format y ""
plot 50*cos(x)+20*sin(2*x) w l lc "magenta" notitle
mp3 = GetPlotParams(0) # store parameters of 3rd plot
# fourth plot
set title "4^{th} plot from 2^{nd} x=0 to 3^{nd} x=0"
set origin PosX(mp2,0),PosY(mp1,-80) # relative to plot1 and plot2
set size PosX(mp3,0)-PosX(mp2,0),SizeY(mp1,60) # relative to plot1, plot2 and plot3
set xrange [*:*]
set format x
set yrange[*:*]
set format y
plot x**2 w l lc "green" notitle
mp4 = GetPlotParams(0) # store parameters of 4th plot
# fifth plot
set title "5^{th} plot" offset 0,-1
set origin PosX(mp4,-4),PosY(mp4,20) # relative to plot4
set size SizeX(mp1,5),SizeY(mp4,60) # relative to plot1 and plot4
set format x ""
set format y ""
plot (int(2*x)%5)*8 w l lc "blue" notitle
mp5 = GetPlotParams(0)
unset multiplot
### end of code
Result: (actually, a nonsense plot just for illustration. Terminal: set term wxt size 650,480)
I am trying to visualize a time series data set on one plot as a pseudo 3d figure. However, I am having some trouble getting the filledcurves capability working properly. It seems to be adding an unwanted border at the "bottom" of my functions and I do not know how to fix this.
This is my current set up: I have nb_of_frames different files that I want to plot on one figure. Without the filledcurves option, I can do something like this
plot for [i=1:nb_of_frames] filename(i) u ($1):(50.0 * $2 + (11.0 - (i-1)*time_step)) w l linewidth 1.2 lt rgb "black" notitle
which produces a figure like this:
no fill options
Instead of doing this, I want to use the filledcurves option to bring my plots "forward" and highlight the function that is more "forward" which I try to do with:
plot for [i=1:nb_of_frames] filename(i) u ($1):(50. * $2 + (11. - (i-1)*time_step)) w filledcurves fc "white" fs solid 1.0 border lc "black" notitle
This produces a figure as follows:
This is very close to what I want, but it seems that the border option adds a line underneath the function which I do not want. I have tried several variants of with filledcurves y1=0.0 with different values of y1, but nothing seems to work.
Any help would be appreciated. Thank you for your time.
Here is another workaround for gnuplot 5.2.
Apparently, gnuplot closes the filled area from the last point back to the first point. Hence, if you specifiy border, then this line will also have a border which is undesired here (at least until gnuplot 5.4rc2 as #Ethan says).
A straightforward solution would be to plot the data with filledcurves without border and then again with lines. However, since this is a series of shifted data, this has to be plotted alternately. Unfortunately, gnuplot cannot switch plotting styles within a for loop (at least I don't know how). As a workaround for this, you have to build your plot command in a previous loop and use it with a macro # (check help macros) in the plot command. I hope you can adapt the example below to your needs.
Code:
### filledcurves without bottom border
reset session
set colorsequence classic
$Data <<EOD
1 0
2 1
3 2
4 1
5 4
6 5
7 2
8 1
9 0
EOD
myData(i) = sprintf('$Data u ($1-0.1*%d):($2+%d/5.)',i,i)
myFill = ' w filledcurves fc "0xffdddd" fs solid 1 notitle'
myLine = ' w l lc rgb "black" notitle'
myPlotCmd = ''
do for [i=11:1:-1] {
myPlotCmd = myPlotCmd.myData(i).myFill.", ".myData(i).myLine.", "
}
plot #myPlotCmd
### end of code
Result:
I can reproduce this in gnuplot 5.2.8 but not in the output from the release candidate for version 5.4. So I think that some bug-fix or change was applied during the past year or so. I realize that doesn't help while you are using verion 5.2, but if you can download and build from source for the 5.4 release candidate that would take care of it.
Update
I thought of a work-around, although it may be too complicated to be worth it.
You can treat this as a 2D projection of a 3D fence plot constructed using plot style with zerrorfill. In this projection the y coordinate is the visual depth. X is X. Three quantities are needed on z: the bounding line, the bottom, and the top. I.e. 5 fields in the using clause: x depth zline zbase ztop.
unset key
set view 90, 180
set xyplane at 0
unset ytics
set title "3D projection into the xz plane\nplot with zerrorfill" offset 0,-2
set xlabel "X axis" offset 0,-1
set zlabel "Z"
splot for [i=1:25] 'foo.dat' using ($1+i):(i/100.):($2-i):(-i):($2-i) \
with zerrorfill fc "light-cyan" lc "black" lw 2
Scenario: I need to draw a plot that has a background image. Based on the information on that image there have to be multiple origins (let's call them 'targets') that can move over time. The movements of these targets will have to be indicated by arrows/vectors where the first vector originates at the location of the target, the second vector originates where the previous vector ended and so on.
The result should look similar to this:
Plot with targets and movement vectors
While trying to implement this, i stumbled upon different questions:
I would use a chart with combined series: a Scatter plot to add the targets at exact x/y locations and a vector plot to insert the vectors. Would this be a correct way?
Since i want to set each vectors starting point to exact x/y coordinates i use rotationOrigin: 'start'. When i now change vectorLength to something other than 20 the vector is still shifted by 10 pixels (http://jsfiddle.net/Chop_Suey/cx35ptrh/) this looks like a bug to me. Can it be fixed or is there a workaround?
When i define a vector it looks like [x, y, length, direction]. But length is a relative unit that is calculated with some magic relative to the longest vector which is 20 (pixels) by default or whatever i set vectorLength to. Thus, the vectors are not connected and the space between them changes depending on plot size axes min/max). I actually want to corellate the length with the plot axis (which might be tricky since the x-axis and y-axis might have different scales). A workaround could be to add a redraw event and recalculate the vectors on every resize and set the vectorLength to the currently longest vector (which again can be calculated to correlate to the axes). This is very cumbersome and i would prefer to be able to set the vectors somehow like [x1, y1, x2, y2] where (x1/y2) denotes the starting- and (x2/y2) the ending-point of the vector. Is this possible somehow? any recommendations?
Since the background image is not just a decoration but relevant for the displayed data to make sense it should change when i zoom in. Is it possible to 'lock' the background image to the original plot min/max so that when i zoom in, the background image is also zoomed (image quality does not matter)?
Combining these two series shoudn't be problematic at all, and that will be the correct way, but it is necessary to change the prototype functions a bit for that the vectors will draw in a different way. Here is the example: https://jsfiddle.net/6vkjspoc/
There is probably the bug in this module and we will report it as new issue as soon as it is possible. However, we made the workaround (or fix) for that and now it's working well, what you can notice in example above.
Vector length is currently calculated using scale, namely - if vectorLength value is equal to 100 (for example), and vector series has two points which looks like that:
{
type: 'vector',
vectorLength: 100,
rotationOrigin: 'start',
data: [
[1, 50000, 1, 120],
[1, 50000, 2, -120]
]
}
Then the highest length of all points is taken and basing on it the scale is calculated for each point, so first one length is equal to 50, because the algorithm is point.length / lengthMax, what you can deduce from the code below:
H.seriesTypes.vector.prototype.arrow = function(point) {
var path,
fraction = point.length / this.lengthMax,
u = fraction * this.options.vectorLength / 20,
o = {
start: 10 * u,
center: 0,
end: -10 * u
}[this.options.rotationOrigin] || 0;
// The stem and the arrow head. Draw the arrow first with rotation 0,
// which is the arrow pointing down (vector from north to south).
path = [
'M', 0, 7 * u + o, // base of arrow
'L', -1.5 * u, 7 * u + o,
0, 10 * u + o,
1.5 * u, 7 * u + o,
0, 7 * u + o,
0, -10 * u + o // top
];
return path;
}
Regarding your question about defining start and end of a vector by two x, y values, you need to refactor entire series code, so that it won't use the vectorLength at all as like as scale, because you will define the points length. I suspect that will be very complex solution, so you can try to do it by yourself, and let me know about the results.
In order to make it works, you need to recalculate and update vectorLength of your vector series inside of chart.events.selection handler. Here is the example: https://jsfiddle.net/nh7b6qx9/
I am trying to use the multiplot feature of gnuplot to make a inset graphic on the main plot. I can generate the plot exactly as I want with term='wxt' except for the axis labels, which require LaTeX formatting for generating the desired symbols. When I submit the same commands to term='epslatex', the plot is fine, but all text (axis and tic mark labels) is positioned incorrectly.
I thought using the set size & origin commands might have confused the epslatex terminal output, so I attempted to use the layout command and make the plots side by side just to see if the text would print correctly. It did not.
I'm using gnuplot 4.6 patch 4, and Linux Mint 17.
My script is below. The commented sections indicate the original script that used set size and origin commands to manually place the second plot as a inset, rather than side by side.
set term epslatex color font ",16"
unset key
set termoption dash
set style line 1 lc rgb 'blue' lw 2 lt 1
set style line 2 lc rgb 'red' lw 2 lt 3
set style line 3 lc rgb 'green' lw 2 lt 5
set style line 4 lc rgb 'magenta' lw 2 lt 7
set style line 5 lc rgb 'black' lw 1 lt 0
set output "gr-thresholds.tex"
#set size 1,1
# set multiplot
set multiplot layout 1,2
# bigger plot
set autoscale
set ytics scale default autofreq
set xrange[0:14]
set yrange[0:1.7]
set xlabel 'r (\AA)'
set ylabel '$g(r)$'
#set size 1,1
#set origin 0,0
plot "foo1.csv" w l ls 2, \
"foo2.csv" w l ls 3 , \
"foo3.csv" w l ls 1, \
"foo4.csv" w l ls 4
#small inset
#set size 0.4, 0.4
#set origin 0.5,0.15
set xrange[1.2:2.2]
set yrange[0:0.8]
set ytics 0, 0.2, 2
set xlabel ""
set ylabel ""
plot "foo1.csv" w l ls 2, \
"foo2.csv" w l ls 3 , \
"foo3.csv" w l ls 1, \
"foo4.csv" w l ls 4
unset multiplot
set output
The figure that was generated:
It might be a problem with the way you generate a pdf. The two commands dvipdfm and dvipdf produce different outcomes.
If I take your code, but plot sin(x) instead, and use the following in the terminal:
$ latex file.tex
$ dvipdfm file.dvi
I also get a mismatch between the axes and the plots.
If I use dvipdf however everything looks fine:
$ dvipdf file.dvi
Ok,
Per Tom Fenech's suggestion, I made a minimum code sample to reproduce the error, and the issue that arose is a machine state problem. To generate my graphs, I had run the script twice, once using term wxt and then again using term epslatex.
The problem is that somewhere the state of the gnuplot environment is changed and is not reset by this script. Specifically, the first time through, the default placement of the text labels is fine. The second time through, the range and labels are still attached to the size and origin from the last plot, which is the inset. I thought this was due to the order of the commands set origin/size relative to x/ylabel and x/y range, but simply running the below code twice without restarting gnuplot will generate two different plots. The first time is exactly what I wanted, the second time will skew the labels as shown above.
So I have a "solution", but it is fragile. I would appreciate if someone could explain what I need to do to make this script run multiple times without restarting each time.
Cheers,
--Jim
set term epslatex color font ",16"
unset key
f(x) = sin(x)
set output "sin.tex"
set multiplot
set size 1,1
set origin 0,0
set xrange[0:14]
set yrange[0:6]
set xlabel 'r (\AA)'
set ylabel '$g(r)$'
plot f(x)
#small inset
set size 0.4, 0.4
set origin 0.5,0.15
set xrange[1:3]
set yrange[0:4]
set ytics 0, 0.2, 2
set xlabel ""
set ylabel ""
plot f(x)
unset multiplot
set output
My data file has four columns because opencv saves elements in an n x 4 form in xml when exporting a cv::Mat to xml.
How can I concatenate these four columns into one?
reset
set terminal postscript eps enhanced
set output 'imp.eps'
set pm3d
set palette model HSV defined ( 0 0 1 1, 1 1 1 1 )
set style data histogram
set colorbox user
set origin 0.0,0.10
set size ratio 0 1,0.8
set colorbox horizontal origin graph 0.0, -0.15, 0 size graph 1, 0.05, 0 noborder
set xrange [0:4096]
plot 'var_imp_first_run.data' using 1
set output
I have 4094 elements, and this example creates an histogram where the first 1024 is plotted. I need to append column 2 from x=1024:2048. Please ignore the colorbox stuff; I'm just playing around to learn gnuplot.
I found out that following solve my problem above.
set xrange [0:4096]
plot newhistogram at 0, 'var_imp_first_run.data' every:: 7 using 1,\
newhistogram at 1024,'var_imp_first_run.data' every:: 7 using 2,\
newhistogram at 2048,'var_imp_first_run.data' every:: 7 using 3,\
newhistogram at 3072,'var_imp_first_run.data' every:: 7 using 4;
Then I found out that it was not what I wanted, because the data are arranged as entries,
x1,x2,x3,x4
x5,x6,x7,x8
and so on.
So what I really need is a histogram that plots the rows before columns. Is it possible?
If you want it to read
x1
x2
x3
instead of
x1,x2,x3
Then (assuming you are on *nix) use
plot 'cat var_imp_first_run.data | tr "," "\n" |' using 1
This is calling the following command and reading the output via the pipe at the end:
cat var_imp_first_run.data | tr "," "\n"
Here, tr is just transcribing commas as newlines.