Public
Edited
Nov 26
1 fork
Insert cell
bikeshare_clean_minimal@3.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
// Function to clean data by removing rows with NaN or null values
function cleanData(data) {
return data.filter(row => {
return !isNaN(row.ride_duration); // || row.start_lat !== null || row.start_lng !== null && row.gender !== null;
});
}

// Clean the bikeshare_data

Insert cell
bikeshare_data = cleanData(bikeshare_data_raw)
Insert cell
viz1={
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach((option) => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateDropdowns;
return select;
};

// Use the bikeshare_data
const data = bikeshare_data;

const durationBinOptions = ["0-10 min", "10-30 min", "30-60 min", "60+ min"];
const memberCasualOptions = ["member", "casual"];

const mainDropdown = createDropdown("Main", ["All", "Duration Bin", "Member Type"]);
const durationBinDropdown = createDropdown("Duration Bin", durationBinOptions);
const memberCasualDropdown = createDropdown("Member Type", memberCasualOptions);

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Update chart based on selected dropdowns
function updateChart() {
const selectedDurationBin = durationBinDropdown.value;
const selectedMemberCasual = memberCasualDropdown.value;
const selectedOption = mainDropdown.value;

const traces = [];

// Filter the data based on dropdown selections
const filteredData = data.filter((entry) => {
if (selectedOption === "Duration Bin") {
if (selectedDurationBin !== "All" && entry["duration_bin"] !== selectedDurationBin) return false;
} else if (selectedOption === "Member Type") {
if (selectedMemberCasual !== "All" && entry["member_casual"] !== selectedMemberCasual) return false;
}
return true;
});

// Group data by hour of day and calculate average ride duration for each hour
const hoursOfDay = Array.from({ length: 24 }, (_, i) => i); // Array of numbers 0-23
const avgRideDurationByHour = hoursOfDay.map((hour) => {
const hourData = filteredData.filter((entry) => parseInt(entry.hour_of_day) === hour);
const avgDuration = hourData.length > 0 ? hourData.reduce((sum, entry) => sum + entry.ride_duration, 0) / hourData.length : 0;
return avgDuration;
});

const xValues = hoursOfDay;
const yValues = avgRideDurationByHour;

// Color scale: low durations (blue) to high durations (red)
const colorScale = avgRideDurationByHour.map(duration => `rgba(${Math.min(255, duration * 4)}, 0, ${255 - Math.min(255, duration * 4)}, 0.8)`);

// Create the bar chart with the color scale
traces.push({
x: xValues,
y: yValues,
type: "bar",
name: "Average Ride Duration by Hour of Day",
marker: {
color: colorScale, // Apply color scale
},
});

const layout = {
title: "Average Ride Duration by Hour of Day",
xaxis: { title: "Hour of Day", dtick: 1 }, // Display all hours
yaxis: { title: "Average Ride Duration (minutes)" },
barmode: "group",
};

Plotly.newPlot(chartContainer, traces, layout);
}

// Update dropdown visibility based on the selection
function updateDropdowns() {
const selectedOption = mainDropdown.value;

// Reset display of both dropdowns
durationBinDropdown.style.display = "none";
memberCasualDropdown.style.display = "none";

// Display the appropriate dropdown
if (selectedOption === "Duration Bin") {
durationBinDropdown.style.display = "inline";
} else if (selectedOption === "Member Type") {
memberCasualDropdown.style.display = "inline";
}
updateChart(); // Update the chart after dropdown change
}

// UI setup
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select: "));
uiContainer.appendChild(mainDropdown);
uiContainer.appendChild(durationBinDropdown);
uiContainer.appendChild(memberCasualDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(chartContainer);

updateChart();

return container;
}
Insert cell
viz2={
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach((option) => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateDropdowns;
return select;
};

// Use the bikeshare_data
const data = bikeshare_data;

const durationBinOptions = ["0-10 min", "10-30 min", "30-60 min", "60+ min"];
const memberCasualOptions = ["member", "casual"];

const mainDropdown = createDropdown("Main", ["All", "Duration Bin", "Member Type"]);
const durationBinDropdown = createDropdown("Duration Bin", durationBinOptions);
const memberCasualDropdown = createDropdown("Member Type", memberCasualOptions);

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Update chart based on selected dropdowns
function updateChart() {
const selectedDurationBin = durationBinDropdown.value;
const selectedMemberCasual = memberCasualDropdown.value;
const selectedOption = mainDropdown.value;

const traces = [];

// Filter the data based on dropdown selections
const filteredData = data.filter((entry) => {
if (selectedOption === "Duration Bin") {
if (selectedDurationBin !== "All" && entry["duration_bin"] !== selectedDurationBin) return false;
} else if (selectedOption === "Member Type") {
if (selectedMemberCasual !== "All" && entry["member_casual"] !== selectedMemberCasual) return false;
}
return true;
});

// Group data by day of the week and calculate average ride duration for each day
const daysOfWeek = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
const avgRideDurationByDay = daysOfWeek.map((day) => {
const dayData = filteredData.filter((entry) => entry.day_of_week === day);
const avgDuration = dayData.length > 0 ? dayData.reduce((sum, entry) => sum + entry.ride_duration, 0) / dayData.length : 0;
return avgDuration;
});

const xValues = daysOfWeek;
const yValues = avgRideDurationByDay;

// Color scale: low durations (blue) to high durations (red)
const colorScale = avgRideDurationByDay.map(duration => `rgba(${Math.min(255, duration * 4)}, 0, ${255 - Math.min(255, duration * 4)}, 0.8)`);

// Create the bar chart with color scale
traces.push({
x: xValues,
y: yValues,
type: "bar",
name: "Average Ride Duration by Day of Week",
marker: {
color: colorScale, // Apply color scale based on duration
},
});

const layout = {
title: "Average Ride Duration by Day of Week",
xaxis: { title: "Day of Week" },
yaxis: { title: "Average Ride Duration (minutes)" },
barmode: "group",
};

Plotly.newPlot(chartContainer, traces, layout);
}

// Update dropdown visibility based on the selection
function updateDropdowns() {
const selectedOption = mainDropdown.value;

// Reset display of both dropdowns
durationBinDropdown.style.display = "none";
memberCasualDropdown.style.display = "none";

// Display the appropriate dropdown
if (selectedOption === "Duration Bin") {
durationBinDropdown.style.display = "inline";
} else if (selectedOption === "Member Type") {
memberCasualDropdown.style.display = "inline";
}
updateChart(); // Update the chart after dropdown change
}

// UI setup
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select: "));
uiContainer.appendChild(mainDropdown);
uiContainer.appendChild(durationBinDropdown);
uiContainer.appendChild(memberCasualDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(chartContainer);

updateChart();

return container;

}
Insert cell
viz3={
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateChart; // Update chart when dropdown changes
return select;
};

// Use the bikeshare_data
const data = bikeshare_data;

const memberCasualOptions = ["member", "casual"];
const mainDropdown = createDropdown("Member Type", memberCasualOptions);

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Create the hourly slider
const slider = document.createElement("input");
slider.type = "range";
slider.min = 0;
slider.max = 23;
slider.value = 12; // default to noon
slider.step = 1;
slider.style.width = "100%";

const hourLabel = document.createElement("div");
hourLabel.textContent = `Hour of Day: ${slider.value} (Drag to change)`;

slider.oninput = function() {
hourLabel.textContent = `Hour of Day: ${slider.value}`;
updateChart(); // Update chart when slider is moved
};

// Function to update the chart based on the slider and dropdown
function updateChart() {
const selectedMemberCasual = mainDropdown.value;
const selectedHour = slider.value;

// Filter the data based on hour of the day and member type
const filteredData = data.filter(entry => {
return entry.hour_of_day == selectedHour && entry.member_casual === selectedMemberCasual;
});

// Group data by hour and calculate the average ride duration for each hour
const xValues = Array.from({ length: 24 }, (_, i) => i); // Fixed x-axis from 0 to 23 (hours)
const yValues = xValues.map(hour => {
const hourData = filteredData.filter(entry => entry.hour_of_day === hour);
return hourData.length > 0
? hourData.reduce((sum, entry) => sum + entry.ride_duration, 0) / hourData.length
: 0; // Calculate average for each hour
});

// Create trace for the fixed point at coordinates 25x25
const dotTrace = {
x: [25], // Fixed x-coordinate for the dot
y: [25], // Fixed y-coordinate for the dot
mode: 'markers',
marker: { size: 12, color: 'red' },
name: `Fixed Point at Coordinates (25, 25)`
};

// Create a trace for the full hourly average line
const lineTrace = {
x: xValues,
y: yValues,
type: 'line',
name: `Average Ride Duration for ${selectedMemberCasual.charAt(0).toUpperCase() + selectedMemberCasual.slice(1)}`
};

// Combine both traces (line and dot)
const traces = [lineTrace, dotTrace];

const layout = {
title: `Average Ride Duration for ${selectedMemberCasual.charAt(0).toUpperCase() + selectedMemberCasual.slice(1)} at Hour ${selectedHour}`,
xaxis: { title: 'Hour of Day', range: [0, 23] }, // Fixed x-axis range from 0 to 23
yaxis: { title: 'Average Ride Duration (minutes)', range: [0, 60] }, // Fixed y-axis range (assuming a range)
showlegend: true
};

Plotly.newPlot(chartContainer, traces, layout);
}

// UI setup
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Member Type: "));
uiContainer.appendChild(mainDropdown);

const sliderContainer = document.createElement("div");
sliderContainer.appendChild(hourLabel);
sliderContainer.appendChild(slider);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(sliderContainer);
container.appendChild(chartContainer);

updateChart(); // Initial chart render

return container;
}

Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateDropdowns;
return select;
};

// Use the bikeshare_data
const data = bikeshare_data;

const cityOptions = ["All", "Frazier Park", "Glendale"];

const mainDropdown = createDropdown("Main", ["All", "City"]);
const cityDropdown = createDropdown("City", cityOptions);

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Update chart based on selected dropdowns
function updateChart() {
const selectedCity = cityDropdown.value;
const selectedOption = mainDropdown.value;

const traces = [];

const filteredData = data.filter(entry => {
if (selectedOption === "City") {
if (selectedCity !== "All" && entry["City"] !== selectedCity) return false;
}
return true;
});

const cityCounts = {};
filteredData.forEach(entry => {
cityCounts[entry.City] = (cityCounts[entry.City] || 0) + 1;
});

const xValues = Object.keys(cityCounts);
const yValues = Object.values(cityCounts);

traces.push({
x: xValues,
y: yValues,
type: 'bar',
name: 'Ride Duration by City'
});

const layout = {
title: 'Ride Duration by City',
xaxis: { title: 'City' },
yaxis: { title: 'Count of Rides' },
barmode: 'group'
};

Plotly.newPlot(chartContainer, traces, layout);
}

// Update dropdown visibility based on the selection
function updateDropdowns() {
const selectedOption = mainDropdown.value;

// Reset display of dropdowns
cityDropdown.style.display = "none";

// Display the appropriate dropdown
if (selectedOption === "City") {
cityDropdown.style.display = "inline";
}
updateChart(); // Update the chart after dropdown change
}

// UI setup
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select: "));
uiContainer.appendChild(mainDropdown);
uiContainer.appendChild(cityDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(chartContainer);

updateChart();

return container;
}


Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateDropdowns;
return select;
};

// Use the bikeshare_data
const data = bikeshare_data;

const membershipOptions = ["All", "Member", "Casual"];

const mainDropdown = createDropdown("Main", ["All", "Membership Type"]);
const membershipDropdown = createDropdown("Membership Type", membershipOptions);

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Update chart based on selected dropdowns
function updateChart() {
const selectedMembership = membershipDropdown.value;
const selectedOption = mainDropdown.value;

const traces = [];

const filteredData = data.filter(entry => {
if (selectedOption === "Membership Type") {
if (selectedMembership !== "All" && entry["member_casual"] !== selectedMembership) return false;
}
return true;
});

const membershipCounts = {};
filteredData.forEach(entry => {
membershipCounts[entry.member_casual] = (membershipCounts[entry.member_casual] || 0) + 1;
});

const xValues = Object.keys(membershipCounts);
const yValues = Object.values(membershipCounts);

traces.push({
x: xValues,
y: yValues,
type: 'bar',
name: 'Ride Duration by Membership Type'
});

const layout = {
title: 'Ride Duration by Membership Type',
xaxis: { title: 'Membership Type' },
yaxis: { title: 'Count of Rides' },
barmode: 'group'
};

Plotly.newPlot(chartContainer, traces, layout);
}

// Update dropdown visibility based on the selection
function updateDropdowns() {
const selectedOption = mainDropdown.value;

// Reset display of dropdowns
membershipDropdown.style.display = "none";

// Display the appropriate dropdown
if (selectedOption === "Membership Type") {
membershipDropdown.style.display = "inline";
}
updateChart(); // Update the chart after dropdown change
}

// UI setup
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select: "));
uiContainer.appendChild(mainDropdown);
uiContainer.appendChild(membershipDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(chartContainer);

updateChart();

return container;
}

Insert cell
viz4={

const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateDropdowns;
return select;
};

// Function to update the dropdowns (this was missing earlier)
function updateDropdowns() {
updateChart(); // Update the chart whenever a dropdown value is changed
}

// Use the bikeshare_data
const data = bikeshare_data;

const durationBinOptions = ["All", "0-10 min", "10-30 min", "30-60 min", "1-2 hours", "2-4 hours", "4+ hours"];
const memberCasualOptions = ["All", "member", "casual"];

const mainDropdown = createDropdown("Main", ["All", "Duration Bin", "Member Type"]);
const durationBinDropdown = createDropdown("Duration Bin", durationBinOptions);
const memberCasualDropdown = createDropdown("Member Type", memberCasualOptions);

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Update chart based on selected dropdowns
function updateChart() {
const dayOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const hours = Array.from({ length: 24 }, (_, i) => i);

// Create matrices to hold total duration and count of rides
const rideDurationMatrix = Array.from({ length: 7 }, () => Array(24).fill(0));
const rideCountMatrix = Array.from({ length: 7 }, () => Array(24).fill(0));

// Get selected filter values
const selectedDurationBin = durationBinDropdown.value;
const selectedMemberCasual = memberCasualDropdown.value;

// Filter data based on selected options
const filteredData = data.filter(entry => {
let includeData = true;
// Filter by Duration Bin
if (selectedDurationBin !== "All") {
if (selectedDurationBin === "0-10 min" && entry.ride_duration > 10) includeData = false;
else if (selectedDurationBin === "10-30 min" && (entry.ride_duration <= 10 || entry.ride_duration > 30)) includeData = false;
else if (selectedDurationBin === "30-60 min" && (entry.ride_duration <= 30 || entry.ride_duration > 60)) includeData = false;
else if (selectedDurationBin === "1-2 hours" && (entry.ride_duration <= 60 || entry.ride_duration > 120)) includeData = false;
else if (selectedDurationBin === "2-4 hours" && (entry.ride_duration <= 120 || entry.ride_duration > 240)) includeData = false;
else if (selectedDurationBin === "4+ hours" && entry.ride_duration <= 240) includeData = false;
}

// Filter by Member Type
if (selectedMemberCasual !== "All" && entry.member_casual !== selectedMemberCasual) {
includeData = false;
}

return includeData;
});

// Fill the matrix with filtered data
filteredData.forEach(entry => {
const startTime = new Date(entry.started_at);

// Validate the data
if (!startTime.getTime() || isNaN(entry.ride_duration)) {
return; // Skip invalid entries
}

const day = startTime.getDay();
const hour = startTime.getHours();
rideDurationMatrix[day][hour] += entry.ride_duration;
rideCountMatrix[day][hour] += 1;
});

// Calculate the average ride duration for each day and hour
const avgRideDurationMatrix = rideDurationMatrix.map((row, i) => row.map((duration, j) => {
return rideCountMatrix[i][j] === 0 ? 0 : duration / rideCountMatrix[i][j]; // Avoid division by zero
}));

const traces = [{
z: avgRideDurationMatrix,
x: hours,
y: dayOfWeek,
type: 'heatmap',
colorscale: 'YlGnBu', // You can adjust this for better contrast, e.g., 'Jet', 'RdYlBu', Viridis
colorbar: {
title: 'Average Ride Duration (min)'
}
}];

const layout = {
title: 'Average Ride Duration by Hour of Day and Day of Week',
xaxis: { title: 'Hour of Day' },
yaxis: { title: 'Day of Week' },
};

Plotly.newPlot(chartContainer, traces, layout);
}

// UI setup
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Filters: "));
uiContainer.appendChild(mainDropdown);
uiContainer.appendChild(durationBinDropdown);
uiContainer.appendChild(memberCasualDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(chartContainer);

updateChart();

return container;

}
Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateDropdowns;
return select;
};

// Function to update the dropdowns
function updateDropdowns() {
updateScatterPlot(); // Update the chart whenever a dropdown value is changed
}

// Use the bikeshare_data
const data = bikeshare_data;

const memberCasualOptions = ["All", "member", "casual"];
const memberCasualDropdown = createDropdown("Member Type", memberCasualOptions);

const scatterContainer = document.createElement("div");
scatterContainer.style.width = "100%";
scatterContainer.style.height = "600px";

// Update chart based on selected dropdown
function updateScatterPlot() {
const selectedMemberCasual = memberCasualDropdown.value;

// Filter data based on selected options
const filteredData = data.filter(entry => {
if (selectedMemberCasual !== "All" && entry.member_casual !== selectedMemberCasual) {
return false;
}
return true;
});

const scatterData = {
x: filteredData.map(entry => new Date(entry.started_at)),
y: filteredData.map(entry => entry.ride_duration),
mode: 'markers',
type: 'scatter',
marker: { size: 5 },
name: 'Ride Duration'
};

const layout = {
title: 'Ride Duration by Start Time',
xaxis: { title: 'Start Time' },
yaxis: { title: 'Ride Duration (minutes)' }
};

Plotly.newPlot(scatterContainer, [scatterData], layout);
}

// UI setup
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Member Type: "));
uiContainer.appendChild(memberCasualDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(scatterContainer);

updateScatterPlot();

return container;
}

Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateDropdowns;
return select;
};

// Function to update the dropdowns
function updateDropdowns() {
updateBoxPlot(); // Update the chart whenever a dropdown value is changed
}

// Use the bikeshare_data
const data = bikeshare_data;

const durationBinOptions = ["All", "0-10 min", "10-30 min", "30-60 min", "1-2 hours", "2-4 hours", "4+ hours"];
const durationBinDropdown = createDropdown("Duration Bin", durationBinOptions);

const boxContainer = document.createElement("div");
boxContainer.style.width = "100%";
boxContainer.style.height = "600px";

// Update chart based on selected dropdowns
function updateBoxPlot() {
const selectedDurationBin = durationBinDropdown.value;

// Filter data based on selected options
const filteredData = data.filter(entry => {
if (selectedDurationBin !== "All") {
if (selectedDurationBin === "0-10 min" && entry.ride_duration > 10) return false;
else if (selectedDurationBin === "10-30 min" && (entry.ride_duration <= 10 || entry.ride_duration > 30)) return false;
else if (selectedDurationBin === "30-60 min" && (entry.ride_duration <= 30 || entry.ride_duration > 60)) return false;
else if (selectedDurationBin === "1-2 hours" && (entry.ride_duration <= 60 || entry.ride_duration > 120)) return false;
else if (selectedDurationBin === "2-4 hours" && (entry.ride_duration <= 120 || entry.ride_duration > 240)) return false;
else if (selectedDurationBin === "4+ hours" && entry.ride_duration <= 240) return false;
}
return true;
});

const casualRides = filteredData.filter(entry => entry.member_casual === "casual").map(entry => entry.ride_duration);
const memberRides = filteredData.filter(entry => entry.member_casual === "member").map(entry => entry.ride_duration);

const traces = [
{
y: casualRides,
type: 'box',
name: 'Casual Riders',
marker: { color: 'red' }
},
{
y: memberRides,
type: 'box',
name: 'Member Riders',
marker: { color: 'blue' }
}
];

const layout = {
title: 'Ride Duration for Casual vs Member Riders',
yaxis: { title: 'Ride Duration (minutes)' }
};

Plotly.newPlot(boxContainer, traces, layout);
}

// UI setup
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Duration Bin: "));
uiContainer.appendChild(durationBinDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(boxContainer);

updateBoxPlot();

return container;
}

Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Use the bikeshare_data
const data = bikeshare_data;

const bubbleContainer = document.createElement("div");
bubbleContainer.style.width = "100%";
bubbleContainer.style.height = "600px";

// Update Bubble Plot
function updateBubblePlot() {
const hours = data.map(entry => new Date(entry.started_at).getHours());
const rideDurations = data.map(entry => entry.ride_duration);
const trace = {
x: hours,
y: rideDurations,
mode: 'markers',
marker: {
size: rideDurations.map(d => Math.sqrt(d)),
sizemode: 'area',
color: hours,
colorscale: 'Viridis'
}
};

const layout = {
title: 'Ride Duration vs Hour of Day',
xaxis: { title: 'Hour of Day' },
yaxis: { title: 'Ride Duration (minutes)' }
};

Plotly.newPlot(bubbleContainer, [trace], layout);
}

updateBubblePlot();

return bubbleContainer;
}

Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateDropdowns; // Trigger update when dropdown changes
return select;
};

// Function to update the chart when dropdown values change
function updateDropdowns() {
updateChart(); // Call the function to update chart with new filters
}

// Use the bikeshare_data
const data = bikeshare_data;

// Dropdown options
const durationBinOptions = ["All", "0-10 min", "10-30 min", "30-60 min", "1-2 hours", "2-4 hours", "4+ hours"];
const memberCasualOptions = ["All", "member", "casual"];

// Create the dropdowns
const mainDropdown = createDropdown("Main", ["All", "Duration Bin", "Member Type"]);
const durationBinDropdown = createDropdown("Duration Bin", durationBinOptions);
const memberCasualDropdown = createDropdown("Member Type", memberCasualOptions);

// Create container for charts
const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Update chart based on selected dropdowns
function updateChart() {
const dayOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const hours = Array.from({ length: 24 }, (_, i) => i);

// Create matrices to hold total duration and count of rides
const rideDurationMatrix = Array.from({ length: 7 }, () => Array(24).fill(0));
const rideCountMatrix = Array.from({ length: 7 }, () => Array(24).fill(0));

// Get selected filter values
const selectedDurationBin = durationBinDropdown.value;
const selectedMemberCasual = memberCasualDropdown.value;

// Filter data based on selected options
const filteredData = data.filter(entry => {
let includeData = true;

// Filter by Duration Bin
if (selectedDurationBin !== "All") {
if (selectedDurationBin === "0-10 min" && entry.ride_duration > 10) includeData = false;
else if (selectedDurationBin === "10-30 min" && (entry.ride_duration <= 10 || entry.ride_duration > 30)) includeData = false;
else if (selectedDurationBin === "30-60 min" && (entry.ride_duration <= 30 || entry.ride_duration > 60)) includeData = false;
else if (selectedDurationBin === "1-2 hours" && (entry.ride_duration <= 60 || entry.ride_duration > 120)) includeData = false;
else if (selectedDurationBin === "2-4 hours" && (entry.ride_duration <= 120 || entry.ride_duration > 240)) includeData = false;
else if (selectedDurationBin === "4+ hours" && entry.ride_duration <= 240) includeData = false;
}

// Filter by Member Type
if (selectedMemberCasual !== "All" && entry.member_casual !== selectedMemberCasual) {
includeData = false;
}

return includeData;
});

// Fill the matrix with filtered data
filteredData.forEach(entry => {
const startTime = new Date(entry.started_at);

// Validate the data
if (!startTime.getTime() || isNaN(entry.ride_duration)) {
return; // Skip invalid entries
}

const day = startTime.getDay();
const hour = startTime.getHours();
rideDurationMatrix[day][hour] += entry.ride_duration;
rideCountMatrix[day][hour] += 1;
});

// Calculate the average ride duration for each day and hour
const avgRideDurationMatrix = rideDurationMatrix.map((row, i) => row.map((duration, j) => {
return rideCountMatrix[i][j] === 0 ? 0 : duration / rideCountMatrix[i][j]; // Avoid division by zero
}));

// Plot the heatmap
const traces = [{
z: avgRideDurationMatrix,
x: hours,
y: dayOfWeek,
type: 'heatmap',
colorscale: 'Viridis', // Adjust color scale for better contrast
colorbar: {
title: 'Average Ride Duration (min)'
}
}];

const layout = {
title: 'Average Ride Duration by Hour of Day and Day of Week',
xaxis: { title: 'Hour of Day' },
yaxis: { title: 'Day of Week' },
};

// Render the chart
Plotly.newPlot(chartContainer, traces, layout);
}

// UI setup: append dropdowns and chart container to the document
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Filters: "));
uiContainer.appendChild(mainDropdown);
uiContainer.appendChild(durationBinDropdown);
uiContainer.appendChild(memberCasualDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(chartContainer);

// Initial rendering
updateChart();

return container;
}

Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateDropdowns; // Trigger update when dropdown changes
return select;
};

// Function to update the chart when dropdown values change
function updateDropdowns() {
updateHeatmap();
updateTimeSeries();
updateUserComparison();
}

// Dropdown options
const durationBinOptions = ["All", "0-10 min", "10-30 min", "30-60 min", "1-2 hours", "2-4 hours", "4+ hours"];
const memberCasualOptions = ["All", "member", "casual"];
const timePeriodOptions = ["Monthly", "Quarterly"];

// Create dropdowns
const durationBinDropdown = createDropdown("Duration Bin", durationBinOptions);
const memberCasualDropdown = createDropdown("Member Type", memberCasualOptions);
const timePeriodDropdown = createDropdown("Time Period", timePeriodOptions);

// Create container for charts
const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Function to filter data based on dropdown values
function filterData() {
const selectedDurationBin = durationBinDropdown.value;
const selectedMemberCasual = memberCasualDropdown.value;
const filteredData = bikeshare_data.filter(entry => {
let includeData = true;

// Filter by Duration Bin
if (selectedDurationBin !== "All") {
if (selectedDurationBin === "0-10 min" && entry.ride_duration > 10) includeData = false;
else if (selectedDurationBin === "10-30 min" && (entry.ride_duration <= 10 || entry.ride_duration > 30)) includeData = false;
else if (selectedDurationBin === "30-60 min" && (entry.ride_duration <= 30 || entry.ride_duration > 60)) includeData = false;
else if (selectedDurationBin === "1-2 hours" && (entry.ride_duration <= 60 || entry.ride_duration > 120)) includeData = false;
else if (selectedDurationBin === "2-4 hours" && (entry.ride_duration <= 120 || entry.ride_duration > 240)) includeData = false;
else if (selectedDurationBin === "4+ hours" && entry.ride_duration <= 240) includeData = false;
}

// Filter by Member Type
if (selectedMemberCasual !== "All" && entry.member_casual !== selectedMemberCasual) {
includeData = false;
}

return includeData;
});
return filteredData;
}

// Heatmap: Average Ride Duration by Hour of Day and Day of Week
function updateHeatmap() {
const dayOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const hours = Array.from({ length: 24 }, (_, i) => i);
const rideDurationMatrix = Array.from({ length: 7 }, () => Array(24).fill(0));
const rideCountMatrix = Array.from({ length: 7 }, () => Array(24).fill(0));
const filteredData = filterData();

filteredData.forEach(entry => {
const startTime = new Date(entry.started_at);
const day = startTime.getDay();
const hour = startTime.getHours();
rideDurationMatrix[day][hour] += entry.ride_duration;
rideCountMatrix[day][hour] += 1;
});

const avgRideDurationMatrix = rideDurationMatrix.map((row, i) => row.map((duration, j) => {
return rideCountMatrix[i][j] === 0 ? 0 : duration / rideCountMatrix[i][j];
}));

const trace = {
z: avgRideDurationMatrix,
x: hours,
y: dayOfWeek,
type: 'heatmap',
colorscale: 'Viridis',
colorbar: {
title: 'Average Ride Duration (min)'
}
};

const layout = {
title: 'Average Ride Duration by Hour of Day and Day of Week',
xaxis: { title: 'Hour of Day' },
yaxis: { title: 'Day of Week' },
};

Plotly.newPlot(chartContainer, [trace], layout);
}

// Time-Series Analysis: Ride Frequency Trends (Monthly or Quarterly)
function updateTimeSeries() {
const timePeriod = timePeriodDropdown.value;
const timeSeriesData = {};
const filteredData = filterData();

filteredData.forEach(entry => {
const startTime = new Date(entry.started_at);
const period = (timePeriod === "Monthly") ? startTime.getMonth() : Math.floor(startTime.getMonth() / 3);
timeSeriesData[period] = (timeSeriesData[period] || 0) + 1;
});

const periods = Object.keys(timeSeriesData).map(key => `Period ${parseInt(key) + 1}`);
const counts = Object.values(timeSeriesData);

const trace = {
x: periods,
y: counts,
type: 'bar',
};

const layout = {
title: `Ride Frequency: ${timePeriod} Trends`,
xaxis: { title: `Period (${timePeriod})` },
yaxis: { title: 'Ride Count' },
};

Plotly.newPlot(chartContainer, [trace], layout);
}

// User Classification Comparisons: Casual vs Member Users
function updateUserComparison() {
const filteredData = filterData();
const casualRiders = filteredData.filter(entry => entry.member_casual === 'casual');
const memberRiders = filteredData.filter(entry => entry.member_casual === 'member');
const casualRideDurations = casualRiders.map(entry => entry.ride_duration);
const memberRideDurations = memberRiders.map(entry => entry.ride_duration);
const trace1 = {
type: 'histogram',
x: casualRideDurations,
name: 'Casual Riders',
opacity: 0.75,
marker: { color: 'rgba(255, 99, 132, 0.6)' }
};
const trace2 = {
type: 'histogram',
x: memberRideDurations,
name: 'Member Riders',
opacity: 0.75,
marker: { color: 'rgba(54, 162, 235, 0.6)' }
};

const layout = {
title: 'Ride Duration Comparison: Casual vs Member Riders',
barmode: 'overlay',
xaxis: { title: 'Ride Duration (minutes)' },
yaxis: { title: 'Frequency' },
};

Plotly.newPlot(chartContainer, [trace1, trace2], layout);
}

// UI setup: append dropdowns and chart container to the document
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Filters: "));
uiContainer.appendChild(durationBinDropdown);
uiContainer.appendChild(memberCasualDropdown);
uiContainer.appendChild(timePeriodDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(chartContainer);

// Initial rendering
updateHeatmap();
updateTimeSeries();
updateUserComparison();

return container;
}

Insert cell
viz5={
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Use the bikeshare_data
const data = bikeshare_data;

// Create dropdown for filter options
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateGeospatialPlot; // Trigger update when dropdown changes
return select;
};

// Function to update Geospatial Bubble Plot
function updateGeospatialPlot() {
const memberCasualOptions = ["All", "member", "casual"];
const rideableTypeOptions = ["All", "electric_bike", "classic_bike", "docked_bike"]; // Options for rideable types
// Get selected filter values
const selectedMemberCasual = memberDropdown.value;
const selectedRideableType = rideableTypeDropdown.value;

// Filter data based on selected options
const filteredData = data.filter(entry => {
let includeData = true;

// Filter by Member Type
if (selectedMemberCasual !== "All" && entry.member_casual !== selectedMemberCasual) {
includeData = false;
}

// Filter by Rideable Type
if (selectedRideableType !== "All" && entry.rideable_type !== selectedRideableType) {
includeData = false;
}


return includeData;
});

// Prepare data for geospatial plot
const latitudes = filteredData.map(entry => entry.start_lat);
const longitudes = filteredData.map(entry => entry.start_lng);
const rideableType = filteredData.map(entry => entry.rideable_type);

const traces = [{
type: "scattermapbox",
lat: latitudes,
lon: longitudes,
mode: "markers",
marker: {
size: 9,
color: rideableType.map(type =>
type === 'electric_bike' ? 'blue' :
type === 'classic_bike' ? 'green' :
type === 'docked_bike' ? 'red' : 'gray'
),
opacity: 0.6,
},
text: rideableType,
}];

const layout = {
mapbox: {
style: "open-street-map",
zoom: 10,
center: { lat: 41.88, lon: -87.63 }, // Chicago center
},
title: 'Start Locations of Bikes',
};

Plotly.newPlot(geospatialContainer, traces, layout);
}

// Create dropdowns for filters
const memberDropdown = createDropdown("Member Type", ["All", "member", "casual"]);
const rideableTypeDropdown = createDropdown("Rideable Type", ["All", "electric_bike", "classic_bike", "docked_bike"]); // Updated dropdown options

// Create container for charts
const geospatialContainer = document.createElement("div");
geospatialContainer.style.width = "100%";
geospatialContainer.style.height = "600px";

// UI setup: append dropdowns and chart container to the document
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Filters: "));
uiContainer.appendChild(memberDropdown);
uiContainer.appendChild(rideableTypeDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(geospatialContainer);

// Initial rendering
updateGeospatialPlot();

// Return the container with dropdowns and chart
return container;

}
Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

const rideableTypeOptions = [...new Set(bikeshare_data.map(entry => entry.rideable_type))];
const memberCasualOptions = ["All", "member", "casual"];

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateChart; // Trigger update when dropdown changes
return select;
};

// Dropdown for rideable type and member/casual
const rideableTypeDropdown = createDropdown("Rideable Type", ["All", ...rideableTypeOptions]);
const memberCasualDropdown = createDropdown("Member Type", memberCasualOptions);

// Create chart container
const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Update chart function
function updateChart() {
const selectedRideableType = rideableTypeDropdown.value;
const selectedMemberCasual = memberCasualDropdown.value;

const filteredData = bikeshare_data.filter(entry => {
let includeData = true;

if (selectedRideableType !== "All" && entry.rideable_type !== selectedRideableType) {
includeData = false;
}

if (selectedMemberCasual !== "All" && entry.member_casual !== selectedMemberCasual) {
includeData = false;
}

return includeData;
});

// Check if filteredData is not empty
if (filteredData.length === 0) {
console.log("No data available for the selected filters.");
return;
}

const trace = {
x: filteredData.map(entry => entry.start_lng),
y: filteredData.map(entry => entry.start_lat),
mode: 'markers',
type: 'scattergeo',
marker: {
size: 5, // Fixed marker size for visibility
color: filteredData.map(entry => {
// Assign colors based on rideable_type
if (entry.rideable_type === 'electric_bike') return 'blue';
if (entry.rideable_type === 'classic_bike') return 'green';
if (entry.rideable_type === 'docked_bike') return 'red';
return 'grey'; // Default color if rideable_type is unknown
}),
showscale: true, // Display color scale
colorbar: {
title: "Rideable Type",
}
},
text: filteredData.map(entry => `Ride Duration: ${entry.ride_duration} min`)
};

const layout = {
title: 'Geospatial Plot: Start Locations of Bike Rides',
geo: {
scope: 'usa',
projection: {
type: 'albers usa'
},
showland: true,
landcolor: 'rgb(255, 255, 255)', // White land color
subunitcolor: 'rgb(217, 217, 217)', // Subunit color for countries/states
center: {
lat: 41.8781, // Center around Chicago
lon: -87.6298
},
zoom: 12, // Adjust the zoom level for better visibility of hotspots
}
};

Plotly.newPlot(chartContainer, [trace], layout);
}

// UI setup: append dropdowns and chart container to the document
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Filters: "));
uiContainer.appendChild(rideableTypeDropdown);
uiContainer.appendChild(memberCasualDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(chartContainer);

// Initial rendering of the plot
updateChart();

return container;
}

Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

const memberCasualOptions = ["All", "member", "casual"];

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateChart;
return select;
};

// Dropdown for member/casual
const memberCasualDropdown = createDropdown("Member Type", memberCasualOptions);

// Create chart container
const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Update chart function
function updateChart() {
const selectedMemberCasual = memberCasualDropdown.value;

const filteredData = bikeshare_data.filter(entry => {
return selectedMemberCasual === "All" || entry.member_casual === selectedMemberCasual;
});

const sortedDurations = filteredData.map(entry => entry.ride_duration).sort((a, b) => a - b);
const cumulativeValues = sortedDurations.map((_, i) => (i + 1) / sortedDurations.length);

const trace = {
x: sortedDurations,
y: cumulativeValues,
type: 'scatter',
mode: 'lines',
name: 'CDF'
};

const layout = {
title: 'CDF Plot of Ride Duration',
xaxis: { title: 'Ride Duration (min)' },
yaxis: { title: 'Cumulative Probability' }
};

Plotly.newPlot(chartContainer, [trace], layout);
}

// UI setup
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Member Type: "));
uiContainer.appendChild(memberCasualDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(chartContainer);

// Initial rendering
updateChart();

return container;
}

Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Use the bikeshare_data
const data = bikeshare_data;

// Create dropdown for filter options
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateGeospatialPlot; // Trigger update when dropdown changes
return select;
};

// Function to update Geospatial Heatmap Plot
function updateGeospatialPlot() {
const memberCasualOptions = ["All", "member", "casual"];
const rideableTypeOptions = ["All", "electric_bike", "classic_bike", "docked_bike"]; // Options for rideable types
const dayOfWeekOptions = ["All", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; // Options for day of the week

// Get selected filter values
const selectedMemberCasual = memberDropdown.value;
const selectedRideableType = rideableTypeDropdown.value;
const selectedDayOfWeek = dayOfWeekDropdown.value;

// Filter data based on selected options
const filteredData = data.filter(entry => {
let includeData = true;

// Filter by Member Type
if (selectedMemberCasual !== "All" && entry.member_casual !== selectedMemberCasual) {
includeData = false;
}

// Filter by Rideable Type
if (selectedRideableType !== "All" && entry.rideable_type !== selectedRideableType) {
includeData = false;
}

// Filter by Day of Week
const rideDate = new Date(entry.start_time);
const dayOfWeek = rideDate.toLocaleString('en-US', { weekday: 'long' }); // Get the day of the week (e.g., "Monday")
if (selectedDayOfWeek !== "All" && dayOfWeek !== selectedDayOfWeek) {
includeData = false;
}

return includeData;
});

// Prepare data for geospatial heatmap
const latitudes = filteredData.map(entry => entry.start_lat);
const longitudes = filteredData.map(entry => entry.start_lng);

const heatmapTrace = {
type: "scattermapbox",
mode: "markers",
lat: latitudes,
lon: longitudes,
marker: {
size: 10, // Adjust size for visibility
color: "rgba(0, 102, 255, 0.6)", // Electric blue color with transparency
opacity: 0.8,
showscale: true,
colorbar: {
title: "Ride Density",
thickness: 15,
tickvals: [0, 0.5, 1],
ticktext: ["Low", "Medium", "High"],
}
},
text: filteredData.map(entry => `Ride Duration: ${entry.ride_duration} min`),
};

const layout = {
mapbox: {
style: "open-street-map",
zoom: 12,
center: { lat: 41.88, lon: -87.63 }, // Chicago center
pitch: 0,
bearing: 0,
},
title: "Heatmap: Start Locations of Bike Rides",
};

// Create the heatmap plot
Plotly.newPlot(geospatialContainer, [heatmapTrace], layout);
}

// Create dropdowns for filters
const memberDropdown = createDropdown("Member Type", ["All", "member", "casual"]);
const rideableTypeDropdown = createDropdown("Rideable Type", ["All", "electric_bike", "classic_bike", "docked_bike"]);
const dayOfWeekDropdown = createDropdown("Day of Week", ["All", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]);

// Create container for charts
const geospatialContainer = document.createElement("div");
geospatialContainer.style.width = "100%";
geospatialContainer.style.height = "600px";

// UI setup: append dropdowns and chart container to the document
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Filters: "));
uiContainer.appendChild(memberDropdown);
uiContainer.appendChild(rideableTypeDropdown);
uiContainer.appendChild(dayOfWeekDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(geospatialContainer);

// Initial rendering
updateGeospatialPlot();

// Return the container with dropdowns and chart
return container;
}

Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Use the bikeshare_data
const data = bikeshare_data;

// Create dropdown for filter options
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateGeospatialPlot; // Trigger update when dropdown changes
return select;
};

// Function to update Geospatial Heatmap Plot
function updateGeospatialPlot() {
const memberCasualOptions = ["All", "member", "casual"];
const rideableTypeOptions = ["All", "electric_bike", "classic_bike", "docked_bike"]; // Options for rideable types

// Get selected filter values
const selectedMemberCasual = memberDropdown.value;
const selectedRideableType = rideableTypeDropdown.value;

// Filter data based on selected options
const filteredData = data.filter(entry => {
let includeData = true;

// Filter by Member Type
if (selectedMemberCasual !== "All" && entry.member_casual !== selectedMemberCasual) {
includeData = false;
}

// Filter by Rideable Type
if (selectedRideableType !== "All" && entry.rideable_type !== selectedRideableType) {
includeData = false;
}

return includeData;
});

// Prepare data for geospatial heatmap
const latitudes = filteredData.map(entry => entry.start_lat);
const longitudes = filteredData.map(entry => entry.start_lng);

const heatmapTrace = {
type: "scattermapbox",
mode: "markers",
lat: latitudes,
lon: longitudes,
marker: {
size: 10, // Adjust size for visibility
color: "rgba(255, 0, 0, 0.5)", // Semi-transparent red color
opacity: 0.6,
showscale: true,
},
text: filteredData.map(entry => `Ride Duration: ${entry.ride_duration} min`),
};

const layout = {
mapbox: {
style: "open-street-map",
zoom: 12,
center: { lat: 41.88, lon: -87.63 }, // Chicago center
pitch: 0,
bearing: 0,
},
title: "Heatmap: Start Locations of Bike Rides",
};

// Create the heatmap plot
Plotly.newPlot(geospatialContainer, [heatmapTrace], layout);
}

// Create dropdowns for filters
const memberDropdown = createDropdown("Member Type", ["All", "member", "casual"]);
const rideableTypeDropdown = createDropdown("Rideable Type", ["All", "electric_bike", "classic_bike", "docked_bike"]);

// Create container for charts
const geospatialContainer = document.createElement("div");
geospatialContainer.style.width = "100%";
geospatialContainer.style.height = "600px";

// UI setup: append dropdowns and chart container to the document
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Filters: "));
uiContainer.appendChild(memberDropdown);
uiContainer.appendChild(rideableTypeDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(geospatialContainer);

// Initial rendering
updateGeospatialPlot();

// Return the container with dropdowns and chart
return container;
}

Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Use the bikeshare_data
const data = bikeshare_data;

// Create dropdown for filter options
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateHotspotPlot; // Trigger update when dropdown changes
return select;
};

// Function to update Hotspot Geospatial Plot
function updateHotspotPlot() {
const memberCasualOptions = ["All", "member", "casual"];
const rideableTypeOptions = ["All", "electric_bike", "classic_bike", "docked_bike"]; // Options for rideable types
const dockedOptions = ["All", "docked", "not_docked"]; // New filter for docked status

// Get selected filter values
const selectedMemberCasual = memberDropdown.value;
const selectedRideableType = rideableTypeDropdown.value;
const selectedDocked = dockedDropdown.value;

// Filter data based on selected options
const filteredData = data.filter(entry => {
let includeData = true;

// Filter by Member Type
if (selectedMemberCasual !== "All" && entry.member_casual !== selectedMemberCasual) {
includeData = false;
}

// Filter by Rideable Type
if (selectedRideableType !== "All" && entry.rideable_type !== selectedRideableType) {
includeData = false;
}

// Filter by Docked Status
if (selectedDocked !== "All" && entry.docked !== selectedDocked) {
includeData = false;
}

return includeData;
});

// Prepare data for hotspot (density) plot
const latitudes = filteredData.map(entry => entry.start_lat);
const longitudes = filteredData.map(entry => entry.start_lng);

// Heatmap: Calculate density of rides at each location
const heatmapData = {
type: 'scattermapbox',
mode: 'markers',
lat: latitudes,
lon: longitudes,
marker: {
size: 6,
color: latitudes.map((lat, index) => Math.random() * 10), // Random color for each point for now
colorscale: 'YlOrRd', // Heatmap colorscale
opacity: 0.6
},
text: filteredData.map(entry => `${entry.start_lat}, ${entry.start_lng}`)
};

const layout = {
mapbox: {
style: "open-street-map",
zoom: 12,
center: { lat: 41.88, lon: -87.63 }, // Chicago center
},
title: 'Hotspots of Bike Rides',
showlegend: false
};

Plotly.newPlot(hotspotContainer, [heatmapData], layout);
}

// Create dropdowns for filters
const memberDropdown = createDropdown("Member Type", ["All", "member", "casual"]);
const rideableTypeDropdown = createDropdown("Rideable Type", ["All", "electric_bike", "classic_bike", "docked_bike"]); // Updated dropdown options
const dockedDropdown = createDropdown("Docked Status", ["All", "docked", "not_docked"]); // New dropdown for docked status

// Create container for charts
const hotspotContainer = document.createElement("div");
hotspotContainer.style.width = "100%";
hotspotContainer.style.height = "600px";

// UI setup: append dropdowns and chart container to the document
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Filters: "));
uiContainer.appendChild(memberDropdown);
uiContainer.appendChild(rideableTypeDropdown);
uiContainer.appendChild(dockedDropdown); // Add the docked dropdown to the UI

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(hotspotContainer);

// Initial rendering
updateHotspotPlot();

// Return the container with dropdowns and chart
return container;

}
Insert cell
viz6={
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Use the bikeshare_data
const data = bikeshare_data;

// Create dropdown for filter options
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateGeospatialPlot; // Trigger update when dropdown changes
return select;
};

// Function to update Geospatial Heatmap Plot
function updateGeospatialPlot() {
const memberCasualOptions = ["All", "member", "casual"];
const rideableTypeOptions = ["All", "electric_bike", "classic_bike", "docked_bike"]; // Options for rideable types
const dayOfWeekOptions = ["All", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; // Options for day of the week

// Get selected filter values
const selectedMemberCasual = memberDropdown.value;
const selectedRideableType = rideableTypeDropdown.value;
const selectedDayOfWeek = dayOfWeekDropdown.value;

// Filter data based on selected options
const filteredData = data.filter(entry => {
let includeData = true;

// Filter by Member Type
if (selectedMemberCasual !== "All" && entry.member_casual !== selectedMemberCasual) {
includeData = false;
}

// Filter by Rideable Type
if (selectedRideableType !== "All" && entry.rideable_type !== selectedRideableType) {
includeData = false;
}

// Filter by Day of Week
if (selectedDayOfWeek !== "All" && entry.day_of_week !== selectedDayOfWeek) {
includeData = false;
}

return includeData;
});

// If no data is filtered, show a message or return
if (filteredData.length === 0) {
geospatialContainer.innerHTML = "No data available for the selected filters.";
return;
}

// Calculate min and max latitude and longitude
const latitudes = filteredData.map(entry => entry.start_lat);
const longitudes = filteredData.map(entry => entry.start_lng);

const minLat = Math.min(...latitudes);
const maxLat = Math.max(...latitudes);
const minLng = Math.min(...longitudes);
const maxLng = Math.max(...longitudes);

// Calculate the center of the bounding box (midpoint)
const centerLat = (minLat + maxLat) / 2;
const centerLng = (minLng + maxLng) / 2;

// Adjust zoom level based on the data range
const latDiff = maxLat - minLat;
const lngDiff = maxLng - minLng;
const zoom = Math.min(14, Math.max(8, Math.max(latDiff, lngDiff) * 10)); // Adjust zoom based on the data spread

// Prepare data for geospatial heatmap
const rideDurations = filteredData.map(entry => entry.ride_duration); // Use ride_duration as the size factor
const maxDuration = Math.max(...rideDurations); // Max value for scaling

const heatmapTrace = {
type: "scattermapbox",
mode: "markers",
lat: latitudes,
lon: longitudes,
marker: {
size: rideDurations.map(duration => (duration / maxDuration) * 30), // Scale size based on ride_duration
color: "rgba(0, 102, 255, 0.6)", // Electric blue color with transparency
opacity: 0.8, // Set opacity for all markers
showscale: false,
colorbar: {
title: "Ride Density",
thickness: 15,
tickvals: [0, 0.5, 1],
ticktext: ["Low", "Medium", "High"],
}
},
text: filteredData.map(entry => `Ride Duration: ${entry.ride_duration} min`),
};

const layout = {
mapbox: {
style: "open-street-map",
zoom: 10, // Set zoom based on the data range
center: { lat: centerLat, lon: centerLng }, // Centering on the data bounding box
pitch: 0,
bearing: 0,
},
title: "Heatmap: Start Locations of Bike Rides in Illinois",
};

// Create the heatmap plot
Plotly.newPlot(geospatialContainer, [heatmapTrace], layout);
}

// Create dropdowns for filters
const memberDropdown = createDropdown("Member Type", ["All", "member", "casual"]);
const rideableTypeDropdown = createDropdown("Rideable Type", ["All", "electric_bike", "classic_bike", "docked_bike"]);
const dayOfWeekDropdown = createDropdown("Day of Week", ["All", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]);

// Create container for charts
const geospatialContainer = document.createElement("div");
geospatialContainer.style.width = "100%";
geospatialContainer.style.height = "600px";

// UI setup: append dropdowns and chart container to the document
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Filters: "));
uiContainer.appendChild(memberDropdown);
uiContainer.appendChild(rideableTypeDropdown);
uiContainer.appendChild(dayOfWeekDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(geospatialContainer);

// Initial rendering
updateGeospatialPlot();

// Return the container with dropdowns and chart
return container;
}

Insert cell
viz7={
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

const memberCasualOptions = ["All", "member", "casual"];

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateChart;
return select;
};

// Dropdown for member/casual
const memberCasualDropdown = createDropdown("Member Type", memberCasualOptions);

// Create chart container
const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Update chart function
function updateChart() {
const selectedMemberCasual = memberCasualDropdown.value;

const filteredData = bikeshare_data.filter(entry => {
return selectedMemberCasual === "All" || entry.member_casual === selectedMemberCasual;
});

const dateDurations = {};
filteredData.forEach(entry => {
const date = new Date(entry.started_at).toLocaleDateString();
if (!dateDurations[date]) dateDurations[date] = { totalDuration: 0, count: 0 };
dateDurations[date].totalDuration += entry.ride_duration;
dateDurations[date].count += 1;
});

const dates = Object.keys(dateDurations);
const avgDurations = dates.map(date => dateDurations[date].totalDuration / dateDurations[date].count);

const trace = {
x: dates,
y: avgDurations,
type: 'scatter',
mode: 'lines',
name: 'Average Ride Duration'
};

const layout = {
title: 'Average Ride Duration Over Time',
xaxis: { title: 'Date' },
yaxis: { title: 'Average Ride Duration (min)' }
};

Plotly.newPlot(chartContainer, [trace], layout);
}

// UI setup
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Member Type: "));
uiContainer.appendChild(memberCasualDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(chartContainer);

// Initial rendering
updateChart();

return container;
}

Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

const continuousFields = ['ride_duration', 'start_lat', 'start_lng'];
const dataMatrix = continuousFields.map(field => bikeshare_data.map(entry => entry[field]));
// Calculate correlation matrix
function calculateCorrelation(matrix) {
const n = matrix[0].length;
const corrMatrix = matrix.map(row1 =>
matrix.map(row2 => {
const mean1 = row1.reduce((acc, x) => acc + x, 0) / n;
const mean2 = row2.reduce((acc, x) => acc + x, 0) / n;
const cov = row1.reduce((acc, x, i) => acc + (x - mean1) * (row2[i] - mean2), 0) / n;
const std1 = Math.sqrt(row1.reduce((acc, x) => acc + Math.pow(x - mean1, 2), 0) / n);
const std2 = Math.sqrt(row2.reduce((acc, x) => acc + Math.pow(x - mean2, 2), 0) / n);
return cov / (std1 * std2);
})
);
return corrMatrix;
}

const corrMatrix = calculateCorrelation(dataMatrix);
const trace = {
z: corrMatrix,
x: continuousFields,
y: continuousFields,
type: 'heatmap',
colorscale: 'RdBu',
zmin: -1,
zmax: 1,
colorbar: {
title: 'Correlation'
}
};

const layout = {
title: 'Correlation Heatmap',
xaxis: { title: 'Variables' },
yaxis: { title: 'Variables' },
};

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

Plotly.newPlot(chartContainer, [trace], layout);

return chartContainer;
}

Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

const dayOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

const rideCounts = Array(7).fill(0);
const totalDurations = Array(7).fill(0);

bikeshare_data.forEach(entry => {
const day = new Date(entry.started_at).getDay();
rideCounts[day]++;
totalDurations[day] += entry.ride_duration;
});

const avgDurations = totalDurations.map((duration, i) => rideCounts[i] === 0 ? 0 : duration / rideCounts[i]);

const trace = {
x: dayOfWeek,
y: avgDurations,
mode: 'markers',
marker: {
size: rideCounts,
color: avgDurations,
colorscale: 'Viridis',
showscale: true
},
text: rideCounts.map(count => `Number of Rides: ${count}`),
};

const layout = {
title: 'Bubble Chart: Ride Duration by Day of the Week',
xaxis: { title: 'Day of the Week' },
yaxis: { title: 'Average Ride Duration (min)' }
};

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

Plotly.newPlot(chartContainer, [trace], layout);

return chartContainer;
}

Insert cell
viz8={
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

const dayOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

const rideCounts = Array(7).fill(0);
const totalDurations = Array(7).fill(0);

bikeshare_data.forEach(entry => {
const day = new Date(entry.started_at).getDay();
rideCounts[day]++;
totalDurations[day] += entry.ride_duration;
});

const avgDurations = totalDurations.map((duration, i) => rideCounts[i] === 0 ? 0 : duration / rideCounts[i]);

const trace = {
y: dayOfWeek,
x: avgDurations,
type: 'funnel',
textinfo: "value+percent previous",
hoverinfo: "percent initial"
};

const layout = {
title: 'Funnel Plot: Average Ride Duration by Day of the Week',
xaxis: { title: 'Average Ride Duration (min)' },
yaxis: { title: 'Day of the Week' }
};

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

Plotly.newPlot(chartContainer, [trace], layout);

return chartContainer;
}

Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

const dayOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

const rideCounts = Array(7).fill(0);
const totalDurations = Array(7).fill(0);

bikeshare_data.forEach(entry => {
const day = new Date(entry.started_at).getDay();
rideCounts[day]++;
totalDurations[day] += entry.ride_duration;
});

const avgDurations = totalDurations.map((duration, i) => rideCounts[i] === 0 ? 0 : duration / rideCounts[i]);

const trace = {
type: 'scatterpolar',
r: avgDurations,
theta: dayOfWeek,
fill: 'toself',
name: 'Ride Duration'
};

const layout = {
title: 'Radar Plot: Ride Durations Across Days of the Week',
polar: {
radialaxis: {
visible: true,
range: [0, Math.max(...avgDurations)]
}
}
};

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

Plotly.newPlot(chartContainer, [trace], layout);

return chartContainer;
}

Insert cell
{
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

const dataPoints = bikeshare_data.map(entry => ({
ride_duration: entry.ride_duration,
hour_of_day: new Date(entry.started_at).getHours(),
start_lat: entry.start_lat,
start_lng: entry.start_lng
}));

const variables = ['ride_duration', 'hour_of_day', 'start_lat', 'start_lng'];

const pairs = [];
for (let i = 0; i < variables.length; i++) {
for (let j = i + 1; j < variables.length; j++) {
pairs.push([variables[i], variables[j]]);
}
}

const scatterTraces = pairs.map(pair => ({
x: dataPoints.map(entry => entry[pair[0]]),
y: dataPoints.map(entry => entry[pair[1]]),
mode: 'markers',
type: 'scatter',
name: `${pair[0]} vs ${pair[1]}`,
xaxis: `x${pairs.indexOf(pair) + 1}`,
yaxis: `y${pairs.indexOf(pair) + 1}`,
marker: { size: 5 }
}));

const layout = {
title: 'Pair Plot: Ride Duration, Hour of Day, Latitude, Longitude',
grid: { rows: 3, columns: 3, pattern: 'independent' },
};

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

Plotly.newPlot(chartContainer, scatterTraces, layout);

return chartContainer;
}

Insert cell
viz10 = {
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");
// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateChart; // Update chart when dropdown changes
return select;
};

const data = bikeshare_data;

const memberCasualOptions = ["member", "casual"];
const mainDropdown = createDropdown("Member Type", memberCasualOptions);

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Create the hourly slider
const slider = document.createElement("input");
slider.type = "range";
slider.min = 0;
slider.max = 23;
slider.value = 12; // default to noon
slider.step = 1;
slider.style.width = "100%";

const hourLabel = document.createElement("div");
hourLabel.textContent = `Hour of Day: ${slider.value} (Drag to change)`;

slider.oninput = function() {
hourLabel.textContent = `Hour of Day: ${slider.value}`;
updateChart(); // Update chart when slider is moved
};

// Function to update the chart based on the slider and dropdown
function updateChart() {
const selectedMemberCasual = mainDropdown.value;
const selectedHour = slider.value;

// Filter the data based on hour of the day and member type
const filteredData = data.filter(entry => {
return entry.member_casual === selectedMemberCasual;
});

// Group data by hour and calculate the average ride duration for each hour
const xValues = Array.from({ length: 24 }, (_, i) => i); // Fixed x-axis from 0 to 23 (hours)
const yValues = xValues.map(hour => {
const hourData = filteredData.filter(entry => entry.hour_of_day === hour);
return hourData.length > 0
? hourData.reduce((sum, entry) => sum + entry.ride_duration, 0) / hourData.length
: 0; // Calculate average for each hour
});

// Find the y-value for the red dot corresponding to the selected hour
const redDotYValue = yValues[selectedHour];

// Create trace for the moving red dot
const dotTrace = {
x: [selectedHour], // x-coordinate moves with the slider
y: [redDotYValue], // y-coordinate depends on the selected hour's y-value
mode: 'markers',
marker: { size: 12, color: '#FF0000' }, // Bright red dot
showlegend: false, // Do not show in the legend
name: `Moving Point for Hour ${selectedHour}`
};

// Create a trace for the full hourly average line with a vibrant color
const lineTrace = {
x: xValues,
y: yValues,
type: 'scatter',
mode: 'lines',
line: { color: '#1f77b4', width: 3 }, // Vibrant blue line
name: `Average Ride Duration for ${selectedMemberCasual.charAt(0).toUpperCase() + selectedMemberCasual.slice(1)}`
};

// Combine both traces (line and moving dot)
const traces = [lineTrace, dotTrace];

// Dynamically set the title including the ride duration for the selected hour
const layout = {
title: `Average Ride Duration for ${selectedMemberCasual.charAt(0).toUpperCase() + selectedMemberCasual.slice(1)} at Hour ${selectedHour} (${redDotYValue.toFixed(2)} minutes)`,
xaxis: { title: 'Hour of Day', range: [0, 23] }, // Fixed x-axis range from 0 to 23
yaxis: { title: 'Average Ride Duration (minutes)', range: [0, Math.max(...yValues) + 10] }, // Adjust y-axis range based on data
showlegend: true,
plot_bgcolor: '#F0F0F0', // Light grey background for better contrast
};

try {
Plotly.newPlot(chartContainer, traces, layout);
} catch (error) {
console.error('Error plotting the chart:', error);
}
}

