I would like to access the legend on a kohonen SOM plot. For example this code ...
library("kohonen")
data("wines")
wines.sc <- scale(wines)
set.seed(7)
wine.som <- som(wines.sc, grid = somgrid(5, 4, "hexagonal"))
plot(wine.som, main = "Wine data",shape="straight")
... creates a nice plot with a legend of the 13 variables in a 3 column 5 row format. How do I access the legend controls on this plot to make it say 2 columns by 7 rows or perhaps 4 columns with4 rows? Perhaps I need to somehow turn the legend off (not sure how) and create my own legend in the outer margin?
Download the myplot.kohcodes function here and save it in your working directory as myplot.kohcodes.r.
Set the number of columns in the legend using the ncolsleg parameter.
Then, run the code:
library("kohonen")
data("wines")
wines.sc <- scale(wines)
set.seed(7)
wine.som <- som(wines.sc, grid = somgrid(5, 4, "hexagonal"))
source("myplot.kohcodes.r")
myplot.kohcodes(wine.som, main = "Wine data", keepMargins=FALSE,
palette.name=NULL, whatmap = NULL, codeRendering = NULL,
bgcol = NULL, ncolsleg=2)
A note. If the legend width is greater than the plot width, myplot.kohcodes reduces the cex parameter until the legend width is lower that the plot width.
myplot.kohcodes <- function (x, whatmap, main, palette.name, bgcol, codeRendering,
keepMargins, shape = c("round", "straight"), border = "black", ncolsleg=3,
...)
{
if (!keepMargins) {
opar <- par(c("mar"))
on.exit(par(opar))
}
if (is.null(palette.name))
palette.name <- terrain.colors
whatmap <- check.whatmap(x, whatmap)
nmaps <- length(whatmap)
if (is.list(x$codes)) {
for (i in 1:nmaps) {
huhn <- list(whatmap = 1, grid = x$grid)
huhn$codes <- getCodes(x, whatmap[i])
if (length(main) == length(x$codes)) {
main.title <- main[whatmap[i]]
}
else {
if (length(main) == nmaps) {
main.title <- main[i]
}
else {
if (length(main) == 1) {
main.title <- main
}
else {
if (is.null(main)) {
if (!is.null(names(x$codes))) {
main.title <- names(x$codes)[whatmap[i]]
}
else {
main.title <- "Codes plot"
}
}
}
}
}
if (length(codeRendering) == length(x$codes)) {
cR <- codeRendering[whatmap[i]]
}
else {
if (length(codeRendering) == nmaps) {
cR <- codeRendering[i]
}
else {
cR <- codeRendering
}
}
myplot.kohcodes(huhn, main = main.title, palette.name = palette.name,
bgcol = bgcol, whatmap = NULL, codeRendering = cR,
keepMargins = TRUE, shape = shape, border = border, ncolsleg,
...)
}
}
else {
codes <- x$codes
nvars <- ncol(codes)
maxlegendcols <- 3
ncols <- ncolsleg
print(ncolsleg)
if (is.null(codeRendering))
codeRendering <- ifelse(nvars < 15, "segments", "lines")
margins <- rep(0.6, 4)
if (!is.null(main))
margins[3] <- margins[3] + 2
par(mar = margins)
if (codeRendering == "segments" & !is.null(colnames(codes))) {
kohonen:::plot.somgrid(x$grid, ylim = c(max(x$grid$pts[, 2]) + min(x$grid$pts[,
2]), -2))
current.plot <- par("mfg")
plot.width <- diff(par("usr")[1:2])
cex <- 1
leg.result <- legend(x = mean(x$grid$pts[, 1]), xjust = 0.5,
y = 0, yjust = 1, legend = colnames(codes), cex = cex,
plot = FALSE, ncol = ncols, fill = palette.name(nvars))
while (leg.result$rect$w > plot.width) {
cex <- cex * 0.9
leg.result <- legend(x = mean(x$grid$pts[, 1]),
xjust = 0.5, y = 0, yjust = 1, legend = colnames(codes),
cex = cex, plot = FALSE, ncol = ncols, fill = palette.name(nvars))
}
leg.result <- legend(x = mean(x$grid$pts[, 1]), xjust = 0.5,
y = 0, yjust = 1, cex = cex, legend = colnames(codes),
plot = FALSE, ncol = ncols, fill = palette.name(nvars),
...)
par(mfg = current.plot)
kohonen:::plot.somgrid(x$grid, ylim = c(max(x$grid$pts[, 2]) + min(x$grid$pts[,
2]), -leg.result$rect$h))
legend(x = mean(x$grid$pts[, 1]), xjust = 0.5, y = 0,
yjust = 1, cex = cex, plot = TRUE, legend = colnames(codes),
ncol = ncols, fill = palette.name(nvars), ...)
}
else {
plot(x$grid, ...)
}
title.y <- max(x$grid$pts[, 2]) + 1.2
if (title.y > par("usr")[4] - 0.2) {
title(main)
}
else {
text(mean(range(x$grid$pts[, 1])), title.y, main,
adj = 0.5, cex = par("cex.main"), font = par("font.main"))
}
if (is.null(bgcol))
bgcol <- "transparent"
shape <- match.arg(shape)
sym <- ifelse(shape == "round", "circle", ifelse(x$grid$topo ==
"rectangular", "square", "hexagon"))
switch(sym, circle = symbols(x$grid$pts[, 1], x$grid$pts[,
2], circles = rep(0.5, nrow(x$grid$pts)), inches = FALSE,
add = TRUE, fg = border, bg = bgcol), hexagon = hexagons(x$grid$pts[,
1], x$grid$pts[, 2], unitcell = 1, col = bgcol, border = border),
square = symbols(x$grid$pts[, 1], x$grid$pts[, 2],
squares = rep(1, nrow(x$grid$pts)), inches = FALSE,
add = TRUE, fg = border, bg = bgcol))
if (codeRendering == "lines") {
yrange <- range(codes)
codes <- codes - mean(yrange)
}
else {
codemins <- apply(codes, 2, min)
codes <- sweep(codes, 2, codemins)
}
switch(codeRendering, segments = {
stars(codes, locations = x$grid$pts, labels = NULL,
len = 0.4, add = TRUE, col.segments = palette.name(nvars),
draw.segments = TRUE)
}, lines = {
for (i in 1:nrow(x$grid$pts)) {
if (yrange[1] < 0 & yrange[2] > 0) {
lines(seq(x$grid$pts[i, 1] - 0.4, x$grid$pts[i,
1] + 0.4, length = 2), rep(x$grid$pts[i,
2], 2), col = "gray")
}
lines(seq(x$grid$pts[i, 1] - 0.4, x$grid$pts[i,
1] + 0.4, length = ncol(codes)), x$grid$pts[i,
2] + codes[i, ] * 0.8/diff(yrange), col = "red")
}
}, stars = stars(codes, locations = x$grid$pts, labels = NULL,
len = 0.4, add = TRUE))
}
invisible()
}
Related
I need to change the x-axis labels so they are words instead of numerals. Currently, the x-axis goes 1, 2, 3, etc. I would like it to go "Placement", "Fresh", etc.
trendplot <- function(timeseries, color, index, first = FALSE, w = 4, add_main = ""){
if (first) {
plot.ts(timeseries[, index], col = color, lwd = w,
ylim = c(-2, 2),
ylab = "Scaled Relative Abundance",
xlab = "Stage",
main = paste0("Trend Plots", add_main)) # gsub(".", " ", colnames(timeseries)[index], fixed = TRUE)
} else {
lines(timeseries[, index], col = color, lwd = w)
}
}
Update:
This code works for what I wanted it be.
stages<-c('Placement','Fresh','Bloat One','Bloat Two','Post-Bloat One','Post-Bloat Two')
trendplot <- function(timeseries, color, index, first = FALSE, w = 4, add_main = ""){
if (first) {
plot.ts(timeseries[, index], col = color, lwd = w, axes = FALSE,
ylim = c(-2, 2),
ylab = "Scaled Measurement",
xlab = "Time Point",
main = paste0("Trend Plots", add_main)) # gsub(".", " ", colnames(timeseries)[index], fixed = TRUE)+
} else {
lines(timeseries[, index], col = color, lwd = w)
}
{axis(1, at=1:6, labels=stages, cex.axis=0.5)}
}
I am using a loop for plotting the histogram, group by different values of column_a at once which works perfectly fine. Here's the code:
par(ask=F)
for (i in unique(Data$column_a)) {
dat <- Data[Data$column_a== i, ]
plotdist(dat$count,histo = TRUE, demp = TRUE, discrete = T,
pch = 16, col = "dodgerblue1")
}
The only problem is that I cannot label each figure relative to column_a value to differentiate the figures from on another.
Thanks in advance for the help.
my data consists of number of losses with the column name of "count" with 3 distinct value in column_a(R,I,F)). and I want to plot the histogram of number of losses for these three values.
A somewhat hacky solution would be to alter the function itself.
Below is the alteret function, which uncludes the title argument (and only works for the configuration you had in your question!)
plotdist_alt <- function (data, distr, para, histo = TRUE, breaks = "default",
demp = FALSE, discrete, title = "default", ...)
{
def.par <- par(no.readonly = TRUE)
if (missing(data) || !is.vector(data, mode = "numeric"))
stop("data must be a numeric vector")
if ((missing(distr) & !missing(para)) || (missing(distr) &
!missing(para)))
stop("distr and para must defined")
if (!histo & !demp)
stop("one the arguments histo and demp must be put to TRUE")
xlim <- c(min(data), max(data))
s <- sort(data)
n <- length(data)
if (missing(distr)) {
par(mfrow = c(1, 2))
if (missing(discrete))
discrete <- FALSE
if (!discrete) {
obsp <- ppoints(s)
if (histo) {
if (demp) {
if (breaks == "default")
h <- hist(data, freq = FALSE, xlab = "Data",
main = "Empirical density", ...)
else h <- hist(data, freq = FALSE, xlab = "Data",
main = "Empirical density", breaks = breaks,
...)
lines(density(data)$x, density(data)$y, lty = 2,
col = "black")
}
else {
if (breaks == "default")
h <- hist(data, freq = FALSE, xlab = "Data",
main = "Histogram", ...)
else h <- hist(data, freq = FALSE, xlab = "Data",
main = "Histogram", breaks = breaks,
...)
}
}
else {
h <- hist(data, freq = FALSE, xlab = "Data",
main = "Histogram", plot = FALSE, ...)
plot(density(data)$x, density(data)$y, lty = 1,
col = "black", type = "l", xlab = "Data",
main = paste("Empirical density"), ylab = "Density",
...)
}
plot(s, obsp, main = paste("Cumulative distribution"),
xlab = "Data", xlim = c(h$breaks[1], h$breaks[length(h$breaks)]),
ylab = "CDF", ...)
}
else {
if (breaks != "default")
warning("Breaks are\tnot taken into account for discrete data")
t <- table(data)
xval <- as.numeric(names(t))
ydobs <- as.vector(t)/n
ydmax <- max(ydobs)
plot(xval, ydobs, type = "h", xlim = xlim,
ylim = c(0, ydmax), main = paste0("Empirical distribution ", title),
xlab = "Data", ylab = "Density",
...)
ycdfobs <- cumsum(ydobs)
plot(xval, ycdfobs, type = "p", xlim = xlim,
ylim = c(0, 1), main = paste0("Empirical CDFs ", title),
xlab = "Data", ylab = "CDF", ...)
}
}
else {
if (!is.character(distr))
distname <- substring(as.character(match.call()$distr),
2)
else distname <- distr
if (!is.list(para))
stop("'para' must be a named list")
ddistname <- paste("d", distname, sep = "")
if (!exists(ddistname, mode = "function"))
stop(paste("The ", ddistname, " function must be defined"))
pdistname <- paste("p", distname, sep = "")
if (!exists(pdistname, mode = "function"))
stop(paste("The ", pdistname, " function must be defined"))
qdistname <- paste("q", distname, sep = "")
if (!exists(qdistname, mode = "function"))
stop(paste("The ", qdistname, " function must be defined"))
densfun <- get(ddistname, mode = "function")
nm <- names(para)
f <- formals(densfun)
args <- names(f)
m <- match(nm, args)
if (any(is.na(m)))
stop(paste("'para' specifies names which are not arguments to ",
ddistname))
if (missing(discrete)) {
if (is.element(distname, c("binom", "nbinom",
"geom", "hyper", "pois")))
discrete <- TRUE
else discrete <- FALSE
}
if (!discrete) {
par(mfrow = c(2, 2))
obsp <- ppoints(s)
if (breaks == "default")
h <- hist(data, plot = FALSE)
else h <- hist(data, breaks = breaks, plot = FALSE,
...)
xhist <- seq(min(h$breaks), max(h$breaks), length = 1000)
yhist <- do.call(ddistname, c(list(xhist), as.list(para)))
if (length(yhist) != length(xhist))
stop("problem when computing densities.")
ymax <- ifelse(is.finite(max(yhist)), max(max(h$density),
max(yhist)), max(h$density))
if (histo) {
hist(data, freq = FALSE, xlab = "Data",
ylim = c(0, ymax), breaks = h$breaks, main = paste("Empirical and theoretical dens."),
...)
if (demp) {
lines(density(data)$x, density(data)$y, lty = 2,
col = "black")
}
}
else plot(density(data)$x, density(data)$y, lty = 2,
col = "black", type = "l", xlab = "Data",
main = paste("Empirical and theoretical dens."),
ylab = "Density", xlim = c(min(h$breaks),
max(h$breaks)), ...)
if (demp)
legend("topright", bty = "n", lty = c(2,
1), col = c("black", "red"), legend = c("empirical",
"theoretical"), bg = "white", cex = 0.7)
lines(xhist, yhist, lty = 1, col = "red")
theoq <- do.call(qdistname, c(list(obsp), as.list(para)))
if (length(theoq) != length(obsp))
stop("problem when computing quantities.")
plot(theoq, s, main = " Q-Q plot", xlab = "Theoretical quantiles",
ylab = "Empirical quantiles", ...)
abline(0, 1)
xmin <- h$breaks[1]
xmax <- h$breaks[length(h$breaks)]
if (length(s) != length(obsp))
stop("problem when computing probabilities.")
plot(s, obsp, main = paste("Empirical and theoretical CDFs"),
xlab = "Data", ylab = "CDF", xlim = c(xmin,
xmax), ...)
sfin <- seq(xmin, xmax, by = (xmax - xmin)/100)
theopfin <- do.call(pdistname, c(list(sfin), as.list(para)))
lines(sfin, theopfin, lty = 1, col = "red")
theop <- do.call(pdistname, c(list(s), as.list(para)))
if (length(theop) != length(obsp))
stop("problem when computing probabilities.")
plot(theop, obsp, main = "P-P plot", xlab = "Theoretical probabilities",
ylab = "Empirical probabilities", ...)
abline(0, 1)
}
else {
par(mfrow = c(1, 2))
if (breaks != "default")
warning("Breaks are not taken into account for discrete distributions")
t <- table(data)
xval <- as.numeric(names(t))
xvalfin <- seq(min(xval), max(xval), by = 1)
xlinesdec <- min((max(xval) - min(xval))/30, 0.4)
yd <- do.call(ddistname, c(list(xvalfin), as.list(para)))
if (length(yd) != length(xvalfin))
stop("problem when computing density points.")
ydobs <- as.vector(t)/n
ydmax <- max(yd, ydobs)
plot(xvalfin + xlinesdec, yd, type = "h", xlim = c(min(xval),
max(xval) + xlinesdec), ylim = c(0, ydmax), lty = 1,
col = "red", main = "Emp. and theo. distr.",
xlab = "Data", ylab = "Density",
...)
points(xval, ydobs, type = "h", lty = 1, col = "black",
...)
legend("topright", lty = c(1, 1), col = c("black",
"red"), legend = c("empirical", paste("theoretical")),
bty = "o", bg = "white", cex = 0.6,
...)
ycdf <- do.call(pdistname, c(list(xvalfin), as.list(para)))
if (length(ycdf) != length(xvalfin))
stop("problem when computing probabilities.")
plot(xvalfin, ycdf, type = "s", xlim = c(min(xval),
max(xval) + xlinesdec), ylim = c(0, 1), lty = 1,
col = "red", main = "Emp. and theo. CDFs",
xlab = "Data", ylab = "CDF", ...)
ycdfobs <- cumsum(ydobs)
points(xval, ycdfobs, type = "p", col = "black",
...)
legend("bottomright", lty = c(1, 1), col = c("black",
"red"), legend = c("empirical", paste("theoretical")),
bty = "o", bg = "white", cex = 0.6,
...)
}
}
par(def.par)
invisible()
}
To now add a title to your plot, simply use this:
par(ask=F)
for (i in unique(Data$column_a)) {
dat <- Data[Data$column_a== i, ]
plotdist_alt(dat$count,histo = TRUE, demp = TRUE, discrete = T,
pch = 16, col = "dodgerblue1", title = i)
}
Edit: Added dummy data to test the provided loop.
df <- data.frame(column_a = rep(c("a", "b"), each = 50),
count = sample(1:1000, 100, replace = T))
par(ask=F)
for (i in unique(df$column_a)) {
dat <- df[df$column_a== i, ]
plotdist_alt(dat$count,histo = TRUE, demp = TRUE, discrete = T,
pch = 16, col = "dodgerblue1", title = i)
}
I have icons on a leaflet plot which have different colors and shapes based on some variables in my data frame. I want to include a legend on the plot that shows what each shape and color combination represents. How should I do it?
To demonstrate with dummy data:
library(leaflet)
lat1= 36+runif(n=5,min=-1,max=1)
lon1 =-115+runif(n=5,min=-1,max=1)
lat2= 35+runif(n=5,min=-0.5,max=0.5)
lon2 =-110+runif(n=5,min=-0.5,max=0.5)
lat3= 34+runif(n=5,min=-0.5,max=0.5)
lon3 =-112+runif(n=5,min=-0.5,max=0.5)
data_all=rbind(data.frame(Longitude=lon1,Latitude=lat1,Group=sample(c(16,17,18),5,replace = TRUE),condition=sample(c("red","blue","green"),5,replace = TRUE),stringsAsFactors = FALSE),
data.frame(Longitude=lon2,Latitude=lat1,Group=sample(c(16,17,18),5,replace = TRUE),condition=sample(c("red","blue","green"),5,replace = TRUE),stringsAsFactors = FALSE),
data.frame(Longitude=lon3,Latitude=lat1,Group=sample(c(16,17,18),5,replace = TRUE),condition=sample(c("red","blue","green"),5,replace = TRUE),stringsAsFactors = FALSE))
# A function to create png images for each shape and color
pchIcons = function(pch = 1, width = 30, height = 30, bg = "transparent", col = NULL, ...) {
n = length(pch)
files = character(n)
# create a sequence of png images
for (i in seq_len(n)) {
f = tempfile(fileext = '.png')
png(f, width = width, height = height, bg = bg)
par(mar = c(0, 0, 0, 0))
plot.new()
points(.5, .5, pch = pch[i], col = col[i], cex = min(width, height) / 8, ...)
dev.off()
files[i] = f
}
files
}
### ---------
leaflet(data_all)%>% addTiles() %>%
addMarkers(
data = data_all,
icon = ~ icons(
iconUrl = pchIcons(pch= Group,width=40,height=40,col=condition,lwd=4),
popupAnchorX = 20, popupAnchorY = 0
))
Based on this post, using base64enc and creating fixed filenames instead of using tempfile:
# A function to create file names
filename <- function(pch,col) paste0(pch, '_', col, '.png')
# A function to create png images for each shape and color
pchIcons = function(pch = 1, width = 30, height = 30, bg = "transparent", col = NULL, ...) {
n = length(pch)
files = character(n)
# create a sequence of png images
for (i in seq_len(n)) {
f = filename(pch[i], col[i])
png(f, width = width, height = height, bg = bg)
par(mar = c(0, 0, 0, 0))
plot.new()
points(.5, .5, pch = pch[i], col = col[i], cex = min(width, height) / 8, ...)
dev.off()
files[i] = f
}
files
}
# A function to build the legend
build_legend <- function(){
paste(sapply(strsplit(unique(paste(data_all$Group,data_all$condition)), " "),
function(x){
paste0("<img src='data:image/png;base64,",
base64enc::base64encode(filename(x[[1]], x[[2]])),
"' width='16'; height='16'> ",
"Group=",x[[1]], " Condition=", x[[2]],
"<br/>" )}), collapse = " ")
}
# The plot
leaflet(data_all)%>% addTiles() %>%
addMarkers(
data = data_all,
icon = ~ icons(
iconUrl = pchIcons(pch= Group,width=40,height=40,col=condition,lwd=4),
popupAnchorX = 20, popupAnchorY = 0)) %>%
addControl(html = build_legend(), position = "bottomleft")
I was building a custom function that automatically add legends to a plot.xts object.
Code here:
library(xts)
library(PerformanceAnalytics)
data(edhec)
R <- edhec[,1:4]
chartS <- function(R,
y = NULL,
multi.panel = FALSE,
type = "l",
yaxis.same = TRUE,
event.lines = NULL,
event.labels = NULL,
event.col = 1,
event.offset = 1.2,
event.pos = 2,
event.srt = 90,
event.cex = 1.5,
lty = 1,
lwd = 2,
legend.loc = NULL,
legend.names = NULL, ...) {
plot.xts(R, y = y, multi.panel = multi.panel,
type = type, yaxis.same = yaxis.same, lty = lty, lwd = lwd, ...)
plot_object <- xts:::current.xts_chob()
columns <- plot_object$Env$xdata
columnnames <- plot_object$Env$column_names
if(!is.null(event.lines)) {
# error occurred
addEventLines(xts(event.labels, as.Date(event.lines)),
offset = event.offset, pos = event.pos,
srt = event.srt, cex = event.cex, col = event.col, ...)
}
if(is.null(legend.loc))
legend.loc <- "topright"
if(is.null(legend.names))
legend.names <- columnnames
if(!multi.panel)
addLegend(legend.loc, legend.names, lty = lty, lwd = lwd, ...)
}
# chartS(R)
# chartS(R, lty = 1:4)
chartS(R, multi.panel = TRUE)
I failed to plot multiple windows with no messages when I set multi.panel = TRUE. But if I remove codes below plot.xts or move them to above plot.xts, it works again.
Remove codes below plot.xts
library(xts)
library(PerformanceAnalytics)
data(edhec)
R <- edhec[,1:4]
chartS <- function(R,
y = NULL,
multi.panel = FALSE,
type = "l",
yaxis.same = TRUE,
event.lines = NULL,
event.labels = NULL,
event.col = 1,
event.offset = 1.2,
event.pos = 2,
event.srt = 90,
event.cex = 1.5,
lty = 1,
lwd = 2,
legend.loc = NULL,
legend.names = NULL, ...) {
plot.xts(R, y = y, multi.panel = multi.panel,
type = type, yaxis.same = yaxis.same, lty = lty, lwd = lwd, ...)
}
# chartS(R)
# chartS(R, lty = 1:4)
chartS(R, multi.panel = TRUE)
Move codes to be above plot.xts
library(xts)
library(PerformanceAnalytics)
data(edhec)
R <- edhec[,1:4]
chartS <- function(R,
y = NULL,
multi.panel = FALSE,
type = "l",
yaxis.same = TRUE,
event.lines = NULL,
event.labels = NULL,
event.col = 1,
event.offset = 1.2,
event.pos = 2,
event.srt = 90,
event.cex = 1.5,
lty = 1,
lwd = 2,
legend.loc = NULL,
legend.names = NULL, ...) {
columns <- ncol(R)
columnnames <- colnames(R)
if(!is.null(event.lines)) {
# error occurred
addEventLines(xts(event.labels, as.Date(event.lines)),
offset = event.offset, pos = event.pos,
srt = event.srt, cex = event.cex, col = event.col, ...)
}
if(is.null(legend.loc))
legend.loc <- "topright"
if(is.null(legend.names))
legend.names <- columnnames
if(!multi.panel)
addLegend(legend.loc, legend.names, lty = lty, lwd = lwd, ...)
plot.xts(R, y = y, multi.panel = multi.panel,
type = type, yaxis.same = yaxis.same, lty = lty, lwd = lwd, ...)
}
# chartS(R)
# chartS(R, lty = 1:4)
chartS(R, multi.panel = TRUE)
Any suggestions?
You need to keep track of the plot object you're building, and return it so it auto-prints. You should also not access unexported objects (xts:::current.xts_chob()) because there's no guarantee they will remain consistent across versions.
chartS <-
function(R, y = NULL, multi.panel = FALSE, type = "l", yaxis.same = TRUE,
event.lines = NULL, event.labels = NULL, event.col = 1,
event.offset = 1.2, event.pos = 2, event.srt = 90, event.cex = 1.5,
lty = 1, lwd = 2, legend.loc = NULL, legend.names = NULL, ...)
{
plot_object <- plot.xts(R, y = y, multi.panel = multi.panel, type = type,
yaxis.same = yaxis.same, lty = lty, lwd = lwd, ...)
columns <- plot_object$Env$xdata
columnnames <- plot_object$Env$column_names
if(!is.null(event.lines)) {
plot_object <-
addEventLines(xts(event.labels, as.Date(event.lines)), offset = event.offset,
pos = event.pos, srt = event.srt, cex = event.cex, col = event.col, ...)
}
if(is.null(legend.loc))
legend.loc <- "topright"
if(is.null(legend.names))
legend.names <- columnnames
if(!multi.panel)
plot_object <- addLegend(legend.loc, legend.names, lty = lty, lwd = lwd, ...)
return(plot_object)
}
I need to remove the lower control limit and center line (and their labels) from my control chart.
Here's the code:
# install.packages('qcc')
library(qcc)
nonconforming <- c(3, 4, 6, 5, 2, 8, 9, 4, 2, 6, 4, 8, 0, 7, 20, 6, 1, 5, 7)
samplesize <- rep(50, 19)
control <- qcc(nonconforming, type = "p", samplesize, plot = "FALSE")
warn.limits <- limits.p(control$center, control$std.dev, control$sizes, 2)
par(mar = c(5, 3, 1, 3), bg = "blue")
plot(control, restore.par = FALSE, title = "P Chart for Medical Insurance Claims",
xlab = "Day", ylab = "Proportion Defective")
abline(h = warn.limits, lty = 3, col = "blue")
v2 <- c("LWL", "UWL") # the labels for warn.limits
mtext(side = 4, text = v2, at = warn.limits, col = "blue", las = 2)
This approach seems more like a "hack" than an answer and it throws a warning:
control$center <- NULL
control$limits <- NULL
plot(control, add.stats = FALSE)
Not a QC expert by any means but would this work for you? Looking at the qcc function it seems to control what needs to be plotted, so what i've done here is manipulate the limits of the LCL and CENTRE lines. I then changed the plot function to plot between some y limits which does not cover the -1 value. The description unfortunately reflects the manipulated limit values of -1.
control$limits[1] <- -1
control$center <- -1
plot(control, restore.par = FALSE, title = "P Chart for Medical Insurance Claims",
xlab = "Day", ylab = "Proportion Defective", ylim=c(0.0,0.4))
The following function will do the required chart, and you don't need to change your control object, neither to know the control's limits. Load the function, then just call:
plot.qcc2(control, restore.par = FALSE, title = "P Chart for Medical Insurance Claims", + xlab = "Day", ylab = "Proportion Defective")
Function:
#Function plotting only UCL:
plot.qcc2 <- function (x, add.stats = TRUE, chart.all = TRUE, label.limits = c( "UCL"), title, xlab, ylab, ylim, axes.las = 0, digits = getOption("digits"),
restore.par = TRUE, ...)
{
object <- x
if ((missing(object)) | (!inherits(object, "qcc")))
stop("an object of class `qcc' is required")
type <- object$type
std.dev <- object$std.dev
data.name <- object$data.name
center <- object$center
stats <- object$statistics
limits <- object$limits
lcl <- limits[, 1]
ucl <- limits[, 2]
newstats <- object$newstats
newdata.name <- object$newdata.name
violations <- object$violations
if (chart.all) {
statistics <- c(stats, newstats)
indices <- 1:length(statistics)
}
else {
if (is.null(newstats)) {
statistics <- stats
indices <- 1:length(statistics)
}
else {
statistics <- newstats
indices <- seq(length(stats) + 1, length(stats) +
length(newstats))
}
}
if (missing(title)) {
if (is.null(newstats))
main.title <- paste(type, "Chart\nfor", data.name)
else if (chart.all)
main.title <- paste(type, "Chart\nfor", data.name,
"and", newdata.name)
else main.title <- paste(type, "Chart\nfor", newdata.name)
}
else main.title <- paste(title)
oldpar <- par(bg = qcc.options("bg.margin"), cex = qcc.options("cex"),
mar = if (add.stats)
pmax(par("mar"), c(8.5, 0, 0, 0))
else par("mar"), no.readonly = TRUE)
if (restore.par)
on.exit(par(oldpar))
plot(indices, statistics, type = "n", ylim = if (!missing(ylim))
ylim
else range(statistics, limits, center), ylab = if (missing(ylab))
"Group summary statistics"
else ylab, xlab = if (missing(xlab))
"Group"
else xlab, axes = FALSE, main = main.title)
rect(par("usr")[1], par("usr")[3], par("usr")[2], par("usr")[4],
col = qcc.options("bg.figure"))
axis(1, at = indices, las = axes.las, labels = if (is.null(names(statistics)))
as.character(indices)
else names(statistics))
axis(2, las = axes.las)
box()
lines(indices, statistics, type = "b", pch = 20)
if (length(center) == 1)
alpha <- 1
else lines(indices, c(center, center[length(center)]), type = "s")
if (length(lcl) == 1) {
abline(h = ucl, lty = 2)
}
else {
lines(indices, ucl[indices], type = "s", lty = 2)
}
mtext(label.limits, side = 4, at = c(rev(ucl)[1],rev(ucl)[1]),
las = 1, line = 0.1, col = gray(0.3))
if (is.null(qcc.options("violating.runs")))
stop(".qcc.options$violating.runs undefined. See help(qcc.options).")
if (length(violations$violating.runs)) {
v <- violations$violating.runs
if (!chart.all & !is.null(newstats)) {
v <- v - length(stats)
v <- v[v > 0]
}
points(indices[v], statistics[v], col = qcc.options("violating.runs")$col,
pch = qcc.options("violating.runs")$pch)
}
if (is.null(qcc.options("beyond.limits")))
stop(".qcc.options$beyond.limits undefined. See help(qcc.options).")
if (length(violations$beyond.limits)) {
v <- violations$beyond.limits
if (!chart.all & !is.null(newstats)) {
v <- v - length(stats)
v <- v[v > 0]
}
points(indices[v], statistics[v], col = qcc.options("beyond.limits")$col,
pch = qcc.options("beyond.limits")$pch)
}
if (chart.all & (!is.null(newstats))) {
len.obj.stats <- length(object$statistics)
len.new.stats <- length(statistics) - len.obj.stats
abline(v = len.obj.stats + 0.5, lty = 3)
mtext(paste("Calibration data in", data.name), at = len.obj.stats/2,
adj = 0.5, cex = 0.8)
mtext(paste("New data in", object$newdata.name), at = len.obj.stats +
len.new.stats/2, adj = 0.5, cex = 0.8)
}
if (add.stats) {
plt <- par()$plt
usr <- par()$usr
px <- diff(usr[1:2])/diff(plt[1:2])
xfig <- c(usr[1] - px * plt[1], usr[2] + px * (1 - plt[2]))
at.col <- xfig[1] + diff(xfig[1:2]) * c(0.1, 0.4, 0.65)
mtext(paste("Number of groups = ", length(statistics),
sep = ""), side = 1, line = 5, adj = 0, at = at.col[1],
font = qcc.options("font.stats"), cex = qcc.options("cex.stats"))
center <- object$center
if (length(center) == 1) {
mtext(paste("Center = ", signif(center[1], digits),
sep = ""), side = 1, line = 6, adj = 0, at = at.col[1],
font = qcc.options("font.stats"), cex = qcc.options("cex.stats"))
}
else {
mtext("Center is variable", side = 1, line = 6, adj = 0,
at = at.col[1], qcc.options("font.stats"), cex = qcc.options("cex.stats"))
}
mtext(paste("StdDev = ", signif(std.dev, digits), sep = ""),
side = 1, line = 7, adj = 0, at = at.col[1], font = qcc.options("font.stats"),
cex = qcc.options("cex.stats"))
if (length(unique(lcl)) == 1)
alpha <- 0
#mtext(paste("LCL = ", signif(lcl[1], digits), sep = ""),
# side = 1, line = 6, adj = 0, at = at.col[2],
# font = qcc.options("font.stats"), cex = qcc.options("cex.stats"))
else mtext("LCL is variable", side = 1, line = 6, adj = 0,
at = at.col[2], font = qcc.options("font.stats"),
cex = qcc.options("cex.stats"))
if (length(unique(ucl)) == 1)
mtext(paste("UCL = ", signif(ucl[1], digits), sep = ""),
side = 1, line = 7, adj = 0, at = at.col[2],
font = qcc.options("font.stats"), cex = qcc.options("cex.stats"))
else mtext("UCL is variable", side = 1, line = 7, adj = 0,
at = at.col[2], font = qcc.options("font.stats"),
cex = qcc.options("cex.stats"))
if (!is.null(violations)) {
mtext(paste("Number beyond limits =", length(unique(violations$beyond.limits))),
side = 1, line = 6, adj = 0, at = at.col[3],
font = qcc.options("font.stats"), cex = qcc.options("cex.stats"))
mtext(paste("Number violating runs =", length(unique(violations$violating.runs))),
side = 1, line = 7, adj = 0, at = at.col[3],
font = qcc.options("font.stats"), cex = qcc.options("cex.stats"))
}
}
invisible()
}