gnuplot automatic stack bar graph - gnuplot

Here is my data set:
type size name
label_0 1 nameOfData_0
label_0 2 nameOfData_1
label_0 3 nameOfData_2
label_1 2 nameOfData_3
label_2 1 nameOfData_4
label_0 2 nameOfData_5
label_1 3 nameOfData_6
label_3 2 nameOfData_7
label_3 1 nameOfData_8
I would like the plot to looks like:
I would like each label to be a stack and each nameOfData_X to fit in the correct stack according to its size. If possible add also the legend for each element of the stack.
I know I could reformat the data to process it easily via gnuplot but I don't want to.
Any ideas on how I could display this graph via gnuplot?
Thanks for your help!

Maybe there is a way to achieve this with the gnuplot built-in stacked histogram style, check help histograms.
The following solution is not too obvious but seems to give the desired result and uses the plotting style with boxxyerror (check help boxxyerror).
you need a list of unique elements of column 1. Here it will be in the order of the first occurrences.
during plotting in loops you add your contributions depending on a "filter" function myAdd().
you change the color when the addition is zero (dy=0).
you add labels in a similar way with an offset
This code can probably be simplified but may act as a starting point.
Code:
### "manual" stacked histogram
reset session
$Data <<EOD
type size name
label_0 1 nameOfData_0
label_0 2 nameOfData_1
label_0 3 nameOfData_2
label_1 2 nameOfData_3
label_2 1 nameOfData_4
label_0 2 nameOfData_5
label_1 3 nameOfData_6
label_3 2 nameOfData_7
label_3 1 nameOfData_8
EOD
# get a unique list from datablock column 1
set table $Dummy
Headers = 1
addToList(list,col) = list.( strstrt(list,'"'.strcol(col).'"') > 0 ? '' : \
' "'.strcol(col).'"')
plot Uniques='' $Data u (Uniques=addToList(Uniques,1),'') skip Headers w table
unset table
N = words(Uniques)
Unique(i) = word(Uniques,i)
set xrange [1:N]
set xtics out noenhanced
set grid x,y
set offsets 0.5,0.5,0.5,0
unset key
set style fill transparent solid 0.7 border
myBoxWidth = 0.8
myAdd(colD,colF,i) = strcol(colF) eq Unique(i) ? column(colD) : 0
myLabel(col1,col2) = dy==0 ? '' : sprintf("%s\n%g",strcol(col1),column(col2))
plot for [i=1:N] y=y0=(c=1,0) $Data u (i):(dy=myAdd(2,1,i), y=y+dy,(y0+y)/2.): \
(myBoxWidth/2.):(y0=y,dy/2.):(dy==0?c:c=c+1) skip Headers w boxxy lc variable, \
for [i=1:N] y=y0=0 $Data u (i):(dy=myAdd(2,1,i), y=y+dy,(y0+y)/2.): \
(y0=y,myLabel(3,2)):xtic(Unique(i)) skip Headers w labels offset 0,0.5 noenhanced
### end of code
Result:

Related

gnuplot: Colour-coding specific / individual histogram bars

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:

Is there any way to visualize the field on adaptive mesh with gnuplot?

