# Analysis of climate data for Swansea and Wuhan for each month in a year


### Functions

# cleanDataFrame()
# Function that takes input data frames and tidies them up
cleanDataFrame <- function(dataFrame) {
  
  # Transpose data frame so months are in a column
  dataFrame <- data.frame(t(dataFrame))
  
  # Remove the first row so we can rename column headers
  dataFrame <- dataFrame[-1,]
  colnames(dataFrame) <- c("Month", "AvgTemperature", "MinTemperature",
                           "MaxTemperature", "Rainfall", "Humidity", "RainyDays",
                           "AvgHoursSun")
  
  return(dataFrame)
}

# cumulativeCalculation()
# Function that takes in a data frame and a column of values and outputs a 
# vector with cumulative values for each city
cumulativeCalculation <- function(dataFrame, columnName) {
  
  # Separate Swansea data from Wuhan data
  swanseaData <- dataFrame[dataFrame$City == "Swansea",]
  wuhanData <- dataFrame[dataFrame$City == "Wuhan",]
  
  # Find the index of the column given to the function
  columnIndex <- which(names(climateData) == columnName, arr.ind=TRUE)
  
  # Initialize vectors containing the first value in the given column for each
  # city
  cumulativeSwansea <- swanseaData[1, columnIndex]
  cumulativeWuhan <- wuhanData[1, columnIndex]
  
  # Loop over each row from the first to the last but one
  for (i in 1:nrow(swanseaData)-1) {
    
    # Add the value at that index plus the value of the next row in the data
    # frame, then add that value to the cumulative vector
    cumulativeSwansea <- c(cumulativeSwansea, cumulativeSwansea[i] + 
                             swanseaData[i+1, columnIndex])
  }
  
  # Loop over each row from the first to the last but one
  for (i in 1:nrow(wuhanData)-1) {
    
    # Add the value at that index plus the value of the next row in the data
    # frame, then add that value to the cumulative vector
    cumulativeWuhan <- c(cumulativeWuhan, cumulativeWuhan[i] + 
                           wuhanData[i+1, columnIndex])
  }
  
  # Bind the Swansea cumulative data and the Wuhan cumulative data
  cumulativeSum <- c(cumulativeSwansea, cumulativeWuhan)
  
  # Return the cumulativeSum vector
  return(cumulativeSum)
}

# displayGraph()
# Function that takes the city and a weather parameter as inputs and outputs
# a line graph of that weather parameter over the year for that city
displayGraph <- function(cityName, weatherParameter) {
  
  # Isolate the data for the input city
  citySubFrame <- climateData[climateData$City == cityName,]
  
  # Select the column containing the data for the input weather parameter
  weatherData <- citySubFrame[[weatherParameter]]
  
  # Isolate the month names from the city sub frame
  monthData <- citySubFrame$Month
  
  # Define units for weather parameter on y-axis
  if (weatherParameter == "AvgTemperature" || weatherParameter == "MinTemperature" || 
      weatherParameter == "MaxTemperature") {
    unitsParameter <- "Degrees Celsius"
  }
  else if (weatherParameter == "Rainfall") {
    unitsParameter <- "mm"
  }
  else if (weatherParameter == "Humidity") {
    unitsParameter <- "%"
  }
  else if (weatherParameter == "RainyDays") {
    unitsParameter <- "Days"
  }
  else if (weatherParameter == "AvgHoursSun") {
    unitsParameter <- "Hours"
  }
  
  # Plot a line graph with the months on the x-axis and the weather parameter
  # data on the y-axis for the input city
  plot.default(monthData, weatherData, xlab="Month", xaxt="n",
               ylab=sprintf("%s / %s", weatherParameter, unitsParameter),
               main=sprintf("Graph of %s in %s", weatherParameter, cityName), 
               type="o")
  
  # Label the x-axis with the names of the months instead of indexes
  axis(1, at=factor(monthData), label = monthData)
}

