How to make a scatter plot in DM script? - plot

I have 2 arrays, one contains the x coordinate and the other contains the y coordinates. I want to plot out those points in a figure according to those x and y coordinates, such as a scatter plot. Is it possible to make a 2D scatter plot in DM script? Can lineplot do it?

Unfortunately not.
DM does not provide any display for non-orthogonal data or sparse data.
Depending on your X/Y arrays you might be able to work arround that issue. If your X-values can be represented as X = offset + var * increment, then you can fake a scatter-plot by creating an image of (Xmax - offest)/increment pixels and setting all to zero, excpet the values for your x/y pairs.
You could do that with a 2D image as well.
Just note, that a regular 2D display will have the 0/0 origin in the top-left. To get a more "regular" display, you could flip vertically (and adjust calibration).
The following script outlines what I mean. However, in general I would say that DM is not the suitable tool for this type of data.
image xVals := [5,1]:
{
{ 2.5, 9.75, 5, 10.25, 4 }
}
image yVals := [5,1]:
{
{ 4.25, 3, 8.75, 11, 4.25 }
}
number sampling = 0.25 // Small enough to fit your data to integer!
image xValSampled = trunc( xVals / sampling )
number sizeX = 10 + max(xValSampled)
image scatterPlot := RealImage( "Scatter (1D)", 4, sizeX)
scatterPlot = 0
scatterPlot[ xValSampled, 0 ] = yVals
scatterPlot.ImageSetDimensionScale(0,sampling)
scatterPlot.ShowImage()
image yValSampled = trunc( yVals / sampling )
number sizeY = 10 + max(YValSampled)
image scatter := RealImage( "Scatter (2D)", 4, sizeX, sizeY )
scatter = 0
scatter.ImageSetDimensionScale(0,sampling)
scatter.ImageSetDimensionScale(1,sampling)
scatter[ xValSampled, yValSampled ] = 1
scatter.ShowImage()
scatter.ImageGetImageDisplay(0).ImageDisplaySetCaptionOn(1)
image scatterInverted := scatter.ImageClone()
scatterInverted.SetName("Scatter (2D) inv.")
FlipVertical(scatterInverted)
scatterInverted.ShowImage()
scatterInverted.ImageGetImageDisplay(0).ImageDisplaySetCaptionOn(1)
scatterInverted.ImageSetDimensionScale(1,-sampling)
scatterInverted.ImageSetDimensionOrigin(1,sizeY*sampling)

Related

How can I solve these two rotation along the x-axis questions?

Question 1
A) Find the volume V of the solid obtained by rotating the region bounded by the given curves about the specified line. y=5 sqrt(25-x^2), y = 0, x = 1, x = 4; about the x-axis with a sketch of the region/solid form (include disk rotation as well)
B)Find the volume V of the solid obtained by rotating the region bounded by the given curves about the specified line.y = (1/25)x^2, x = 5, y = 0; about the x-axis with a sketch of the region/solid form (include disk rotation as well)

Is there an R function to draw a solid circle with a radius in user coordinates

