Simple Data Analysis (SDA)

repository·main·Indexed 43 days ago

https://github.com/nshiab/simple-data-analysis

A high-performance TypeScript library for tabular, geospatial, vector, and AI-assisted data analysis. Built on DuckDB, it provides a chainable API for Deno, Node.js, and Bun. Features include geospatial joins, OpenStreetMap and Statistics Canada data loading, AI-driven enrichment via aiRowByRow, hybrid search, RAG (aiRAG), and integrations with Google Cloud Storage, Google Sheets, and Datawrapper. Supports visualization through terminal charts and Observable Plot.

Tokens
55.4K
Snippets
194
Records
216
Agent score
55%

What's inside SDA

  1. Execute queued operations with run() and close()

    main

    SimpleDB uses a deferred execution model. Sync builder methods (like filter() or convert()) only queue operations. Execution is triggered when an async observer method (like getData(), log(), or writeData()) is awaited.

    • run(): Use this when your script ends in pure mutations with no observer. It executes all queued methods across every table in the database in program order.
    • close(): Executes all pending transformations, saves SDA metadata (for writable persistent databases), and closes the connection, cleans up temporary files, and the cache.
    // Nothing is observed after the mutations, so run() executes them.
    table1.loadData("data1.csv").convert({ price: "number" });
    table2.loadData("data2.csv").filter(`price > 0`);
    await sdb.run();
    
    // close() executes queued transformations before cleaning up resources.
    table.loadData("data.csv").convert({ price: "number" });
    await sdb.close();
  2. Use AI for data enrichment and search

    main

    SDA provides several AI-driven capabilities powered by journalism-ai. Responses and embeddings are cached in .journalism-cache by default.

    Supported Providers

    • Gemini / Vertex AI: Requires AI_PROVIDER=gemini, AI_MODEL, AI_EMBEDDINGS_PROVIDER=gemini, AI_EMBEDDINGS_MODEL, and either AI_KEY (Gemini) or AI_PROJECT/AI_LOCATION (Vertex AI).
    • Ollama: Requires AI_PROVIDER=ollama, AI_MODEL, AI_EMBEDDINGS_PROVIDER=ollama, and AI_EMBEDDINGS_MODEL.
  3. Understand the SDA library structure

    main

    SDA is composed of two main packages:

    1. simple-data-analysis-core: Contains core functions depending on DuckDB, such as data loading, filtering, joining, summarizing, and geospatial operations. Use this if you only need core analysis capabilities.
    2. simple-data-analysis (the main package): Extends the core with AI methods (embeddings, vector similarity, RAG, etc.), Google Cloud Storage/Sheets integrations, and charting/dataviz methods.

    Note on inheritance: SimpleDB and SimpleTable in the main package inherit all core methods. Due to JSR documentation limitations, inherited methods might not appear in the main package's documentation, but they are available for direct use on SDA instances.

  4. How SDA data pipelines and execution work

    main

    SDA is built on DuckDB and uses a lazy execution model to optimize performance:

    • Lazy Transformation Queueing: Core transformation methods are synchronous and chainable. Instead of executing immediately, SDA queues these operations. Consecutive compatible operations are fused into a single DuckDB statement to reduce database round trips.
    • Synchronous vs. Asynchronous Methods:
      • Transformation methods are synchronous and chainable.
      • Observer methods (e.g., getData(), log(), writeData()) are asynchronous and flush the transformation queue before producing a result.
      • Export/Answer methods (e.g., aiRAG(), toBucket(), toSheet(), toDatawrapper(), toGeoDatawrapper(), writeChart(), writeMap()) are asynchronous and must be awaited.
    • Lazy Dependency Loading: AI, Google, and charting dependencies are only loaded when those specific operations are executed, minimizing startup costs.
  5. Use aiRAG for Retrieval-Augmented Generation

    main

    The aiRAG method performs Retrieval-Augmented Generation by combining semantic vector search and BM25 full-text search to retrieve context, then passing it to an LLM to answer queries.

    Key differences from hybridSearch:

    • aiRAG includes an LLM step to generate a natural language answer.
    • hybridSearch returns the raw table of results.

    Caching and Cleanup:

    • Embeddings and vector tables are cached in .sda-cache.
    • Final answers and other metadata are cached in .journalism-cache.
    • To clear caches, delete the .journalism-cache and .sda-cache directories. Add these to your .gitignore.
  6. Visualize data with charts and maps

    main

    SDA provides several ways to visualize data:

    1. Terminal Charts: Use logBarChart, logDotChart, logLineChart, or logHistogram for quick terminal output.
    2. Observable Plot Images: Use writeChart to generate .png or .svg files using Observable Plot.
    3. Observable Plot Maps: Use writeMap to generate map images.
    // Example: Creating a chart with writeChart
    import { SimpleDB } from "@nshiab/simple-data-analysis";
    import { dodgeX, dot, plot } from "@observablehq/plot";
    
    const sdb = new SimpleDB();
    const table = await sdb
      .newTable()
      .loadData("https://raw.githubusercontent.com/nshiab/simple-data-analysis/main/test/geodata/files/firesCanada2023.csv")
      .filter(`hectares > 1`)
      .replace("cause", { "H": "Human", "N": "Natural", "U": "Unknown" })
      .log();
    
    await table.writeChart(
      (data) =>
        plot({
          height: 600,
          width: 800,
          color: { legend: true },
          y: { type: "log", label: "Hectares" },
          r: { range: [1, 20] },
          marks: [
            dot(
              data,
              dodgeX("middle", {
                fx: "cause",
                y: "hectares",
                fill: "cause",
                r: "hectares",
              }),
            ),
          ],
        }),
      "sda/output/chart.png",
    );
    
    await sdb.close();
  7. Install the Simple Data Analysis (SDA) library

    main

    SDA is available via JSR and NPM. Choose the command corresponding to your runtime (Deno, Node.js, or Bun).

    # Deno
    deno add jsr:@nshiab/simple-data-analysis
    
    # Node.js
    npm i @nshiab/simple-data-analysis
    
    # Bun
    bun add @nshiab/simple-data-analysis
  8. Quick setup a data project

    main

    You can use @nshiab/setup-data-project to automatically create a data project with essential folders, configurations, and documentation optimized for AI agents.

    # Deno
    deno run -A jsr:@nshiab/setup-data-project
    
    # Node
    npx @nshiab/setup-data-project
    
    # Bun
    bunx @nshiab/setup-data-project
  9. Quick setup with SimpleDB and SimpleTable

    main

    To begin analyzing data, instantiate a SimpleDB object, create a SimpleTable from it, and load your data (e.g., from a CSV file). Always remember to call sdb.close() when your operations are complete to release resources.

    Workflow:

    1. Create SimpleDB instance.
    2. Call .newTable(name) on the DB instance.
    3. Call .loadData(path) to populate the table.
    4. Perform analysis operations.
    5. Call .close() on the DB instance.
    import { SimpleDB } from "@nshiab/simple-data-analysis";
    
    const sdb = new SimpleDB();
    const table = await sdb
      .newTable("myTable")
      .loadData("path/to/your/data.csv")
      .log();
    
    // You can now perform various data analysis operations on the table.
    
    await sdb.close(); // Close the database when you're finished.
  10. Integrate with Google Cloud Storage

    main

    Use toBucket to upload a table to GCS and loadBucket to download and load an object. Authentication relies on Google Application Default Credentials (ADC).

    Required Environment Variables:

    • BUCKET_PROJECT: Your Google Cloud project ID.
    • BUCKET_NAME: Your GCS bucket name.
    • GOOGLE_APPLICATION_CREDENTIALS (Optional): Path to a service account JSON file.
    BUCKET_PROJECT=my-google-cloud-project
    BUCKET_NAME=my-storage-bucket
    GOOGLE_APPLICATION_CREDENTIALS=./service-account.json
    import { SimpleDB } from "@nshiab/simple-data-analysis";
    
    const sdb = new SimpleDB();
    
    const temperatures = await sdb
      .newTable("temperatures")
      .loadBucket("inputs/temperatures.parquet")
      .filter("temperature > 30")
      .log();
    
    const uri = await temperatures.toBucket(
      "outputs/hotTemperatures.parquet",
      { overwrite: true },
    );
    
    console.log(uri); // gs://my-storage-bucket/outputs/hotTemperatures.parquet
    
    await sdb.close();
  11. Integrate with Google Sheets

    main

    Use loadSheet() to read from a Google Sheet tab and toSheet() to write to one. Authentication requires a service account.

    Required Environment Variables:

    • GOOGLE_SERVICE_ACCOUNT_EMAIL: The service account email.
    • GOOGLE_PRIVATE_KEY: The service account private key.
    • GOOGLE_APPLICATION_CREDENTIALS (Alternative): Path to the service account JSON file.

    Note: You must share the spreadsheet with the service account email before running.

    // Writing to a sheet
    import { SimpleDB } from "@nshiab/simple-data-analysis";
    
    const sdb = new SimpleDB();
    const temperatures = sdb.newTable("temperatures");
    
    await temperatures
      .loadData("https://raw.githubusercontent.com/nshiab/simple-data-analysis/main/test/data/files/dailyTemperatures.csv")
      .renameColumns({ t: "temperature", id: "station" })
      .selectColumns(["station", "time", "temperature"])
      .toSheet("https://docs.google.com/spreadsheets/d/.../edit#gid=0");
    
    await sdb.close();