# compareCities()
# Function that takes in a start month and end month, and two weather parameters,
# and displays them in a plot
# Humidity and average temperature are plotted as line graphs, all other 
# parameters are plotted as bar graphs
compareCities <- function(startMonth, endMonth, weatherParamOne, weatherParamTwo) {
  
  # Split the data frame into Swansea and Wuhan data sub frames
  swanseaData <- climateData[climateData$City == "Swansea",]
  wuhanData <- climateData[climateData$City == "Wuhan",]
  
  # Identify the index of the start month and end month
  startPlot <- which(climateData$Month == startMonth)[1]
  endPlot <- which(climateData$Month == endMonth)[1]
  
  # Find the upper and lower limits for plotting our graph 
  maxLimitOne <- max(max(swanseaData[[weatherParamOne]]), 
                     max(wuhanData[[weatherParamOne]]))
  minLimitOne <- min(min(swanseaData[[weatherParamOne]]), 
                     min(wuhanData[[weatherParamOne]]))
  maxLimitTwo <- max(max(swanseaData[[weatherParamTwo]]), 
                     max(wuhanData[[weatherParamTwo]]))
  minLimitTwo <- min(min(swanseaData[[weatherParamTwo]]), 
                     min(wuhanData[[weatherParamTwo]]))
  
  # Define which variables will be plotted as line graphs and bar graphs
  barGraphVariables <- c("MinTemperature", "MaxTemperature", "Rainfall", 
                         "RainyDays", "AvgHoursSun")
  lineGraphVariables <- c("Humidity", "AvgTemperature")
  
  # Define the units for the first weather parameter to show on the y-axis
  if (weatherParamOne == "AvgTemperature" || weatherParamOne == "MinTemperature" || 
      weatherParamOne == "MaxTemperature") {
    unitsParamOne <- "Degrees Celsius"
  }
  else if (weatherParamOne == "Rainfall") {
    unitsParamOne <- "mm"
  }
  else if (weatherParamOne == "Humidity") {
    unitsParamOne <- "%"
  }
  else if (weatherParamOne == "RainyDays") {
    unitsParamOne <- "Days"
  }
  else if (weatherParamOne == "AvgHoursSun") {
    unitsParamOne <- "Hours"
  }
  
  # Define the units for the second weather parameter to show on the y-axis
  if (weatherParamTwo == "AvgTemperature" || weatherParamTwo == "MinTemperature" || 
      weatherParamTwo == "MaxTemperature") {
    unitsParamTwo <- "Degrees Celsius"
  }
  else if (weatherParamTwo == "Rainfall") {
    unitsParamTwo <- "mm"
  }
  else if (weatherParamTwo == "Humidity") {
    unitsParamTwo <- "%"
  }
  else if (weatherParamTwo == "RainyDays") {
    unitsParamTwo <- "Days"
  }
  else if (weatherParamTwo == "AvgHoursSun") {
    unitsParamTwo <- "Hours"
  }
  
  # If both weather parameters are line graph variables, plot a line-line graph
  if ((weatherParamOne %in% lineGraphVariables) && (weatherParamTwo %in% lineGraphVariables)) {
    
    # Plot the first weather parameter as a line graph with the appropriate
    # y-axis limits and labels
    # Plot the Swansea data first for the first weather parameter
    par(mar=c(5, 5, 3, 5))
    plot.default(swanseaData$Month[startPlot:endPlot], 
                 swanseaData[[weatherParamOne]][startPlot:endPlot], xlab="Month",
                 ylab=sprintf("%s / %s", weatherParamOne, unitsParamOne), 
                 ylim=c(minLimitOne, maxLimitOne), type="l", col="red", 
                 main=sprintf("A graph of %s and %s from %s to %s for Swansea and Wuhan",
                              weatherParamOne, weatherParamTwo, startMonth, endMonth))
    
    # Add a line to the plot on the same axis for the first weather parameter 
    # for Wuhan
    lines(wuhanData$Month[startPlot:endPlot], 
          wuhanData[[weatherParamOne]][startPlot:endPlot], xaxt="n", yaxt="n",
          type="l", col="blue")
    
    # Plot the second weather parameter as a line graph with the appropriate
    # y-axis limits and labels, with the y-axis on the right
    # Plot the Swansea data first for the second weather parameter
    par(new=TRUE)
    plot.default(swanseaData$Month[startPlot:endPlot],
                 swanseaData[[weatherParamTwo]][startPlot:endPlot], xlab="",
                 ylab="", ylim=c(minLimitTwo, maxLimitTwo), xaxt="n", yaxt="n",
                 type="l", lty=2, col="red")
    
    # Set the axis to the right side of the graph and add a label with units
    axis(side=4)
    mtext(sprintf("%s / %s", weatherParamTwo, unitsParamTwo), side=4, line=3)
    
    # Add a line to the plot on the same axis for the second weather parameter 
    # for Wuhan
    lines(wuhanData$Month[startPlot:endPlot], 
          wuhanData[[weatherParamTwo]][startPlot:endPlot], xaxt="n", yaxt="n",
          type="l", lty=2, col="blue")
    
    # Add a legend to show which lines belong to which data set
    legend("topleft", c(sprintf("%s in Swansea", weatherParamOne), 
                        sprintf("%s in Wuhan", weatherParamOne),
                        sprintf("%s in Swansea", weatherParamTwo),
                        sprintf("%s in Wuhan", weatherParamTwo)),
           col=c("red", "blue", "red", "blue"), lty=c(1, 1, 2, 2))
  }
  
  # If one weather parameter is a line graph variable and the other is a bar
  # graph variable, plot a bar-line graph
  else if (((weatherParamOne %in% lineGraphVariables) && 
            (weatherParamTwo %in% barGraphVariables)) || 
           ((weatherParamOne %in% barGraphVariables) &&
            (weatherParamTwo %in% lineGraphVariables))) {
    
    if (weatherParamOne %in% barGraphVariables) {
      
      # Plot the first weather parameter as a bar graph with the appropriate
      # y-axis limits and labels
      par(mar=c(5, 5, 3, 5))
      
      # Bind the Swansea and Wuhan data for the first weather parameter
      boundWeatherOne <- rbind(swanseaData[[weatherParamOne]][startPlot:endPlot], 
                               wuhanData[[weatherParamOne]][startPlot:endPlot])
      
      # Plot the data for both cities side by side in a bar plot
      barplot(boundWeatherOne, beside=TRUE, names=swanseaData$Month[startPlot:endPlot],
              ylab=sprintf("%s / %s", weatherParamOne, unitsParamOne), axis.lty=1,
              main=sprintf("A graph of %s and %s from %s to %s for Swansea and Wuhan",
                           weatherParamOne, weatherParamTwo, startMonth, endMonth),
              col=c("maroon", "yellowgreen"))
      
      # Plot the second weather parameter as a line graph with the appropriate
      # y-axis limits and labels, with the y-axis on the right
      # Plot the Swansea data first for the second weather parameter
      par(new=TRUE)
      plot.default(swanseaData$Month[startPlot:endPlot],
                   swanseaData[[weatherParamTwo]][startPlot:endPlot], xlab="",
                   ylab="", ylim=c(minLimitTwo, maxLimitTwo), xaxt="n", yaxt="n",
                   type="l", lty=1, col="red")
      
      # Set the axis to the right side of the graph and add a label with units
      axis(side=4)
      mtext(sprintf("%s / %s", weatherParamTwo, unitsParamTwo), side=4, line=3)
      
      # Add a line to the plot on the same axis for the second weather parameter 
      # for Wuhan
      lines(wuhanData$Month[startPlot:endPlot], 
            wuhanData[[weatherParamTwo]][startPlot:endPlot], xaxt="n", yaxt="n",
            type="l", lty=1, col="blue")
      
      # Add a legend to show which lines and bars belong to which data set
      legend("topleft", c(sprintf("%s in Swansea", weatherParamOne),
                          sprintf("%s in Wuhan", weatherParamOne),
                          sprintf("%s in Swansea", weatherParamTwo),
                          sprintf("%s in Wuhan", weatherParamTwo)),
             col=c(NA, NA, "red", "blue"), lty=c(1, 1), 
             fill=c("maroon", "yellowgreen", NA, NA), 
             border=c("maroon", "yellowgreen", NA, NA))
    }
    
    else if (weatherParamOne %in% lineGraphVariables) {
      
      # Plot the first weather parameter as a bar graph with the appropriate
      # y-axis limits and labels
      par(mar=c(5, 5, 3, 5))
      
      # Bind the Swansea and Wuhan data for the second weather parameter
      boundWeatherTwo <- rbind(swanseaData[[weatherParamTwo]][startPlot:endPlot], 
                               wuhanData[[weatherParamTwo]][startPlot:endPlot])
      
      # Plot the data for both cities side by side in a bar plot
      barplot(boundWeatherTwo, beside=TRUE, names=swanseaData$Month[startPlot:endPlot],
              ylab=sprintf("%s / %s", weatherParamTwo, unitsParamTwo), axis.lty=1,
              main=sprintf("A graph of %s and %s from %s to %s for Swansea and Wuhan",
                           weatherParamTwo, weatherParamOne, startMonth, endMonth),
              col=c("maroon", "yellowgreen"))
      
      # Plot the first weather parameter as a line graph with the appropriate
      # y-axis limits and labels, with the y-axis on the right
      # Plot the Swansea data first for the first weather parameter
      par(new=TRUE)
      plot.default(swanseaData$Month[startPlot:endPlot],
                   swanseaData[[weatherParamOne]][startPlot:endPlot],  xlab="",
                   ylab="", ylim=c(minLimitOne, maxLimitOne), xaxt="n", yaxt="n",
                   type="l", lty=1, col="red")
      
      # Set the axis to the right side of the graph and add a label with units
      axis(side=4)
      mtext(sprintf("%s / %s", weatherParamOne, unitsParamOne), side=4, line=3)
      
      # Add a line to the plot on the same axis for the first weather parameter 
      # for Wuhan
      lines(wuhanData$Month[startPlot:endPlot], 
            wuhanData[[weatherParamOne]][startPlot:endPlot], xaxt="n", yaxt="n",
            type="l", lty=1, col="blue")
      
      # Add a legend to show which lines and bars belong to which data set
      legend("topleft", c(sprintf("%s in Swansea", weatherParamTwo),
                          sprintf("%s in Wuhan", weatherParamTwo),
                          sprintf("%s in Swansea", weatherParamOne),
                          sprintf("%s in Wuhan", weatherParamOne)),
             col=c(NA, NA, "red", "blue"), lty=c(1, 1), 
             fill=c("maroon", "yellowgreen", NA, NA), 
             border=c("maroon", "yellowgreen", NA, NA))
    }
  }
  
  # If both weather parameters are bar graph variables, plot a bar-bar graph
  else if ((weatherParamOne %in% barGraphVariables) && 
           (weatherParamTwo %in% barGraphVariables)) {
    
    # Import the ggplot2 library to plot the bar graph
    library(ggplot2)
    
    # Create vectors containing the data needed to build the bar graph
    monthNames <- rep(swanseaData$Month[startPlot:endPlot], 4)
    repeatValue <- endPlot - startPlot + 1
    cityWeather <- rep(c(sprintf("%s in Swansea", weatherParamOne), 
                         sprintf("%s in Wuhan", weatherParamOne), 
                         sprintf("%s in Swansea", weatherParamTwo), 
                         sprintf("%s in Wuhan", weatherParamTwo)), each=repeatValue)
    weatherValues <- rbind(swanseaData[[weatherParamOne]][startPlot:endPlot], 
                           wuhanData[[weatherParamOne]][startPlot:endPlot],
                           swanseaData[[weatherParamTwo]][startPlot:endPlot], 
                           wuhanData[[weatherParamTwo]][startPlot:endPlot])
    
    # Use the vectors created to build a data frame which will be used to plot
    # the bar graph
    barDataFrame <- data.frame(cityWeather, monthNames, weatherValues)
    
    # Use the ggplot function to plot all of the data
    ggplot(data=barDataFrame, aes(x=monthNames, y=weatherValues, fill=cityWeather)) +
      geom_bar(stat="identity", position=position_dodge()) +
      scale_y_continuous(name=sprintf("%s / %s", weatherParamOne, unitsParamOne), 
                         sec.axis=sec_axis(trans=~.*1, 
                         name=sprintf("%s / %s", weatherParamTwo, unitsParamTwo))) +
      
      # Add a title and x-axis and y-axis labels
      ggtitle(sprintf("Graph of %s and %s from %s to %s for Swansea and Wuhan",
                      weatherParamOne, weatherParamTwo, startMonth, endMonth)) +
      xlab("Month") + labs(fill="Legend")
  }
}