Is it possible to draw real solid circle with a radius in "user" coordinates?
I tried the following:
Polygons:
I don't want to use them because I need real circles in the resulting svg.
Segments
segments(x, y, x, y, lwd=px, lend=0)
With segments there is the problem that I don't find a way to specify the segment in "user" coordinates.
The resulting graph is at the end exported to PDF.
Update
I draw a graph with a lot of elements and the elements has a distinct width. The width of the elements depends on the width at the x-axis. If I don't use user coordinates the result in the PDF is not correct in dependence to the x-axis.
A Polygon is an approximation to a circle and if I use them the result e.g. PDF is very large and the performance is not good and memory usage is very high. I draw 10,000 circles and more on one graph.
I use the following code with the described performance problems:
circle <- function(x, y, r, col) {
edgeCount <- 50
intervals <- (1:edgeCount) / edgeCount * 2 * pi
for(i in 1:length(x)) {
polygon(r[i]*sin(intervals) + x[i], r[i]*cos(intervals) + y[i], col=col[i],border=NA)
}
}
If you're comfortable with using a wrapper for sp's SpatialLine object you can try the oceanmap package which has a quite useful function called SpatialCircle(). It essentially builds a circle via seq() and adjusts it for your center point coordinates x and y, and for your radius r. It's still a set of line segments (so not one curved line), but quite simple to use.
Result:
Code:
Pretty straightforward:
# Load libraries.
library(oceanmap)
# Generate plot window and data.
set.seed(1702)
plot.new()
plot.window(xlim = c(0, 20), ylim = c(0, 10),
asp = 1, xaxs = "i", yaxs = "i")
axis(1)
axis(2)
box()
n <- 1000
x <- runif(n, 0, 20)
y <- runif(n, 0, 10)
for (i in 1:n) {
circle <- SpatialCircle(x = x[i], y = y[i], r = 0.1, n = 1000)
lines(circle)
}
This also works with ggplot2 with some data wrangling.
Addendum: Precision of SpatialCircles
If you want to check out what n (precision) in the SpatialCircle() function really means, try the following:
nrow(circle#lines[[1]]#Lines[[1]]#coords)
Result:
[1] 1000
This means that the object has 1,000 coordinate pairs (x and y) through which a line can be drawn. Furthermore, this line will have 999 distinct line segments, as the first and the last coordinate pairs are always identical. Proof:
all.equal(circle#lines[[1]]#Lines[[1]]#coords[1, ],
circle#lines[[1]]#Lines[[1]]#coords[1000, ])
Result:
[1] TRUE
If found a solution myself with the help of Gregor2 which did lead me to the library "grid".
library(grid)
#draw frame using normal plot
plot(0, 0, cex=0)
margins <- par("mar")
#1: bottom 2:left 3:top 4:right
mb <- unit(margins[1], "lines")
ml <- unit(margins[2], "lines")
mt <- unit(margins[3], "lines")
mr <- unit(margins[4], "lines")
#create viewport equivalent to margins in par
pushViewport(viewport(x = ml, y = mb, width = unit(1, "npc") - ml - mr, height = unit(1, "npc") - mb - mt, just=c("left", "bottom"), clip=TRUE))
#draw circle in npc units (easily convertable to user units using grconvertX)
grid.draw(circleGrob(x=0.5, y=0.5, r=0.5, default.units="npc", gp=gpar(col="blue", fill="blue")))
popViewport()

R rgl 3d log scale plot and Antenna pattern plots

first of all before my sharing my problem I want to share a bit of code that might be helpful for some people outside there. I have been looking quite some time code to plot in 3d antenna measurements but I could not find code that does that. The problem is that antenna measurements have polar coordinates and typical 3d plot functions use cartesian coordinates. So my code below does just that (I am not an advanced programmer so I am sure someone might be able to optimize it for its use). The code can be run directly and I added comments to make it easier readable.
require("rgl")
require("fields")
degreeToRadian<-function(degree){
return (0.01745329252*degree)
}
turnPolarToX<-function(Amplitude,Coordinate){
return (Amplitude*cos(degreeToRadian(Coordinate)))
}
turnPolarToY<-function(Amplitude,Coordinate){
return (Amplitude*sin(degreeToRadian(Coordinate)))
}
# inputs for the code
test<-runif(359,min=-50,max=-20) # the 359 elements correspond to the polar coordinates of 1 to 359
test2<-runif(359,min=-50,max=-20) # the 359 elements correspond to the polar coordinates of 1 to 359
test3<-runif(359,min=-50,max=-20) # the 359 elements correspond to the polar coordinates of 1 to 359
# My three input vectors above are considered to be dBm values, typically unit for antenna or propagation measurements
# I want to plot those on three different 3d planes the XY, the YZ and the ZX. Since the rgl does not support
# polar coordinates I need to cast my polar coordinates to cartesian ones, using the three functions
# defined at the beginning. I also need to change my dBm values to their linear relative ones that are the mW
# Convert my dBm to linear ones
test<-10^(test/10)
test2<-10^(test2/10)
test3<-10^(test3/10)
# Start preparing the data to be plotted in cartesian domain
X1<-turnPolarToX(test,1:359)
Y1<-turnPolarToY(test,1:359)
Z1<-rep(0,359)
X2<-turnPolarToX(test2,1:359)
Y2<-rep(0,359)
Z2<-turnPolarToY(test2,1:359)
X3<-rep(0,359)
Y3<-turnPolarToX(test3,1:359)
Z3<-turnPolarToY(test3,1:359)
# Time for the plotting now
Min<-min(test,test2,test3)
Max<-max(test,test2,test3)
bgplot3d( suppressWarnings (
image.plot( legend.only=TRUE, legend.args=list(text='dBm/100kHz'), zlim=c(Min,Max),col=plotrix::color.scale(seq(Min,Max,length.out=21),c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)))
) # zlim is the colorbar numbers
)
# for below alternatively you can also use the lines3d to get values
points3d(X1,Y1,Z1,col=plotrix::color.scale(test,c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)),add=TRUE)
points3d(X2,Y2,Z2,col=plotrix::color.scale(test2,c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)),add=TRUE)
points3d(X3,Y3,Z3,col=plotrix::color.scale(test3,c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)),add=TRUE)
The problem I have now is that my plotting ideally I would like to be on a log scale that the rgl packet does not support! If I try to use log on my X,Y,Z to compress them I get an error that log is not defined for negative numbers (of course that is correct). How would you think to solve that problem on compressing the axes values when log scale plotting is not supported?
I would like to thank you for your reply
Regards
Alex
It doesn't make sense to apply a log scale to X, Y and Z. Just apply it to your original data, and transform the logged values to polar coordinates.
Since your logged test values are negative, you probably will want to apply an offset; polar coordinates with negative radius values are pretty hard to interpret.
Once you have done that, you can use the axis3d() function to add an axis with arbitrary labels to the plot. For example, if you want the origin to correspond to -50 dBm, you'd skip the transformation to linear coordinates and just add 50. You need to undo this when calculating labels. Here's your example, modified:
require("rgl")
require("fields")
degreeToRadian<-function(degree){
return (0.01745329252*degree)
}
turnPolarToX<-function(Amplitude,Coordinate){
return (Amplitude*cos(degreeToRadian(Coordinate)))
}
turnPolarToY<-function(Amplitude,Coordinate){
return (Amplitude*sin(degreeToRadian(Coordinate)))
}
# inputs for the code
test<-runif(359,min=-50,max=-20) # the 359 elements correspond to the polar coordinates of 1 to 359
test2<-runif(359,min=-50,max=-20) # the 359 elements correspond to the polar coordinates of 1 to 359
test3<-runif(359,min=-50,max=-20) # the 359 elements correspond to the polar coordinates of 1 to 359
# Add an offset of 50 to the values.
test <- test + 50
test2 <- test2 + 50
test3 <- test3 + 50
# Start preparing the data to be plotted in cartesian domain
X1<-turnPolarToX(test,1:359)
Y1<-turnPolarToY(test,1:359)
Z1<-rep(0,359)
X2<-turnPolarToX(test2,1:359)
Y2<-rep(0,359)
Z2<-turnPolarToY(test2,1:359)
X3<-rep(0,359)
Y3<-turnPolarToX(test3,1:359)
Z3<-turnPolarToY(test3,1:359)
# Time for the plotting now
Min<-min(test,test2,test3)
Max<-max(test,test2,test3)
bgplot3d( suppressWarnings (
image.plot( legend.only=TRUE, legend.args=list(text='dBm/100kHz'), zlim=c(Min,Max)-50,col=plotrix::color.scale(seq(Min-50,Max-50,length.out=21),c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)-50))
) # zlim is the colorbar numbers
)
# for below alternatively you can also use the lines3d to get values
points3d(X1,Y1,Z1,col=plotrix::color.scale(test,c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)),add=TRUE)
points3d(X2,Y2,Z2,col=plotrix::color.scale(test2,c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)),add=TRUE)
points3d(X3,Y3,Z3,col=plotrix::color.scale(test3,c(0,1,1),c(0,1,0),0,xrange=c(Min,Max)),add=TRUE)
# Add axes
labels <- pretty(c(-50, -20))
axis3d("x", at = labels + 50, labels = labels, pos = c(NA, 0, 0) )
axis3d("y", at = labels + 50, labels = labels, pos = c(0, NA, 0) )
axis3d("z", at = labels + 50, labels = labels, pos = c(0, 0, NA) )
One my system it produces this display:
You might want to add circles to show how the scale continues around in each plane. This code would do it:
theta <- seq(0, 2*pi, len = 100)
for (i in seq_along(labels)) {
x <- (labels[i] + 50)*cos(theta)
y <- (labels[i] + 50)*sin(theta)
lines3d(x, y, 0)
lines3d(x, 0, y)
lines3d(0, x, y)
}
I find the plot too busy with those added, but you can try it and decide for yourself.

