async function drawLines() {
const dataset = await d3.json("./my_weather_data.json");
const width = 600;
let dimensions = {
width: width,
height: width * 0.6,
margin: {
top: 20,
right: 30,
bottom: 20,
left: 30,
}
};
dimensions.boundedWidth = dimensions.width
- dimensions.margin.left
- dimensions.margin.right;
dimensions.boundedHeight = dimensions.height
- dimensions.margin.top
- dimensions.margin.bottom;
// 3. Draw canvas
const wrapper = d3.select("#wrapper")
.append("svg")
.attr("width", dimensions.width)
.attr("height", dimensions.height);
const bounds = wrapper.append("g")
.style("transform", `translate(${dimensions.margin.left}px,${dimensions.margin.top}px)`);
// init static elements
bounds.append("path")
.attr("class", "line");
bounds.append("g")
.attr("class", "y-axis")
//style("transform", `translateX(${dimensions.margin.left}px)`)
//.append("text")
//.attr("class", "y-axis-label")
//.attr("x", dimensions.boundedWidth / 2)
//.attr("y", dimensions.margin.bottom - 10);
const drawLineChart = metric => {
const dateParser = d3.timeParse("%Y-%m-%d");
//Accessor
const yAccessor = d => d[metric];
const xAccessor = d => dateParser(d.date);
const updateTransition = d3.transition().duration(600);
/*
const xScaler = d3.scaleLinear()
.domain(d3.extent(dataset, metricAccessor))
.range([0, dimensions.boundedWidth])
.nice();
const binsGen = d3.bin()
.domain(xScaler.domain())
.value(metricAccessor)
.thresholds(12);
const bins = binsGen(dataset);
console.log(bins);
*/
const xScaler = d3.scaleTime()
.domain(d3.extent(dataset, xAccessor))
.range([0, dimensions.boundedWidth]);
const yScaler = d3.scaleLinear()
.domain(d3.extent(dataset, yAccessor))
.range([dimensions.boundedHeight, 0]);
const lineGenerator = d3.line()
.x(d => xScaler(xAccessor(d)))
.y(d => yScaler(yAccessor(d)));
let line = bounds.select(".line")
.transition(updateTransition)
.attr("d", lineGenerator(dataset))
.attr("fill", "none")
.attr("stroke", "#af9999")
.attr("stroke-width", 2);
const yAxisGenerator = d3.axisLeft()
.scale(yScaler);
const xAxisGenerator = d3.axisBottom()
.scale(xScaler);
const yAxis = bounds.select(".y-axis")
.transition(updateTransition)
.call(yAxisGenerator);
const xAxis = bounds.append("g")
.call(xAxisGenerator)
.style("transform", `translateY(${dimensions.boundedHeight}px)`);
/*
const oldLine = line.exit();
oldLine.remove();
const newLine = line.enter().append("path")
.attr("class", "line");
line = newLine.merge(line);
*/
/*
let binGroups = bounds.select(".bins").selectAll(".bin").data(bins);
const oldBinGroups = binGroups.exit();
oldBinGroups.selectAll("rect")
.style("fill", "orangered")
.transition(exitTransition)
.attr("y", dimensions.boundedHeight)
.attr('height', 0);
oldBinGroups.selectAll("text")
.transition(exitTransition)
.attr("y", dimensions.boundedHeight);
oldBinGroups.transition(exitTransition).remove();
const newBinGroups = binGroups.enter().append("g")
.attr("class", "bin");
newBinGroups.append("rect");
newBinGroups.append("text");
binGroups = newBinGroups.merge(binGroups);
const barPadding = 1;
const barRect = binGroups.select("rect")
.transition(updateTransition)
.attr("x", d => xScaler(d.x0) + barPadding / 2)
.attr("y", d => yScaler(yAccessor(d)))
.attr("width", d => d3.max([0, xScaler(d.x1) - xScaler(d.x0) - barPadding]))
.attr("height", d => dimensions.boundedHeight - yScaler(yAccessor(d)))
.transition()
.style("fill","cornflowerblue");
const barText = binGroups.select("text")
.transition(updateTransition)
.attr("x", d => xScaler(d.x0) + (xScaler(d.x1) - xScaler(d.x0)) / 2)
.attr("y", d => yScaler(yAccessor(d)) - 5)
.text(d => yAccessor(d) || "");
*/
/*
const mean = d3.mean(dataset, metricAccessor);
console.log(mean);
const meanLine = bounds.selectAll(".mean")
.transition(updateTransition)
.attr("x1", xScaler(mean))
.attr("x2", xScaler(mean))
.attr("y1", -15)
.attr("y2", dimensions.boundedHeight);
*/
/*
const xAxisGen = d3.axisBottom()
.scale(xScaler);
const xAxis = bounds.select("x-axis")
.transition(updateTransition)
.call(xAxisGen)
.style("transform", `translateY(${dimensions.boundedHeight}px)`);
*/
}
const metrics = [
"windSpeed",
"moonPhase",
"dewPoint",
"humidity",
"uvIndex",
"windBearing",
"temperatureMin",
"temperatureMax"
];
let mIndex = 0;
drawLineChart(metrics[mIndex]);
const button = d3.select("body")
.append("button")
.text("Change Metric");
button.node().addEventListener("click", onClick);
function onClick() {
mIndex = (mIndex + 1) % metrics.length;
drawLineChart(metrics[mIndex]);
console.log(mIndex);
};
}
drawLines();
//load data----
async function createApp(){
const dataset= await d3.csv('data.csv')
console.log(dataset)
//create dimensions---
let dimensions={
width: 800,
height:600,
margins: {
left: 50,
right: 20,
top:20,
bottom: 50,
},
};
//bound dimensions
dimensions.boundedwidth=dimensions.width-
dimensions.margins.left-
dimensions.margins.right;
dimensions.boundedheight=dimensions.height-
dimensions.margins.top-
dimensions.margins.bottom;
//Draw canvas----
wrapper=d3.select("#vis")
.append("svg")
.attr("width", dimensions.width)
.attr("height", dimensions.height);
bounds=wrapper.append("g")
.style("transform", `translate(${
dimensions.margins.left
}px, ${
dimensions.margins.top
}px)`);
//create scales------
const xScatterscale= d3.scaleLinear()
.range([0, dimensions.boundedwidth])
.nice()
const yScatterscale= d3.scaleLinear()
.range([dimensions.boundedheight, 0])
.nice()
const xBarscale= d3.scaleBand()
.range([0, dimensions.boundedwidth])
.padding(0.2)
const yBarscale=d3.scaleLinear()
.range([dimensions.boundedheight, 0])
.nice()
//Draw perpherals--axes-------
//create axis generators
const xAxisgeneratorscatter= d3.axisBottom()
.scale(xScatterscale)
.ticks(8)
const yAxisgeneratorscatter= d3.axisLeft()
.scale(yScatterscale)
.ticks(9)
const xAxisgeneratorbar=d3.axisBottom()
.scale(xBarscale)
const yAxisgeneratorbar=d3.axisLeft()
.scale(yBarscale)
//creating a group element which contains all the things related to x-axis like axis and the labels
bounds.append("g")
.attr("class", "x-axis")
.style("transform", `translateY(${
dimensions.boundedheight
}px)`)
.append("text")
.attr("class", "x-axis-label")
.attr("x", dimensions.boundedwidth/2)
.attr("y", dimensions.margins.bottom-10)
.attr("fill", "black")
.style("font-size", "1.4em")
//creating a group element which contains all the things related to y-axis like axis and the labels
bounds.append("g")
.attr("class", "y-axis")
.append("text")
.attr("class", "y-axis-label")
.attr("x", -dimensions.boundedheight/2)
.attr("y", -dimensions.margins.left+10)
.attr("fill", "black")
.style("font-size", "1.4em")
.style("transform", "rotate(-90deg)")
.style("text-anchor", "middle")
//binding data to empty request-----
const requests= bounds.append("g")
.attr("class", "request")
const chartgroups= requests.selectAll(".request")
.data(dataset)
.enter().append("g")
let duration = 750
//const updateTransition = d3.transition().duration(duration)
const updateTransition = (t) => {
return t.duration(duration)
}
var previousChartType = "scatter";
scatterplot();
//create functions to draw data scatter plot----
function scatterplot(){
const xAccessorscatter= d=> +d.risk
const yAccessorscatter= d=> +d.return
xScatterscale.domain([0, d3.max(dataset, xAccessorscatter)+0.05])
yScatterscale.domain([0, d3.max(dataset, yAccessorscatter)+0.02])
const xAxis=bounds.select(".x-axis")
.transition()
.call(updateTransition)
.call(xAxisgeneratorscatter)
const xAxislabel= xAxis.select(".x-axis-label")
.transition()
.call(updateTransition)
.text("Risk")
const yAxis= bounds.select(".y-axis")
.transition()
.call(updateTransition)
.call(yAxisgeneratorscatter)
const yAxislabel= yAxis.select(".y-axis-label")
.transition()
.call(updateTransition)
.text("Return")
const newscattergroup= chartgroups.append("circle")
.attr("cx", d=>xScatterscale(xAccessorscatter(d)))
.attr("cy", dimensions.boundedheight)
.attr("r", 0)
const scattergroups= newscattergroup
.transition().duration(previousChartType === "bar" ? duration : 0)
// .call(updateTransition)
.attr("cx", d=>xScatterscale(xAccessorscatter(d)))
.attr("cy", d=>yScatterscale(yAccessorscatter(d)))
.attr("r", 5)
.attr("fill", "red")
previousChartType = "scatter";
}
//create functions to draw data bar plot----
function plotbar(){
const xAccessorbar = d=> d.id
const yAccessorbar = d=> +d.equity
xBarscale
.domain(dataset.map(xAccessorbar))
yBarscale
.domain([0, d3.max(dataset, yAccessorbar)+0.1])
const xAxis=bounds.select(".x-axis")
.transition()
.call(updateTransition)
.call(xAxisgeneratorbar)
const xAxislabel=xAxis.select(".x-axis-label")
.transition()
.call(updateTransition)
.text("id")
const yAxis=bounds.select(".y-axis")
.transition()
.call(updateTransition)
.call(yAxisgeneratorbar)
const yAxislabel=yAxis.select(".y-axis-label")
.transition()
.call(updateTransition)
.text("Equity")
const newbarsgroups= chartgroups.append("rect")
.attr("x", d=> xBarscale(d.id))
.attr("height", 0)
.attr("y", dimensions.boundedheight)
.attr("width", xBarscale.bandwidth())
const t= newbarsgroups
.transition().duration(previousChartType === "scatter" ? duration : 0)
//.call(updateTransition)
.attr("x", d=> xBarscale(d.id))
.attr("y", d=> yBarscale(d.equity))
.attr("width", xBarscale.bandwidth())
.attr("height", d=>dimensions.boundedheight- yBarscale(yAccessorbar(d)))
.attr("fill", "cornflowerblue")
const barText= chartgroups.filter(yAccessorbar)
.append("text")
.attr("x", d=>xBarscale(d.id)+(xBarscale.bandwidth())/2)
.attr("y", dimensions.boundedheight)
.transition().duration(previousChartType === "scatter" ? duration : 0)
// .call(updateTransition)
.attr("x", d=>xBarscale(d.id)+(xBarscale.bandwidth())/2)
.attr("y", d=>yBarscale(yAccessorbar(d))-5)
.text(yAccessorbar)
.style("text-anchor", "middle")
.attr("fill", "black")
.style("font-size", "12px")
.style("font-family", "sans-serif")
previousChartType = "bar";
}
d3.select("#scatter").on("click", function () {
chartgroups
.selectAll("rect")
.attr("fill-opacity", 1)
.transition()
.duration(duration)
.attr("y", dimensions.boundedheight)
.attr("height", 0)
.attr("fill-opacity", 0)
.remove();
chartgroups
.select("text")
.transition()
.duration(duration)
.attr("fill", "white")
.remove();
scatterplot()
});
d3.select("#bar").on("click", function () {
chartgroups
.selectAll("circle")
.attr("fill-opacity", 1)
.transition()
.duration(duration)
.attr("fill-opacity", 0)
.remove();
plotbar()
});
}
createApp()
async function drawBars() {
// 1. Access data
const dataset = await d3.json("./../../my_weather_data.json");
// 2. Create chart dimensions
const width = 500;
let dimensions = {
width: width,
height: width * 0.6,
margin: {
top: 30,
right: 10,
bottom: 50,
left: 50,
},
};
dimensions.boundedWidth =
dimensions.width - dimensions.margin.left - dimensions.margin.right;
dimensions.boundedHeight =
dimensions.height - dimensions.margin.top - dimensions.margin.bottom;
// 3. Draw canvas
const wrapper = d3
.select("#wrapper")
.append("svg")
.attr("width", dimensions.width)
.attr("height", dimensions.height);
const bounds = wrapper
.append("g")
.style(
"transform",
`translate(${dimensions.margin.left}px, ${dimensions.margin.top}px)`
);
// init static elements
bounds.append("g").attr("class", "bins");
bounds.append("line").attr("class", "mean");
bounds
.append("g")
.attr("class", "x-axis")
.style("transform", `translateY(${dimensions.boundedHeight}px)`)
.append("text")
.attr("class", "x-axis-label")
.attr("x", dimensions.boundedWidth / 2)
.attr("y", dimensions.margin.bottom - 10);
const drawHistogram = (metric) => {
const metricAccessor = (d) => d[metric];
const yAccessor = (d) => d.length;
// 4. Create scales
const xScale = d3
.scaleLinear()
.domain(d3.extent(dataset, metricAccessor))
.range([0, dimensions.boundedWidth])
.nice();
const binsGenerator = d3
.bin()
.domain(xScale.domain())
.value(metricAccessor)
.thresholds(12);
const bins = binsGenerator(dataset);
const yScale = d3
.scaleLinear()
.domain([0, d3.max(bins, yAccessor)])
.range([dimensions.boundedHeight, 0])
.nice();
// 5. Draw data
/* animate the bars when they leaving */
const exitTransition = d3.transition().duration(600);
const updateTransition = exitTransition.transition().duration(600);
/* the animation was out of sync with the labels again!
by doing so we can make a transition on the root document that can be used in multiple places.
*/
/* const updateTransition = d3
.transition()
.duration(600)
.ease(d3.easeBounceIn);
console.log(updateTransition); */
/* expand the _groups array and see that this transition is indeed targeting
* the root <html> element.
*/
const barPadding = 1;
let binGroups = bounds.select(".bins").selectAll(".bin").data(bins);
const oldBinGroups = binGroups.exit();
oldBinGroups
.selectAll("rect")
.style("fill", "orangered")
.transition(exitTransition)
.attr("y", dimensions.boundedHeight)
.attr("height", 0);
oldBinGroups
.selectAll("text")
.transition(exitTransition)
.attr("y", dimensions.boundedHeight);
oldBinGroups.transition(exitTransition).remove();
const newBinGroups = binGroups.enter().append("g").attr("class", "bin");
newBinGroups
.append("rect")
.attr("height", 0)
.attr("x", (d) => xScale(d.x0) + barPadding)
.attr("y", dimensions.boundedHeight)
.attr("width", (d) =>
d3.max([0, xScale(d.x1) - xScale(d.x0) - barPadding])
)
/* we using .style() instead if .attr() because we need to fill the value to be an inline style
* instead of an SVG attribute in order to override the CSS styles in styles.css */
.style("fill", "yellowgreen");
newBinGroups
.append("text")
/* set the label's initial position to prevent them from flying in from the left */
.attr("x", (d) => xScale(d.x0) + (xScale(d.x1) - xScale(d.x0)) / 2)
.attr("y", dimensions.boundedHeight);
// update binGroups to include new points
binGroups = newBinGroups.merge(binGroups);
const barRects = binGroups
.select("rect")
/* we can use the .transition() methode on the d3 selection object
* to transform the selection object into a d3 transition object.
*/
//.transition() /* now we have two additional keys: _id and _name */
/* see also the __proto__ of the transition object,
* which contains d3-specific methods
* and the nested __proto__: Object contains native object methods such as toString().
* we can see also some methods are ingerited form d3 selection object such as call() and each() */
/* slow things down */
//.duration(600)
/* specify a timing func = CSS's transition-timing-func to give the animation some life */
// .ease(d3.easeBounceOut)
/* update: to use the updateTransition instead of creating a new on */
.transition(updateTransition)
.attr("x", (d) => xScale(d.x0) + barPadding)
.attr("y", (d) => yScale(yAccessor(d)))
.attr("height", (d) => dimensions.boundedHeight - yScale(yAccessor(d)))
.attr("width", (d) =>
d3.max([0, xScale(d.x1) - xScale(d.x0) - barPadding])
)
.transition()
.style("fill", "cornflowerblue");
//console.log(barRects);
const barText = binGroups
.select("text")
/* adding another transition to make the text transition with the bars */
//.transition()
//.duration(600)
/* update: to use the updateTransition instead of creating a new on */
.transition(updateTransition)
.attr("x", (d) => xScale(d.x0) + (xScale(d.x1) - xScale(d.x0)) / 2)
.attr("y", (d) => yScale(yAccessor(d)) - 5)
.text((d) => yAccessor(d) || "");
const mean = d3.mean(dataset, metricAccessor);
const meanLine = bounds
.selectAll(".mean")
/* use the updateTransition*/
.transition(updateTransition)
.attr("x1", xScale(mean))
.attr("x2", xScale(mean))
.attr("y1", -20)
.attr("y2", dimensions.boundedHeight);
// 6. Draw peripherals
const xAxisGenerator = d3.axisBottom().scale(xScale);
const xAxis = bounds
.select(".x-axis")
/* update: use the updateTransition*/
.transition(updateTransition)
.call(xAxisGenerator);
const xAxisLabel = xAxis.select(".x-axis-label").text(metric);
};
const metrics = [
"windSpeed",
"moonPhase",
"dewPoint",
"humidity",
"uvIndex",
"windBearing",
"temperatureMin",
"temperatureMax",
];
let selectedMetricIndex = 0;
drawHistogram(metrics[selectedMetricIndex]);
const button = d3.select("body").append("button").text("Change metric");
button.node().addEventListener("click", onClick);
function onClick() {
selectedMetricIndex = (selectedMetricIndex + 1) % metrics.length;
drawHistogram(metrics[selectedMetricIndex]);
}
}
drawBars();
Accelerate Your Automation Test Cycles With LambdaTest
Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.