Public
Edited
Jul 11, 2023
4 forks
21 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
seattleWeatherTyped = d3.csv("https://raw.githubusercontent.com/vega/vega-datasets/next/data/seattle-weather.csv", d3.autoType)
Insert cell
Insert cell
vl.markBar()
.data(seattleWeatherTyped)
.title("Histogram of Daily Max Temperatures in Seattle (2012-2015)")
.encode(
vl.x().fieldQ('temp_max').bin(true),
vl.y().aggregate("count").title("Num of Days")
)
.render()
Insert cell
Insert cell
{
return vl.markBar({color: 'darkblue'}, {opacity:0.7}, {stroke: 'white'}, {strokeWidth:2})
.data(seattleWeatherTyped)
.title("Histogram of Daily Max Temperatures in Seattle (2012-2015)")
.encode(
vl.x().fieldQ('temp_max').bin(true),
vl.y().aggregate("count").title("Num of Days"),
)
.render()
}
Insert cell
Insert cell
{
// Set the Vega-Lite parameter.
const barColorParam = vl.param("bar_color") // name the param 'bar_color'
.value('lightblue'); // set the param value to 'lightblue', try manually changing the color here

return vl.markBar({color: {'expr': 'bar_color'}}) // reference the param using expr
.data(seattleWeatherTyped)
.title("Histogram of Daily Max Temperatures in Seattle (2012-2015)")
.params(barColorParam) // add the parameters for this mark
.encode(
vl.x().fieldQ('temp_max').bin(true),
vl.y().aggregate("count").title("Num of Days"),
)
.render()
}
Insert cell
Insert cell
{
const barColor = 'lightblue'; // simple JavaScript const for the bar color

return vl.markBar({color: barColor}) // set the color to the JavaScript const
.data(seattleWeatherTyped)
.title("Histogram of Daily Max Temperatures in Seattle (2012-2015)")
.encode(
vl.x().fieldQ('temp_max').bin(true),
vl.y().aggregate("count").title("Num of Days"),
)
.render()
}
Insert cell
Insert cell
{
const param = vl.param("bar_color") // name the param 'bar_color'
.value('lightblue') // set initial value to 'lightblue'
.bind(vl.menu(['lightblue', 'violet', 'peachpuff'])); // add dynamic menu with CSS color names

return vl.markBar({color: {'expr': 'bar_color'}}) // reference the binded param
.data(seattleWeatherTyped)
.title("Histogram of Daily Max Temperatures in Seattle (2012-2015)")
.params(param) // add the parameters for this mark
.encode(
vl.x().fieldQ('temp_max').bin(true),
vl.y().aggregate("count").title("Num of Days"),
)
.render()
}
Insert cell
Insert cell
{
const barColorParam = vl.param("bar_color") // name the param 'bar_color'
.value('lightblue') // initial value
.bind(vl.menu(['lightblue', 'violet', 'peachpuff']).name('Bar Color: ')); // add dynamic menu with CSS color names
const cornerRadiusParam = vl.param("bar_corner_radius")
.value(10) // initial value
.bind(vl.slider(0, 20, 1).name('Corner radius: ')) // add slider with min, max, step

return vl.markBar({color: {expr: 'bar_color'},
cornerRadius: {expr: 'bar_corner_radius'}})
.data(seattleWeatherTyped)
.title("Histogram of Daily Max Temperatures in Seattle (2012-2015)")
.params(barColorParam, cornerRadiusParam)
.encode(
vl.x().fieldQ('temp_max').bin(true),
vl.y().aggregate("count").title("Num of Days"),
)
.render()
}
Insert cell
Insert cell
vl.markPoint()
.data(seattleWeatherTyped)
.title("Seattle Daily Max Temperatures (2012-2015)")
.encode(
vl.x().fieldT("date").title('Day'),
vl.y().fieldQ('temp_max').title('Max Temp'),
vl.color().fieldQ('temp_max').scale({domain: [0, 30]}).title('Max Temp')
)
.render();
Insert cell
Insert cell
vl.markPoint()
.data(seattleWeatherTyped)
.title("Seattle Daily Max Temperatures (2012-2015)")
.transform(
// In Vega-Lite, datum refers to the current data point when
// iterating through all data points in the dataset.
// In this case, the filter expression of 'datum.temp_max > 20'
// retains the datapoint if it is greater than 20 C
vl.filter('datum.temp_max > 20') // keep all data with temp_max > 20° C
)
.encode(
vl.x().fieldT("date").title('Day'),
vl.y().fieldQ('temp_max').title('Max Temp'),
vl.color().fieldQ('temp_max').scale({domain: [0, 30]}).title('Max Temp')
)
.render();
Insert cell
Insert cell
{
// Add in an interactive slider to filter the data
const maxTempParam = vl.param("max_temp_threshold")
.value(0) // initial value
.bind(vl.slider(-5, 35, 1).name('Filter temps: ')) // add slider with min, max, step
return vl.markPoint()
.data(seattleWeatherTyped)
.title("Seattle Daily Max Temperatures (2012-2015)")
.params(maxTempParam) // add bounded parameter here
.transform(
// Check each data point (datum refers to current point in an iteration of all points)
// If that point is greater than the currently selected slider temp, return true (i.e., keep it).
// Otherwise, discard
vl.filter('datum.temp_max > max_temp_threshold') // filter now checks bounded parameter
)
.encode(
vl.x().fieldT("date").title('Day'),
vl.y().fieldQ('temp_max').title('Max Temp'),
vl.color().fieldQ('temp_max').scale({domain: [0, 30]}).title('Max Temp')
)
.render();
}
Insert cell
Insert cell
filterTempsExample = {
// Add in an interactive slider to filter the data
const maxTempParam = vl.param("max_temp_threshold")
.value(0) // initial value
.bind(vl.slider(-5, 35, 1).name('Filter temps: ')) // add slider with min, max, step
return vl.markPoint()
.data(seattleWeatherTyped)
.title("Seattle Daily Max Temperatures (2012-2015)")
.params(maxTempParam) // add bounded parameter here
.transform(
// Check each data point (datum refers to current point in an iteration of all points)
// If that point is greater than the currently selected slider temp, return true (i.e., keep it).
// Otherwise, discard
vl.filter('datum.temp_max > max_temp_threshold') // filter now checks bounded parameter
)
.encode(
vl.x().fieldT("date")
.title('Day')
.scale({domain: ["2012/01/01", "2016/01/01"]}), // make x-axis scale fixed
vl.y().fieldQ('temp_max')
.title('Max Temp')
.scale({domain: [-5, 40]}), // make y-axis scale fixed
vl.color().fieldQ('temp_max')
.title('Max Temp')
.scale({domain: [0, 30]}) // make color scale fixed
)
.render();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const selectedPoint = vl.selectPoint('selected_point') // create our selection param
.on('click') // mouse click for selection ('click' is default but specifying for clarity)
.nearest(true) // select nearest point to the click (helpful because the points are small)
.clear('dblclick'); // double click to clear selection

return vl.markCircle()
.data(seattleWeatherTyped)
.params(selectedPoint) // add in the selection param
.transform(
vl.filter(selectedPoint) // filter out all but the selected point
)
.title({text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Click to select a point | Double click to deselect"})
.encode(
vl.x().fieldT("date").scale({domain: ["2012/01/01", "2016/01/01"]}), // make x-axis scale fixed
vl.y().fieldQ('temp_max').scale({domain: [-5, 40]}), // make y-axis scale fixed
vl.color().fieldQ('temp_max').scale({domain: [0, 30]}), // make color scale fixed
).render();
}
Insert cell
Insert cell
{
const selectedPoint = vl.selectPoint('selected_point')
.fields('temp_max') // grab the 'temp_max' field of the selected point
.nearest(true)
.toggle(false);

return vl.markCircle()
.data(seattleWeatherTyped)
.params(selectedPoint)
.transform(
// This filter is in two parts—if either conditional is true, we keep the point in
// 1. Check to see if a point is selected, if not, return true (i.e., keep the point!)
// 2. Check to see if the current datum.temp_max is greater than or equal to
// the selected point. If so, return true (i.e., keep the point). Remember,
// datum is Vega-Lite's special keyword for the current data value when iterating
// through the list of all values in the dataset for the visualization
vl.filter('!selected_point.temp_max || datum.temp_max >= selected_point.temp_max')
)
.title({text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Click to select a point | Double click to deselect"})
.encode(
vl.x().fieldT("date").scale({domain: ["2012/01/01", "2016/01/01"]}), // make x-axis scale fixed
vl.y().fieldQ('temp_max').scale({domain: [-5, 40]}), // make y-axis scale fixed
vl.color().fieldQ('temp_max').scale({domain: [0, 30]}) // make color scale fixed
).render();
}
Insert cell
Insert cell
{
const selectedPoint = vl.selectPoint('selected_point')
.on('click') // mouse click for selection ('click' is default but specifying for clarity)
.nearest(true) // select nearest point to the click (helpful because the points are small)
.clear('dblclick'); // double click to clear selection

// Create the scatter plot (same as before)
const scatterPlot = vl.markCircle()
.data(seattleWeatherTyped)
.params(selectedPoint)
.transform(
vl.filter(selectedPoint) // filter out all but the selected point
)
.title({text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Click to select a point | Double click to deselect"})
.encode(
vl.x().fieldT("date").scale({domain: ["2012/01/01", "2016/01/01"]}), // make x-axis scale fixed
vl.y().fieldQ('temp_max').scale({domain: [-5, 40]}), // make y-axis scale fixed
vl.color().fieldQ('temp_max').scale({domain: [0, 30]}), // make color scale fixed
);

// Create the text layer, which is only shown when a selection is made
const text = vl.markText({ dx: 15 }) // dx to move text position a bit to the right
.data(seattleWeatherTyped)
.transform(
vl.filter(selectedPoint.empty(false)) // show text for selection but only if a selection exists
)
.encode(
vl.x().fieldT("date"),
vl.y().fieldQ("temp_max"),
vl.text().fieldQ("temp_max")
);

return vl.layer(scatterPlot, text).render();
}
Insert cell
Insert cell
Insert cell
randWeatherDay = seattleWeatherTyped[Math.floor(Math.random()*seattleWeatherTyped.length)]
Insert cell
{
const selectedPoint = vl.selectPoint('selected_point'); // just use defaults

const scatterPlot = vl
.markCircle()
.data(seattleWeatherTyped)
.params(selectedPoint)
.title({text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Click to select a point | Click elsewhere to deselect"})
.encode(
vl.x().fieldT("date"),
vl.y().fieldQ("temp_max"),
vl.color().if(selectedPoint, vl.fieldQ('temp_max')).value("grey"), // if selected, use default color, otherwise grey
vl.opacity().if(selectedPoint, vl.value(0.7)).value(0.1) // if selected, use opacity 0.7, otherwise 0.1
);

// Create the text layer, which is only shown when a selection is made
const text = vl.markText({ dx: 15 })
.data(seattleWeatherTyped)
.transform(
vl.filter(selectedPoint.empty(false)) // show text for selection but only if a selection exists
)
.encode(
vl.x().fieldT("date"),
vl.y().fieldQ("temp_max"),
vl.text().fieldQ("temp_max")
);

return vl.layer(scatterPlot, text).render();
}
Insert cell
Insert cell
{
const selectedPoint = vl.selectPoint('selected_point')
.on("mouseover")
.nearest(true); // select closest point

const scatterPlot = vl.markCircle()
.params(selectedPoint)
.title({text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Mouseover to select a point | Double click to deselect"})
.encode(
vl.x().fieldT("date"), vl.y().fieldQ("temp_max"),
vl.color().if(selectedPoint, vl.fieldQ('temp_max')).value("grey"), // if pt selected, use default color, otherwise grey
vl.opacity().if(selectedPoint, vl.value(0.7)).value(0.1) // if point selected, use opacity 0.7, otherwise 0.1
);

// Create the text layer, which is only shown when a selection is made
const text = vl.markText({ dx: 15 })
.transform(vl.filter(selectedPoint.empty(false)))
.encode(vl.x().fieldT("date"), vl.y().fieldQ("temp_max"), vl.text().fieldQ("temp_max")
);

return vl
.data(seattleWeatherTyped)
.layer(scatterPlot, text).render();
}
Insert cell
Insert cell
{
const hoverSelector = vl.selectPoint()
.on('mouseover') // select on mouseover
.toggle(false) // do not toggle on shift-hover
.nearest(true); // select the nearest mouse cursor

const clickSelector = vl.selectPoint()
.on('click') // select on click
.toggle(true); // allow for multi-select (on by default) with shift-click

// Use an OR operator on clicking or selecting
const hoverOrClickSelector = vl.or(
clickSelector.empty(false), // If false, empty predicate will not select all values
hoverSelector.empty(false) // If false, empty predicate will not select all values
);

// Create the scatterplot
const scatterPlot = vl
.markCircle()
.title({text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Mouseover to view value, click to select, shift-click to multi-select, double click to clear"})
.encode(
vl.x().fieldT("date").title("Date"),
vl.y().fieldQ("temp_max").title("Max Temp C°"),
vl.color().if(hoverOrClickSelector, vl.fieldQ('temp_max')).value('gray'),
vl.opacity().if(hoverOrClickSelector, vl.value(1)).value(0.2)
);

// shared base for new layers but filtered
const base = scatterPlot.transform(
vl.filter(hoverOrClickSelector)
);

// mark properties for new layers
const halo = {size: 100, stroke: 'firebrick', strokeWidth: 1};
const label = {dx: 5, dy: -8, align: 'left', size: 14};
const black = {stroke: 'black', strokeWidth: 0.5}
const white = {stroke: 'white', strokeWidth: 2};

return vl.data(seattleWeatherTyped)
.layer(
scatterPlot.params(hoverSelector, clickSelector),
base.markPoint(halo),
base.markText(label, white).encode(vl.text().fieldQ('temp_max')), // backing white text
base.markText(label, black).encode(vl.text().fieldQ('temp_max')) // black text label
).render();
}
Insert cell
Insert cell
weatherColors = ["#aec7e8", "#c7c7c7", "#1f77b4","#9467bd", "#e7ba52"];
Insert cell
Insert cell
weatherTypes = uniqueValid(seattleWeatherTyped, d => d.weather, true);
Insert cell
Insert cell
{
const weatherSelector = vl.selectPoint()
.fields('weather') // select the 'weather' field
.nearest(true); // select nearest point to click
return vl.markCircle()
.data(seattleWeatherTyped)
.params(weatherSelector)
.title({text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Click to select weather category | Double click to reset"})
.encode(
vl.x().fieldT("date"),
vl.y().fieldQ('temp_max'),
vl.color().fieldN('weather').scale({range: weatherColors}),
vl.opacity().if(weatherSelector, vl.value(0.7)).value(0.1) // conditional encoding of opacity
)
.render();
}
Insert cell
Insert cell
{
const weatherSelector = vl.selectPoint()
.fields('weather') // select the 'weather' field
.nearest(true) // select nearest point to click
.on('click') // click to select a point
.clear('dblclick') // double click to clear
.bind('legend'); // also bind to the legend
return vl.markCircle()
.data(seattleWeatherTyped)
.params(weatherSelector)
.title({text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Click on point or legend to select a weather category | Double click to reset"})
.encode(
vl.x().fieldT("date"),
vl.y().fieldQ('temp_max'),
vl.color().fieldN('weather').scale({range: weatherColors}),
vl.opacity().if(weatherSelector, vl.value(0.7)).value(0.1) // conditional encoding of opacity
)
.render();
}
Insert cell
Insert cell
{
const weatherSelector = vl.selectPoint('Select')
.fields('weather')
.nearest(true) // select nearest point to click
.on('click') // click to select a point
.clear('dblclick') // double click to clear
.bind({weather: vl.menu(weatherTypes).name("Weather: ")});
return vl.markCircle()
.data(seattleWeatherTyped)
.params(weatherSelector)
.title({
text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Select weather type in drop-down | Double click on plot to clear the selection"})
.encode(
vl.x().fieldT("date"),
vl.y().fieldQ('temp_max'),
vl.color().fieldN('weather').scale({range: weatherColors}),
vl.opacity().if(weatherSelector, vl.value(0.7)).value(0.1)
)
.render();
}
Insert cell
Insert cell
{
const weatherSelection = vl.selectPoint()
.fields('weather')
.nearest(true) // select nearest point to click
.on('click') // click to select a point
.clear('dblclick') // double click to clear
.bind('legend');
const precipParams = vl.param('precip_threshold')
.value(0)
.bind(vl.slider(0, 40, 0.1).name('precipitation: '));
return vl.markCircle()
.data(seattleWeatherTyped)
.params(weatherSelection, precipParams)
.title({
text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Select weather via clicks & filter precipitation via slider | Double click to clear weather"})
.encode(
vl.x().fieldT('date'), // fieldT is shorthand for temporal data type
vl.y().fieldQ('temp_max'),
vl.color().fieldN('weather').scale({range: weatherColors}),
vl.opacity().if(vl.and(weatherSelection, "datum.precipitation >= precip_threshold"), vl.value(0.7)).value(0.1),
vl.size().fieldQ('precipitation').bin(true)
)
.render()
}
Insert cell
Insert cell
{
const weatherSelection = vl.selectPoint()
.fields('weather')
.nearest(true) // select nearest point to click
.on('click') // click to select a point
.clear('dblclick') // double click to clear
.bind({weather: vl.menu(weatherTypes).name("Weather: ")});
const precipParams = vl.param('threshold')
.value(0)
.bind(vl.slider(0, 40, 0.1).name('precipitation: '));
return vl.markCircle()
.data(seattleWeatherTyped)
.params(weatherSelection, precipParams)
.title({
text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Select weather via clicks or dropdown & filter precipitation via slider | Double click to clear weather"})
.encode(
vl.x().fieldT('date'), // fieldT is shorthand for temporal data type
vl.y().fieldQ('temp_max'),
vl.color().fieldN('weather').scale({range: weatherColors}),
vl.opacity().if(vl.and(weatherSelection, "datum.precipitation >= threshold"), vl.value(0.7)).value(0.1),
vl.size().fieldQ('precipitation').bin(true)
)
.render()
}
Insert cell
Insert cell
{
const weatherSelector = vl.selectPoint()
.fields('weather') // select the 'weather' field
.nearest(true) // select nearest point to click
.on('click') // click to select a point
.clear('dblclick') // double click to clear
.bind('legend'); // also bind to the legend
const scatterPlot = vl.markCircle()
.data(seattleWeatherTyped)
.select(weatherSelector)
.title({text: "Seattle Daily Max Temperatures (2012-2015) with Overall Means",
subtitle: "Click on point or legend to select a weather category | Double click to reset"})
.encode(
vl.x().fieldT("date"),
vl.y().fieldQ('temp_max'),
vl.color().fieldN('weather').scale({range: weatherColors}),
vl.opacity().if(weatherSelector, vl.value(0.7)).value(0.1)
);

const overallAvgLine = vl.markRule({tooltip: true, color: 'firebrick'}) // we always show the overall avg line
.data(seattleWeatherTyped)
.encode(
vl.y().fieldQ('temp_max').aggregate("mean")
);

const avgLinePerWeatherType = vl.markRule({tooltip: true})
.data(seattleWeatherTyped)
.transform(vl.filter(weatherSelector.empty(false))) // only show this line if weather is selected
.encode(
vl.y().fieldQ('temp_max').aggregate("mean"),
vl.color().fieldN('weather').scale({range: weatherColors})
);

return vl.layer(scatterPlot, overallAvgLine, avgLinePerWeatherType)
.render();
}
Insert cell
Insert cell
{
const weatherSelector = vl.selectPoint()
.fields('weather') // select the 'weather' field
.nearest(true) // select nearest point to click
.on('click') // click to select a point
.clear('dblclick') // double click to clear
.bind('legend'); // also bind to the legend
const scatterPlot = vl.markCircle()
.data(seattleWeatherTyped)
.select(weatherSelector)
.title({text: "Seattle Daily Max Temperatures (2012-2015) with Overall Means",
subtitle: "Click on point or legend to select a weather category | Double click to reset"})
.encode(
vl.x().fieldT("date").title("Date"),
vl.y().fieldQ('temp_max').title("Max Temperature C°"),
vl.color().fieldN('weather').scale({range: weatherColors}),
vl.opacity().if(weatherSelector, vl.value(0.8)).value(0.05)
);

const overallAvgLine = vl.markRule({color: 'firebrick'})
.data(seattleWeatherTyped)
.encode(
vl.y().fieldQ('temp_max').aggregate("mean")
);

const overallAvgText = vl.markText({color: 'firebrick', align: 'left', dx:2})
.data(seattleWeatherTyped)
.encode(
vl.x().fieldT('date').aggregate('max'),
vl.y().fieldQ('temp_max').aggregate("mean"),
vl.text().mean('temp_max').format('0.1f')
);

const avgLinePerWeatherType = vl.markRule()
.data(seattleWeatherTyped)
.transform(vl.filter(weatherSelector.empty(false)))
.encode(
vl.y().fieldQ('temp_max').aggregate("mean"),
vl.color().fieldN('weather').scale({range: weatherColors})
);

const avgTextPerWeatherType = vl.markText({align:'left', x:'width', dx:2})
.data(seattleWeatherTyped)
.transform(vl.filter(weatherSelector.empty(false)))
.encode(
vl.y().mean('temp_max'),
vl.color().fieldN('weather').scale({range: weatherColors}),
vl.text().mean('temp_max').format('0.1f')
);

return vl.layer(scatterPlot, overallAvgLine, avgLinePerWeatherType,
overallAvgText, avgTextPerWeatherType)
.render();
}
Insert cell
Insert cell
{
const selectedInterval = vl.selectInterval('selected_interval'); // create our selectInterval param

return vl.markCircle()
.data(seattleWeatherTyped)
.params(selectedInterval) // add in the selection param
.title({text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Drag to select points | Click to deselect"})
.encode(
vl.x().fieldT("date"),
vl.y().fieldQ('temp_max'),
vl.color().if(selectedInterval, vl.fieldQ('temp_max')).value("grey"), // if point selected, use default color, otherwise grey
vl.opacity().if(selectedInterval, vl.value(0.7)).value(0.1) // if point selected, use opacity 0.7, otherwise 0.1
).render();
}
Insert cell
Insert cell
{
const selectedInterval = vl.selectInterval('selected_interval'); // create our selectInterval param

const scatterPlot = vl.markCircle()
.data(seattleWeatherTyped)
.params(selectedInterval) // add in the selection param
.title({text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Drag to select points | Click to deselect"})
.encode(
vl.x().fieldT("date"),
vl.y().fieldQ('temp_max').title('Max Temp'),
vl.color().if(selectedInterval, vl.fieldQ('temp_max')).value("grey"), // if point selected, use default color, otherwise grey
vl.opacity().if(selectedInterval, vl.value(0.7)).value(0.1) // if point selected, use opacity 0.7, otherwise 0.1
);
const overallAvgLine = vl.markRule({color: 'firebrick'})
.data(seattleWeatherTyped)
.encode(
vl.y().fieldQ('temp_max').aggregate("mean")
);

const overallAvgText = vl.markText({color: 'firebrick', align: 'left', dx:2})
.data(seattleWeatherTyped)
.encode(
vl.x().fieldT('date').aggregate('max'),
vl.y().fieldQ('temp_max').aggregate("mean"),
vl.text().mean('temp_max').format('0.1f')
);

const avgLineForSelection = vl.markRule()
.data(seattleWeatherTyped)
.transform(vl.filter(selectedInterval.empty(false)))
.encode(
vl.y().fieldQ('temp_max').aggregate("mean"),
vl.color().value("#ff9632")
);

const avgTextForSelection = vl.markText({align:'left', x:'width', dx:2})
.data(seattleWeatherTyped)
.transform(vl.filter(selectedInterval.empty(false)))
.encode(
vl.y().mean('temp_max'),
vl.color().value("#ff9632"),
vl.text().mean('temp_max').format('0.1f')
);

return vl.layer(scatterPlot, overallAvgLine, overallAvgText,
avgLineForSelection, avgTextForSelection)
//.config({"legend": {"orient": "bottom", "layout": {"bottom": {"anchor": "middle"}}}})
.config({"legend" : {"offset" : 35}}) // offset the legend a bit more to make room for labels
.render();
}
Insert cell
Insert cell
{
const selectedInterval = vl.selectInterval('selected_interval')
.encodings("x"); // added the x-encoding to constrain selection

const scatterPlot = vl.markCircle()
.data(seattleWeatherTyped)
.params(selectedInterval) // add in the selection param
.title({text: "Seattle Daily Max Temperatures (2012-2015)",
subtitle: "Drag to select points | Click to deselect"})
.encode(
vl.x().fieldT("date"),
vl.y().fieldQ('temp_max'),
vl.color().if(selectedInterval, vl.fieldQ('temp_max')).value("grey"), // if selected, use default color, otherwise grey
vl.opacity().if(selectedInterval, vl.value(0.7)).value(0.1) // if selected, use opacity 0.7, otherwise 0.1
);
const overallAvgLine = vl.markRule({color: 'firebrick'})
.data(seattleWeatherTyped)
.encode(
vl.y().fieldQ('temp_max').aggregate("mean")
);

const overallAvgText = vl.markText({color: 'firebrick', align: 'left', dx:2})
.data(seattleWeatherTyped)
.encode(
vl.x().fieldT('date').aggregate('max'),
vl.y().fieldQ('temp_max').aggregate("mean"),
vl.text().mean('temp_max').format('0.1f')
);

const avgLineForSelection = vl.markRule()
.data(seattleWeatherTyped)
.transform(vl.filter(selectedInterval.empty(false)))
.encode(
vl.y().fieldQ('temp_max').aggregate("mean"),
vl.color().value("#ff9632")
);

const avgTextForSelection = vl.markText({align:'left', x:'width', dx:2})
.data(seattleWeatherTyped)
.transform(vl.filter(selectedInterval.empty(false)))
.encode(
vl.y().mean('temp_max'),
vl.color().value("#ff9632"),
vl.text().mean('temp_max').format('0.1f')
);

return vl.layer(scatterPlot, overallAvgLine, overallAvgText,
avgLineForSelection, avgTextForSelection)
//.config({"legend": {"orient": "bottom", "layout": {"bottom": {"anchor": "middle"}}}})
.config({"legend" : {"offset" : 35}}) // offset the legend a bit more to make room for labels
.render();
}
Insert cell
Insert cell
{
// Create the selection brush
const selectIntervalBrush = vl.selectInterval().encodings("x");
// Create the same temporal plot as before
const temporalCirclePlot = vl.markCircle()
.params(selectIntervalBrush) // add in selection brush
.title({text: "Seattle Max Temperatures (2012-2015)",
subtitle: "Shows weather by day of year from 2012-2015"})
.encode(
vl.x().fieldT("date").timeUnit('monthdate').title('Date'),
vl.y().fieldQ('temp_max').title('Max Temp'),
vl.color().value("lightgray").if( // create conditional based on brush interval
selectIntervalBrush,
vl.color().fieldN('weather').scale({ range: weatherColors,})),
vl.size().fieldQ('precipitation').scale({range:[5, 350]})
).width(width - 300);

// Create a bar plot of weather frequencies
const weatherFreqBarPlot = vl.markBar()
.transform(vl.filter(selectIntervalBrush)) // add in the selection interval to the bar chart
.encode(
vl.x().count().scale({ domain: [0, 1600] }).title('Num of Days (2012-2015)'),
vl.y().fieldN('weather'),
vl.color().fieldN('weather').scale({ range: weatherColors })
).width(width - 300);

const barText = vl.markText({fontWeight: 'bold', align: 'left', dx:3})
.transform(vl.filter(selectIntervalBrush)) // add in the selection interval to the bar chart
.encode(
vl.x().count().scale({ domain: [0, 1600] }).title('Num of Days (2012-2015)'),
vl.y().fieldN('weather').scale({ domain: weatherTypes.slice(1, 6)}),
vl.text().count()
).width(width - 300);
return vl.vconcat(temporalCirclePlot, vl.layer(weatherFreqBarPlot, barText))
.data(seattleWeatherTyped)
.render();
}
Insert cell
Insert cell
Insert cell
viewof sortWeatherWidget = Inputs.select(["x", "-x"], {label: "Sort by"})
Insert cell
vl.markBar()
.data(seattleWeatherTyped)
.title("Num of Weather Days by Type (2012-2015)")
.encode(
vl.x().aggregate("count").title("Num of Days"),
vl.y().fieldN('weather').sort(sortWeatherWidget),
vl.color().fieldN('weather').scale({ range: weatherColors,})
)
.height(200).render()
Insert cell
Insert cell
// declare a slider widget for the xPosition
viewof xDataPosition = Inputs.range([0, 100], {value: 50, step: 1, label: "X:"})
Insert cell
// declare
viewof yDataPosition = Inputs.range([0, 100], {value: 50, step: 1, label: "Y:"})
Insert cell
viewof circleColor = Inputs.color({label: "Fill", value: "#4682b4"})
Insert cell
viewof circleSize = Inputs.text({label: "Circle size:", placeholder: "Enter the circle size", value: "500"})
Insert cell
{
return vl.markCircle({color: circleColor})
.data([{}]) // have to set the data to something, even if empty list
.title("Dynamic Circle with Observable Inputs")
.encode(
vl.x().datum(xDataPosition).type('quantitative').scale({domain: [0, 100]}),
vl.y().datum(yDataPosition).type('quantitative').scale({domain: [0, 100]}),
vl.size().value(circleSize) // use value rather than datum as we are setting a visual property, not a data one
)
.width(250)
.height(250)
.render()
}
Insert cell
Insert cell
{
const xParam = vl.param("x")
.value(50) // initial value
.bind(vl.slider(0, 100, 1).name('x: '));
const yParam = vl.param("y")
.value(50) // initial value
.bind(vl.slider(0, 100, 1).name('y: '))
return vl.markCircle()
.data([{}]) // have to set the data to something, even if empty list
.title("Dynamic Circle")
.params(xParam, yParam)
.encode(
vl.x().datum({'expr':'x'}).type('quantitative').scale({domain: [0, 100]}),
vl.y().datum({'expr':'y'}).type('quantitative').scale({domain: [0, 100]}),
vl.size().value(500) // use value rather than datum as we are setting a visual property, not a data one
)
.width(250)
.height(250)
.render()
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function plotWeatherDemoPortion(selection, includeText=true){
const scatterPlot = vl
.markCircle()
.data(seattleWeatherTyped)
.params(selection)
.encode(
vl.x().fieldT("date"),
vl.y().fieldQ("temp_max").title('Max Temp'),
vl.color()
.if(selection, vl.fieldQ('temp_max')).value("grey") // if pt selected, use default color, otherwise grey
.title('Max Temp'),
vl.opacity().if(selection, vl.value(0.7)).value(0.1) // if point selected, use opacity 0.7, otherwise 0.1
);

// Create the text layer, which is only shown when a selection is made
const text = vl.markText({ dx: 15 })
.data(seattleWeatherTyped)
.transform(
vl.filter(selection.empty(false)) // show text for selection but only if a selection exists
)
.encode(
vl.x().fieldT("date"),
vl.y().fieldQ("temp_max").title('Max Temp'),
vl.text().fieldQ("temp_max").title('Max Temp')
);

const meanRule = vl.markRule({color: '#E45756CC', size: 2})
.data(seattleWeatherTyped)
.transform(
vl.filter(selection.empty(false))
)
.encode(
vl.y().fieldQ('temp_max').aggregate('mean'),
);

const meanText = vl.markText({color: 'firebrick', align: 'left', dx:5, dy: -5})
.data(seattleWeatherTyped)
.transform(
vl.filter(selection.empty(false))
)
.encode(
vl.x().value(0),
vl.y().fieldQ('temp_max').aggregate('mean'),
vl.text().fieldQ('temp_max').aggregate('mean').format('0.1f')
);

const meanTextTitle = vl.markText({color: 'firebrick', align: 'left', fontWeight: 'bold', dx:5, dy: -16})
.data(seattleWeatherTyped)
.transform(
vl.filter(selection.empty(false))
)
.encode(
vl.x().value(0),
vl.y().fieldQ('temp_max').aggregate('mean'),
vl.text().value('Mean of Selection')
);

if(includeText){
return vl.layer(scatterPlot, text);
}else{
return vl.layer(scatterPlot, meanRule, meanText, meanTextTitle);
}
}
Insert cell
function plotWeatherDemo(w, h){
const title = "Seattle Daily Max Temperatures (2012-2015)";
const subTitlePoint = "Mouse over to select a point, double click to clear";
const subTitleInterval = "Drag mouse to select points, click to clear";

const selectPoint = vl.selectPoint('selected_point')
.nearest(true) // select nearest
.on('mouseover'); // mouseover

const selectInterval = vl.selectInterval('selected_interval');

return vl.hconcat(
plotWeatherDemoPortion(selectPoint)
.title({text: title, subtitle: subTitlePoint})
.width(w)
.height(h),
plotWeatherDemoPortion(selectInterval, false)
.title({text: title, subtitle: subTitleInterval})
.width(w)
.height(h),
)
.render()
}
Insert cell
plotWeatherDemo(300, 250)
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