Manipulating x axis labelling for a feather plot - r

I have some wind speed and direction data over a course of some time and I need to plot it into a feather plot.
After surfing the web for some time, I find a function someone wrote to plot the feather plot that works for me (Thank you if you are reading this!!). My problem now is that I don't know how to manipulate the labelling of the x-axis.
After the plotting, the figure looks like this:
Now the x-axis doesn't look too bad here, but imagine I have 200 data points (and thus ticks) instead of 10, and the axis ticks can get a bit confusing. So I was hoping someone can help me manipulate the x-axis, specifically messing with the ticks.
The code to plot the figure is:
stg <- scan(what="", sep="\n")
9/20/15_12:00 2.597058824 157.9411765
9/21/15_0:00 2.177192982 185.1754386
9/21/15_12:00 2.577391304 189.2173913
9/22/15_0:00 1.984955752 237.4336283
9/22/15_12:00 3.993859649 252.6315789
9/23/15_0:00 1.613392857 175.5357143
9/23/15_12:00 3.849166667 216.8333333
9/24/15_0:00 2.138135593 117.0338983
9/24/15_12:00 3.32605042 216.302521
9/25/15_0:00 1.490178571 239.8214286
df <- read.table(textConnection(stg), sep="")
colnames(df) <- c("Time", "wsp", "wdir")
df$PTime <- as.POSIXct(df$Time, format="%m/%d/%y_%H:%M")
feather.plot2 <- function (r, theta, xpos, yref = 0, use.arrows = TRUE, col.refline = "lightgray",
fp.type = "s", main = "", xlab = "", ylab = "", xlabels = NULL,
...)
{
if (missing(xpos))
xpos <- 1:length(theta)
if (fp.type == "m")
theta <- 5 * pi/2 - theta
x <- r * cos(theta)
y <- r * sin(theta)
xmult <- diff(range(xpos))/(diff(range(y)) * 2)
x <- x * xmult
xlim <- range(c(xpos, x + xpos))
ylim <- range(c(y, yref))
oldpin <- par("pin")
xdiff <- xlim[2] - xlim[1]
ydiff <- ylim[2] - ylim[1]
plot(0, xlim = xlim, ylim = ylim, type = "n", main = main,
xlab = xlab, ylab = ylab, axes = TRUE, xaxt = "n")
box()
if (is.null(xlabels))
axis(1)
else axis(1, at = xpos, labels = xlabels)
abline(h = yref, col = col.refline)
if (use.arrows)
arrows(xpos, yref, xpos + x, y, length = 0.1, ...)
else segments(xpos, yref, xpos + x, y, ...)
par(pin = oldpin)
}
feather.plot2(df$wsp, df$wdir, fp.type="m", xlabels=df$PTime)
And what I want is something like having big ticks for 12:00, and smaller ticks for 0:00, like in this figure:
Although I don't know why the label for this figure comes out as "Sun - Thu" instead of dates...
The code for this figure is:
daterange=c(min(df$PTime), max(df$PTime))
plot(x=df$PTime, y=df$wsp, xaxt="n", type="l")
axis.POSIXct(1, at=seq(daterange[1], daterange[2], by="day"))
axis.POSIXct(1, at=seq(daterange[1], daterange[2], by="12 hours"), tcl = -0.3, labels=FALSE )
I've tried using using these axis commands on the feather plot, but it did not work. So I'd appreciate any help/advice. Thank you so much!!