I am a beginner in gnuplot. Recently I tried to visualize a pressure field on adaptive mesh.
Firstly I got the coordinates of nodes and center of the cell and the pressure value at the center of the cell.
And, I found something difficult to deal with. That is the coordinates in x and y directions are not regular, which made me feel hard in preparing the format of source data. For regular and equal rectangular case, I can do something just like x-y-z format. But is there any successful case in adaptive mesh?
I understand that you have some x,y,z data which is in no regular grid (well, your adaptive mesh).
I'm not fully sure whether this is what you are looking for, but
gnuplot can grid the data for you, i.e. inter-/extrapolating your data within a regular grid and then plot it.
Check help dgrid3d.
Code:
### grid data
reset session
# create some test data
set print $Data
do for [i=1:200] {
x = rand(0)*100-50
y = rand(0)*100-50
z = sin(x/15)*sin(y/15)
print sprintf("%g %g %g",x,y,z)
}
set print
set view equal xyz
set view map
set multiplot layout 1,2
set title "Original data with no regular grid"
unset dgrid3d
splot $Data u 1:2:3 w p pt 7 lc palette notitle
set title "Gridded data"
set dgrid3d 100,100 qnorm 2
splot $Data u 1:2:3 w pm3d
unset multiplot
### end of code
Result:
If you have the size of each cell, you can use the "boxxyerror" plotting style. Let xdelta and ydelta be half the size of a cell along the x-axis and y-axis.
Script:
$datablock <<EOD
# x y xdelta ydelta pressure
1 1 1 1 0
3 1 1 1 1
1 3 1 1 1
3 3 1 1 3
2 6 2 2 4
6 2 2 2 4
6 6 2 2 5
4 12 4 4 6
12 4 4 4 6
12 12 4 4 7
EOD
set xrange [-2:18]
set yrange [-2:18]
set palette maxcolors 14
set style fill solid 1 border lc black
plot $datablock using 1:2:3:4:5 with boxxyerror fc palette title "mesh", \
$datablock using 1:2 with points pt 7 lc rgb "gray30" title "point"
pause -1
In this script, 5-column data (x, y, xdelta, ydelta, pressure) is given for "boxxyerror" plot. To colorize the cells, the option "fc palette" is required.
Result:
I hope this figure is what you are looking for.
Thanks.

GNUplot: how to plot rowstacked bar chart using color codes in data?

