Reputation: 33
I am plotting the graph in ggplot. Everything was fine but now I have a problem with the legend. i want to rearrange the legend. The legend that I am getting now is
0-63
100-200
200-400
63-100
what I want is. I want to move the last value to the 2nd position. It should be like that
0-63
63-100
100-200
200-400
my code is below
my data look like this but up to 1000 rows
time less63 63_100 100_200 200_400
06:01 0 4 3 1
06:02 2 6 6 5
06:03 4 8 8 6
06:04 6 9 7 8
06:05 7 10 8 7
06:06 3 11 3 7
06:07 6 7 2 2
06:08 7 3 0 3
ggplot(df)+
geom_area(aes(x=time,y=less63,fill="0-63"),alpha=0.5)+
geom_area(aes(x=time,y=63_100,fill="63-100"),alpha=0.5)+
geom_area(aes(x=time,y=100_200,fill="100-200"),alpha=0.5)+
geom_area(aes(x=time,y=200_400,fill="200-400"),alpha=0.5)+
scale_colour_manual(name="Legend", values = c("0-63" = "red","63-100" = "green","100-200" = "black","200-400" = "blue"))
I shall be really thankful in this regard
Upvotes: 1
Views: 8174
Reputation: 13863
The first thing you want to do here is put your data into Tidy Data format. Notice how you are specifying a geom_area()
function for every fill color in your dataset and naming them manually? The philosophy behind grammar of graphics upon which ggplot2
was built is that you can use the mapping function aes()
to let ggplot2
define the separation and how fill=
is applied by the observations in your dataset. We'll do that here, then demonstrate a few other things that will get your plot working... as well as finally making your legend in the proper order.
To tidy the data, you need to gather the columns except for time into 2 new columns: one to specify the range (i.e. "0-63" or "100-200") which will be mapped to the fill aesthetic, and one to specify the value that will be mapped to the y aesthetic. As the data stands in df_original
, you have the values spread across multiple columns (they should be in one column) and the names of those columns should really be gathered into a separate column. The result of doing this is called "gathering" or making your data "long".
Here, we'll use pivot_longer()
:
library(ggplot2)
library(dplyr)
library(tidyr)
library(scales)
df_original <- read.table(text="time less63 63_100 100_200 200_400
06:01 0 4 3 1
06:02 2 6 6 5
06:03 4 8 8 6
06:04 6 9 7 8
06:05 7 10 8 7
06:06 3 11 3 7
06:07 6 7 2 2
06:08 7 3 0 3", header=TRUE)
df <- df_original %>%
pivot_longer(
cols = -time, # take everything except time column
names_to = "ranges",
values_to = "val"
) %>%
mutate(ranges = factor(
ranges,
levels=c("less63", "X63_100", "X100_200", "X200_400"),
labels=c("0-63", "63-100", "100-200", "200-400")))
Then you want to change the df$range
column to a factor. Here you can specify the order of the ranges using the levels=
argument, and while we're at it you can specify how they look (renaming) by the labels=
argument:
df <- df %>%
mutate(ranges = factor(
ranges,
levels=c("less63", "X63_100", "X100_200", "X200_400"),
labels=c("0-63", "63-100", "100-200", "200-400")))
The last step is converting your df$time
column to a POSIXct
object, which means we can reference it as a time object. You can look at the help for strptime()
to see what the string for format=
is referencing:
# OP states time is in hours:minutes, so reflected here
df$time <- as.POSIXct(df$time, format="%H:%M")
Plotting is pretty simple now. Since we tidied up the data, we can just use one geom_area()
call. Also, we reordered the factor levels for range, so the order of objects in the legend is set the way it should be and looks the way it should be thanks to the labels=
argument.
One more thing: you need to reference scale_fill_manual()
not scale_colour_manual()
, since the aesthetic that is mapped in geom_area()
is the fill:
ggplot(df, aes(x=time, y=val, fill=ranges)) +
geom_area(alpha=0.5) +
scale_x_time(labels = scales::time_format(format = "%H:%M")) +
scale_fill_manual(name="Legend", values = c("0-63" = "red","63-100" = "green","100-200" = "black","200-400" = "blue"))
The OP indicated they were creating an overlapping plot. By default, the position of the layers mapped to fill in geom_are()
is set to "stacked", which means the y values are stacked on top of one another. This makes it easy to view and see the way the areas change over the x axis. However, OP wanted to prepare a plot where the y values are... the value. This would be position="identity"
and creates overlapping areas. You can see the direct effect here:
ggplot(df, aes(x=time, y=val, fill=ranges)) +
geom_area(alpha=0.2, position="identity") +
scale_x_time(labels = scales::time_format(format = "%M:%S")) +
scale_fill_manual(name="Legend", values = c("0-63" = "red","63-100" = "green","100-200" = "black","200-400" = "blue"))
You can see that even cutting down the alpha=
value, this is going to be hard to discern what's going on. If you want to see this information more clearly, I would recommend using horizontally-placed facets as a better viewing option:
ggplot(df, aes(x=time, y=val, fill=ranges)) +
geom_area(alpha=0.2, position="identity") +
scale_x_time(labels = scales::time_format(format = "%M:%S")) +
scale_fill_manual(name="Legend", values = c("0-63" = "red","63-100" = "green","100-200" = "black","200-400" = "blue")) +
facet_grid(ranges ~ .)
Upvotes: 5
Reputation: 79246
pivot_longer
name
to factor (level and label it)fill
and group
Custom OP:
library(ggplot2)
library(dplyr)
library(tidyr)
df %>%
pivot_longer(
-time
) %>%
mutate(name = factor(name, levels = c("less63", "X63_100", "X100_200", "X200_400"),
labels = c("0-63","63-100","100-200","200-400"))) %>%
ggplot(aes(x=factor(time), y=value, fill=name, group=name))+
geom_area(position = "identity", alpha=0.5) +
scale_fill_manual(name="Legend", values = c("0-63" = "red","63-100" = "green","100-200" = "black","200-400" = "blue"))
library(ggplot2)
library(dplyr)
library(tidyr)
df %>%
pivot_longer(
-time
) %>%
mutate(name = factor(name, levels = c("less63", "X63_100", "X100_200", "X200_400"))) %>%
ggplot(aes(x=time, y=value, fill=name, group=name))+
geom_area()
Upvotes: 1
Reputation: 1385
I suggest using tidyr::pivot_longer() on your data so that it looks like this.
time variable value 1 06:01 less63 0 2 06:01 63_100 4
etc...
Then use ordered() to set "variable" as an ordered factor. Then use geom_area(aes(x = time, y = variable, full = variable)
Upvotes: 1