I currently position my key with:
set key outside bottom horizontal
I have 6 items in the key, coming from two plot for... commands (3 each). The size of my plot results in a key that is 2 rows x 3 columns. I'd like to fill my key across rows instead of down columns so that the nth item from each plot command is aligned vertically:
Current:
135
246
Desired:
123
456
I can't find any options for this in help set key. Is this possible without changing my plotting commands?
In the multiplot environment for placing multiple graphs you have the option rowsfirst and columnsfirst (check help multiplot).
Although, for the key entries you have the options vertical and horizontal (check help key). And as you hoped that horizontal would solve your problem, I also would have expected that horizontal together with the option maxcols 3 would do what you're requesting. But it doesn't. Hence, you need a workaround.
You don't specify where you get your key entries from. From the columheader or from some string created with some index? So, in the example below I assumed a key is created from your two loop indices.
Script: (works with gnuplot>=4.6.0, March 2012)
### change order in legend/key
reset
M = 2 # rows
N = 3 # columns
myTitles = ''
set key noautotitle maxrows M
set offsets 0,0,0.5,0
plot for [i=1:3] myTitles=myTitles.sprintf(" Data%d",i) '+' u 1:(cos(i*0.1*$1)) w l lw 2 lc i, \
for [i=4:6] myTitles=myTitles.sprintf(" Data%d",i) '+' u 1:(cos(i*0.1*$1)) w l lw 2 lc i, \
for [i=1:words(myTitles)] c=((i-1)%M*N+1 + (i-1)/M) '+' u 1:(NaN) w l lw 2 lc c ti word(myTitles,c)
### end of script
Result: (created with gnuplot 4.6.0)
Related
I am using feedgnuplot to create a barchart, in order to visually show how teams compare to each other (I'd use the term benchmarking, but that's not a suitable tag here).
What I would like to do is to colour one or more bars to indicate which team I'm working with.
Since pictures explain more, here is an example visually that I am attempting to reproduce:
Here we have several components: Firstly the horizontal line indicating the "group mean", and then four specific teams -- two of which are over-performing, and two of which are under.
Can you help with the red bars please?
Current attempt is produced with:
< ../gnuplot.csv /usr/bin/feedgnuplot --set 'style data histograms' --set 'style fill solid border lt -1' -xticlabels
The gnuplot command this generates is:
set grid
set boxwidth 1
histbin(x) = 1 * floor(0.5 + x/1)
set style data histograms
set style fill solid border lt -1
plot '-' using 3:xticlabels(2) notitle
2 "E" 8
3 "H" 7
4 "B" 6
5 "F" 5
6 "A" 4
7 "D" 3
8 "C" 2
e
From your example I don't see why you would need plotting style histogram. A simple bar chart with conditional color should be sufficient.
simply define a function based on your condition for bar coloring and use variable linecolor (check help lc variable).
if you want to plot the statistical mean value, use stats (check help stats).
the example below has just two columns column 1 text and column 2 numbers. Since you need an x-value for the bars, you take pseudocolumn 0, which is basically the row number with 0-based index (check help pseudocolumns).
Script:
### bar chart with conditional color
reset session
# create some random test data
set table $Data
set samples 26
y0 = 900
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
plot '+' u (alphabet[$0+1:$0+1]):(y0=y0-rand(0)*50) w table
unset table
myColor(col) = (_s=strcol(col), _s eq "C" || _s eq "J" || _s eq "T" || _s eq "X" ? \
0xff3333 : 0x3333ff)
set offset 1,1,0,0
set key noautotitle
set style fill solid 0.5
set yrange[0:1000]
stats $Data u 0:2 nooutput # get the mean value into variable STATS_mean_y
set label 1 at STATS_max_x, STATS_mean_y sprintf("mean=%.1f",STATS_mean_y) offset 0,0.7 right
plot $Data u 0:2:(myColor(1)):xtic(1) w boxes lc rgb var, \
STATS_mean_y w l lw 2 lc "web-green"
### end of script
Result:
I have a datafile with an arbitrary number of datasets, each with an arbitrary number of columns. Every column starts with a header that I would like to use as a title. This is an example datafile, "gp.dat":
a b
2 3
4 9
16 27
c
4
16
64
I would like to generate a plot using gnuplot (gnuplot 5.4 patchlevel 2) that interprets every column in every dataset as an independent line, each labeled with its column header. For the above dataset, this would do the trick:
plot for [d=0:*] for [i=1:2] "gp.dat" index d using i title columnheader with linespoints
Resulting in the following plot:
However, when I try to specify ALL datasets AND ALL columns, the "c" line vanishes:
plot for [d=0:*] for [i=1:*] "gp.dat" index d using i title columnheader with linespoints
This seems to hold for any index I supply for the column number above 2, so this produces the same bad plot:
plot for [d=0:*] for [i=1:3] "gp.dat" index d using i title columnheader with linespoints
How can I specify ALL datasets and ALL columns and guarantee that everything will be plotted?
In the past, I made other strange observations using the * in such "self (de-/non-)terminating loops". I guess gnuplot determines the number of columns from the last block, but is probably not prepared to have variable number of columns.
Here is a somewhat awkward but straightforward procedure to plot all blocks and all columns. This example works as long as your column separator is whitespace.
determine the number of blocks using stats (check help stats)
set the column separator temporarily to "\n", i.e. strcol(1) will be the whole line
extract the number of columns from the first row of each block using words (check help words) and write it to a datablock $ColMax (check help table).
reset the column separator to whitespace again
use the variable number of columns for each block
Maybe there are shorter and smarter solutions.
Script:
### plot all blocks and all columns (variable number of columns in blocks)
reset session
$Data <<EOD
a b
2 3
4 9
16 27
c
4
16
64
d e f
5 6 7
33 44 55
77 88 99
EOD
stats $Data u 0 nooutput
set datafile separator "\n"
set table $ColMax
plot for [b=0:STATS_blocks-1] $Data u (words(strcol(1))) index b every ::::0 w table
unset table
set datafile separator whitespace
set key top center
plot for [b=0:STATS_blocks-1] for [c=1:$ColMax[b+1]] $Data u 0:c index b w lp pt 7 ti columnhead
### end of script
Result:
Addition:
Here is a bit shorter solution which does not use reading from or plotting to a table/datablock (which works only for gnuplot>5.0).
The following should also work for later versions of 4.x if you read the data from a file.
Script:
### plot all blocks and all columns (variable number of columns in blocks)
reset
FILE = 'myFile.dat'
set datafile separator "\n" # or any character which is not in the data
B = 0
Cols = ''
stats FILE u (column(-2)==B ? (B=B+1, Cols=Cols.' '.words(strcol(1))):0) every ::1::1 nooutput
set datafile separator whitespace
set key top center
plot for [b=0:B-1] for [c=1:word(Cols,b+1)] FILE u 0:c index b w lp pt 7 ti columnhead
### end of script
I would like to draw a line with plots that contain "jumping" values.
Here is an example: when we have plots of sin(x) for several cycles and plot it, unrealistic line will appear that go across from right to left (as shown in following figure).
One idea to avoid this might be using with linespoints (link), but I want to draw it without revising the original data file.
Do we have simple and robust solution for this problem?
Assuming that you are plotting a function, that is, for each x value there exists one and only one corresponding y value, the easiest way to achieve what you want is to use the smooth unique option. This smoothing routine will make the data monotonic in x, then plot it. When several y values exist for the same x value, the average will be used.
Example:
Data file:
0.5 0.5
1.0 1.5
1.5 0.5
0.5 0.5
Plotting without smoothing:
set xrange [0:2]
set yrange [0:2]
plot "data" w l
With smoothing:
plot "data" smooth unique
Edit: points are lost if this solution is used, so I suggest to improve my answer.
Here can be applied "conditional plotting". Suppose we have a file like this:
1 2
2 5
3 3
1 2
2 5
3 3
i.e. there is a backline between 3rd and 4th point.
plot "tmp.dat" u 1:2
Find minimum x value:
stats "tmp.dat" u 1:2
prev=STATS_min_x
Or find first x value:
prev=system("awk 'FNR == 1 {print $1}' tmp.dat")
Plot the line if current x value is greater than previous, or don't plot if it's less:
plot "tmp.dat" u ($0==0? prev:($1>prev? $1:1/0), prev=$1):2 w l
OK, it's not impossible, but the following is a ghastly hack. I really advise you add an empty line in your dataset at the breaks.
$dat << EOD
1 1
2 2
3 3
1 5
2 6
3 7
1 8
2 9
3 10
EOD
plot for [i=0:3] $dat us \
($0==0?j=0:j=j,llx=lx,lx=$1,llx>lx?j=j+1:j=j,i==j?$1:NaN):2 w lp notit
This plots your dataset three times (acually four, there is a small error in there. I guess i have to initialise all variables), counts how often the abscissa values "jump", and only plots datapoints if this counter j is equal to the plot counter i.
Check the help on the serial evaluation operator "a, b" and the ternary operator "a?b:c"
If you have data in a repetitive x-range where the corresponding y-values do not change, then #Miguel's smooth unique solution is certainly the easiest.
In a more general case, what if the x-range is repetitive but y-values are changing, e.g. like a noisy sin(x)?
Then compare two consecutive x-values x0 and x1, if x0>x1 then you have a "jump" and make the linecolor fully transparent, i.e. invisible, e.g. 0xff123456 (scheme 0xaarrggbb, check help colorspec). The same "trick" can be used when you want to interrupt a dataline which has a certain forward "jump" (see https://stackoverflow.com/a/72535613/7295599).
Minimal solution:
plot x1=NaN $Data u 1:2:(x0=x1,x1=$1,x0>x1?0xff123456:0x0000ff) w l lc rgb var
Script:
### plot "folded" data without connecting lines
reset session
# create some test data
set table $Data
plot [0:2*pi] for [i=1:4] '+' u 1:(sin(x)+rand(0)*0.5) w table
unset table
set xrange[0:2*pi]
set key noautotitle
set multiplot layout 1,2
plot $Data u 1:2 w l lc "red" ti "data as is"
plot x1=NaN $Data u 1:2:(x0=x1,x1=$1,x0>x1?0xff123456:0x0000ff) \
w l lc rgb var ti "\n\n\"Jumps\" removed\nwithout changing\ninput data"
unset multiplot
### end of script
Result:
I'd like to draw an impulse graph from a text file that looks like this:
II 5 0 0 288.40 1.3033e+14
II 6 0 0 289.60 1.5621e+14
II 1 4 0 302.70 3.0084e+13
II 2 4 0 303.40 4.0230e+13
II 1 5 1 304.40 3.4089e+13
The plot conceptually should be plot "datafile.dat" using 5:6 w impulses ls $2.
Basically, given a previously defined set of line styles, I'd like to input the line style number from column 2 for every couple of plotted points from column 5 and 6.
Also I'd like to create a text box, for every plotted point, taking strings from the first four columns.
Does somebody know if that's possible?
To use the data from column two as line style use set style increment user and linecolor variable:
set style increment user
plot "datafile.dat" using 5:6:2 with impulses lc var
In order to place a label, use the labels plotting style:
plot "datafile.dat" using 5:6:1 with labels offset 0,1
Putting everything together, you have:
set style increment user
set for [i=1:6] style line i lt i
set yrange [0:*]
set offsets 0,0,graph 0.1,0
plot "datafile.dat" using 5:6:2 with impulses lc var, "" using 5:6:1 with labels offset 0,1
The result with 4.6.3 is:
Thanks for the helpful answer above. It almost solved my problem
I'm actually trying to use a column from my data file to specify a linestyle (dot, squares,triangles, whatever as long as it's user-defined), and not a linecolor. Is there any way to do that?
This line works : I get points with different colors (specified in column 4), but the point style is the same.
plot "$file" u 1:2:4 w p notitle lc var, "" using 1:2:3 with labels offset 0,1 notitle
Replacing lc with ls after defining my own styles doesn't work (ls can't have variable as an option)
I can live without different linestyles, but it would be much prettier.
You only have to replace the lineset for [i=1:6] style line i lt i for set for [i=1:6] style line i lt i pt %, Where % can be any type of point you want
I am currently using a script to generate histogram plots, e.g., by doing:
set style histogram cluster gap 4
plot for [COL=2:10] 'example.dat' u COL:xticlabels(1) title columnheader(COL)
Now I wish to add the y-values (numbers) above the bars in the histogram but adding w labels gives the 'Not enough columns for this style' error.
plot for [COL=2:10] 'example.dat' u COL:xticlabels(1) title columnheader(COL), \
for [COL=2:10] 'example.dat' u COL title '' w labels
Is it possible to add y-labels using the histogram style?
Note: I know that there are examples for plotting with boxes. I wish to make this work with the histogram style if possible.
Here's a test datafile I came up with:
example.dat
hi world foo bar baz qux
1 2 3 4 5 6
4 5 7 3 6 5
Here's the script I used to plot it:
set yrange [0:*]
GAPSIZE=4
set style histogram cluster gap 4
STARTCOL=2 #Start plotting data in this column (2 for your example)
ENDCOL=6 #Last column of data to plot (10 for your example)
NCOL=ENDCOL-STARTCOL+1 #Number of columns we're plotting
BOXWIDTH=1./(GAPSIZE+NCOL) #Width of each box.
plot for [COL=STARTCOL:ENDCOL] 'example.dat' u COL:xtic(1) w histogram title columnheader(COL), \
for [COL=STARTCOL:ENDCOL] 'example.dat' u (column(0)-1+BOXWIDTH*(COL-STARTCOL+GAPSIZE/2+1)-0.5):COL:COL notitle w labels
Each cluster of histograms takes a total width of 1 unit on the x axis. We know how many widths we need (the number of boxes +4 since that is the gapsize). We can calculate the width of each box (1/(N+4)). We then plot the histograms as normal. (Note that I added with histogram to the plot command).
According to the builtin help, labels require 3 columns of data (x y label). In this case, the y position and the label are the same and can be read directly from the column COL. The x position of the first block is centered 0 (and has a total width of 1). So, the first block is going to be located at x=-0.5+2*BOXWIDTH. The 2 here is because the gap is 4 boxwidths -- two on the left and 2 on the right. The next block is going to be located at -0.5+3*BOXWIDTH, etc. In general, (as a function of COL) we can write this as
-0.5+BOXSIZE*(COL-STARTCOL+1+GAPSIZE/2)
We need to shift this to the right by 1 unit for each additional block we read. Since each block corresponds to 1 line in the data file, we can use pseudo-column 0 (i.e. column(0) or $0) for this since it gets incremented for each "record/line" gnuplot reads. The 0th record holds the titles, the first record holds the first block. Since we want a function which returns 0 for the first record, we use column(0)-1. Putting it all together, we find that the x-position is:
(column(0)-1-0.5+BOXSIZE*(COL-STARTCOL+1+GAPSIZE/2))
which is equivalent to what I have above.