I want to make a plot in R where the spacing between ticks on the y-axis all have the same distance and the tick labels are a custom list of values, for example:
set.seed(1)
n <- 10
x <- 1:n
y <- rnorm(n)
plot(x, y, axes = FALSE, ylim=c(-2,2))
axis(1)
axis(2, seq(-2,2,1), c(-100,-10,0,5,1000))
gets me a plot where the distance between the y-axis ticks are equal but clearly the true distance between values is not equal, i.e., -100 to - 10 is not the same distance as 5 to 1000, numerically.
Now this works, but the problem with this solution is that the data is not correctly mapped to the right position in the plot. As in, I would like for the data to be plotted correctly based on the original scale. So either I need a way to simply change the y-axis to be plotted on a different scale, or for the data to be transformed to a new scale that matches my axis(2, seq(-2,2,1), c(-100,-10,0,5,1000)) command.
I guess what I am saying is I want the equivalent of plot(x, y, log = "y") but I don't actually want the log scale, I just want the tick marks to be even spaced based on values I want shown, i.e., -100,-10,0,5,1000
Your example is a bit hard to implement because you are setting the plot boundaries from -2 to 2 and then wanting axis labels that go from -100 to 1000. It should work if you use at and set the boundaries of the initial plot to match the axis parameters. I've modified your example to spread the data across the plot more evenly:
set.seed(1)
n <- 10
x <- 1:n
y <- 100*rnorm(n)
yticks = c(-100,-10,0,5,200)
plot(x, y, axes = FALSE, ylim=c(-100,200))
axis(1)
axis(2,at = yticks,labels=yticks)
Related
I'm trying to use base R (and would like to stick to it for this problem) to plot a specific portion of a dataset.
My example data looks like below:
x <- c(1:100)
y <- sort(runif(100, min=0, max=1000))
When I plot this with plot(x,y, type='l'), I get a plot with a y axis that shows 0 to 1000. However, when I plot only a specific x range, my y axis still shows 0 to 1000. I would like to zoom in to reduce the y axis range.
For example,
plot(x,y, type='l', xlim=c(40,60))
plot(x,y, type='l', xlim=c(80,90))
both produces plots with a y axis that ranges c(0,1000). But I'd like to zoom in so that the y axis range for the first plot is something like c(300,700) and that for the second plot is c(700,1000). (300, 700 and 1000 are all arbitrary numbers just to illustrate the purpose to really zoom into the plot). Is there a way to do this without setting specific ylim?
I'd like to avoid using ylim because I'm plotting and saving in a for loop and I can't write a ylim that is suitable for all plots. I've thought of doing something like ylim = max(y)*1.5, but again, since I'm cutting the y values off based on xlim, this doesn't help with zooming in whenever xlim changes.
Subset the relevant data and plot that
lower = 40
upper = 60
ind = which(x >= lower & x <= upper)
plot(x[ind], y[ind], type = "l")
Let's consider a vector and plot it.
s1 <- sample(100:1000,32,replace = T)
plot(s1)
The plot I get has a Y-Axis that ranges from 0-1000 with points in the intervals of 200 (0,200,400,600,800,1000) and this is happening implicitly.
If I use ylim argument, apparently or to be honest, evidently, I can now have a custom range,
plot(s1,ylim = c(0,1500))
The points on Y Axis now are 0-1500 as indicated but with the points in the intervals of 500 (0,500,1000,1500), this is happening without my control.
My question, how can I have custom points with custom intervals on the X or Y axis?
use axis() to set your limits : on either x, y, or both
s1 <- sample(100:1000,32,replace = T)
plot(s1, yaxt = "n") # `yaxt` prevents y-axis labels to be printed
axis(2, yaxp=c(10, 1000, 10), las=2) # 'las' helps to align the tick mark labels along the axis or perpendicular
# 'yaxp' helps to set the break points you desire. Learn more from ?par
I have a perspective plot of a locfit model and I wish to add two things to it
Predictor variables as points in the 3D space
Color the surface according to the Z axis value
For the first, I have tried to use the trans3d function. But I get the following error even though my variables are in vector format:
Error in cbind(x, y, z, 1) %*% pmat : requires numeric/complex matrix/vector arguments
Here is a snippet of my code
library(locfit)
X <- as.matrix(loc1[,1:2])
Y <- as.matrix(loc1[,3])
zz <- locfit(Y~X,kern="bisq")
pmat <- plot(zz,type="persp",zlab="Amount",xlab="",ylab="",main="Plains",
phi = 30, theta = 30, ticktype="detailed")
x1 <- as.vector(X[,1])
x2 <- as.vector(X[,2])
Y <- as.vector(Y)
points(trans3d(x1,x2,Y,pmat))
My "loc1" data can be found here - https://www.dropbox.com/s/0kdpd5hxsywnvu2/loc1_amountfreq.txt?dl=0
TL,DR: not really in plot.locfit, but you can reconstruct it.
I don't think plot.locfit has good support for this sort of customisation. Supposedly get.data=T in your plot call will plot the original data points (point 1), and it does seem to do so, except if type="persp". So no luck there. Alternatively you can points(trans3d(...)) as you have done, except you need the perspective matrix returned by persp, and plot.locfit.3d does not return it. So again, no luck.
For colouring, typically you make a colour scale (http://r.789695.n4.nabble.com/colour-by-z-value-persp-in-raster-package-td4428254.html) and assign each z facet the colour that goes with it. However, you need the z-values of the surface (not the z-values of your original data) for this, and plot.locfit does not appear to return this either.
So to do what you want, you'll essentially be recoding plot.locfit yourself (not hard, though just cludgy).
You could put this into a function so you can reuse it.
We:
make a uniform grid of x-y points
calculate the value of the fit at each point
use these to draw the surface (with a colour scale), saving the perspective matrix so that we can
plot your original data
so:
# make a grid of x and y coords, calculate the fit at those points
n.x <- 20 # number of x points in the x-y grid
n.y <- 30 # number of y points in the x-y grid
zz <- locfit(Total ~ Mex_Freq + Cal_Freq, data=loc1, kern="bisq")
xs <- with(loc1, seq(min(Mex_Freq), max(Mex_Freq), length.out=20))
ys <- with(loc1, seq(min(Cal_Freq), max(Cal_Freq), length.out=30))
xys <- expand.grid(Mex_Freq=xs, Cal_Freq=ys)
zs <- matrix(predict(zz, xys), nrow=length(xs))
# generate a colour scale
n.cols <- 100 # number of colours
palette <- colorRampPalette(c('blue', 'green'))(n.cols) # from blue to green
# palette <- colorRampPalette(c(rgb(0,0,1,.8), rgb(0,1,0,.8)), alpha=T)(n.cols) # if you want transparency for example
# work out which colour each z-value should be in by splitting it
# up into n.cols bins
facetcol <- cut(zs, n.cols)
# draw surface, with colours (col=...)
pmat <- persp(x=xs, y=ys, zs, theta=30, phi=30, ticktype='detailed', main="plains", xlab="", ylab="", zlab="Amount", col=palette[facetcol])
# draw your original data
with(loc1, points(trans3d(Mex_Freq,Cal_Freq,Total,pmat), pch=20))
Note - doesn't look that pretty! might want to adjust say your colour scale colours, or the transparency of the facets, etc. Re: adding legend, there are some other questions that deal with that.
(PS: what a shame ggplot doesn't do 3D scatter plots.)
I'm building a plot in R and I have used the plot() function, with log="y" parameter.
Does that mean that ONLY the y-axis labels will be converted in log scale OR that also the y-coordinates of my data will be converted in log-scale?
Thank you
When using log = "y" it plots the log-transformed y-values with the labels on the original scale -- the opposite of what you seem to suggest.
Compare these three plots:
x <- rnorm(50)
y <- 2*exp(x) + rexp(50)
plot(x, y) # y-scale, y-scale-labels
plot(x, y, log = "y") # log-y-scale, y-scale-labels
plot(x, log(y)) # log-y-scale, log-y-scale labels
Notice that the last two plots only differs in the y-axis labels. Both are still correct as the axis titles are also different.
I have a problem in plotting uneven scale plot on x axis with R
Here is an example:
plot(1:100,1:100)
will give the equal tick space on x axis.
However, I want to show the graph with first half of space showing 1 to 10, and the left half space showing 10 to 100, so the points in the 10 to 100 more dense, and points in 1:10 are easier to see. How to do it with R?
Like this:
This is not an easy one-off task to complete. You'll actually need to transform to the scaled data and supply custom tick marked axes. Any reason you haven't considered simply logging the x-axis instead? (supplying the option plot(x, y, log='x') will do that).
What I think you've described is this:
xnew <- ifelse(x<10, x, x/10)
plot(xnew, y, axes=FALSE, xlab='x')
axis(1, at=c(0, 10, 20), labels=c(0, 10, 100))
axis(2)
box()
You could log the x axis:
x<-1:100
y<-1:100
plot(log(x,base=10),y,axes=F)
axis(2)
axis(1,at=0:2,labels=10^(0:2))
For a logarithmic axis, use:
plot(x,y,log="x") ## specifies which axis to put on log scale
For determining how many "tick marks" to use, check
par()$lab
Default is 5,5,7. To put more x axis labels, do
par(lab=c(10,5,7))
And for y:
par(lab=c(5,10,7))