Code
# install.packages("devtools") #IF NOT ALREADY INSTALLED
::install_github("https://github.com/MAISRC/ggplot_plus") #<--NOTE THE _ INSTEAD OF THE . IN THE PACKAGE NAME. devtools
To use the ggplot.plus
package, you’ll need to install it from GitHub using the devtools
package (you only need to do this once for each release):
# install.packages("devtools") #IF NOT ALREADY INSTALLED
::install_github("https://github.com/MAISRC/ggplot_plus") #<--NOTE THE _ INSTEAD OF THE . IN THE PACKAGE NAME. devtools
Then, load it alongside ggplot2
:
# install.packages("ggplot2") #IF NOT ALREADY INSTALLED
library(ggplot2)
library(ggplot.plus)
This guide introduces the ggplot.plus
package—a collection of tools developed by Dr. Alex Bajcz, Quantitative Ecologist at the Minnesota Aquatic Invasive Species Research Center (MAISRC) at the University of Minnesota. The tools in these package are meant to provide an opinionated, Universal-Design-oriented veneer overtop of ggplot2
’s existing tools and defaults, with the goal of making accessible graphs based on design best practices quicker and more painless.
This guide is intended to offer a practical (if not totally comprehensive) overview of how the tools in this package can be used and is especially aimed at users who are relatively new to ggplot2
and relatively unfamiliar with its inner workings.
At its core, ggplot.plus
re-imagines the default aesthetics of ggplot2
. While a typical one-line ggplot()
call yields a functional graphic, it will often fall short of modern best practices in data visualization and graph design, including with respect to accessibility. As such, many simple ggplot()
calls do not immediately yield graphs fit for publication.
Of course, experienced users of ggplot2
can use its tools, like theme()
, scale_*()
, and geom_*()
, to redesign and customize their graphs to meet the highest standards, but doing so requires hard-won knowledge of how these tools work and can be tedious to implement even when you have the knowledge to do so. Plus, even if one has the technical know-how, not everyone is familiar enough with the tenets of data visualization to know what to change and how. The ggplot.plus
package is designed to help users of all experience levels start from a more accessible baseline, but without sacrificing ggplot2
’s capacity for individuality and experimentation.
Accessibility is a major design focus of ggplot.plus
. Many of its defaults are intended to improve compliance with modern accessibility standards, and this guide will attempt to highlight those cases whenever relevant.
To be clear: ggplot.plus
is not a replacement for making careful design choices, personal artistry, solicitation of feedback, or understanding your audience’s needs and capabilities. Instead, it’s meant to be a new (and arguably better) starting point. While the design choices baked into its tools ultimately reflect Dr. Bajcz’s professional judgments, they are grounded in a thorough review of the last several decades of the data visualization literature, so they don’t primarily reflect his personal opinions about good graph design (though they also do!).
The ggplot.plus
package is guided by three core principles:
Better Defaults:
Many default settings in ggplot2
are functional but sub-optimal in terms of design and accessibility. ggplot.plus
attempts to improve upon these—adjusting colors, shapes, gridlines, spacing, text, etc. to yield cleaner, more accessible products from the outset.
Customization:
All defaults set by ggplot.plus
’s tools can be overridden by the user, either through standard ggplot2
syntax or using _plus
variants using optional arguments. You’re rarely (if ever) stuck with any of the opinions baked into these tools (even though they have these opinions for a reason!).
Modularity:
Each tool in ggplot.plus
is designed to be additive. Sure, you can use just one or two (e.g., theme_plus()
or geom_plus()
), but the idea is to call all relevant ones together to achieve the full effect.
The package has several core functions and a couple of more situational ones:
Function | Purpose |
---|---|
geom_plus() |
A general wrapper for all supported ggplot2 geoms, enforcing opinionated design choices. |
geom_point_plus() |
An alternative version to geom_point() that introduces a new palette of shapes designed to be more readily differentiated. |
theme_plus() |
An opinionated version of ggplot2 ’s base theme_gray theme, with changes to the settings for size, spacing, legend placement, and much more. |
scale_x/y/color/fill_continuous_plus() |
Drop-in replacements for scale_x/y/color/fill_continuous() that will attempt to ensure axis breakpoints and limits are appropriate for fully labeling the entire parameter space encompassed by your data. |
yaxis_title_plus() |
A function for relocating the y axis title from its normal, less accessible location and orientation. |
palettes_plus() |
Converts ggplot2 ’s default color palette for color and fill aesthetics over to viridis ’s more accessible color palettes for the session. |
gridlines_plus() |
Adds subtle gridlines only when and where justified to add the minimal cognitive load to the graph. |
Each of these is discussed in more depth in the sections that follow, along with examples.
ggplot
for ComparisonLet’s start by creating a simple, one-line ggplot2
plot to use as a reference. The code below generates a scatterplot of petal length vs. sepal length for iris flowers from three species. These data come from the iris
data set, which is automatically included with every installation of R. Points in the scatterplot are colored according to species:
ggplot(data = iris, #<--THE DATA SET
mapping = aes(x = Petal.Length, #<--MAPPING OUR AESTHETICS, I.E., SAYING "*THIS* VARIABLE IN THE DATA SET SHOULD USE *THAT* VISUAL CHANNEL IN THE GRAPH". HERE, WE'RE SAYING MAP PETAL LENGTH TO HORIZONTAL (X) POSITION AND SEPAL LENGTH TO VERTICAL (Y) POSITION.
y = Sepal.Length)) +
geom_point(mapping = aes(color = Species)) #<--WE ALSO MAP SPECIES TO THE VISUAL CHANNEL OF COLOR.
This graph is simple and reasonably effective—it’s perfectly suitable for exploratory work or sharing informally with colleagues. However, for presentation or publication, it falls short in several respects. Some of the key issues one might take with this graph are:
Text size: The default font size for axis and legend text is too small for easy reading, especially for those with visual impairments. A common rule of thumb is: if the text feels almost too large to you (assuming you have “standard” vision), it’s probably just right for those with visual impairment. Said differently, text should generally be on the verge of looking “stupidly large” to be large enough!
Point size: The points are also quite small, which can hinder readability for some users. The same rule applies here—data elements should be larger than you probably think.
Color palette: ggplot2
’s default “rainbow” color palette lacks variance in luminance (how “bright” or “dark” the color is). For someone who is colorblind (especially red-green colorblind), the red and green shades used are very difficult to distinguish. For those with no color vision at all, or for those using black-and-white viewing technologies, all three hues here would be virtually indistinguishable.
Foreground/background contrast: While contrast (the ease with which nearby elements can be distinguished from one another on the basis of color) between the points and the background here is ok, it could be improved by using darker point colors and/or a lighter plot background color. As noted above, it would also help if the different color shades used for the points contrasted better with each other. High contrast is critical for accessible and quickly interpretable graph design.
Whitespace and layout: Default ggplot
s can suffer from cramped layouts. In particular, spacing is often tight between:
Axis titles and the paired axis labels.
Items within the legend(s).
Axis labels on densely labeled axes (not an issue here, but often a problem)
Adding more void space (space not housing any element) between components helps readers visually parse and process the plot, especially those with cognitive or visual impairments.
Axis readability: In ggplot2
, axis and legend titles and labels will default to the column names/values found in the data set unless the user sets custom text for them. These default title/label strings are often “computer-y” (e.g., they lack spaces, have unusual capitalization, and contain punctuation instead of spaces, etc.) rather than designed for human readability or interpretation. Axis titles and labels should have standard spelling, spacing, and punctuation, and they should be readily human-interpretable and contain units, if applicable.
Gridlines: The research on the merits of gridlines is, admittedly, mixed. They:
Can reduce contrast between themselves and the background and between themselves and the data elements.
Increase cognitive load (the amount of mental effort needed to integrate the available information and form conclusions) by adding visual information to the plotting area that must be parsed and either integrated or dismissed. When they are not needed or dismissed, they may constitute visual clutter that slows down interpretation.
Are unhelpful when included for scales linked to discrete data.
On the flip side, gridlines are familiar to some novice graph readers and can thus serve as a “foothold” for them to understand a graph. They can also help readers estimate exact values when this is required.
However, most experts agree that graphs are not the most efficient device for conveying exact values. Text, tables, and sharing of raw data files are all superior! The adage to remember is that graphs ought to primarily be about “vibes!”
So, gridlines are often unnecessary. However, even when a designer deems them needed, research has shown they can and should be as faint and as infrequent as possible to minimize their costs relative to their benefits.
Incomplete axis labeling: Axes should generally include tick marks and labels at both ends of the continuum shown, both to align with reader expectations (especially those of more novice readers) and to aid in efficient comprehension. Axes are essentially “number lines,” and so should be completely graduated by labels like number lines are. On the sample graph above, both axes are missing one or more labels near the limits of the x and y axis ranges, which makes these axes feel visually “unfinished.”
Overplotting: When data elements partially or wholly overlap, it becomes hard to judge how many elements are present in a location. This limits the reader’s ability to actually gauge data density.
Vertical y-axis title: Text rotated from horizontal (0 degrees) is harder to read and less accessible—especially for dyslexics, non-native readers of the language, users with motor or visual impairments, and those with certain technological limitations, among others. Despite this, the y axis title is almost always still shown rotated 90 degrees from horizontal in scientific graphs. The y axis title is also less prominent when placed in the left margin, as it is here. Since many graphs are “about” the y-axis variable at a conceptual level, the y axis title deserves a more prominent location so readers will encounter it earlier.
Tick marks: The tick marks on the axes are small and easily lost. More prominent ticks improve usability.
No axis lines: To better visually represent “number lines,” and to demarcate the boundary between the plotting area and the axis areas, most graphs feature axis lines. However, ggplot2
graphs lack such lines by default.
Legend placement: ggplot2
’s default legend location (in the right-hand margin) is often space-inefficient, creating large voids above and below it. Plus, because most readers scan left to right, top-to-bottom, the legend is not seen early on by many readers, making it more difficult to integrate its contents with the rest of the plot. Design experts suggest that legend information should either be integrated into the plot directly (e.g., through direct labeling inside the plotting area) or else the legend should be placed somewhere where it can be more prominent and compact.
This list isn’t exhaustive, but it illustrates how even a simple ggplot
can require particular graph designers to make many tweaks to meet accessibility, clarity, and design standards. Not everyone has the time, patience, or wherewithal to do that work for every graph they make, hence why we built the ggplot.plus
package.
We noted above that the default color palette used by ggplot2
is not as accessible as it could be. Fortunately, the viridis
package—bundled with ggplot2
—includes several broadly accessible palette options. These palettes vary not just in hue (i.e., the base “color” like red, green, or blue), but also in luminance (light vs. dark). This multidimensional variance makes the colors in these palettes more universally distinguishable from one another.
The ggplot.plus
package includes a convenience function, palettes_plus()
, that run automatically on package load. It activates carefully chosen default palettes for whenever the color
/colour
or fill
aesthetics are used:
#SAME GRAPH AS BEFORE, THIS TIME WITH palettes_plus() ACTIVATED
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_point(mapping = aes(color = Species))
This function uses the titular viridis
palette for discrete variables and the cividis
palette for continuous variables. By default, viridis
spans from dark purple to light yellow, passing through blue, green, and teal. This relatively large number of hues makes it relatively easy to find several discrete hues that are visually distinct from each other and from whatever background color you use.
However, palettes_plus()
excludes, by default, the lightest yellow region of the viridis
palette because these shades can lack contrast against elements that are light-colored, as backgrounds in ggplots tend to be. As a result, the remaining palette includes just the purple/blue/teal/green region of the palette to strike a balance between accessibility and visual appeal suitable for most contexts.
However, you can easily adjust this using the function’s begin_discrete
and end_discrete
parameters, which range from 0 to 1:
begin_discrete = 0.28
would disable the dark purple portion of the color range, such as when you have dark elements or backgrounds.
end_discrete = 1
would enable the light yellow portion, such as when you don’t have other light elements.
palettes_plus(begin_discrete = 0.28,#<--DISALLOW DARK PURPLE REGION.
end_discrete = 1) #<--ALLOW YELLOW REGION.
#SAME GRAPH AS BEFORE
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_point(mapping = aes(color = Species))
In this example, we’ve disabled the purple end of the palette, which might be appropriate if you had dark elements and you needed to ensure contrast. Meanwhile, we’ve enabled the yellow region, which means we have some points that now lack sufficient contrast against the background. But no worries–we’ll fix that in a moment.
To see what the color palette looks like for continuous variables, let’s temporarily map color to a numeric variable in the data set instead:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_point(mapping = aes(color = Petal.Width)) #<--MAP COLOR TO A CONTINUOUS VARIABLE.
In contrast to viridis
, the cividis
palette has essentially just three hues: blue, gray, and yellow. Because humans like to “chunk” data into discrete groups according to hue, even in circumstances where the underlying phenomenon is continuous and nothing “special” is happening at the points of hue transition, this palette’s low number of hues results in less “false binning” of the data. After all, blue, gray, and yellow points here are quite different, so the hue differences many will perceive map accurately to differences in the underlying data.
One of the core tools in ggplot.plus
is geom_plus()
. This function is designed to replace most of the standard geom_*()
calls you’d typically use in a ggplot2
command.
It has one required argument: geom
, which should be either the first argument provided or else explicitly named. The required value should correspond to the portion after the underscore in the name of the geom_*()
function from ggplot2
you’d otherwise have called. For example:
"point"
for geom_point()
"line"
for geom_line()
"bar"
for geom_bar()
,
And so on.
So, to recreate our scatterplot using geom_plus()
, we simply swap out geom_point(...)
with geom_plus(geom = "point", ...)
:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point", #<--NEW FUNCTION, WITH GEOM INPUT.
mapping = aes(color = Species))
The primary purpose of geom_plus()
is to apply opinionated defaults that are designed to address common design concerns, especially those of accessibility. In this example:
The points are made larger and thus easier to parse.
The default shape changes from 16 to 21.
The latter change is important because shape 16 only supports the color
aesthetic, whereas shape 21 supports both color
(for the stroke/outline) and fill
(for the interior). This gives us more flexibility in our design.
By default, geom_plus()
will set the interior color for these points to "transparent"
, resulting in hollow circles. This allows partial overlaps between points to be distinguishable—though, of course, total overlap would still not discernible. We’ll present some ideas for more extreme overplotting later in the guide.
If we switch from mapping species to color
to instead mapping it to fill
, geom_plus()
will switch to using a black stroke color by default. This fixes our earlier issue wherein our yellow points lacked contrast against the light-gray background:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species)) #<--CHANGE TO FILL AESTHETIC
Because the fill colors are now surrounded by black outlines, our eyes will compare the fill color to the black directly next to it rather than to the background, resolving the contrast issue.
Even though dark purple can’t be distinguished from a black point stroke, that’s not actually a problem because the point strokes aren’t encoding any information. As a result, if we wanted more color options, we could restore the full range of the viridis palette:
palettes_plus(begin_discrete = 0, end_discrete = 1) #<--RESTORE PURPLE END OF COLOR RANGE AND RETAIN YELLOW RANGE.
#SAME GRAPH
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species))
Purple points still look purple here, whether we can distinguish their black outlines from their fill colors or not. Meanwhile, all points are easily distinguished from the background, so we can utilize the entire color space of the palette!
There are two broadly effective options for addressing overplotting in graphs like this one. The first, as we’ve already seen, is to map color to the point stroke and set the fill color to "transparent"
so that partial overlap is evident.
However, another, more aggressive option is to instead map stroke to a color that contrasts against the background well (such as black for a white background), map fill color, and make the points semi-transparent so that points that stack on top of one another “blend” chromatically:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) #<--MAKE POINTS SEMI-TRANSPARENT. 0 IS TOTALLY CLEAR, 1 IS TOTALLY OPAQUE.
At alpha = 0.3
, points maintain sufficient contrast against the background, but points in dense regions layer on top of each other, resulting in darker colors.
Note: This approach also dims the black point strokes, so contrast could still be a concern for low-vision readers. Additionally, variance in luminance will be reduced, making the graph harder to view in grayscale. What can we say: Color in graphs is hard! When overplotting is a serious concern, consider whether a scatterplot is the best way to represent your data!
ggplot2
(a Review)In ggplot2
, you can control the visual appearance of your graph using aesthetics, which connect visual channels (like position, color, size, or fill) to either variables in your data set or to constants.
There are three (partially overlapping) ways to assign aesthetics:
Global mapping: Inside aes()
in the ggplot()
call. These mappings apply to all layers (geoms).
Local mapping: Inside aes()
within a specific geom_*()
call. These only apply to the layer they are included within.
Constants: Set inside or outside aes()
within a geom or inside of aes()
within ggplot()
. This will fix the aesthetic to a single value, e.g., setting all colors to “red,” that will override any conflicting mapping.
This system gives you flexibility, but it can be confusing—especially for new users. Let’s clarify with an example that uses two geoms: a boxplot overlaid with jittered points (jittering randomly varies a point’s location data):
#NEW PLOT
ggplot(iris,
mapping = aes(x = Species, #<--MAKE THIS SPECIES, A DISCRETE VARIABLE
y = Sepal.Length)) +
geom_plus(geom = "boxplot") + #<--A NEW GEOM = BOXPLOT
geom_plus(geom = "jitter", #<--SAME POINTS AS BEFORE EXCEPT JITTERED.
mapping = aes(fill = Species),
alpha = 0.3)
Here’s what’s happening:
Global mappings of x = Species
and y = Sepal.Length
apply to both the boxplot and the jittered points.
The fill aesthetic is mapped to Species
, but only locally within the jittered points layer, so the boxplots are unaffected and don’t get species-specific fill colors.
The alpha aesthetic is set to a constant (0.3), again only locally for the jittered points. This means all points get this value.
If you map the same aesthetic in multiple places (e.g., globally and locally), the local mapping always wins—it overrides any global specification for that layer. Also, if you try to map an aesthetic to both a variable and a constant, the constant usually wins.
We bring all this up just to say that all of the same rules apply when using ggplot.plus
. You can:
Map aesthetics globally or locally.
Map aesthetics to variables in your data set or to constants.
Combine the approaches as needed–conflicts will resolve as they normally do in ggplot2
.
Here’s a similar plot with a few tweaks to illustrate this further:
ggplot(iris,
mapping = aes(x = Species,
y = Sepal.Length,
fill = Species, #<-- WE CAN SWITCH TO MAPPING FILL GLOBALLY SO IT SHOULD APPLY TO BOTH GEOMS.
color = Petal.Length)) + #<--WE ALSO MAP COLOR
geom_plus(geom = "boxplot", color = "blue") + #<--WE LOCALLY OVERRIDE COLOR, SO IT'LL BE BLUE FOR ALL BOXES INSTEAD OF LINKED TO PETAL LENGTH
geom_plus(geom = "jitter") #<--SIMPLIFY HERE.
In this version:
Fill is now applied to both geoms, since it’s mapped globally.
Color is also mapped globally but overridden locally in the boxplot layer (so boxplot outlines are blue, regardless of Petal.Length
).
Many common base geoms are already implemented in geom_plus()
. To see a list of those available, run this command:
sort(names(geom_plus_defaults))
[1] "abline" "area" "bar" "boxplot" "col"
[6] "count" "crossbar" "curve" "density" "dotplot"
[11] "errorbar" "freqpoly" "histogram" "hline" "jitter"
[16] "line" "linerange" "point" "point_plus" "pointrange"
[21] "ribbon" "segment" "smooth" "tile" "violin"
[26] "vline"
If you’d like to see additional geoms supported, you can request them using the Issues feature on the package’s Github page. And you can always use the ggplot2
version for those we’ve missed with the rest of the functions in the package.
Let’s return to our earlier scatterplot:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3)
There’s still room for improvement, including with the axis titles and labels. A key first step is to make the axis titles more human-readable, intuitive, and complete, including by specifying units. You can do this using the scale_*_*()
family of functions in ggplot2
:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous(name = "Petal length (cm)") #<--STANDARD WAY TO CHANGE THE X AXIS TITLE FOR A NUMERIC VARIABLE.
This works, but the x-axis still lacks labels near its endpoints—a common issue with ggplot2
’s default breaks-determining process. How close are the purple points to 0? The yellow points to 8? It’s hard to tell without anchors on both ends. You can fix this using scale_x_continuous_plus()
, which automatically adjusts breaks and limits to ensure label coverage near the ends of the scale:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)") #<--SWITCH TO PLUS
The axis is now expanded to start with a break at 1 and to end with a break at 7, with breaks in between still chosen to be regular and “pretty,” just as in ggplot2
.
As with the base scale
function, you can pass arguments like name
, expand
, or labels
to the _plus()
version. However, you cannot manually set breaks
or limits
, since those are managed internally by the function. If you want to specify those yourself, use the base scale_x_continuous()
instead. ggplot.plus
is opinionated!
If the resulting labels feel a little too frequent, the package’s scale_*continuous_plus()
functions contain a trick: You can set their thin_labels
argument to TRUE
to convert every other label (starting with the second) to an empty string (""
) while retaining the tick marks:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) #<--WILL CONVERT EVERY OTHER LABEL TO AN EMPTY STRING.
This reduces cognitive load and increases void space while preserving the visual scaffolding the ticks provide. Optional, but a nice touch!
There’s a matching function for the y-axis:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") #<--ADDED Y EQUIVALENT.
Here, the y-axis expands downward to include a break at 4, making the axis appear more complete and aiding interpretation.
There are also equivalent functions for fill
and color
for when these are mapped to continuous variables: scale_fill_continuous_plus()
and scale_color_continuous_plus()
. We’ll see those in the next section.
Much of ggplot2
’s visual styling is governed by the theme()
function, which controls over 100 parameters affecting how a plot looks and feels. That flexibility is powerful—but also overwhelming for beginners.
To help with this, ggplot.plus
includes theme_plus()
, a custom version of ggplot2
’s theme()
function that supercedes many of ggplot2
’s default theme settings with an eye towards publication and accessibility:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() #<--ADD PLUS THEME TO OVERRIDE THE DEFAULT.
This version of the theme makes a number of adjustments to the graph’s visual design:
Larger text for better readability.
Increased spacing between key elements (like legend keys and axis titles and their labels).
Thicker axis ticks for greater visibility and easier distinguishing between them and data elements and between them and axis lines.
Removes gridlines by default (but see next section for how to selectively reintroduce them).
White background for highest contrast against most foreground elements (well, technically, it’s a very subtle offwhite, since true white can increase eye strain over prolonged viewing).
Black axis lines at the bottom and left for visual anchoring (but no top or right borders, which typically carry no data and thus are usually extraneous).
Legend moved above the plot as a horizontal stripe, which is more space-efficient and increases the likelihood it will be encountered early on by readers.
All text rendered in black, rather than the default dark gray for some elements, to maximize contrast.
Of course, everything is still customizable. If you don’t love a particular choice—say, the thickness of the axis lines or the legend’s location—you can adjust them, same as you normally would using theme()
, except that you can pass the overrides straight into theme_plus()
instead:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus(axis.line = element_line(linewidth = 0.75)) #<--WE CAN MAKE THE AXIS LINES A LITTLE THINNER IF WE WANT. DEFAULT = 1.2
Here’s how you’d relocate the legend to its normal position–the theme will automatically apply some styling unique to this position instead:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus(legend_pos = "right") #<--ANY VALUE OTHER THAN "top" OR "right" WILL RETURN AN ERROR.
Like the rest of the ggplot.plus
toolkit, theme_plus()
is meant to be a smart starting point, not a “final destination.” Its outputs won’t be ideal for every plot, person, or context (that’s not even remotely possible!), but it’s designed to save you time by making it so there are fewer adjustments you need to make to get your graphs where they need to be.
There are a few theme considerations that apply only to color bars, which are the legend components you see when you map color
or fill
to a continuous variable. Let’s map a continuous variable to fill
to get such a legend:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Petal.Width), #<--TO GET A CONTINUOUS COLOR BAR
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus()
The changes here include longer and fatter tick marks of pure white for maximum contrast against the colors within (usually–there’s no perfect hue to use for this purpose), a black border to prevent any contrast issues with the background, and larger dimensions for easier reading and enhanced visibility.
Note that color bars can have the same issue as axes, where the ends don’t get labels at or near them. As alluded to earlier, there’s a scale_fill_continuous_plus()
function to help with that:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Petal.Width)) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
scale_fill_continuous_plus(name = "Petal width (cm)") #<--GET BETTER AXIS BREAKS AND PROVIDE CUSTOM TITLE.
The left-hand side of the scale has expanded to include 0 so that it is clear to the reader exactly which color would correspond to a value of 0
.
Our graph is nearly there (at least in our estimation!)—but one issue remains: the y axis title is still vertically oriented and tucked away in the plot’s left margin. Let’s change that.
In base ggplot2
, you can reorient the title to be horizontal, at least, using a few hacky adjustments involving line breaks and theme tweaks:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal\nlength\n(cm)") + #<--INSERT LINE BREAKS USING \n TO BREAK TITLE ONTO MANY LINES FOR SPACE EFFICIENCY.
theme_plus(axis.title.y = element_text(vjust = 0.5, angle = 0)) #<--CHANGE Y AXIS TITLE TO VERTICALLY JUSTIFIED AND HORIZONTAL.
This works reasonably well, to be honest. It’s readable, and it’s relatively simple to implement, if you know how (but that’s a big if for many ggplot2
beginners!). But it has limitations:
It steals horizontal space in the graph’s “center row” from your data, much as a right-hand legend does, and it forces a similar amount of wasted white space above and below it.
It keeps the label in a relatively unprominent location, where readers may not encounter it early.
It doesn’t scale up well to longer axis titles or those with long, unbreakable words.
To get around these challenges, ggplot.plus
includes yaxis_title_plus()
, which moves the y axis title to the top left, above the y axis line and left-justified to the edges of the y-axis labels:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") + #<--NO HACKS TO TITLE NEEDED.
theme_plus() + #<--NO THEME ADJUSTMENTS.
yaxis_title_plus() #<--THIS HANDLES EVERYTHING!
This may seem a little radical to some at first, but this small adjustment has a number of potential benefits:
Prominence: Readers of left-to-right, top-to-bottom languages naturally start in the upper-left (we read in what’s called a “Z reading frame,” which is to say we read in a pattern that traces one or more Z shapes, starting at the top left of an element), so the y axis title is now one of the first components of our graph many readers will encounter.
Readability: The title is horizontal, making it easier and faster to read for all kinds of people in all kinds of contexts.
Space efficiency: Instead of taking up room in the “data row” of the graph, the title sits in a narrow horizontal band above the plot, freeing up the core of the graphing area for your data.
Pseudo-title element: Many graph design advocates recommend against plot titles. The reason is that, at best, titles tend to do what y axis titles and captions already do, only worse. However, research suggests novice graph readers, especially, find titles helpful nonetheless. By moving the y axis title to where a plot title might reasonably go, we allow it to serve a similar purpose but with no risk of being repetitive.
No ambiguity: One hazard with moving the y axis title to anywhere other than its “normal” location is that it may become unclear what it refers to. By anchoring it above the y axis line and left-justified to the left edge of the y axis labels, there’s little, if any, ambiguity as to its purpose.
This adjustment is backed by decades of advocacy from the data visualization community (dating back to at least the 1990s). So while it’s optional, it’s not a fringe or new idea! Give it a try–you just might find you like it better too!
One neat feature: No matter how long your y axis labels get, yaxis_title_plus()
will ensure the title stays left-justified to their left edge:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)",
labels = c(4, 5, 6, "7.0000000", 8)) + #<--ONE OBNOXIOUS LABEL.
theme_plus() +
yaxis_title_plus()
If you’re using yaxis_title_plus()
and theme_plus()
together and your graph has a legend, the latter will default to a horizontal stripe at the top of the graph. By default, this stripe will sit in its own “row” above the relocated y axis title.
Sometimes, this will be necessary to get both elements to fit. However, if there is enough room for them to sit side by side, you can set move_top_legend_down
to TRUE
inside yaxis_title_plus()
to move the legend down into the same row as the relocated y axis title for some sweet sweet space efficiency:
#SAME GRAPH AS BEFORE, BUT NOW RENDERED AT A WIDTH/HEIGHT OF 9/6.
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
yaxis_title_plus(move_top_legend_down = TRUE) #<--MOVE TOP LEGEND(S) DOWN INTO SAME ROW AS Y AXIS TITLE.
Sometimes, this won’t work–the two elements will clip into one another, so just keep that in mind.
One (arguably) controversial opinion coded into ggplot.plus
’s theme_plus()
is the removal of gridlines. While some readers rely on them or expect them, many (probably the clear majority!) tend to find them distracting or visually cluttering in most situations. In fact, data viz experts often advise they not be used, as a general rule.
If you’d like to restore them, however, you can: you could manually add them using theme()
or theme_plus()
. But there’s an easier (and more opinionated) option: gridlines_plus()
. This function selectively reintroduces only the major gridlines (not minor ones) in only directions mapped to numeric variables (not discrete ones) and renders them as faintly as possible:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
yaxis_title_plus() +
gridlines_plus() #<--REINTRODUCE GRIDLINES
These gridlines default to "gray90"
. Prior research suggests gridlines this faint relative to the background color will be just visible enough for those who need help estimating values or otherwise want to use them to be able to while being light enough to easily fade into the background for everyone else.
As such, research has shown that faint, thin, and infrequent gridlines like these can improve comprehension for some readers without drawing undue attention or degrading visual contrast. That’s what we’re aiming for here.
However, if you want to tweak them in some respect or another, gridlines_plus()
allows adjustments to linetype
, color
, and linewidth
for your convenience–no need to use theme_plus()
to make those adjustments!
If we had just one continuous axis, gridlines_plus()
would automatically detect this and draw the gridlines in only the one relevant direction:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Species)) + #<--MAKE DISCRETE
geom_plus(geom = "boxplot") + #<--CHANGE GEOM TYPE.
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) + #<--NO CONTINUOUS Y ANY LONGER.
theme_plus() +
yaxis_title_plus() +
gridlines_plus()
Because gridlines are primarily designed to aid in reading exact values, there’s no need for them when an axis is discrete and thus has no exact values to read! Thus, we can simplify the presentation by omitting them in that direction.
As the above examples have demonstrated, ggplot.plus
’s core functions can be used ala carte, if that’s your preference. However, geom_plus()
can also include the operations of several other functions if you’d prefer to bundle several together into one call.
For example, our previous scatterplot could also have been generated this way:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3,
include_gridlines = TRUE, #<--TURNS ON gridlines_plus()
include_ytitle_plus = TRUE, #<--TURNS ON yaxis_title_plus()
include_yscale_plus = TRUE, #<--TURNS ON scale_y_continuous_plus()
include_theme = TRUE, #<--TURNS ON theme_plus()
y_title = "Sepal length (cm)" #<--SETS Y AXIS TITLE.
+
) scale_x_continuous_plus("Petal length (cm)", thin_labels = TRUE) #<--WE STILL SPECIFY CUSTOM LABELS AND TITLE THIS WAY, SINCE WE DON'T WANT TO ACCEPT THE DEFAULTS OF scale_x_continuous_plus().
In this example, we were able to call scale_y_continuous_plus()
, theme_plus()
, yaxis_title_plus()
, and gridlines_plus()
with their default parameters by setting the corresponding arguments inside geom_plus()
to TRUE
.
If we don’t want to accept the defaults for these, though, we need to call them separately, which is why we do not set include_xscale_plus
to TRUE
; we want to adjust the x axis labels, so we call scale_x_continuous_plus()
separately to do that.
Note that we can also specify new axis/scale titles inside geom_plus
if we want (so long as we are not subsequently calling their associated scale_*_continuous_plus()
function!).
ggplot.plus
Faceting—splitting a plot into small multiples based on one or more discrete variables—is a core ggplot2
feature, and it works with the tools provided by ggplot.plus
:
#EXAMPLE GRAPH TO SHOW FACETING FEATURES:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3,
show.legend = FALSE) + #<--SUPPRESS REDUNDANT LEGEND.
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
yaxis_title_plus() +
gridlines_plus() +
facet_grid(. ~ Species) #<--MAKE ONE SMALL MULTIPLE (PANEL) PER SPECIES (ACROSS COLUMNS)
As this example shows, many features in ggplot.plus
are compatible with faceting, though some may require extra thought.
For example, using yaxis_title_plus()
with facets works—the function automatically shuffles where facet strip labels go to ensure that they go above the top y axis title, as shown above, so the latter stays close to the axis it labels. However, for some, this could look a little confusing or awkward.
There are three potential workarounds here. The first is to facet by rows instead of columns:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3,
show.legend = FALSE) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
yaxis_title_plus() +
gridlines_plus() +
facet_grid(Species ~ .) #<--FACET ACROSS ROWS
Another option would be to relocate the facet strip labels to the bottom of the graph so they aren’t competing with the relocated y axis title:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3,
show.legend = FALSE) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
yaxis_title_plus() +
gridlines_plus() +
facet_grid(. ~ Species,
switch = "x") #<--MOVE STRIP LABELS TO BOTTOM.
A third option would be to suppress the facet strip labels and instead retain the legend:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3,
show.legend = TRUE) + #<--KEEP LEGEND.
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus(strip.background = element_blank(),
strip.text = element_blank()) + #<--SUPPRESS STRIP TEXT AND BACKGROUND.
yaxis_title_plus() +
gridlines_plus() +
facet_grid(. ~ Species)
Faceting is a relatively complex feature of ggplot2
. ggplot.plus
’s features are designed to work with it, but that doesn’t mean some creativity won’t still be involved!
You may have noticed that the legend keys—the circles in the legend that clarify fill color—are solid even though the plotted points are semi-transparent. This is not the way things normally work in ggplot2
; by default, the alpha
value applied to the points would be applied to their legend key representations as well. We can see that behavior by using geom_point()
:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_point(mapping = aes(fill = Species), #<--REVERT TO geom_point, BUT WITH SETTINGS MORE LIKE GEOM_PLUS WOULD SET.
shape = 21,
size = 5,
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() #+ #<--TURN THESE OTHER PACKAGE TOOLS OFF FOR THIS EXAMPLE.
# yaxis_title_plus() +
# gridlines_plus()
As you can see, the legend keys get the same treatment as our points here, which makes the legend keys (arguably) harder to interpret. ggplot.plus
’s geom_plus()
function attempts to see if you may have set size
and/or alpha
aesthetics that would result in legend keys that might be too faint or too small to easily read and overrides the legend aesthetics accordingly, if so.
We can observe this behavior for size as well:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
size = 1) + #<--MAKE POINTS MUCH SMALLER THAN DEFAULT.
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
yaxis_title_plus() +
gridlines_plus()
Even though the points are smaller here (far too small, really!), the legend keys are still large enough to read.
Thus far, we’ve mostly focused on graphs that use color (hue, luminance, and saturation) to communicate differences in the data. ggplot.plus
is designed to revamp how ggplot2
approaches color to yield graphs that are more accessible and interpretable while still having the aesthetic and engagement benefits of color.
However, any graph that uses color to communicate difference can only be so accessible and interpretable. A small but sizable number of humans are completely colorblind, and color perception weakens as we age. Additionally, many people still read and/or view publications in gray scale, wherein colors may not be as readily distinguished (unless they vary sufficiently in luminance).
As such, data viz advocates would remind us there are many other visual channels (ways of communicating difference in a graph) out there, including a ton baked into ggplot2
! One of these, point shape
, is a useful and classic channel for communicating difference in scatterplots like those we’ve made so far.
However, ggplot2
only makes available the same 26 point shapes for points that are available in base R:
= 0:25
pch_values
#THE SHAPES AVAILABLE IN R/GGPLOT2
plot(pch_values,
rep(1, length(pch_values)),
pch = 0:25, cex = 2)
While there is certainly some variation between these shapes, many are perceptually similar, making them difficult to distinguish quickly: Research has suggested that humans more readily distinguish shapes when they vary strongly from each other along three axes: 1) Openness, 2) Spikiness, and 3) Intersectionality.
Notably, only the last five shapes have separate outline (stroke) and interior (fill) portions, allowing them to bear separate outline and fill colors, and these five shapes are very similar with respect to openness and intersectionality, making them harder to distinguish from each other at a glance. This limits their versatility.
As such, we designed a custom version of geom_point()
, geom_point_plus()
, that introduces the ability to access nine new and thoughtfully crafted shapes that:
Intentionally vary as much as possible along the three axes described above.
Can bear separate stroke and fill colors:
geom_point_plus_shapes
These more distinctive shapes can be used to communicate difference whenever using color (alone) to do so might be undesirable or unnecessary:
set.seed(123)
ggplot(iris[sample(1:nrow(iris), 30, replace = FALSE), ], #<--RESTRICT DATA VOLUME TO REDUCE OVERPLOTTING FOR ILLUSTRATION.
mapping = aes(x = Petal.Length, y = Sepal.Length)) +
geom_point_plus(mapping = aes(shape = factor(round(Petal.Length))), #<--MAP SHAPE TO FACTOR WITH 9 OR FEWER LEVELS!
legend_title = "Petal length (binned)") + #<--SPECIFY NEW LEGEND TITLE.
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
yaxis_title_plus() +
gridlines_plus()
As the example above shows, you can specify a new shape legend title inside geom_point_plus()
using the legend_title
parameter for convenience. You can also use the chosen_shapes
parameter to specify which specific shapes from the new palette you want to use:
set.seed(123)
ggplot(iris[sample(1:nrow(iris), 30, replace = FALSE), ],
mapping = aes(x = Petal.Length, y = Sepal.Length)) +
geom_point_plus(mapping = aes(shape = factor(round(Petal.Length))),
legend_title = "Petal length (binned)",
chosen_shapes = c("oval", "lotus", "cross", "flower", "octagon", "economy", "waffle")) + #<--SPECIFY SPECIFIC SHAPES YOU WANT.
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
yaxis_title_plus() +
gridlines_plus()
As you might hope, you can also access these features using geom_plus(geom = "point_plus")
instead:
set.seed(123)
ggplot(iris[sample(1:nrow(iris), 30, replace = FALSE), ],
mapping = aes(x = Petal.Length, y = Sepal.Length)) +
geom_plus(geom = "point_plus", #<--EASIER WAY TO ACCESS THESE FEATURES
mapping = aes(shape = factor(round(Petal.Length))),
legend_title = "Petal length (binned)",
chosen_shapes = c("oval", "lotus", "cross", "flower", "octagon", "economy", "waffle")) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
yaxis_title_plus() +
gridlines_plus()
As previously noted, all these shapes have separate fill and color aesthetics, so these color-based aesthetics can be set to constants or even mapped to variables (although we wouldn’t necessarily recommend doing the latter in most cases, we did want to ensure it was possible!):
set.seed(123)
ggplot(iris[sample(1:nrow(iris), 30, replace = FALSE), ],
mapping = aes(x = Petal.Length, y = Sepal.Length)) +
geom_plus(geom = "point_plus",
mapping = aes(shape = factor(round(Petal.Length))),
legend_title = "Petal length (binned)",
chosen_shapes = c("oval", "lotus", "cross", "flower", "octagon", "economy", "waffle"),
fill = viridis::viridis(1,0.5,0.5)) + #<--BOTH COLOR AND FILL CAN BE MAPPED TO CONSTANTS OR EVEN TO VARIABLES
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
yaxis_title_plus() +
gridlines_plus()
These shapes are specifically designed for use via geom_point_plus()
for when you want to map a discrete variable to shape, especially in lieu of using color to do this. However, you could use them in “regular” scatterplots (i.e., those that don’t map shape) too, if you want! To do this (at present), you must:
Use geom_point_plus()
rather than geom_point()
.
Set shape
to a constant outside of aes()
using the chosen_shapes
argument.
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point_plus", #<--MUST USE GEOM_POINT_PLUS SOMEHOW
mapping = aes(fill = Species),
size = 2.5,
alpha = 0.5,
chosen_shapes = "waffle" #<--PICK EXACT SHAPE(S) YOU WANT, OTHERWISE THE DEFAULT ONE WILL BE USED.
+
) scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
yaxis_title_plus() +
gridlines_plus()
One sort of strange function in ggplot2
is coord_flip()
, which will flip the graph’s coordinate system so that the x axis runs vertically and the y axis runs horizontally. ggplot.plus
’s tools will work with this function, if you use it:
palettes_plus(begin_discrete = 0,
end_discrete = 1)
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
yaxis_title_plus() +
gridlines_plus() +
coord_flip() #<--
There are some aspects of suboptimal graph design that ggplot.plus
can’t (currently) help you implement (yet). However, it tries to at least detect these circumstances and give you informative messages about what has been detected and what you should do about it.
For example, by default, ggplot2
will make your axis titles the column names of the variables in the data set you’ve mapped to those axes. So, if we map x
to Petal.Length
in our data set, our axis title will say Petal.Length
unless we change it.
Just like “Petal.Length”, most column names are not designed to be perfectly human-readable and intuitive. Instead, they are designed to be short, computer-readable, and easy to type. They may feature unusual capitalization and punctuation, lack spaces, include cryptic abbreviations, and lack units.
If you use geom_plus()
and the function can detect that you have not specified custom axis titles for your scales (because the titles being rendered match the column names of the mapped variables exactly), it will flag this:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(thin_labels = TRUE) + #<--NO NAME SPECIFIED.
scale_y_continuous_plus() + #<--NO NAME SPECIFIED.
theme_plus() +
yaxis_title_plus() +
gridlines_plus()
Since your inherit.aes argument was ambiguous, it was set to TRUE.
You provided an unnamed aes-like input to geom_plus() but inherit.aes is TRUE, so the former was ignored.
Some mapped aesthetics appear to be using default titles. Consider setting human-readable titles (with units) via scale_*() or labs().
Unrenamed: x: Petal.Length, y: Sepal.Length. Set silence_warnings = TRUE in geom_plus() to suppress warnings like these.
The idea here is to flag an issue that someone who might be new to making graphics in ggplot2
(or in general) might not otherwise immediately notice or think of and to move them more quickly towards best practices.
Another example: The number of distinct colors that the human eye can successfully distinguish from each other is relatively small. Most research puts this number at 12 (at maximum) but closer to 8 in most contexts. Color perceptual space is just not that big! As such, if you attempt to request a discrete color palette requiring more than 8 colors, you will get a warning about a likely lack of contrast:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = as.factor(Petal.Width))) + #<--MAKE THIS VARIABLE A FACTOR--IT WILL HAVE TONS OF LEVELS
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus() +
yaxis_title_plus() +
gridlines_plus() +
labs(fill = "Petal width (cm)") #<--SATISFY THE PREVIOUS WARNING SO WE DON'T GET IT AGAIN.
Since your inherit.aes argument was ambiguous, it was set to TRUE.
You provided an unnamed aes-like input to geom_plus() but inherit.aes is TRUE, so the former was ignored.
It’s hard to even keep the legend “in bounds” here, since it’s so big! But it’s also nigh-impossible to distinguish neighboring colors here in the legend.
Here’s a “final” version of our scatterplot using all of ggplot.plus
’s tools together:
ggplot(iris,
mapping = aes(x = Petal.Length,
y = Sepal.Length)) +
geom_plus(geom = "point",
mapping = aes(fill = Species),
alpha = 0.3) +
scale_x_continuous_plus(name = "Petal length (cm)", thin_labels = TRUE) +
scale_y_continuous_plus(name = "Sepal length (cm)") +
theme_plus(legend.text = element_text(face= "italic")) + #<--MAKE THE TAXON NAMES ITALIC LIKE THEY OUGHT TO BE (A PASS-THRU TO ggplot2::theme)
yaxis_title_plus() +
gridlines_plus() +
scale_fill_viridis_d(name = "Taxon",
begin = 0,
end = 1,
option = "D",
labels = c("I. setosa", "I. versicolor", "I. virginica")
#<--TO MODIFY THE FILL SCALE, WE CALL THE SAME ggplot2::scale FUNCTION THAT palettes_plus() CALLS, SPECIFYING A MORE APPROPRIATE TITLE AND LABELS. )
I’d say that looks pretty nice, but it’s, at worst, an evidence-based starting point upon which to build something truly impactful and distinctive.