Published
Edited
Apr 3, 2020
Insert cell
Insert cell
Insert cell
// Try to change the value of "radius" and hit "shitf+enter". You will see the "area" cell changes automatically

radius = 3
Insert cell
// The variable "area" depends on "radius", its value will be updated whenever "radius" changes

area = Math.PI * Math.pow(radius, 2)
Insert cell
Insert cell
Insert cell
{
let length = 3
return length * length
}
Insert cell
Insert cell
Insert cell
// Declare an array with square brackets "[]"

visualChannels = ['position', 'length', 'angle', 'area', 'color', 'curvature']
Insert cell
// Get the length of an array

visualChannels.length
Insert cell
// Access an item in an array

'Most effective channel: ' + visualChannels[0]
Insert cell
Insert cell
// Concatenate two arrays

moreVisualChannels = visualChannels.concat(['color hue', 'color saturation', 'color luminance'])
Insert cell
// To sort an array, we use "sort"

moreVisualChannels.sort()
Insert cell
/******************************************************************************
* TODO: *
* Try to create two lists of colors, then concatenate them, and sort in *
* alphabetical order! *
* The two lists are: *
* red, green, blue *
* cyan, magenta, yellow, black *
******************************************************************************/
{
let colors = ['red', 'green', 'blue']
let color2 = ['cyan', 'magenta', 'yellow', 'black']
let moreColors = colors.concat(color2)
return moreColors.sort()
}


/******************************************************************************
* END OF YOUR CODE *
******************************************************************************/
Insert cell
Insert cell
Insert cell
// Declare an object

typesOfData = ({
ordered: [1, 2, 3, 4, 5],
categorical: ['strawberry', 'apple', 'orange']
})
Insert cell
// To access an attribute of an object, we simply use "."

typesOfData.categorical
Insert cell
Insert cell
Insert cell
// To modify an attribute of an object, we simply assign a value to it

{
let typesOfData = {
ordered: [1, 2, 3, 4, 5],
categorical: ['strawberry', 'apple', 'orange']
}
typesOfData.categorical = ['strawberry', 'apple', 'orange', 'banana']
return typesOfData.categorical
}
Insert cell
/******************************************************************************
* TODO: *
* Try to modify the values of the "ordered" attribute to 1, 10, 100, 1000! *
******************************************************************************/
{
typesOfData.ordered=[1, 10, 100, 1000]
return typesOfData.ordered
}

/******************************************************************************
* END OF YOUR CODE *
******************************************************************************/
Insert cell
Insert cell
// If statement

{
let color = 'cyan'
let hex = ''

if (color === 'cyan') {
hex = rgb2hex(0, 255, 255)
} else if (color === 'magenta') {
hex = rgb2hex(255, 0, 255)
} else if (color === 'yellow') {
hex = rgb2hex(255, 255, 0)
} else {
hex = rgb2hex(255, 255, 255)
}
return hex
}
Insert cell
// Loop through items in an array

{
let rgb = ['red', 'green', 'blue']
let rgbValues = [[255, 0, 0], [0, 255, 0], [0, 0, 255]]
let rgbHex = []
for (let i = 0; i < rgb.length; i++) {
let [r, g, b] = rgbValues[i]
// append an item to the array
rgbHex.push(rgb2hex(r, g, b))
}
return rgbHex
}
Insert cell
/******************************************************************************
* TODO: *
* Try to find the hex codes of cyan, magenta, yellow and black! *
******************************************************************************/
{
let color = ['cyan', 'magenta', 'yellow', 'black']
let hex = ' '
for(let i = 0; i< color.length;i++){
if (color[i] === 'cyan') {
hex = color[i] + ":" +rgb2hex(0, 255, 255)+"\n"
} else if (color[i] === 'magenta') {
hex += color[i] + ":" +rgb2hex(255, 0, 255)+"\n"
} else if (color[i] === 'yellow') {
hex += color[i] + ":" +rgb2hex(255, 255, 0)+"\n"
} else {
hex += color[i] + ":" +rgb2hex(255, 255, 255)+"\n"
}
}
return hex
}

