SaulLu's picture
add component code
3fc2d14
raw
history blame
5.56 kB
/**
* @license
* Copyright 2018-2019 Streamlit Inc.
*
* 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.
*/
import { Table, Type } from "apache-arrow"
type CellType = "blank" | "index" | "columns" | "data"
export interface ArrowDataframeProto {
data: ArrowTableProto
height: string
width: string
}
export interface ArrowTableProto {
data: Uint8Array
index: Uint8Array
columns: Uint8Array
styler: Styler
}
interface Cell {
classNames: string
content: string
id?: string
type: CellType
}
interface Styler {
caption?: string
displayValuesTable: Table
styles?: string
uuid: string
}
export class ArrowTable {
private readonly dataTable: Table
private readonly indexTable: Table
private readonly columnsTable: Table
private readonly styler?: Styler
constructor(
dataBuffer: Uint8Array,
indexBuffer: Uint8Array,
columnsBuffer: Uint8Array,
styler?: any
) {
this.dataTable = Table.from(dataBuffer)
this.indexTable = Table.from(indexBuffer)
this.columnsTable = Table.from(columnsBuffer)
this.styler = styler
? {
caption: styler.get("caption"),
displayValuesTable: Table.from(styler.get("displayValues")),
styles: styler.get("styles"),
uuid: styler.get("uuid"),
}
: undefined
}
get rows(): number {
return this.indexTable.length + this.columnsTable.numCols
}
get columns(): number {
return this.indexTable.numCols + this.columnsTable.length
}
get headerRows(): number {
return this.rows - this.dataRows
}
get headerColumns(): number {
return this.columns - this.dataColumns
}
get dataRows(): number {
return this.dataTable.length
}
get dataColumns(): number {
return this.dataTable.numCols
}
get uuid(): string | undefined {
return this.styler && this.styler.uuid
}
get caption(): string | undefined {
return this.styler && this.styler.caption
}
get styles(): string | undefined {
return this.styler && this.styler.styles
}
get table(): Table {
return this.dataTable
}
get index(): Table {
return this.indexTable
}
get columnTable(): Table {
return this.columnsTable
}
public getCell = (rowIndex: number, columnIndex: number): Cell => {
const isBlankCell =
rowIndex < this.headerRows && columnIndex < this.headerColumns
const isIndexCell =
rowIndex >= this.headerRows && columnIndex < this.headerColumns
const isColumnsCell =
rowIndex < this.headerRows && columnIndex >= this.headerColumns
if (isBlankCell) {
const classNames = ["blank"]
if (columnIndex > 0) {
classNames.push("level" + rowIndex)
}
return {
type: "blank",
classNames: classNames.join(" "),
content: "",
}
} else if (isColumnsCell) {
const dataColumnIndex = columnIndex - this.headerColumns
const classNames = [
"col_heading",
"level" + rowIndex,
"col" + dataColumnIndex,
]
return {
type: "columns",
classNames: classNames.join(" "),
content: this.getContent(this.columnsTable, dataColumnIndex, rowIndex),
}
} else if (isIndexCell) {
const dataRowIndex = rowIndex - this.headerRows
const classNames = [
"row_heading",
"level" + columnIndex,
"row" + dataRowIndex,
]
return {
type: "index",
id: `T_${this.uuid}level${columnIndex}_row${dataRowIndex}`,
classNames: classNames.join(" "),
content: this.getContent(this.indexTable, dataRowIndex, columnIndex),
}
} else {
const dataRowIndex = rowIndex - this.headerRows
const dataColumnIndex = columnIndex - this.headerColumns
const classNames = [
"data",
"row" + dataRowIndex,
"col" + dataColumnIndex,
]
const content = this.styler
? this.getContent(
this.styler.displayValuesTable,
dataRowIndex,
dataColumnIndex
)
: this.getContent(this.dataTable, dataRowIndex, dataColumnIndex)
return {
type: "data",
id: `T_${this.uuid}row${dataRowIndex}_col${dataColumnIndex}`,
classNames: classNames.join(" "),
content,
}
}
}
public getContent = (
table: Table,
rowIndex: number,
columnIndex: number
): any => {
const column = table.getColumnAt(columnIndex)
if (column === null) {
return ""
}
const columnTypeId = this.getColumnTypeId(table, columnIndex)
switch (columnTypeId) {
case Type.Timestamp: {
return this.nanosToDate(column.get(rowIndex))
}
default: {
return column.get(rowIndex)
}
}
}
/**
* Returns apache-arrow specific typeId of column.
*/
private getColumnTypeId(table: Table, columnIndex: number): Type {
return table.schema.fields[columnIndex].type.typeId
}
private nanosToDate(nanos: number): Date {
return new Date(nanos / 1e6)
}
}