Plotting several lines in one diagramm - r

I have a time series which shows the electricity load for every 15min during one year. I already filtered to show only one specific weekday.
My dataframe:
Date Timestamp Weekday Load
2017-01-02 00:00:00 Monday 272
2017-01-02 00:15:00 Monday 400
2017-01-02 00:30:00 Monday 699
2017-01-02 00:45:00 Monday 764
2017-01-02 01:00:00 Monday 983
..
..
2017-01-09 00:45:00 Monday 764
2017-01-09 01:00:00 Monday 983
..
2017-12-25 23:45:00 Monday 983
Now I want to plot several line diagrams for every monday in one diagram:
x axis = Timestamp
y axis = Load
I tried with ggplot:
ggplot(Loadprofile, aes(x= Timestamp, y = Load, color = Date)) + geom_line()
But this brings me following error
Error: Aesthetics must be either length 1 or the same as the data (4992): x, y, colour
That is the output, the x-axis does not look continious though?
enter image description here
Any suggestions?

Your problem is that you need Date to be a factor, but when it is on a Date form, ggplot takes it as a continuous variable.
I simulated some data, just to be able to do the graph, the following code is the one I used to generate the data:
library(tidyverse)
library(lubridate)
DateTimes <- seq(
from=as.POSIXct("2017-1-02 0:00", tz="UTC"),
to=as.POSIXct("2017-1-09 23:59", tz="UTC"),
by="15 min"
)
DF <- data.frame(Date = as.Date(DateTimes), timestamp = strftime(DateTimes, format="%H:%M:%S"), Weekday = weekdays(DateTimes)) %>% filter(Weekday == "Monday") %>% mutate(load = as.numeric(timestamp)*20 + -as.numeric(timestamp)^2 + rnorm(nrow(DF), sd = 1000) + (as.numeric(Date))) %>% mutate(load = ifelse(Date < ymd("2017_01_4"), load -5000, load))
Once I have done that, if I do the following:
ggplot(DF, aes(x = timestamp, y = load)) + geom_line(aes(group = as.factor(Date), color = as.factor(Date
I get the following graph
I think that is what you need, if you need more help formating the x axis and legend let me know
Cheers

Related

How to change x axis from years to months with ggplot2

I have a web visits over time chart which plots daily traffic from 2014 until now, and looks like this:
ggplot(subset(APRA, Post_Day > "2013-12-31"), aes(x = Post_Day, y = Page_Views))+
geom_line()+
scale_y_continuous(labels = comma)+
ylim(0,50000)
As you can see it's not a great graph, what would make a bit more sense is to break it down by month as opposed to day. However when I try this code:
ggplot(subset(APRA, Post_Day > "2013-12-31"), aes(x = Post_Day, y = Page_Views))+
geom_line()+
scale_y_continuous(labels = comma)+
ylim(0,50000)+
scale_x_date(date_breaks = "1 month", minor_breaks = "1 week", labels = date_format("%B"))
I get this error:
Error: Invalid input: date_trans works with objects of class Date only
The date field Post_Day is POSIXct. Page_Views is numeric. Data looks like:
Post_Title Post_Day Page_Views
Title 1 2016-05-15 139
Title 2 2016-05-15 61
Title 3 2016-05-15 79
Title 4 2016-05-16 125
Title 5 2016-05-17 374
Title 6 2016-05-17 39
Title 7 2016-05-17 464
Title 8 2016-05-17 319
Title 9 2016-05-18 84
Title 10 2016-05-18 64
Title 11 2016-05-19 433
Title 12 2016-05-19 418
Title 13 2016-05-19 124
Title 14 2016-05-19 422
I'm looking to change the X axis from a daily granularity into monthly.
The sample data set shown in the question has multiple data points per day. So, it needs to be aggregated day-wise anyway. For the aggregation by day or month, data.table and lubridate are used.
Create sample data
As no reproducible example is supplied, a sample data set is created:
library(data.table)
n_rows <- 5000L
n_days <- 365L*3L
set.seed(123L)
DT <- data.table(Post_Title = paste("Title", 1:n_rows),
Post_Day = as.Date("2014-01-01") + sample(0:n_days, n_rows, replace = TRUE),
Page_Views = round(abs(rnorm(n_rows, 500, 200))))[order(Post_Day)]
DT
Post_Title Post_Day Page_Views
1: Title 74 2014-01-01 536
2: Title 478 2014-01-01 465
3: Title 3934 2014-01-01 289
4: Title 4136 2014-01-01 555
5: Title 740 2014-01-02 442
---
4996: Title 1478 2016-12-31 586
4997: Title 2251 2016-12-31 467
4998: Title 2647 2016-12-31 468
4999: Title 3243 2016-12-31 498
5000: Title 4302 2016-12-31 309
Plot raw data
Without aggregation the data can be plotted by
library(ggplot2)
ggplot(DT) + aes(Post_Day, Page_Views) + geom_line()
Aggregated by day
ggplot(DT[, .(Page_Views = sum(Page_Views)), by = Post_Day]) +
aes(Post_Day, Page_Views) + geom_line()
To aggregate day-wise the grouping parameter by of data.table is used and sum() as aggregation function. The aggregation is reducing the number of data points from 5000 to 1087. Hence, the plot looks less convoluted.
Aggregated by month
ggplot(DT[, .(Page_Views = sum(Page_Views)),
by = .(Post_Month = lubridate::floor_date(Post_Day, "month"))]) +
aes(Post_Month, Page_Views) + geom_line()
In order to aggregate by month, the grouping parameter by is used but this time Post_Day is mapped to the first day of the respective months. So, 2014-03-26 becomes a Post_Month of 2014-03-01 which is still of class POSIXct. By this, the x-axis remains continuous with a date scale. This avoids the trouble when converting Post_Day to factor, e.g, "2014-03" using format(Post_Day, ""%Y-%m"), where the x-axis would become discrete.
APRA$month <- as.factor(stftime(APRA$Post_Day, "%m")
APRA <- APRA[order(as.numeric(APRA$month)),]
This would create a month column to your data
z <- apply(split(APRA, APRA$month), function(x) {sum(as.numeric(APRA$Page_Views))})
z <- do.call(rbind, z)
z$month <- unique(APRA$month)
colnames(Z) <- c("Page_Views", "month")
This would create a z dataframe which has months and page views each month
Now plot it
ggplot(z, aes(x = month, y = Page_Views)) + geom_line()
Please let me know if this is what you were looking for. Also I haven't compiled it, please tell if it throws some error.

plotting daily rainfall data using geom_step

I have some rainfall data collected continuously from which I have calculated daily totals. Here is some toy data:
Date <- c(seq(as.Date("2016-07-01"), by = "1 day", length.out = 10))
rain_mm <- c(3,6,8,12,0,0,34,23,5,1)
rain_data <- data.frame(Date, rain_mm)
I can plot this data as follows:
ggplot(rain_data, aes(Date, rain_mm)) +
geom_bar(stat = "identity") +
scale_x_date(date_labels = "%d")
Which gives the following:
This seems fine. It is clear how much rainfall there was on a certain day. However, it could also be interpreted that between midday of one day and midday of the next, a certain amount of rain fell, which is wrong. This is especially a problem if the graph is combined with other plots of related continuous variables over the same period.
To get round this issue I could use geom_step as follows:
library(ggplot)
ggplot(rain_data, aes(Date, rain_mm)) +
geom_step() +
scale_x_date(date_labels = "%d")
Which gives:
This is a better way to display the data, and now scale_x_date appears to be a continuous axis. However, it would be nice to get the area below the steps filled but cant seem to find a straight forward way of doing this.
Q1: How can I fill beneath the geom_step? Is it possible?
It may also be useful to convert Date into POSIXct to facilitate identical x-axis in multi-plot figures as discussed in this SO question here.
I can do this as follows:
library(dplyr)
rain_data_POSIX <- rain_data %>% mutate(Date = as.POSIXct(Date))
Date rain_mm
1 2016-07-01 01:00:00 3
2 2016-07-02 01:00:00 6
3 2016-07-03 01:00:00 8
4 2016-07-04 01:00:00 12
5 2016-07-05 01:00:00 0
6 2016-07-06 01:00:00 0
7 2016-07-07 01:00:00 34
8 2016-07-08 01:00:00 23
9 2016-07-09 01:00:00 5
10 2016-07-10 01:00:00 1
However, this gives a time of 01:00 for each date. I would rather have 00:00. Can I change this in the as.POSIXct function call, or do I have to do it afterwards using a separate function? I think it is something to do with tz = "" but cant figure it out.
How can I convert from class Date to POSIXct so that the time generated is 00:00?
Thanks
For your first question, you can work off this example. First, create a time-lagged version of your data:
rain_tl <- mutate( rain_data, rain_mm = lag( rain_mm ) )
Then combine this time-lagged version with the original data, and re-sort by date:
rain_all <- bind_rows( old = rain_data, new = rain_tl, .id="source" ) %>%
arrange( Date, source )
(Note the newly created source column is used to break ties, correctly interlacing the original data with the time-lagged version):
> head( rain_all )
source Date rain_mm
1 new 2016-07-01 NA
2 old 2016-07-01 3
3 new 2016-07-02 3
4 old 2016-07-02 6
5 new 2016-07-03 6
6 old 2016-07-03 8
You can now use the joint matrix to "fill" your steps:
ggplot(rain_data, aes(Date, rain_mm)) +
geom_step() +
geom_ribbon( data = rain_all, aes( ymin = 0, ymax = rain_mm ),
fill="tomato", alpha=0.5 ):
This produces the following plot:
For your second question, the problem is that as.POSIX.ct does not pass additional arguments to the converter, so specifying the tz argument does nothing.
You basically have two options:
1) Reformat the output to what you want: format( as.POSIXct( Date ), "%F 00:00" ), which returns a vector of type character. If you want to preserve the object type as POSIXct, you can instead...
2) Cast your Date vector to character prior to passing it to as.POSIX.ct: as.POSIXct( as.character(Date) ), but this will leave off the time entirely, which may be what you want anyway.
If you would like to avoid the hack, you can customize the position in the geom_bar expression.
I found good results with:
ggplot(rain_data, aes(Date, rain_mm)) +
geom_bar(stat = "identity", position = position_nudge(x = 0.51), width = 0.99) +
scale_x_date(date_labels = "%d")

Plotting numerous layers (bar graph) using ggplot and R [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I am trying to recreate a bar graph that I created in Excel using data that lists inventory and sales throughout the year. Here is my graph in Excel:
Note: Average sales rate is total sales / total inventory for the 13 months in the bar graph.
I am doing this through R and the ggplot package. I am quite new at this but this was what I managed so far:
library(lubridate)
library(ggplot2)
library(scales)
library(reshape2)
COdata <- read.csv("C:/.../CenterOne.csv")
# Grab related data
# VIN refers to a unique inventory identifier for the item
# First Launch Date is what I use to count my inventory for the month
# Sale Date is what I use to count my sales for the month
DFtest <- COdata[, c("VIN", "First.Launch.Date", "Sale.Date")]
Here is a snapshot of what the data looks like:
> head(DFtest)
VIN First.Launch.Date Sale.Date
1 4T1BF1FK4CU048373 22/04/2015 0:00
2 2T3KF4DVXCW108677 16/03/2015 0:00
3 4T1BF1FKXCU035935 19/03/2015 0:00 20/03/2015 0:00
4 JTDKN3DU3B1465796 16/04/2015 0:00
5 2T3YK4DV8CW015050
6 4T1BF1FK5CU599556 30/04/2015 0:00
I convert the dates to a proper format removing the hours/seconds and breaking them up into monthly intervals:
DFtest$First.Launch.Date <- as.Date(DFtest$First.Launch.Date, format = "%d/%m/%Y")
DFtest$Sale.Date <- as.Date(DFtest$Sale.Date, format = "%d/%m/%Y")
DFtest$month.listings <- as.Date(cut(DFtest$First.Launch.Date, breaks = "month"))
DFtest$month.sales <- as.Date(cut(DFtest$Sale.Date, breaks = "month"))
> head(DFtest)
VIN First.Launch.Date Sale.Date month.listings month.sales
1 4T1BF1FK4CU048373 2015-04-22 <NA> 2015-04-01 <NA>
2 2T3KF4DVXCW108677 2015-03-16 <NA> 2015-03-01 <NA>
3 4T1BF1FKXCU035935 2015-03-19 2015-03-20 2015-03-01 2015-03-01
4 JTDKN3DU3B1465796 2015-04-16 <NA> 2015-04-01 <NA>
5 2T3YK4DV8CW015050 <NA> <NA> <NA> <NA>
6 4T1BF1FK5CU599556 2015-04-30 <NA> 2015-04-01 <NA>
Avg line graph - my attempt at creating one
DF_Listings = data.frame(table(format(DFtest$month.listings)))
DF_Sales = data.frame(table(format(DFtest$month.sales)))
DF_Merge <- merge(DF_Listings, DF_Sales, by = "Var1", all = TRUE)
> head(DF_Listings)
Var1 Freq
1 2014-12-01 77
2 2015-01-01 886
3 2015-02-01 930
4 2015-03-01 1167
5 2015-04-01 1105
6 2015-05-01 1279
DF_Merge$Avg <- DF_Merge$Freq.y / DF_Merge$Freq.x
> head(DF_Merge)
Var1 Freq.x Freq.y Avg
1 2014-12-01 77 NA NA
2 2015-01-01 886 277 0.3126411
3 2015-02-01 930 383 0.4118280
4 2015-03-01 1167 510 0.4370180
5 2015-04-01 1105 309 0.2796380
6 2015-05-01 1279 319 0.2494136
ggplot(DF_Merge, aes(x=Var1, y=Avg, group = 1)) +
stat_smooth(aes(x = seq(length(unique(Var1)))),
se = F, method = "lm", formula = y ~ poly(x, 11))
Bar Graph
dfm <- melt(DFtest[ , c("VIN", "First.Launch.Date", "Sale.Date")], id.vars = 1)
dfm$value <- as.Date(cut(dfm$value, breaks = "month"))
ggplot(dfm, aes(x= value, width = 0.4)) +
geom_bar(aes(fill = variable), position = "dodge") +
scale_x_date(date_breaks = "months", labels = date_format("%m-%Y")) +
theme(axis.text.x=element_text(hjust = 0.5)) +
xlab("Date") + ylab("")
So I managed to make some of the plots which brings me to several questions:
How would I combine them into all a single graph using ggplot?
Notice how my bar graph has blanks for the first and last month? How do I remove that (precisely, how do I remove 11-2014 and 01-2016 from the x-axis)?
In my bar graph, January 2014 had no sales and as a result, the inventory bar takes up a larger space. How do I reduce its size to fit with the rest of the graph?
What could I do to change the x-axis from using dates as numbers (i.e. 12-2014) to using month-year in words (i.e. December-2014). I've tried using as.yearmon but that doesn't work with the scale_x_date portion of my ggplot function.
There's also the issue with the average sales rate line which I can safely assume I would be using geom_hline() but I am not sure how to approach this.
Using mtoto's suggestion of utilizing googleVis, I took a crack at recreating the graph:
# Testing Google Vis
mytest <- DF_Merge
library(zoo)
library(plyr) # to rename columns
library(googleVis)
mytest$Var1 <- as.yearmon(mytest$Var1)
mytest$Var1 <- as.factor(mytest$Var1) # googleVis cannot understand yearmon "class" so change it to factor
# Rename columns to ensure comprehension
mytest <- rename(mytest, c("Var1"="Date", "Freq.x"="Listings", "Freq.y"="Sales", "Avg"="Sales Rate"))
# Prepare for values to be displayed right on the plot
mytest$Listings.annotation <- mytest$Listings
mytest$Sales.annotation <- mytest$Sales
mytest$`Sales Rate.annotation` <- percent(mytest$`Sales Rate`) #Googlevis automatically understands that .annotation is used to display values in the graph
# Create average rate line
mytest$`Sales Rate` <- as.numeric(mytest$`Sales Rate`)
mytest$AvgRate <- (sum(mytest$Sales) / sum(mytest$Listings))
mytest <- rename(mytest, c("AvgRate"="Average Sales Rate"))
# Create the annotation for the average line
mytest$`Average Sales Rate.annotation` <- mytest$`Average Sales Rate`
x = nrow(mytest) - 1
mytest$`Average Sales Rate.annotation`[1:x] = "" # Ensures only the last row in this column has a value
mytest$`Average Sales Rate.annotation` <- as.numeric(mytest$`Average Sales Rate.annotation`, na.rm = TRUE)
mytest$`Average Sales Rate.annotation`[nrow(mytest)] <- percent(mytest$`Average Sales Rate.annotation`[nrow(mytest)]) # Transforms only the last row to a proper percentage!
# Plot the graph
column <- gvisComboChart(mytest, xvar= "Date",
yvar=c("Listings", "Listings.annotation", "Sales", "Sales.annotation", "Sales Rate", "Sales Rate.annotation", "Average Sales Rate",
"Average Sales Rate.annotation"),
options=list(seriesType="bars",
series="[{type: 'bars', targetAxisIndex:0, color:'orange'},
{type: 'bars', targetAxisIndex:0, color:'green'},
{type: 'line', targetAxisIndex:1, color:'red'},
{type: 'line', targetAxisIndex:1, color:'purple', lineDashStyle:[2,2,20,2,20,2]}]",
vAxes="[{format:'decimal', textPosition: 'out', viewWindow:{min:0, max:200}},
{format:'percent', textPosition: 'out', viewWindow:{min:0, max:1}}]",
hAxes="[{textPosition: 'out'}]",
legend = "bottom",
curveType="function",
width=1500,
height=800))
plot(column)
The variables could have been named better but I was able to get what I was looking for with my final result:

Plot hourly data using ggplot2

I am using ggplot2 to plot my hourly time series data. Data organization is as
> head(df)
timestamp power
1 2015-08-01 00:00:00 584.4069
2 2015-08-01 01:00:00 577.2829
3 2015-08-01 02:00:00 569.0937
4 2015-08-01 03:00:00 561.6945
5 2015-08-01 04:00:00 557.9449
6 2015-08-01 05:00:00 562.4152
I use following ggplot2 command to plot the data:
ggplot(df,aes(timestamp,power,group=1))+ theme_bw() + geom_line()+
scale_x_datetime(labels = date_format("%d:%m; %H"), breaks=pretty_breaks(n=30)) +
theme(axis.text.x = element_text(angle=90,hjust=1))
With this the plotted graph is:
My questions are:
In the plotted graph, why it is showing only the labels corresponding to hour 18. Now, what if I want to display the labels corresponding to hour 12 of each day.
I am plotting hourly data, hoping to see the fine granular details. But, I am not able to see all the hours of entire one month. Can I somehow see the zoomed view for any selected day in the same plot?
Here is a rather long example of scaling dates in ggplot and also a possible interactive way to zoom in on ranges. First, some sample data,
## Make some sample data
library(zoo) # rollmean
set.seed(0)
n <- 745
x <- rgamma(n,.15)*abs(sin(1:n*pi*24/n))*sin(1:n*pi/n/5)
x <- rollmean(x, 3, 0)
start.date <- as.POSIXct('2015-08-01 00:00:00') # the min from your df
dat <- data.frame(
timestamp=as.POSIXct(seq.POSIXt(start.date, start.date + 60*60*24*31, by="hour")),
power=x * 3000)
For interactive zooming, you could try plotly. You need to set it up (get an api-key and username) then just do
library(plotly)
plot_ly(dat, x=timestamp, y=power, text=power, type='line')
and you can select regions of the graph and zoom in on them. You can see it here.
For changing the breaks in the ggplot graphs, here is a function to make date breaks by various intervals at certain hours.
## Make breaks from a starting date at a given hour, occuring by interval,
## length.out is days
make_breaks <- function(strt, hour, interval="day", length.out=31) {
strt <- as.POSIXlt(strt - 60*60*24) # start back one day
strt <- ISOdatetime(strt$year+1900L, strt$mon+1L, strt$mday, hour=hour, min=0, sec=0, tz="UTC")
seq.POSIXt(strt, strt+(1+length.out)*60*60*24, by=interval)
}
One way to zoom in, non-interactively, is to simply subset the data,
library(scales)
library(ggplot2)
library(gridExtra)
## The whole interval, breaks on hour 18 each day
breaks <- make_breaks(min(dat$timestamp), hour=18, interval="day", length.out=31)
p1 <- ggplot(dat,aes(timestamp,power,group=1))+ theme_bw() + geom_line()+
scale_x_datetime(labels = date_format("%d:%m; %H"), breaks=breaks) +
theme(axis.text.x = element_text(angle=90,hjust=1)) +
ggtitle("Full Range")
## Look at a specific day, breaks by hour
days <- 20
samp <- dat[format(dat$timestamp, "%d") %in% as.character(days),]
breaks <- make_breaks(min(samp$timestamp), hour=0, interval='hour', length.out=length(days))
p2 <- ggplot(samp,aes(timestamp,power,group=1))+ theme_bw() + geom_line()+
scale_x_datetime(labels = date_format("%d:%m; %H"), breaks=breaks) +
theme(axis.text.x = element_text(angle=90,hjust=1)) +
ggtitle(paste("Day:", paste(days, collapse = ", ")))
grid.arrange(p1, p2)
I didn't worked with data time data a lot so my code might look a bit messy... But the solution to 1 is to not use pretty_breaks() but better use concrete breaks and also limit the within the scale_x_datetime() function.
A bad written example might be the following:
ggplot(df,aes(timestamp,power,group=1))+ theme_bw() + geom_line()+
scale_x_datetime(labels = date_format("%d:%m; %H"),
breaks=as.POSIXct(sapply(seq(18000, 3600000, 86400), function(x) 0 + x),
origin="2015-10-19 7:00:00"),
limits=c(as.POSIXct(3000, origin="2015-10-19 7:00:00"),
as.POSIXct(30000, origin="2015-10-19 7:00:00"))) +
theme(axis.text.x = element_text(angle=90,hjust=1))
I am not sure how to write the as.POSIXct() more readable... But Basically create the 12 hour point manually and add always a complete day within the range of your data frame...

Mixing line chart and dots points in baseline of chart in R

I have built a chart in R with two series, but I want to add a coloured bar at the bottom of the chart:
The data to be plotted is
2013-01-01 12:35:00 0
2013-01-01 12:45:00 1
2013-01-01 13:00:00 1
....
2013-01-01 13:00:00 2
where 0 is green, 1 is orange and 2 is red. Datetime is aligned with data X in original chart.
This is the code for the chart (without coloured bar):
datos_tem <- dbGetQuery(connection, paste("SELECT temp_int,hum_int,datetime FROM datalog_v2 WHERE host_id=41 and datetime>='2014-02-01 00:00:00' and datetime<='2014-02-01 23:59:00';", sep=""))
dbDisconnect(connection)
datos_tem$datetime <- as.POSIXct(datos_tem$datetime)
datos_tem$temp_int <- as.numeric(datos_tem$temp_int)
datos_tem$hum_int <- as.numeric(datos_tem$hum_int)
#gg <- qplot(datos_tem$datetime, datos_tem$temp_int) + geom_line() # first line
#gg <- gg + geom_line(aes( x=datos_tem$datetime, y=datos_tem$hum_int )) # add the second line!
png(file.path("/tmp/", paste("comp",".png",sep="_")))
Molten <- melt(datos_tem, id.vars = "datetime")
ggplot(Molten, aes(x = datetime, y = value, colour = variable)) + geom_line() +
scale_y_continuous(limits=c(0, 100)) +
xlab("Tiempo") +
ylab("Temperatura --- (ÂșC) y Humedad (%)")+
geom_line(size=1.9)+
scale_color_manual(values=c("#FF0000", "#0000FF"),
name="Medidas",
labels=c("Temperature", "Humidity"))
So, I want to add something like my example to my code.
Is it possible?
Data for lines are:
temp_int hum_int datetime
11.6 76.8 2014-02-01 00:00:00
11.4 77.8 2014-02-01 00:15:00
11.3 79.4 2014-02-01 00:30:00
.....
And data for the bar at bottom is:
datetime DPV
2013-01-01 12:35:00 0
2013-01-01 12:45:00 1
2013-01-01 13:00:00 1
....
2013-01-01 13:00:00 2
Better!! I've changed my data and now I have:
datetime,temp_int,hum_int,dpv
"2014-02-15 00:00:00",67.2,13.6,"red"
"2014-02-15 00:15:00",63.4,13.8,"yellow"
"2014-02-15 00:30:00",61.2,14.2,"green"
"2014-02-15 00:45:00",60.4,14.5,"green"
....
It hard to answer without actual data but here some ideas to start with.
Made some sample data consisting of x values, temp values for lines and id values used to color bar.
set.seed(1)
df<-data.frame(x=1:100,temp=runif(100,10,50),id=sample(1:3,100,replace=TRUE))
One solution is to use geom_tile() and set y values to 0 and use id for the fill=. Problem with this solution is that height of bar will depend on range of your data. You can increase the height by calling several geom_tile() calls with different y values.
ggplot(df,aes(x))+geom_line(aes(y=temp))+
geom_tile(aes(y=0,fill=factor(id)))
Another possibility is to use geom_bar() with stat="identity" and set y value height of bars you need. With argument width= you can change width of bars to ensure that there is no space between bars.
ggplot(df,aes(x))+geom_line(aes(y=temp))+
geom_bar(aes(y=4,fill=factor(id)),stat="identity",width=1)
UPDATE - solution with OP data
Data provided in question.
df<-read.table(text="datetime,temp_int,hum_int,dpv
2014-02-15 00:00:00,67.2,13.6,red
2014-02-15 00:15:00,63.4,13.8,yellow
2014-02-15 00:30:00,61.2,14.2,green
2014-02-15 00:45:00,60.4,14.5,green",header=T,sep=",")
Converting datetime column to POSIXct.
df$datetime <- as.POSIXct(df$datetime)
Melting data frame to long format.
library(reshape2)
df.melt<-melt(df,id.vars=c("datetime","dpv"))
Now for plotting use melted data frame. Argument colour= should be placed inside the aes() of geom_line() because color change border of bars if placed inside the ggplot() call. For geom_bar() use dpv as fill= and also use scale_fill_identity() because dpv contains actual color names. If you need to have bars that are close to each other use width=900. I set 900 because you have time interval of 15 minutes that correspond to 900 seconds (1 second is unit in this case).
ggplot(df.melt, aes(x = datetime, y = value)) +
geom_line(aes(colour = variable),size=1.9) +
geom_bar(aes(y=4,fill=dpv),stat="identity",width=900)+
scale_fill_identity()

Resources