Adding a picture to plot in R

I'm trying to add a picture (jpeg,png doesn't care) to a plot which is defined by the layout function. For example:
a<-c(1,2,3,4,5)
b<-c(2,4,8,16,32)
m <- matrix(c(1,1,1,1,2,3,2,3), nrow = 2, ncol = 4)
layout(m); hist(a);boxplot(a~b);plot(b~a)*
Instead of the histogram on position 1 I want to add an image (In my case it's a map)
I don't know how to deal with the jpeg package, maybe you can help me!
Regarding Rodrigo's comment, I created a function that should preserve the image's pixel aspect ratio (addImg).
addImg <- function(
obj, # an image file imported as an array (e.g. png::readPNG, jpeg::readJPEG)
x = NULL, # mid x coordinate for image
y = NULL, # mid y coordinate for image
width = NULL, # width of image (in x coordinate units)
interpolate = TRUE # (passed to graphics::rasterImage) A logical vector (or scalar) indicating whether to apply linear interpolation to the image when drawing.
){
if(is.null(x) | is.null(y) | is.null(width)){stop("Must provide args 'x', 'y', and 'width'")}
USR <- par()$usr # A vector of the form c(x1, x2, y1, y2) giving the extremes of the user coordinates of the plotting region
PIN <- par()$pin # The current plot dimensions, (width, height), in inches
DIM <- dim(obj) # number of x-y pixels for the image
ARp <- DIM[1]/DIM[2] # pixel aspect ratio (y/x)
WIDi <- width/(USR[2]-USR[1])*PIN[1] # convert width units to inches
HEIi <- WIDi * ARp # height in inches
HEIu <- HEIi/PIN[2]*(USR[4]-USR[3]) # height in units
rasterImage(image = obj,
xleft = x-(width/2), xright = x+(width/2),
ybottom = y-(HEIu/2), ytop = y+(HEIu/2),
interpolate = interpolate)
}
Example of use:
library(png)
myurl <- "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/Jupiter_%28transparent%29.png/242px-Jupiter_%28transparent%29.png"
z <- tempfile()
download.file(myurl,z,mode="wb")
pic <- readPNG(z)
file.remove(z) # cleanup
dim(pic)
png("plot.png", width = 5, height = 4, units = "in", res = 400)
par(mar = c(3,3,0.5,0.5))
image(volcano)
addImg(pic, x = 0.3, y = 0.5, width = 0.2)
dev.off()
You need to read your png or jpeg file through the png and jpeg packages. Then, with the rasterImage function you can draw the image on a plot. Say that your file is myfile.jpeg, you can try this:
require(jpeg)
img<-readJPEG("myfile.jpeg")
#now open a plot window with coordinates
plot(1:10,ty="n")
#specify the position of the image through bottom-left and top-right coords
rasterImage(img,2,2,4,4)
The above code will draw the image between the (2,2) and (4,4) points.
Just wanted to offer an alternative solution from the builtin "grid" package called grid.raster
From what I can tell it acts very much like rasterImage, but takes in normalized units, "npc" --a bonus in my opinion, and preserves aspect ratio unless you set both width and height. For my purposes, i just set either/or and the image seems to scale perfectly.
library(png)
library(grid)
x11()
mypng = readPNG('homer.png')
image(volcano)
grid.raster(mypng, x=.3, y=.3, width=.25) # print homer in ll conrner
grid.raster(mypng, x=.9, y=.7, width=.5) # print bigger homer in ur corner
while(!is.null(dev.list())) Sys.sleep(1)

Using scatterplot3d to plot a sphere

I have a matrix of the x,y,z coordinates of all amino acids. I plot the protein in 3D space using the following function:
make.Plot <- function(position.matrix, center, radius){
scatterplot3d(x = position.matrix[,4], y = position.matrix[,5], z = position.matrix[,6], type = 'o', color = 'blue')
}
Each row in the position.matrix is for a different amino acid. What I would like to do is modify the function so if I pass it a "center" which would correspond to a number in column 2 of position matrix (which lists the amino acid numberings), as well as a radius, I want a sphere with center at that amino acid.
For instance, if I pass it (position.matrix, 9, 3), I want it to plot a sphere of radius 3 around amino acid 9. I have uploaded a copy of the position data here:
http://temp-share.com/show/YgFHv2J7y
Notice that the row count is not always the canonical count as some residues are skipped. I will always pass it the "canonical" count...
Thanks for your help!
Here is a tested modification of your code. It adds a length-2 size vector for cex.symbols which is chosen by adding 1 to a logical vector:
make.Plot <- function(position.matrix, center, radius){
scatterplot3d(x = position.matrix[,4], y = position.matrix[,5],
z = position.matrix[,6], type = 'o',
cex.symbols=c(1,radius)[1+(position.matrix[,2]==center)], color = 'blue')
}
I wonder if what you really want is the rgl package. It has shapes and an interactive plotting environment. With scatterplot3d you could make the chose point red with this code:
myplot <- make.Plot(position.matrix, 3, 9)
myplot$points3d(position.matrix[3 , 4:6], col="red", cex=10)
I also located some code to draw a "parametric sphere" which can be adapted to creating a highlighting indicator:
myplot <- make.Plot(position.matrix, 3, 9)
a=seq(-pi,pi, length=10);
myplot$points3d(x=2*c(rep(1, 10) %*% t(cos(a)))+position.matrix[3 , 4] ,
y=2*c(cos(a) %*% t(sin(a)))+position.matrix[3 , 5],
z=2*c(sin(a) %*% t(sin(a)))+position.matrix[3 , 6],
col="red", cex=.2)

Resources