ignore
Author

Taras Novak (@RandomFractals)

Use this Tabular Data Viewer 中 notebook 📓 to view sample datasets or preview any public Apache Arrow, CSV, or JSON array data with Summary Table and Tabulator. Just paste your data url to fetch it.

Also, try our Data Table 🈸 notebook 📓 cell ⌗ output renderer extension with VSCode Notebooks 📚.

code
dataPath = "https://raw.githubusercontent.com/Post45-Data-Collective/data/refs/heads/main/hathitrust_fiction/hathitrust_post45fiction_metadata.csv"

data = fetchData(dataPath)

defaultDisplayedColumns = [
    "shorttitle",
    "inferreddate",
    "author",
    "recordid",
    "hathi_rights",
    "genres",
    "id",
    "docid",
    "juvenileprob",
    "nonficprob",
    "author_authorized_heading",
    "author_lccn",
    "author_viaf",
    "author_wikidata_qid"
  ];

categoryColumns = ["hathi_rights",  "genres","geographics"];

// Reorder the available columns to match defaultDisplayedColumns, appending any extra columns at the end
orderedColumns = [
  ...defaultDisplayedColumns,
  ...Object.keys(data[0] || {}).filter(col => !defaultDisplayedColumns.includes(col))
];

Select Columns

code
viewof selectedColumns = Inputs.checkbox(orderedColumns, {
  label: "Select Columns",
  value: defaultDisplayedColumns, // Default selected columns
});
code
function generateTabulatorTableForObservable(
  containerId,
  data,
  {
    displayedColumns = null,
    columnWidths = {},
    currencyColumns = [],
    categoryColumns = [],
    numericColumns = [],
    rangeValues = {},
    sortColumns = [],
    sortOrders = [],
    columnPopups = [],
    height = 645,
    paginationSize = 1000,
  } = {}
) {
  if (!data || data.length === 0) {
    console.error("No data provided to generate the table.");
    return null;
  }

  if (!displayedColumns) {
    displayedColumns = Object.keys(data[0]);
  }

  const tabulatorColumns = displayedColumns.map((column) => ({
    title: column,
    field: column,
    maxInitialWidth: 150,
    resizable: true,
    headerFilter: numericColumns.includes(column)
      ? "input"
      : categoryColumns.includes(column)
      ? "list"
      : "input",
    headerFilterParams: categoryColumns.includes(column)
      ? { valuesLookup: true, clearable: true }
      : {},
    formatter: currencyColumns.includes(column) ? "money" : undefined,
    formatterParams: currencyColumns.includes(column)
      ? { symbol: "$", precision: 0 }
      : undefined,
  }));

  const table = new Tabulator(containerId, {
    height: height,
    data: data,
    columns: tabulatorColumns,
     columnDefaults: {
    headerMenu: columnHeaderMenu
  },
//    movableColumns: true,
    layout: "fitDataStretch",
    pagination: true,
    paginationSize: paginationSize,
    paginationSizeSelector: [10, 100, 1000, 10000],
    paginationCounter: "rows",
    persistenceMode: false,
    initialSort: sortColumns.map((col, idx) => ({
      column: col,
      dir: sortOrders[idx] || "asc",
    })),
  });

  return table;
}
```{ojs}
// Add fullscreen event listener
      document.addEventListener("fullscreenchange", () => {
        if (document.fullscreenElement) {
          // Fullscreen mode: adjust table height
          table.setHeight(window.innerHeight - 50); // Adjust for padding/margins
        } else {
          // Exit fullscreen: reset table height
          table.setHeight(645);
        }
      });

      // Add download buttons
      document
        .querySelectorAll("#button-container button")
        .forEach((button) => {
          button.addEventListener("click", () => {
            const type = button.getAttribute("id").replace("download-", "");
            const downloadFilename = `${filename}.${type}`;

            if (type === "xlsx") {
              table.download("xlsx", downloadFilename, { sheetName: "Sheet1" });
            } else if (type === "pdf") {
              table.download("pdf", downloadFilename, {
                orientation: "portrait",
                title: "Table Data"
              });
            } else if (type === "html") {
              table.download("html", downloadFilename, { style: true });
            } else {
              table.download(type, downloadFilename);
            }
          });
        });

      // Update raw data download button dynamically
      // Raw data download using `download` function
      const rawDownloadButton = document.getElementById("download-raw");
      rawDownloadButton.addEventListener("click", () => {
        download(dataPath, `${filename}.csv`);
      });

      // Copy URL button
      document.getElementById("copy-url").addEventListener("click", () => {
        const tempInput = document.createElement("input");
        tempInput.value = dataPath;
        document.body.appendChild(tempInput);
        tempInput.select();
        document.execCommand("copy");
        document.body.removeChild(tempInput);
        alert("URL copied to clipboard: " + dataPath);
      });
```
OJS Syntax Error (line 203, column 7)Unexpected token
code
html`<div id="table-container" style="height: 600px"></div>`
code
generateTabulatorTableForObservable("#table-container", data, {
  displayedColumns: selectedColumns,

    columnPopups: [
  "Shortened title of the work",  // shorttitle
  "Inferred date of the work",    // inferreddate
  "Author of the work",           // author
  "Unique record ID",             // recordid
  "Rights code from HathiTrust",  // hathi_rights
  "Genres associated with the work",  // genres
  "Unique identifier for the title in the titles dataset (may contain duplicates for reprinted works)", // id
  "Unique volume ID from HathiTrust", // docid (htid)
  "Probability that the work is for a juvenile audience", // juvenileprob
  "Probability that the work is nonfiction", // nonficprob
  "Author’s authorized Name Authority Cooperative (NACO) heading", // author_authorized_heading
  "Author’s LCCN from id.loc.gov", // author_lccn
  "Author’s viaf.org cluster number", // author_viaf
  "Author’s Wikidata Q number"      // author_wikidata_qid
],
    // columnWidths: { "gender": "50px", "role": "75px", "mfa_degree": "100px", "prize_name": "100px" },
    currencyColumns: ["prize_amount"],
    categoryColumns: ["hathi_rights",  "genres","geographics"],
    // sortColumns: ["prize_year"],
    // sortOrders: ["desc"]
  paginationSize: 1000,
});

Tabular Data View

code
columnHeaderMenu = [
  {
    label: 'Hide Column',
    action: function (e, column) {
      column.hide();
    }
  },
  {
    label: "Freeze Column",
    action: function (e, column) {
      column.updateDefinition({ frozen: true });
    }
  },
  {
    label: 'Delete Column',
    action: function (e, column) {
      column.delete();
    }
  }
];

Table UX Tips

  • Hold CTRL or Shift key when clicking on column headers to Sort table data by multiple columns.
  • See Clipboard options for the clipboard copy and paste data options.
  • Use row context menu to Delete or Freeze a row.

Data

code
dataUrlParam = new URLSearchParams(html`<a href>`.search).get('dataUrl')


async function fetchData(dataUrl) {
  let data = [];
  if (dataUrl.endsWith('.csv')) {
    data = await d3.csvParse(await d3.text(dataUrl), d3.autoType);
  }
  else if (dataUrl.endsWith('.json')) {
    data = await d3.json(dataUrl);
  }
  else if (dataUrl.endsWith('.arrow')) {
    data = loadArrowData(dataUrl);
  }
  return data;
}

async function loadArrowData(dataUrl){
  const response = await fetch(dataUrl);
  const arrayBuffer = await response.arrayBuffer();
  const table = arrow.Table.from(new Uint8Array(arrayBuffer));
  const rows = Array(table.length);
  const fields = table.schema.fields.map(d => d.name);
  for (let i=0, n=rows.length; i<n; ++i) {
    const proto = {};
    fields.forEach((fieldName, index) => {
      const column = table.getColumnAt(index);
      proto[fieldName] = column.get(i);
    });
    rows[i] = proto;
  }
  return rows;
}

async function download(dataurl, fileName) {
  const response = await fetch(dataurl);
  const blob = await response.blob();

  const link = document.createElement("a");
  link.href = URL.createObjectURL(blob);
  link.download = fileName;
  link.click();
  URL.revokeObjectURL(link.href); // Clean up
}

Table Styles

code
tableStyles = html `
<style>
/* add space for sort direction symbol */
thead th span {
  margin-left: 0 !important;
  padding-right: 0.4rem;
}

.tabulator .tabulator-tableholder{
  background-color: aliceblue;
}
</style>`

html`<link href='https://unpkg.com/tabulator-tables@5.3.1/dist/css/tabulator.min.css' rel='stylesheet' />
tabulator.min.css`

Imports

code
import { SummaryTable } from "fcb971390dae8f6d"

Tabulator = require('https://unpkg.com/tabulator-tables@5.3.1');

arrow = require('apache-arrow@6.0.1')