ggplot "glow" effect for line similar to Excel - r

Does ggplot have a similar line effect as Excel's "Glow"? Based on all my searching I don't think it does, but any other suggestions on how to make one line "stand out" from another line on a plot (other than just alpha)? My plot is basically 2 time-series of the same xy data, except that one series is the raw 15-min data, the other is the daily average of those data. I would like to bring the daily average data visually to the foreground, and push the 15min data to the background.
Thanks!

How's this?
library(ggplot2)
df <- data.frame(x = c(1:6), y = c(1,4,3,4,5,2))
ggplot(df) +
geom_line(aes(x = x, y = y), size = 3, colour = 'red', alpha = 0.1) +
geom_line(aes(x = x, y = y), size = 2, colour = 'red', alpha = 0.2) +
geom_line(aes(x = x, y = y), size = 1, colour = 'red', alpha = 0.5)

Related

How to add geom_rect to geom_line plot

I am plotting a time series of returns and would like to use NBER recession dating to shade recessions, like FRED graphs do.
The recession variable is in the same data frame and is a 1, 0 variable for: 1 = Recession, 0 = Expansion.
The idea is to use geom_rect and alpha = (Recession == 1) to shade the areas where Recession == 1.
The code for the gg_plot is below. Thanks for the help!
ERVALUEplot <- ggplot(data = Alldata)+
geom_line(aes(x = Date, y = ERVALUE), color = 'red')+
geom_rect(aes(x = Date, alpha = (Alldata$Recession ==1)), color = 'grey')
I think your case might be slightly simplified by using geom_tile() instead of geom_rect(). The output is the same but the parametrisation is easier.
I have presumed your data had a structure roughly like this:
library(ggplot2)
set.seed(2)
Alldata <- data.frame(
Date = Sys.Date() + 1:10,
ERVALUE = cumsum(rnorm(10)),
Recession = sample(c(0, 1), 10, replace = TRUE)
)
With this data, we can make grey rectangles wherever recession == 1 as follows. Here, I've mapped it to a scale to generate a legend automatically.
ggplot(Alldata, aes(Date)) +
geom_tile(aes(alpha = Recession, y = 1),
fill = "grey", height = Inf) +
geom_line(aes(y = ERVALUE), colour = "red") +
scale_alpha_continuous(range = c(0, 1), breaks = c(0, 1))
Created on 2021-08-25 by the reprex package (v1.0.0)

How to create size varying points with stat_summary_2d

I want to vary the size of points created with stat_summary_2d, at present they are all the same size which isn't informative. I would normally use geom_point() but because I want the points central to their correct bins it isn't appropriate, they are inconsistent in their placement relative to the bin centres so an offset also doesn't work.
The code relevant for creating the points is:
stat_summary_2d(data = filter(ni_eff, fishyear %in% c('2013', '2014', '2015', '2016') & coverage),
mapping = aes(x = start_long, y = start_lat, z=event_key),
binwidth = c(1, 1),
geom = 'point',
colour = 'red',
shape = 1,
# size = event_key,
fun = n_distinct) +
Stat_summary_2d doesn't like size in the aesthetics, and also doesn't recognise event_key if it is entered to determine size. I think it should be possible but haven't worked out how, so any help would be appreciated.
Ultimately, I want points centred on 1*1 degree lat-long bins that vary in size given a column event_key within the dataframe with their co-ordinates.
Similar question with an applicable answer:
Map with geom_bin2d overlay with additional stat info
Applying my code:
point_df <- ggplot(filter(ni_eff, fishyear %in% c('2013', '2014', '2015', '2016') & coverage),
aes(x = start_long, y = start_lat)) +
stat_summary_2d(aes(z = event_key), binwidth = c(1, 1), fun = length)
df <- ggplot_build(point_df)$data[[1]]
And the size varying points are plotted using geom_point() and at the correct lat-long bin centres (x, y) generated from ggplot_build()
geom_point(data = df, aes(x = x, y = y, size = value),
colour = "red", shape = 1)
You could add the points manually without stat_summary2d() and then use position_nudge to adjust the position so the dots are centered. For example:
df = data.frame(a = 1:10, b = 1:10, c = 1:10)
d <- ggplot(df, aes(a, b, z = c))
d + stat_summary_2d() +
geom_point(aes(x = a, y = b, size = c),
position = position_nudge(-.1, -.1))

Plotting points and lines separately in R with ggplot

