Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 211 additions & 0 deletions Homework2/Vue-Skeleton/src/views/components/linechart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
<template>
<div id="line"></div>
</template>

<script>
import * as d3 from "d3";
import csvData from "../../../../datasets/CO2_emission.csv"; /* Example of reading in data direct from file*/

export default {
name: 'LineChart',
data() {
return {
}
},
props:{
myLinechartData: Array,
},
mounted(){
this.drawLineFromCsv('#line')
},
methods:{
drawLineFromCsv(id) {
const processData = []
d3.csv(csvData).then((data) => {
//console.log("line chart data");
//console.log(data.length);
//console.log(data);
data.forEach(element => {
let k = Object.keys(element)
//console.log(k)
k.forEach(d => {
if (d.length == 4) {
const temp = {
year: new Date(d),
value: Number(element[d]),
country: element['Country Name'],
}
//console.log(temp)
processData.push(temp)
}
});
});
//console.log(processData);
LineChart(processData, {
x: d => d.year,
y: d => d.value,
z: d => d.country,
yLabel: "CO2 emissions (metric tons per capita)",
color: "steelblue"
})
function LineChart(data, {
x = ([x]) => x, // given d in data, returns the (temporal) x-value
y = ([, y]) => y, // given d in data, returns the (quantitative) y-value
z = () => 1, // given d in data, returns the (categorical) z-value
title, // given d in data, returns the title text
defined, // for gaps in data
curve = d3.curveLinear, // method of interpolation between points
marginTop = 20, // top margin, in pixels
marginRight = 30, // right margin, in pixels
marginBottom = 30, // bottom margin, in pixels
marginLeft = 40, // left margin, in pixels
width = 640, // outer width, in pixels
height = 400, // outer height, in pixels
xType = d3.scaleUtc, // type of x-scale
xDomain, // [xmin, xmax]
xRange = [marginLeft, width - marginRight], // [left, right]
yType = d3.scaleLinear, // type of y-scale
yDomain, // [ymin, ymax]
yRange = [height - marginBottom, marginTop], // [bottom, top]
yFormat, // a format specifier string for the y-axis
yLabel, // a label for the y-axis
zDomain, // array of z-values
color = "currentColor", // stroke color of line, as a constant or a function of *z*
strokeLinecap, // stroke line cap of line
strokeLinejoin, // stroke line join of line
strokeWidth = 1.5, // stroke width of line
strokeOpacity, // stroke opacity of line
mixBlendMode = "multiply", // blend mode of lines
voronoi // show a Voronoi overlay? (for debugging)
} = {}) {
// Compute values.
const X = d3.map(data, x);
const Y = d3.map(data, y);
console.log(Y);
const Z = d3.map(data, z);
const O = d3.map(data, d => d);
if (defined === undefined) defined = (d, i) => !isNaN(X[i]) && !isNaN(Y[i]);
const D = d3.map(data, defined);

// Compute default domains, and unique the z-domain.
if (xDomain === undefined) xDomain = d3.extent(X);
if (yDomain === undefined) yDomain = [0, d3.max(Y, d => typeof d === "string" ? +d : d)];
if (zDomain === undefined) zDomain = Z;
zDomain = new d3.InternSet(zDomain);

// Omit any data not present in the z-domain.
const I = d3.range(X.length).filter(i => zDomain.has(Z[i]));

// Construct scales and axes.
const xScale = xType(xDomain, xRange);
const yScale = yType(yDomain, yRange);
const xAxis = d3.axisBottom(xScale).ticks(width / 80).tickSizeOuter(0);
const yAxis = d3.axisLeft(yScale).ticks(height / 60, yFormat);

// Compute titles.
const T = title === undefined ? Z : title === null ? null : d3.map(data, title);

// Construct a line generator.
const line = d3.line()
.defined(i => D[i])
.curve(curve)
.x(i => xScale(X[i]))
.y(i => yScale(Y[i]));

const svg = d3.select(id).append("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto; height: intrinsic;")
.style("-webkit-tap-highlight-color", "transparent")
.on("pointerenter", pointerentered)
.on("pointermove", pointermoved)
.on("pointerleave", pointerleft)
.on("touchstart", event => event.preventDefault());

// An optional Voronoi display (for fun).
if (voronoi) svg.append("path")
.attr("fill", "none")
.attr("stroke", "#ccc")
.attr("d", d3.Delaunay
.from(I, i => xScale(X[i]), i => yScale(Y[i]))
.voronoi([0, 0, width, height])
.render());

svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(xAxis);

svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(yAxis)
.call(g => g.select(".domain").remove())
.call(voronoi ? () => {} : g => g.selectAll(".tick line").clone()
.attr("x2", width - marginLeft - marginRight)
.attr("stroke-opacity", 0.1))
.call(g => g.append("text")
.attr("x", -marginLeft)
.attr("y", 10)
.attr("fill", "currentColor")
.attr("text-anchor", "start")
.text(yLabel));

const path = svg.append("g")
.attr("fill", "none")
.attr("stroke", typeof color === "string" ? color : null)
.attr("stroke-linecap", strokeLinecap)
.attr("stroke-linejoin", strokeLinejoin)
.attr("stroke-width", strokeWidth)
.attr("stroke-opacity", strokeOpacity)
.selectAll("path")
.data(d3.group(I, i => Z[i]))
.join("path")
.style("mix-blend-mode", mixBlendMode)
.attr("stroke", typeof color === "function" ? ([z]) => color(z) : null)
.attr("d", ([, I]) => line(I));

const dot = svg.append("g")
.attr("display", "none");

dot.append("circle")
.attr("r", 2.5);

dot.append("text")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "middle")
.attr("y", -8);

function pointermoved(event) {
const [xm, ym] = d3.pointer(event);
const i = d3.least(I, i => Math.hypot(xScale(X[i]) - xm, yScale(Y[i]) - ym)); // closest point
path.style("stroke", ([z]) => Z[i] === z ? null : "#ddd").filter(([z]) => Z[i] === z).raise();
dot.attr("transform", `translate(${xScale(X[i])},${yScale(Y[i])})`);
if (T) dot.select("text").text(T[i]);
svg.property("value", O[i]).dispatch("input", {bubbles: true});
}

function pointerentered() {
path.style("mix-blend-mode", null).style("stroke", "#ddd");
dot.attr("display", null);
}

function pointerleft() {
path.style("mix-blend-mode", mixBlendMode).style("stroke", null);
dot.attr("display", "none");
svg.node().value = null;
svg.dispatch("input", {bubbles: true});
}

return Object.assign(svg.node(), {value: null});
}
});
}
}
}
</script>


