im having trouble plotting the results of simplex method used for linear programing in Maxima
i used
minimize_lp(-4*x-5*y,[5*x+4*y<=40, x+4*y<=32, 5*x<=30]);
to solve the problem but now i need to plot this
tried this:
wxplot2d(minimize_lp(-4*x-5*y,[5*x+4*y<=40, x+4*y<=32, 5*x<=30]),[x,-10,10],[y,-10,10]);
all i get is "expression evaluates to non-numeric value everywhere in plotting range" and "nothing to plot" messages
i dont really use Maxima, im not very familiar with it,
its an assigment for a course, any help would be great
Graphical solution for a linear optimization problem subject to constraints
To plot the inequalities and the feasible set I did the following:
Step 1 – solving algebraically using minimize_lp()
load("simplex")$
minimize_lp(
-4*x-5*y,[
5*x+4*y<=40,
x+4*y<=32,
5*x<=30,
x>=0,y>=0
]
);
which yields
%o2) [-91/2,[y=15/2,x=2]]
Step 2 – extracting the coordinates of the optimizing point from %o2
soln: %o2$
c4sol: soln[2]$
x_c: rhs(c4sol[2])$
y_c: rhs(c4sol[1])$
pOpt: [x_c,y_c];
This outputs
(%o7) [2,15/2]
the coordinates of the optimizing point pOpt in a list that we later need for plotting.
Step 3 – defining the feasible set
We know from minimize_lp() that f(x,y) is minimized at (x=2,y=15/2) with
f=-91/2. So we rewrite the target function as -4x-5y=-91/2
tfm: solve(-4*x-5*y=-91/2,y)$
Next we use the restriction r1,r2,r3 to define the the bounderies of the feasible set by turning the inequalities into equalities and solving for the dependent variables:
r1: solve(5*x+4*y=40,y)$
r2: solve(x+4*y=32,y)$
r3: solve(5*x=30,x)$
We then create a list L containing:
L: [ev(y,tfm), ev(y,r1), ev(y,r2), ev(x,r3)];
which yields:
(%o12) [-(8*x-91)/10,-(5*x-40)/4,-(x-32)/4,6]
Step 4 – The plots
We use plot2d() for quick'n'dirty sketches:
plot2d(L,[x,1.5,5.25],[y,5,8.25])$
For the final plot we use draw2d
draw2d(
proportional_axes=xy ,
xrange = [1.5,5.25],
yrange = [5.00,8.25],
point_type = filled_circle, point_size=1.25,
color = black,
points(pOpt),
label(["pOpt = (2,15/2)", 2.50, 7.65]),
key = "tfMin=-91/2",
line_width = 2,
color = steelblue4,
explicit(ev(y,tfm ), x,0,12.25),
key = "r1",
line_width = 1.5,
color = DeepPink3,
explicit(ev(y,r1), x,0,12.25),
key = "r2",
line_width = 1.5,
color = cyan4,
explicit(ev(y,r2), x,0,12.25),
key = "r3",
line_width = 1.5,
color = orange,
explicit(ev(x,r3), x,0,12.25),
key = "feasible set",
border = false,
fill_color = LightPink2,
polygon([[3.20,6],[2,7.5],[3.9,6]])
)$
Hope this helps, after all these years.
Cheers
Tilda
Related
I am trying to use vtkImageReSlicer to extract a 2d slice from a 3d
vtkImageData object. But I can't seem to get the recipe right. Am I doing it right?
I am also a bit confused about ResliceAxes Matrix. Does it represent a cutting plane? If
I move the ReSliceAxes origin will it also move the cutting plane? When I
call Update on the vtkImageReSlicer, the program crashes. But when I don't
call it, the output is empty.
Here's what I have so far.
#my input is any vtkactor that contains a closed curve of type vtkPolyData
ShapePolyData = actor.GetMapper().GetInput()
boundingBox = ShapePolyData.GetBounds()
for i in range(0,6,2):
delta = boundingBox[i+1]-boundingBox[i]
newBoundingBox.append(boundingBox[i]-0.5*delta)
newBoundingBox.append(boundingBox[i+1]+0.5*delta)
voxelizer = vtk.vtkVoxelModeller()
voxelizer.SetInputData(ShapePolyData)
voxelizer.SetModelBounds(newBoundingBox)
voxelizer.SetScalarTypeToBit()
voxelizer.SetForegroundValue(1)
voxelizer.SetBackgroundValue(0)
voxelizer.Update()
VoxelModel =voxelizer.GetOutput()
ImageOrigin = VoxelModel.GetOrigin()
slicer = vtk.vtkImageReslice()
#Am I setting the cutting axis here. x axis set at 1,0,0 , y axis at 0,1,0 and z axis at 0,0,1
slicer.SetResliceAxesDirectionCosines(1,0,0,0,1,0,0,0,1)
#if I increase the z value, will the cutting plane move up?
slicer.SetResliceAxesOrigin(ImageOrigin[0],ImageOrigin[1],ImageOrigin[2])
slicer.SetInputData(VoxelModel)
slicer.SetInterpolationModeToLinear()
slicer.SetOutputDimensionality(2)
slicer.Update() #this makes the code crash
voxelSurface = vtk.vtkContourFilter()
voxelSurface.SetInputConnection(slicer.GetOutputPort())
voxelSurface.SetValue(0, .999)
voxelMapper = vtk.vtkPolyDataMapper()
voxelMapper.SetInputConnection(voxelSurface.GetOutputPort())
voxelActor = vtk.vtkActor()
voxelActor.SetMapper(voxelMapper)
Renderer.AddActor(voxelActor)
I have never used vtkImageReslice, but I have used vtkExtractVOI for vtkImageData, which allows you to achieve a similar result, I think. Here is your example modified with the latter, instead:
ImageOrigin = VoxelModel.GetOrigin()
slicer = vtk.vtkExtractVOI()
slicer.SetInputData(VoxelModel)
#With the setVOI method you can define which slice you want to extract
slicer.SetVOI(xmin, xmax, ymin, ymax, zslice, zslice)
slicer.SetSampleRate(1, 1, 1)
slicer.Update()
voxelSurface = vtk.vtkContourFilter()
voxelSurface.SetInputConnection(slicer.GetOutputPort())
voxelSurface.SetValue(0, .999)
voxelMapper = vtk.vtkPolyDataMapper()
voxelMapper.SetInputConnection(voxelSurface.GetOutputPort())
voxelActor = vtk.vtkActor()
voxelActor.SetMapper(voxelMapper)
Renderer.AddActor(voxelActor)
I calculated the eigenvalues of the Hamiltonian for the 1D-hydrogen atom in atomic units with the Fourier-Grid-Hamiltonian method in a nice little Fortran program.
All the eigenvalues found between -1 and 0 (the bound states) are saved into a file line by line like this:
-0.50016671392950229
-0.18026105614262633
-0.11485673263086937
-4.7309305955423042E-002
-4.7077108902158216E-002
As the number of found eigenvalues differs depends on the stepsize my program uses, the number of entries in the file can vary (in theory, there are infinite ones).
I now want to plot the values from the file as a line parallel to the x-axis with the offset given by the values read from file.
I also want to be able to plot the data only up to a certain line number, as the values get really close to each other the further you come to zero and they cannot be distinguished by eye anymore.
(Here e.g. it would make sence to plot the first four entries, the fifth is already too close to the previous one)
I know that one can plot lines parallel to the x axis with the command plot *offset* but I don't know how to tell gnuplot to use the data from the file. So far I had to manually plot the values.
As a second step I would like to plot the data only in a certain x range, more concrete between the points of intersection with the harmonic potential used for the numeric solution V(x) = -1/(1+abs(x))
The result should look like this:
scheme of the desired plot (lookalike)
The closest I got to, was with
plot -1/(1+abs(x)),-0.5 title 'E0',-0.18 title 'E1', -0.11 title 'E2'
which got me the following result:
my plot
Hope you guys can help me, and I'm really curios whether gnuplot actually can do the second step I described!
As for the first part of your question, you can for example use the xerrorbars plotting style as:
set terminal pngcairo
set output 'fig.png'
unset key
set xr [-1:1]
set yr [-1:0]
unset bars
plot '-' u (0):($1<-0.1?$1:1/0):(1) w xerrorbars pt 0 lc rgb 'red'
-0.50016671392950229
-0.18026105614262633
-0.11485673263086937
-4.7309305955423042E-002
-4.7077108902158216E-002
e
The idea here is to:
interpret the energies E as points with coordinates (0,E) and assign to each of them an x-errorbar of width 1 (via the third part of the specification (0):($1<-0.1?$1:1/0):(1))
"simulate" the horizontal lines with x-errorbars. To this end, unset bars and pt 0 ensure that Gnuplot displays just plain lines.
consider only energies E<-0.1, the expressions $1<-0.1?$1:1/0 evaluates otherwise to an undefined value 1/0 which has the consequence that nothing is plotted for such E.
plot '-' with explicit values can be of course replaced with, e.g., plot 'your_file.dat'
This produces:
For the second part, it mostly depends how complicated is your function V(x). In the particular case of V(x)=-1/(1+|x|), one could infer directly that it's symmetric around x=0 and calculate the turning points explicitly, e.g.,
set terminal pngcairo
set output 'fig.png'
fName = 'test.dat'
unset key
set xr [-10:10]
set yr [-1:0]
unset bars
f(x) = -1 / (1+abs(x))
g(y) = (-1/y - 1)
plot \
f(x) w l lc rgb 'black', \
fName u (0):($1<-0.1?$1:1/0):(g($1)) w xerrorbars pt 0 lc rgb 'red', \
fName u (0):($1<-0.1?$1:1/0):(sprintf("E%d", $0)) w labels offset 0, char 0.75
which yields
The idea is basically the same as before, just the width of the errorbar now depends on the y-coordinate (the energy). Also, the labels style is used in order to produce explicit labels.
Another approach may be to get data from "energy.dat" (as given in the question) with system and cat commands (so assuming a Un*x-like system...) and select V(x) and E at each x via max:
set key bottom right
set yr [-1:0.2]
set samples 1000
Edat = system( "cat energy.dat" )
max(a,b) = ( a > b ) ? a : b
V(x) = -1/(1+abs(x))
plot for [ E in Edat ] \
max(V(x),real(E)) title sprintf("E = %8.6f", real(E)) lw 2, \
V(x) title "V(x) = -1/(1+|x|)" lc rgb "red" lw 2
If we change the potential to V(x) = -abs(cos(x)), the plot looks pretty funny (and the energy levels are of course not correct!)
More details about the script:
max is not a built-in function in Gnuplot, but a user-defined function having two formal arguments. So for example, we may define it as
mymax( p, q ) = ( p > q ) ? p : q
with any other names (and use mymax in the plot command). Next, the ? symbol is a ternary operator that gives a short-hand notation for an if...else construct. In a pseudo-code, it works as
function max( a, b ) {
if ( a > b ) then
return a
else
return b
end
}
This way, max(V(x),real(E)) selects the greater value between V(x) and real(E) for any given x and E.
Next, Edat = system( "cat energy.dat" ) tells Gnuplot to run the shell command "cat energy.dat" and assign the output to a new variable Edat. In the above case, Edat becomes a string that contains a sequence of energy values read in from "energy.dat". You can check the contents of Edat by print( Edat ). For example, it may be something like
Edat = "-0.11 -0.22 ... -0.5002"
plot for [ E in Edat ] ... loops over words contained in a string Edat. In the above case, E takes a string "-0.11", "-0.22", ..., "-0.5002" one-by-one. real(E) converts this string to a floating-point value. It is used to pass E (a character string) to any mathematical function.
The basic idea is to draw a truncated potential above E, max(V(x),E), for each value of E. (You can check the shape of such potential by plot max(V(x),-0.5), for example). After plotting such curves, we redraw the potential V(x) to make it appear as a single potential curve with a different color.
set samples 1000 increases the resolution of the plot with 1000 points per curve. 1000 is arbitrary, but this seems to be sufficient to make the figure pretty smooth.
Question
Is it possible to define functions which have multiple statements defined within?
Context
I want to automate some of the calculations involved in creating stacked plots by defining functions. In particular, I was hoping to have something like
mp_setup(bottom_margin, top_margin) = \
set tmargin 0; \
set bmargin 0; \
mp_available_height = 1.0 - top_margin - bottom_margin; \
mp_current_height = bottom_margin;
mp_plot(plot_height) = \
mp_plot_size = plot_height * mp_available_height; \
set origin 0,mp_current_height; \
set size 1,mp_plot_size; \
mp_current_height = mp_current_height + mp_plot_size;
with the intended usage being:
...
set multiplot
mp_setup(0.05, 0.05)
mp_plot(1.0/3.0)
plot ...
mp_plot(2.0/3.0)
plot ...
and this should automatically result in the plots being nicely stacked without me having to calculate the origin and size for each graph.
Problem
The way of defining the functions above doesn't work because it seems like the parsing of the function definition ends at the first occurrence of ;; but these semicolons are necessary in order to separate each statement (otherwise, we have set tmargin 0 set bmargin 0... which is invalid).
It also seems like Gnuplot doesn't support any way of grouping statement (like {...} in C/C++); or at least, I have never come across it.
Possible Solution
The only method I know to store multiple functions and evaluate them is using macros:
mp_setup = "<as above>"
mp_plot = "<as above>"
But the issue here is that macros do not allow for arguments to be passed in and instead each variable would have to be declared beforehand as follows:
...
set multiplot
top_margin = 0.05
bottom_margin = 0.05
#mp_setup
plot_height = 1.0/3.0
#mp_plot
plot ...
plot_height = 2.0/3.0
#mp_plot
plot ...
This solution, although it should work, is not quite as elegant.
Is there no other way of doing this?
No, it isn't possible to define such functions. In gnuplot user-defined functions cannot contain set, unset or other commands. Only those kind of expressions are allowed, which return numerical or string variables. Here, you can have several expressions, separated by comma:
a = 0
f(x) = (a = a + 1, a + x)
print f(1)
print f(1)
Besides your solution to use macros (#var), I prefer constructing strings inside the function and calling eval:
set_margin(s, v) = sprintf('set %smargin at screen %f;', s, v)
set_margins(l, r, b, t) = set_margin('l', l).set_margin('r', r).set_margin('b', b).set_margin('t', t)
eval(set_margins(0.1, 0.95, 0.15, 0.98))
For your specific case of a multiplot layout you can also see Removing blank gap in gnuplot multiplot.
You can do like that
mp_setup(bottom_margin, top_margin)=(tmargin=0,bmargin=0,mp_available_height=1.0 -top_margin-bottom_margin,mp_current_height=bottom_margin)
test:
print mp_setup(0.05,0.05)
==> 0.05
As you mentioned, the grouping statement in the function is not supporting yet.
I am trying to implement a colorbar in Matlab that looks linear when printed in grey. The most straight forward approach I though would be to implement the gnuplot pm3d 30,31,32 RGB colour space. On this website I found a good introduction, which works OK for some of the easier gnuplot schemes. However, when trying to implement the 30,31,32 scheme I run into trouble.
The gnuplot instructions are
30: x/0.32-0.78125 31: 2*x-0.84 32: 4x;1;-2x+1.84;x/0.08-11.5
And I interpreted this such that for the blue channel I have to apply four different equations. One for each quarter of intensity values. This is what I have tried so far
x = linspace(0,1,128);
r = x/0.32-0.78125;
g = 2*x-0.84;
b(1:length(x)/4) = 4*x(1:length(x)/4);
b(length(x)/4:length(x)/2) = 1;
b(length(x)/2:length(x)*.75) = -2*x(length(x)/2:length(x)*.75)+1.84;
b(length(x)*.75:end) = x(length(x)*.75:end)/0.08-11.5;
pm3d303132=[r;g;b]';
but unfortunately it doesn't work. I end up with negative values and values that exceed 1, which Matlab cannot interpret.
I did read in the show palette rgbformulae help that
* negative numbers mean inverted=negative colour component
But I don't know how to implement this in Matlab; and I also don't understand how to deal with values exceeding 1. Can anyone help?
Ignoring the out of bound values seems to work. (http://juluribk.com/2011/05/18/843/)
pm3d303132(pm3d303132<0)=0;
pm3d303132(pm3d303132>1)=1;
I know how to create a histogram (just use "with boxes") in gnuplot if my .dat file already has properly binned data. Is there a way to take a list of numbers and have gnuplot provide a histogram based on ranges and bin sizes the user provides?
yes, and its quick and simple though very hidden:
binwidth=5
bin(x,width)=width*floor(x/width)
plot 'datafile' using (bin($1,binwidth)):(1.0) smooth freq with boxes
check out help smooth freq to see why the above makes a histogram
to deal with ranges just set the xrange variable.
I have a couple corrections/additions to Born2Smile's very useful answer:
Empty bins caused the box for the adjacent bin to incorrectly extend into its space; avoid this using set boxwidth binwidth
In Born2Smile's version, bins are rendered as centered on their lower bound. Strictly they ought to extend from the lower bound to the upper bound. This can be corrected by modifying the bin function: bin(x,width)=width*floor(x/width) + width/2.0
Be very careful: all of the answers on this page are implicitly taking the decision of where the binning starts - the left-hand edge of the left-most bin, if you like - out of the user's hands. If the user is combining any of these functions for binning data with his/her own decision about where binning starts (as is done on the blog which is linked to above) the functions above are all incorrect. With an arbitrary starting point for binning 'Min', the correct function is:
bin(x) = width*(floor((x-Min)/width)+0.5) + Min
You can see why this is correct sequentially (it helps to draw a few bins and a point somewhere in one of them). Subtract Min from your data point to see how far into the binning range it is. Then divide by binwidth so that you're effectively working in units of 'bins'. Then 'floor' the result to go to the left-hand edge of that bin, add 0.5 to go to the middle of the bin, multiply by the width so that you're no longer working in units of bins but in an absolute scale again, then finally add back on the Min offset you subtracted at the start.
Consider this function in action:
Min = 0.25 # where binning starts
Max = 2.25 # where binning ends
n = 2 # the number of bins
width = (Max-Min)/n # binwidth; evaluates to 1.0
bin(x) = width*(floor((x-Min)/width)+0.5) + Min
e.g. the value 1.1 truly falls in the left bin:
this function correctly maps it to the centre of the left bin (0.75);
Born2Smile's answer, bin(x)=width*floor(x/width), incorrectly maps it to 1;
mas90's answer, bin(x)=width*floor(x/width) + binwidth/2.0, incorrectly maps it to 1.5.
Born2Smile's answer is only correct if the bin boundaries occur at (n+0.5)*binwidth (where n runs over integers). mas90's answer is only correct if the bin boundaries occur at n*binwidth.
Do you want to plot a graph like this one?
yes? Then you can have a look at my blog article: http://gnuplot-surprising.blogspot.com/2011/09/statistic-analysis-and-histogram.html
Key lines from the code:
n=100 #number of intervals
max=3. #max value
min=-3. #min value
width=(max-min)/n #interval width
#function used to map a value to the intervals
hist(x,width)=width*floor(x/width)+width/2.0
set boxwidth width*0.9
set style fill solid 0.5 # fill style
#count and plot
plot "data.dat" u (hist($1,width)):(1.0) smooth freq w boxes lc rgb"green" notitle
As usual, Gnuplot is a fantastic tool for plotting sweet looking graphs and it can be made to perform all sorts of calculations. However, it is intended to plot data rather than to serve as a calculator and it is often easier to use an external programme (e.g. Octave) to do the more "complicated" calculations, save this data in a file, then use Gnuplot to produce the graph. For the above problem, check out the "hist" function is Octave using [freq,bins]=hist(data), then plot this in Gnuplot using
set style histogram rowstacked gap 0
set style fill solid 0.5 border lt -1
plot "./data.dat" smooth freq with boxes
I have found this discussion extremely useful, but I have experienced some "rounding off" problems.
More precisely, using a binwidth of 0.05, I have noticed that, with the techniques presented here above, data points which read 0.1 and 0.15 fall in the same bin. This (obviously unwanted behaviour) is most likely due to the "floor" function.
Hereafter is my small contribution to try to circumvent this.
bin(x,width,n)=x<=n*width? width*(n-1) + 0.5*binwidth:bin(x,width,n+1)
binwidth = 0.05
set boxwidth binwidth
plot "data.dat" u (bin($1,binwidth,1)):(1.0) smooth freq with boxes
This recursive method is for x >=0; one could generalise this with more conditional statements to obtain something even more general.
We do not need to use recursive method, it may be slow. My solution is using a user-defined function rint instesd of instrinsic function int or floor.
rint(x)=(x-int(x)>0.9999)?int(x)+1:int(x)
This function will give rint(0.0003/0.0001)=3, while int(0.0003/0.0001)=floor(0.0003/0.0001)=2.
Why? Please look at Perl int function and padding zeros
I have a little modification to Born2Smile's solution.
I know that doesn't make much sense, but you may want it just in case. If your data is integer and you need a float bin size (maybe for comparison with another set of data, or plot density in finer grid), you will need to add a random number between 0 and 1 inside floor. Otherwise, there will be spikes due to round up error. floor(x/width+0.5) will not do because it will create pattern that's not true to original data.
binwidth=0.3
bin(x,width)=width*floor(x/width+rand(0))
With respect to binning functions, I didn't expect the result of the functions offered so far. Namely, if my binwidth is 0.001, these functions were centering the bins on 0.0005 points, whereas I feel it's more intuitive to have the bins centered on 0.001 boundaries.
In other words, I'd like to have
Bin 0.001 contain data from 0.0005 to 0.0014
Bin 0.002 contain data from 0.0015 to 0.0024
...
The binning function I came up with is
my_bin(x,width) = width*(floor(x/width+0.5))
Here's a script to compare some of the offered bin functions to this one:
rint(x) = (x-int(x)>0.9999)?int(x)+1:int(x)
bin(x,width) = width*rint(x/width) + width/2.0
binc(x,width) = width*(int(x/width)+0.5)
mitar_bin(x,width) = width*floor(x/width) + width/2.0
my_bin(x,width) = width*(floor(x/width+0.5))
binwidth = 0.001
data_list = "-0.1386 -0.1383 -0.1375 -0.0015 -0.0005 0.0005 0.0015 0.1375 0.1383 0.1386"
my_line = sprintf("%7s %7s %7s %7s %7s","data","bin()","binc()","mitar()","my_bin()")
print my_line
do for [i in data_list] {
iN = i + 0
my_line = sprintf("%+.4f %+.4f %+.4f %+.4f %+.4f",iN,bin(iN,binwidth),binc(iN,binwidth),mitar_bin(iN,binwidth),my_bin(iN,binwidth))
print my_line
}
and here's the output
data bin() binc() mitar() my_bin()
-0.1386 -0.1375 -0.1375 -0.1385 -0.1390
-0.1383 -0.1375 -0.1375 -0.1385 -0.1380
-0.1375 -0.1365 -0.1365 -0.1375 -0.1380
-0.0015 -0.0005 -0.0005 -0.0015 -0.0010
-0.0005 +0.0005 +0.0005 -0.0005 +0.0000
+0.0005 +0.0005 +0.0005 +0.0005 +0.0010
+0.0015 +0.0015 +0.0015 +0.0015 +0.0020
+0.1375 +0.1375 +0.1375 +0.1375 +0.1380
+0.1383 +0.1385 +0.1385 +0.1385 +0.1380
+0.1386 +0.1385 +0.1385 +0.1385 +0.1390
Different number of bins on the same dataset can reveal different features of the data.
Unfortunately, there is no universal best method that can determine the number of bins.
One of the powerful methods is the Freedman–Diaconis rule, which automatically determines the number of bins based on statistics of a given dataset, among many other alternatives.
Accordingly, the following can be used to utilise the Freedman–Diaconis rule in a gnuplot script:
Say you have a file containing a single column of samples, samplesFile:
# samples
0.12345
1.23232
...
The following (which is based on ChrisW's answer) may be embed into an existing gnuplot script:
...
## preceeding gnuplot commands
...
#
samples="$samplesFile"
stats samples nooutput
N = floor(STATS_records)
samplesMin = STATS_min
samplesMax = STATS_max
# Freedman–Diaconis formula for bin-width size estimation
lowQuartile = STATS_lo_quartile
upQuartile = STATS_up_quartile
IQR = upQuartile - lowQuartile
width = 2*IQR/(N**(1.0/3.0))
bin(x) = width*(floor((x-samplesMin)/width)+0.5) + samplesMin
plot \
samples u (bin(\$1)):(1.0/(N*width)) t "Output" w l lw 1 smooth freq