I am creating a program that solves a 3D partial differential equation using finite difference methods. This is surprisingly not the hard part, and it is technically finished.
At the end of the program, I am writing the numerical solutions to the PDE in the following format to some file (for later processing)
X Y Z C
0 0 0 0.1
0 0 1 etc etc
Where X Y and Z are spatial coordinates and C is the intensity at each location.
I found one a lot of information on plotting 3D data with 2 spatial dimensions and 1 intensity. So "technically" I have 4D data ... 3 spacial, 1 intensity.
The one piece of information I found was using this command:
splot 'datafile' u 1:2:3:4 w pm3d
Which does do the job, but since it is a rectangular prism, you can't easily see the concentration at the center of the prism.
I was imagining that the best way to do this would be to take a "chunk" out of the rectangular prism, so that you can see the intensity layers. The best analogy I could think of was the how text books represent the layers of the earth, where they take a chunk of the earth out to show all the way down to the core.
Another way I saw in research papers was to plot and XY cross section, YZ cross section and XZ cross section all on the same graph.
I have tried to search for both of these but it is very hard (for me) to concisely articulate.
Any advice would be great on the best way to represent this data!
I always find color maps to be the most helpful when interpreting data. You basically plot slices though planes with sensible information. If you have gridded data this is very easy to do in gnuplot even without preprocessing the data file. For instance, if your data looks like this:
# x y z c
0 0 0 0.15
1 0 0 0.14
2 0 0 0.16
0 1 0 0.11
1 1 0 0.19
2 1 0 0.12
0 2 0 0.15
1 2 0 0.19
2 2 0 0.13
0 0 1 0.10
1 0 1 0.09
2 0 1 0.17
# etc
then you can make a conditional plot with gnuplot for a fixed value of x, y or z. For the z = 0 plane, this could be achieved with splot "data" u 1:2:($3 == 0 ? $4 : 1/0), that is, if 3rd column's value is 0 then plot the 4th column's value, else ignore that point. For the simple example above:
set pm3d map
splot "data" u 1:2:($3 == 0 ? $4 : 1/0)
Note that pm3d does some interpolation between data points.
If you preprocess your data or have it nicely structured like in my example, you can also use the with image style, that might be preferred over pm3d for several reasons, including smaller file sizes:
plot "data" u 1:2:4 every :::0::2 with image
Where there is no interpolation but the actual point values. every :::0::2 above selected data blocks 0 to 2, which are the ones that belong to z = 0 in my example.
Finally, if your data is non gridded, you cannot use with image and should use pm3d instead. In this case the command should take into considerations points that are at an acceptable distance from the plane where you want to plot. This could be achieved as follows:
set pm3d map
plane_z = 0
splot "data" u 1:2:( abs($3 - plane_z) < 0.1 ? $4 : 1/0)
Above I include in the plot all the points whose z values are less than a distance 0.1 away from the plane (z = 0) I'm interested in.
Related
I have data that have 3 points to display in a 3D coordinate system. I want a line between each point and the coordinate origin (0 0 0). How can I draw these lines not connecting the points with each other but only with the origin?
I'm not very into gnuplot yet: I'm using the following code to display my data:
splot "C:/a/Drehmatrizenxyz.txt" with lines
But this only connects the points, which is exactly what I do not want.
Thank you.
Data file contains six values for each line. From origin is (0 0 0 x y z)
Example - plot vectors <-1,2,-4>, <-2,0,1> & <2,9,2>
file.dat:
0 0 0 -1 2 -4
0 0 0 -2 0 1
0 0 0 2 9 2
gnuplot> splot 'file.dat' with vectors
vectors
In case this is still of interest...
Please check the gnuplot homepage and basic gnuplot tutorials and in gnuplot console help vectors or in general help <keyword>.
Code:
### plot with vectors from origin
reset session
$Data <<EOD
1 2 3
4 5 6
7 8 1
EOD
set view equal xyz
set view 56,48, 1.3
set xyplane relative 0
splot $Data u (0):(0):(0):1:2:3 w vectors
### end of code
Result:
Can you tell me how to specify the default cb (or z) value?
I build a 3d chart {x,y,z} or {x,y,cb}, but for different x there are different ranges of y, and as a result white bars are visible on the chart (for heatmap/colorbox). I would like to see no white stripes, and where there is no data, gnuplot would substitute the default value (for example, 0) and, accordingly, paint the field with the appropriate color for heatmap
You have several options, depending on exactly what plot mode you are using and what type of data you have. In general you can use two properties of the color assignment to get what you want:
1) out-of-bound values are mapped to the color of the extreme min or max of the colorbar. So one option is to assign a palette that has your desired "default" color at the min and max, independent of whatever palette function you use for the rest of the range
2) data values that are "missing" or "not-a-number" generally leave a hole in the grid of a pixel image or heat map that lets the background color show through.
There is a demo imageNaN.dem in the standard demo set that shows use of these features for several 2D and 3D heat map commands. The output from a heatmap generated by splot $matrixdata matrix with image is shown below.You can see extreme values pinned to the min/max of the colorbar range.
Note that if you want some color other than the backgroundn to show through, you could position a colored rectangle behind the heat map surface.
# Define the test data as a named data block
$matrixdata << EOD
0 5 4 3 0
? 2 2 0 1
Junk 1 2 3 5
NaN 0 0 3 0
Inf 3 2 0 3
-Inf 0 1 2 3
EOD
set view map
set datafile missing '?'
unset xtics
set ytics ("0" 0.0, "?" 1.0, "Junk" 2.0, "NaN" 3.0, "Inf" 4.0, "-Inf" 5.0)
set cblabel "Score"
set cbrange [ -2.0 : 7.0 ]
splot $matrixdata matrix using 1:2:(0):3 with image
#Ethan, I really don't have some data, which results in white slits.
I can fill in the missing data 0 at the stage of forming the data file, but then some files become very large and gnuplot spends all the memory.
So I'm looking for a way to solve the problem.
My example:
For #Ethan: my code:
set arrow from 0,86400 rto graph 1, graph 0 nohead ls 5 front
#===> decision of problem
set object rectangle from graph 0, graph 0 to graph 1, graph 1 behind fc rgbcolor 'blue' fs noborder
set pm3d map
# set pm3d interpolate 32,32
set size square
set palette rgbformulae 22,13,-31
splot inputFullPath u 2:1:(percentage($4)) notitle
and my data (for example):
0 1 0.1
0 2 0.2
0 4 0.5
# -------- {0,5..7} - white gap
# -------- {1,1..3} - white gap
1 3 0.6
1 4 0.5
1 7 0.9
I have a matrix describing a 2D surface and I need to be able to calculate values along the surface for an arbitrary line.
This is best explained by an example
#x and y axes
x=c(1:100)
y=c(1:100)
# 2D Matrix function defined as 0 except for a middle box filled with 1
M=matrix(0,nrow=100,ncol=100)
M[40:60,40:60]=1
# define two points
x1=50
y1=50
x2=23
y2=80
# plot contour graph of M, add points (x1,y1) and (x2,y2)
# and a line connecting the two
contour(x,y,M)
points(x1,y1,col=2)
points(x2,y2,col=3)
lines(c(x1,x2),c(y1,y2),lty=2)
What I want to do is to get values of M along the line from (x1,y1) to (x2,y2), for instance at the values (xvec,yvec) where xvec=seq(x1,x2,length.out=N) and likewise for yvec.
Is there a simple way to do this in R?
Sincerely
It actually pretty easy using the capacity of the "[" function to accept a two column matrix (and here assuming N <- 20):
M[ cbind(xvec,yvec) ]
[1] 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
Because indices are truncated, the values won't necessary be those of the nearest points when the arguments are not integers.
Hi I'm using gnuplot to plot data from a simulation structured in data blocks, like this:
CurrentTime CurrentState
0 2
1.234 2
1.990 1
2.462 0
CurrentTime CurrentState
0 2
0.895 1
1.456 2
2.052 1
3.017 0
The number of data blocks is not strictly known but is at least 30 blocks.
Notice that the number of intervals are different for each CurrentTime.
I'm using the following code to plot the data as is
# GNUPlot code
set multiplot layout 2,1 title "Insert title" font ",14"
set tmargin 3
set bmargin 3
set lmargin 5
set rmargin 2
plot "data.txt" every :1 using 1:2:(column(-2)) with linespoints lc variable
The next thing I want to plot will go in the lower plot due to the multiplot command. That plot I want to be the average of my data at intervals of time that I set. In pseudo code I want:
# pseudo code
float start, step, stop;
assign start, step, stop;
define Interval=start, by step, to stop; typed another way Interval=start:step:stop
array sum(size(number of data blocks,length(Interval), length(Interval)))
assign sum=0;
for every data block
for k=0 to length(CurrentTime)
for j=0 to length(Interval)-1
(CurrentTime(k) < Interval(j+1) && CurrentTime(k) > Interval(j-1)) ? sum += CurrentState(k) : sum += 0
average=sum/(Number of data blocks)
I am stuck trying to implement that in gnuplot. Any assistance would be awesome!
First there is the data file, some of my real data is
CurrentTime CurrentState
0 2
4.36393 1
5.76339 2
13.752 1
13.7645 2
18.2609 1
19.9713 2
33.7285 1
33.789 0
CurrentTime CurrentState
0 2
3.27887 1
3.74072 2
3.86885 1
4.97116 0
CurrentTime CurrentState
0 2
1.19854 1
3.23982 2
7.30501 1
7.83872 0
Then I used python to find the average of the data at the time I intervals I want to check the average. I chose to check at discrete time steps but they could be any time step. The following is my python code
#Loading data file: Goal is to calculate average(TimeIntervals)=averageOfTimeIntervals.
import numpy as np
data=np.genfromtxt('data.txt', comments='C')
CurrentState=data[:,1]
CurrentTime=data[:,0]
numberTimeIntervals=101
TimeIntervals=np.linspace(0,numberTimeIntervals-1,numberTimeIntervals) #gives integer values of time
stateOfTimeIntervals=np.zeros(numberTimeIntervals,dtype=np.float64)
stateOfTimeIntervals[0]=CurrentState[0] #setting initial state
#main loop
run=0
numberSimTimes=len(CurrentTime)
for j in range(0,len(stateOfTimeIntervals)): #start at 1 b/c we know initial state
for k in range(0,numberSimTimes-1):
lengthThisRun=0
if CurrentTime[k] <= TimeIntervals[j] and CurrentTime[k+1] > TimeIntervals[j]:
lengthThisRun+=1
#Goal is to get the length of this run up to the time we decide to check the state
stateOfTimeIntervals[j]+=CurrentState[k]
else:
lengthThisRun+=1
#The number of runs can be claculated using
numberRuns=len(CurrentTime) - np.count_nonzero(CurrentTime)
print "Number of Runs=%f" %(numberRuns)
#Compute the average
averageState=stateOfTimeIntervals/numberRuns
#Write to file and plot with gnuplot
np.savetxt('plot2gnu.txt',averageState)
Then using gnuplot I plotted 'plot2gnu.txt' using the following code
# to plot everything on the same plot use "multiplot"
set multiplot layout 2,1 title "Insert title" font ",14"
set tmargin 3
set bmargin 3
set lmargin 5
set rmargin 2
plot "data.txt" every :1 using 1:2:(column(-2)) with linespoints lc variable
plot 'plot2gnu.txt' using 1:2 with linespoints
I would like to point out the use of a pseudocolumn 'column(-2)' in the third column specifying line color. 'column(-2)' represents "The index number of the current data set within a file that contains multiple data sets." - From the 'old' gnuplot 4.6 documentation.
I think this is probably a simple maths question but I have no idea what's going on right now.
I'm capturing the positions of "markers" on a webcam and I have a list of markers and their co-ordinates. Four of the markers are the outer corners of a work surface, and the fifth (green) marker is a widget. Like this:
Here's some example data:
Top left marker (a=98, b=86)
Top right marker (c=119, d=416)
Bottom left marker (e=583, f=80)
Bottom right marker (g=569, h=409)
Widget marker (x=452, y=318)
I'd like to somehow transform the webcam's widget position into a co-ordinate to display on the screen, where top left is 0,0 not 98,86 and somehow take into account the warped angles from the webcam capture.
Where would I even begin? Any help appreciated
In order to compute the warping, you need to compute a homography between the four corners of your input rectangle and the screen.
Since your webcam polygon seems to have an arbitrary shape, a full perspective homography can be used to convert it to a rectangle. It's not that complicated, and you can solve it with a mathematical function (should be easily available) known as Singular Value Decomposition or SVD.
Background information:
For planar transformations like this, you can easily describe them with a homography, which is a 3x3 matrix H such that if any point on or in your webcam polygon, say x1 were multiplied by H, i.e. H*x1, we would get a point on the screen (rectangular), i.e. x2.
Now, note that these points are represented by their homogeneous coordinates which is nothing but adding a third coordinate (the reason for which is beyond the scope of this post). So, suppose your coordinates for X1 were, (100,100), then the homogeneous representation would be a column vector x1 = [100;100;1] (where ; represents a new row).
Ok, so now we have 8 homogeneous vectors representing 4 points on the webcam polygon and the 4 corners of your screen - this is all we need to compute a homography.
Computing the homography:
A little math:
I'm not going to get into the math, but briefly this is how we solve it:
We know that 3x3 matrix H,
H =
h11 h12 h13
h21 h22 h23
h31 h32 h33
where hij represents the element in H at the ith row and the jth column
can be used to get the new screen coordinates by x2 = H*x1. Also, the result will be something like x2 = [12;23;0.1] so to get it in the screen coordinates, we normalize it by the third element or X2 = (120,230) which is (12/0.1,23/0.1).
So this means each point in your webcam polygon (WP) can be multiplied by H (and then normalized) to get your screen coordinates (SC), i.e.
SC1 = H*WP1
SC2 = H*WP2
SC3 = H*WP3
SC4 = H*WP4
where SCi refers to the ith point in screen coordinates and
WPi means the same for the webcam polygon
Computing H: (the quick and painless explanation)
Pseudocode:
for n = 1 to 4
{
// WP_n refers to the 4th point in the webcam polygon
X = WP_n;
// SC_n refers to the nth point in the screen coordinates
// corresponding to the nth point in the webcam polygon
// For example, WP_1 and SC_1 is the top-left point for the webcam
// polygon and the screen coordinates respectively.
x = SC_n(1); y = SC_n(2);
// A is the matrix which we'll solve to get H
// A(i,:) is the ith row of A
// Here we're stacking 2 rows per point correspondence on A
// X(i) is the ith element of the vector X (the webcam polygon coordinates, e.g. (120,230)
A(2*n-1,:) = [0 0 0 -X(1) -X(2) -1 y*X(1) y*X(2) y];
A(2*n,:) = [X(1) X(2) 1 0 0 0 -x*X(1) -x*X(2) -x];
}
Once you have A, just compute svd(A) which will give decompose it into U,S,VT (such that A = USVT). The vector corresponding to the smallest singular value is H (once you reshape it into a 3x3 matrix).
With H, you can retrieve the "warped" coordinates of your widget marker location by multiplying it with H and normalizing.
Example:
In your particular example if we assume that your screen size is 800x600,
WP =
98 119 583 569
86 416 80 409
1 1 1 1
SC =
0 799 0 799
0 0 599 599
1 1 1 1
where each column corresponds to corresponding points.
Then we get:
H =
-0.0155 -1.2525 109.2306
-0.6854 0.0436 63.4222
0.0000 0.0001 -0.5692
Again, I'm not going into the math, but if we normalize H by h33, i.e. divide each element in H by -0.5692 in the example above,
H =
0.0272 2.2004 -191.9061
1.2042 -0.0766 -111.4258
-0.0000 -0.0002 1.0000
This gives us a lot of insight into the transformation.
[-191.9061;-111.4258] defines the translation of your points (in pixels)
[0.0272 2.2004;1.2042 -0.0766] defines the affine transformation (which is essentially scaling and rotation).
The last 1.0000 is so because we scaled H by it and
[-0.0000 -0.0002] denotes the projective transformation of your webcam polygon.
Also, you can check if H is accurate my multiplying SC = H*WP and normalizing each column with its last element:
SC = H*WP
0.0000 -413.6395 0 -411.8448
-0.0000 0.0000 -332.7016 -308.7547
-0.5580 -0.5177 -0.5554 -0.5155
Dividing each column, by it's last element (e.g. in column 2, -413.6395/-0.5177 and 0/-0.5177):
SC
-0.0000 799.0000 0 799.0000
0.0000 -0.0000 599.0000 599.0000
1.0000 1.0000 1.0000 1.0000
Which is the desired result.
Widget Coordinates:
Now, your widget coordinates can be transformed as well H*[452;318;1], which (after normalizing is (561.4161,440.9433).
So, this is what it would look like after warping:
As you can see, the green + represents the widget point after warping.
Notes:
There are some nice pictures in this article explaining homographies.
You can play with transformation matrices here
MATLAB Code:
WP =[
98 119 583 569
86 416 80 409
1 1 1 1
];
SC =[
0 799 0 799
0 0 599 599
1 1 1 1
];
A = zeros(8,9);
for i = 1 : 4
X = WP(:,i);
x = SC(1,i); y = SC(2,i);
A(2*i-1,:) = [0 0 0 -X(1) -X(2) -1 y*X(1) y*X(2) y];
A(2*i,:) = [X(1) X(2) 1 0 0 0 -x*X(1) -x*X(2) -x];
end
[U S V] = svd(A);
H = transpose(reshape(V(:,end),[3 3]));
H = H/H(3,3);
A
0 0 0 -98 -86 -1 0 0 0
98 86 1 0 0 0 0 0 0
0 0 0 -119 -416 -1 0 0 0
119 416 1 0 0 0 -95081 -332384 -799
0 0 0 -583 -80 -1 349217 47920 599
583 80 1 0 0 0 0 0 0
0 0 0 -569 -409 -1 340831 244991 599
569 409 1 0 0 0 -454631 -326791 -799
Due to perspective effects linear or even bilinear transformations may not be accurate enough.
Look at correct perspective mapping and more from google on this phrase, may be this is what you need...
Since your input area isn't a rectangle of the same aspect-ratio as the screen, you'll have to apply some sort of transformation to do the mapping.
What I would do is take the proportions of where the inner point is with respect to the outer sides and map that to the same proportions of the screen.
To do this, calculate the amount of the free space above, below, to the left, and to the right of the inner point and use the ratio to find out where in the screen the point should be.
alt text http://img230.imageshack.us/img230/5301/mapkg.png
Once you have the measurements, place the inner point at:
x = left / (left + right)
y = above / (above + below)
This way, no matter how skewed the webcam frame is, you can still map to the full regular rectangle on the screen.
Try the following: split the original rectangle and this figure with 2 diagonals. Their crossing is (k, l). You have 4 distorted triangles (ab-cd-kl, cd-ef-kl, ef-gh-kl, gh-ab-kl) and the point xy is in one of them.
(4 triangles are better than 2, since the distortion doesn't depend on the diagonal chosen)
You need to find in which triangle point XY is. To do that you need only 2 checks:
Check if it's in ab-cd-ef. If true, go on with ab-cd-ef, (in your case it's not, so we proceed with cd-ef-gh).
We don't check cd-ef-gh, but already check a half of it: cd-gh-kl. The point is there. (Otherwise it would have been ef-gh-kl)
Here's an excellent algorythm to check if a point is in a polygon, using only it's points.
Now you need only to map the point to the original triangle cd-gh-kl. The point xy is a linear combination of the 3 points:
x = c * a1 + g * a2 + k * (1 - a1 - a2)
y = d * a1 + h * a2 + l * (1 - a1 - a2)
a1 + a2 <= 1
2 variables (a1, a2) with 2 equations. I guess you can derive the solution formulae on your own.
Then you just make a linear combinations of a1&a2 with the corresponding points' co-ordinates in the original rectangle. In this case with W (width) and H (height) it's
X = width * a1 + width * a2 + width / 2 * (1 - a1 - a2)
Y = 0 * a1 + height * a2 + height / 2 * (1 - a1 - a2)
More of how to do this in objective-c in xcode, related to jacobs post, you can find here: calculate the V from A = USVt in objective-C with SVD from LAPACK in xcode
The "Kabcsh Algorithm" does exactly this: it creates a rotation matrix between two spaces given N matched pairs of positions.
http://en.wikipedia.org/wiki/Kabsch_algorithm