I have to plot a physical variable over a world map at differents moments. So i have to make many plot as how many moments i have to plot. The problem is that my routine set the end of the scale by default, and this make the reading of the plot difficult. I would like to fix the end of the scale, in order to have one scale for all the plots. This is piece of an old code i would reuse
require(reshape)
require(mapdata)
require(mapproj)
df <- read.table('/media/Lacie2/dati/hy.dat',head=F)
names(df) <- c("value", "x", "y")#, "t")
dfc <- cast(df[ ,-4], x ~ y)
mm<-as.matrix(dfc,ncol=480,nrow=241)
filled.contour(x=seq(0,360,length.out=480),y=seq(-90,90,length.out=241),mm,
color.palette = colorRampPalette(c("lightblue", "blue","violet", "black")),
xlab = "Longitude (°)", ylab = "Latitude (°)",
plot.axes = {axis(1); axis(2);
map('world2Hires',
xlim = c(0, 360),
ylim = c(-90, 90),
add = T, col = "black")}
)
I don't understand how to fix the endscale of the ladder. How can i do it?
If you want to plot colors only up to a maximum, then just 'trim' the value that you pass to the plot routine with:
df$trimval <- pmin(df$value, 2)
# the range in the example below is roughly -4.5 to 4.5
... and plot using that value as the z-argument to contour.plot. Indented code and random "value" argument below:
require(reshape)
require(mapdata)
require(mapproj)
df <- data.frame(value=rnorm( 480*241), x=seq(0,360,length.out=480),y=seq(-90,90,length.out=241) )
df$trimval <- pmin(df$value, 2)
dfc <- cast(df[-1], x ~ y)
mm<-as.matrix(dfc,ncol=480,nrow=241)
filled.contour(x=seq(0,360,length.out=480),y=seq(-90,90,length.out=241),mm,
color.palette = colorRampPalette(c("lightblue", "blue","violet", "black")),
xlab = "Longitude (°)", ylab = "Latitude (°)",
plot.axes = {axis(1); axis(2);
map('world2Hires',
xlim = c(0, 360),
ylim = c(-90, 90),
add = T, col = "black")}
)
The color range is therefore maxxed out at 2 and all of the values above 2 are plotted with the color given to 2. (I might mention that I tried using zlim and the results were not as I imagined you would want.)
Related
I am doing quarterly analysis, for which I want to plot a graph. To maintain continuity on x axis I have turned quarters into factors. But then when I am using plot function and trying to color it red, the col argument is not working.
An example:
quarterly_analysis <- data.frame(Quarter = as.factor(c(2020.1,2020.2,2020.3,2020.4,2021.1,2021.2,2021.3,2021.4)),
AvgDefault = as.numeric(c(0.24,0.27,0.17,0.35,0.32,0.42,0.38,0.40)))
plot(quarterly_analysis, col="red")
But I am getting the graph in black color as shown below:
Converting it to a factor is not ideal to plot unless you have multiple values for each factor - it tries to plot a box plot-style plot. For example, with 10 observations in the same factor, the col = "red" color shows up as the fill:
set.seed(123)
fact_example <- data.frame(factvar = as.factor(rep(LETTERS[1:3], 10)),
numvar = runif(30))
plot(fact_example$factvar, fact_example$numvar,
col = "red")
With only one observation for each factor, this is not ideal because it is just showing you the line that the box plot would make.
You could use border = "red:
plot(quarterly_analysis$Quarter,
quarterly_analysis$AvgDefault, border="red")
Or if you want more flexibility, you can plot it numerically and do a little tweaking for more control (i.e., can change the pch, or make it a line graph):
# make numeric x values to plot
x_vals <- as.numeric(substr(quarterly_analysis$Quarter,1,4)) + rep(seq(0, 1, length.out = 4))
par(mfrow=c(1,3))
plot(x_vals,
quarterly_analysis$AvgDefault, col="red",
pch = 7, main = "Square Symbol", axes = FALSE)
axis(1, at = x_vals,
labels = quarterly_analysis$Quarter)
axis(2)
plot(x_vals,
quarterly_analysis$AvgDefault, col="red",
type = "l", main = "Line graph", axes = FALSE)
axis(1, at = x_vals,
labels = quarterly_analysis$Quarter)
axis(2)
plot(x_vals,
quarterly_analysis$AvgDefault, col="red",
type = "b", pch = 7, main = "Both", axes = FALSE)
axis(1, at = x_vals,
labels = quarterly_analysis$Quarter)
axis(2)
Data
set.seed(123)
quarterly_analysis <- data.frame(Quarter = as.factor(paste0(2019:2022,
rep(c(".1", ".2", ".3", ".4"),
each = 4))),
AvgDefault = runif(16))
quarterly_analysis <- quarterly_analysis[order(quarterly_analysis$Quarter),]
I am planning to reproduce the attached figure, but I have no clue how to do so:
Let´s say I would be using the CO2 example dataset, and I would like to plot the relative change of the Uptake according to the Treatment. Instead of having the three variables in the example figure, I would like to show the different Plants grouped for each day/Type.
So far, I managed only to get this bit of code, but this is far away from what it should look like.
aov1 <- aov(CO2$uptake~CO2$Type+CO2$Treatment+CO2$Plant)
plot(TukeyHSD(aov1, conf.level=.95))
Axes should be switched, and I would like to add statistical significant changes indicated with letters or stars.
You can do this by building it in base R - this should get you started. See comments in code for each step, and I suggest running it line by line to see what's being done to customize for your specifications:
Set up data
# Run model
aov1 <- aov(CO2$uptake ~ CO2$Type + CO2$Treatment + CO2$Plant)
# Organize plot data
aov_plotdata <- data.frame(coef(aov1), confint(aov1))[-1,] # remove intercept
aov_plotdata$coef_label <- LETTERS[1:nrow(aov_plotdata)] # Example labels
Build plot
#set up plot elements
xvals <- 1:nrow(aov_plotdata)
yvals <- range(aov_plotdata[,2:3])
# Build plot
plot(x = range(xvals), y = yvals, type = 'n', axes = FALSE, xlab = '', ylab = '') # set up blank plot
points(x = xvals, y = aov_plotdata[,1], pch = 19, col = xvals) # add in point estimate
segments(x0 = xvals, y0 = aov_plotdata[,2], y1 = aov_plotdata[,3], lty = 1, col = xvals) # add in 95% CI lines
axis(1, at = xvals, label = aov_plotdata$coef_label) # add in x axis
axis(2, at = seq(floor(min(yvals)), ceiling(max(yvals)), 10)) # add in y axis
segments(x0=min(xvals), x1 = max(xvals), y0=0, lty = 2) #add in midline
legend(x = max(xvals)-2, y = max(yvals), aov_plotdata$coef_label, bty = "n", # add in legend
pch = 19,col = xvals, ncol = 2)
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.
I am trying to plot rose diagrams/ circular histograms on specific coordinates on a map analogous to drawing pie charts on a map as in the package mapplots.
Below is an example generated with mapplots (see below for code), I'd like to replace the pie charts with rose diagrams
The package circular lets me plot the rose diagrams, but I am unable to integrate it with the mapplots package. Any suggestions for alternative packages or code to achieve this?
In response to the question for the code to make the map. It's all based on the mapplots package. I downloaded a shapefile for the map (I think from http://www.freegisdata.org/)
library(mapplots)
library(shapefiles)
xlim = c(-180, 180)
ylim = c(-90, 90)
#load shapefile
wmap = read.shapefile ("xxx")
# define x,y,z for pies
x <- c(-100, 100)
y <- c(50, -50)
z1 <- c(0.25, 0.25, 0.5)
z2 <- c(0.5, 0.2, 0.3)
z <- rbind(z1,z2)
# define radii of the pies
r <- c(5, 10)
# it's easier to have all data in a single df
plot(NA, xlim = xlim, ylim = ylim, cex = 0.75, xlab = NA, ylab = NA)
draw.shape(wmap, col = "grey", border = "NA")
draw.pie(x,y,z,radius = r, col=c("blue", "yellow", "red"))
legend.pie (x = -160, y = -70, labels = c("0", "1", "2"), radius = 5,
bty = "n", cex = 0.5, label.dist=1.5, col = c("blue", "yellow", "red"))
the legend for the pie size can then be added using legend.bubble
Have a look at this example, you can use the map as background an plot your rose diagrams withPlotrix or ggplot2. In either case you would want to overlay multiple of these diagrams on top of your map which is easy to do in ggplot, just have a look at the example.
I discovered subplot() in the package Hmisc, which seems to do exactly what I wanted. Below is my solution (without the map in the background, which can be plotted using mapplots). I am open to suggestions on how to improve this though...
library(Hmisc)
library (circular)
dat <- data.frame(replicate(2,sample(0:360,10,rep=TRUE)))
lat <- c(50, -40)
lon <- c(-100, 20)
# convert to class circular
cir.dat <- as.circular (dat, type ='angles', units = 'degrees', template = 'geographic', modulo = 'asis', zero = 'pi/2', rotation = 'clock')
# function for subplot, plots relative frequencies, see rose.diag for how to adjust the plot
sub.rose <- function(x){
nu <- sum(!is.na(x))
de <- max(hist(x, breaks = (seq(0, 360, 30)), plot = FALSE)$counts)
prop <- nu/de
rose.diag(x, bins = 12, ticks = FALSE, axes = FALSE,
radii.scale = 'linear',
border = NA,
prop = prop,
col = 'black'
)
}
plot(NA, xlim = xlim, ylim = ylim)
for(i in 1:length(lat)){
subplot(sub.rose(cir.dat[,i]), x = lon[i], y = lat[i], size = c(1, 1))
}
I have to plot some plot(x,y) scatters, but i would like the points to be color coded based on the value of a continuous variable z.
I would like a temperature palette (from dark blue to bright red). I tried with Rcolorbrewer however the the RdBu palette (which resembles the temperature palette) uses white for the middle values which looks very bad.
I would also like to plot a legend explaining the color coding with a sample of colors and corresponding values.
Any ideas if this can be performed easily in R? No ggplot please!
Season greetings to everybody
Building off of #BenBolker's answer, you can do the legend if you take a peek at the code for filled.contour. I hacked that function apart to look like this:
scatter.fill <- function (x, y, z,
nlevels = 20, plot.title, plot.axes,
key.title, key.axes, asp = NA, xaxs = "i",
yaxs = "i", las = 1,
axes = TRUE, frame.plot = axes, ...)
{
mar.orig <- (par.orig <- par(c("mar", "las", "mfrow")))$mar
on.exit(par(par.orig))
w <- (3 + mar.orig[2L]) * par("csi") * 2.54
layout(matrix(c(2, 1), ncol = 2L), widths = c(1, lcm(w)))
par(las = las)
mar <- mar.orig
mar[4L] <- mar[2L]
mar[2L] <- 1
par(mar = mar)
#Some simplified level/color picking
levels <- seq(min(z),max(z),length.out = nlevels)
col <- colorRampPalette(c("blue","red"))(nlevels)[rank(z)]
plot.new()
plot.window(xlim = c(0, 1), ylim = range(levels), xaxs = "i",
yaxs = "i")
rect(0, levels[-length(levels)], 1, levels[-1L], col = colorRampPalette(c("blue","red"))(nlevels)
if (missing(key.axes)) {
if (axes)
axis(4)
}
else key.axes
box()
if (!missing(key.title))
key.title
mar <- mar.orig
mar[4L] <- 1
par(mar = mar)
#Simplified scatter plot construction
plot(x,y,type = "n")
points(x,y,col = col,...)
if (missing(plot.axes)) {
if (axes) {
title(main = "", xlab = "", ylab = "")
Axis(x, side = 1)
Axis(y, side = 2)
}
}
else plot.axes
if (frame.plot)
box()
if (missing(plot.title))
title(...)
else plot.title
invisible()
}
And then applying the code from Ben's example we get this:
x <- runif(40)
y <- runif(40)
z <- runif(40)
scatter.fill(x,y,z,nlevels = 40,pch = 20)
which produces a plot like this:
Fair warning, I really did just hack apart the code for filled.contour. You will likely want to inspect the remaining code and remove unused bits, or fix parts that I rendered non-functional.
Here some home-made code to achieve it with default packages (base, graphics, grDevices) :
# Some data
x <- 1:1000
y <- rnorm(1000)
z <- 1:1000
# colorRamp produces custom palettes, but needs values between 0 and 1
colorFunction <- colorRamp(c("darkblue", "black", "red"))
zScaled <- (z - min(z)) / (max(z) - min(z))
# Apply colorRamp and switch to hexadecimal representation
zMatrix <- colorFunction(zScaled)
zColors <- rgb(zMatrix, maxColorValue=255)
# Let's plot
plot(x=x, y=y, col=zColors, pch="+")
For StanLe, here is the corresponding legend (to be added by layout or something similar) :
# Resolution of the legend
n <- 10
# colorRampPalette produces colors in the same way than colorRamp
plot(x=NA, y=NA, xlim=c(0,n), ylim=0:1, xaxt="n", yaxt="n", xlab="z", ylab="")
pal <- colorRampPalette(c("darkblue", "black", "red"))(n)
rect(xleft=0:(n-1), xright=1:n, ybottom=0, ytop=1, col=pal)
# Custom axis ticks (consider pretty() for an automated generation)
lab <- c(1, 500, 1000)
at <- (lab - min(z)) / (max(z) - min(z)) * n
axis(side=1, at=at, labels=lab)
This is a reasonable solution -- I used blue rather than dark blue for the starting point, but you can check out ?rgb etc. to adjust the color to your liking.
nbrk <- 30
x <- runif(20)
y <- runif(20)
cc <- colorRampPalette(c("blue","red"))(nbrk)
z <- runif(20)
plot(x,y,col=cc[cut(z,nbrk)],pch=16)