I'm seeing two requests: Major and minor ticks; and More compact axis annotation of date-times. Step 1: Suppress the default axis creation. Step 2: The usual manor is to label the major ticks, so we would determine the proper location of those ticks and give a format specification to the labels. Step 3: place the minor tick marks. Most of this you've already figured out, and I would have thought the format problem was the easiest one to solve, so let's see:
plot(x=df$PTime, y=df$wsp, xaxt="n", type="l")
axis.POSIXct(1, at=seq(daterange[1], daterange[2], by="day"), format="%m-%d %H%P",
lwd.ticks=2)
axis.POSIXct(1, at=seq(daterange[1], daterange[2], by="12 hours"),
tcl = -0.3, labels=FALSE )
Seems to succeed at what I think are your goals. The use of by = "day" may be what leads the interpreter to choose the three letter abbrev of day names. (I don't really know.)

Related

R barplots: specify intervals of date-based x-axis

I've been producing different sets of charts, all in R base. I have a problem though with barplots. I've formatted the x-axis to show the dates by year, however, many years show up several times. I would like each year to only show up once.
Here's my example code:
library(quantmod)
start <- as.Date("01/01/2010", "%d/%m/%Y")
#Download FRED data
tickers <- c("WTISPLC", "DCOILBRENTEU")
fred <- lapply(tickers, function(sym) {na.omit(getSymbols(sym, src="FRED", auto.assign=FALSE, return.class = "zoo"))})
df <- do.call(merge, fred)
#Subset for start date
df <- subset(df, index(df)>=start)
#Create bar plot
par(mar = c(5,5,5,5))
barplot(df[,2], names.arg=format(index(df), "%Y"), ann=FALSE, bty="n", tck=-0, col=1:1, border=NA, space=0); title(main="Example chart", ylab="y-axis")
This example should be reproducible and show clearly what I mean. Now, I've been researching how to add a separate x-axis and how to define that axis. So, I've tried to add the following code:
#Plot bars but without x-axis
barplot(df[,2], names.arg=format(index(df), "%Y"), ann=FALSE, bty="n", tck=-0, xaxt="n", col=1:1, border=NA, space=0); title(main="Example chart", ylab="y-axis")
# Set x-axis parameters
x_min <- min(index(df))
x_max <- max(index(df))
xf="%Y"
#Add x-axis
axis.Date(1, at=seq(as.Date(x_min), x_max, "years"), format=xf, las=1, tck=-0)
This does not give me an error message, but it also does absolutely nothing in terms of drawing an x-axis.
Please do not provide a solution for ggplot. Even though I like ggplot, these barplots are part of a bigger project for me, all using R base and I would not like to introduce ggplot into this project now.
Thanks!
If you are not limited to barplot, you may use the following very simple solution using plot.zoo behind the screens:
# only use what you want, and avoid multiple plots
df2 <- df[ , 2]
# use zoo.plot's functionality
plot(df2, main = "Example Chart", ylab = "y-axis", xlab = "")
This yields the following plot:
I know it is not a barplot, but I don't see what a barplot would add here. Please let me know, whether this is what you want or not.
Edit 1
If you do want to use barplot you may use the following code:
### get index of ts in year format
index_y <- format(index(df), "%Y")
### logical vector with true if it is the start of a new year
index_u <- !duplicated(index_y)
### index of start of new year for tick marks
at_tick <- which(index_u)
### label of start of new year
labels <- index_y[index_u]
### draw barplot without X-axis, and store in bp
### bp (bar midpoints) is used to set the ticks right with the axis function
bp <- barplot(df[,2], xaxt = "n", ylab= "y-axis")
axis(side = 1, at = bp[at_tick] , labels = labels)
yielding the following plot:
Please let me know, whether this is what you want.
Edit 2
We need to take into account two bits of information, when explaining why the ticks and labels group together at the left-hand side.
(1) in barplot, space defines the amount of space before each bar (as a fraction of the average bar width). In our case, it defaults to around zero (see ?barplot for details). In the illustration below, we use spaces of 0.0, 0.5, and 2.0
(2) Barplot returns a numeric vector with the midpoints of the bars drawn (again see the help pages for more detailed info). We can use these midpoints to add information to the graph, like we do in the following excerpt: after storing the result of barplot in bp, we use bp to set the ticks: axis(... at = bp[at_tick] ... ).
When we add space, the location of the bar midpoints change. So, when we want to use the bar midpoints after adding space, we need to be sure we have the right information. Simply stated, use the vector returned by barplot with the call where you added space. If you don't, the graph will be messed up. In the below, if you continue to use the bar-midpoints of the call with (space=0), and you increase space, the ticks and labels will group at the left-hand side.
Below, I illustrate this with your data limited to 3 months in 2017.
In the top layer 3 barplots are drawn with space equal to 0.0, 0.5 and 2.0. The information used to calculated the location of ticks and labels is recalculated and saved at every plot.
In the bottom layer, the same 3 barplots are drawn, but the information used to draw the ticks and labels is only created with the first plot (space=0.0)
# Subset for NEW start for illustration of space and bp
start2 <- as.Date("01/10/2017", "%d/%m/%Y")
df2 <- subset(df, index(df)>=start2)
### get index of ts in month format, define ticks and labels
index_y2 <- format(index(df2), "%m")
at_tick2 <- which(!duplicated(index_y2))
labels2 <- index_y2[!duplicated(index_y2)]
par(mfrow = c(2,3))
bp2 <- barplot(df2[,2], xaxt = "n", ylab= "y-axis", space= 0.0, main ="Space = 0.0")
axis(side = 1, at = bp2[at_tick2] , labels = labels2)
bp2 <- barplot(df2[,2], xaxt = "n", ylab= "y-axis", space= 0.5, main ="Space = 0.5")
axis(side = 1, at = bp2[at_tick2] , labels = labels2)
bp2 <- barplot(df2[,2], xaxt = "n", ylab= "y-axis", space= 2.0, main ="Space = 2.0")
axis(side = 1, at = bp2[at_tick2] , labels = labels2)
### the lower layer
bp2 <- barplot(df2[,2], xaxt = "n", ylab= "y-axis", space= 0.0, main ="Space = 0.0")
axis(side = 1, at = bp2[at_tick2] , labels = labels2)
barplot(df2[,2], xaxt = "n", ylab= "y-axis", space= 0.5, main ="Space = 0.5")
axis(side = 1, at = bp2[at_tick2] , labels = labels2)
barplot(df2[,2], xaxt = "n", ylab= "y-axis", space= 2.0, main ="Space = 2.0")
axis(side = 1, at = bp2[at_tick2] , labels = labels2)
par(mfrow = c(1,1))
Have a look here:
Top layer: bp recalculated every time
Bottom layer: bp space=0 reused
Cutting and pasting the commands in your console may illustrate the effects better than the pic above.
I hope this helps.
You could use the axis function, I used match to obtain the indices of the dates on the axis:
space=1
#Plot bars but without x-axis
barplot(df[,2], names.arg=format(index(df), "%Y"), ann=FALSE, bty="n", tck=-0, xaxt="n",
col=1:1, border=NA, space=space); title(main="Example chart", ylab="y-axis")
# Set x-axis parameters
x_min <- min(index(df))
x_max <- max(index(df))
#Add x-axis
axis(1, at=match(seq(as.Date(x_min), x_max, "years"),index(df))*(1+space),
labels = format(seq(as.Date(x_min), x_max, "years"),"%Y"),lwd=0)
Hope this helps!

R plot,why is introducing of axis limits creating havoc?

My code
library(Hmisc)
r1 <- read.table("mt7.1r1.rp", header = FALSE)
r2 <- read.table("mt7.1r2.rp", header = FALSE)
r3 <- read.table("mt7.2r1.rp", header = FALSE)
r4 <- read.table("mt7.2r2.rp", header = FALSE)
p1=r1[1]
per1=log10(p1)
p2=r2[1]
per2=log10(p2)
p3=r3[1]
per3=log10(p3)
p4=r4[1]
per4=log10(p4)
m1=nrow(per1)
m2=nrow(per2)
m3=nrow(per3)
m4=nrow(per4)
xmin <- floor( min(per1,per2,per3,per4))
xmax <- ceiling( max(per1,per2,per3,per4))
lxmax=10^(xmax)
lxmin=10^(xmin)
rhoaxy = r2[3]
phaxy = r2[5]
rhoayx = r3[3]
phayx = r3[5]
rhoaxx = r1[3]
phaxx = r1[5]
rhoayy = r4[3]
phayy = r4[5]
per2=unname(per2)
per2=unlist(per2)
per3=unname(per3)
per3=unlist(per3)
rhoaxy=unname(rhoaxy)
rhoaxy=unlist(rhoaxy)
rhoaxy=log10(rhoaxy)
rhoayx=unname(rhoayx)
rhoayx=unlist(rhoayx)
rhoayx=log10(rhoayx)
ymin1=floor(min(rhoaxy)-1)
ymax1=ceiling(max(rhoaxy)+1)
ymin2=floor(min(rhoayx)-1)
ymax2=ceiling(max(rhoayx)+1)
ymin=min(ymin1,ymin2)
ymax=max(ymax1,ymax2)
png("withlim.png")
plot(per2,rhoaxy, col='red', xlab='Per (s)', ylab = 'Rho-xy/yx',ylim=c(ymin, ymax))
par(new=TRUE)
plot(per3,rhoayx, col='green', xaxt='n', xlab= NA, yaxt = 'n', ylab = NA)
dev.off()
The image I got
If I delete ylim
My question is,why are the axis limits changing the image content?The values from the second image correspond to proper data values.The first image is with values that do not represent rhoaxy and rhoayx.
It is difficult to test without the data, but my guess is that, on the second plot, the Y axis is not the same, although the Y axis is not plot.
So you've got the superposition of 2 plot, with a different Y axis.
If you want the same ylim on both plot, add ylim=c(ymin, ymax) on the second plot also.
If it does not work, please provide data example, so we can test.

Reverse the scale of the x axis in a plot

I have created a plot in R and my own custom x and y axes. I would like the x axis to be displayed in a reverse order (1-0 by -.02). I have read numerous posts and threads that suggest using xlim and reverse range but I just can't seem to make it work. Once plotted I am also converting the axes labels to percentages by multiplying by 100 (as you will see in the code). Here is what I have so far;
plot(roc.val, xlab = "Specificity (%)", ylab = "Sensitivity (%)", axes = FALSE)
axis(2, at = seq(0,1,by=.2), labels = paste(100*seq(0,1, by=.2)), tick = TRUE)
axis(1, at = seq(0,1,by=.2), labels = paste(100*seq(0,1, by=.2)), tick = TRUE)
How can I reverse the x axis scale so that the values begin at 100 and end at 0 with increments of 20?
I think this creates a plot in which the y-axis is in reverse order:
x <- seq(-4, 4, length = 10)
y <- exp(x) / (1 + exp(x))
plot(x,y, ylim = rev(range(y)))
This removes the axis values:
x <- seq(-4, 4, length = 10)
y <- exp(x) / (1 + exp(x))
plot(x,y, ylim = rev(range(y)), labels = FALSE)
I guess you can assign the axis values you want then with a variation of your lines:
axis(2, at = seq(0,1,by=.2), labels = paste(100*seq(0,1, by=.2)), tick = TRUE)
axis(1, at = seq(0,1,by=.2), labels = paste(100*seq(0,1, by=.2)), tick = TRUE)
df <- data.frame(x=seq(0,1, length.out=50), y=seq(0, 1, length.out=50))
plot(df)
df$x1 <- (max(df$x) - df$x)/ (max(df$x) - min(df$x))
plot(df$x1, df$y, axes=F, xlab = "Specificity (%)", ylab = "Sensitivity (%)")
axis(2, at = seq(0,1,by=.2), labels = paste(100*seq(0,1, by=.2)), tick = TRUE)
axis(1, at = seq(0,1,by=.2), labels = paste(100*seq(1,0, by=-.2)), tick = TRUE)
Adapting Mark Miller's answer to solve a similar problem (I found this topic by looking for the solution) and I found a variation of his solution in https://tolstoy.newcastle.edu.au/R/help/05/03/0342.html.
Basically if you want to reverse the X-axis values in the plot, instead of using ylim=rev(range(y)), you can use xlim=rev(c(-4,4)).
x <- seq(-4, 4, length = 10)
y <- exp(x) / (1 + exp(x))
par(mfrow=c(1,2))
plot(x, y, ylim=range(y), xlim=c(-4, 4))
plot(x, y, ylim=range(y), xlim=rev(c(-4, 4)))
plot1
And if you want to keep the x-axis values in the true order, you can use this:
par(mfrow=c(1,1))
plot(x, y, ylim=range(y), xlim=c(-4, 4), axes=FALSE)
par(new=TRUE)
plot(-100, -100, ylim=range(y), xlim=c(-4, 4), axes=FALSE, xlab="", ylab="", main="")
axis(1, at = seq(-4,4,by=1), labels = seq(-4,4,by=1), tick = TRUE)
axis(2, at = seq(0,1,by=.2), labels = paste(100*seq(0,1, by=.2)), tick = TRUE)
plot2
I'm posting this solution because I needed something very straightforward to solve my problem. And the solution for it needed the plot with the X-axis value in the correct order (and not reversed).
First, check out the ggplot2 library for making beautiful and extendable graphics. It is part of the Tidyverse approach to R and a gamechanger if you have not been exposed to it.
For example, to solve your issue using ggplot, you simply add the term scale_x_reverse() to your graphic.
See: http://ggplot.yhathq.com/docs/scale_x_reverse.html

3d plot of 2d simplex in R

Is there a way to reproduce the following plot in R?
EDIT
This is what I could do with persp() in base R and plot_ly in plotly. Also a bit ugly.
x <- seq(0,1,0.01)
y <- seq(0,1,0.01)
f <- function(x,y){ z <- -x - y + 1 }
z <- outer(x,y,f)
z <- ifelse(z<0,NA,z)
persp(x, y, z, theta = 30, phi = 30, expand = 0.5, col = "lightblue")
plot_ly(x=x,y=y,z=z,type="surface") %>% layout(xaxis=list(range=c(0,1)), yaxis=list(range=c(0,1)), zaxis=list(range=c(0,1)))
BTW...the matplotlib plots were obtained here:
http://blog.bogatron.net/blog/2014/02/02/visualizing-dirichlet-distributions/
Using persp in base R I was able to get this far:
persp(0:1, 0:1,
matrix(c(1,0,0,NA), nrow=2),
col="green", theta=60,
xlab= "theta_1",
ylab = "theta_2",
zlab="theata_3")
But I could not figure out how to do a few things, including greek symbols on axes.
I am turning this into a wiki in case any persp experts out there want to finish the job.
This is a little ugly/still incomplete but at least shows one way to get Greek labels in.
pp <- persp(0:1, 0:1,
matrix(c(2,0,0,NA), nrow=2),
col="green", theta=60,
xlab= "",
ylab ="",
zlab="",
ticktype="detailed",
nticks=1)
text(trans3d(0.5,-0.1,-0.1,pp),labels=expression(theta[1]))

R changing format of scale on y-axis

I have a plot that has $-amounts and dates on y and x axis respectively. Currently the dollar amounts range from $0-15 million. Something like this:
x <- rnorm(20)^2 * 1000000
plot(x)
R does stuff like '1.0e+07' instead of '10,000,000' and also orients the text vertically instead of horizontally.
My questions are:
1) how would I get the scale text to be horizontally oriented?
2) how would I get R to use 10MM instead of '10,000,000' or '1.0e+07'?
1) See the scipen option in ?options which is a penalty against the use of scientific notation. For better control, you need to plot the axis by hand with labels you want.
2) See las in ?par which controls to orientation crudely of axis labels.
For 1):
x <- rnorm(20)^2 * 10000000
layout(matrix(1:2, ncol = 2))
plot(x)
getOption("scipen")
opt <- options("scipen" = 20)
getOption("scipen")
plot(x)
options(opt)
layout(1)
which gives
To plot your own axis try
plot(x / 10000000, axes = FALSE)
axis(1)
pts <- pretty(x / 10000000)
axis(2, at = pts, labels = paste(pts, "MM", sep = ""))
box()
Which gives
Where we use pretty() to select pretty locations for the ticks just as R would and then add a custom axis. Notice how we suppress axis drawing in the plot() call and then add back the axes and the plot frame with calls to axis() and box().
For 2) combining with 1)
opt <- options("scipen" = 20)
op <- par(mar = c(5,7,4,2) + 0.1) ## extra margin to accommodate tick labs
x <- rnorm(20)^2 * 10000000
plot(x, las = 1, ylab = "") ## no y-axis label
title(ylab = "label", line = 5.5) ## need to plot the axis label
par(op)
options(opt)
Which gives
Notice how we use las in the plot() call, and we need to create some extra margin space to accommodate the tick labels. We also need to plot the label by hand otherwise R will stick it in amongst the tick labels.
For the custom axis labels, add the las = 1 to the axis() call:
op <- par(mar = c(5,5,4,2) + 0.1)
plot(x / 10000000, axes = FALSE, ylab = "")
axis(1)
pts <- pretty(x / 10000000)
axis(2, at = pts, labels = paste(pts, "MM", sep = ""), las = 1)
title(ylab = "my label", line = 4)
box()
par(op)
Which produces
Use axis with custom labels. First, divide your data by 1 million. And then create a series with the MM notation using paste()
y <-rnorm(20)^2 * 1000000 /1000000
x <-11:30
plot(x,y, yaxt="n")
my.axis <-paste(axTicks(2),"MM",sep="")
axis(2,at=axTicks(2), labels=my.axis)
The text is now horizontal. But if you run into a problem use, las=1 to force labels to be horizontal.
axis(2,at=axTicks(2), labels=my.axis, las=1)

Resources