chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:25:07 +08:00
commit a26e856398
1681 changed files with 296950 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
# python-tornado
This example contains a simple `perspective-python` folder that uses Tornado to
serve a static dataset to the user through various data bindings. There are a
examples of end-to-end `perspective-viewer` integrated `.html` files hosted:
- `index.html`: a
[client/server replicated](https://perspective-dev.github.io/docs/md/server.html#clientserver-replicated)
setup that synchronizes the client and server data using Apache Arrow.
- `server_mode.html`: a
[server-only](https://perspective-dev.github.io/docs/md/server.html#server-only)
setup that reads data and performs operations directly on the server using
commands sent through the Websocket.
- `client_server_editing.html`: a client-server replicated setup that also
enables editing, where edits from multiple clients are applied properly to the
server, and then synchronized back to the clients.
@@ -0,0 +1,99 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<script type="module" src="http://localhost:8080/node_modules/@perspective-dev/viewer-datagrid/dist/cdn/perspective-viewer-datagrid.js"></script>
<script type="module" src="http://localhost:8080/node_modules/@perspective-dev/viewer-charts/dist/cdn/perspective-viewer-charts.js"></script>
<link rel="stylesheet" crossorigin="anonymous" href="/node_modules/@perspective-dev/viewer/dist/css/themes.css" />
<style>
perspective-viewer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
</style>
</head>
<body>
<!--
Clicking on cells in the grid and typing will fire edits back into the Table in memory.
If you open another tab and navigate to the same URL, edits will appear in all the windows in real time.
This allows collaborative editing of the underlying Table, with all updates propagated automatically to all clients.
-->
<perspective-viewer id="viewer" editable></perspective-viewer>
<script type="module">
import "/node_modules/@perspective-dev/viewer/dist/cdn/perspective-viewer.js";
import perspective from "/node_modules/@perspective-dev/client/dist/cdn/perspective.js";
/**
* This example sets up Perspective in "distributed mode", but manually
* controls state synchronization between client and server in order to
* enable "edits" from the client to update the server (and all other
* clients), and "updates" from the server to notify all clients.
*
* For a simple example of distributed mode without editing, see
* `index.html`.
*/
const viewer = document.getElementById("viewer");
// Connect to the websocket and create a new webworker
const websocket = perspective.websocket("ws://localhost:8080/websocket");
const worker = perspective.worker();
// Get handles to the `Table` on the server, and create a
// `view()` on the server.
const server_table = await websocket.open_table("data_source_one");
const server_view = await server_table.view();
// Serialize the current state of the view to an arrow, and create
// a Table on the client that has the same index as the Table
// on the server using `get_index()`.
//
// Client/server editing does not work on an unindexed Table.
const arrow = await server_view.to_arrow();
const client_table = await worker.table(arrow, { index: "Row ID" });
const client_view = await client_table.view(); // client -> server
await viewer.load(Promise.resolve(client_table));
// Create ports on both the client and the server - this allows
// the client and server to track which updates are coming from
// the server, and which edits are coming from the client
// in the browser.
const client_edit_port = await viewer.getEditPort();
const server_edit_port = await server_table.make_port();
// When the client updates, if the update comes through the edit
// port then forward it to the server.
client_view.on_update(
(updated) => {
if (updated.port_id === client_edit_port) {
// `update` must be on the `server_edit_port`
server_table.update(updated.delta, {
port_id: server_edit_port,
});
}
},
{ mode: "row" },
);
// If the server updates, and the edit is not coming from the
// server edit port, then synchronize state with the client.
server_view.on_update(
(updated) => {
if (updated.port_id !== server_edit_port) {
// any port, we don't care
client_table.update(updated.delta);
}
},
{ mode: "row" },
);
</script>
</body>
</html>
+44
View File
@@ -0,0 +1,44 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<script type="module" src="/node_modules/@perspective-dev/viewer-datagrid/dist/cdn/perspective-viewer-datagrid.js"></script>
<script type="module" src="/node_modules/@perspective-dev/viewer-charts/dist/cdn/perspective-viewer-charts.js"></script>
<link rel="stylesheet" crossorigin="anonymous" href="/node_modules/@perspective-dev/viewer/dist/css/themes.css" />
<style>
perspective-viewer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
</style>
</head>
<body>
<perspective-viewer id="viewer"></perspective-viewer>
<script type="module">
import "/node_modules/@perspective-dev/viewer/dist/cdn/perspective-viewer.js";
import perspective from "/node_modules/@perspective-dev/client/dist/cdn/perspective.js";
/**
* `perspective.websocket` connects to a remote Perspective server
* that accepts WebSocket connections at the specified URL.
*
* Use `perspective.websocket` to set up Perspective in server or
* distributed modes.
*/
const websocket = await perspective.websocket("ws://localhost:8080/websocket");
const server_table = await websocket.open_table("data_source_one");
// const table = worker.table(server_table);
// Load the local table in the `<perspective-viewer>`.
document.getElementById("viewer").load(server_table);
</script>
</body>
</html>
+22
View File
@@ -0,0 +1,22 @@
{
"name": "python-tornado",
"private": true,
"version": "4.5.2",
"description": "An example of editing a `perspective-python` server from the browser.",
"scripts": {
"start": "PYTHONPATH=../../python/perspective python3 server.py"
},
"keywords": [],
"license": "Apache-2.0",
"dependencies": {
"@perspective-dev/client": "workspace:",
"@perspective-dev/viewer": "workspace:",
"@perspective-dev/viewer-charts": "workspace:",
"@perspective-dev/viewer-datagrid": "workspace:",
"@perspective-dev/workspace": "workspace:",
"superstore-arrow": "^3.2.0"
},
"devDependencies": {
"npm-run-all": "^4.1.3"
}
}
+65
View File
@@ -0,0 +1,65 @@
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
# ┃ 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 os
import os.path
import logging
import tornado.websocket
import tornado.web
import tornado.ioloop
import perspective
import perspective.handlers.tornado
here = os.path.abspath(os.path.dirname(__file__))
file_path = os.path.join(
here, ".", "node_modules", "superstore-arrow", "superstore.lz4.arrow"
)
def make_app(perspective_server):
return tornado.web.Application(
[
(
r"/websocket",
perspective.handlers.tornado.PerspectiveTornadoHandler,
{"perspective_server": perspective_server},
),
(
r"/node_modules/(.*)",
tornado.web.StaticFileHandler,
{"path": "../../node_modules/"},
),
(
r"/(.*)",
tornado.web.StaticFileHandler,
{"path": "./", "default_filename": "index.html"},
),
],
websocket_max_message_size=100 * 1024 * 1024,
)
if __name__ == "__main__":
perspective_server = perspective.Server()
app = make_app(perspective_server)
app.listen(8080)
logging.critical("Listening on http://localhost:8080")
loop = tornado.ioloop.IOLoop.current()
client = perspective_server.new_local_client()
with open(file_path, mode="rb") as file:
data = file.read()
table = client.table(data, name="data_source_one")
for _ in range(10):
table.update(data)
loop.start()
+38
View File
@@ -0,0 +1,38 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<script type="module" src="http://localhost:8080/node_modules/@perspective-dev/viewer-datagrid/dist/cdn/perspective-viewer-datagrid.js"></script>
<script type="module" src="http://localhost:8080/node_modules/@perspective-dev/viewer-charts/dist/cdn/perspective-viewer-charts.js"></script>
<link rel="stylesheet" crossorigin="anonymous" href="/node_modules/@perspective-dev/viewer/dist/css/themes.css" />
<style>
perspective-viewer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
</style>
</head>
<body>
<perspective-viewer id="viewer" editable></perspective-viewer>
<script type="module">
import "/node_modules/@perspective-dev/viewer/dist/cdn/perspective-viewer.js";
import perspective from "http://localhost:8080/node_modules/@perspective-dev/viewer/dist/cdn/perspective-viewer.js";
const REQ = fetch("/node_modules/superstore-arrow/superstore.lz4.arrow");
// Create a client that expects a Perspective server to accept
// Websocket connections at the specified URL.
const websocket = await perspective.websocket("ws://localhost:8082/websocket");
const resp = await REQ;
const arrow = await resp.arrayBuffer();
const table = websocket.table(arrow);
document.getElementById("viewer").load(table);
</script>
</body>
</html>