I have a gnuplot script that produces bar graphs like this:
The input data is in files that have a number of columns, each column ultimately contributes to a cluster in the chart (2 clusters shown in the example). Each file contributes to a bar in the chart (there are 9 in the example). Each file may have a large number of rows.
The script takes the input data files and, using the stats command, produces new files containing one row per column of the original files. Each row contains a mean, min and max value for its source column.
These new files are then used to plot the bar chart with error bars. Each file represents one bar and each row contributes to one cluster. The plot code is as follows:
plot for [f in FILES] f.'.stats' using 2:3:4 title columnhead(1), \
'' using (0):xticlabels(1) with lines
Now I have a second set of files and that produce another similar bar chart. I would like to combine these charts onto one so there will be two rows of 3-D bars, one in front of the other (rendered with a 3-D style - the new 'z' axis representing the two data sets (two sets of FILES).
Here is an example to illustrate the look I'm after (obviously not made with gnuplot!):
Can I do this with Gunplot?
I have read the user manual and the Gnuplot In Action book but haven't found anything that would indicate this is possible.
gnuplot version 5.3 (the development branch) adds a 3D barchart variant
3D boxes demo. However rendering the boxes in 3D unfortunately depends on features that were not present in earlier gnuplot release versions so I cannot offer a work-around for the current one (5.2.4). Also the new 3D variant does not show error bars, although I think one could construct a plot command that would add them.
I produced a 3D bar chart using the development 5.3 version (git checkout). Here is my splot command:
splot for [c = 1:ncats] for [f = 1:nfiles] \
word(cat_files[c],f).'.stats' \
using (f+column(0)*(nfiles+2)):(scale_y(c)):2 \
with boxes \
title (c==1 ? columnhead(1) : '')
The input data is in a set of 'stats' files as described in the question. To draw the plot, I separated the input FILES into categories - two (ncats) sets of files held in the array cat_files, each containing the same number of files (nfiles).
The categores equate to positions on the y-axis (rows) and the individual files equate to positions on the x-axis (bars). Rows in each file equate to clusters of bars and the values in each row is the bar height which is the Z axis. The Z axis was the Y axis in the 2D model. The nasty expressions are to position the bars on the x and y axes as I explain below.
I had a lot of difficulty getting this to work but I think that the result looks good:
The problems, which I cover below are:
matching colours between chart 'rows' of the y-axis
bar dimensions - making square bars is very hit-and-miss, hence my scale_y function.
x-axis label orientation
repeated items in the key, hence conditional expression for title.
no clustering support, hence nasty positioning expressions
What I have is brittle---it works on my Linux system but relies heavily on shell helpers. But it works. Hopefully this information helps others or can be taken as feedback to improve gnuplot to make it even more awesome!
Colours
To get the colours in each data set to line up, I set linetype cycle nfiles and hope gnuplot defines sufficient colours.
The reason for doing this is to reset the colour assignment between file sets (categories on the y-axis) so that the same bar in different file sets had the same colour. By explictly setting it to cycle after the known number of files (chart bars) I ensured the colours matched.
Bar dimensions
The bar dimensions (boxwidth and boxdepth) are relative to the axis ranges and it's therefore difficult to make them square.
If a bar rests on the extreme of the y axis (lower or upper) then it is cut in half vertically (it's visible box depth is half the defined boxdepth value).
I had to play with scaling the y axis so that my two category sets were displayed near each other. The default behaviour displayed a range from 1 to 2 in steps of 0.2 and placed the two plots at 1 and 2, making them appear far apart.
I tried set ytics to no effect. I ended up scaling the y value.
scale(y) = 0.1 * y - 0.05
set yrange [0:1]
set boxdepth (0.8 / clusters)
all the numbers are fudge factors. clusters is the number of clusters (rows in files). The numbers I have maintain a square appearance with my test data (I have data to display up to 5 clusters).
I had to start the x axis at 0.5 otherwise the first bar would appear too far in (if x starts at 0) or vertically half-cut off (if x starts at 1).
set xrange [0.5:*]
Axis labels
I replaced the automatic tick marks with custom labels. On the Y axis:
set ytics ()
set for [c = 1:ncats] ytics add (word(CATS,c) scale_y(c) )
Similarly for the x axis. First, where there is 1 cluster I label each category
set xtics ()
set for [f = 1:nfiles] xtics add (label(word(cat_files[1],f)) f)
Or where there are multiple clusters, I label the clusters:
set xtics ()
set set for [c = 2:(clusters+1)] xtics add (cell(f,c,1) (nfiles/2)+2+((c-2)*nfiles))
Here, cell is a shell helper that returns the value from file f at row c position 1. The horrible formula is a hack to position the label along the axis in the middle of the cluster. I also use shell helpers to get the number of clusters. I could not find a way in gnuplot to query rows and columns. Note that previously (when 2D plotting) I would have used xticlabels(1) to plot the clusered x-axis.
I wanted to turn the x labels to run perpendicular to the axis but this doesn't seem possible. I also wanted to tweak their positions with 'right' alignment but couldn't make that work either.
Key labels
An entry is added into the key for each bar plotted. Because these are repeated within each category they get duplicted in the key. I made it only add them once by using a conditional, changing from
title columnhead(1)
to
title (c==1 ? columnhead(1) : '')
I only show the key when there is more than one cluster.
Clustering
The 2D plot was clustered. I had difficulty making a clustered appearance in 3D. If I run the plot on clustered data then they overlay (they have the same Y values). To overcome this I used a formula to shift latter clusters along the x-axis and add a gap between them. So instead of a simple value for x:
... using (f):(scale_y(c)):2 ...
I have a formula:
... using (f+column(0)*(nfiles+2)):(scale_y(c)):2 ...
where f is the file number (eq. the bar number), column(0) is the cluster number, nfiles is the number of files (eq. the numer of bars, or cluster size), and 2 is the separator gap.
Incidentally, whilst doing this I discovered that ($0) doesn't work in gnuplot 5.3, you have to use column(0) instead ($0 works in 5.2.4).
I used the Arch Linux AUR package to build which gave me a package gnuplot-git-5.3r20180810.10527-1-x86_64.pkg.tar.xz.
An example plot with one cluster.
An example plot with three clusters and a key legend.
There are probably better ways to do the things I've done here. Being relatively new to gnuplot, I would be interested in any ways to improve upon this solution.
(I can't figure out how to format text in a comment, so I'll provide this as a separate answer)
Matching color: This is more reliably done by providing the color in a separate field of the using spec. From the help text:
splot with boxes requires at least 3 columns of input data. Additional
input columns may be used to provide information such as box width or
fill color.
3 columns: x y z
4 columns: x y z [x_width or color]
5 columns: x y z x_width color
The last column is used as a color only if the splot command specifies a
variable color mode. Examples
splot 'blue_boxes.dat' using 1:2:3 fc "blue"
splot 'rgb_boxes.dat' using 1:2:3:4 fc rgb variable
splot 'category_boxes.dat' using 1:2:3:4:5 lc variable
In the first example all boxes are blue and have the width previously set
by set boxwidth. In the second example the box width is still taken from
set boxwidth because the 4th column is interpreted as a 24-bit RGB color.
The third example command reads box width from column 4 and interprets the
value in column 5 as an integer linetype from which the color is derived.
Half-depth boxes at each end: This was an autoscaling bug (now fixed)
Related
Im trying to draw a simple gnuplot bar chart. With labels on top of each bar.
this is my test.out
279 2 10149
286 1 699999
295 3 14098
and this is my command:
echo "set terminal dumb size 70,30; plot 'test.out' using 3:xtic(1) with boxes" | gnuplot
It draws a boxes. I want also labels on top of each.
Please help )
You must plot the data again with labels.
To get the correct x-positions, you must know that in your plot command plot 'test.out' using 3:xtic(1) with boxes the x-position is implicitely taken as the row number.
Also, when plotting with labels it is best to explicitely format the label string. Using only a column may or may not work and can give quite surprising results, depending on your data.
So, to be short:
plot 'test.out' using 0:3:xtic(1) with boxes,\
'' using 0:3:(strcol(3)) with labels offset 0,1
This plots the string content of column 3 as label at position (rownumber, value from column 3), shifted by 1 character height in y-direction.
I have few simple bar charts here. I find it kind of difficult to read out the exact value or even the approximate value of each bar. So it would be nice to have the exact number written into or above the bar, as shown in the attached image:
Any ideas on how to do this?
OK, so I have created a file so.dat with mock data, namely
1 1
2 1.25
3 4.5
4 7
If you now use the command
plot [0:5][0:8] "so.dat" using 1:2 with boxes, "" u 1:(2):2 w labels
you get
The instruction "" u 1:(2):2 w labels tells gnuplot
to use the same input file,
to create labels,
to put them on a location on the x axis that is determined by the first data column in that file,
to place them at a level of 2 on the y axis,
and to read the data for the labels from the second column in the data file.
You could also put the labels relative to the box height - try u 1:($2-.5):2.
This should get you started. Color and direction of the labels, style of the boxes, axis labels, legend etc. can be customised as much as you like, but we would need a bit more information here - hence the barebone reply.
How can I plot (many) uncorrelated points from a data file in 3D with color corresponding to the value of one column? The color-value is non-integral.
======================================================================
details:
I have a large data file with three columns of the form
longitude latitude color
The data is scattered and uncorrelated, i.e. no underlying grid and no relationship between the points (except that every coordinate appears only once). color is an arbitrary scalar. I know the min and the max value of that, and would like to have linear scaling of the color in between. Which colormap is not clear atm, a first step would be to produce any meaningful output.
How can I plot dots on the longitude-latitude coordinates on the unit sphere (i.e. radius = 1) with the specified color?
No interpolation is wanted, not even a connection between the points. (I'm also happy for suggestions how to do that in an easy way, but it's actually not important)
This is how far I've gone, but the coloring is missing:
set mapping spherical
splot 'the_file.data' u 1:2:(1)
Thanks a bunch!
You can use linecolor palette, which allows you to specify an additional column which is used to select the respective color from the current palette:
set mapping spherical
splot 'the_file.data' using 1:2:(1):3 linecolor palette
I have a plot with exponential y axis range. I'm using multiplot command by inserting two images in one row. So due to this wide y axis range I'm loosing some space which I could use it to show my plots in a better way. I want basically something like this
How could i do this? I think for doing this I have do some math operations in the y axis range. Also what is the most convenient command to insert ( xE-10) at top left of the plot.
reset
set terminal epslatex size 16cm,18cm color colortext
set output new.tex
set key off
set format $%g$
set title "sinx"
set ylabel "[kNm]"
plot 1000000*sin(x)
This is not my exact code but it looks similar to this. The plot I have presented is a part of the multiplot code and I use 7 input files with time series data of 300 seconds at a time step of 0.02. The point I want to edit the y axis range (use some mathtematical expressions) and also include the term ( xE-10 ) on the top of the plot something like this
You can manually add the exponent with a set label .... For instance, the following function takes large values within the given interval:
plot[0:50] exp(x)
We can place the "x 10^21" manually in the desired place after dividing the plotted quantity by it:
set label 1 "{/Symbol \264} 10^{21}" at graph 0,1.025 left
plot[0:50] exp(x)/1e21
You have to be careful with the exact placement of the exponent since it might lie outside the plotting area, in which case you should lower the top margin with set tmargin .... Also, to use the "times" symbol, you need to pass the enhanced option to your terminal. With the epslatex terminal, you can use latex syntax: $\times 10^{21}$.
I need to draw dots and empty dots in a plot to show the fixed points. They should look like in the figure below: an empty dot (a circle) and a thick dot.
Is there any way to plot something like that?
Thanks
(source: emathematics.net)
If you wish to use the built in point types, there are usually (depending on the terminal) a filled circle and an empty circle. Issuing the test command will show you what is available. For instance, with the wxt terminal, I see
which shows me that I can get a filled circle with point type 7 and an empty one with point type 6 (we don't worry about the different colors as those are inherited from the line type).
Now, the easy way to get our desired plot is to just issue plot datafile with points pt 6 or point type 7. It is trickier if you need it to depend on your data.
Suppose that my data looks like this:
1 3 0
5 8 1
2 6 0
3 2 1
The first two columns are the x and y coordinates and the third tells me if I should use an empty dot (0) or a filled dot (1). Unfortunately, gnuplot does not support a variable point type command (something like plot datafile u 1:2:($3+6) with linespoints pt var), which is exactly what we need here.
In order to plot our data, we will make two passes. The first will plot the lines and the empty circles (for all points), and the second will plot the filled circles (for only the points that should be filled - overwriting the empty circles).
plot datafile u 1:2 with linespoints pt 6, \
datafile u 1:($3==1?$2:1/0) with points pt 7 lt 1
This command will plot the lines and the empty circles first. Next it plots the filled circles only when they are needed. To do this, it computes a conditional y-coordinate. If the third column is 1, it uses the second column as the y-coordinate. If not, it uses the invalid value 1/0, which causes gnuplot to skip the point. In order to keep the colors and everything else the same, we use lt 1 (which was used by default in the first plot command segment).
Note: I have put in a feature request for a pointtype variable option, and it looks like it may work its way into a future version. A preliminary patch is available implementing this under feature request 437.
Updated Note: The pointtype variable option is currently availabe in the development version of gnuplot.