-
Notifications
You must be signed in to change notification settings - Fork 24
added uploading dataset and drag & drop support #317
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
Open
AjayThorve
wants to merge
39
commits into
rapidsai:main
Choose a base branch
from
AjayThorve:demo/viz-app/improvements
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 11 commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
d126f34
added uploading dataset and drag & drop support
AjayThorve 0a0616e
fix client-server bug
AjayThorve 19c189a
added server side pagination API
AjayThorve e0a39c0
create dir if not exists
AjayThorve 69d5ce9
Merge branch 'main' into demo/viz-app/improvements
AjayThorve f0fa54d
added redbird node based reverse-proxying
AjayThorve 90e5eb3
apply suggestions
AjayThorve 6a919aa
update readme instructions
AjayThorve ce3cdaa
typo
AjayThorve 5dc3eda
change front-end app port
AjayThorve 59d279a
add missing license text
AjayThorve 8058756
update rest api routes as per suggestions
AjayThorve df6f994
fix route name
AjayThorve 0625236
removed unnecessary condition
AjayThorve f7f0d74
bug fixes and improvements
AjayThorve 8ba7977
sending arrow tables to the client directly
AjayThorve 0bac16f
update route
AjayThorve e28eb5a
typo fix route
AjayThorve f589db7
update apache-arrow version
AjayThorve 6420370
revert apache arrow version update
AjayThorve cba5b22
add apache-arrow based streaming
AjayThorve 5881444
add updated viz to html front-end as well
AjayThorve 5c504ea
handle cases where numRows is less than pageIndex*pageSize
AjayThorve 8174c67
Update modules/demo/viz-app/pages/demo/graph.jsx
AjayThorve 765e61e
Merge branch 'main' into demo/viz-app/improvements
AjayThorve eb95097
Merge branch 'main' of github.com:rapidsai/node into demo/viz-app/imp…
trxcllnt bd535a5
update math.gl version
trxcllnt b7fde93
Merge branch 'main' of github.com:rapidsai/node into demo/viz-app/imp…
trxcllnt b4dc58a
Merge branch 'main' of github.com:rapidsai/node into demo/viz-app/imp…
trxcllnt 5718e16
add missing parameters
trxcllnt 47de288
add missing const and script type
trxcllnt 48de9ca
fix graph viz column dtypes
trxcllnt b59926c
Update yarn.lock
trxcllnt b6a27f3
separate makeDeck from the render class, and generalize the render mo…
AjayThorve e3ec1a0
Merge branch 'main' into demo/viz-app/improvements
AjayThorve 27bb83f
Merge branch 'main' into demo/viz-app/improvements
AjayThorve e23304f
fix graph api
AjayThorve 9ca9a98
update forceatlas2 calculations
AjayThorve d3be34c
fix positions
AjayThorve File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,249 @@ | ||
| // Copyright (c) 2021, NVIDIA CORPORATION. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| const {graphs, clients} = require('../graph'); | ||
| const fs = require('fs') | ||
| const util = require('util') | ||
| const {pipeline} = require('stream') | ||
| const pump = util.promisify(pipeline) | ||
| var glob = require('glob'); | ||
| const {Float32Buffer} = require('@rapidsai/cuda'); | ||
| const {GraphCOO} = require('@rapidsai/cugraph'); | ||
| const {DataFrame, Series, Int32, Uint64, Float64} = require('@rapidsai/cudf'); | ||
| const {loadEdges, loadNodes} = require('../graph/loader'); | ||
| const {RecordBatchStreamWriter} = require('apache-arrow'); | ||
|
|
||
| function readDataFrame(path) { | ||
| if (path.indexOf('.csv', path.length - 4) !== -1) { | ||
| // csv file | ||
| return DataFrame.readCSV({sources: [path], header: 0, sourceType: 'files'}); | ||
|
|
||
| } else if (path.indexOf('.parquet', path.length - 8) !== -1) { | ||
| // csv file | ||
| return DataFrame.readParquet({sources: [path]}); | ||
| } | ||
| // if (df.names.includes('Unnamed: 0')) { df = df.cast({'Unnamed: 0': new Uint32}); } | ||
| return new DataFrame({}); | ||
| } | ||
|
|
||
| async function getNodesForGraph(asDeviceMemory, nodes, numNodes) { | ||
| let nodesRes = {}; | ||
| const pos = new Float32Buffer(Array.from( | ||
| {length: numNodes * 2}, | ||
| () => Math.random() * 1000 * (Math.random() < 0.5 ? -1 : 1), | ||
| )); | ||
|
|
||
| if (nodes.x in nodes.dataframe.names) { | ||
| nodesRes.nodeXPositions = asDeviceMemory(nodes.dataframe.get(node.x).data); | ||
| } else { | ||
| nodesRes.nodeXPositions = pos.subarray(0, pos.length / 2); | ||
| } | ||
| if (nodes.y in nodes.dataframe.names) { | ||
| nodesRes.nodeYPositions = asDeviceMemory(nodes.dataframe.get(node.y).data); | ||
| } else { | ||
| nodesRes.nodeYPositions = pos.subarray(pos.length / 2); | ||
| } | ||
| if (nodes.dataframe.names.includes(nodes.size)) { | ||
| nodesRes.nodeRadius = asDeviceMemory(nodes.dataframe.get(nodes.size).cast(new Float64).data); | ||
| } | ||
| if (nodes.dataframe.names.includes(nodes.color)) { | ||
| nodesRes.nodeFillColors = | ||
| asDeviceMemory(nodes.dataframe.get(nodes.color).cast(new Float64).data); | ||
| } | ||
| if (nodes.dataframe.names.includes(nodes.id)) { | ||
| nodesRes.nodeElementIndices = | ||
| asDeviceMemory(nodes.dataframe.get(nodes.id).cast(new Uint64).data); | ||
| } | ||
| return nodesRes; | ||
| } | ||
|
|
||
| async function getEdgesForGraph(asDeviceMemory, edges) { | ||
| let edgesRes = {}; | ||
|
|
||
| if (edges.dataframe.names.includes(edges.color)) { | ||
| edgesRes.edgeColors = asDeviceMemory(edges.dataframe.get(edges.color).data); | ||
| } else { | ||
| edgesRes.edgeColors = asDeviceMemory( | ||
| Series | ||
| .sequence( | ||
| {type: new Uint64, size: edges.dataframe.numRows, init: 18443486512814075489n, step: 0}) | ||
| .data); | ||
| } | ||
| if (edges.dataframe.names.includes(edges.id)) { | ||
| edgesRes.edgeList = asDeviceMemory(edges.dataframe.get(edges.id).cast(new Uint64).data); | ||
| } | ||
| if (edges.dataframe.names.includes(edges.bundle)) { | ||
| edgesRes.edgeBundles = asDeviceMemory(edges.dataframe.get(edges.bundle).data); | ||
| } | ||
| return edgesRes; | ||
| } | ||
|
|
||
| async function getPaginatedRows(df, pageIndex = 1, pageSize = 400, selected = []) { | ||
| console.log(selected); | ||
| if (selected.length == 0) { | ||
| return [df.head(pageIndex * pageSize).tail(pageSize).toArrow(), df.numRows]; | ||
AjayThorve marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| const selectedSeries = Series.new({type: new Int32, data: selected}); | ||
| let dfUpdated = df.gather(selectedSeries); | ||
| return [dfUpdated.head(pageIndex * pageSize).tail(pageSize).toArrow(), dfUpdated.numRows]; | ||
AjayThorve marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| module.exports = function(fastify, opts, done) { | ||
| // fastify.addHook('preValidation', (request, reply, done) => { | ||
| // console.log('this is executed', request); | ||
| // done() | ||
| // }); | ||
AjayThorve marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| async function loadGraph(id, data) { | ||
| if (!(id in fastify[graphs])) { | ||
| const asDeviceMemory = (buf) => new (buf[Symbol.species])(buf); | ||
| const src = data.edges.dataframe.get(data.edges.src); | ||
| const dst = data.edges.dataframe.get(data.edges.dst); | ||
| const graph = new GraphCOO(src._col, dst._col, {directedEdges: true}); | ||
| fastify[graphs][id] = { | ||
| refCount: 0, | ||
| nodes: await getNodesForGraph(asDeviceMemory, data.nodes, graph.numNodes()), | ||
| edges: await getEdgesForGraph(asDeviceMemory, data.edges), | ||
| graph: graph, | ||
| }; | ||
| } | ||
|
|
||
| ++fastify[graphs][id].refCount; | ||
|
|
||
| return { | ||
| gravity: 0.0, | ||
| linLogMode: false, | ||
| scalingRatio: 5.0, | ||
| barnesHutTheta: 0.0, | ||
| jitterTolerance: 0.05, | ||
| strongGravityMode: false, | ||
| outboundAttraction: false, | ||
| graph: fastify[graphs][id].graph, | ||
| nodes: { | ||
| ...fastify[graphs][id].nodes, | ||
| length: fastify[graphs][id].graph.numNodes(), | ||
| }, | ||
| edges: { | ||
| ...fastify[graphs][id].edges, | ||
| length: fastify[graphs][id].graph.numEdges(), | ||
| }, | ||
| }; | ||
| } | ||
|
|
||
| fastify.get('/getIDValue', async (request, reply) => { | ||
| console.log(fastify[clients][request.query.id + ':video']); | ||
| reply.send(fastify[clients][request.query.id + ':video'].graph.dataframes[0].numRows); | ||
| }); | ||
AjayThorve marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| fastify.post('/uploadFile', async function(req, reply) { | ||
| const data = await req.file(); | ||
| const basePath = `${__dirname}/../../data/`; | ||
| if (!fs.existsSync(basePath)) { fs.mkdirSync(basePath); } | ||
AjayThorve marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| const filepath = `${basePath}${data.filename}`; | ||
AjayThorve marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| const target = fs.createWriteStream(filepath); | ||
| try { | ||
| await pump(data.file, target); | ||
| console.log('success'); | ||
| } catch (err) { console.log(err); } | ||
| reply.send() | ||
| }); | ||
|
|
||
| fastify.get('/getFileNames', async (request, reply) => { | ||
| if (`${request.query.id}:video` in fastify[clients]) { | ||
| glob(`*.{csv,parquet}`, | ||
| {cwd: `${__dirname}/../../data/`}, | ||
| (er, files) => { reply.send(JSON.stringify(files.concat(['defaultExample']))); }); | ||
| } else { | ||
| reply.code(500).send('client handshake not established'); | ||
| } | ||
| }); | ||
AjayThorve marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| fastify.get('/loadOnGPU', async (request, reply) => { | ||
| const id = `${request.query.id}:video`; | ||
| const filePath = `${__dirname}/../../data/` | ||
| if (id in fastify[clients]) { | ||
| if (fs.existsSync(`${filePath}${request.query.nodes}`) && | ||
| fs.existsSync(`${filePath}${request.query.edges}`)) { | ||
| fastify[clients][id].data.nodes.dataframe = | ||
| await readDataFrame(`${filePath}${request.query.nodes}`); | ||
|
|
||
| fastify[clients][id].data.edges.dataframe = | ||
| await readDataFrame(`${filePath}${request.query.edges}`); | ||
| } else { | ||
| fastify[clients][id].data.nodes.dataframe = await loadNodes(); | ||
| fastify[clients][id].data.edges.dataframe = await loadEdges(); | ||
| } | ||
| if (fastify[clients][id].data.nodes.dataframe.numRows == 0) { | ||
| reply.code(500).send('no dataframe loaded'); | ||
| } | ||
| reply.send(JSON.stringify({ | ||
| 'nodes': fastify[clients][id].data.nodes.dataframe.numRows, | ||
| 'edges': fastify[clients][id].data.edges.dataframe.numRows | ||
| })); | ||
| } | ||
| else { | ||
| reply.code(500).send('client handshake not established'); | ||
| } | ||
| }) | ||
AjayThorve marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| fastify.get('/fetchDFParameters', async (request, reply) => { | ||
| const id = `${request.query.id}:video`; | ||
| if (id in fastify[clients]) { | ||
| reply.send(JSON.stringify({ | ||
| nodesParams: fastify[clients][id].data.nodes.dataframe.names.concat([null]), | ||
| edgesParams: fastify[clients][id].data.edges.dataframe.names.concat([null]) | ||
| })); | ||
| } else { | ||
| reply.code(500).send('client handshake not established'); | ||
| } | ||
| }); | ||
|
|
||
| fastify.post('/updateRenderColumns', async (request, reply) => { | ||
| const id = `${request.body.id}:video`; | ||
| if (id in fastify[clients]) { | ||
| Object.assign(fastify[clients][id].data.nodes, request.body.nodes); | ||
| Object.assign(fastify[clients][id].data.edges, request.body.edges); | ||
| fastify[clients][id].graph = await loadGraph('default', fastify[clients][id].data); | ||
| reply.code(200).send(); | ||
| } else { | ||
| reply.code(500).send('client handshake not established'); | ||
| } | ||
| }); | ||
|
|
||
| fastify.post('/fetchPaginatedData', async (request, reply) => { | ||
| const id = `${request.body.id}:video`; | ||
| if (id in fastify[clients]) { | ||
| const pageIndex = request.body.pageIndex; | ||
| const pageSize = request.body.pageSize; | ||
| const dataframe = request.body.dataframe; //{'nodes', 'edges'} | ||
| const [res, numRows] = | ||
| await getPaginatedRows(fastify[clients][id].data[dataframe].dataframe, | ||
| pageIndex, | ||
| pageSize, | ||
| fastify[clients][id].state.selectedInfo[dataframe]); | ||
|
|
||
| reply.send(JSON.stringify({page: res.toArray(), numRows: numRows})); | ||
| // try { | ||
| // // RecordBatchStreamWriter.writeAll(res).pipe(reply.stream()); | ||
| // } catch (err) { | ||
| // request.log.error({err}, '/run_query error'); | ||
| // reply.code(500).send(err); | ||
| // } | ||
AjayThorve marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } else { | ||
| reply.code(500).send('client handshake not established'); | ||
| } | ||
| }); | ||
|
|
||
| done(); | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.