/******************************************************************************
* END OF YOUR CODE *
******************************************************************************/
Insert cell
Insert cell
// Declare a function with keyword "function"

function int2hex (n) {
return n >= 16 ? n.toString(16) : '0' + n.toString(16)
}
Insert cell
// Calling the "int2hex" function

int2hex(255)
Insert cell
// Alternatively, we can declare a function using arrow

rgb2hex = (r = 0, g = 0, b = 0) => {
return '#' + int2hex(r) + int2hex(g) + int2hex(b)
}
Insert cell
rgb2hex(64, 224, 208)
Insert cell
// Converting color name to hex code

function rgbColor2hex (color) {
if (color === 'red') {
return rgb2hex(255, 0, 0)
} else if (color === 'green') {
return rgb2hex(0, 255, 0)
} else {
return rgb2hex(0, 0, 255)
}
}
Insert cell
rgbColor2hex('red')
Insert cell
/******************************************************************************
* TODO: *
* Try to use arrow function expression to create a function that takes color *
* name as input and return hex code for cyan, magenta, yellow and black! *
******************************************************************************/
cmyk2hex=(color)=>{
let hex=''
if (color === 'cyan') {
hex = rgb2hex(0, 255, 255)
} else if (color === 'magenta') {
hex = rgb2hex(255, 0, 255)
} else if (color === 'yellow') {
hex = rgb2hex(255, 255, 0)
} else {
hex = rgb2hex(255, 255, 255)
}
return hex
}
/******************************************************************************
* END OF YOUR CODE *
******************************************************************************/
Insert cell
Insert cell
// Built-in array function "map"
// It calls the "rgbColor2hex" function for each item in the array

['red', 'green', 'blue'].map(rgbColor2hex)
Insert cell
/******************************************************************************
* TODO: *
* Try to map the "cyan", "magenta", "yellow", "black" over the function you *
* have created above to get their hex codes! *
******************************************************************************/
["cyan", "magenta", "yellow", "black" ].map(cmyk2hex)


/******************************************************************************
* END OF YOUR CODE *
******************************************************************************/
Insert cell
Insert cell
function getDataFromServer (color, callback) {
setTimeout(function () {
callback(rgbColor2hex(color))
}, 5000)
}
Insert cell
// Run this cell, the value of "colorInHex" will be updated in 5 seconds

mutable colorInHex = 'Waiting for server...'
Insert cell
Insert cell
getDataFromServer('red', function (hex) {
mutable colorInHex = `The hex code of "Red" is ${hex}. Run the cell below to try again!`
})
Insert cell
Insert cell
Insert cell
// Get the current date and time, in "ticks"

Date.now()
Insert cell
// Make "ticks" human readable

new Date(Date.now())
Insert cell
// Access a specific part of a "date", there are also hour, minute, second and
// millisecond accessible. Be awared that we need to add 1 to the value returned
// from getMonth because it counts from 0, which means January.

{
let now = new Date(Date.now())
// A string encapsulated with backtick "`" is a template string, it will
// evaluate the expression inside the placeholder "${}"
return `Year: ${now.getFullYear()} Month: ${now.getMonth() + 1} Day: ${now.getDate()}`
}
Insert cell
// Create a date object with a specific date. Be reminded, month counts from 0

new Date(2019, 4, 3)
Insert cell
// Javascript does not provide arithematic manipulation for datetime, we need to
// get the value, add/subtract then set the value

{
let oldDate = new Date(2019, 4, 3)
oldDate.setDate(oldDate.getDate() + 2)
return oldDate
}
Insert cell
Insert cell
Insert cell
Insert cell
// Import d3, "@5" specifies the version we want

d3 = require('d3@5')
Insert cell
// Import vega-embed

vegaEmbed = require("vega-embed@6")
Insert cell
// Import vega-lite-api from another Observable notebook (https://observablehq.com/@vega/vega-lite-api)

import { vl } from '@vega/vega-lite-api'
Insert cell
Insert cell
// Load pokemon_tsne.csv from the tutorial repository on GitHub

