This is a minimal working example of the code I'm using:
#!/bin/bash
gnuplot << EOF
set term postscript portrait color enhanced
set encoding iso_8859_1
set output 'temp.ps'
set grid noxtics noytics noztics front
set size ratio 1
set multiplot
set lmargin 9; set bmargin 3; set rmargin 2; set tmargin 1
n=32 #number of intervals
max=13. #max value
min=-3.0 #min value
width=(max-min)/n #interval width
hist(x,width)=width*floor(x/width)+width/2.0
set boxwidth width
set style fill solid 0.25 noborder
plot "< awk '{if (3.544068>=\$1) {print \$0}}' /data_file" u (hist(\$2,width)):(1.0) smooth freq w boxes lc rgb "red" lt 1 lw 1.5 notitle
EOF
which gets me this:
What I need is to use histeps instead, but when I change boxes for histeps in the plotcommand above, I get:
What is going on here??
Here's the data_file. Thank you!
EDIT: If having histeps follow the actual outer bars limits instead of interpolating values in between (like boxesdoes) is not possible, then how could I draw just the outline of a histogram made with boxes?
EDIT2: As usual mgilson, your answer is beyond useful. One minor glitch though, this is the output I'm getting which when I combine both plots with the command:
plot "< awk '{if (3.544068>=\$1) {print \$0}}' data_file" u (hist(\$2,width)):(1.0) smooth freq w boxes lc rgb "red" lt 1 lw 1.5 notitle, \
"<python pyscript.py data_file" u 1:2 w histeps lc rgb "red" lt 1 lw 1.5 notitle
Something appears to be shifting the output of the python script and I can't figure out what it might be.
(Fixed in comments)
The binning is quite easy if you have python + numpy. It's a very popular package, so you should be able to find it in your distribution's repository if you're on Linux.
#Call this script as:
#python this_script_name.py 3.14159 data_file.dat
import numpy as np
import sys
n=32 #number of intervals
dmax=13. #max value
dmin=-3.0 #min value
#primitive commandline parsing
limit = float(sys.argv[1]) #first argument is the limit
datafile = sys.argv[2] #second argument is the datafile to read
data = [] #empty list
with open(datafile) as f: #Open first commandline arguement for reading.
for line in f: #iterate through file returning 1 line at a time
line = line.strip() #remove whitespace at start/end of line
if line.startswith('#'): #ignore comment lines.
continue
c1,c2 = [float(x) for x in line.split()] #convert line into 2 floats and unpack
if limit >= c1: #Check to make sure first one is bigger than your 3.544...
data.append(c2) #If c1 is big enough, then c2 is part of the data
counts, edges = np.histogram(data, #data to bin
bins=n, #number of bins
range=(dmin,dmax), #bin range
normed=False #numpy2.0 -- use `density` instead
)
centers = (edges[1:] + edges[:-1])/2. #average the bin edges to the center.
for center,count in zip(centers,counts): #iterate through centers and counts at same time
print center,count #write 'em out for gnuplot to read.
and the gnuplot script looks like:
set term postscript portrait color enhanced
set output 'temp.ps'
set grid noxtics noytics noztics front
set size ratio 1
set multiplot
set lmargin 9
set bmargin 3
set rmargin 2
set tmargin 1
set style fill solid 0.25 noborder
plot "<python pyscript.py 3.445 data_file" u 1:2 w histeps lc rgb "red" lt 1 lw 1.5 notitle
I'll explain more when I get a little more free time ...
Related
I usually code in Python and do not know any GNUplot but I have to use a small bit of C to plot human cells represented as polygons. I have a file with all the coordinates of the polygon vertices at each time (it is a dynamic simulation), what the code does (and I don't know how) is that it links each cell vertex to form a cell edge and so we can see the different cells. Here is the code used to plot my polygons, the code I was given.
start = 0000
stop = 49990
set terminal pngcairo rounded size 800,800
set style line 1 lt 3 lc rgb pt 7 lw 2
set xrange [0:d*sqrt(N)]
set yrange [0:h*sqrt(N)]
point_files(n) = sprintf('./PointFiles/points%06d.txt', n)
cell_files(n) = sprintf('./CellpopFiles/cells%06d.txt', n)
do for [i = start:stop:10] {
outfile = sprintf('./Figures/figures%06d.png',i)
set output outfile
unset key
plot cell_files(i) w filledcurves ls 1
}
So far the code works but then, I want to separate my cell population in 2 and color the two populations in 2 different colors, that's what I haven't managed. Only one of my cells are colored and even then the cell edges are not shown - I have white (instead of green) and red surfaces moving around but I can't see the limit between each cell, there is no edge.
start = 0000
stop = 49990
set terminal pngcairo rounded size 800,800
set style line 1 lt 3 lc rgb 'red' pt 7 lw 2
set style line 2 lt 3 lc rgb 'green' pt 7 lw 2
set xrange [0:d*sqrt(N)]
set yrange [0:h*sqrt(N)]
point_files(n) = sprintf('./PointFiles/points%06d.txt', n)
cell_files0(n) = sprintf('./Cellpop0Files/cells%06d.txt', n)
cell_files1(n) = sprintf('./Cellpop1Files/cells%06d.txt', n)
do for [i = start:stop:10] {
outfile = sprintf('./Figures/figures%06d.png',i)
set output outfile
unset key
plot cell_files0(i) w filledcurves ls 1
plot cell_files1(i) w filledcurves ls 2
}
Using 'w filledcurves closed ls 1' does not change anything.
The solution might be pretty simple but without knowing any C I've been struggling, thank you in advance!
Plotting multiple files into the same plot can be done by separating the plotting elements via comma. Check help plot.
Syntax:
plot {<ranges>} <plot-element> {, <plot-element>, <plot-element>}
In order to increase the readability of the script and lengthy plot commands, you can introduce "linebreaks" with \ being the very last character in the line (couldn't find the help keyword anymore for this, but I know it is somewhere hidden in help).
Have you tried:
plot cell_files0(i) w filledcurves ls 1, \
cell_files1(i) w filledcurves ls 2
Thanks for the help, in case someone has the same problem as I, here is the code once it works:
N = 100
d = sqrt(2/sqrt(3))
h = sqrt(3)*d/2
start = 0000
stop = 1990
set terminal pngcairo rounded size 800,800
set xrange [0:d*sqrt(N)]
set yrange [0:h*sqrt(N)]
point_files(n) = sprintf('./PointFiles/points%06d.txt', n)
cell_files0(n) = sprintf('./Cellpop0Files/cells%06d.txt', n)
cell_files1(n) = sprintf('./Cellpop1Files/cells%06d.txt', n)
do for [i = start:stop:10] {
outfile = sprintf('./Figures/figures%06d.png',i)
set output outfile
set border
unset key
plot cell_files0(i) with filledcurves fc "royalblue" fs solid 0.5 border lc "black", \
cell_files1(i) with filledcurves fc "yellow" fs solid 0.5 border lc "black"
}
Is it possible in Gnuplot to emulate the drawing style of an analogue oscilloscope, meaning thinner+dimmisher lines on larger amplitudes, like this:?
The effect you see in the oscilloscope trace is not due to amplitude, it is due to the rate of change as the trace is drawn. If you know that rate of change and can feed it to gnuplot as a third column of values, then you could use it to modulate the line color as it is drawn:
plot 'data' using 1:2:3 with lines linecolor palette z
I don't know what color palette would work best for your purpose, but here is an approximation using a function with an obvious, known, derivative.
set palette gray
set samples 1000
plot '+' using ($1):(sin($1)):(abs(cos($1))) with lines linecolor palette
For thickness variations, you could shift the curve slightly up and down, and fill the area between them.
f(x) = sin(2*x) * sin(30*x)
dy = 0.02
plot '+' u 1:(f(x)+dy):(f(x)-dy) w filledcurves ls 1 notitle
This does not allow variable colour, but the visual effect is similar.
Another approach:
As #Ethan already stated, the intensity is somehow proportional to the speed of movement, i.e. the derivative. If you have sin(x) as waveform, the derivative is cos(x). But what if you have given data? Then you have to calculate the derivative numerically.
Furthermore, depending on the background the line should fade from white (minimal derivative) to fully transparent (maximum derivative), i.e. you should change the transparency with the derivative.
Code:
### oscilloscope "imitation"
reset session
set term wxt size 500,400 butt # option butt, otherwise you will get overlap points
set size ratio 4./5
set samples 1000
set xrange[-5:5]
# create some test data
f(x) = 1.5*sin(15*x)*(cos(1.4*x)+1.5)
set table $Data
plot '+' u 1:(f($1)) w table
unset table
set xtics axis 1 format ""
set mxtics 5
set grid xtics ls -1
set yrange[-4:4]
set ytics axis 1 format ""
set mytics 5
set grid ytics ls -1
ColorScreen = 0x28a7e0
set obj 1 rect from screen 0,0 to screen 1,1 behind
set obj 1 fill solid 1.0 fc rgb ColorScreen
x0=y0=NaN
Derivative(x,y) = (dx=x-x0,x0=x,x-dx/2,dy=y-y0,y0=y,dy/dx) # approx. derivative
# get min/max derivative
set table $Dummy
plot n=0 $Data u (d=abs(Derivative($1,$2)),n=n+1,n<=2? (dmin=dmax=d) : \
(dmin>d ? dmin=d:dmin), (dmax<d?dmax=d:dmax)) w table
unset table
myColor(x,y) = (int((abs(Derivative(column(x),column(y)))-dmin)/(dmax-dmin)*0xff)<<24) +0xffffff
plot $Data u 1:2:(myColor(1,2)) w l lw 1.5 lc rgb var not
### end of code
Result:
I'm making some speedup graphs using histogram clustered. For each instance, I group the speedup reached using 2,4,8,16 and 32 computers. I also use a line to indicate the "linear speedup". However, for each instance/computer, I would like also to place a point on top of it, to indicate a value I'm comparing my speedup to.
I've tried to use the same strategy for plotting the boxes, but using points instead. However, the points are plotted on the same place, they are not obeying the ''clustered'' spacing.
Here is the code I'm using:
set yrange [0:105]
set grid ytics
set style line 1 lc rgb '#0e1111' lt 1 lw 2 pt -1 ps 1.0
set xlabel "Instance" font "sans, 18"
set ylabel "Normalized Speedup (In %)" font "sans, 18"
set style histogram clustered
plot for [COL=2:2] 'data.dat' using COL:xticlabels(1) title columnheade lc rgbcolor "black" lt -1 fs pattern 3,\
for [COL=3:3] 'data.dat' using COL:xticlabels(1) title columnheade lc rgbcolor "black" lt -1 fs pattern 1,\
"linear.t" t "Lin" with linespoints ls 1
Example of data
0 2 4 8 16 32
ta22 65.67 37.98 38.16 30.91 19.24
ta23 73.69 45.59 48.59 44.20 34.19
That's what I got. The points are what I would like to have.
Is it possible to have such a thing? It would also work like an error bar. However, without line and just a ''max''.
Thank you all!
I couldn't run your code. But, based on your image, I understood you problem.
To plot the points with you want, I created a file called points.dat.
0 2 4 8 16 32
ta22 75.67 47.98 48.16 40.91 29.24
ta23 83.69 55.59 58.59 54.20 44.19
This one nothing else is that your data + 10.
The gnuplot code
reset # Restore the default settings
set encoding utf8 # Selects the character encoding
set terminal pngcairo size 800,500 # Generates output in png
set output 'histogram.png' # The filename
set grid ytics ls -1 lc 'gray' # Grid lines ytics only
set yrange [0:100] # Yrange 0 to 100 (% ?)
set style data histograms # Type of data: histograms
set style histogram clustered gap 1 # Type of histogram: clustered with gap 1
set style fill transparent solid 1 border lt -1 # Style: fillstyle and border
stats 'points.dat' skip 1 matrix nooutput # Statistical summary with skip
# for header and without output
numRows = STATS_size_y # Y size of matrix (rows)
numCols = STATS_size_x # X size of matrix (columns)
array Value[numRows*(numCols-1)] # Create an array based on size of data
position = 0 # Count to position on array
# Loop for populate the array
do for [i=1:numRows]{
do for [j=2:numCols]{
# Statistical summary (with skip for header) at each value and without output
stats 'points.dat' skip 1 u j every ::i-1::i-1 nooutput
position = position + 1 # Increase the count of position
Value[position] = STATS_min # Define the array-value as result of statistical analysis
}
}
# Mapping functions:
# i-cluster/rows (x-values),
# j-column (y-values)
# ignore the cluster name ($1)
posX(i, j) = (i - 1) + 1.0*(j - numCols + 3)/numCols # To X-values
posY(i, j) = i == 1 ? Value[j] : Value[numCols - 1 + j] # To Y-values
# The plot itself as newhistogram and nested loops:
# i-loop to bars and title as columnheade
# j-loop to rows (x-values)
# k-loop to columns (y-values)
plot \
newhistogram ,\
for [i=2:numCols]\
'data.dat' u i:xticlabels(1) ls i-1 title columnheade,\
for [j=1:numRows] \
for [k=1:numCols-1] \
'+' u (posX(j, k)):(posY(j, k)) w p pt 5 ps 0.75 lc 'black' notitle
produces
I would like to plot data with lines and points with different colors. It seems to exist different solutions:
https://stackoverflow.com/a/31887351/4373898 , https://stackoverflow.com/a/31562632/4373898
https://gnuplot-tricks.blogspot.fr/2009/12/defining-some-new-plot-styles.html
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.
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
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.
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:
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:
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:
Kind regards,
Alexis
I have x- and y-data points representing a star cluster. I want to visualize the density using Gnuplot and its scatter function with overlapping points.
I used the following commands:
set style fill transparent solid 0.04 noborder
set style circle radius 0.01
plot "data.dat" u 1:2 with circles lc rgb "red"
The result:
However I want something like that
Is that possible in Gnuplot? Any ideas?
(edit: revised and simplified)
Probably a much better way than my previous answer is the following:
For each data point check how many other data points are within a radius of R. You need to play with the value or R to get some reasonable graph.
Indexing the datalines requires gnuplot>=5.2.0 and the data in a datablock (without empty lines). You can either first plot your file into a datablock (check help table) or see here:
gnuplot: load datafile 1:1 into datablock
The time for creating this graph will increase with number of points O(N^2) because you have to check each point against all others. I'm not sure if there is a smarter and faster method. The example below with 1200 datapoints will take about 4 seconds on my laptop. You basically can apply the same principle for 3D.
Script: works with gnuplot>=5.2.0
### 2D density color plot
reset session
t1 = time(0.0)
# create some random rest data
set table $Data
set samples 700
plot '+' u (invnorm(rand(0))):(invnorm(rand(0))) w table
set samples 500
plot '+' u (invnorm(rand(0))+2):(invnorm(rand(0))+2) w table
unset table
print sprintf("Time data creation: %.3f s",(t0=t1,t1=time(0.0),t1-t0))
# for each datapoint: how many other datapoints are within radius R
R = 0.5 # Radius to check
Dist(x0,y0,x1,y1) = sqrt((x1-x0)**2 + (y1-y0)**2)
set print $Density
do for [i=1:|$Data|] {
x0 = real(word($Data[i],1))
y0 = real(word($Data[i],2))
c = 0
stats $Data u (Dist(x0,y0,$1,$2)<=R ? c=c+1 : 0) nooutput
d = c / (pi * R**2) # density: points per unit area
print sprintf("%g %g %d", x0, y0, d)
}
set print
print sprintf("Time density check: %.3f sec",(t0=t1,t1=time(0.0),t1-t0))
set size ratio -1 # same screen units for x and y
set palette rgb 33,13,10
plot $Density u 1:2:3 w p pt 7 lc palette z notitle
### end of script
Result:
Would it be an option to postprocess the image with imagemagick?
# convert into a gray scale image
convert source.png -colorspace gray -sigmoidal-contrast 10,50% gray.png
# build the gradient, the heights have to sum up to 256
convert -size 10x1 gradient:white-white white.png
convert -size 10x85 gradient:red-yellow \
gradient:yellow-lightgreen \
gradient:lightgreen-blue \
-append gradient.png
convert gradient.png white.png -append full-gradient.png
# finally convert the picture
convert gray.png full-gradient.png -clut target.png
I have not tried but I am quite sure that gnuplot can plot the gray scale image directly.
Here is the (rotated) gradient image:
This is the result:
Although this question is rather "old" and the problem might have been solved differently...
It's probably more for curiosity and fun than for practical purposes.
The following code implements a coloring according to the density of points using gnuplot only. On my older computer it takes a few minutes to plot 1000 points. I would be interested if this code can be improved especially in terms of speed (without using external tools).
It's a pity that gnuplot does not offer basic functionality like sorting, look-up tables, merging, transposing or other basic functions (I know... it's gnuPLOT... and not an analysis tool).
The code:
### density color plot 2D
reset session
# create some dummy datablock with some distribution
N = 1000
set table $Data
set samples N
plot '+' u (invnorm(rand(0))):(invnorm(rand(0))) w table
unset table
# end creating dummy data
stats $Data u 1:2 nooutput
XMin = STATS_min_x
XMax = STATS_max_x
YMin = STATS_min_y
YMax = STATS_max_y
XRange = XMax-XMin
YRange = YMax-YMin
XBinCount = 20
YBinCount = 20
BinNo(x,y) = floor((y-YMin)/YRange*YBinCount)*XBinCount + floor((x-XMin)/XRange*XBinCount)
# do the binning
set table $Bins
plot $Data u (BinNo($1,$2)):(1) smooth freq # with table
unset table
# prepare final data: BinNo, Sum, XPos, YPos
set print $FinalData
do for [i=0:N-1] {
set table $Data3
plot $Data u (BinNumber = BinNo($1,$2),$1):(XPos = $1,$1):(YPos = $2,$2) every ::i::i with table
plot [BinNumber:BinNumber+0.1] $Bins u (BinNumber == $1 ? (PointsInBin = $2,$2) : NaN) with table
print sprintf("%g\t%g\t%g\t%g", XPos, YPos, BinNumber, PointsInBin)
unset table
}
set print
# plot data
set multiplot layout 2,1
set rmargin at screen 0.85
plot $Data u 1:2 w p pt 7 lc rgb "#BBFF0000" t "Data"
set xrange restore # use same xrange as previous plot
set yrange restore
set palette rgbformulae 33,13,10
set colorbox
# draw the bin borders
do for [i=0:XBinCount] {
XBinPos = i/real(XBinCount)*XRange+XMin
set arrow from XBinPos,YMin to XBinPos,YMax nohead lc rgb "grey" dt 1
}
do for [i=0:YBinCount] {
YBinPos = i/real(YBinCount)*YRange+YMin
set arrow from XMin,YBinPos to XMax,YBinPos nohead lc rgb "grey" dt 1
}
plot $FinalData u 1:2:4 w p pt 7 ps 0.5 lc palette z t "Density plot"
unset multiplot
### end of code
The result: