To begin, we will expand our Chapter 8 bar chart using arguments specifically designed for the barplot(...)
function. We will also become familiar with two different types of bar charts.
> #set the R working directory > #replace the sample location with one that is relevant to you > setwd("/Users/johnmquick/rBeginnersGuide/")
> #load the chapter 9 workspace > load("rBeginnersGuide_Ch_09_ReadersCopy.RData")
names, width
, and space
arguments to customize a chart's bars:> #modify the chapter 8 bar chart that compared the mean durations of the battle methods > #use the names argument to assign a text label to each bar > #the names argument receives a vector containing text labels for each of the chart's bars > barAllMethodsDurationNames <- c("Fire", "Ambush", "Head to Head", "Surround") > #use the width argument to change the width of each bar > #note that width can be set using a single value for all bars or by creating a vector to hold a unique value for each bar > #note that the xlim argument must be defined in order to use the single value approach > barAllMethodsDurationLimX <- c(0, 4) > barAllMethodsDurationWidth <- 0.25 > #use the space argument to change the distance between each bar > #the space value is a ratio of the average bar width; it defaults to 0.2 > #note that space can be set using a single value for all bars or by creating a vector to hold a unique value for each bar > barAllMethodsDurationSpace <- 2 > #use barplot(...) to create and display the bar chart > barplot(height = barAllMethodsDurationBars, main = barAllMethodsDurationLabelMain, xlab = barAllMethodsDurationLabelX, ylab = barAllMethodsDurationLabelY, xlim = barAllMethodsDurationLimX, ylim = barAllMethodsDurationLimY, col = barAllMethodsDurationRainbowColors, names = barAllMethodsDurationNames, width = barAllMethodsDurationWidth, space = barAllMethodsDurationSpace)
horiz
argument to change the chart's orientation:> #set a bar chart's orientation using the horiz argument > #if TRUE, the bars will display horizontally > #if FALSE (default), the bars will display vertically > barAllMethodsDurationHoriz <- TRUE > #note that you must reorient the chart for it to display properly > #this can be accomplished by switching the values of all arguments related to the x and y axes > #use barplot(...) to create and display the bar chart > barplot(height = barAllMethodsDurationBars, main = barAllMethodsDurationLabelMain, xlab = barAllMethodsDurationLabelY, ylab = barAllMethodsDurationLabelX, xlim = barAllMethodsDurationLimY, ylim = barAllMethodsDurationLimX, col = barAllMethodsDurationRainbowColors, names = barAllMethodsDurationNames, width = barAllMethodsDurationWidth, space = barAllMethodsDurationSpace, horiz = barAllMethodsDurationHoriz)
Note that if your bar labels do not all appear along the y-axis, you may want to resize the graphic window. Making your window larger will provide it with enough space to display all of the chart's labels.
beside
argument to create a stacked bar chart:> #create a new bar chart to demonstrate the stacking feature > #create a bar chart that depicts the average number of soldiers involved in each battle method with stacked bars for the Shu and Wei forces > #set the stacking of a chart's bars using the beside argument > #if TRUE (default), the bars will display next to one another > #if FALSE, the bars will display atop one another > barAllMethodsSoldiersBeside <- FALSE > #note that the bar values must be in matrix form for the beside argument to take effect > #calculate the bar values for each method > #fire > meanShuSoldiersFire <- mean(subsetFire$ShuSoldiers) > meanWeiSoldiersFire <- mean(subsetFire$WeiSoldiers) > #ambush > meanShuSoldiersAmbush <- mean(subsetAmbush$ShuSoldiers) > meanWeiSoldiersAmbush <- mean(subsetAmbush$WeiSoldiers) > #head to head > meanShuSoldiersHeadToHead <- mean(subsetHeadToHead$ShuSoldiers) > meanWeiSoldiersHeadToHead <- mean(subsetHeadToHead$WeiSoldiers) > #surround > meanShuSoldiersSurround <- mean(subsetSurround$ShuSoldiers) > meanWeiSoldiersSurround <- mean(subsetSurround$WeiSoldiers) > #put the bar values into matrix form using the matrix(...) function > #the matrix should have four columns (one for each method) and two rows (one for each kingdom) > #when the chart is created, the rows will be stacked within each column > barAllMethodsSoldiersBars <- matrix(c(meanShuSoldiersFire, meanWeiSoldiersFire, meanShuSoldiersAmbush, meanWeiSoldiersAmbush, meanShuSoldiersHeadToHead, meanWeiSoldiersHeadToHead, meanShuSoldiersSurround, meanWeiSoldiersSurround), 2, 4) > #customize the chart > barAllMethodsSoldiersMain <- "Average Number of Soldiers Engaged in Battle by Kingdom" > barAllMethodsSoldiersMain <- "Average Number of Soldiers Engaged in Battle by Kingdom" > barAllMethodsSoldiersLabX <- "Battle Method" > barAllMethodsSoldiersLabY <- "Number of Soldiers" > barAllMethodsSoldiersNames <- c("Fire", "Ambush", "Head to Head", "Surround") > #use barplot(...) to create and display the bar chart > barplot(height = barAllMethodsSoldiersBars, main = barAllMethodsSoldiersMain, xlab = barAllMethodsSoldiersLabX, ylab = barAllMethodsSoldiersLabY, names = barAllMethodsSoldiersNames, beside = barAllMethodsSoldiersBeside)
density
and angle
arguments to change the shading of the chart's bars:> #use the density argument to define the thickness of the shaded lines > #density receives either a single nonnegative value for all matrix rows or a vector containing a value for each row > #density is measured in lines per inch with a default value of NULL > barAllMethodsSoldiersDensity <- c(10, 25) > #angle modifies the angle of the shaded lines > #angle receives either a single value for all matrix rows or a vector containing a value for each row > #angle is measured in degrees > barAllMethodsSoldiersAngle <- c(45, -45) > #use barplot(...) to create and display the bar chart > barplot(height = barAllMethodsSoldiersBars, main = barAllMethodsSoldiersMain, xlab = barAllMethodsSoldiersLabX, ylab = barAllMethodsSoldiersLabY, names = barAllMethodsSoldiersNames, beside = barAllMethodsSoldiersBeside, density = barAllMethodsSoldiersDensity, angle = barAllMethodsSoldiersAngle)
> #add a legend to the stacked bar chart > #use the x and y arguments to specify the exact location of the legend > #note that the possible x and y values are determined by the limits of your axes > #add labels for the Shu and Wei armies > #incorporate the density and angle arguments from our barplot(...) function > #use cex to increase the size of the legend > legend(x = 0.2, y = 70000, legend = c("Shu", "Wei"), density = barAllMethodsSoldiersDensity, angle = barAllMethodsSoldiersAngle, cex = 2)
We created vertical, horizontal, and stacked bar charts using the barplot(...)
function and its custom arguments. We also expanded upon the legend(...)
function to gain more control over its appearance. Let us reflect upon each of these steps.
We started by adding text labels to our bars via the names
argument. This argument receives a vector containing the text label to be appended to each bar. In our case, the labels consisted of the four battle methods that follow:
barAllMethodsSoldiersNames <- c("Fire", "Ambush", "Head to Head", "Surround")
Then, we looked at two arguments that are unique to the barplot(...)
function. The width
argument specifies the thickness of a chart's bars. It can be defined as a single value for all bars or a vector that contains unique values for each bar. Note that if a single value is used, the xlim
argument must be defined for the width
argument to take effect. In coordination with width
, we also employed the space
argument, which determines the distance between a chart's bars. Like width, space
can be defined as a single value or a vector containing values for each bar. It is measured as a ratio of the average bar width and defaults to a value of 0.2. For example, if the average width of the bars was 5 and the space
was set to 0.5, then the distance between each bar would be 2.5. For our chart, we chose a width of 0.25 and a space of 2, which had the visual effect of making our bars skinnier and spread farther apart:
> barAllMethodsDurationWidth <- 0.25 > barAllMethodsDurationSpace <- 2
We chose uniform width and space values for our bars. Had we wanted to set unique values for each bar, such as when weighting the bars according to the number of data points they include, we could have used the following code:
> barAllMethodsDurationWidth <- c(0.1, 0.25, 0.5, 0.75) > barAllMethodsDurationSpace <- c(0.5, 1, 1.5, 2)
Lastly, the names, width
, and space
arguments were incorporated into our overall barplot(...)
function:
> barplot(height = barAllMethodsDurationBars, main = barAllMethodsDurationLabelMain, xlab = barAllMethodsDurationLabelX, ylab = barAllMethodsDurationLabelY, xlim = barAllMethodsDurationLimX, ylim = barAllMethodsDurationLimY, col = barAllMethodsDurationRainbowColors, names = barAllMethodsDurationNames, width = barAllMethodsDurationWidth, space = barAllMethodsDurationSpace)
To further expand our bar chart, we incorporated the horiz
argument. This argument allows us to reorient our bars such that they extend horizontally, rather than vertically, across the chart. The horiz
argument receives either a TRUE
or FALSE
value indicating whether the bars should be oriented horizontally. By default, horiz
is set to FALSE
and the bars are drawn vertically. We chose to reorient our bars by setting our horiz
variable to TRUE:
barAllMethodsDurationHoriz <- TRUE
We then included it into our barplot(...)
function:
> barplot(height = barAllMethodsDurationBars, main = barAllMethodsDurationLabelMain, xlab = barAllMethodsDurationLabelY, ylab = barAllMethodsDurationLabelX, xlim = barAllMethodsDurationLimY, ylim = barAllMethodsDurationLimX, col = barAllMethodsDurationRainbowColors, names = barAllMethodsDurationNames, width = barAllMethodsDurationWidth, space = barAllMethodsDurationSpace, horiz = barAllMethodsDurationHoriz)
Note that reorienting the bars of a chart is similar in effect to rotating it by 90 degrees. Therefore, to prevent a misshapen and unreadable graphic, we must also swap all arguments related to the x and y-axes. In our case, that meant exchanging our x-axis and y-axis limits and labels:
> barplot(height = barAllMethodsDurationBars, main = barAllMethodsDurationLabelMain, xlab = barAllMethodsDurationLabelY, ylab = barAllMethodsDurationLabelX, xlim = barAllMethodsDurationLimY, ylim = barAllMethodsDurationLimX, col = barAllMethodsDurationRainbowColors, names = barAllMethodsDurationNames, width = barAllMethodsDurationWidth, space = barAllMethodsDurationSpace, horiz = barAllMethodsDurationHoriz)
After swapping these values, the chart displays appropriately. Had we forgotten to make this exchange, we would have ended up with the following graphic:
Remember to swap your x-axis and y-axis arguments when making horizontal bar charts.
We then turned to developing a new chart that would make use of the beside
argument. This argument tells a chart's bars to stack atop one another, rather than stand side by side. Like horiz, beside
accepts a TRUE
or FALSE
value. If TRUE
, the default setting, the bars will display side by side. If FALSE
, the bars will be stacked. We chose to stack our bars by setting beside
to FALSE
.
barAllMethodsSoldiersBeside <- FALSE
Note that for the beside argument to take effect, the height
argument must be in matrix form. To organize our data into a matrix, we used the matrix(...)
function, whose basic format is as follows:
matrix(values, rows, columns)
Here, values
is a vector containing the relevant data points, rows
is the number of rows, and columns
is the number of columns. Our matrix consisted of eight data points that were organized into two rows (Shu and Wei) and four columns (Fire, Ambush, Head to Head, and Surround). In the final chart, the four bars are formed by stacking the two rows within each column; the following is the code:
> barAllMethodsSoldiersBars <- matrix(c(meanShuSoldiersFire, meanWeiSoldiersFire, meanShuSoldiersAmbush, meanWeiSoldiersAmbush, meanShuSoldiersHeadToHead, meanWeiSoldiersHeadToHead, meanShuSoldiersSurround, meanWeiSoldiersSurround), 2, 4)
Our stacked bar chart depicted the average number of soldiers that are engaged in each type of battle. By stacking our bars, we were able to specify what proportion of the soldiers came from the Shu and Wei armies. Thus, our chart was able to include more information in the same amount of space:
> barplot(height = barAllMethodsSoldiersBars, main = barAllMethodsSoldiersMain, xlab = barAllMethodsSoldiersLabX, ylab = barAllMethodsSoldiersLabY, names = barAllMethodsSoldiersNames, beside = barAllMethodsSoldiersBeside)
After beside
, we used the density
and angle
arguments to define the shading of our bars. The density
argument defines the closeness of the shaded lines. It receives either a single non-negative value for all matrix rows or a vector that contains values for each row. The angle
argument specifies the angle at which the shaded lines are to be drawn. It also accepts a single value for all matrix rows or a vector containing values for each row.
Our stacked bar chart used a density of 10
for the Shu row and 25
for the Wei row:
> barAllMethodsSoldiersDensity <- c(10, 25)
It also featured an angle of 45
for the Shu and -45
for the Wei:
> barAllMethodsSoldiersAngle <- c(45, -45)
Hence, you will notice that the shading in the Shu portions of our bars is spread thinner and rises to the upper-right of the chart, whereas the shading in the Wei portions of the chart is thicker and declines towards the lower-right of the chart:
> barplot(height = barAllMethodsSoldiersBars, main = barAllMethodsSoldiersMain, xlab = barAllMethodsSoldiersLabX, ylab = barAllMethodsSoldiersLabY, names = barAllMethodsSoldiersNames, beside = barAllMethodsSoldiersBeside, density = barAllMethodsSoldiersDensity, angle = barAllMethodsSoldiersAngle)
In the final step, we added a legend to our chart. A legend is critical to a stacked bar chart, because it indicates the difference between its grouped regions. Our legend(...)
function expanded upon the legends that we created in the previous chapter. We positioned the legend towards the upper-left side of the chart using the x
and y
arguments. We also specified the labels that we wanted to show in the legend (Shu and Wei). By default, the legend would have displayed the bar names (Fire, Ambush, Head to Head, and Surround). Since we needed to display the stacked segments of each bar instead, we had to specifically define them as a vector in the legend
argument. Next, we incorporated the exact density
and angle
arguments from our barplot(...)
function. This matched the legend's shading to that of our chart. To complete our legend, we used the cex
argument to multiply its size by 2
times. The cex
argument accepts a numeric value that indicates how much a legend should be scaled by. Increasing the size of our legend made it easier to read, thus enabling viewers to quickly distinguish between our chart's stacked regions:
> legend(x = 0.2, y = 70000, legend = c("Shu", "Wei"), density = barAllMethodsSoldiersDensity, angle = barAllMethodsSoldiersAngle, cex = 2)
barplot(...)
function, what is the relationship between the width
and space
arguments?a. width
sets the distance between the bars, while space
sets the thickness of the bars.
b. width
sets the thickness of the bars, while space
sets the distance between the bars.
c. space
sets the range of the bars on the x-axis, while width
sets the length of the bars.
d. space
sets the length of the bars, while width
sets the range of the bars on the x-axis.
barplot(...)
function, which of the following is not critical to note when using the horiz
argument?a. It accepts either a TRUE
(for horizontal bars) or FALSE
(for vertical bars) value.
b. It defaults to FALSE
.
c. When TRUE
, all arguments related to the x and y axes must be swapped for the chart to display properly.
d. When undefined, the barplot(...)
function will draw horizontal bars.
barplot(...)
function, which of the following is not critical to note when using the beside
argument?a. It accepts either a TRUE
(for adjacent bars) or FALSE
(for stacked bars) value.
b. It defaults to FALSE
.
c. To take effect, the chart's height
data must be in matrix form.
d. When FALSE
, it is advisable to include a legend with the chart.
Use your soldiersByCity
dataset to create a chart that depicts the total number of soldiers in the Shu and Wei armies as two separate bars. Then create a stacked bar chart with the same data, but separate the Shu and Wei bars into distinct sections for each city. Compare these two charts and reflect upon the pros and cons of using each.