<style>

</style>
125 changes: 125 additions & 0 deletions Homework2/Vue-Skeleton/src/views/components/piechart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<template>
<div id="pie"></div>
</template>

<script>
import * as d3 from "d3";
import testData from "../../assets/data/test.json"; /* Example of reading in data direct from file*/

export default {
name: 'PieChart',
data() {
return {
name: 'Hello',
someLocalValues: [1, 2, 3, 4, 5],

}
},
props:{
myPiechartData: Array,
},
mounted(){
console.log(testData);
let localData = testData['data'];
this.drawPieChart(localData, "#pie", {
name: d => d.y,
value: d => d.x
}) /* Example of reading data from a json file */
// this.drawBarChart(this.myBarchartData, "#bar")
console.log("Data Passed down as a Prop ", this.myPiechartData)
},
methods: {
drawPieChart(data, id, {
name = ([x]) => x, // given d in data, returns the (ordinal) label
value = ([, y]) => y, // given d in data, returns the (quantitative) value
title, // given d in data, returns the title text
width = 640, // outer width, in pixels
height = 400, // outer height, in pixels
innerRadius = 0, // inner radius of pie, in pixels (non-zero for donut)
outerRadius = Math.min(width, height) / 2, // outer radius of pie, in pixels
labelRadius = (innerRadius * 0.2 + outerRadius * 0.8), // center radius of labels
format = ",", // a format specifier for values (in the label)
names, // array of names (the domain of the color scale)
colors, // array of colors for names
stroke = innerRadius > 0 ? "none" : "white", // stroke separating widths
strokeWidth = 1, // width of stroke separating wedges
strokeLinejoin = "round", // line join of stroke separating wedges
padAngle = stroke === "none" ? 1 / outerRadius : 0, // angular separation between wedges
} = {}) {
const N = d3.map(data, name);
const V = d3.map(data, value);
const I = d3.range(N.length).filter(i => !isNaN(V[i]));

// Unique the names.
if (names === undefined) names = N;
names = new d3.InternSet(names);

// Chose a default color scheme based on cardinality.
if (colors === undefined) colors = d3.schemeSpectral[names.size];
if (colors === undefined) colors = d3.quantize(t => d3.interpolateSpectral(t * 0.8 + 0.1), names.size);

// Construct scales.
const color = d3.scaleOrdinal(names, colors);

// Compute titles.
if (title === undefined) {
const formatValue = d3.format(format);
title = i => `${N[i]}\n${formatValue(V[i])}`;
} else {
const O = d3.map(data, d => d);
const T = title;
title = i => T(O[i], i, data);
}

// Construct arcs.
const arcs = d3.pie().padAngle(padAngle).sort(null).value(i => V[i])(I);
const arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius);
const arcLabel = d3.arc().innerRadius(labelRadius).outerRadius(labelRadius);

const svg = d3.select(id).append("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [-width / 2, -height / 2, width, height])
.attr("style", "max-width: 100%; height: auto; height: intrinsic;");

svg.append("g")
.attr("stroke", stroke)
.attr("stroke-width", strokeWidth)
.attr("stroke-linejoin", strokeLinejoin)
.selectAll("path")
.data(arcs)
.join("path")
.attr("fill", d => color(N[d.data]))
.attr("d", arc)
.append("title")
.text(d => title(d.data));

svg.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "middle")
.selectAll("text")
.data(arcs)
.join("text")
.attr("transform", d => `translate(${arcLabel.centroid(d)})`)
.selectAll("tspan")
.data(d => {
const lines = `${title(d.data)}`.split(/\n/);
return (d.endAngle - d.startAngle) > 0.25 ? lines : lines.slice(0, 1);
})
.join("tspan")
.attr("x", 0)
.attr("y", (_, i) => `${i * 1.1}em`)
.attr("font-weight", (_, i) => i ? null : "bold")
.text(d => d);

return Object.assign(svg.node(), {scales: {color}});
}
}
}
</script>