I'm trying to plot 2 sets of data points and a single line in R using ggplot.
The issue I'm having is with the legend.
As can be seen in the attached image, the legend applies the lines to all 3 data sets even though only one of them is plotted with a line.
I have melted the data into one long frame, but this still requires me to filter the data sets for each individual call to geom_line() and geom_path().
I want to graph the melted data, plotting a line based on one data set, and points on the remaining two, with a complete legend.
Here is the sample script I wrote to produce the plot:
xseq <- 1:100
x <- rnorm(n = 100, mean = 0.5, sd = 2)
x2 <- rnorm(n = 100, mean = 1, sd = 0.5)
x.lm <- lm(formula = x ~ xseq)
x.fit <- predict(x.lm, newdata = data.frame(xseq = 1:100), type = "response", se.fit = TRUE)
my_data <- data.frame(x = xseq, ypoints = x, ylines = x.fit$fit, ypoints2 = x2)
## Now try and plot it
melted_data <- melt(data = my_data, id.vars = "x")
p <- ggplot(data = melted_data, aes(x = x, y = value, color = variable, shape = variable, linetype = variable)) +
geom_point(data = filter(melted_data, variable == "ypoints")) +
geom_point(data = filter(melted_data, variable == "ypoints2")) +
geom_path(data = filter(melted_data, variable == "ylines"))
pushViewport(viewport(layout = grid.layout(1, 1))) # One on top of the other
print(p, vp = viewport(layout.pos.row = 1, layout.pos.col = 1))
You can set them manually like this:
We set linetype = "solid" for the first item and "blank" for others (no line).
Similarly for first item we set no shape (NA) and for others we will set whatever shape we need (I just put 7 and 8 there for an example). See e.g. http://www.r-bloggers.com/how-to-remember-point-shape-codes-in-r/ to help you to choose correct shapes for your needs.
If you are happy with dots then you can use my_shapes = c(NA,16,16) and scale_shape_manual(...) is not needed.
my_shapes = c(NA,7,8)
ggplot(data = melted_data, aes(x = x, y = value, color=variable, shape=variable )) +
geom_path(data = filter(melted_data, variable == "ylines") ) +
geom_point(data = filter(melted_data, variable %in% c("ypoints", "ypoints2"))) +
scale_colour_manual(values = c("red", "green", "blue"),
guide = guide_legend(override.aes = list(
linetype = c("solid", "blank","blank"),
shape = my_shapes))) +
scale_shape_manual(values = my_shapes)
But I am very curious if there is some more automated way. Hopefully someone can post better answer.
This post relied quite heavily on this answer: ggplot2: Different legend symbols for points and lines

How to make a color scale with sharp transition in ggplot2

