Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Localize NYPD, Magic and Olympics examples #2375

Merged
merged 1 commit into from
Oct 5, 2023
Merged
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,5 @@ playwright/.cache/

.pyodide-xbuildenv
benchmark_venv

venv/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ and/or [Jupyterlab](https://jupyterlab.readthedocs.io/en/stable/).
### Examples

<!-- Examples -->
<table><tbody><tr><td>editable</td><td>file</td><td>fractal</td></tr><tr><td><a href="https://perspective.finos.org/block?example=editable"><img height="125" src="https://perspective.finos.org/blocks/editable/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=file"><img height="125" src="https://perspective.finos.org/blocks/file/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=fractal"><img height="125" src="https://perspective.finos.org/blocks/fractal/preview.png"></img></a></td></tr><tr><td>market</td><td>raycasting</td><td>evictions</td></tr><tr><td><a href="https://perspective.finos.org/block?example=market"><img height="125" src="https://perspective.finos.org/blocks/market/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=raycasting"><img height="125" src="https://perspective.finos.org/blocks/raycasting/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=evictions"><img height="125" src="https://perspective.finos.org/blocks/evictions/preview.png"></img></a></td></tr><tr><td>streaming</td><td>covid</td><td>movies</td></tr><tr><td><a href="https://perspective.finos.org/block?example=streaming"><img height="125" src="https://perspective.finos.org/blocks/streaming/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=covid"><img height="125" src="https://perspective.finos.org/blocks/covid/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=movies"><img height="125" src="https://perspective.finos.org/blocks/movies/preview.png"></img></a></td></tr><tr><td>superstore</td><td>citibike</td><td>olympics</td></tr><tr><td><a href="https://perspective.finos.org/block?example=superstore"><img height="125" src="https://perspective.finos.org/blocks/superstore/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=citibike"><img height="125" src="https://perspective.finos.org/blocks/citibike/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=olympics"><img height="125" src="https://perspective.finos.org/blocks/olympics/preview.png"></img></a></td></tr><tr><td>jupyterlab</td><td>magic</td><td>nft</td></tr><tr><td><a href="http://beta.mybinder.org/v2/gh/finos/perspective/master?urlpath=lab/tree/examples/jupyter-notebooks"><img height="125" src="https://perspective.finos.org/img/jupyterlab.png"></img></a></td><td><a href="https://texodus.github.io/mtg-perspective/?seasons-in-the-abyss-67"><img height="125" src="https://perspective.finos.org/img/mtg_preview.png"></img></a></td><td><a href="https://sc1f.github.io/pudgy-penguin-perspective/"><img height="125" src="https://raw.githubusercontent.com/sc1f/pudgy-penguin-perspective/pages/meta.png"></img></a></td></tr><tr><td>nypd ccrb</td></tr><tr><td><a href="https://texodus.github.io/nypd-ccrb/"><img height="125" src="https://texodus.github.io/nypd-ccrb/preview.png"></img></a></td></tr></tbody></table>
<table><tbody><tr><td>editable</td><td>file</td><td>fractal</td></tr><tr><td><a href="https://perspective.finos.org/block?example=editable"><img height="125" src="https://perspective.finos.org/blocks/editable/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=file"><img height="125" src="https://perspective.finos.org/blocks/file/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=fractal"><img height="125" src="https://perspective.finos.org/blocks/fractal/preview.png"></img></a></td></tr><tr><td>market</td><td>raycasting</td><td>evictions</td></tr><tr><td><a href="https://perspective.finos.org/block?example=market"><img height="125" src="https://perspective.finos.org/blocks/market/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=raycasting"><img height="125" src="https://perspective.finos.org/blocks/raycasting/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=evictions"><img height="125" src="https://perspective.finos.org/blocks/evictions/preview.png"></img></a></td></tr><tr><td>nypd</td><td>magic</td><td>streaming</td></tr><tr><td><a href="https://perspective.finos.org/block?example=nypd"><img height="125" src="https://perspective.finos.org/blocks/nypd/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=magic"><img height="125" src="https://perspective.finos.org/blocks/magic/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=streaming"><img height="125" src="https://perspective.finos.org/blocks/streaming/preview.png"></img></a></td></tr><tr><td>covid</td><td>movies</td><td>superstore</td></tr><tr><td><a href="https://perspective.finos.org/block?example=covid"><img height="125" src="https://perspective.finos.org/blocks/covid/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=movies"><img height="125" src="https://perspective.finos.org/blocks/movies/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=superstore"><img height="125" src="https://perspective.finos.org/blocks/superstore/preview.png"></img></a></td></tr><tr><td>citibike</td><td>olympics</td><td>jupyterlab</td></tr><tr><td><a href="https://perspective.finos.org/block?example=citibike"><img height="125" src="https://perspective.finos.org/blocks/citibike/preview.png"></img></a></td><td><a href="https://perspective.finos.org/block?example=olympics"><img height="125" src="https://perspective.finos.org/blocks/olympics/preview.png"></img></a></td><td><a href="http://beta.mybinder.org/v2/gh/finos/perspective/master?urlpath=lab/tree/examples/jupyter-notebooks"><img height="125" src="https://perspective.finos.org/img/jupyterlab.png"></img></a></td></tr></tbody></table>
<!-- Examples -->

### Documentation
Expand Down
22 changes: 16 additions & 6 deletions docs/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,21 @@ async function run_with_theme(page, is_dark = false) {
}

async function run() {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await run_with_theme(page);
await run_with_theme(page, true);
await browser.close();
if (!fs.existsSync("static/features")) {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await run_with_theme(page);
await run_with_theme(page, true);
await browser.close();
}

// TODO There is a typescript module annoyingly called `blocks`.
if (!fs.existsSync("static/blocks")) {
fs.mkdirSync("static/blocks");
}

const { dist_examples } = await import("../examples/blocks/index.mjs");
await dist_examples(`${__dirname}/static/blocks`);
}

function template(is_dark) {
Expand Down Expand Up @@ -137,7 +147,7 @@ function template(is_dark) {
</perspective-viewer>
<script type="module">
import perspective from "/node_modules/@finos/perspective/dist/cdn/perspective.js";
const WORKER = window.perspective.worker();
const WORKER = perspective.worker();
async function on_load() {
var el = document.getElementsByTagName('perspective-viewer')[0];
const plugin = await el.getPlugin("Heatmap");
Expand Down
5 changes: 0 additions & 5 deletions docs/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ const darkCodeTheme = require("prism-react-renderer/themes/dracula");

const fs = require("fs");

// TODO There is a typescript module annoyinglt called `blocks`.
const blocks = import("../examples/blocks/index.mjs");

blocks.then(({ dist_examples }) => dist_examples(`${__dirname}/static/blocks`));

const examples = fs.readdirSync("static/blocks").map((ex) => {
const files = fs
.readdirSync(`static/blocks/${ex}`)
Expand Down
2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"scripts": {
"docusaurus": "docusaurus",
"start": "docusaurus start",
"docs": "docusaurus build",
"docs": "node build.js && docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
"clean": "docusaurus clear",
Expand Down
17 changes: 2 additions & 15 deletions examples/blocks/examples.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const LOCAL_EXAMPLES = [
"market",
"raycasting",
"evictions",
"nypd",
"magic",
"streaming",
"covid",
"movies",
Expand All @@ -36,21 +38,6 @@ exports.get_examples = function get_examples(
url: "http://beta.mybinder.org/v2/gh/finos/perspective/master?urlpath=lab/tree/examples/jupyter-notebooks",
name: "jupyterlab",
},
{
img: "https://perspective.finos.org/img/mtg_preview.png",
url: "https://texodus.github.io/mtg-perspective/?seasons-in-the-abyss-67",
name: "magic",
},
{
img: "https://raw.githubusercontent.com/sc1f/pudgy-penguin-perspective/pages/meta.png",
url: "https://sc1f.github.io/pudgy-penguin-perspective/",
name: "nft",
},
{
img: "https://texodus.github.io/nypd-ccrb/preview.png",
url: "https://texodus.github.io/nypd-ccrb/",
name: "nypd ccrb",
},
];

const hashes = LOCAL_EXAMPLES.map((x) => ({
Expand Down
15 changes: 13 additions & 2 deletions examples/blocks/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const replacements = {
"perspective-workspace/dist/cdn/perspective-workspace.js": `perspective-workspace@${version}/dist/cdn/perspective-workspace.js`,
};

export function dist_examples(
export async function dist_examples(
outpath = `${__dirname}/../../docs/static/blocks`
) {
sh`mkdir -p ${outpath}`.runSync();
Expand All @@ -45,9 +45,14 @@ export function dist_examples(
for (const name of LOCAL_EXAMPLES) {
// Copy
if (fs.existsSync(`${__dirname}/src/${name}`)) {
// Copy
for (const filename of fs.readdirSync(`${__dirname}/src/${name}`)) {
sh`mkdir -p ${outpath}/${name}`.runSync();
if (filename.endsWith(".js") || filename.endsWith(".html")) {
if (
filename.endsWith(".mjs") ||
filename.endsWith(".js") ||
filename.endsWith(".html")
) {
let filecontents = fs
.readFileSync(`${__dirname}/src/${name}/${filename}`)
.toString();
Expand All @@ -61,6 +66,12 @@ export function dist_examples(
`${outpath}/${name}/${filename}`,
filecontents
);

if (filename.endsWith("build.mjs")) {
console.log("Building " + name);
const script = `${outpath}/${name}/build.mjs`;
sh`node ${script}`.runSync();
}
} else if (filename !== ".git") {
sh`cp ${__dirname}/src/${name}/${filename} ${outpath}/${name}/${filename}`.runSync();
}
Expand Down
2 changes: 1 addition & 1 deletion examples/blocks/server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { dirname } from "path";

const __dirname = dirname(fileURLToPath(import.meta.url));

dist_examples(`${__dirname}/dist`);
await dist_examples(`${__dirname}/dist`);

const template = (body) => `
<!DOCTYPE html>
Expand Down
2 changes: 2 additions & 0 deletions examples/blocks/src/magic/.block
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
license: apache-2.0
height: 800
7 changes: 7 additions & 0 deletions examples/blocks/src/magic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
A demo showing some visualization of decks of from the collectable trading card
game ["Magic: The Gathering"](https://magic.wizards.com/en). The dataset is a
single ~90,000 row database of every card ever published, which can be explored
as before loading a deck. By clicking the "Load Deck" button, a user created
deck provided by the [Tapped Out API](https://tappedout.net/) can be supplied
to generate some simple analytics by projecting cards from this deck using
Perspective's filtering.
188 changes: 188 additions & 0 deletions examples/blocks/src/magic/build.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

import perspective from "@finos/perspective";

import * as fs from "fs";
import * as https from "https";
import * as url from "url";

const __dirname = url.fileURLToPath(new URL(".", import.meta.url));

const ARRAY_SIZE_HINTS = {
colors: 4,
keywords: 3,
types: 3,
};

function inferSchema(card) {
const schema = {
name: undefined,
manaCost: undefined,
convertedManaCost: undefined,
types: undefined,
colorIdentity: undefined,
keywords: undefined,
};
const accessors = {};
for (const field of Object.keys(card)) {
const value = card[field];
if (typeof value === "string") {
schema[field] = "string";
accessors[field] = (card) => card[field] || "-";
} else if (typeof value === "number") {
schema[field] = "integer";
accessors[field] = (card) => card[field] || null;
} else if (Array.isArray(value)) {
schema[field] = "string";
accessors[field] = (card) => (card[field] || ["-"]).join(",");
for (
let i = 0;
i < (ARRAY_SIZE_HINTS[field] || value.length);
i++
) {
let frozen_i = i;
schema[`${field}_${i}`] = "string";
accessors[`${field}_${i}`] = (card) =>
card[field] ? card[field][frozen_i] || "-" : "-";
}
} else {
console.warn(
`Dropping column "${field}" from ${JSON.stringify(card[field])}`
);
}
}
return { schema, accessors };
}

function download_json(url) {
return new Promise((resolve, reject) => {
https
.get(url, (resp) => {
let data = "";
resp.on("data", (chunk) => {
data += chunk;
});
resp.on("end", () => {
resolve(data);
});
})
.on("error", reject);
});
}

async function main() {
if (fs.existsSync(`${__dirname}/all_identifiers.arrow`)) {
return;
}

const buffer = JSON.parse(
await download_json(`https://mtgjson.com/api/v5/AllIdentifiers.json`)
);

let { _schema, accessors } = inferSchema(
buffer.data[Object.keys(buffer.data)[0]]
);

const schema = {
name: "string",
manaCost: "string",
convertedManaCost: "integer",
types: "string",
colorIdentity: "string",
text: "string",
keywords: "string",
artist: "string",
artistIds: "string",
artistIds_0: "string",
availability: "string",
availability_0: "string",
borderColor: "string",
colorIdentity_0: "string",
colors: "string",
colors_0: "string",
colors_1: "string",
colors_2: "string",
colors_3: "string",
edhrecRank: "integer",
edhrecSaltiness: "integer",
finishes: "string",
finishes_0: "string",
flavorText: "string",
// "foreignData": "string",
frameVersion: "string",
keywords_0: "string",
keywords_1: "string",
keywords_2: "string",
language: "string",
layout: "string",
manaValue: "integer",
number: "string",
power: "string",
// printings: "string",
// printings_0: "string",
// printings_1: "string",
promoTypes: "string",
promoTypes_0: "string",
promoTypes_1: "string",
promoTypes_2: "string",
rarity: "string",
// rulings: "string",
// rulings_0: "string",
securityStamp: "string",
setCode: "string",
subtypes: "string",
subtypes_0: "string",
supertypes: "string",
toughness: "string",
type: "string",
types_0: "string",
types_1: "string",
types_2: "string",
uuid: "string",
scryfallId: "string",
};

// schema["scryfallId"] = "string";
accessors["scryfallId"] = (card) => card.identifiers.scryfallId;

const table = await perspective.table(schema, { index: "uuid" });

let rows = [];
for (const uuid of Object.keys(buffer.data)) {
const card = buffer.data[uuid];
const row = {};
for (const field of Object.keys(schema)) {
try {
row[field] = accessors[field](card);
} catch (e) {
console.error(field);
throw e;
}
}
rows.push(row);
if (rows.length > 100) {
table.update(rows);
rows = [];
}
}

table.update(rows);
const arrow = await (await table.view()).to_arrow();
fs.writeFileSync(
`${__dirname}/all_identifiers.arrow`,
Buffer.from(arrow),
"binary"
);
}

await main();
Loading