Public
Edited
Mar 24, 2023
Insert cell
Insert cell
Insert cell
Insert cell
listener = {
// This being observable, the code below will run every time 'searchterm' changes.

// It creates a new async transformation on deepscatter that returns `1` for each entry where the regex matches, and `0` for each where it doesn't.
if (searchterm == "") {
return;
}
await scatterplot.ready;
scatterplot._root.transformations[searchterm] = async function (tile) {
// First ensure it exists in duckdb.
const encoded = encode_string(searchterm);
const key = tile.key;
await tile.promise;
const data = tile.record_batch.getChild("title").data[0];
let match_start = 0;
let match_length = 0;
// The first zero in the buffer
let target_length = encoded.findIndex((d) => d === 0);
const matches = [];
for (let i = 0; i < data.values.length; i++) {
if (data.values[i] === encoded[match_length]) {
match_length += 1;
if (match_length === 1) {
match_start = i;
}
if (match_length === target_length) {
matches.push(match_start);
match_length = 0;
}
} else {
if (match_length > 0) {
match_length = 0;
}
}
}
const output = new Float32Array(tile.record_batch.numRows);
let offsets_index = 0;
while (matches.length > 0) {
const searching = matches.shift();
while (data.valueOffsets[offsets_index + 1] < searching) {
offsets_index += 1;
}
output[offsets_index] = 1;
}
return output;
};
}
Insert cell
r.shift(0)
Insert cell
r.shift()
Insert cell
r = [1, 2, 3]
Insert cell
d3.part
Insert cell
test_batch.getChild("title").data[0]
Insert cell
encode_string("foo").findIndex((d) => d === 0)
Insert cell
function encode_string(searchterm) {
const arr = new Uint8Array(128);
const encoder = new TextEncoder();
encoder.encodeInto(searchterm, arr);
return arr;
}
Insert cell
test_batch = {
await scatterplot.ready;
return new Promise((resolve) => {
setTimeout(function () {
resolve(scatterplot._root.root_tile.children[3].record_batch);
}, 8000);
});
}
Insert cell
transformation_plot = {
listener;
if (searchterm != "") {
//
scatterplot.plotAPI({
background_options: {
size: [0.4, 2] // Background half normal size, foreground double normal size.
},
encoding: {
foreground: {
field: searchterm,
op: "eq",
a: 1
}
}
});
} else {
scatterplot.plotAPI({
background_options: {
size: [0.4, 1] // Bring the foreground size back down to normal.
},
encoding: {
foreground: null
}
});
}
}
Insert cell
scatterplot = {
const plot = new deepscatter.default("#plot", 900, 600);
await plot.plotAPI({
source_url: "http://localhost:8080/pmed_original",
point_size: 1,
max_points: 1e6,
zoom_balance: 0.35,
alpha: 40,
background_color: "#FFFAF2",
encoding: {
x: {
field: "x",
transform: "literal"
},
y: {
field: "y",
transform: "literal"
},
color: {
field: "labels",
range: "category10"
}
}
});

invalidation.then(() => plot.destroy());
return plot;
}
Insert cell
html`
<style type="text/css">

.tooltip {
background-color: black;
width: 400px;
font-family: sans-serif;
}

.rect {
fill: white;
}

</style>
`
Insert cell
deepscatter = import("https://benschmidt.org/deepscatter@2.9.3")
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell
arrow = scatterplot.arrow
Insert cell
db = {
const db = await DuckDBClient.of({});
return db;
}
Insert cell
Insert cell
import {
DuckDBClient,
} from "@bmschmidt/duckdb-client-1-24-0-arrow-11-0-0"
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