<style>

</style>
48 changes: 48 additions & 0 deletions Homework2/yihchiu/Vue-Skeleton/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# VUE 3.0 Skeleton
This is is a tempalate for working in Vue.js.
Vue 3.0 sits between react and basic javascript depending on the developers comfort level.
For this class stick with **Options API** rather than **Composition**.
If Vue is too weird, feel free to use the simpler template.
We offer Vue, since it is a modern framework that companies use so it could be useful for you if one of your projects in this class could make use of it.

OPTION API DOCUMENTATION [link](https://vuejs.org/api/#options-api)

## Note
You are not required to use Vue.js to solve HW2 and 3.
However, if you don't want to use it I would recommend using the Simple-Skeleton template.
If you have personal experience with another framework and would prefer to use that please go ahead, just let me know how to compile and run that.


# Install Dependencies
Assuming you have node.js installed. (If not go do that :) )
Install [Node](https://nodejs.org/en/).

Install from the package.json via terminal.
`npm i`

To install additional packages based on your needs
`npm install <package-name>`

## Run application
`npm start`



## Some of the libraries attached
For UI components this template comes with [Ant Design](https://antdv.com/)
For icons etc. [Font-Awesome](https://fontawesome.com/)
Animations [Animate css](https://animate.style/)

D3 is included as well.

For fetching data from an API [Axios](https://axios-http.com/docs/intro)

# Files you have to care about
Most of these files you can ignore.
The files under `src/` are your concern.
The root script file for VUE will be `index.ts` which is the initial typescript/javascript file that instatinate our single page application.
The root file for all **development** needs with be `App.vue`

You will be adding to and editing files under the **Views** Directory.
Within the pages directory you really only need one page **Pages/Home.vue**
For components you may have several based on your design feel free to add what makes sense to you under **Components**
5 changes: 5 additions & 0 deletions Homework2/yihchiu/Vue-Skeleton/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"include": [
"./src/**/*"
]
}
Loading