I have a set of data, looks like:
x y z
1 1 2 1
2 3 5 7
3 -3 2 4
4 -2 1 1
so each row record the dot coordinate in a 3-D space. I want to plot all the dot as points except for one, say no.15 as a translucent sphere, with radius I can set. Then I can see from the plot that which of those points in the data are included in the sphere. I'm using RGL package right now and did the following:
> open3d()
> plot3d(readin,col=3,type="p")
> plot3d(readin[15,],col=2,add=T,type="s",radius=0.1)
So the first plot command plotted the whole set as scatter plots and the second plot command picked the 15th row of the data and plot it as a sphere and add it to the previous canvas. I just wondering if I can make the sphere translucent so that I can see which dots a included in the sphere which means those dots are very near to the one I select.
Is there a way to do this by RGL Or you can provide me another ways to complete this task?
Thanks!
I think what you are looking for is the argument alpha.
Example
df <- data.frame(x=c(1,3,-3,-2), y=c(2,5,2,1),z=c(1,7,4,1))
library(rgl)
open3d()
plot3d(df,col=3,type="p", radius=0.5)
plot3d(df,col=rgb(1,0,0.3),alpha=0.5, add=T,type="s",radius=1)
You can plot transparent spheres using the alpha argument to spheres3d. You can rotate the plot to move the box line behind the sphere to prove it's transparent.
spheres3d(dat[4,],col=rgb(1,0,0), alpha=0.9) # transparent red.
(I tried to do it with the alpha argument to rgb but it failed.)
If you just want to find out which points are within a certain radius of point 15 then you can calculate the Euclidean distance from each point to point 15 and see which of those distances are less than the radius. No plotting needed (though you could plot those points as a different color to highlight them. The dist function is one way to compute the distances, or it is simple to program yourself.
Related
I'm looking for a way to plot histograms in 3d to produce something like this figure http://www.gnuplot.info/demo/surface1.17.png but where each series is a histogram.
I'm using the procedure given here https://stackoverflow.com/a/19596160 and http://www.gnuplotting.org/calculating-histograms/ to produce histograms, and it works perfectly in 2d.
Basically, the commands I use are
hist = 'u (binwidth*(floor(($2-binstart)/binwidth)+0.5)+binstart):(1) smooth freq w boxes
plot 'data.txt' #hist
Now I would just like to add multiple histograms in the same plot, but because they overlap in 2d, I would like to space them out in a 3d plot.
I have tried to do the following command (using above procedure)
hist = 'u (1):(binwidth*(floor(($2-binstart)/binwidth)+0.5)+binstart):(1) smooth freq w boxes
splot 'data.txt' #hist
But gnuplot complains that the z values are undefined.
I don't understand why this would not put a histogram along the value 1 on the x-axis with the bins along the y-axis, and plot the height on the z-axis.
My data is formatted simply in two columns:
Index angle
0 92.046
1 91.331
2 86.604
3 88.446
4 85.384
5 85.975
6 88.566
7 90.575
I have 10 files like this, and since the values in the files are close to each other, they will completely overlap if I plot them all in one 2d histogram. Therefore, I would like to see 10 histograms behind each other in a sort of 3d perspective.
This second answer is distinct from my first. Whereas the first addresses what the OP was trying to accomplish, this second provides an alternative approach which address the underlying problem the OP was trying to overcome.
I have posted an answer that addresses the ability to do this in 3d. However, this isn't usually the best way to do this with multiple histograms like this. A 3d graph like that will be difficult to compare.
We can address the overlap in 2D by stagnating the position of the boxes. With default settings, the boxes will spread out to touch. We can turn that off and adjust the position of the boxes to allow more than 1 histogram on a graph. Remember, that the coordinates you supply are the center of the boxes.
Suppose that I have the data you have provided and this additional data set
Index Angle
0 85.0804
1 92.2482
2 90.0384
3 99.2974
4 87.729
5 94.6049
6 86.703
7 97.9413
We can set the boxwidth to 2 units with set boxwidth 2 (your bins are 4 units wide). Additionally, we will turn on box filling with set style fill solid border lc black.
Then I can issue
plot datafile1 u (binwidth*(floor(($2-binstart)/binwidth)+0.5)+binstart):(1) smooth freq w boxes, \
datafile2 u (binwidth*(floor(($2-binstart)/binwidth)+0.5)+binstart+1):(1) smooth freq w boxes
The second plot command is identical to the first, except for the +1 after binstart. This will shift this box 1 unit to the right. This produces
Here, the two series are clear. Keeping track of which box is associated with each is easy because of the overlap, but it is not enough to mask the other series.
We can even move them next to each other, with no overlap, by subtracting 1 from the first plot command:
plot datafile1 u (binwidth*(floor(($2-binstart)/binwidth)+0.5)+binstart-1):(1) smooth freq w boxes, \
datafile2 u (binwidth*(floor(($2-binstart)/binwidth)+0.5)+binstart+1):(1) smooth freq w boxes
producing
This first answer is distinct from my second. This answer address what the OP was trying to accomplish whereas the second addresses the underlying problem the OP was trying to overcome.
Gnuplot isn't going to be able to do this on it's own, as the relevant styles (boxes and histograms) only work in 2D. You would have to do it using an external program.
For example, using your data and your 2d command (your first command), we get (using your data and the linked values of -100 and 4 for binstart and binwidth)
To draw these boxes on the 3d grid, we will need to use the line style and have four points for each: lower left, upper left, upper right, and lower right. We can use the previous command and capture to a table, but this will only gives the upper center point. We can use an external program to pre-process, however. The following python program, makehist.py, does just that.
from sys import argv
import re
from math import floor
pat = re.compile("\s+")
fname = argv[1]
binstart = float(argv[2])
binwidth = float(argv[3])
data = [tuple(map(float,pat.split(x.strip()))) for x in open(fname,"r").readlines()[1:]]
counts = {}
for x in data:
bn = binwidth*(floor((x[-1]-binstart)/binwidth)+0.5)+binstart
if not bn in counts: counts[bn] = 0
counts[bn]+=1
for x in sorted(counts.keys()):
count = counts[x]
print(x-binwidth/2,0)
print(x-binwidth/2,count)
print(x+binwidth/2,count)
print(x+binwidth/2,0)
print(max(counts.keys())+binwidth/2,0)
print(min(counts.keys())-binwidth/2,0)
Essentially, this program does the same thing as the smooth frequency option does, but instead of getting the upper center of each box, we get the four previously mentioned points along with two points to draw a line along the bottom of all the boxes.
Running the following command,
plot "< makehist.py data.txt -100 4" u 1:2 with lines
produces
which looks very similar to the original graph. We can use this in a 3d plot
splot "< makehist.py data.txt -100 4" u (1):1:2 with lines
which produces
This isn't all that pretty, but does lay the histogram out on a 3d plot. The same technique can be used to add multiple data files onto it spread out. For example, with the additional data
Index Angle
0 85.0804
1 92.2482
2 90.0384
3 99.2974
4 87.729
5 94.6049
6 86.703
7 97.9413
We can use
splot "< makehist.py data.txt -100 4" u (1):1:2 with lines, \
"< makehist.py data2.txt -100 4" u (2):1:2 with lines
to produce
I am trying to generate a plot which uses arrows as markers in Gnuplot. These arrows I want to turn in a specific angle which I know. So I have value triples of x1 ... xn, y1...yn, alpha1...alphan. Sorry, I wasn't able to include a pic from my hard drive to illustrate what I want to achieve.
Basically, for every (15th or so) x-y pair, the marker should be an arrow which uses a certain angle.
The measured data is tightly packed so I suppose I will have to define an increment between the markers. The length of the arrow can be the same all over.
I would appreciate your ideas.
Gnuplot has a plot mode with vectors that is what you want
Given that your file has the following format, x y angle and assuming that
your angle is in radians, you have to take into account that
with vectors requires 4 parameters, namely x y dx dy where dx
and dy are the projections of the lenght of the arrow.
this draws only the arrows, if you want a line you have to make
two passes on the data.
you want to draw an arrow for a data point over, say, 10 points.
That said, I'd proceed like this
dx(a) = 0.2*cos(a) # 0.2 is an arbitrary scaling factor
dy(a) = 0.2*sin(a)
# this draws the arrows
plot 'mydata.dat' every 10 using 1:2:(dx(a)):(dy(a)) with vectors
# this draws the line
plot 'mydata.dat'
You may want to use help plot to find the detailed explanation of all the parameters that you can apply to a with vectors plot.
Credits: An article on the gnuplotting site
I am new to R, so can someone please help with this?
I have a data frame with 4 columns: x,y,z and freq. One row in this frame represents one point in 3D space (x,y,z are x-,y- and z- coordinates respectively) and it's frequency. I want to plot these points and make these points coloured such that the color is decided by the frequency. For eg: All points with frequency 0 are blue, between 1 and 5 are red, between 5 and 10 are orange, between 10 and 15 are yellow and so on. Some points can have a frequency of 0 also. But I don't know the range of frequency. Max no of colors to be used is 10. Also, there should be a scale explaining the meaning of colors.
I have been trying to correct the following code and make it work, but it`s just not working:
lev <- levels(factor(t$freq));
n <- as.numeric(lev);
n <- n+1;
plot3d(t$x,t$z,t$z,col=n);
Please help! Thank you.
PS- Please tell the solution using rgl package
PPS - I have been trying to manipulate the col arguement in plot3d function of rgl package, but I am unable to get the desired result.
I would load package rgl and do
plot3d(x,y,z, col=colors)
That means that you should prepare a list of color values that is of the same length as x,y,z lists so that you have a color selected for each x,y,z point.
the other part would be to make the list. I would try
givecolor = function(freq){
if(freq < 1) "red"
else if ....
}
colors = sapply(mydataframe[,"freq"], givecolor)
You just need to build a vector of colors that is the same length as the number of points you are plotting. You then pass this vector as the col argument to the rgl plot3d() function. See this page for a demonstration that uses the iris dataset: http://planspace.org/2013/02/03/pca-3d-visualization-and-clustering-in-r/
First you should select a palette you like and pick the number of colors you want, e.g. palette=rainbow(10). Then use a factor you get from splitting your data 10 ways to set your color from the palette.
See 3d scatterplot in R using rgl plot3d - different size for each data point? for how to effectively split a dataframe by a newly created factor. That question is w.r.t. size, but it also works for color.
I am writing an regression algorithm which tries to "capture" points inside boxes. The algorithm tries to keep the boxes as small as possible, so usually the edges/corners of the boxes go through points, which determines the size of the box.
Problem: I need graphical output of the boxes in R. In 2D it is easy to draw boxes with segments(), which draws a line between two points. So, with 4 segments I can draw a box:
plot(x,y,type="p")
segments(x1,y1,x2,y2)
I then tried both the scatterplot3d and plot3d package for 3D plotting. In 3D the segments() command is not working, as there is no additional z-component. I was surprised that apparently (to me) there is no adequate replacement in 3D for segments()
Is there an easy way to draw boxes / lines between two points when plotting in three dimensions ?
The scatterplot3d function returns information that will allow you to project (x,y,z) points into the relevant plane, as follows:
library(scatterplot3d)
x <- c(1,4,3,6,2,5)
y <- c(2,2,4,3,5,9)
z <- c(1,3,5,9,2,2)
s <- scatterplot3d(x,y,z)
## now draw a line between points 2 and 3
p2 <- s$xyz.convert(x[2],y[2],z[2])
p3 <- s$xyz.convert(x[3],y[3],z[3])
segments(p2$x,p2$y,p3$x,p3$y,lwd=2,col=2)
The rgl package is another way to go, and perhaps even easier (note that segments3d takes points in pairs from a vector)
plot3d(x,y,z)
segments3d(x[2:3],y[2:3],z[2:3],col=2,lwd=2)
I know on gnuplot you can plot some data with circles as the plot points:
plot 'data.txt' using 1:2 ls 1 with circles
How do I then set the size of the circles? I want to plot several sets of data but with different size circles for each data set.
If you have a third column in your data, the third column specifies the size of the circles. In your case, you could have the third column have the same value for all the points in each data set. For example:
plot '-' with circles
1 1 0.2
e
will plot a circle at (1,1) with radius 0.2. Note that the radius is in the same units as the data. (The special file name '-' lets you input data directly; typing 'e' ends the input. Type help special at the gnuplot console for more info.)
You can look here for more ideas of how to use circles.
I used:
plot "file" using 1:2:($2*0+10) with circles
This will fake a the third column specifying the sizes - it is probably possible to write it simpler, but this worked for me.