Published
Edited
Oct 13, 2021
Insert cell
Insert cell
plot = {
// select a point for which to provide details-on-demand
const hover = vl.selectPoint('hover')
.encodings('x') // limit selection to x-axis value
.on('mouseover') // select on mouseover events
.toggle(false) // disable toggle on shift-hover
.nearest(true); // select data point nearest the cursor

const hover2 = vl.selectPoint('hover2')
.encodings('x') // limit selection to x-axis value
.on('mouseover') // select on mouseover events
.toggle(false) // disable toggle on shift-hover
.nearest(true); // select data point nearest the cursor

const hover3 = vl.selectPoint('hover3')
.encodings('x') // limit selection to x-axis value
.on('mouseover') // select on mouseover events
.toggle(false) // disable toggle on shift-hover
.nearest(true); // select data point nearest the cursor

// predicate to test if a point is hover-selected
// return false if the selection is empty
const isHovered = hover.empty(() => { console.log('!!!'); return false;} );
// define our base line chart of SOP
const line = vl.markLine().encode(
vl.x().fieldO('aspect_num'),
vl.y().fieldQ('SOP')
);

const line2 = vl.markLine().encode(
vl.x().fieldO('aspect_num'),
vl.y().fieldQ('GOE+'),
// vl.opacity(0.4)
);

const line3 = vl.markLine().encode(
vl.x().fieldO('aspect_num'),
vl.y().fieldQ('GOE-')
);

// define our area chart of GOE
const area = vl.markArea({ color: "darkseagreen", opacity: 0.5 })
.encode(
vl.x().fieldO("aspect_num"),
vl.y2().fieldQ("GOE+"),
vl.y().fieldQ("GOE-")
)
// shared base for new layers, filtered to hover selection
const base = line.transform(vl.filter(isHovered));

// mark properties for text label layers
const label = {align: 'left', dx: 5, dy: -5};
const white = {stroke: 'white', strokeWidth: 2};

return vl.data(bv)
.layer(
line, line2, line3,
area,
// add a rule mark to serve as a guide line
vl.markRule({color: '#aaa'})
.transform(vl.filter(isHovered))
.encode(vl.x().fieldO('aspect_num')),
// add circle marks for selected time points, hide unselected points
line.markCircle()
.params(hover) // use as anchor points for selection
.encode(vl.opacity().if(isHovered, vl.value(1)).value(0)),
line2.markCircle()
.params(hover2) // use as anchor points for selection
.encode(vl.opacity().if(isHovered, vl.value(1)).value(0)),
line3.markCircle()
.params(hover3) // use as anchor points for selection
.encode(vl.opacity().if(isHovered, vl.value(1)).value(0)),
// add white stroked text to provide a legible background for SOP
base.markText(label, white).encode(vl.text().fieldQ('SOP')),
// add text labels for SOP
base.markText(label).encode(vl.text().fieldQ('SOP')),
// add white stroked text to provide a legible background for GOE+
base.markText(label, white).encode(vl.text().fieldQ('GOE+'), vl.y().fieldQ("GOE+")),
// add text labels for GOE+
base.markText(label).encode(vl.text().fieldQ('GOE+'), vl.y().fieldQ("GOE+")),
// add white stroked text to provide a legible background for GOE-
base.markText(label, white).encode(vl.text().fieldQ('GOE-'), vl.y().fieldQ("GOE-")),
// add text labels for GOE-
base.markText(label).encode(vl.text().fieldQ('GOE-'), vl.y().fieldQ("GOE-"))
)
.width(700)
.height(400)
.render();
}
Insert cell
bv = FileAttachment("bv_template.csv").csv()
Insert cell
bv1 = FileAttachment("bv_template@4.csv").csv()
Insert cell
Insert cell
import {printTable} from '@uwdata/data-utilities'
Insert cell
{
const colors = {
domain: ['Satoko MIYAHARA', 'Kaori SAKAMOTO','Sofia SAMODUROVA','Marin HONDA','Bradie TENNELL','Megan WESSENBERG','Laurine LECAVELIER', 'Polina TSURSKAYA', 'Starr ANDREWS', 'Loena HENDRICKX','Alaine CHARTRAND'],
range: ['#9467bd', '#e7ba52', '#9467bd', '#e7ba52','#9467bd', '#e7ba52','#9467bd', '#e7ba52','#9467bd', '#e7ba52']
};
return vl.markLine()
.data(bv1)
.encode(
vl.x().fieldO('aspect_num'),
vl.y().fieldQ('SOP'),
vl.color().fieldN('performance_id').scale(colors),
vl.column().fieldN('performance_id')
)
.width(150)
.height(150)
.render();
}
Insert cell
{
const goeMinMax = vl.markArea({opacity: 0.3}).encode(
vl.x().fieldO('aspect_num'),
vl.y().fieldQ('GOE+').title('Points'),
vl.y2().fieldQ('GOE-'),
vl.color().fieldN('performance_id')
);

const sop = vl.markLine().encode(
vl.x().fieldO('aspect_num'),
vl.y().fieldQ('SOP'),
vl.color().fieldN('performance_id')
);

return vl.layer(goeMinMax, sop)
.facet({column: vl.field('performance_id')})
.data(bv1)
.render();
}
Insert cell
{
const hover = vl.selectPoint('hover')
.encodings('x') // limit selection to x-axis value
.on('mouseover') // select on mouseover events
.toggle(false) // disable toggle on shift-hover
.nearest(true); // select data point nearest the cursor

// predicate to test if a point is hover-selected
// return false if the selection is empty
const isHovered = hover.empty(false);

const line = vl.markLine().encode(
vl.x().fieldO('aspect_num'),
vl.y().fieldQ('SOP'),
vl.color().fieldN('performance_id')
);
const base = line.transform(vl.filter(isHovered));

// mark properties for text label layers
const label = {align: 'left', dx: 5, dy: -5};
const white = {stroke: 'white', strokeWidth: 2};

return vl.data(bv1)
.layer(
line,
// add a rule mark to serve as a guide line
vl.markRule({color: '#aaa'})
.transform(vl.filter(isHovered))
.encode(vl.x().fieldO('aspect_num')),
// add circle marks for selected time points, hide unselected points
line.markCircle()
.params(hover) // use as anchor points for selection
.encode(vl.opacity().if(isHovered, vl.value(1)).value(0)),
// add white stroked text to provide a legible background for labels
base.markText(label, white).encode(vl.text().fieldN('aspect_desc')),
// add text labels for stock prices
base.markText(label).encode(vl.text().fieldN('aspect_desc'))
)
.width(900)
.height(700)
.render();
}
Insert cell
Insert cell
vl.markLine()
.data(bv1)
.encode(
vl.x().fieldO('aspect_num'),
vl.y().fieldQ('SOP_cum'),
vl.color().fieldN('performance_id')
)
.width(350)
.height(350)
.render()
Insert cell
fin={
const hover = vl.selectSingle()
.encodings('x') // limit selection to x-axis value
.on('mouseover') // select on mouseover events
.toggle(false) // disable toggle on shift-hover
.nearest(true); // select data point nearest the cursor

const sop = vl.markLine().encode(
vl.x().fieldO('aspect_num'),
vl.y().fieldQ('SOP'),
vl.color().fieldN('performance_id')
);

const goeMinMax = vl.markArea({opacity: 0.3}).encode(
vl.x().fieldO('aspect_num'),
vl.y().fieldQ('GOE+').title('Points'),
vl.y2().fieldQ('GOE-'),
vl.color().fieldN('performance_id')
);

const base = sop.transform(vl.filter(hover));

const label = {align: 'left', dx: 5, dy: -5};
const white = {stroke: 'white', strokeWidth: 2};
return vl
.layer(
sop,
goeMinMax,
// add a rule mark to serve as a guide line
vl.markRule({color: '#aaa'})
.transform(vl.filter(hover))
.encode(vl.x().fieldO('aspect_num')),
// add circle marks for selected time points, hide unselected points
sop.markCircle()
.select(hover) // use as anchor points for selection
.encode(vl.opacity().if(hover, vl.value(1)).value(0)),
// add white stroked text to provide a legible background for labels
base.markText(label, white).encode(vl.text().fieldN('aspect_desc')),
// add text labels for stock prices
base.markText(label).encode(vl.text().fieldN('aspect_desc'))
)
.width(300)
.height(120)
.facet(vl.facet()
.fieldN('performance_id')
)
.columns(3)
.data(bv1)
.render();
}
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