I am trying to plot a heat map of 3D results, a f(x,y) function, obtained on an uneven grid.
The plot I obtain gives me some ugly empty spaces at the top of the graph.
Below are minimal scripts to reproduce the issue I am facing.
#Generate some dummy data
f(x,y) = sqrt(x**2 + y**2)
set table
set samples 1000
set output "table.dat"
splot [0:10][0:10] f(x,y)
The plotting script :
# plot it
set term x11
set out
set pm3d map
splot [1:5] [0:2] "table.dat" u ($1):($2/$1):($3)
Since the y-axis value depends on the x-axis, the grid is now even. As can be seen in the following figure gnuplot fails to fill-up some space close to the top border of the plot. Changing the axis limits doesn't help.
sample impage plot
Any idea how to fill-up the white triangles and make this plot look nicer ?
Thanks for your help.
You can use dgrid3d for 2-d interpolation. With your using specification ($1):($2/$1):($3) the domain where you have data points is very irregular. It helps to tell dgrid3d that you are interested only in a small rectangle by setting all other values to NaN. For example:
set pm3d map
set dgrid3d 100,100 qnorm 4
splot [1:5] [0:2] "table.dat" u ($1 >= 1 && $1 <= 5 ? $1 : 1/0):($2/$1 > 0 && $2/$1 < 2 ? $2/$1 : 1/0):3
You will have to experiment with the various options of dgrid3d to get a reasonable interpolation.
Related
I would like to make a density plot from a distribution like the second subfigure in the following:
Here is what I tried:
unset key
set yrange [0:]
set ytics 5
set print $data
do for [i = 1:100] { print rand(0)*10 }
unset print
binwidth = 1
set boxwidth 0.8*binwidth
# set fill style of bins
set style fill solid 0.5
# define macro for plotting the histogram
hist = 'u (binwidth*(floor(($1)/binwidth)+0.5)):(1.0) smooth freq w boxes'
density = 'u (binwidth*(floor(($1)/binwidth)+0.5)):(1.0) smooth freq with filledcurves y=0'
plot $data #density
It is mainly based on a histogram by adding with filledcurves, but a clear difference is that the resulting figure is not smooth at all.
So, how can I generate smooth density plots from a distribution? Is there any interpolation function that can be used in gnuplot?
I found kernel density estimate in gnuplot can be helpful here.
plot $data u 1:(1/100.) s kdens bandwidth 1 with filledcurves y=0
I would like to plot a smoothed curve based on a dataset which spans over 13 orders of magnitude [1E-9:1E4] in x and 4 orders of magnitude [1E-6:1e-2] in y.
MWE:
set log x
set log y
set xrange [1E-9:1E4]
set yrange [1E-6:1e-2]
set samples 1000
plot 'data.txt' u 1:3:(1) smooth csplines not
The smooth curve looks nice above x=10. Below, it is just a straight line down to the point at x=1e-9.
When increasing samples to 1e4, smoothing works well above x=1. For samples 1e5, smoothing works well above x=0.1 and so on.
Any idea on how to apply smoothing to lower data points without setting samples to 1e10 (which does not work anyway...)?
Thanks and best regards!
JP
To my understanding sampling in gnuplot is linear. I am not aware, but maybe there is a logarithmic sampling in gnuplot which I haven't found yet.
Here is a suggestion for a workaround which is not yet perfect but may act as a starting point.
The idea is to split your data for example into decades and to smooth them separately.
The drawback is that there might be some overlaps between the ranges. These you can minimize or hide somehow when you play with set samples and every ::n or maybe there is another way to eliminate the overlaps.
Code:
### smoothing over several orders of magnitude
reset session
# create some random test data
set print $Data
do for [p=-9:3] {
do for [m=1:9:3] {
print sprintf("%g %g", m*10**p, (1+rand(0))*10**(p/12.*3.-2))
}
}
set print
set logscale x
set logscale y
set format x "%g"
set format y "%g"
set samples 100
pMin = -9
pMax = 3
set table $Smoothed
myFilter(col,p) = (column(col)/10**p-1) < 10 ? column(col) : NaN
plot for [i=pMin:pMax] $Data u (myFilter(1,i)):2 smooth cspline
unset table
plot $Data u 1:2 w p pt 7 ti "Data", \
$Smoothed u 1:2 every ::3 w l ti "cspline"
### end of code
Result:
Addition:
Thanks to #maij who pointed out that it can be simplified by simply mapping the whole range into linear space. In contrast to #maij's solution I would let gnuplot handle the logarithmic axes and keep the actual plot command as simple as possible with the extra effort of some table plots.
Code:
### smoothing in loglog plot
reset session
# create some random test data
set print $Data
do for [p=-9:3] {
do for [m=1:9:3] {
print sprintf("%g %g", m*10**p, (1+rand(0))*10**(p/12.*3.-2))
}
}
set print
set samples 500
set table $SmoothedLog
plot $Data u (log10($1)):(log10($2)) smooth csplines
set table $Smoothed
plot $SmoothedLog u (10**$1):(10**$2) w table
unset table
set logscale x
set logscale y
set format x "%g"
set format y "%g"
set key top left
plot $Data u 1:2 w p pt 7 ti "Data", \
$Smoothed u 1:2 w l lc "red" ti "csplines"
### end of code
Result:
Using a logarithmic scale basically means to plot the logarithm of a value instead of the value itself. The set logscale command tells gnuplot to do this automatically:
read the data, still linear world, no logarithm yet
calculate the splines on an equidistant grid (smooth csplines), still linear world
calculate and plot the logarithms (set logscale)
The key point is the equidistant grid. Let's say one chooses set xrange [1E-9:10000] and set samples 101. In the linear world 1e-9 compared to 10000 is approximately 0, and the resulting grid will be 1E-9 ~ 0, 100, 200, 300, ..., 9800, 9900, 10000. The first grid point is at 0, the second one at 100, and gnuplot is going to draw a straight line between them. This does not change when afterwards logarithms of the numbers are plotted.
This is what you already have noted in your question: you need 10 times more points to get a smooth curve for smaller exponents.
As a solution, I would suggest to switch the calculation of the logarithms and the calculation of the splines.
# create some random test data, code "stolen" from #theozh (https://stackoverflow.com/a/66690491)
set print $Data
do for [p=-9:3] {
do for [m=1:9:3] {
print sprintf("%g %g", m*10**p, (1+rand(0))*10**(p/12.*3.-2))
}
}
set print
# this makes the splines smoother
set samples 1000
# manually account for the logarithms in the tic labels
set format x "10^{%.0f}" # for example this format
set format y "1e{%+03.0f}" # or this one
set xtics 2 # logarithmic world, tic distance in orders of magnitude
set ytics 1
# just "read logarithm of values" from file, before calculating splines
plot $Data u (log10($1)):(log10($2)) w p pt 7 ti "Data" ,\
$Data u (log10($1)):(log10($2)) ti "cspline" smooth cspline
This is the result:
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 have problem with plotting fitted function.
The part of the ploted function close to zero disappears and connected with the hyperbola or something which should not be there at all. This happen only if I change set xrange to something smaller than 0. I have to do this because I have lot of data points to close zero so it would look very ugly if I would not changed it.
I tried to use conditionals x>0?f(x):1/0 but it does not help. The hyperbola disappear but the function does not continue down as it should.
I use this code:
set terminal postscript eps size 3.5,2.62 enhanced color
set output "a.eps"
set xrange [-1:]
f(x)=a*b*x/(1+a*x)
fit f(x) "./a" via a, b
plot "./a" w p title "", f(x) w l title "Langmuir isotherm"
That is simply a matter of sampling. The default sampling rate is 100 (show samples), which isn't enough to show fast-varying functions. Increase the sampling rate with e.g.
set samples 1000
to have your function plotted correctly.
A second point is, that discontinuities aren't shown properly if no sample is located exactly at that position. Consider the following plot to demonstrate this:
set xrange [-1:1]
set multiplot layout 2,1
set samples 100
plot 1/x
set samples 101
plot 1/x
unset multiplot
So, if you want to plot the function correctly on both sides of the discontinuity, you must either define a small region around the discontinuity as undefined, or you plot the parts on the left and right separately:
set xrange [-1:]
f(x)=a*b*x/(1+a*x)
fit f(x) "./a" via a, b
left(x) = (x < -1/a ? f(x) : 1/0)
right(x) = (x > -1/a ? f(x) : 1/0)
plot "./a" w p title "", left(x) w l lt 2 title "Langmuir isotherm", right(x) w l lt 2 notitle
I would like to plot the frequency-domain response of a filter in a similar manner to how the pole-zero plots are on the Wikipedia's "Chebyshev filter" page: http://en.wikipedia.org/wiki/File:Chebyshev_Type_I_Filter_s-Plane_Response_(8th_Order).svg . In particular, what I would like is to cut the plot in half along the Y axis and to make the cut stand out as representing the frequency response.
So far I have managed to get this:
The maked seam can be seen but it doesn't stand out, as if freshly welded. I hope the meaning gets to you because I can't find a better explanation now.
Now, what I have, so far, with wxMaxima's draw3d() function, is this:
draw3d(logx=false,logy=false,logz=true,
enhanced3d=false,line_width=2,color=red,explicit(cabs(Hs(x+%i*y)),x,-0.01,0,y,-3,3),
enhanced3d=[z**.5,x,y,z],palette=gray,proportional_axes=xy,
/* cbrange=[0.05,100.95], */ view=[0,0],yv_grid=101,xu_grid=101,
explicit(cabs(Hs(x+%i*y)),x,-1,0,y,-3,3))$
where Hs(s) is defined earlier, say:
Hs(s):=0.0248655/((s+0.210329)*(s^2+0.12999*s+0.521695)*(s^2+0.340319*s+0.22661))$
I don't know how to make the frequency response stand out, the order of printing doesn't seem to matter. Does anyone know if it can be done and, if so, how?
I don't know how to achieve that with maxima, but here is a solution with gnuplot only. This uses the + pseudo filename to create the 1D-plot for x=0 with splot. Complex numbers are specified with brackets, {x,y}, i.e. i = {0,1}:
set terminal pngcairo size 1000,800
set output 'chebyshev.png'
N = 501
set isosamples N
set samples N
set pm3d interpolate 3,3
set palette gray
set cbrange [*:10]
set xrange [-1:0]
set yrange [-3:3]
set logscale z
set autoscale zfix
set view 120,278
unset key
set grid
Hs(s) = 0.0248655/((s+0.210329)*(s**2+0.12999*s+0.521695)*(s**2+0.340319*s+0.22661))
splot abs(Hs(x+{0,1}*y)) w pm3d, \
'+' using (y = ($0/(N-1.0) * 6 - 3), 0):(y):(abs(Hs({0,1}*y))) w l lw 3
The result with 4.6.3 is: