Created
May 20, 2024 09:31
-
-
Save Madhusuthanan-B/38f3306118c2f751ccf4e0b3e977e8a3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Skewness Example - SaaS Subscription Analysis</title> | |
<script src="https://d3js.org/d3.v6.min.js"></script> | |
<style> | |
body { | |
font-family: Arial, sans-serif; | |
} | |
.result { | |
margin: 20px; | |
padding: 10px; | |
border: 1px solid #ccc; | |
border-radius: 5px; | |
width: 300px; | |
} | |
.positive-skew { | |
background-color: #d4edda; | |
} | |
.chart { | |
margin-top: 20px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="results" class="result"></div> | |
<div id="chart" class="chart"></div> | |
<script> | |
const SubscriptionAnalysis = (function() { | |
function calculateMean(data) { | |
const sum = data.reduce((acc, obj) => acc + obj.subscription_price, 0); | |
return sum / data.length; | |
} | |
function calculateMedian(data) { | |
const prices = data.map(obj => obj.subscription_price).sort((a, b) => a - b); | |
const mid = Math.floor(prices.length / 2); | |
return prices.length % 2 === 0 ? (prices[mid - 1] + prices[mid]) / 2 : prices[mid]; | |
} | |
function calculateMode(data) { | |
const frequency = {}; | |
data.forEach(obj => { | |
frequency[obj.tier] = (frequency[obj.tier] || 0) + 1; | |
}); | |
const maxFreq = Math.max(...Object.values(frequency)); | |
return Object.keys(frequency).filter(key => frequency[key] === maxFreq); | |
} | |
function calculateStandardDeviation(data) { | |
const mean = calculateMean(data); | |
const squaredDiffs = data.map(obj => Math.pow(obj.subscription_price - mean, 2)); | |
const variance = squaredDiffs.reduce((acc, val) => acc + val, 0) / data.length; | |
return Math.sqrt(variance); | |
} | |
function calculateSkewness(data) { | |
const mean = calculateMean(data); | |
const median = calculateMedian(data); | |
const stdDev = calculateStandardDeviation(data); | |
return 3 * (mean - median) / stdDev; | |
} | |
function renderResults(data) { | |
const meanPrice = calculateMean(data); | |
const medianPrice = calculateMedian(data); | |
const modeTier = calculateMode(data); | |
const skewness = calculateSkewness(data); | |
const resultsDiv = document.getElementById('results'); | |
resultsDiv.innerHTML = ` | |
<p>Mean Subscription Price: $${meanPrice.toFixed(2)}</p> | |
<p>Median Subscription Price: $${medianPrice.toFixed(2)}</p> | |
<p>Mode Subscription Tier: ${modeTier.join(", ")}</p> | |
<p>Skewness: ${skewness.toFixed(2)}</p> | |
`; | |
if (skewness > 0) { | |
resultsDiv.classList.add('positive-skew'); | |
} | |
} | |
function renderChart(data) { | |
const meanPrice = calculateMean(data); | |
const medianPrice = calculateMedian(data); | |
const margin = {top: 20, right: 30, bottom: 40, left: 40}; | |
const width = 600 - margin.left - margin.right; | |
const height = 400 - margin.top - margin.bottom; | |
const svg = d3.select("#chart").append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", `translate(${margin.left},${margin.top})`); | |
const x = d3.scaleBand() | |
.domain(data.map(d => d.customer_id)) | |
.range([0, width]) | |
.padding(0.1); | |
const y = d3.scaleLinear() | |
.domain([0, d3.max(data, d => d.subscription_price)]) | |
.nice() | |
.range([height, 0]); | |
svg.append("g") | |
.selectAll("rect") | |
.data(data) | |
.enter().append("rect") | |
.attr("x", d => x(d.customer_id)) | |
.attr("y", d => y(d.subscription_price)) | |
.attr("width", x.bandwidth()) | |
.attr("height", d => height - y(d.subscription_price)) | |
.attr("fill", "steelblue"); | |
svg.append("g") | |
.attr("class", "x-axis") | |
.attr("transform", `translate(0,${height})`) | |
.call(d3.axisBottom(x).tickFormat(d => `C${d}`)); | |
svg.append("g") | |
.attr("class", "y-axis") | |
.call(d3.axisLeft(y)); | |
svg.append("line") | |
.attr("x1", 0) | |
.attr("x2", width) | |
.attr("y1", y(meanPrice)) | |
.attr("y2", y(meanPrice)) | |
.attr("stroke", "red") | |
.attr("stroke-dasharray", "4") | |
.attr("stroke-width", 2) | |
.attr("opacity", 0.7); | |
svg.append("text") | |
.attr("x", width - 60) | |
.attr("y", y(meanPrice) - 10) | |
.attr("fill", "red") | |
.text(`Mean: $${meanPrice.toFixed(2)}`); | |
svg.append("line") | |
.attr("x1", 0) | |
.attr("x2", width) | |
.attr("y1", y(medianPrice)) | |
.attr("y2", y(medianPrice)) | |
.attr("stroke", "green") | |
.attr("stroke-dasharray", "4") | |
.attr("stroke-width", 2) | |
.attr("opacity", 0.7); | |
svg.append("text") | |
.attr("x", width - 60) | |
.attr("y", y(medianPrice) - 10) | |
.attr("fill", "green") | |
.text(`Median: $${medianPrice.toFixed(2)}`); | |
} | |
return { | |
renderResults, | |
renderChart | |
}; | |
})(); | |
const subscriptions = [ | |
{customer_id: 1, subscription_price: 30, tier: "Basic"}, | |
{customer_id: 2, subscription_price: 50, tier: "Standard"}, | |
{customer_id: 3, subscription_price: 50, tier: "Standard"}, | |
{customer_id: 4, subscription_price: 80, tier: "Premium"}, | |
{customer_id: 5, subscription_price: 30, tier: "Basic"}, | |
{customer_id: 6, subscription_price: 60, tier: "Standard"}, | |
{customer_id: 7, subscription_price: 90, tier: "Premium"}, | |
{customer_id: 8, subscription_price: 50, tier: "Standard"}, | |
{customer_id: 9, subscription_price: 70, tier: "Premium"}, | |
{customer_id: 10, subscription_price: 40, tier: "Basic"} | |
]; | |
document.addEventListener('DOMContentLoaded', () => { | |
SubscriptionAnalysis.renderResults(subscriptions); | |
SubscriptionAnalysis.renderChart(subscriptions); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment