Monday Discussion Problems
part(1)
# Constructor for base class "vehicle"
vehicle <- function(make, model, year, mpg) {
# --- validation ---
if (!is.character(make) || length(make) != 1L)
stop("`make` must be a single character string")
if (!is.character(model) || length(model) != 1L)
stop("`model` must be a single character string")
if (!is.numeric(year) || length(year) != 1L)
stop("`year` must be a single number")
if (!is.numeric(mpg) || length(mpg) != 1L)
stop("`mpg` must be a single number")
# --- build object ---
structure(
list(
make = make,
model = model,
year = year,
mpg = mpg
),
class = "vehicle"
)
}
part(2)
print.vehicle <- function(x, ...) {
cat(sprintf("%s %s (%d)\n", x$make, x$model, x$year))
cat(sprintf(" Fuel economy: %g.mpg\n", x$mpg))
invisible(x) # preserve default console behaviour
}
part(3)
electric_car <- function(make, model, year, mpg = 0, battery_range) {
if (!is.numeric(battery_range) || length(battery_range) != 1L || battery_range <= 0)
stop("battery_range must be a positive number")
obj <- vehicle(make, model, year, mpg) # reuse the base constructor
obj$battery_range <- battery_range
class(obj) <- c("electric_car", "vehicle")
obj
}
part (4)
print.electric_car <- function(x, ...) {
NextMethod() # prints the vehicle part
cat(sprintf(" Battery range: %g.miles\n", x$battery_range))
invisible(x)
}
part 5
## ---- S4 class definition
setClass(
"Truck",
slots = list(
make = "character",
model = "character",
cargo_capacity = "numeric" # tons
),
validity = function(object) {
if (!is.character(object@make) || length(object@make) != 1L)
"Slot 'make' must be a single character string"
else if (!is.character(object@model) || length(object@model) != 1L)
"Slot 'model' must be a single character string"
else if (!is.numeric(object@cargo_capacity) ||
length(object@cargo_capacity) != 1L ||
object@cargo_capacity <= 0)
"Slot 'cargo_capacity' must be a single positive number (tons)"
else
TRUE
}
)
part (6)
setMethod(
"show",
"Truck",
function(object) {
cat(sprintf(
"%s %s\n Cargo capacity: %g tons\n",
object@make,
object@model,
object@cargo_capacity
))
}
)
# ── Test S3 vehicles ────────────────────────────────────────────────────────
car1 <- vehicle("Toyota", "Camry", 2022, 32)
car2 <- vehicle("Honda", "Civic", 2023, 36)
# ── Test electric car ───────────────────────────────────────────────────────
tesla <- electric_car("Tesla", "Model 3", 2024, 0, 300)
# ── Test S4 truck ───────────────────────────────────────────────────────────
library(methods)
truck1 <- new("Truck", make = "Ford", model = "F‑150", cargo_capacity = 2.5)
# ── Print / show the objects ────────────────────────────────────────────────
print(car1)
## Toyota Camry (2022)
## Fuel economy: 32.mpg
print(car2)
## Honda Civic (2023)
## Fuel economy: 36.mpg
print(tesla)
## Tesla Model 3 (2024)
## Fuel economy: 0.mpg
## Battery range: 300.miles
show(truck1)
## Ford F‑150
## Cargo capacity: 2.5 tons
Wednesday Discussion Problems
# --------------------------------------------------------------------------
# 1. Bar plot – mean carat by cut & colour
# --------------------------------------------------------------------------
bar_plot <- diamonds %>%
group_by(cut, color) %>%
summarise(mean_carat = mean(carat), .groups = "drop") %>%
ggplot(aes(x = cut, y = mean_carat, fill = color)) +
geom_col(position = position_dodge()) +
labs(
title = "Average Carat by Cut and Color",
x = "Cut",
y = "Average Carat",
fill = "Colour"
) +
scale_fill_viridis_d(option = "viridis") +
theme_bw()
# --------------------------------------------------------------------------
# 2. Scatter plot – carat vs price, 30 diamonds per cut
# --------------------------------------------------------------------------
set.seed(82294) # reproducible sampling
diamonds_sample <- diamonds %>%
group_by(cut) %>%
sample_n(30) %>%
ungroup()
scatter_plot <- ggplot(
diamonds_sample,
aes(x = carat, y = price, colour = cut, shape = cut)
) +
geom_point(size = 5) +
labs(
title = "Scatter Plot of Carat vs Price by Cut",
x = "Carat",
y = "Price",
colour = "Cut",
shape = "Cut"
) +
scale_color_viridis_d(option = "viridis") +
scale_shape_manual(
values = c(
"Fair" = 16, # filled circle ●
"Good" = 17, # filled triangle ▲
"Very Good" = 15, # filled square ■
"Premium" = 3, # plus +
"Ideal" = 7 # square with X inside ⌧
)
) +
theme_bw()
# --------------------------------------------------------------------------
# Display
# --------------------------------------------------------------------------
bar_plot
scatter_plot