// UI setup
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Member Type: "));
uiContainer.appendChild(mainDropdown);

const sliderContainer = document.createElement("div");
sliderContainer.appendChild(hourLabel);
sliderContainer.appendChild(slider);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(sliderContainer);
container.appendChild(chartContainer);

updateChart(); // Initial chart render

return container;
}

Insert cell
viz9 = {
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");
// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach(option => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateChart; // Update chart when dropdown changes
return select;
};

const data = bikeshare_data;

const memberCasualOptions = ["member", "casual"];
const mainDropdown = createDropdown("Member Type", memberCasualOptions);

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Create the hourly slider
const slider = document.createElement("input");
slider.type = "range";
slider.min = 0;
slider.max = 23;
slider.value = 12; // default to noon
slider.step = 1;
slider.style.width = "100%";

const hourLabel = document.createElement("div");
hourLabel.textContent = `Hour of Day: ${slider.value} (Drag to change)`;

slider.oninput = function() {
hourLabel.textContent = `Hour of Day: ${slider.value}`;
updateChart(); // Update chart when slider is moved
};

// Function to update the chart based on the slider and dropdown
function updateChart() {
const selectedMemberCasual = mainDropdown.value;
const selectedHour = slider.value;

// Filter the data based on hour of the day and member type
const filteredData = data.filter(entry => {
return entry.member_casual === selectedMemberCasual;
});

// Group data by hour and calculate the average ride duration for each hour
const xValues = Array.from({ length: 24 }, (_, i) => i); // Fixed x-axis from 0 to 23 (hours)
const yValues = xValues.map(hour => {
const hourData = filteredData.filter(entry => entry.hour_of_day === hour);
return hourData.length > 0
? hourData.reduce((sum, entry) => sum + entry.ride_duration, 0) / hourData.length
: 0; // Calculate average for each hour
});

// Find the y-value for the red dot corresponding to the selected hour
const redDotYValue = yValues[selectedHour];

// Create trace for the moving red dot
const dotTrace = {
x: [selectedHour], // x-coordinate moves with the slider
y: [redDotYValue], // y-coordinate depends on the selected hour's y-value
mode: 'markers',
marker: { size: 12, color: '#FF0000' }, // Bright red dot
showlegend: false, // Do not show in the legend
name: `Moving Point for Hour ${selectedHour}`
};

// Create a trace for the full hourly average line with a vibrant color
const lineTrace = {
x: xValues,
y: yValues,
type: 'scatter',
mode: 'lines',
line: { color: '#1f77b4', width: 3 }, // Vibrant blue line
name: `Average Ride Duration for ${selectedMemberCasual.charAt(0).toUpperCase() + selectedMemberCasual.slice(1)}`
};

// Combine both traces (line and moving dot)
const traces = [lineTrace, dotTrace];

// Dynamically set the title including the ride duration for the selected hour
const layout = {
title: `Average Ride Duration for ${selectedMemberCasual.charAt(0).toUpperCase() + selectedMemberCasual.slice(1)} at Hour ${selectedHour} (${redDotYValue.toFixed(2)} minutes)`,
xaxis: { title: 'Hour of Day', range: [0, 23] }, // Fixed x-axis range from 0 to 23
yaxis: { title: 'Average Ride Duration (minutes)', range: [0, Math.max(...yValues) + 10] }, // Adjust y-axis range based on data
showlegend: true,
plot_bgcolor: '#F0F0F0', // Light grey background for better contrast
};

try {
Plotly.newPlot(chartContainer, traces, layout);
} catch (error) {
console.error('Error plotting the chart:', error);
}
}

// UI setup
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select Member Type: "));
uiContainer.appendChild(mainDropdown);

const sliderContainer = document.createElement("div");
sliderContainer.appendChild(hourLabel);
sliderContainer.appendChild(slider);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(sliderContainer);
container.appendChild(chartContainer);

updateChart(); // Initial chart render

return container;
};

Insert cell
viz11 = {
const Plotly = await require("https://cdn.plot.ly/plotly-latest.min.js");

// Function to create dropdowns
const createDropdown = (name, options) => {
const select = document.createElement("select");
select.name = name;
options.forEach((option) => {
const optionElement = document.createElement("option");
optionElement.value = option;
optionElement.text = option;
select.appendChild(optionElement);
});
select.onchange = updateDropdowns;
return select;
};

// Use the bikeshare_data
const data = bikeshare_data;

const durationBinOptions = ["0-10 min", "10-30 min", "30-60 min", "60+ min"];
const memberCasualOptions = ["member", "casual"];

const mainDropdown = createDropdown("Main", ["All", "Duration Bin", "Member Type"]);
const durationBinDropdown = createDropdown("Duration Bin", durationBinOptions);
const memberCasualDropdown = createDropdown("Member Type", memberCasualOptions);

const chartContainer = document.createElement("div");
chartContainer.style.width = "100%";
chartContainer.style.height = "600px";

// Update chart based on selected dropdowns
function updateChart() {
const selectedDurationBin = durationBinDropdown.value;
const selectedMemberCasual = memberCasualDropdown.value;
const selectedOption = mainDropdown.value;

const traces = [];

// Filter the data based on dropdown selections
const filteredData = data.filter((entry) => {
if (selectedOption === "Duration Bin") {
if (selectedDurationBin !== "All" && entry["duration_bin"] !== selectedDurationBin) return false;
} else if (selectedOption === "Member Type") {
if (selectedMemberCasual !== "All" && entry["member_casual"] !== selectedMemberCasual) return false;
}
return true;
});

// Group data by day of the week and calculate average ride duration for each day
const daysOfWeek = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
const avgRideDurationByDay = daysOfWeek.map((day) => {
const dayData = filteredData.filter((entry) => entry.day_of_week === day);
const avgDuration = dayData.length > 0 ? dayData.reduce((sum, entry) => sum + entry.ride_duration, 0) / dayData.length : 0;
return avgDuration;
});

const xValues = daysOfWeek;
const yValues = avgRideDurationByDay;

// Color scale: low durations (blue) to high durations (red)
const colorScale = avgRideDurationByDay.map(duration => `rgba(${Math.min(255, duration * 4)}, 0, ${255 - Math.min(255, duration * 4)}, 0.8)`);

// Create the bar chart with color scale
traces.push({
x: xValues,
y: yValues,
type: "bar",
name: "Average Ride Duration by Day of Week",
marker: {
color: colorScale, // Apply color scale based on duration
},
});

const layout = {
title: "Average Ride Duration by Day of Week",
xaxis: { title: "Day of Week" },
yaxis: { title: "Average Ride Duration (minutes)" },
barmode: "group",
};

Plotly.newPlot(chartContainer, traces, layout);
}

// Update dropdown visibility based on the selection
function updateDropdowns() {
const selectedOption = mainDropdown.value;

// Reset display of both dropdowns
durationBinDropdown.style.display = "none";
memberCasualDropdown.style.display = "none";

// Display the appropriate dropdown
if (selectedOption === "Duration Bin") {
durationBinDropdown.style.display = "inline";
} else if (selectedOption === "Member Type") {
memberCasualDropdown.style.display = "inline";
}
updateChart(); // Update the chart after dropdown change
}

// UI setup
const uiContainer = document.createElement("div");
uiContainer.appendChild(document.createTextNode("Select: "));
uiContainer.appendChild(mainDropdown);
uiContainer.appendChild(durationBinDropdown);
uiContainer.appendChild(memberCasualDropdown);

const container = document.createElement("div");
container.appendChild(uiContainer);
container.appendChild(chartContainer);

updateChart();

return container;
};

Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more