I have the following sample data:
col1 2 0 1 1
col2 1 1 0 0
col3 1 1 1 0
col4 1 1 2 1
col5 1 1 1 1
col6 2 0 1 1
col7 1 1 2 2
col8 1 1 2 1
columns #4 and #5 are the color codes for columns #2 and #3. For example, I want '1' for green, 2 for white, and 0 for orange.
Here is how I tried to plot it:
set key off
unset border
unset xtics
unset ytics
set style data histograms
set style histogram rowstacked
set boxwidth 1 relative
set style fill solid 1.0 border -1
set yrange [0:2]
set lmargin 0
set rmargin 0
set tmargin 0
set bmargin 0.1
set terminal pngcairo truecolor size 100,65
set output "/export/test.png"
set palette model RGB defined ( 0 'orange', 1 'green', 2 'white')
plot 'test.data' u 2 linecolor rgb "orange", '' u 3 linecolor rgb "green"
Here is what I got without being able to implement the color according to the actual data:
Sample Image
So how do I use the actual colors as specified in my data file?
[in case anybody wonders and in case the rational behind this encourages your efforts;-): I am trying to draw an HP blade c7000 chassis, using color coding to show empty chassis slots, slots with blades that are powered on and off. The actual values in column #2 and #3 indicate whether the blade is full-height (with value of 2) or half-height blades (with a value of 1). Where there is no blade, it still gets a value of 1, defaulting to half-height.]
## Update
With this, I was able to get what I need...Anybody has a shorter version?
plot 'test.data' u ($5==0?$2:sqrt(-1)) linecolor rgb "orange",\
'' u ($5==1?$2:sqrt(-1)) linecolor rgb "green",\
'' u ($5==2?$2:sqrt(-1)) linecolor rgb "white",\
'' u ($4==0?$3:sqrt(-1)) linecolor rgb "orange",\
'' u ($4==1?$3:sqrt(-1)) linecolor rgb "green",\
'' u ($4==2?$3:sqrt(-1)) linecolor rgb "white"
new sample image
Further refinement
How do I add numbering to the blocks as the following image shows:
Updated Question:
I noticed that sometimes the color pallete gets the color wrong, unless all colors defined in the pallete are present in the data. For example, with the following data:
1 2 0 1 1
2 1 1 0 0
3 2 0 1 1
4 2 0 1 1
5 1 1 1 1
6 1 1 1 0
7 1 1 1 1
8 1 1 1 1
As you can see from col#4-5, I have only 'green' (1) and 'organge' (0). As I don't have any slot empty, I don't have 'white' color. I get this image:
This image obviously is incorrect, as white would indicate that I have an empty slot. I expected this image:
So how did the colors 'white' and 'green' get flipped? I noticed if I change any one of those color code to white, then the color pallete will work correctly.
I would use the boxxyerrorbars plotting style. Despite the name, this is what you should use, when you want to plot "different" boxes.
set key off
unset border
unset xtics
unset ytics
unset colorbox
set style fill solid 1.0 border -1
set palette model RGB defined ( 0 'orange', 1 'green', 2 'white')
set cbrange [0:2]
set style data boxxyerrorbars
plot 'test.data' u 0:(0.5*$2):(0.5):(0.5*$2):4 lc palette,\
'' u 0:($2 + 0.5*$3):(0.5):(0.5*$3):5 lc palette
The boxxyerrorbars plotting style itself takes four columns, x, y, dx, and dy, and the lc palette uses the values in a fifth column to determine the color based on the current palette. To make the values in the palette absolute values I additionally set the cbrange to the same range which is covered by the palette.
The expression using 0:(0.5*$2):(0.5):(0.5*$2):4 means:
Use the zeroth column (the row number) as x-value (box center)
the value in the second column multiplied by 0.5 as y-value (box center)
the number 0.5 as dx (half of the box width)
the value in the second column multiplied by 0.5 as dy-value (half of the box height)
For the second plot part the y-value is the value in the second column plus half of the value in the third column.
This solution can also easily be written to allow increasing the number of stacked boxes:
set palette model RGB defined ( 0 'orange', 1 'green', 2 'white')
set cbrange [0:2]
set style data boxxyerrorbars
last_column = 3
plot for [i=2:last_column] 'test.data' \
u 0:(0.5*column(i) + sum[c=2:(i-1)] column(c)):(0.5):(0.5*column(i)):(column(last_column + i - 1)) lc palette
The colors are used to identify the corresponding parts in different stacks. Therefore they must follow the same order in all stacks which belong to the same histogram.
But Gnuplot has a newhistogram command after which the colors can be "reset". And there is the multiplot command which can be used to add new histograms in a loop.
Here is the part of the script which replaces the original plot command:
set style line 1 lt 1 lc rgb "white"
set style line 2 lt 1 lc rgb "green"
set style line 3 lt 1 lc rgb "orange"
stats 'test.data' u 2
n = STATS_records
set multiplot
do for [i=0:n-1] {
plot "test.data" u (0) ,\
newhistogram "" at i, "" every ::i::i u (style = $5 + 1, 0), \
"" every ::i::i u 2 ls style, \
"" every ::i::i u (style = $4 + 1, 0), \
"" every ::i::i u 3 ls style
}
unset multiplot
And this is how it works:
set style ...: Define the styles (colors) which will be used.
stats ...: Find the number of rows. We are going to plot an independent histogram for each row.
set multiplot: We will plot again and again on the same area.
"test.data" u (0): Plot nothing, but reserve space for all histograms.
new histogram "" at i: Initialize a new histogram without a name with offset i on the x axis. We are going to plot a single stack at this offset.
"" every ::i::i: Plot row i.
u (style = $5 + 1, 0): Plot nothing, but read the color of the current row from file.
u 2 ls style: Plot column 2 of the current row with the previously read style.
I'm not sure whether this version is shorter than yours :)

Gnuplot columnstacked histogram with errorbars