### Main code

# Task 1: Read in csv files and display in a data frame with the city as a factor
# Read in csv files as data frames
climateDataSwansea <- read.csv("climate_swansea.csv", header=FALSE)
climateDataWuhan <- read.csv("climate_wuhan.csv", header=FALSE)

# Use cleanDataFrame function to transpose and clean data frames
climateDataSwansea <- cleanDataFrame(climateDataSwansea)
climateDataWuhan <- cleanDataFrame(climateDataWuhan)

# Bind individual data frames into one data frame
climateData <- rbind(climateDataSwansea, climateDataWuhan)

# Add a column to the data frame containing city names
climateData <- cbind(City=rep(c("Swansea", "Wuhan"), each=12), climateData)

# Turn city and month columns into factors
climateData$City <- factor(climateData$City)
climateData$Month <- factor(climateData$Month, levels = c("January", "February", 
                                                          "March", "April", "May",
                                                          "June", "July", "August",
                                                          "September", "October",
                                                          "November", "December"))

# Ensure columns containing numeric data are in fact numeric
numericCols <- c("AvgTemperature", "MinTemperature", "MaxTemperature",
                 "Rainfall", "Humidity", "RainyDays", "AvgHoursSun")

# Loop over each column containing numeric data and turn into a numeric column
for (i in numericCols) {
  
  climateData[[i]] <- as.numeric(climateData[[i]])
}

