update arquero library to v4+ & fix layout alignment (#15)

* fix footer layout

* update arquero and components using it

* fix get values from column at index with new arquero

* fix selecting an item on search

* creates loader when searching

* removed unused file change

* fix lint & .gitignore

* use updated ts & updates example files

* fix useDebounce onChange and onSearch

* fix packages

* fix types & webpack

* removed general import of arquero
This commit is contained in:
Dayenne Souza 2021-12-17 16:40:16 -03:00 коммит произвёл GitHub
Родитель 094bbc9dce
Коммит 35315242bd
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
83 изменённых файлов: 25344 добавлений и 61482 удалений

2
.gitignore поставляемый
Просмотреть файл

@ -27,3 +27,5 @@ yarn-error.log*
!.yarn/plugins
!.yarn/sdks
!.yarn/versions
public/data/msft*

36441
.pnp.cjs сгенерированный

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/@types-d3-scale-npm-2.2.6-d18cd56795-ba4bd7e099.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/@types-d3-selection-npm-2.0.1-81a3e6c54d-23a337564e.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/@types-flatbuffers-npm-1.10.0-0aae837bc1-f6665700a8.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/@types-node-npm-12.20.37-9ce6eac5c0-8c8b12f802.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/@types-node-npm-14.17.0-2942ba859f-8e71840253.zip поставляемый

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/@types-node-npm-14.18.0-090dae09d8-b120c26fe5.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/@types-react-dom-npm-16.9.13-aefc858bae-71f0e63e28.zip поставляемый

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/@types-react-dom-npm-16.9.14-758ab4d1e1-68a4ee88f7.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/@types-react-npm-16.14.21-7ae562f957-9660ea0a2c.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/@types-react-npm-16.14.6-230d069a48-7aeb670a46.zip поставляемый

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/@types-text-encoding-utf-8-npm-1.0.2-d39a8dfdeb-a7199bb5c0.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/acorn-npm-8.6.0-9de50afc7d-9d0de73b73.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/apache-arrow-npm-3.0.0-e45ffe1a93-2ebd5e76d7.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/argv-tools-npm-0.1.2-2181fefcc7-77f8c7727c.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/arquero-npm-0.13.3-a1a2185d91-5952608e2e.zip поставляемый

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/arquero-npm-4.8.7-afd14ab866-63a832e7f0.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/array-back-npm-2.0.0-3366a86d25-ab36ab3504.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/command-line-args-npm-5.0.2-6a7d7bfe5d-fc239cc262.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/command-line-usage-npm-5.0.5-29cebea723-d636200649.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/find-replace-npm-2.0.1-3aaa403567-8eaa35d2a1.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/flatbuffers-npm-1.11.0-b1e0cd4a49-1248894094.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/json-bignum-npm-0.0.3-2b08f05834-e64b69089f.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/lodash.camelcase-npm-4.3.0-bf268e3bf0-cb9227612f.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/lodash.padend-npm-4.6.1-6a28392d72-c2e6e789de.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/node-fetch-npm-2.6.6-056db6b778-ee8290626b.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/pad-left-npm-2.1.0-ffe13d2d40-a1605c3cb0.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/re-resizable-npm-6.9.1-79ca365a45-b164f6b956.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/react-rnd-npm-10.3.5-20968f001c-2171e3119a.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/reduce-flatten-npm-1.0.1-63b2c5a753-5e5a450500.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/table-layout-npm-0.4.5-1ffc9a985b-9642b67d1b.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/test-value-npm-3.0.0-85a3319573-5bac284cbe.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/text-encoding-utf-8-npm-1.0.2-d3a9fb552b-ec4c15d50e.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/tr46-npm-0.0.3-de53018915-726321c5ea.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/tslib-npm-2.3.0-277e75e108-8869694c26.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/typical-npm-2.6.1-25fd0ac6b5-6af04fefe5.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/webidl-conversions-npm-3.0.1-60310f6a2b-c92a0a6ab9.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/whatwg-url-npm-5.0.0-374fb45e60-b8daed4ad3.zip поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
.yarn/cache/wordwrapjs-npm-3.0.0-3ae3b50ec3-953322ec8d.zip поставляемый Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -51,7 +51,7 @@
"@types/react-rnd": "^8.0.0",
"@yarnpkg/pnpify": "^2.4.0",
"ahooks": "^2.10.6",
"arquero": "^0.13.3",
"arquero": "^4.8.4",
"core-js": "^3.12.0",
"d3-array": "^2.8.0",
"d3-brush": "2",

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -3,7 +3,8 @@
* Licensed under the MIT license. See LICENSE file in the project.
*/
import { extension } from './util'
import { fromCSV, table } from 'arquero'
import { fromCSV } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
const identity = (d: any) => d
@ -23,12 +24,12 @@ const fns = {
target: identity,
}
export async function fetchDSVTable(url: string) {
export async function fetchDSVTable(url: string): Promise<ColumnTable> {
const content = await fetch(url).then(res => res.text())
return parseDSVTable(url, content)
}
export function parseDSVTable(filename: string, content: string): table {
export function parseDSVTable(filename: string, content: string): ColumnTable {
const ext = extension(filename)
const table = fromCSV(content, {
header: true,

Просмотреть файл

@ -4,13 +4,14 @@
*/
import { fetchDSVTable } from './dsv'
import { extension } from './util'
import ColumnTable from 'arquero/dist/types/table/column-table'
/**
* Fetch a file visible to the application in csv or tsv format,
* such as from the public folder or any other no-auth url
* @param url
*/
export async function fetchUrl(url: string) {
export async function fetchUrl(url: string): Promise<ColumnTable> {
const ext = extension(url)
switch (ext) {
case 'csv':

Просмотреть файл

@ -2,11 +2,11 @@
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
import { table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
import { useMemo } from 'react'
export interface ArqueroTableProps {
table: table
table: ColumnTable
/**
* Direct pass-through to Arquero table options
*/
@ -36,7 +36,8 @@ export const ArqueroTable: React.FC<ArqueroTableProps> = ({
thead: 'display:none;',
}
}
return table.toHTML(opts)
return table.toHTML()
}, [table, options, hideHeaders])
return <div style={style} dangerouslySetInnerHTML={{ __html: html }} />
}

Просмотреть файл

@ -3,13 +3,16 @@
* Licensed under the MIT license. See LICENSE file in the project.
*/
import { Community, Edge, ItemType, Node, TableBackedItem } from '../types'
import { table as createTable, table } from 'arquero'
//importing as aqtable because there's already a param named table in this file
import { table as aqtable } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
import { TableData } from 'arquero/dist/types/table/table'
class TableItemFacade implements TableBackedItem {
private _table: table
private _table: ColumnTable
private _index: number
private _id: string
constructor(table: table, index: number, prefix: ItemType) {
constructor(table: ColumnTable, index: number, prefix: ItemType) {
this._table = table
this._index = index
this._id = `${prefix}.id`
@ -21,7 +24,7 @@ class TableItemFacade implements TableBackedItem {
return this._table.columnNames()
}
get(col: string) {
return this._table.get(col, this._index)
return this._table.column(col)?.get(this._index)
}
get id() {
return this.get(this._id)
@ -29,7 +32,7 @@ class TableItemFacade implements TableBackedItem {
}
class NodeFacade extends TableItemFacade implements Node {
constructor(table: table, index: number) {
constructor(table: ColumnTable, index: number) {
super(table, index, 'node')
}
get x() {
@ -44,7 +47,7 @@ class NodeFacade extends TableItemFacade implements Node {
}
class CommunityFacade extends TableItemFacade implements Community {
constructor(table: table, index: number) {
constructor(table: ColumnTable, index: number) {
super(table, index, 'community')
}
get pid() {
@ -59,7 +62,7 @@ class CommunityFacade extends TableItemFacade implements Community {
}
class EdgeFacade extends TableItemFacade implements Edge {
constructor(table: table, index: number) {
constructor(table: ColumnTable, index: number) {
super(table, index, 'edge')
}
get source() {
@ -76,11 +79,15 @@ class EdgeFacade extends TableItemFacade implements Edge {
type Callback<T> = (item: T, index: number) => any
export class TableCollection<T> {
private _table: table = createTable()
private _table: ColumnTable = aqtable({})
private _prefix: string
private _Ctor: any
private _indices: Uint32Array | undefined
constructor(table: table | undefined, prefix: string, indices?: Uint32Array) {
private _indices: number[] | undefined
constructor(
table: ColumnTable | undefined,
prefix: string,
indices?: number[],
) {
if (table) {
this._table = table
}
@ -102,7 +109,7 @@ export class TableCollection<T> {
this._indices = indices
}
}
get table(): table {
get table(): ColumnTable {
return this._table
}
get size(): number {
@ -124,19 +131,21 @@ export class TableCollection<T> {
const output: T[] = []
this.scan(idx => {
const n = new this._Ctor(this._table, idx, this._prefix)
if (idx === undefined) return
output.push(callback(n, idx))
}, ordered)
return output
}
forEach(callback: Callback<T>, ordered = false) {
this.scan((idx: number) => {
this.scan((idx: number | undefined) => {
const n = new this._Ctor(this._table, idx)
if (idx === undefined) return
callback(n, idx)
}, ordered)
}
toMap(): Map<string, T> {
const map = new Map<string, T>()
this.scan((idx: number) => {
this.scan((idx: number | undefined) => {
const n = new this._Ctor(this._table, idx)
const id = n.id
map.set(id, n)
@ -145,7 +154,7 @@ export class TableCollection<T> {
}
toSet(): Set<T> {
const set = new Set<T>()
this.scan((idx: number) => {
this.scan((idx: number | undefined) => {
const n = new this._Ctor(this._table, idx)
set.add(n)
})
@ -153,7 +162,7 @@ export class TableCollection<T> {
}
toArray(ordered = false): T[] {
const arr: T[] = []
this.scan((idx: number) => {
this.scan((idx: number | undefined) => {
arr.push(new this._Ctor(this._table, idx))
}, ordered)
return arr
@ -175,8 +184,8 @@ export class TableCollection<T> {
sample(proportion: number): T[] {
const arr: T[] = []
const ratio = Math.floor(1 / proportion)
this.scan((idx: number) => {
if (idx % ratio === 0) {
this.scan((idx: number | undefined) => {
if (idx !== undefined && idx % ratio === 0) {
arr.push(new this._Ctor(this._table, idx))
}
})
@ -192,7 +201,11 @@ export class TableCollection<T> {
* @param ordered
*/
scan(
callback: (row: number, data: any, stop: () => void) => void,
callback: (
row?: number | undefined,
data?: TableData | any[] | undefined,
stop?: (() => void) | undefined,
) => void,
ordered = false,
) {
// note that we assume provided indices are already ordered
@ -211,19 +224,19 @@ export class TableCollection<T> {
}
export class CommunityCollection extends TableCollection<Community> {
constructor(table?: table, indices?: Uint32Array) {
constructor(table?: ColumnTable, indices?: number[]) {
super(table, 'community', indices)
}
}
export class NodeCollection extends TableCollection<Node> {
constructor(table?: table, indices?: Uint32Array) {
constructor(table?: ColumnTable, indices?: number[]) {
super(table, 'node', indices)
}
}
export class EdgeCollection extends TableCollection<Edge> {
constructor(table?: table, indices?: Uint32Array) {
constructor(table?: ColumnTable, indices?: number[]) {
super(table, 'edge', indices)
}
}

Просмотреть файл

@ -5,6 +5,7 @@
import { NodeCollection } from './TableCollection'
import { findGroupIndices } from './table'
import { table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
/**
* Gets a table of just the nodes for a matching community.
@ -20,11 +21,11 @@ import { table } from 'arquero'
*/
export function findNodesTableForCommunity(
cid: string | undefined,
byParent: table,
byCommunity: table,
byParent: ColumnTable,
byCommunity: ColumnTable,
) {
if (!cid) {
return table()
return table({})
}
const pidx = findGroupIndices(byParent, 'community.pid', cid)
@ -39,8 +40,8 @@ export function findNodesTableForCommunity(
// this is duplicative of findNodesTableForCommunity, but retaining the indices allows us to avoid reify
export function findNodesCollectionForCommunity(
cid: string | undefined,
byParent: table,
byCommunity: table,
byParent: ColumnTable,
byCommunity: ColumnTable,
) {
if (!cid) {
return new NodeCollection()
@ -60,7 +61,7 @@ export function findNodesCollectionForCommunity(
* @param pid
* @param byParent
*/
export function findNodesTableForParent(pid: string, byParent: table) {
export function findNodesTableForParent(pid: string, byParent: ColumnTable) {
const pidx = findGroupIndices(byParent, 'community.pid', pid)
return byParent.reify(pidx)
}

Просмотреть файл

@ -4,11 +4,12 @@
*/
import { NodeCollection } from './TableCollection'
import { table, op, desc } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
export function getEdgesFromTableByID(
selectedId: string,
nodeTable: table,
edges: table,
nodeTable: ColumnTable,
edges: ColumnTable,
) {
if (selectedId) {
console.log('selected id', selectedId)
@ -19,9 +20,12 @@ export function getEdgesFromTableByID(
}
// joins the community ids for edge source/target into the edge table
function joinNodeCommunities(edges: table, nodes: table): table {
function joinNodeCommunities(
edges: ColumnTable,
nodes: ColumnTable,
): ColumnTable {
if (edges.numRows() === 0) {
return table()
return table({})
}
const derived = edges
@ -36,7 +40,7 @@ function joinNodeCommunities(edges: table, nodes: table): table {
return derived
}
function hashNodeField(nodes: table, field: string) {
function hashNodeField(nodes: ColumnTable, field: string) {
const hash: any = {}
const id = nodes.getter('node.id')
const cid = nodes.getter(field)
@ -45,9 +49,13 @@ function hashNodeField(nodes: table, field: string) {
}
// for a given community, finds all the connected sibling counts via edges
function getNeighbors(selectedId: string, joined: table, nodes: table): table {
function getNeighbors(
selectedId: string,
joined: ColumnTable,
nodes: ColumnTable,
): ColumnTable {
if (joined.numRows() === 0 && nodes.numRows() === 0) {
return table()
return table({})
}
const cFiltered = joined
@ -86,7 +94,10 @@ function getNeighbors(selectedId: string, joined: table, nodes: table): table {
* @param edges
* @param nodes
*/
export function filterEdgesToNodes(edges: table, nodes: NodeCollection): table {
export function filterEdgesToNodes(
edges: ColumnTable,
nodes: NodeCollection,
): ColumnTable {
if (edges.numRows() === 0) {
return edges
}

Просмотреть файл

@ -23,6 +23,7 @@ import {
} from './table'
import { PositionMap } from '@graspologic/graph'
import { not, table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
import { useCallback, useMemo } from 'react'
import {
useHoveredCommunity,
@ -76,7 +77,7 @@ export function useArqueroAddTable() {
const setBigTable = useSetArqueroBigTable()
const setEdgeTable = useSetArqueroEdgeTable()
return useCallback(
(newTable: table, type: string) => {
(newTable: ColumnTable, type: string) => {
console.log('adding table/columns', type)
newTable.print()
let updated = bigTable
@ -153,11 +154,11 @@ export function useEdgeCount() {
return edges.numRows()
}
export function useColumnStats(table: table, field?: string) {
export function useColumnStats(table: ColumnTable, field?: string) {
return useCachedColumnStats(table, field)
}
export function useColumnHistogram(table: table, field?: string) {
export function useColumnHistogram(table: ColumnTable, field?: string) {
return useCachedColumnHistogram(table, field)
}
@ -186,7 +187,7 @@ export function useArqueroVisibleCommunities() {
.ungroup()
return filtered
}
return table()
return table({})
}, [pid, communities])
return useMemo(() => new CommunityCollection(tbl), [tbl])
}
@ -259,7 +260,7 @@ export function useTableColumnsByType(dataType: string) {
const valueTable = bigTable.select(columns)
return valueTable
}
return table()
return table({})
}
// for a list of communities, get a map of [cid]: nodepositions[]

Просмотреть файл

@ -2,6 +2,7 @@
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
export * from './communities'
export * from './hooks'
export * from './TableCollection'

Просмотреть файл

@ -3,26 +3,27 @@
* Licensed under the MIT license. See LICENSE file in the project.
*/
import { PositionMap } from '@graspologic/graph'
import { desc, table } from 'arquero'
import { desc } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
// TODO: we may want to provide fallback checks for
// position columns, in the case that arbitrary non-layout data was
// loaded by the user
function getters(table: table) {
function getters(table: ColumnTable) {
return {
id: table.getter('node.id'),
x: table.getter('node.x'),
y: table.getter('node.y'),
}
}
export function deriveLayoutPositions(table: table): PositionMap {
export function deriveLayoutPositions(table: ColumnTable): PositionMap {
const positions = {} as PositionMap
if (table.numRows() === 0) {
return positions
}
const { id, x, y } = getters(table)
table.scan((idx: number) => {
table.scan((idx: number | undefined) => {
positions[id(idx)] = {
x: x(idx),
y: y(idx),
@ -31,7 +32,7 @@ export function deriveLayoutPositions(table: table): PositionMap {
return positions
}
export function deriveSmallMultiplePositions(table: table): PositionMap {
export function deriveSmallMultiplePositions(table: ColumnTable): PositionMap {
const positions: PositionMap = {}
if (table.numRows() === 0) {
return positions
@ -46,7 +47,8 @@ export function deriveSmallMultiplePositions(table: table): PositionMap {
grouped
.count()
.orderby(desc('count'))
.scan((idx: number) => {
.scan((idx: number | undefined) => {
if (idx === undefined) return
const indices = partitions[idx]
indices.forEach((index: number) => {
positions[id(index)] = layout(cell, x(index), y(index))

Просмотреть файл

@ -1,5 +1,6 @@
// eslint-disable-next-line
import { op, table } from 'arquero'
import { op } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
export interface ArqueroNode {
['node.id']: string
@ -12,7 +13,7 @@ export interface ArqueroNode {
* @param table assumed pre-grouped table (e.g., by parent id)
* @param quantile
*/
export function getNodeStats(table: table, quantile = 1) {
export function getNodeStats(table: ColumnTable, quantile = 1) {
if (!table || table.numRows() === 0 || quantile === 1) {
return [
{

Просмотреть файл

@ -4,7 +4,8 @@
*/
import { ROOT_COMMUNITY_ID } from '../constants'
import { ColumnDef } from '../types'
import { all, not, op, table } from 'arquero'
import { all, not, op } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
/**
* Extracts the objects from a single-row table.
@ -14,7 +15,7 @@ import { all, not, op, table } from 'arquero'
*/
// TODO: this is pretty basic, but the intent would be to provide optional
// transformers per column or as a whole
export function one(table: table): { [key: string]: any } {
export function one(table: ColumnTable): { [key: string]: any } {
return table.objects()[0]
}
@ -24,7 +25,7 @@ export function one(table: table): { [key: string]: any } {
* @param prefix prefix to add to column names
* @param exclude exclusion list if you want to retain some original columns
*/
export function rename(table: table, prefix: string, exclude?: string[]) {
export function rename(table: ColumnTable, prefix: string, exclude?: string[]) {
const ex = new Set(exclude)
return table.columnNames().reduce((obj: any, name: string) => {
if (ex.has(name) || name.startsWith(prefix)) {
@ -36,11 +37,11 @@ export function rename(table: table, prefix: string, exclude?: string[]) {
}, {})
}
export function hasColumn(table: table, column: string) {
export function hasColumn(table: ColumnTable, column: string) {
return table.columnNames().some(name => name === column)
}
export function columnTypes(table: table) {
export function columnTypes(table: ColumnTable) {
if (table.numRows() === 0) {
return []
}
@ -50,7 +51,7 @@ export function columnTypes(table: table) {
}))
}
export function recomputeCommunityStats(table: table, force?: boolean) {
export function recomputeCommunityStats(table: ColumnTable, force?: boolean) {
const selected = force
? table.select(not(['community.nodeCount', 'community.childCount']))
: table
@ -70,10 +71,10 @@ export function recomputeCommunityStats(table: table, force?: boolean) {
* @param fallback
*/
function ensureColumn(
table: table,
table: ColumnTable,
name: string,
variants: string[],
fallback: (table: table) => table,
fallback: (table: ColumnTable) => ColumnTable,
) {
if (hasColumn(table, name)) {
return table
@ -97,7 +98,7 @@ function ensureColumn(
* In the worst case, we select the first column.
* @param table
*/
function ensureNodeId(table: table) {
function ensureNodeId(table: ColumnTable) {
return ensureColumn(table, 'node.id', ['id', 'ID', 'nodeId'], table => {
// just pick the first - this is risky, but sometimes we don't have a header at all
const column = table.columnNames()[0]
@ -113,7 +114,7 @@ function ensureNodeId(table: table) {
* present we just default to '0' as an id
* @param table
*/
function ensureCommunityId(table: table) {
function ensureCommunityId(table: ColumnTable) {
return ensureColumn(
table,
'community.id',
@ -126,7 +127,7 @@ function ensureCommunityId(table: table) {
)
}
function ensureParentCommunityId(table: table) {
function ensureParentCommunityId(table: ColumnTable) {
return ensureColumn(
table,
'community.pid',
@ -146,7 +147,7 @@ function ensureParentCommunityId(table: table) {
// TEMP: make sure there are no empties, which some csvs have
// use our -1 default.
// TODO: use empty as default instead of -1, which need broader refactor
function fixPid(table: table) {
function fixPid(table: ColumnTable) {
return table
.params({
pid: ROOT_COMMUNITY_ID,
@ -156,7 +157,7 @@ function fixPid(table: table) {
})
}
function ensureX(table: table) {
function ensureX(table: ColumnTable) {
return ensureColumn(table, 'node.x', ['x', 'X'], table => {
return table.derive({
'node.x': () => Math.random(),
@ -164,7 +165,7 @@ function ensureX(table: table) {
})
}
function ensureY(table: table) {
function ensureY(table: ColumnTable) {
return ensureColumn(table, 'node.y', ['y', 'Y'], table => {
return table.derive({
'node.y': () => Math.random(),
@ -172,7 +173,7 @@ function ensureY(table: table) {
})
}
function ensureD(table: table) {
function ensureD(table: ColumnTable) {
return ensureColumn(table, 'node.d', ['d', 'D', 'size', 'weight'], table => {
return table.derive({
'node.d': () => 1,
@ -180,7 +181,7 @@ function ensureD(table: table) {
})
}
function ensureNodeLabel(table: table) {
function ensureNodeLabel(table: ColumnTable) {
return ensureColumn(table, 'node.label', ['label', 'name'], table => {
return table.derive({
'node.label': (d: any) => d['node.id'],
@ -188,7 +189,7 @@ function ensureNodeLabel(table: table) {
})
}
function ensureEdgeSource(table: table) {
function ensureEdgeSource(table: ColumnTable) {
return ensureColumn(table, 'edge.source', ['source', 'src'], table => {
return table.derive({
'edge.source': () => '0',
@ -196,7 +197,7 @@ function ensureEdgeSource(table: table) {
})
}
function ensureEdgeTarget(table: table) {
function ensureEdgeTarget(table: ColumnTable) {
return ensureColumn(table, 'edge.target', ['target', 'tgt'], table => {
return table.derive({
'edge.target': () => '1',
@ -204,7 +205,7 @@ function ensureEdgeTarget(table: table) {
})
}
function ensureEdgeWeight(table: table) {
function ensureEdgeWeight(table: ColumnTable) {
return ensureColumn(table, 'edge.weight', ['weight', 'value'], table => {
return table.derive({
'edge.weight': () => 1,
@ -212,7 +213,7 @@ function ensureEdgeWeight(table: table) {
})
}
function ensureEdgeId(table: table) {
function ensureEdgeId(table: ColumnTable) {
return ensureColumn(table, 'edge.id', ['id', 'edgeId'], table => {
return table.derive({
'edge.id': (d: any) => `${d['edge.source']}-${d['edge.target']}`,
@ -221,7 +222,7 @@ function ensureEdgeId(table: table) {
}
// normalizes x and y in a single operation because we need to maintain aspect ratio
export function normalizeXY(table: table) {
export function normalizeXY(table: ColumnTable) {
const bounds = table.rollup({
xMin: op.min('node.x'),
xMax: op.max('node.x'),
@ -246,7 +247,7 @@ export function normalizeXY(table: table) {
})
}
function normalizeD(table: table) {
function normalizeD(table: ColumnTable) {
// for the node size, the range should always be positive
// we usually specify a minimum of 5 in the files - we do
// not want those going to 0 once normalized, so here we
@ -271,7 +272,7 @@ const prefixes = {
// our current "data model" expects every column to have a type prefix
// used for filtering views, etc.
// this will find any unprefixed columns and add the specified one to them
function prefixRemaining(table: table, prefix: string) {
function prefixRemaining(table: ColumnTable, prefix: string) {
const columns = table.columnNames(name => {
const pref = name.split('.')[0]
return !prefixes[pref]
@ -289,7 +290,10 @@ function prefixRemaining(table: table, prefix: string) {
* @param table
* @param functions
*/
export function chain(table: table, functions: ((table: table) => table)[]) {
export function chain(
table: ColumnTable,
functions: ((table: ColumnTable) => ColumnTable)[],
) {
return functions.reduce((acc, cur) => cur(acc), table)
}
@ -298,7 +302,7 @@ export function chain(table: table, functions: ((table: table) => table)[]) {
* @param table
* @param type
*/
export function initializeNodeTable(table: table, fromEdges = false) {
export function initializeNodeTable(table: ColumnTable, fromEdges = false) {
const starter = fromEdges
? table
.fold(['source', 'target'])
@ -323,11 +327,11 @@ export function initializeNodeTable(table: table, fromEdges = false) {
])
}
export function initializeJoinTable(table: table) {
export function initializeJoinTable(table: ColumnTable) {
return chain(table, [ensureNodeId, ensureCommunityId])
}
export function initializeEdgeTable(table: table) {
export function initializeEdgeTable(table: ColumnTable) {
return chain(table, [
ensureEdgeSource,
ensureEdgeTarget,
@ -337,14 +341,17 @@ export function initializeEdgeTable(table: table) {
])
}
export function initializeCommunityTable(table: table) {
export function initializeCommunityTable(table: ColumnTable) {
return chain(table, [
ensureCommunityId,
table => prefixRemaining(table, 'community'),
])
}
export function joinNodeCommunityTables(nodes: table, communities: table) {
export function joinNodeCommunityTables(
nodes: ColumnTable,
communities: ColumnTable,
) {
const leftKey = 'node.id'
const rightKey = 'node.id'
@ -379,8 +386,8 @@ export function joinNodeCommunityTables(nodes: table, communities: table) {
* @param rightKey
*/
export function joinWithReplace(
left: table,
right: table,
left: ColumnTable,
right: ColumnTable,
joinDefinition: any,
) {
return left.join(right, joinDefinition, [not(right.columnNames()), all()])
@ -397,8 +404,8 @@ export function joinWithReplace(
* @param rightKey optional explicit right key, otherwise it will use 'id'
*/
export function joinDataTables(
left: table,
right: table,
left: ColumnTable,
right: ColumnTable,
type: string,
leftKey?: string,
rightKey = 'id',
@ -420,8 +427,8 @@ export function joinDataTables(
// and (b) auto-generate an incremental id if none appears present
const toMerge = right
// rename all new columns with their prefix except the id
.select((table: table) => rename(table, `${type}.`, [rightKey]))
.select((table: table) => table.columnNames(filter))
.select((table: ColumnTable) => rename(table, `${type}.`, [rightKey]))
.select((table: ColumnTable) => table.columnNames(filter))
return left.join(toMerge, [joinKey, rightKey], [all(), not(rightKey)])
}
@ -430,7 +437,7 @@ export function joinDataTables(
* @param main current fully-populated table with joined communities
* @param communities flat community list to rollup childCount
*/
export function checkAndAddChildCount(main: table) {
export function checkAndAddChildCount(main: ColumnTable) {
if (hasColumn(main, 'community.childCount')) {
return main
}
@ -458,7 +465,7 @@ export function checkAndAddChildCount(main: table) {
* This checks the main table for a community.nodeCount column and computes if missing
* @param main current fully-populated table with joined communities
*/
export function checkAndAddNodeCount(main: table) {
export function checkAndAddNodeCount(main: ColumnTable) {
if (hasColumn(main, 'community.nodeCount')) {
return main
}
@ -477,7 +484,7 @@ export function checkAndAddNodeCount(main: table) {
* @param readOnlyNames
*/
export function listColumnDefs(
table: table,
table: ColumnTable,
readOnlyNames?: Set<string>,
): ColumnDef[] {
if (table.numRows() === 0) {
@ -491,12 +498,16 @@ export function listColumnDefs(
}))
}
export function listColumnNames(table: table): string[] {
export function listColumnNames(table: ColumnTable): string[] {
const defs = listColumnDefs(table)
return defs.map(d => d.name)
}
export function findGroupIndices(table: table, field: string, value: any) {
export function findGroupIndices(
table: ColumnTable,
field: string,
value: any,
) {
if (table.numRows() > 0) {
const groups = table.groups()
const index = groups.rows.findIndex(

Просмотреть файл

@ -7,10 +7,11 @@ import { TableCollection } from './TableCollection'
import { one } from './table'
import { histogram, Histogram } from '@essex-js-toolkit/toolbox'
// eslint-disable-next-line
import { op, table } from 'arquero'
import { op } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
import { precisionFixed } from 'd3-format'
export function getColumnStats(table: table, name?: string): ColumnStats {
export function getColumnStats(table: ColumnTable, name?: string): ColumnStats {
if (!table || table.numRows() === 0 || table.numCols() === 0 || !name) {
return {
dataType: '',
@ -32,7 +33,7 @@ export function getColumnStats(table: table, name?: string): ColumnStats {
q05: op.quantile(name, 0.05),
q95: op.quantile(name, 0.95),
q99: op.quantile(name, 0.99),
unique: op.unique(name),
unique: op.array_agg_distinct(name),
}),
)
@ -62,7 +63,10 @@ function checkWhole(numbers?: number[]): boolean {
return numbers.every(n => Number.isInteger(n))
}
export function getColumnHistogram(table: table, name?: string): Histogram {
export function getColumnHistogram(
table: ColumnTable,
name?: string,
): Histogram {
if (!table || table.numRows() === 0 || !name) {
return []
}
@ -83,7 +87,7 @@ export function getColumnHistogram(table: table, name?: string): Histogram {
* @param table
* @param column
*/
export function binTableColumn(table: table, column: string): any[] {
export function binTableColumn(table: ColumnTable, column: string): any[] {
const quantileOps = new Array(100).fill(1).reduce((acc, cur, idx) => {
acc[idx] = op.quantile(column, idx / 100)
return acc
@ -113,7 +117,7 @@ export function binTableColumn(table: table, column: string): any[] {
})
// fill the bins
table.scan((idx: number) => {
table.scan((idx: number | undefined) => {
const value = table.get(column, idx)
const binIndex = bins.findIndex(bin => value >= bin.x0 && value < bin.x1)
// bin maxes are exclusive except for the last bin

Просмотреть файл

@ -50,5 +50,4 @@ const Main = styled.div`
height: 100%;
width: 100%;
flex-direction: column;
align-items: center;
`

Просмотреть файл

@ -41,14 +41,6 @@ export function useTestFiles(bundle: FileBundle) {
const files: FileBundle = {}
const [nodesTable, joinTable, communitiesTable, edgesTable] =
await Promise.all([
nodesFile?.url && fetchUrl(nodesFile.url),
joinFile?.url && fetchUrl(joinFile.url),
communitiesFile?.url && fetchUrl(communitiesFile.url),
edgesFile?.url && fetchUrl(edgesFile.url),
])
let nodes
let edges
@ -57,6 +49,7 @@ export function useTestFiles(bundle: FileBundle) {
// note that the order of nodes -> join -> communities -> edges is *required* to layer properly
if (nodesFile) {
console.log('loading nodes file from url', nodesFile.url)
const nodesTable = await fetchUrl(nodesFile.url)
console.time('nodes')
nodes = initializeNodeTable(nodesTable)
files.nodes = {
@ -68,6 +61,7 @@ export function useTestFiles(bundle: FileBundle) {
}
if (joinFile) {
console.log('loading join file from url', joinFile.url)
const joinTable = await fetchUrl(joinFile.url)
console.time('join')
const join = initializeJoinTable(joinTable)
files.join = {
@ -82,6 +76,7 @@ export function useTestFiles(bundle: FileBundle) {
}
if (communitiesFile) {
console.log('loading communities file from url', communitiesFile.url)
const communitiesTable = await fetchUrl(communitiesFile.url)
console.time('communities')
files.communities = {
...communitiesFile,
@ -95,6 +90,7 @@ export function useTestFiles(bundle: FileBundle) {
}
if (edgesFile) {
console.log('loading edges file from url', edgesFile.url)
const edgesTable = await fetchUrl(edgesFile.url)
console.time('edges')
edges = initializeEdgeTable(edgesTable)
files.edges = {

Просмотреть файл

@ -99,7 +99,7 @@ export const LeftSidePanel: React.FC<LeftSidePanelProps> = memo(
</Text>
</HeaderLabel>
<CommunityPanelContainer tabIndex={0} style={communityPanelStyle}>
{<CommunityPanel />}
<CommunityPanel />
</CommunityPanelContainer>
</CommunityContainer>
{miniMap}

Просмотреть файл

@ -4,7 +4,8 @@
*/
import { UmapLayout } from './UmapLayout'
import { DefaultButton, Spinner, Toggle } from '@fluentui/react'
import { all, not, table } from 'arquero'
import { all, not } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
import { memo, useCallback, useState } from 'react'
import styled from 'styled-components'
import {
@ -27,7 +28,7 @@ export const Layout: React.FC = memo(function Layout() {
const performLayout = useCallback(
(type: LayoutType) => {
console.log('performing layout', type)
const finalize = (table: table) => {
const finalize = (table: ColumnTable) => {
console.log('layout complete', type)
table.print()
const merged = nodes.join(

Просмотреть файл

@ -70,22 +70,27 @@ export const SearchItems: React.FC<SearchItemsProps> = ({
setSelectedCommunity('-1')
} else {
if (searchNodeTable) {
const key = searchNodeTable.getter('node.id')
let found
const cols = listColumnDefs(searchNodeTable.table)
searchNodeTable.scan((idx: number, data: any, stop: () => void) => {
const id = key(idx)
if (nodeid === id && !found) {
const obj = cols.reduce((acc, col) => {
const accessor = searchNodeTable.getter(col.name)
const val = accessor(idx)
acc[col.name] = val
return acc
}, {})
found = obj
stop()
}
}, true)
searchNodeTable.scan(
(
idx: number | undefined,
data: any,
stop: (() => void) | undefined,
) => {
const id = data['node.id'].get(idx)
if (nodeid === id && !found) {
const obj = cols.reduce((acc, col) => {
const val = data[col.name].get(idx)
acc[col.name] = val
return acc
}, {})
found = obj
stop && stop()
}
},
true,
)
if (found) {
const commId = found['community.id']
if (commId) {

Просмотреть файл

@ -16,7 +16,8 @@ import {
import { SearchItems } from './SearchItems'
import { SearchPanelHeader } from './SearchPanelHeader'
import { CollapsiblePanel } from '@essex-js-toolkit/themed-components'
import { op, table } from 'arquero'
import { useDebounceFn } from 'ahooks'
import { op } from 'arquero'
import { useCallback, useState, useMemo } from 'react'
import styled from 'styled-components'
@ -37,6 +38,7 @@ export const SearchPanel: React.FC = () => {
const [isExpanded, setIsExpanded] = useState<boolean>(false)
const [errorMsg, setErrorMsg] = useState<string | undefined>()
const [isInFocus, setIsInFocus] = useState<boolean>(false)
const [isSearching, setIsSearching] = useState<boolean>(false)
const setSelectedNode = useSetSelectedNodes()
const modifiedTable = useTableColumnsByType('string')
const columns = listColumnNames(modifiedTable)
@ -60,24 +62,27 @@ export const SearchPanel: React.FC = () => {
const setSelectedCommunity = useSetSelectedCommunity()
const getColumnByRow = useCallback(
(col, row): [string, boolean] => {
(col, row, searchValue): [string, boolean] => {
const stringValue = modifiedTable.get(col, row)
let isInSearch = false
if (stringValue.indexOf(searchText) > -1) {
if (stringValue.indexOf(searchValue) > -1) {
isInSearch = true
}
return [stringValue, isInSearch]
},
[modifiedTable, searchText],
[modifiedTable],
)
const getMatchingValuesByRow = useCallback(
(columns: string[]): [table, table] => {
(
columns: string[],
searchValue: string,
): [CommunityCollection, NodeCollection] => {
const matches: SearchByIndex[] = []
modifiedTable.scan(row => {
const o = columns.reduce(
(acc, col) => {
const [value, isInSearch] = getColumnByRow(col, row)
const [value, isInSearch] = getColumnByRow(col, row, searchValue)
if (isInSearch) {
acc.isInSearch = true
acc.matchColumns.push(col)
@ -114,15 +119,15 @@ export const SearchPanel: React.FC = () => {
)
const matchTable = communities
.params({ match: communityIds })
.filter((d: any, $: any) => op.includes($.match, d['community.id']))
.filter((d: any, $: any) => op.includes($.match, d['community.id'], 0))
.ungroup()
const nodeMatchTable = modifiedTable
.params({ match: Array.from(nodeids), commIds: nodeCommIds })
.filter(
(d: any, $: any) =>
op.includes($.match, d['node.id']) &&
op.includes($.commIds, d['community.id']),
op.includes($.match, d['node.id'], 0) &&
op.includes($.commIds, d['community.id'], 0),
)
.ungroup()
const ccTable = new CommunityCollection(matchTable)
@ -151,36 +156,70 @@ export const SearchPanel: React.FC = () => {
setIsExpanded,
])
const onSearch = useCallback(() => {
if (!searchText) {
onClear()
} else {
setErrorMsg(undefined)
if (columns.length > 0) {
// filter out community.pid, need to figure out properly display if we choose to include it
const cols = columns.filter(d => d !== 'community.pid')
const [matchTable, matchingValues] = getMatchingValuesByRow(cols)
if (matchingValues.size < 1) {
setErrorMsg(`No results found for ${searchText}`)
}
setIsExpanded(true)
setSearchTable(matchTable)
setSearchNodeTable(matchingValues)
const useSearchDebounce = useDebounceFn(
(searchValue: string) => {
searchByText(searchValue)
},
{
wait: 10, //wait to search to show spinner
},
)
const searchByText = useCallback(
(searchValue: string) => {
// filter out community.pid, need to figure out properly display if we choose to include it
const cols = columns.filter(d => d !== 'community.pid')
const [matchTable, matchingValues] = getMatchingValuesByRow(
cols,
searchValue,
)
if (matchingValues.size < 1) {
setErrorMsg(`No results found for ${searchText}`)
}
}
}, [
searchText,
columns,
setSearchNodeTable,
onClear,
getMatchingValuesByRow,
setSearchTable,
setErrorMsg,
setIsExpanded,
])
setIsExpanded(true)
setSearchTable(matchTable)
setSearchNodeTable(matchingValues)
setIsSearching(false)
},
[
searchText,
columns,
setSearchNodeTable,
getMatchingValuesByRow,
setSearchTable,
setErrorMsg,
setIsExpanded,
setIsSearching,
],
)
const onSearch = useCallback(
(searchValue?: string) => {
if (!searchText && !searchValue) {
onClear()
} else {
if (!searchValue) {
searchValue = searchText as string
}
setErrorMsg(undefined)
if (columns.length > 0) {
setIsSearching(true)
useSearchDebounce.run(searchValue)
}
}
},
[
searchText,
columns,
onClear,
setErrorMsg,
setIsSearching,
useSearchDebounce,
],
)
const onChange = useCallback(
(event?: React.ChangeEvent<HTMLInputElement>, newValue?: string): any => {
(newValue: string): any => {
setSearchText(newValue)
},
[setSearchText],
@ -196,9 +235,10 @@ export const SearchPanel: React.FC = () => {
onSearch={onSearch}
onClear={onClear}
onFocusChange={onFocusChange}
isSearching={isSearching}
/>
),
[disabled, onClear, onChange, onSearch, onFocusChange],
[disabled, onClear, onChange, onSearch, onFocusChange, isSearching],
)
return (

Просмотреть файл

@ -2,7 +2,7 @@
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
import { SearchBox, IconButton } from '@fluentui/react'
import { SearchBox, IconButton, Spinner, SpinnerSize } from '@fluentui/react'
import { useDebounceFn } from 'ahooks'
import { useCallback } from 'react'
import styled from 'styled-components'
@ -21,13 +21,11 @@ const searchIcon = { iconName: 'Search' }
interface SearchPanelHeaderProps {
disabled: boolean
onChange: (
event?: React.ChangeEvent<HTMLInputElement>,
newValue?: string,
) => any
onChange: (newValue: string) => any
onClear: () => void
onSearch: () => void
onSearch: (searchValue?: string) => void
onFocusChange: (state: boolean) => void
isSearching: boolean
}
export const SearchPanelHeader = ({
disabled,
@ -35,13 +33,14 @@ export const SearchPanelHeader = ({
onSearch,
onClear,
onFocusChange,
isSearching,
}: SearchPanelHeaderProps) => {
const focusCallback = useCallback(() => onFocusChange(true), [onFocusChange])
const blurCallback = useCallback(() => onFocusChange(false), [onFocusChange])
const useDebounce = useDebounceFn(
(event, newValue) => {
onChange(event, newValue)
newValue => {
onChange(newValue)
},
{
wait: 500,
@ -55,23 +54,24 @@ export const SearchPanelHeader = ({
styles={searchBoxStyle}
disabled={disabled}
onChange={(
event?: React.ChangeEvent<HTMLInputElement>,
_?: React.ChangeEvent<HTMLInputElement>,
newValue?: string,
) => useDebounce.run(event, newValue)}
) => useDebounce.run(newValue)}
onClear={onClear}
onSearch={onSearch}
onSearch={(value: string) => onSearch(value)}
onFocus={focusCallback}
onBlur={blurCallback}
/>
<IconButton
iconProps={searchIcon}
iconProps={!isSearching ? searchIcon : {}}
styles={searchButtonStyle}
title="Search"
ariaLabel={'Search'}
disabled={disabled}
onClick={onSearch}
/>
onClick={() => onSearch()}
>
{isSearching && <Spinner size={SpinnerSize.xSmall} />}
</IconButton>
</Label>
)
}

Просмотреть файл

@ -44,7 +44,7 @@ export const FileList: React.FC = () => {
<DefaultButton text="Clear all" onClick={handleResetClick} />
) : null}
</Reset>
{selectedFile ? (
{selectedFile && selectedFile.table ? (
<Viewer>
<h3>{selectedFile.url}</h3>
<ArqueroTable table={selectedFile?.table} options={{ limit: 10 }} />

Просмотреть файл

@ -9,17 +9,19 @@ import styled from 'styled-components'
export const Footer: FC = memo(function Footer() {
return (
<FooterEl>
<Link href={constants.privacyUrl}>Privacy</Link>
{' | '}
<Link id={'managecookies'} onClick={manageConsent}>
Cookies
</Link>
{' | '}
<Link href={constants.termsOfUseUrl}>Terms of Use</Link>
{' | '}
<Link href={constants.trademarksUrl}>Trademarks</Link>
{' | '}
<Link href={constants.microsoft}>{constants.copyright}</Link>
<Container>
<Link href={constants.privacyUrl}>Privacy</Link>
{' | '}
<Link id={'managecookies'} onClick={manageConsent}>
Cookies
</Link>
{' | '}
<Link href={constants.termsOfUseUrl}>Terms of Use</Link>
{' | '}
<Link href={constants.trademarksUrl}>Trademarks</Link>
{' | '}
<Link href={constants.microsoft}>{constants.copyright}</Link>
</Container>
</FooterEl>
)
})
@ -50,6 +52,10 @@ const Link: FC<{
})
const FooterEl = styled.footer`
width: 100%;
`
const Container = styled.div`
width: 500px;
height: 20px;
font-size: 12px;
@ -58,6 +64,7 @@ const FooterEl = styled.footer`
align-items: center;
align-content: center;
justify-content: space-between;
margin: auto;
`
const constants = {

Просмотреть файл

@ -12,7 +12,8 @@ import {
IHierarchyDataResponse,
IHierarchyNeighborResponse,
} from '@essex-js-toolkit/hierarchy-browser'
import { table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
import { TableData } from 'arquero/dist/types/table/table'
import { useMemo } from 'react'
import {
findNodesCollectionForCommunity,
@ -79,13 +80,13 @@ function nodeColumns(
export function useEntityCallback(): (
loadParams: ILoadParams,
byParent: table,
byCommunity: table,
byParent: ColumnTable,
byCommunity: ColumnTable,
) => Promise<IHierarchyDataResponse> {
async function handleEntityCallback(
loadParams: ILoadParams,
byParent: table,
byCommunity: table,
byParent: ColumnTable,
byCommunity: ColumnTable,
): Promise<IHierarchyDataResponse> {
const cid = loadParams.communityId
const selectedNeighbor = findNodesCollectionForCommunity(
@ -101,13 +102,13 @@ export function useEntityCallback(): (
export function useNeighborCallback(): (
params: ILoadParams,
nodeTable: table,
edges: table,
nodeTable: ColumnTable,
edges: ColumnTable,
) => Promise<IHierarchyNeighborResponse> {
const handleNeighborCallback = async function (
params: ILoadParams,
nodeTable: table,
edges: table,
nodeTable: ColumnTable,
edges: ColumnTable,
): Promise<IHierarchyNeighborResponse> {
const neighborTable = getEdgesFromTableByID(
params.communityId,
@ -132,7 +133,7 @@ export function useNeighborCallback(): (
return handleNeighborCallback
}
function getNeighborIds(counts: table, communityId: string) {
function getNeighborIds(counts: ColumnTable, communityId: string) {
if (counts.numRows() > 0) {
// scan the edge counts table to create a few table rows
const max = Math.min(100, counts.numRows())
@ -140,22 +141,29 @@ function getNeighborIds(counts: table, communityId: string) {
const key = counts.getter('key')
const count = counts.getter('count')
const membership = counts.getter('members')
counts.scan((idx: number, data: any, stop: () => void) => {
const k = key(idx)
const c = count(idx)
const size = membership(idx)
if (communityId !== k) {
output.push({
communityId: k,
connections: c,
edgeCommunityId: communityId,
size,
} as INeighborCommunityDetail)
}
if (output.length > max) {
stop()
}
}, true)
counts.scan(
(
idx?: number | undefined,
data?: TableData | any[] | undefined,
stop?: (() => void) | undefined,
) => {
const k = key(idx)
const c = count(idx)
const size = membership(idx)
if (communityId !== k) {
output.push({
communityId: k,
connections: c,
edgeCommunityId: communityId,
size,
} as INeighborCommunityDetail)
}
if (output.length > max) {
stop && stop()
}
},
true,
)
return output
}
return []

Просмотреть файл

@ -8,7 +8,7 @@ import { NumericDomainEditor } from '../NumericDomainEditor'
import { ColorSelectorProps } from './types'
import { Dropdown } from '@fluentui/react'
import { ScaleDropdown } from '@thematic/fluent'
import { table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
import { useCallback, useMemo } from 'react'
import styled from 'styled-components'
@ -72,7 +72,7 @@ export const ScaledPicker: React.FC<ColorSelectorProps> = ({
)
}
function useFieldDropdownOptions(table: table) {
function useFieldDropdownOptions(table: ColumnTable) {
return useMemo(() => {
return table.columnNames().map(key => ({
key,

Просмотреть файл

@ -3,14 +3,14 @@
* Licensed under the MIT license. See LICENSE file in the project.
*/
import { ColorEncoding } from '../../types'
import { table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
export interface ColorSelectorProps {
/**
* table the encoding will be binding to, so we can lookup stats
* or column names as needed
*/
table: table
table: ColumnTable
encoding: ColorEncoding
onChange: (encoding: Partial<ColorEncoding>) => void
}

Просмотреть файл

@ -7,7 +7,7 @@ import { DomainBrush } from '../DomainBrush'
import { Label } from '@fluentui/react'
import { ScaleType } from '@thematic/core'
import { ScaleTypeChoiceGroup } from '@thematic/fluent'
import { table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
import { format } from 'd3-format'
import { useCallback, useMemo } from 'react'
import styled from 'styled-components'
@ -18,7 +18,7 @@ export interface NumericDomainEditorProps {
* table the encoding will be binding to, so we can lookup stats
* or column names as needed
*/
table: table
table: ColumnTable
encoding: Encoding
onChange: (encoding: Partial<Encoding>) => void
}

Просмотреть файл

@ -6,7 +6,7 @@ import { NumericDomainEditor } from '../NumericDomainEditor'
import { NumericRangeEditor } from '../NumericRangeEditor'
import { NumericSelectorProps } from './types'
import { Dropdown } from '@fluentui/react'
import { table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
import { useCallback, useMemo } from 'react'
import styled from 'styled-components'
import { columnTypes } from '~/arquero'
@ -63,7 +63,7 @@ export const ScaledPicker: React.FC<NumericSelectorProps> = ({
}
// for opacity, we can only allow numeric bindings
function useFieldDropdownOptions(table: table) {
function useFieldDropdownOptions(table: ColumnTable) {
return useMemo(() => {
const types = columnTypes(table)
return types

Просмотреть файл

@ -3,14 +3,14 @@
* Licensed under the MIT license. See LICENSE file in the project.
*/
import { NumericEncoding } from '../../types'
import { table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
export interface NumericSelectorProps {
/**
* table the encoding will be binding to, so we can lookup stats
* or column names as needed
*/
table: table
table: ColumnTable
encoding: NumericEncoding
onChange: (encoding: Partial<NumericEncoding>) => void
label?: string

Просмотреть файл

@ -4,7 +4,8 @@
*/
import { GraphContainer } from '@graspologic/graph'
import { LayoutWorkerManager } from '@graspologic/layout-core'
import { from, table } from 'arquero'
import { from } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
import { ArqueroNode, normalizeXY } from '~/arquero'
function getFa2Worker() {
@ -13,7 +14,7 @@ function getFa2Worker() {
}
// this gets the nodes + edges ready for the graspologic layout worker
function prepGraph(edgeTable: table, nodeTable?: table) {
function prepGraph(edgeTable: ColumnTable, nodeTable?: ColumnTable) {
// edgeTable should just be source + target cols, plus optional weight
// derive a weight if needed, and then extract individual nodes
const edges: any = []
@ -82,7 +83,11 @@ function postProcessLayout(graph: GraphContainer) {
* @param nodes - optional, will be derived from edge list if necessary
* @param options - addl layout worker options
*/
export async function layoutFa2(edges: table, nodes?: table, options?: any) {
export async function layoutFa2(
edges: ColumnTable,
nodes?: ColumnTable,
options?: any,
) {
console.time('layout-fa2')
const graph = prepGraph(edges, nodes)

Просмотреть файл

@ -2,7 +2,8 @@
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
import { table, op } from 'arquero'
import { op } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
import { normalizeXY } from '~/arquero'
/**
@ -11,7 +12,7 @@ import { normalizeXY } from '~/arquero'
* as it will consolidate blocks of color in strips.
* @param nodes
*/
export async function layoutGrid(nodes: table): Promise<table> {
export async function layoutGrid(nodes: ColumnTable): Promise<ColumnTable> {
return new Promise(resolve => {
const ranked = nodes
.params({

Просмотреть файл

@ -7,7 +7,7 @@ import { layoutGrid } from './grid'
import { layoutRandom } from './random'
import { Layout } from './types'
import { layoutUmap } from './umap'
import { table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
export * from './fa2'
export * from './grid'
@ -25,18 +25,18 @@ export * from './types'
*/
export async function executeLayout(
type: Layout,
nodes?: table,
edges?: table,
nodes?: ColumnTable,
edges?: ColumnTable,
options?: any,
) {
switch (type) {
case Layout.Random:
return layoutRandom(nodes)
return nodes && layoutRandom(nodes)
case Layout.Grid:
return layoutGrid(nodes)
return nodes && layoutGrid(nodes)
case Layout.FA2:
return layoutFa2(edges, nodes, options)
return edges && layoutFa2(edges, nodes, options)
case Layout.UMAP:
return layoutUmap(edges)
return edges && layoutUmap(edges)
}
}

Просмотреть файл

@ -2,12 +2,12 @@
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
import { table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
/**
* Randomly assign x/y positions to a table of nodes
* @param table
*/
export async function layoutRandom(nodes: table): Promise<table> {
export async function layoutRandom(nodes: ColumnTable): Promise<ColumnTable> {
return new Promise(resolve => {
resolve(
nodes.derive({

Просмотреть файл

@ -4,13 +4,14 @@
*/
import { umapLayout } from '../api'
import { EdgeCollection, normalizeXY } from '../arquero'
import { from, table } from 'arquero'
import { from } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
/**
* Runs our autolayout umap - note that this mostly just thunks over to the web service.
* @param edges
*/
export async function layoutUmap(edges: table) {
export async function layoutUmap(edges: ColumnTable) {
const positions = await umapLayout(new EdgeCollection(edges))
const transformed = positions.map(n => ({
'node.id': n.id,

94
src/modules.d.ts поставляемый
Просмотреть файл

@ -1,94 +0,0 @@
import { Theme } from '@thematic/core'
import 'styled-components'
declare module 'styled-components' {
export interface DefaultTheme extends Theme {}
}
declare module 'arquero' {
interface GroupBySpecification {
names: string[]
get: any[]
rows: number[]
size: number
keys: Uint32Array
}
interface table {
// table meta
numCols: () => number
numRows: () => number
totalRows: () => number
isFiltered: () => boolean
isGrouped: () => boolean
isOrdered: () => boolean
groups: () => GroupBySpecification
params: (params?: any) => table | any
// table columns
columnNames: (filter?: any) => string[]
// verbs
// https://uwdata.github.io/arquero/api/verbs
derive: (values: any) => table
filter: (criteria: any) => table
groupby: (keys: any) => table
ungroup: () => table
orderby: (keys: any) => table
unorder: () => table
rollup: (values: any) => table
count: (options?: any) => table
sample: (size: number, options?: any) => table
select: (...values: any) => table
reify: (indices?: number[]) => table
// join verbs
join: (other: table, on?: any, values?: any, options?: any) => table
join_left: (other: table, on?: any, values?: any, options?: any) => table
join_right: (other: table, on?: any, values?: any, options?: any) => table
lookup: (other: table, on?: any, values?: any) => table
semijoin: (other: table, on?: any) => table
concat: (other: table | table[]) => table
// reshape verbs
fold: (values: any, options?: any) => table
pivot: (keys: any, values?: any, options?: any) => table
unroll: (values: any, options?: any) => table
// set verbs
dedupe: (values: any) => table
// table values
data: () => any
get: (name: string, row: number) => any
getter: (name: string) => any
indices: (order?: boolean) => Uint32Array
partitions: (order?: boolean) => Uint32Array[]
scan: (
callback: (row: number, data: any, stop: () => void) => void,
order?: boolean,
) => void
// output
objects(options?: any): any[]
print(options?: any): void
}
function table(): table
function from(objects: any): table
function fromCSV(text: string, options?: any): table
function not(args?: any): any
function all(args?: any): any
function desc(args?: any): any
const op = {
count: () => any,
min: (field: string) => any,
max: (field: string) => any,
quantile: (field: string, p: number) => any,
values: (field: string) => any,
unique: (field: string) => any,
sum: (value: any) => any,
any: (field: string) => any,
has: (obj: any, property: string) => any,
// window functions
ntile: (num: number) => any,
rank: () => any,
row_number: () => any,
cume_dist: () => any,
}
}

Просмотреть файл

@ -11,7 +11,7 @@ import { settingsState } from './settings'
import { communityNodesTableState, edgeTableState } from './tables'
import { edgesVisibleState } from './vis'
import { GraphContainer } from '@graspologic/graph'
import { table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
import { useEffect } from 'react'
import {
atom,
@ -125,7 +125,7 @@ export function useVisibleNodeMap(cid: string) {
// generate a unique key for storing cached values related to a table
// warning: this isn't entirely guaranteed to be unique, but should
// cover any expected scenarios we encounter (right?)
function tableKey(table: table) {
function tableKey(table: ColumnTable) {
return `${table.columnNames().join('-')}-${table.numRows()}`
}
@ -134,7 +134,7 @@ const cachedColumnStatsState = atomFamily<ColumnStats | undefined, string>({
default: undefined,
})
export function useCachedColumnStats(table: table, field?: string) {
export function useCachedColumnStats(table: ColumnTable, field?: string) {
const key = `${tableKey(table)}-${field}`
const [cached, setCached] = useRecoilState(cachedColumnStatsState(key))
useEffect(() => {
@ -151,7 +151,7 @@ const cachedColumnHistogramState = atomFamily<any[] | undefined, string>({
default: undefined,
})
export function useCachedColumnHistogram(table: table, field?: string) {
export function useCachedColumnHistogram(table: ColumnTable, field?: string) {
const key = `${tableKey(table)}-${field}`
const [cached, setCached] = useRecoilState(cachedColumnHistogramState(key))
useEffect(() => {

Просмотреть файл

@ -3,6 +3,7 @@
* Licensed under the MIT license. See LICENSE file in the project.
*/
import { table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
import {
atom,
selector,
@ -13,9 +14,9 @@ import {
} from 'recoil'
import { findNodesTableForCommunity, getNodeStats } from '~/arquero'
export const bigTableState = atom<table>({
export const bigTableState = atom<ColumnTable>({
key: 'big-table',
default: table(),
default: table({}),
// this is required so that arquero can update indexes under the hood
dangerouslyAllowMutability: true,
})
@ -33,14 +34,14 @@ export function useResetBigTable() {
}
// keep ahold of a pre-grouped copy of the big table,
// because all of our interactions are based around communities
const groupedCommunitiesTableState = selector<table>({
const groupedCommunitiesTableState = selector<ColumnTable>({
key: 'grouped-community-table',
dangerouslyAllowMutability: true,
get: ({ get }) => {
console.log('deriving pre-grouped community table')
const bigTable = get(bigTableState)
if (bigTable.numRows() === 0) {
return table()
return table({})
}
console.time('groupby community state')
const grouped = bigTable.groupby('community.id')
@ -53,14 +54,14 @@ export function useGroupedByCommunityTable() {
return useRecoilValue(groupedCommunitiesTableState)
}
export const groupedParentsTableState = selector<table>({
export const groupedParentsTableState = selector<ColumnTable>({
key: 'grouped-parent-community-table',
dangerouslyAllowMutability: true,
get: ({ get }) => {
console.log('deriving pre-grouped parent community table')
const bigTable = get(bigTableState)
if (bigTable.numRows() === 0) {
return table()
return table({})
}
console.time('groupby parent state')
const grouped = bigTable.groupby('community.pid')
@ -74,7 +75,7 @@ export function useGroupedByParentTable() {
}
// returns a table representing only the nodes for the selected community
export const communityNodesTableState = selectorFamily<table, string>({
export const communityNodesTableState = selectorFamily<ColumnTable, string>({
key: 'community-nodes-table',
get:
cid =>
@ -91,13 +92,13 @@ export function useCommunityNodesTable(cid: string) {
}
// creates a single row per community in the app (just grabbing the first from each group in the big table)
const communitiesTableState = selector<table>({
const communitiesTableState = selector<ColumnTable>({
key: 'communities-table',
get: ({ get }) => {
const byCommunity = get(groupedCommunitiesTableState)
console.time('communities state')
const groups = byCommunity.groups()
const tbl = groups ? byCommunity.reify(groups.rows) : table()
const tbl = groups ? byCommunity.reify(groups.rows) : table({})
console.timeEnd('communities state')
return tbl
},
@ -129,9 +130,9 @@ export function useNodeStatsByCommunity(cid: string, quantile: number) {
// standalone edge table
// we don't want to join that with the node/community table,
// as it would be massive and not useful
export const edgeTableState = atom<table>({
export const edgeTableState = atom<ColumnTable>({
key: 'edge-table',
default: table(),
default: table({}),
dangerouslyAllowMutability: true,
})

Просмотреть файл

@ -3,7 +3,7 @@
* Licensed under the MIT license. See LICENSE file in the project.
*/
import { ScaleType } from '@thematic/core'
import { table } from 'arquero'
import ColumnTable from 'arquero/dist/types/table/column-table'
export interface TableBackedItem {
id: string
@ -43,7 +43,7 @@ export interface Edge extends TableBackedItem {
export type ItemType = 'node' | 'community' | 'edge' | 'join'
export interface TableDef {
table: table
table: ColumnTable
// NOTE: these are the supported types of aggregation
// however, there is no reason this can't allow completely arbitrary "types"
type: ItemType
@ -82,7 +82,7 @@ export interface DataFile {
* If the user has indicated whether this is nodes, edges, etc.
*/
tableType?: ItemType
table?: table
table?: ColumnTable
rows?: number
}

Просмотреть файл

@ -19,6 +19,12 @@ const lineupRules = [
mimetype: 'image/svg+xml',
},
},
{
test: /\.m?js/,
resolve: {
fullySpecified: false,
},
},
{
test: /\.(ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader',
@ -30,7 +36,8 @@ base.module.rules = [...base.module.rules, ...lineupRules]
const aliasFields = base.resolve.aliasFields || []
base.resolve = {
...base.resolve,
//.mjs required for apache-arrow
extensions: ['.ts', '.mjs', '.js', '.tsx'],
// mjolnir.js relies on this functionality
// it has a "browser" package.json property that it uses to define which
// scripts to load

340
yarn.lock
Просмотреть файл

@ -3611,11 +3611,11 @@ __metadata:
linkType: hard
"@types/d3-brush@npm:^2.1.0":
version: 2.1.0
resolution: "@types/d3-brush@npm:2.1.0"
version: 2.1.2
resolution: "@types/d3-brush@npm:2.1.2"
dependencies:
"@types/d3-selection": "*"
checksum: 9b524de33dc4f80cdb1e73c4408e48ae17e984ba25eab7525cf71e1be796deae037e542b977cf2378412a333fe8415d3a3eb2f9522e30e83bba27fe034076e4a
"@types/d3-selection": ^2
checksum: 44bb9f845b03380f626ae422d2b2f7f2710b4a28fd8c4539e82567502a14bfab2150cc30726fa03c802ac063ad36f46407eb64596d09e38f19b8546fee942a37
languageName: node
linkType: hard
@ -3633,7 +3633,16 @@ __metadata:
languageName: node
linkType: hard
"@types/d3-scale@npm:^2.1.1, @types/d3-scale@npm:^2.2.4":
"@types/d3-scale@npm:^2.1.1":
version: 2.2.6
resolution: "@types/d3-scale@npm:2.2.6"
dependencies:
"@types/d3-time": ^1
checksum: ba4bd7e09995f8c08b0723b74aae5a165dbdf46178ae06016f6a4c7dd810dba76b8ec4b000bef95424eed204c02b7e7f3d9b8faaaf16255c57e79c4a59e3f18e
languageName: node
linkType: hard
"@types/d3-scale@npm:^2.2.4":
version: 2.2.4
resolution: "@types/d3-scale@npm:2.2.4"
dependencies:
@ -3642,13 +3651,6 @@ __metadata:
languageName: node
linkType: hard
"@types/d3-selection@npm:*, @types/d3-selection@npm:^2.0.0":
version: 2.0.0
resolution: "@types/d3-selection@npm:2.0.0"
checksum: a4fe69ae9d21c0b12dc60c0e7d7cea70eed9d6db72dce6d9fd6d9ac7bbb8bf3684ae1a123426c7bbfe606c0540e6196b953c279dcb86e5360292f179661528d9
languageName: node
linkType: hard
"@types/d3-selection@npm:^1, @types/d3-selection@npm:^1.4.3":
version: 1.4.3
resolution: "@types/d3-selection@npm:1.4.3"
@ -3656,6 +3658,20 @@ __metadata:
languageName: node
linkType: hard
"@types/d3-selection@npm:^2":
version: 2.0.1
resolution: "@types/d3-selection@npm:2.0.1"
checksum: 23a337564e4540e1672103ad4d8b8eca1a8c50ec5d3382fbd764a3b93f591b7651441da0ae68119945789a8ba7b8d3ab208088ebf8b6fd1add2134df937bfe15
languageName: node
linkType: hard
"@types/d3-selection@npm:^2.0.0":
version: 2.0.0
resolution: "@types/d3-selection@npm:2.0.0"
checksum: a4fe69ae9d21c0b12dc60c0e7d7cea70eed9d6db72dce6d9fd6d9ac7bbb8bf3684ae1a123426c7bbfe606c0540e6196b953c279dcb86e5360292f179661528d9
languageName: node
linkType: hard
"@types/d3-time@npm:^1":
version: 1.1.1
resolution: "@types/d3-time@npm:1.1.1"
@ -3762,6 +3778,13 @@ __metadata:
languageName: node
linkType: hard
"@types/flatbuffers@npm:^1.9.1":
version: 1.10.0
resolution: "@types/flatbuffers@npm:1.10.0"
checksum: f6665700a8aca5129c487650607548fb50f3ae1d2de2b0d1d71ee5275a7b250004f956a21e38f47ab3b26315b29f175a84471f82a4569a09fb6c3dc19640ef9a
languageName: node
linkType: hard
"@types/glob-stream@npm:*":
version: 6.1.0
resolution: "@types/glob-stream@npm:6.1.0"
@ -3978,6 +4001,13 @@ __metadata:
languageName: node
linkType: hard
"@types/node@npm:^12.0.4":
version: 12.20.37
resolution: "@types/node@npm:12.20.37"
checksum: 8c8b12f802678b3b87c5344b6c84082be08561dda81dc161d42be8cd327330d1a5227cef039c45a5e63a6d4a01ef5ef215dccc42d06100f59f6a8814b4f91cdd
languageName: node
linkType: hard
"@types/node@npm:^13.7.0":
version: 13.13.52
resolution: "@types/node@npm:13.13.52"
@ -3986,9 +4016,9 @@ __metadata:
linkType: hard
"@types/node@npm:^14.14.44":
version: 14.17.0
resolution: "@types/node@npm:14.17.0"
checksum: 8e718402537fdfb11a3e59d43d8b0fe46112b1a4799f0d348c01030fc83c0d7c820fd8afa2db1dbe51674b9460a048d111b9caf71bb99342bd32db653effbe94
version: 14.18.0
resolution: "@types/node@npm:14.18.0"
checksum: b120c26fe5f30bc358e861db8d7e401e419d14bd9dd25c022f3c2ea8b0b429d4c9efd77ad5d6d2a8bde61702a6786fb74d409f1b2cbb61c79133e2a65aab4fb1
languageName: node
linkType: hard
@ -4065,11 +4095,11 @@ __metadata:
linkType: hard
"@types/react-dom@npm:^16.9.12":
version: 16.9.13
resolution: "@types/react-dom@npm:16.9.13"
version: 16.9.14
resolution: "@types/react-dom@npm:16.9.14"
dependencies:
"@types/react": ^16
checksum: 71f0e63e28fe8e4b42a3126599d65c43db1336f82f61970ccdfb32db941c0db217617e3ebfaf65c6b3dd6b27e66e771cecab7b0261db14117fd9e7a433e6ac7f
checksum: 68a4ee88f7a56cdbfbca24b1936b9aa5dad8b40ffbf1f047ddf990454aec6e0c9da2a01c9ae87045e95236602061646c90d02f01281533e14f1970687873030f
languageName: node
linkType: hard
@ -4124,13 +4154,13 @@ __metadata:
linkType: hard
"@types/react@npm:^16, @types/react@npm:^16.14.6":
version: 16.14.6
resolution: "@types/react@npm:16.14.6"
version: 16.14.21
resolution: "@types/react@npm:16.14.21"
dependencies:
"@types/prop-types": "*"
"@types/scheduler": "*"
csstype: ^3.0.2
checksum: 7aeb670a46ef8dbb516a984e26578bbdc4341b40325ff7928d803a82b11812ebdb4e46ace5e2e643d371c4a8e6486cf5c9608b7f99f645ebe623f274c37ea2c9
checksum: 9660ea0a2c7ad364295c1e5abd6b98a05fd372a0f06f97850f60fcc254bcec766d19b101c0acc382746a4e0b71848d88097a1db7124e3fd441c0472fb6b3f849
languageName: node
linkType: hard
@ -4228,6 +4258,13 @@ __metadata:
languageName: node
linkType: hard
"@types/text-encoding-utf-8@npm:^1.0.1":
version: 1.0.2
resolution: "@types/text-encoding-utf-8@npm:1.0.2"
checksum: a7199bb5c09448274b0f7f6535d84594bad5b492933cd6423bdcf73724c6fe6cbadb2c49bb526cb4eda3d03538a2e62a7e372dcc7688d1e5f87ac2f5c4c4410a
languageName: node
linkType: hard
"@types/through2@npm:^2.0.36":
version: 2.0.36
resolution: "@types/through2@npm:2.0.36"
@ -5132,7 +5169,7 @@ __metadata:
languageName: node
linkType: hard
"acorn@npm:^8.0.4, acorn@npm:^8.1.0, acorn@npm:^8.2.1":
"acorn@npm:^8.1.0, acorn@npm:^8.2.1":
version: 8.2.4
resolution: "acorn@npm:8.2.4"
bin:
@ -5141,6 +5178,15 @@ __metadata:
languageName: node
linkType: hard
"acorn@npm:^8.5.0":
version: 8.6.0
resolution: "acorn@npm:8.6.0"
bin:
acorn: bin/acorn
checksum: 9d0de73b73cb6ea8ccd8263a8144d9e2c4b6af90ea0c429997538af0ebbe83c5addecee814b2a7f91f7f615d0bd1547cc7137b3fa236ce058adc64feccee850b
languageName: node
linkType: hard
"agent-base@npm:6":
version: 6.0.2
resolution: "agent-base@npm:6.0.2"
@ -5397,6 +5443,26 @@ __metadata:
languageName: node
linkType: hard
"apache-arrow@npm:^3.0.0":
version: 3.0.0
resolution: "apache-arrow@npm:3.0.0"
dependencies:
"@types/flatbuffers": ^1.9.1
"@types/node": ^12.0.4
"@types/text-encoding-utf-8": ^1.0.1
command-line-args: 5.0.2
command-line-usage: 5.0.5
flatbuffers: 1.11.0
json-bignum: ^0.0.3
pad-left: ^2.1.0
text-encoding-utf-8: ^1.0.2
tslib: ^1.12.0
bin:
arrow2csv: bin/arrow2csv.js
checksum: 2ebd5e76d716bc122b40e4e923f5b4d390084ecce2a55daabab925d94540789597d726b63bac86d5839ba29497124242ba0b99a9d1f0c788662f5dcc70aacd8f
languageName: node
linkType: hard
"append-buffer@npm:^1.0.2":
version: 1.0.2
resolution: "append-buffer@npm:1.0.2"
@ -5472,6 +5538,16 @@ __metadata:
languageName: node
linkType: hard
"argv-tools@npm:^0.1.1":
version: 0.1.2
resolution: "argv-tools@npm:0.1.2"
dependencies:
array-back: ^2.0.0
find-replace: ^2.0.1
checksum: 77f8c7727cdfcbb944a5d3c78a2b85dec7ca2dc85de08a6d3bebb7ca20572740e3916126165fc979f5bc9bc4f12b04679e04f9a6aa6f3d2889e1a3e08ee0d847
languageName: node
linkType: hard
"aria-query@npm:^4.0.2, aria-query@npm:^4.2.2":
version: 4.2.2
resolution: "aria-query@npm:4.2.2"
@ -5482,12 +5558,14 @@ __metadata:
languageName: node
linkType: hard
"arquero@npm:^0.13.3":
version: 0.13.3
resolution: "arquero@npm:0.13.3"
"arquero@npm:^4.8.4":
version: 4.8.7
resolution: "arquero@npm:4.8.7"
dependencies:
acorn: ^8.0.4
checksum: 5952608e2e197c3a29b9c02108692192daae17f1e76e8a1c3a61f8af3cf357cb22b86d92a28f75fa9332395b857d91404c8f24e827dc1b9e8bbecf1d2d170535
acorn: ^8.5.0
apache-arrow: ^3.0.0
node-fetch: ^2.6.2
checksum: 63a832e7f0a5d60d70d3b036f6c5714aa4593c6d1d3ba6c4fa9e1bef304bf307de434c3c41de5706e5767ddf77a8397b4bf6f129899adfbdb4b271caf33f3413
languageName: node
linkType: hard
@ -5547,6 +5625,15 @@ __metadata:
languageName: node
linkType: hard
"array-back@npm:^2.0.0":
version: 2.0.0
resolution: "array-back@npm:2.0.0"
dependencies:
typical: ^2.6.1
checksum: ab36ab3504b25116b47541fb0ac78ff13d1e991f33d98c361edd3aada3ed818a900b619bd67b195dd4e41b9256c27e8cdd6a69ece507e482f1207d07670ed6bd
languageName: node
linkType: hard
"array-differ@npm:^3.0.0":
version: 3.0.0
resolution: "array-differ@npm:3.0.0"
@ -7102,6 +7189,31 @@ __metadata:
languageName: node
linkType: hard
"command-line-args@npm:5.0.2":
version: 5.0.2
resolution: "command-line-args@npm:5.0.2"
dependencies:
argv-tools: ^0.1.1
array-back: ^2.0.0
find-replace: ^2.0.1
lodash.camelcase: ^4.3.0
typical: ^2.6.1
checksum: fc239cc26284e75f21bae0a5a0c716743eaf95ae4deadffbcffe84f9cf94419db3f953afec748a86a2543932733a4e85aa08b8c06e9b6e8fb8c42c27328fd3e3
languageName: node
linkType: hard
"command-line-usage@npm:5.0.5":
version: 5.0.5
resolution: "command-line-usage@npm:5.0.5"
dependencies:
array-back: ^2.0.0
chalk: ^2.4.1
table-layout: ^0.4.3
typical: ^2.6.1
checksum: d6362006497598f67aad61308c5ef3445b951501cc6f6d640aa53b81a59bd7f84ba282664819329c67ed9dae78479941c235d03e3aa2711502b7f11881ea3df8
languageName: node
linkType: hard
"commander@npm:2, commander@npm:^2.20.0":
version: 2.20.3
resolution: "commander@npm:2.20.3"
@ -8098,7 +8210,7 @@ __metadata:
languageName: node
linkType: hard
"deep-extend@npm:^0.6.0":
"deep-extend@npm:^0.6.0, deep-extend@npm:~0.6.0":
version: 0.6.0
resolution: "deep-extend@npm:0.6.0"
checksum: 7be7e5a8d468d6b10e6a67c3de828f55001b6eb515d014f7aeb9066ce36bd5717161eb47d6a0f7bed8a9083935b465bc163ee2581c8b128d29bf61092fdf57a7
@ -9632,6 +9744,16 @@ __metadata:
languageName: node
linkType: hard
"find-replace@npm:^2.0.1":
version: 2.0.1
resolution: "find-replace@npm:2.0.1"
dependencies:
array-back: ^2.0.0
test-value: ^3.0.0
checksum: 8eaa35d2a1322f063a59f8663404aa89941d7e32d6f470a3e22ae8ec18583c926a5e20953d184718763eceb8a268dffc6e4c2ae5e6192fcdb97fd29aa4760c22
languageName: node
linkType: hard
"find-up@npm:^1.0.0":
version: 1.1.2
resolution: "find-up@npm:1.1.2"
@ -9734,6 +9856,13 @@ __metadata:
languageName: node
linkType: hard
"flatbuffers@npm:1.11.0":
version: 1.11.0
resolution: "flatbuffers@npm:1.11.0"
checksum: 124889409411c57033c7b1e27525357adfa9234eb7e657693338cbbafdb871ce925cc074644696a917e65a95133594e16c5d6a1c871eb16bd6df1eafb7b82fbd
languageName: node
linkType: hard
"flatted@npm:^3.1.0":
version: 3.1.1
resolution: "flatted@npm:3.1.1"
@ -10447,7 +10576,7 @@ fsevents@^1.2.7:
"@typescript-eslint/parser": ^4.23.0
"@yarnpkg/pnpify": ^2.4.0
ahooks: ^2.10.6
arquero: ^0.13.3
arquero: ^4.8.4
concurrently: ^5.3.0
core-js: ^3.12.0
d3-array: ^2.8.0
@ -12621,6 +12750,13 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
"json-bignum@npm:^0.0.3":
version: 0.0.3
resolution: "json-bignum@npm:0.0.3"
checksum: e64b69089fa6760ef6373138754fece6467110a769a57991f6c9f0abf203413606540200e0682c8d3b377421aa9584eeccfaef424f7d8253b3b74c6b670b2fab
languageName: node
linkType: hard
"json-buffer@npm:3.0.0":
version: 3.0.0
resolution: "json-buffer@npm:3.0.0"
@ -13127,6 +13263,13 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
"lodash.camelcase@npm:^4.3.0":
version: 4.3.0
resolution: "lodash.camelcase@npm:4.3.0"
checksum: cb9227612f71b83e42de93eccf1232feeb25e705bdb19ba26c04f91e885bfd3dd5c517c4a97137658190581d3493ea3973072ca010aab7e301046d90740393d1
languageName: node
linkType: hard
"lodash.clonedeep@npm:^4.5.0":
version: 4.5.0
resolution: "lodash.clonedeep@npm:4.5.0"
@ -13183,6 +13326,13 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
"lodash.padend@npm:^4.6.1":
version: 4.6.1
resolution: "lodash.padend@npm:4.6.1"
checksum: c2e6e789debf83b98f5c085305cdcfff1067e7a31bda2a110fd765d3c11a99edfbeef570d9ef737ab3212006bdb8114e77622e518c18c1fce52b8fdfd9dab685
languageName: node
linkType: hard
"lodash.throttle@npm:^4.1.1":
version: 4.1.1
resolution: "lodash.throttle@npm:4.1.1"
@ -14052,6 +14202,15 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
"node-fetch@npm:^2.6.2":
version: 2.6.6
resolution: "node-fetch@npm:2.6.6"
dependencies:
whatwg-url: ^5.0.0
checksum: ee8290626bdb73629c59722b75dcf4b9b6a67c1ed7eb9102e368479c4a13b56a48c2bb3ad71571e378e98c8b2c64c820e11f9cd39e4b8557dd138ad571ef9a42
languageName: node
linkType: hard
"node-forge@npm:^0.10.0":
version: 0.10.0
resolution: "node-forge@npm:0.10.0"
@ -14824,6 +14983,15 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
"pad-left@npm:^2.1.0":
version: 2.1.0
resolution: "pad-left@npm:2.1.0"
dependencies:
repeat-string: ^1.5.4
checksum: a1605c3cb0ebd9be1a74f7f895524d3bf30f24492db87421c2fda9b8c0fcee17b3b594dacfb5eb1d3189d59c69d2f969677bc04b8280a7ef6303566154dbd078
languageName: node
linkType: hard
"pako@npm:~1.0.5":
version: 1.0.11
resolution: "pako@npm:1.0.11"
@ -15871,6 +16039,18 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
"re-resizable@npm:6.9.1":
version: 6.9.1
resolution: "re-resizable@npm:6.9.1"
dependencies:
fast-memoize: ^2.5.1
peerDependencies:
react: ^16.13.1 || ^17.0.0
react-dom: ^16.13.1 || ^17.0.0
checksum: b164f6b956dc1f45b6c2603f0f402b04df8306017c59d68a9a71a2c857049a314a01c3fb7aedba66d8c60c4ccf9aa182c345276825eed745e5b847b6f104d78e
languageName: node
linkType: hard
"react-animate-height@npm:^2.0.23":
version: 2.0.23
resolution: "react-animate-height@npm:2.0.23"
@ -15945,7 +16125,18 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
"react-rnd@npm:*, react-rnd@npm:^10.2.3":
"react-rnd@npm:*":
version: 10.3.5
resolution: "react-rnd@npm:10.3.5"
dependencies:
re-resizable: 6.9.1
react-draggable: 4.4.3
tslib: 2.3.0
checksum: 2171e3119acbc7e2778f5e18d84fec66a0cad3984f83f733b06dc174142b4c65c45dc954db69121881e6d36b7fc30b8a6b5e6603f64160135b400b239c184ddd
languageName: node
linkType: hard
"react-rnd@npm:^10.2.3":
version: 10.3.0
resolution: "react-rnd@npm:10.3.0"
dependencies:
@ -16175,6 +16366,13 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
"reduce-flatten@npm:^1.0.1":
version: 1.0.1
resolution: "reduce-flatten@npm:1.0.1"
checksum: 5e5a450500ece8dfff95ecd0b34f48941084c00fdc63e6a4413f758334d2d3f8b4d725670896c04853c477c062af03402aeb5e145b948e03abc914ee51bb3b89
languageName: node
linkType: hard
"reflect-metadata@npm:^0.1.13":
version: 0.1.13
resolution: "reflect-metadata@npm:0.1.13"
@ -16346,7 +16544,7 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
"repeat-string@npm:^1.6.1":
"repeat-string@npm:^1.5.4, repeat-string@npm:^1.6.1":
version: 1.6.1
resolution: "repeat-string@npm:1.6.1"
checksum: 1b809fc6db97decdc68f5b12c4d1a671c8e3f65ec4a40c238bc5200e44e85bcc52a54f78268ab9c29fcf5fe4f1343e805420056d1f30fa9a9ee4c2d93e3cc6c0
@ -17988,6 +18186,19 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard
"table-layout@npm:^0.4.3":
version: 0.4.5
resolution: "table-layout@npm:0.4.5"
dependencies:
array-back: ^2.0.0
deep-extend: ~0.6.0
lodash.padend: ^4.6.1
typical: ^2.6.1
wordwrapjs: ^3.0.0
checksum: 9642b67d1bb3d9ba85f2b95f0a65a12ec7e1186ce842c9be63f1fdf76e36e91be89955b58b7a16358e1b39a12ceb9860c41ed977d8305d792651c19f08e3f8f2
languageName: node
linkType: hard
"table@npm:^6.0.4, table@npm:^6.0.9":
version: 6.7.1
resolution: "table@npm:6.7.1"
@ -18144,6 +18355,23 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard
"test-value@npm:^3.0.0":
version: 3.0.0
resolution: "test-value@npm:3.0.0"
dependencies:
array-back: ^2.0.0
typical: ^2.6.1
checksum: 5bac284cbe4b8e2024f987854952424925ba607c22e0af1b88020484e9d77d6b85e301c61f95f8f27f9eda58e4439d99056318f8b649bbc79f43e125f4f63f0b
languageName: node
linkType: hard
"text-encoding-utf-8@npm:^1.0.2":
version: 1.0.2
resolution: "text-encoding-utf-8@npm:1.0.2"
checksum: ec4c15d50e738c5dba7327ad432ebf0725ec75d4d69c0bd55609254c5a3bc5341272d7003691084a0a73d60d981c8eb0e87603676fdb6f3fed60f4c9192309f9
languageName: node
linkType: hard
"text-extensions@npm:^1.0.0":
version: 1.9.0
resolution: "text-extensions@npm:1.9.0"
@ -18402,6 +18630,13 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard
"tr46@npm:~0.0.3":
version: 0.0.3
resolution: "tr46@npm:0.0.3"
checksum: 726321c5eaf41b5002e17ffbd1fb7245999a073e8979085dacd47c4b4e8068ff5777142fc6726d6ca1fd2ff16921b48788b87225cbc57c72636f6efa8efbffe3
languageName: node
linkType: hard
"tree-kill@npm:^1.2.2":
version: 1.2.2
resolution: "tree-kill@npm:1.2.2"
@ -18503,7 +18738,14 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard
"tslib@npm:^1.10.0, tslib@npm:^1.13.0, tslib@npm:^1.8.1, tslib@npm:^1.9.0":
"tslib@npm:2.3.0":
version: 2.3.0
resolution: "tslib@npm:2.3.0"
checksum: 8869694c26e4a7b56d449662fd54a4f9ba872c889d991202c74462bd99f10e61d5bd63199566c4284c0f742277736292a969642cc7b590f98727a7cae9529122
languageName: node
linkType: hard
"tslib@npm:^1.10.0, tslib@npm:^1.12.0, tslib@npm:^1.13.0, tslib@npm:^1.8.1, tslib@npm:^1.9.0":
version: 1.14.1
resolution: "tslib@npm:1.14.1"
checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd
@ -18738,6 +18980,13 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard
"typical@npm:^2.6.1":
version: 2.6.1
resolution: "typical@npm:2.6.1"
checksum: 6af04fefe50d90d3471f058b2cdc0f49b7436bdd605cd00acea7965926ff388a5a7d692ef144f45fccee6f8e896c065702ecc44b69057e2ce88c09e897c7d3a4
languageName: node
linkType: hard
"uglify-js@npm:^3.1.4":
version: 3.13.7
resolution: "uglify-js@npm:3.13.7"
@ -19291,6 +19540,13 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard
"webidl-conversions@npm:^3.0.0":
version: 3.0.1
resolution: "webidl-conversions@npm:3.0.1"
checksum: c92a0a6ab95314bde9c32e1d0a6dfac83b578f8fa5f21e675bc2706ed6981bc26b7eb7e6a1fab158e5ce4adf9caa4a0aee49a52505d4d13c7be545f15021b17c
languageName: node
linkType: hard
"webidl-conversions@npm:^5.0.0":
version: 5.0.0
resolution: "webidl-conversions@npm:5.0.0"
@ -19506,6 +19762,16 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard
"whatwg-url@npm:^5.0.0":
version: 5.0.0
resolution: "whatwg-url@npm:5.0.0"
dependencies:
tr46: ~0.0.3
webidl-conversions: ^3.0.0
checksum: b8daed4ad3356cc4899048a15b2c143a9aed0dfae1f611ebd55073310c7b910f522ad75d727346ad64203d7e6c79ef25eafd465f4d12775ca44b90fa82ed9e2c
languageName: node
linkType: hard
"whatwg-url@npm:^8.0.0, whatwg-url@npm:^8.5.0":
version: 8.5.0
resolution: "whatwg-url@npm:8.5.0"
@ -19605,6 +19871,16 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard
"wordwrapjs@npm:^3.0.0":
version: 3.0.0
resolution: "wordwrapjs@npm:3.0.0"
dependencies:
reduce-flatten: ^1.0.1
typical: ^2.6.1
checksum: 953322ec8dd8b634a1a07a611760b0473e258073fd3bcab473082c6f0f30cdc48e641310209973d8557b9893bc291e32587f6dce05ea675242e21f8b0b0877bc
languageName: node
linkType: hard
"worker-farm@npm:^1.7.0":
version: 1.7.0
resolution: "worker-farm@npm:1.7.0"