Suppose I have the following data file, so-qn.dat:
Type on on-err off off-err
good 75 5 55 4
bad 15 2 30 3
#other 10 1 15 2
which contains values on columns 2 and 4 and corresponding error deltas on columns 3 and 5.
I can produce a columnstacked histogram:
#!/usr/bin/gnuplot
set terminal png
set output 'so-qn.png'
set linetype 1 lc rgb "blue" lw 2 pt 0
set linetype 2 lc rgb "dark-red" lw 2 pt 0
set style data histograms
set style histogram columnstacked
set style fill solid
set ylabel "% of all items"
set yrange [0:100]
set boxwidth 0.75
set xtics scale 0
set xlabel "Option"
plot 'so-qn.dat' using 2 ti col, \
'' using 4:key(1) ti col
But I can’t figure out how to add errorbars to this. The closest I got so far is with
plot 'so-qn.dat' using 2 ti col, '' using 2:3 with yerrorbars lc rgb 'black' ti col, \
'' using 4:key(1) ti col, '' using 4:5:key(1) with yerrorbars lc rgb 'black' ti col
which produces
but only one of the error bars is in the right spot (I actually have no idea where the bottom left one gets its y from), one is completely invisible (hidden behind the right stack?), and I’d like the error bars to not show up in the key.
Is it possible to combine column-stacked histograms and error bars?
You can add errorbars to column-stacked histograms by manually adding plot-commands for the errorbars. To do so, you need, however, to keep track of the y-positions.
Therefore, let's introduce two variables which store the y-position for each of the two columns' errorbars.
y1 = -2
y2 = -4
You need to initialize these variables with -(number of column)
Next, let us define two functions that update the variables y1, y2.
f1(x) = (y1 = y1+x)
f2(x) = (y2 = y2+x)
Now, generate the desired plot via
plot 'so-qn.dat' using 2 ti col, \
'' using 4:key(1) ti col, \
'' using (0):(f1($2)):3 w yerr t "", \
'' using (1):(f2($4)):5 w yerr t ""
As you can see, you can supress the errorbars in the key by assigning an empty title (t ""). This approach even gives you more flexibility in customizing the appearance of the errorbars (e.g., assign different linestyles etc.).
This being said, I personally think this visualization is rather confusing. You might want to consider another visualization:
set bars fullwidth 0
set style data histograms
set style fill solid 1 border lt -1
set style histogram errorbars gap 2 lw 2
plot 'so-qn.dat' using 2:3:xtic(1) ti columnhead(2), \
'' using 4:5:xtic(1) ti columnhead(4)

Custom legend (or text) gnuplot

I have a file with 3 columns, the first 2 are the position x y and the 3rd one I use it for define the color so I have something like this:
set palette model RGB defined ( 1 'black', 2 'blue', 3 'green', 4 'red')
unset colorbox
plot "file" u 2:1:3 w points pt 14 ps 2 palette, "file2" u 2:1:3 w points pt 14 ps 2 palette
Now the question: Is it possible to have a proper legend with this kind of point and COLOR?.
Since the points will have different colors (according to the pallete) I want to specify what means each color in the legend.
The only solution I was thinking was to write somewhere in the plot some text with the character of the point (in this case pt 14) and specify the color... but is not really a solution right?
So please help!
There is no option for this, you need to fiddle a bit. Here is YAGH (Yet another gnuplot hack) ;)
Assuming that your values are equidistantly spaced, you can use the '+' special filename with the labels plotting style.
To show only the custom key, consider the following example:
labels="first second third fourth"
set xrange[0:1] # must be set for '+'
set yrange[0:1]
set samples words(labels) # number of colors to use
key_x = 0.8 # x-value of the points, must be given in units of the x-axis
key_y = 0.8
key_dy = 0.05
set palette model RGB defined ( 1 'black', 2 'blue', 3 'green', 4 'red')
unset colorbox
plot '+' using (key_x):(key_y + $0*key_dy):(word(labels, int($0+1))):0 \
with labels left offset 1,-0.1 point pt 7 palette t ''
This gives (with 4.6.4):
As the set samples doesn't affect the data plots, you can integrate this directly in your plot command:
...
unset key
plot "file" u 2:1:3 w points pt 14 ps 2 palette, \
"file2" u 2:1:3 w points pt 14 ps 2 palette, \
'+' using (key_x):(key_y - $0*key_dy):(word(labels, int($0+1))):0 \
with labels left offset 1,-0.1 point pt 14 ps 2 palette
But you need to set a proper xrange, yrange and the values of key_x, key_y and key_dy.
This is not the most intuitive way, but it works :)
I have an alternative solution posted here:
Using Gnuplot to plot point colors conditionally
Essentially you plot once without a legend entry, then make dummy plots (with no data) for each point color/label.

Resources