Related
I am having a 3D plot in which the points are colored acording to some extra vector. My problem is to add a color gradient legend. This is my code:
x = matrix(NA,100,6)
#x value
x[,1] = runif(100, 0, 10)
#y value
x[,2] = runif(100, 0, 10)
#z value
x[,3] = x[,1]+x[,2]
#additional value
x[,4] = runif(100, 0, 1)
#find out in which interval each additional value is
intervals = seq(0,1,1/10)
x[,5] = findInterval(x[,4], intervals)
colours = topo.colors(length(intervals))
x[,6] = colours[x[,5]]
library(rgl)
plot3d(as.numeric(x[,1]),as.numeric(x.stab.in[,2]), as.numeric(x[,3]),
type="p", col=x[,6], size=2, xlab = "x(t)", ylab = "y(t)",
zlab = "z(t)")
decorate3d(xlab = "x", ylab = "y", zlab = "z")
legend3d("topright", legend = intervals, pch = 16, col = colours, cex=1, inset=c(0.02))
grid3d(c("x", "y+", "z"),col = "gray")
The plot looks like this
but I want the legend in a gradient form. That means I don't want separate points for each color but one box in which the colors fade into each other.
Here is a possible solution if you are okay with using scatterplot3d package instead of rgl. It is basically same but non-interactive. Here is your code modified to produce your expected result.
x = matrix(NA,100,6)
#x value
x[,1] = runif(100, 0, 10)
#y value
x[,2] = runif(100, 0, 10)
#z value
x[,3] = x[,1]+x[,2]
#additional value
x[,4] = runif(100, 0, 1)
#find out in which interval each additional value is
intervals = seq(0,1,1/10)
x[,5] = findInterval(x[,4], intervals)
#produce gradient of colors
#you can define different colors (two or more)
gradient <- colorRampPalette(colors = c("yellow", "green", "blue"))
colours <- gradient(length(intervals))
x[,6] = colours[x[,5]]
library(scatterplot3d)
png('3d.png', width = 600, height = 400)
layout(matrix(1:2, ncol=2), width = c(3, 1), height = c(1, 1))
scatterplot3d(as.numeric(x[,1]),as.numeric(x[,2]), as.numeric(x[,3]), type = 'p',
cex.symbols = 1.25, color=x[,6], pch = 16, xlab = "x(t)", ylab = "y(t)", zlab = "z(t)")
plot(x = rep(1, 100), y = seq_along(x[,6]),
pch = 15, cex = 2.5,
col = gradient(length(x[,6])),
ann = F, axes = F, xlim = c(1, 2))
axis(side = 2, at = seq(1, nrow(x), length.out = 11),
labels = 1:11,
line = 0.15)
dev.off()
This will plot the following graph
Here is another solution if you want to plot a gradient on an interactive 3d plot, such as if you needed to animate the plot into a movie.
require(car)
require(rgl)
require(RColorBrewer)
require(mgcv)
require(magick) #Only for creating the animation of the plot as a gif
#Creating mock dataset
Example_Data <- data.frame(Axis1 = rnorm(100),
Axis2 = rnorm(100),
Axis3 = rnorm(100))
Example_Data$Value <- Example_Data$Axis1+Example_Data$Axis2
#Defining function that takes a vector of numeric values and converts them to
#a spectrum of rgb colors to help color my scatter3d plot
get_colors <- function(values){
v <- (values - min(values))/diff(range(values))
x <- colorRamp(rev(brewer.pal(11, "Spectral")))(v)
rgb(x[,1], x[,2], x[,3], maxColorValue = 255)
}
#Writing function that takes a vector of numeric values and a title and creates
#a gradient legend based on those values and the title and suitable for addition
#to a scatter3d plot via a call to bgplot3d()
#Note, I didn't have time to make this automatically adjust text position/size for different size
#plot windows, so values may need to be adjusted manually depending on the size of the plot window.
gradient_legend_3d <- function(values, title){
min_val <- min(values)
max_val <- max(values)
x <- colorRamp(brewer.pal(11, "Spectral"))((0:20)/20)
colors <- rgb(x[,1], x[,2], x[,3], maxColorValue = 255)
legend_image <- as.raster(matrix(colors, ncol=1))
plot(c(0,1),c(0,1),type = 'n', axes = F,xlab = '', ylab = '', main = '') #Generates a blank plot
text(x=0.92, y = seq(0.5, 1,l=5), labels = signif(seq(min_val, max_val,l=5), 2), cex = 1.5) #Creates the numeric labels on the scale
text(x = 0.85, y = 1, labels = title, adj = 1, srt = 90, cex = 1.5) #Determines where the title is placed
rasterImage(legend_image, 0.87, 0.5, 0.9,1) #Values can be modified here to alter where and how wide/tall the gradient is drawn in the plotting area
}
#Creating scatter3d plot
scatter3d(x = Example_Data$Axis1, y = Example_Data$Axis2, z = Example_Data$Axis3, xlab = "Axis1", ylab = "Axis2", zlab = "Axis3", surface = F, grid = F, ellipsoid = F, fogtype = "none", point.col = get_colors(Example_Data$Value))
#Changing size of plotting window and orientation to optimize for addition of static legend
#This may not work on another machine, so the window may need to be adjusted manually
par3d(windowRect = c(0,23,1536,824))
par3d(userMatrix = matrix(c(-0.98181450, -0.02413967, 0.18830180, 0, -0.03652956, 0.99736959, -0.06260729, 0, -0.18629514, -0.06834736, -0.98011345, 0, 0, 0, 0, 1), nrow = 4, ncol = 4, byrow = T))
#Adding legend
bgplot3d(gradient_legend_3d(Example_Data$Value, "Point Value"))
#Animating plot and saving as gif
movie3d(spin3d(axis = c(0,1,0), rpm = 5), duration = 12, dir = getwd(), fps = 5, convert = FALSE, clean = FALSE)
frames <- NULL
for(j in 0:60){
if(j == 1){
frames <- image_read(sprintf("%s%03d.png", "movie", j))
} else {
frames <- c(frames, image_read(sprintf("%s%03d.png", "movie", j)))
}
}
animation <- image_animate(frames, fps = 10, optimize = TRUE)
image_write(animation, path = "Example.gif")
for(j in 0:60){
unlink(sprintf("%s%03d.png", "movie", j))
}
See link to view 3d plot generated by this code:
gif of 3d plot with gradient color scale
I want to make a graph where the size of the circles indicate the size of the sample. if i use plot in p1(), it works fine.
but if i try to have the different type of points colored, then the relative size is wrong.
How would I get both the red and green circles to be the same size?
p1<-function() {
plot(t$x,t$y,cex=100*t$size,xlim=c(0,1),ylim=c(0.,1.))
}
p2<-function() {
plot(t$x[t$r=="0"],t$y[t$r=="0"],xlim=c(0,1),ylim=c(0.,1.),cex=100*t$size,col="red")
points(t$x[t$r=="1"],t$y[t$r=="1"],xlim=c(0,1),ylim=c(0.,1.),cex=100*t$size,col="green")
}
l<-20
x<-seq(0,1,1/l)
y<-sqrt(x)
r=round(runif(n=length(x),min=0,max=.8))
n<-1:length(x)
size=n/sum(n)
t<-data.frame(x,y,r,n,size)
t$r<-factor(r)
str(t)
p1()
You have to change function p2 a bit. You are using t$size, all of it, when you should be subsetting by the factor t$r, since you are doing so when plotting the points.
If you plot t$x[t$r == "0"] versus t$y[t$r == "0"] then you must use the sizes corresponding to those points, which are t$size[t$r == "0"]. Alternatively, you could subset the data frame t first, and then use those two resulting data frames to plot the points. See function p2_alt at the end.
p2 <- function() {
plot(t$x[t$r == "0"], t$y[t$r == "0"],
xlim = c(0, 1), ylim = c(0., 1.),
cex = 100*t$size[t$r == "0"],
col = "red",
xlab = "x", ylab = "y")
points(t$x[t$r == "1"],
t$y[t$r == "1"],
xlim = c(0, 1), ylim = c(0., 1.),
cex = 100*t$size[t$r == "1"],
col = "green")
}
set.seed(651) # make the results reproducible
l <- 20
x <- seq(0, 1, 1/l)
y <- sqrt(x)
r <- round(runif(n = length(x), min = 0, max = 0.8))
n <- 1:length(x)
size <- n/sum(n)
t <- data.frame(x, y, r, n, size)
t$r <- factor(r)
#str(t)
#p1()
p2()
p2_alt <- function() {
df1 <- subset(t, r == "0")
df2 <- subset(t, r == "1")
plot(df1$x, df1$y,
xlim = c(0, 1), ylim = c(0., 1.),
cex = 100*df1$size,
col = "red",
xlab = "x", ylab = "y")
points(df2$x,
df2$y,
xlim = c(0, 1), ylim = c(0., 1.),
cex = 100*df2$size,
col = "green")
}
p2_alt()
The graph is exactly the same, but maybe the code is more readable.
Finally, note that I have added arguments xlab and ylab to both p2() and p2_alt().
how to
Combine a bar chart and line in single plot in R (from different data sources)?
Say I have two data sources as:
barData<-c(0.1,0.2,0.3,0.4) #In percentage
lineData<-c(100,22,534,52,900)
Note that they may not be in the same scale.
Can I plot both barData and LineData in one plot and make them good looking ?
I cant use ggplot in this case so this is not a duplicated question..
Something like the following:
Maybe this helps as a starting point:
par(mar = rep(4, 4))
barData<-c(0.1,0.2,0.3,0.4) * 100
y <- lineData<-c(100,22,534,900);
x <- barplot(barData,
axes = FALSE,
col = "blue",
xlab = "",
ylab = "",
ylim = c(0, 100) )[, 1]
axis(1, at = x, labels = c("Julia", "Pat", "Max", "Norman"))
ats <- c(seq(0, 100, 15), 100); axis(4, at = ats, labels = paste0(ats, "%"), las = 2)
axis(3, at = x, labels = NA)
par(new = TRUE)
plot(x = x, y = y, type = "b", col = "red", axes = FALSE, xlab = "", ylab = "")
axis(2, at = c(pretty(lineData), max(lineData)), las = 2)
mtext(text="Lines of code by Programmer", side = 3, line = 1)
box()
I'm using a function that among several things plots the results in two panels using par(mfrow = c(1, 2)).
I would like to run the function with three different datasets and plot the outputs together so that each one is in a row, as if I were using par(mfrow = c(3, 2)).
If there a way of doing this without modifying the function itself?
Probably basic issue, but help very much appreciated.
The function is a little bit long, but the relevant part plots a PCoA:
# perform classical multidimensional sclaing (PCoA) of the dist matrix
acop <- cmdscale(dat.d, k = nrow(as.matrix(dat.d)) - 1, eig = TRUE) # keep n-1 eigenvalues
axes.tot <- acop$eig # eig are the n eigenvalues computed by cmdscale. Axes are ranked by their
eigenvalues, so the first axis has the highest eigenvalue, the second axis has the second highest
eigenvalue, etc.
inertia <- sum(acop$eig[acop$eig > 0])
percents <- round(as.numeric(100 * axes.tot/inertia), digits = 0) # The eigenvalues represent
the variance extracted by each axis, here they are expressed as a percentage of the sum of all
eigenvalues (i.e. total variance).
par()
par(mfrow = c(1, 2), pty = "s")
coord1 <- acop$points[, c(1, 2)] # points is a matrix whose rows give the coordinates of the
points chosen to represent the dissimilarities
col.grps <- data.frame(vect.grps, coord1)
# plot so that the maximum variance is projected along the first axis, then on the second and so
on
plot(coord1, asp = 1, cex = 0.1, xlab = paste("Axis 1 ",
"(", percents[1], " % variance explained)", sep = ""),
ylab = paste("Axis 2 ", "(", percents[2], " % variance explained)",
sep = ""), main = "", type = "n", bty = "n")
abline(h = 0, lty = 2, col = "grey")
abline(v = 0, lty = 2, col = "grey")
if (length(vect.grps) == nrow(as.matrix(dat.d))) {
for (g in 1:length(names.grps)) {
text(x = coord1[col.grps[, 1] == names.grps[g], 1],
y = coord1[col.grps[, 1] == names.grps[g], 2],
labels = names.grps[g], col = topo.col[g], cex = 0.7)
}
}
else {
points(coord1, pch = 19, col = "blue", cex = 0.5)
}
coord1 <- acop$points[, c(3, 4)]
col.grps <- data.frame(vect.grps, coord1)
plot(coord1, asp = 1, cex = 0.1, xlab = paste("Axis 3 ",
"(", percents[3], " % variance explained)", sep = ""),
ylab = paste("Axis 4 ", "(", percents[4], " % variance explained)",
sep = ""), main = "", type = "n", bty = "n")
abline(h = 0, lty = 2, col = "grey")
abline(v = 0, lty = 2, col = "grey")
if (length(vect.grps) == nrow(as.matrix(dat.d))) {
for (g in 1:length(names.grps)) {
text(x = coord1[col.grps[, 1] == names.grps[g], 1],
y = coord1[col.grps[, 1] == names.grps[g], 2],
labels = names.grps[g], col = topo.col[g], cex = 0.7)
}
}
else {
points(coord1, pch = 19, col = "blue", cex = 0.5)
I guess you can overwrite par(),
foo <- function(){
par(mfrow=c(2,1), mar=c(0,0,0,0))
plot(1:10)
plot(rnorm(10))
}
par <- function(mfrow, ...) {graphics::par(mfrow=c(3, 2), ...)}
foo()
rm(par)
I have a customized function for plotting filled contours which is heavily based on Carey McGilliard and Bridget Ferris work (http://wiki.cbr.washington.edu/qerm/sites/qerm/images/1/16/Filled.contour3.R) and http://wiki.cbr.washington.edu/qerm/index.php/R/Contour_Plots .
the filled.contour3 function runs perfectly in R 2.15.3 but throws an error in R 3.0.x
Error in .Internal(filledcontour(as.double(x), as.double(y), z, as.double(levels), :
there is no .Internal function 'filledcontour'
Could you please help me with a solution or a workarround so that I can use the filled.contour3() function in R 3.0.x . *A great deal of my work depends on this function and I am on LInux so changing R versions is not that easy on production machines. Will be happy to offer bounty.*
To reproduce the error please source first the following
filled.contour3 <-
function (x = seq(0, 1, length.out = nrow(z)),
y = seq(0, 1, length.out = ncol(z)), z, xlim = range(x, finite = TRUE),
ylim = range(y, finite = TRUE), zlim = range(z, finite = TRUE),
levels = pretty(zlim, nlevels), nlevels = 20, color.palette = cm.colors,
col = color.palette(length(levels) - 1), plot.title, plot.axes,
key.title, key.axes, asp = NA, xaxs = "i", yaxs = "i", las = 1,
axes = TRUE, frame.plot = axes,mar, ...)
{
# modification by Ian Taylor of the filled.contour function
# to remove the key and facilitate overplotting with contour()
# further modified by Carey McGilliard and Bridget Ferris
# to allow multiple plots on one page
if (missing(z)) {
if (!missing(x)) {
if (is.list(x)) {
z <- x$z
y <- x$y
x <- x$x
}
else {
z <- x
x <- seq.int(0, 1, length.out = nrow(z))
}
}
else stop("no 'z' matrix specified")
}
else if (is.list(x)) {
y <- x$y
x <- x$x
}
if (any(diff(x) <= 0) || any(diff(y) <= 0))
stop("increasing 'x' and 'y' values expected")
# mar.orig <- (par.orig <- par(c("mar", "las", "mfrow")))$mar
# on.exit(par(par.orig))
# w <- (3 + mar.orig[2]) * par("csi") * 2.54
# par(las = las)
# mar <- mar.orig
plot.new()
# par(mar=mar)
plot.window(xlim, ylim, "", xaxs = xaxs, yaxs = yaxs, asp = asp)
if (!is.matrix(z) || nrow(z) <= 1 || ncol(z) <= 1)
stop("no proper 'z' matrix specified")
if (!is.double(z))
storage.mode(z) <- "double"
.Internal(filledcontour(as.double(x), as.double(y), z, as.double(levels),
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()
}
filled.legend <-
function (x = seq(0, 1, length.out = nrow(z)), y = seq(0, 1,
length.out = ncol(z)), z, xlim = range(x, finite = TRUE),
ylim = range(y, finite = TRUE), zlim = range(z, finite = TRUE),
levels = pretty(zlim, nlevels), nlevels = 20, color.palette = cm.colors,
col = color.palette(length(levels) - 1), plot.title, plot.axes,
key.title, key.axes, asp = NA, xaxs = "i", yaxs = "i", las = 1,
axes = TRUE, frame.plot = axes, ...)
{
# modification of filled.contour by Carey McGilliard and Bridget Ferris
# designed to just plot the legend
if (missing(z)) {
if (!missing(x)) {
if (is.list(x)) {
z <- x$z
y <- x$y
x <- x$x
}
else {
z <- x
x <- seq.int(0, 1, length.out = nrow(z))
}
}
else stop("no 'z' matrix specified")
}
else if (is.list(x)) {
y <- x$y
x <- x$x
}
if (any(diff(x) <= 0) || any(diff(y) <= 0))
stop("increasing 'x' and 'y' values expected")
# 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)
# plot.new()
plot.window(xlim = c(0, 1), ylim = range(levels), xaxs = "i",
yaxs = "i")
rect(0, levels[-length(levels)], 1, levels[-1L], col = col)
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)
# plot.new()
# plot.window(xlim, ylim, "", xaxs = xaxs, yaxs = yaxs, asp = asp)
# if (!is.matrix(z) || nrow(z) <= 1L || ncol(z) <= 1L)
# stop("no proper 'z' matrix specified")
# if (!is.double(z))
# storage.mode(z) <- "double"
# .Internal(filledcontour(as.double(x), as.double(y), z, as.double(levels),
# 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 run
#Example Four Panel Contour Plot with One Legend
#Author: Carey R McGilliard
#September 2010
#This code uses a modified version of filled.contour called filled.contour3 (created by Carey McGilliard, Ian Taylor, and Bridget Ferris)
#to make an example figure of four contour plots sharing a legend (to the right).
#The example demonstrates how to use various color schemes for the contour plots and legend, but the user will want to
#pick one color scheme for all four plots such that the legend matches the plots.
#Changing the x- and y-axis values will change the placement of text added to the figure using the text() function and adjustments will be necessary
#Source the following functions (change the paths as necessary)
#source("./print.letterTrevor.R")
#gplots has the function colorpanel, which is handy for making gray-scale contour plots
library(gplots)
#------------------------------------------------------
#Generate some fake data
x = rep(c(10,11,12),length = 9)
y = rep(c(1,2,3),each = 3)
z = rnorm(n=9,mean = 0,sd = 1)
xcoords = unique(x)
ycoords = unique(y)
surface.matrix = matrix(z,nrow=length(xcoords),ncol=length(ycoords),byrow=T)
#------------------------------------------------------
#plot.new() is necessary if using the modified versions of filled.contour
plot.new()
#I am organizing where the plots appear on the page using the "plt" argument in "par()"
par(new = "TRUE",
plt = c(0.1,0.4,0.60,0.95), # using plt instead of mfcol (compare
# coordinates in other plots)
las = 1, # orientation of axis labels
cex.axis = 1, # size of axis annotation
tck = -0.02 ) # major tick size and direction, < 0 means outside
#Top left plot:
#
# the filled contour - coloured areas
filled.contour3(xcoords,
ycoords,
surface.matrix,
color=terrain.colors,
xlab = "", # suppress x-axis annotation
ylab = "", # suppress y-axis annotation
xlim = c(min(xcoords),max(xcoords)),
ylim = c(min(ycoords),max(ycoords)),
zlim = c(min(surface.matrix),max(surface.matrix))
)
# the contour part - draw iso-lines
contour(xcoords,
ycoords,
surface.matrix,
color=terrain.colors,
xlab = "",
ylab = "",
xlim = c(min(xcoords),max(xcoords)),
ylim = c(min(ycoords),max(ycoords)),
zlim = c(min(surface.matrix),max(surface.matrix)),
add=TRUE, # add the contour plot to filled-contour,
#thus making an overlay
col = grey(0.4) # color of overlay-lines
)
#
# An annotation inside first plot
#The xpd=NA allows for writing outside the plot limits, but still using the the x and y axes to place the text
par(xpd = NA)
text(x=11,y=1.5,"x",cex = 1.5,font = 2)
print.letter(text = "(a)")
######################################################################
#
#
#Top right plot:
par(new = "TRUE",
plt = c(0.5,0.8,0.60,0.95), # defining window for second plot
las = 1,
cex.axis = 1)
#
filled.contour3(
xcoords,
ycoords,
surface.matrix,
color=heat.colors,
xlab = "",
ylab = "",
xlim = c(min(xcoords),max(xcoords)),
ylim = c(min(ycoords),max(ycoords)),
zlim = c(-1,1)
)
#
contour(
xcoords,
ycoords,
surface.matrix,
xlab = "",
ylab = "",
xlim = c(min(xcoords),max(xcoords)),
ylim = c(min(ycoords),max(ycoords)),
zlim = c(-1,1),
add=TRUE
)
#
#Alternatively, you could set z axis limits to depend
#on the min and max values in surface.matrix.
#filled.contour3(xcoords,ycoords,surface.matrix,color=heat.colors,xlab = "",ylab = "",xlim = c(min(xcoords),max(xcoords)),ylim = c(min(ycoords),max(ycoords)),zlim = c(min(surface.matrix),max(surface.matrix)))
#
# Add annotation
text(x=11,
y=1.5,
"x",
cex = 1.5,
font = 2)
######################################################################
#
#Bottom left plot:
par(new = "TRUE",
plt = c(0.1,0.4,0.15,0.5),
las = 1,
cex.axis = 1)
#
filled.contour3(xcoords,
ycoords,
surface.matrix,
col=colorpanel(11, "white", "grey10"),
nlevels=11,
xlab = "",
ylab = "",
xlim = c(min(xcoords),max(xcoords)),
ylim = c(min(ycoords),max(ycoords)),
zlim = c(-1,1))
#
contour(xcoords,
ycoords,
surface.matrix,
xlab = "",
ylab = "",
xlim = c(min(xcoords),max(xcoords)),
ylim = c(min(ycoords),max(ycoords)),
zlim = c(-1,1),
add = TRUE)
#
text(x=11,
y=1.5,
"x",
cex = 1.5,
font = 2,
col = "white")
######################################################################
#
#Bottom right plot:
par(new = "TRUE",
plt = c(0.5,0.8,0.15,0.5),
las = 1,
cex.axis = 1)
#
filled.contour3(
xcoords,
ycoords,
surface.matrix,
color = terrain.colors,
xlab = "",
ylab = "",
xlim = c(min(xcoords),max(xcoords)),
ylim = c(min(ycoords),max(ycoords)),
zlim = c(-1,1)
)
#
contour(
xcoords,
ycoords,
surface.matrix,
xlab = "",
ylab = "",
xlim = c(min(xcoords),max(xcoords)),
ylim = c(min(ycoords),max(ycoords)),
zlim = c(-1,1),
add=TRUE
)
text(x=11,
y=1.5,
"hello",
cex = 1.5,
font = 2)
#
######################################################################
#Add a legend:
par(new = "TRUE",
plt = c(0.85,0.9,0.25,0.85), # define plot region for legend
las = 1,
cex.axis = 1)
#
filled.legend(
xcoords,
ycoords,
surface.matrix,
color = terrain.colors,
xlab = "",
ylab = "",
xlim = c(min(xintercepts),max(xintercepts)),
ylim = c(min(slopes),max(slopes)),
zlim = c(-1,1))
#Add some figure labels
par(xpd=NA,cex = 1.3)
text(x = -16.7,y = 0,"slope",srt = 90,cex = 1.3)
text(x = -8,y = -1.62,expression(paste(italic(x),"-intercept",sep = "")),cex = 1.3)
This happens if you use a non-standard API. You are allowed to do that, but cannot expect that it is maintained.
Change
.Internal(filledcontour(as.double(x), as.double(y), z, as.double(levels),
col = col))
to
.filled.contour(as.double(x), as.double(y), z, as.double(levels),
col = col)
The change was announced with the release notes:
The C code underlying base graphics has been migrated to the graphics
package (and hence no longer uses .Internal() calls).
Have you ever heard of a "minimal reproducible example" (emphasis on "minimal")?