I am trying to create a color scale with a sharp color transition at one point. What I am currently doing is:
test <- data.frame(x = c(1:20), y = seq(0.01, 0.2, by = 0.01))
cutoff <- 0.10
ggplot(data = test,
aes(x = as.factor(x), y = y, fill = log(y), width = 1, binwidth = 0)) +
geom_bar(stat = "identity") +
scale_fill_gradientn(colours = c("red", "red", "yellow", "green"),
values = rescale(log(c(0.01, cutoff - 0.0000000000000001, cutoff, 0.2))),
breaks = c(log(cutoff)), label = c(cutoff))
It is producing the plots I want. But the position of the break in colorbar somehow varies depending on the cutoff. Sometimes below the value, sometimes above, sometimes on the line. Here are some plots with different cutoffs (0.05, 0.06, 0.1):
What am I doing wrong? Or alternatively, is there a better way to create a such a color scale?
Have you looked into scale_colour_steps or scale_colour_stepsn?
Using the option n.break from scale_colour_stepsn you should be able to specify the number of breaks you want and have sharper transitions.
Be sure to use ggplot2 > 3.3.2
In case you are still interested in a solution for this, you can add guide = guide_colourbar(nbin = <some arbitrarily large number>) to scale_fill_gradientn(). This increases the number of bins used by the colourbar legend, which makes the transition look sharper.
# illustration using nbin = 1000, & weighted colours below the cutoff
plot.cutoff <- function(cutoff){
p <- ggplot(data = test,
aes(x = as.factor(x), y = y, fill = log(y))) +
geom_col(width = 1) +
scale_fill_gradientn(colours = c("red4", "red", "yellow", "green"),
values = scales::rescale(log(c(0.01, cutoff - 0.0000000000000001,
cutoff, 0.2))),
breaks = c(log(cutoff)),
label = c(cutoff),
guide = guide_colourbar(nbin = 1000))
return(p)
}
cowplot::plot_grid(plot.cutoff(0.05),
plot.cutoff(0.06),
plot.cutoff(0.08),
plot.cutoff(0.1),
ncol = 2)
(If you find the above insufficiently sharp at very high resolutions, you can also set raster = FALSE in guide_colourbar(), which turns off interpolation & draws rectangles instead.)
I think it is slightly tricky to achieve an exact, discrete cutoff point in the continuous color scale using scale_fill_gradientn. A quick alternative would be to use scale_fill_gradient, set the cutoff with limits, and set the color of 'out-of-bounds' values with na.value.
Here's a slightly simpler example than in your question:
# some data
df <- data.frame(x = factor(1:10), y = 1, z = 1:10)
# a cutoff point
lo <- 4
ggplot(df, aes(x = x, y = y, fill = z)) +
geom_bar(stat = "identity") +
scale_fill_gradient(low = "yellow", high = "green",
limits = c(lo, max(df$z)), na.value = "red")
As you see, the values below your cutpoint will not appear in the legend, but one may consider including a large chunk of red a waste of "legend band width" anyway. You might just add a verbal description of the red bars in the figure caption instead.
You may also wish to differentiate between values below a lower cutpoint and above an upper cutpoint. For example, set 'too low' values to blue and 'too high values' to red. Here I use findInterval to differentiate between low, mid and high values.
# some data
set.seed(2)
df <- data.frame(x = factor(1:10), y = 1, z = sample(1:10))
# lower and upper limits
lo <- 3
hi <- 8
# create a grouping variable based on the the break points
df$grp <- findInterval(df$z, c(lo, hi), rightmost.closed = TRUE)
ggplot(df, aes(x = x, y = y, fill = z)) +
geom_bar(stat = "identity") +
scale_fill_gradient(low = "yellow", high = "green", limits = c(lo, hi), na.value = "red") +
geom_bar(data = df[df$grp == 0, ], fill = "blue", stat = "identity")

R: In ggplot, how to add multiple text labels on the y-axis for each of multiple dates on the x-axis

I am making a very wide chart that, when output as a PNG file, takes up several thousand pixels in the x-axis; there is about 20 years of daily data. (This may or may not be regarded as good practise, but it is for my own use, not for publication.) Because the chart is so wide, the y-axis disappears from view as you scroll through the chart. Accordingly I want to add labels to the plot at 2-yearly intervals to show the values on the y-axis. The resulting chart looks like the one below, except that in the interests of keeping it compact I have used only 30 days of fake data and put labels roughly every 10th day:
This works more or less as required, but I wonder if there is some better way of approaching it as in this chart (see code below) I have a column for each of the 3 y-axis values of 120, 140 and 160. The real data has many more levels, so I would end up with 15 calls to geom_text to put everything on the plot area.
Q. Is there a simpler way to splat all 20-odd dates, with 15 labels per date, on to the chart at once?
require(ggplot2)
set.seed(12345)
mydf <- data.frame(mydate = seq(as.Date('2012-01-01'), as.Date('2012-01-31'), by = 'day'),
price = runif(31, min = 100, max = 200))
mytext <- data.frame(mydate = as.Date(c('2012-01-10', '2012-01-20')),
col1 = c(120, 120), col2 = c(140,140), col3 = c(160,160))
p <- ggplot(data = mydf) +
geom_line(aes(x = mydf$mydate, y = mydf$price), colour = 'red', size = 0.8) +
geom_text(data = mytext, aes(x = mydate, y = col1, label = col1), size = 4) +
geom_text(data = mytext, aes(x = mydate, y = col2, label = col2), size = 4) +
geom_text(data = mytext, aes(x = mydate, y = col3, label = col3), size = 4)
print(p)
ggplot2 likes data to be in long format, so melt()ing your text into long format lets you make a single call to geom_text():
require(reshape2)
mytext.m <- melt(mytext, id.vars = "mydate")
Then your plotting command becomes:
ggplot(data = mydf) +
geom_line(aes(x = mydf$mydate, y = mydf$price), colour = 'red', size = 0.8) +
geom_text(data = mytext.m, aes(x = mydate, y = value, label = value), size = 4)

Resources