# Display the data frame
climateData


# Task 2: Create a new data frame cumulativeData that shows the cumulative 
# rainfall and cumulative number of hours of sunshine for each city

# Create a data frame containing the city, month, cumulative rainfall and 
# cumulative average hours of sun columns using the cumulativeCalculation
# function
cumulativeData <- data.frame(City=climateData$City, Month=climateData$Month, 
                             CumulativeRainfall = 
                               cumulativeCalculation(climateData, "Rainfall"),
                             CumulativeHoursSun = 
                               cumulativeCalculation(climateData, "AvgHoursSun"))

# Display the data frame
cumulativeData


# Task 3: Include a function displayGraph that will take the city name and 
# weather parameter and will produce a line graph of that weather parameter 
# over the year for that city

# Display humidity in Wuhan using the displayGraph function
displayGraph("Wuhan", "Humidity")

# Display rainfall in Swansea using the displayGraph function
displayGraph("Swansea", "Rainfall")


# Task 4: Include a function compareCities that will take the start month and 
# end month and two weather parameters, and will plot the data for those 
# parameters for both cities on the same graph
# Mean temperature and humidity are shown as line graphs, while all other 
# weather parameters are shown as bar plots

# Display the mean temperature and hours of sunshine for both cities (from 
# January to December) using the compareCities function
compareCities("January", "December", "AvgTemperature", "AvgHoursSun")