pokemonBaseStats = d3.csv('https://raw.githubusercontent.com/leoyuholo/learning-vis-tools/master/tutorial06/lab6/pokemon_tsne.csv')
Insert cell
Insert cell
/*
* vega-lite-api makes it intiutive to plot with vega-lite
*
* The following is actually a single Javascript statement, it uses a
* common pattern in Javascript called "method chaining".
*
* "vl.markPoint()" returns an object that with many methods,
* including what we are about to use, "width", "height", "title", etc.
*
* Each of these methods returns an object that also has these methods,
* but with a different internal state.
* For example, before calling "height", the internal state is:
* { width: 500 }
* After calling ".height(400)", the method returns an object with state
* { width: 500, height: 400}
*
* The most important method call is "encode(...)". It takes an unordered list
* of arguments that specifies the visual encodings. In our case, x and y
* encode the dimension reduction result of t-sne and color encodes whether
* the pokemon "is_legendary". Tooltip can also be specified as an encoding
* channel. Notice that there is a data type specifier in the "field" method,
* "fieldQ()" means quantitative data and "fieldN" means nominal data.
*
* And after we called it with all the methods we want, "title", "width",
* "height" and "encode", we call the "render" method, which returns a plot for
* Observable notebook to render.
*/

vl.markPoint()
.title('Pokemon base stats t-sne')
.width(500)
.height(400)
.data(pokemonBaseStats)
.encode(
vl.x().fieldQ('x'),
vl.y().fieldQ('y'),
vl.color().fieldN('is_legendary'),
vl.tooltip(['name', 'hp', 'speed', 'attack', 'defense', 'sp_attack', 'sp_defense', 'is_legendary'])
).render()
Insert cell
/******************************************************************************
* TODO: *
* Try to plot other attributes of Pokemons with vega-lite-api, and find the *
* trend! *
* For example, change the color channel to "attack"! Don't forget to change *
* the data type as well! It is "Q" for quantitative, "O" for ordinal, *
* "N" for nominal and "T" for temporal. *
******************************************************************************/
vl.markPoint()
.width(500)
.height(400)
.data(pokemonBaseStats)
.encode(
vl.x().fieldQ('x'),
vl.y().fieldQ('y'),
vl.color().fieldQ('attack'),
vl.tooltip(['name', 'hp', 'speed', 'attack', 'defense', 'sp_attack', 'sp_defense', 'is_legendary'])
).render()


/******************************************************************************
* END OF YOUR CODE *
******************************************************************************/
Insert cell
// This is the Vega-Lite equivalent to the plot we made above
// It takes a Javascript object, with all the specification of a plot,
// and returns the exact same visualization.

vegaEmbed({
data: { values: pokemonBaseStats },
width: 500,
height: 400,
title: 'Pokemon base stats t-sne',
mark: 'point',
encoding: {
x: { field: 'x' },
y: { field: 'y' },
color: { field: 'is_legendary' },
tooltip: [
{ field: 'name' },
{ field: 'hp' },
{ field: 'speed' },
{ field: 'attack' },
{ field: 'defense' },
{ field: 'sp_attack' },
{ field: 'sp_defense' },
{ field: 'is_legendary' }
]
}
})
Insert cell
/******************************************************************************
* TODO: *
* Try to plot other attributes of Pokemons with vega-lite! *
* Most of the time, the data type will be inferred automatically, if it does *
* not, you may specify it alongside the field, for example: *
* color: { field: 'attack', type: 'q' } *
******************************************************************************/
vegaEmbed({
data: { values: pokemonBaseStats },
width: 500,
height: 400,
title: 'Pokemon base stats t-sne',
mark: 'point',
encoding: {
x: { field: 'x' },
y: { field: 'y' },
color: { field: 'capture_rate', type: 'q' },
tooltip: [
{ field: 'name' },
{ field: 'hp' },
{ field: 'speed' },
{ field: 'attack' },
{ field: 'defense' },
{ field: 'sp_attack' },
{ field: 'sp_defense' },
{ field: 'capture_rate' },
{ field: 'is_legendary' }
]
}
})


/******************************************************************************
* END OF YOUR CODE *
******************************************************************************/
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more