# bp3way() version 3.2 plots 3-way bubble plots # This replaces bpplot.3 # Keith A. Markus # 3 November 2008 # bp3way <- function(x, xc=1, bc=2, yc=3, proportion=1, random=TRUE, x.margin=.1, y.margin=.1, rad.ex=1, rad.min=NULL, names=c('X', 'B', 'Y'), std=FALSE, fg='black', bg='grey90', tacit=TRUE, main=NULL, grid=TRUE, hlen=25, vlen=25, hlwd=1, vlwd=1, hlty=1, vlty=1, hcol='grey50', vcol='grey50', ...) { # Checks x.margin <- max(x.margin, 0) y.margin <- max(y.margin, 0) if(!is.null(rad.min)) {rad.min <- max(rad.min, 0)} # For action when rad.min is NULL, see calculations below. rad.ex <- max(rad.ex, 0) proportion <- min(max(proportion, 0) , 1) if(!(is.data.frame(x) & length(x)>= 1)) {stop('x is not a data frame with at least one variable')} if(xc > length(x)) {stop('xc is out of range')} if(yc > length(x)) {stop('yc is out of range')} if(bc > length(x)) {stop('bc is out of range')} # Sample size calculations N <- length(x[,xc])# Length of data set plotN <- round(proportion * N) # Length of plotted portion # Plot title if(is.null(main)) {main <- paste(names[bc], 'by', names[xc], 'and', names[yc], sep=' ')} # Random Sample Ran.ord <- order(rnorm(N,0,1)) # Randomized order ABC <- x # Copy of data frame if (random == TRUE) ABC <- x[Ran.ord,] # Conditional randomization # Standardize all variables if(std==TRUE) { A <- (ABC[,xc] - mean(ABC[,xc]))/sd(ABC[,xc]) C <- (ABC[,yc] - mean(ABC[,yc]))/sd(ABC[,yc]) } else { A <- (ABC[,xc]) C <- (ABC[,yc]) } B <- (ABC[,bc] - mean(ABC[,bc]))/sd(ABC[,bc]) ABC <- data.frame(A, B, C) # All Positive Y values if(min(ABC[,2][1:plotN]) < 0) {ABC[,2] <- (ABC[,2] + (-1 * min(ABC[,2][1:plotN])))} # Margin Calculation A.range <- max(ABC[,1][1:plotN]) - min(ABC[,1][1:plotN]) C.range <- max(ABC[,3][1:plotN]) - min(ABC[,3][1:plotN]) x.marg <- A.range * x.margin y.marg <- C.range * y.margin # rad.min Calculation if(is.null(rad.min)) {rad.min <- A.range * .025} # Grid calculations if(isTRUE(grid)) { vertical.grid.lines <- seq(min(ABC[,1][1:plotN]) - (2 * x.marg), max(ABC[,1][1:plotN]) + (2 * x.marg), len=vlen) horizontal.grid.lines <- seq(min(ABC[,3][1:plotN]) - (2 * y.marg), max(ABC[,3][1:plotN]) + (2 * y.marg), len=hlen) #Note: margins are multiplied by 2 to avoid gaps along axes. } # Output to Console if(tacit==FALSE) { print(noquote('Bubble Plot Parameters')) print(noquote(paste(' Radius Expansion Factor:', rad.ex))) print(noquote(paste(' Minimum Radius:', rad.min))) print(noquote(paste(' X Margin:', x.margin))) print(noquote(paste(' Y Margin:', y.margin))) print(noquote(paste(' Plotted Proportion:', proportion))) print(noquote(paste(' Standardized:', std))) } # Bubble Plot plot(seq(min(ABC[,1][1:plotN]) - x.marg, max(ABC[,1][1:plotN]) + x.marg, len=10), seq(min(ABC[,3][1:plotN]) - y.marg, max(ABC[,3][1:plotN]) + y.marg, len=10), type='n', xlab=names[xc], ylab=names[yc], main=main, sub=paste('Point Size =', names[bc], sep=' ') ) radii <- rad.min + (C.range * .025 * rad.ex * (ABC[,2][1:plotN] / max(ABC[,2][1:plotN])) ) symbols(x = ABC[,1][1:plotN], y = ABC[,3][1:plotN], circles = radii, fg=fg, bg=bg, add=T, inches=F) symbols(x = ABC[,1][1:plotN], y = ABC[,3][1:plotN], circles = radii, add=T, inches=F) if(isTRUE(grid)) { abline(h=horizontal.grid.lines, lty=hlty, col=hcol, lwd=hlwd) abline(v=vertical.grid.lines, lty=vlty, col=vcol, lwd=vlwd) } # Returned Value return( invisible( list( full.data = ABC, plot.data = ABC[1:plotN,], xc = xc, bc = bc, yc = yc, proportion = proportion, random = random, x.margin = x.margin, y.margin = y.margin, rad.ex = rad.ex, rad.min = rad.min, names = names, std = std, fg = fg, bg = bg, tacit = tacit, x.actual.margin = x.marg, y.actual.margin = y.marg, main=main, grid=grid, hlen=hlen, vlen=vlen, hlwd=hlwd, vlwd=vlwd, hlty=hlty, vlty=vlty, hcol=hcol, vcol=vcol ) ) ) } # bp3way Help # # Description # # Draws 2-dimensional bubble plots displaying a tri-variate relationship. # # Usage # # bp3way(x, xc=1, bc=2, yc=3, proportion=.05, random=TRUE, x.margin=.1, # y.margin=.1, rad.ex=1, rad.min=NULL, names=c('X', 'Y', 'Z'), std=FALSE, # fg='black', bg='grey90', tacit=TRUE, ...) # # bp3way(x) # # Arguments # # x Data frame with at least 1 variable # xc Column in the data frame containing x-axis variable # bc Column in the data frame containing the bubble size variable # yc Column in the data frame containing the y-axis variable # proportion The proportion of cases to plot # random Cases sampled at random if TRUE, in order provided if FALSE # x.margin Controls space between plot area and x axis edges # y.margin Controls space between plot area and y axis edges # rad.ex Controls relative size of bubbles # rad.min Controls minumum size of bubbles # names A vector of display labels for x, b, and y (in that order) # fg Bubble edge color # bg Bubble fill color # tacit Controls output to console, handy for dubugging a plot # main Plot main title # grid Logical controls use of grid lines # hlen Number of horizontal lines # vlen Number of vertical lines # hlwd Width of horizontal lines # vlwd Width of vertical lines # hlty Type of horizontal lines # vlty Type of vertical lines # hcol Color of horizontal lines # vcol Color of vertical lines # # Details # # Defaults are intended to provide reasonable plots for # most data. Control parameters allow user to compensate # when this is not so. # # Value # # Returns a list containing the full data, plotted data, # and plot parameters. # # References # # See Also # # pb.data() for data simulation.plot() and symbols() for core R functions. # # Examples # x <- rnorm(100,50,10) # z <- rnorm(100,100,20) # y <- 10 + (-1 * x) + (z) + (-1 * x * z) + rnorm(100,0,1) # xyz <- data.frame(X=x,y,z) # # Default plot: # bp3way(xyz) # # Effect of standardization: # bp3way(xyz, proportion=1, names=c('Stores', 'Prices', 'Sales')) # bp3way(xyz, proportion=1, names=c('Stores', 'Prices', 'Sales'), std=T) # # Switch variable order: # bp3way(xyz, bg='pink', proportion=1) # bp3way(xyz, bg='pink', proportion=1, xc=3, yc=1) # # Save plot vlaues for further use: # MyPlot <- bp3way(xyz) # MyPlot