Utilities for converting Vega-Lite specs from the command line and Python

Overview

VlConvert

VlConvert provides a Rust library, CLI utility, and Python library for converting Vega-Lite chart specifications into static images (SVG or PNG) or Vega chart specifications.

🎉 Announcement Blog Post 🎉

Try the Python library out on Binder!
Binder

Getting started

CLI

Install vl-convert using cargo with:

$ cargo install vl-convert
$ vl-convert --help

vl-convert: A utility for converting Vega-Lite specifications

Usage: vl-convert <COMMAND>

Commands:
  vl2vg      Convert a Vega-Lite specification to a Vega specification
  vl2svg     Convert a Vega-Lite specification to an SVG image
  vl2png     Convert a Vega-Lite specification to an PNG image
  vg2svg     Convert a Vega specification to an SVG image
  vg2png     Convert a Vega specification to an PNG image
  ls-themes  List available themes
  cat-theme  Print the config JSON for a theme
  help       Print this message or the help of the given subcommand(s)

Options:
  -h, --help     Print help information
  -V, --version  Print version information

For example, convert a Vega-Lite specification file named in.vl.json into an SVG file named out.svg. Perform the conversion using version 5.5 of the Vega-Lite JavaScript library.

$ vl-convert vl2svg -i ./in.vl.json -o ./out.svg --vl-version 5.5

Python

Install the vl-convert-python package using pip

$ pip install vl-convert-python

Then in Python, import the library, use the vegalite_to_png function to convert a Vega-Lite specification string to a PNG image, then write the image to a file.

import vl_convert as vlc

vl_spec = r"""
{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {"url": "data/movies.json"},
  "mark": "circle",
  "encoding": {
    "x": {
      "bin": {"maxbins": 10},
      "field": "IMDB Rating"
    },
    "y": {
      "bin": {"maxbins": 10},
      "field": "Rotten Tomatoes Rating"
    },
    "size": {"aggregate": "count"}
  }
}
"""

png_data = vlc.vegalite_to_png(vl_spec=vl_spec, scale=2)
with open("chart.png", "wb") as f:
    f.write(png_data)

For more examples, see the vl-convert-python README.

Motivation

VlConvert was motivated by the needs of VegaFusion, which extracts data transformations from Vega specifications and evaluates them on the server. Using VlConvert, VegaFusion can input Vega-Lite specifications directly. That said, VlConvert is designed to be used by the wider Vega-Lite ecosystem, independent of VegaFusion.

How it works

VlConvert relies on the standard Vega-Lite JavaScript library to perform the Vega-Lite to Vega conversion. It uses the Deno project (in particular deno_runtime) to run Vega-Lite using the v8 JavaScript runtime, embedded into a Rust library called vl-convert-rs. This Rust library is then wrapped as a CLI application (vl-convert) and a Python library using PyO3 (vl-convert-python).

In addition to easy embedding of the v8 JavaScript runtime, another advantage of building on deno_runtime is that it's possible to customize the module loading logic. vl-convert-rs takes advantage of this to inline the minified JavaScript source code for multiple versions of Vega-Lite, and all their dependencies, into the Rust library itself. This way, no internet connection is required to use vl-convert, and the executable and Python library are truly self-contained.

Vega-Lite to Vega conversion

The Vega-Lite to Vega compilation is performed directly by the Vega-Lite library running fully in the Deno runtime.

Vega(-Lite) to SVG

The Vega JavaScript library supports exporting chart specifications to SVG images, and this conversion works in Deno. However, there is a subtle complication. In order to properly position text within the exported SVG, Vega needs to compute the width of text fragments (at a particular font size, in a particular font, etc.). When running in Node.js, these calculations are done using node canvas, which does not work in Deno. When node canvas is not available, Vega falls back to a rough heuristic for text measurement that results in poor text placement results.

VlConvert works around this by overriding the text width calculation function using a custom Rust function. This custom Rust function uses the usvg crate (part of the resvg project) to compute the width of text fragments. With this customization, we regain accurate text placement in the SVG results produced by Vega.

Vega(-Lite) to PNG

The Vega JavaScript library supports exporting chart specifications directly to PNG images. When running in Node.js, this functionality relies on node canvas, which is not available in Deno.

VlConvert generates PNG images by first exporting charts to SVG as described above, then converting the SVG image to a PNG image using the resvg crate.

Limitations

PNG Performance

VlConvert relies on the resvg Rust library for rendering PNG images from the SVG produced by Vega. resvg is a very accurate implementation of SVG rendering, but it is not GPU accelerated and can be somewhat slow when asked to render charts with many individual marks (e.g. large scatter plots). For a single pane scatter plot, the performance is on the order of 1 second per 1000 points.

If PNG rendering performance is prohibitive, the recommended approach is to export to SVG and use another approach to convert the resulting SVG images to PNG.

System font requirements

SVG text placement and PNG text rendering require that the fonts referenced by the exported chart are installed on the system that VlConvert is running on. For example, when using the vl-convert-python package in Google Colab, VlConvert will only have access to the limited set of fonts installed in the Colab kernel. It will not have access to the user fonts that the web browser has access to.

A directory containing additional font files can registered with the VlConvert Python library using the vl_convert.register_font_directory function. Similarly, the --font-dir argument can be used to register custom fonts in the vl-convert CLI application.

Emoji support in PNG export

The Altair isotype emoji gallery example does not currently convert property to PNG.

Built-in Datasets

The Vega Editor supports referring to built-in datasets as if the exist under a data/ directory (e.g. data/cars.json). This is not currently supporte by VlConvert. Instead an absolute URL must be used (e.g. https://raw.githubusercontent.com/vega/vega-datasets/next/data/cars.json).

Comments
  • Allow A Configuration file in `~/.config/vl-convert/config.json`

    Allow A Configuration file in `~/.config/vl-convert/config.json`

    I could imagine some fun tools making use of vl-convert in a terminal context where having a general config file would be nice (with semantics like { config: { ...userConfig, ...specConfig } }). I would imagine that the config would just be a regular config.

    enhancement 
    opened by lsh 6
  • Quickjs, Okab (altair saver)

    Quickjs, Okab (altair saver)

    Hey all, thanks for working on this! Just to let you know, there is similar development effort going on at okab. It started as a way to provide a better altair-saver method I think. I've asked the author if he's interested in somehow joining forces, see this thread.

    The thread started with my idea of using QuickJs javascript engine, which might also be relevant here. See also quickjs-rs. QuickJS does run the minified vega and vega-lite code.

    What are your thoughts?

    opened by k-groenbroek 4
  • refactoring: remove vega and vegalite wrappers

    refactoring: remove vega and vegalite wrappers

    Continuation of the discussion that started from this comment and onwards.

    Vega 5 specifications can currently be rendered using Altair, with support of interactivity:

    import altair.vega.v5 as alt
    import json
    vg_spec = r"""
    {
      "$schema": "https://vega.github.io/schema/vega/v5.json",
      "description": "A basic bar chart example, with value labels shown upon mouse hover.",
      "width": 400,
      "height": 200,
      "padding": 5,
      "data": [
        {
          "name": "table",
          "values": [
            {"category": "A", "amount": 28},
            {"category": "B", "amount": 55},
            {"category": "C", "amount": 43},
            {"category": "D", "amount": 91},
            {"category": "E", "amount": 81},
            {"category": "F", "amount": 53},
            {"category": "G", "amount": 19},
            {"category": "H", "amount": 87}
          ]
        }
      ],
      "scales": [
        {
          "name": "xscale",
          "type": "band",
          "domain": {"data": "table", "field": "category"},
          "range": "width",
          "padding": 0.05,
          "round": true
        },
        {
          "name": "yscale",
          "domain": {"data": "table", "field": "amount"},
          "nice": true,
          "range": "height"
        }
      ],
      "axes": [
        {"orient": "bottom", "scale": "xscale"},
        {"orient": "left", "scale": "yscale"}
      ],
      "marks": [
        {
          "type": "rect",
          "from": {"data": "table"},
          "encode": {
            "enter": {
              "x": {"scale": "xscale", "field": "category"},
              "width": {"scale": "xscale", "band": 1},
              "y": {"scale": "yscale", "field": "amount"},
              "y2": {"scale": "yscale", "value": 0}
            },
            "update": {"fill": {"value": "steelblue"}},
            "hover": {"fill": {"value": "red"}}
          }
        }
      ]
    }
    """
    alt.vega(json.loads(vg_spec))
    

    image

    Now, one can also use vl-convert (pip/conda install vl-convert-python) to render these as png or svg in a notebook:

    import vl_convert as vlc
    from IPython.display import Image
    from IPython.display import SVG, display
    
    #vg_png = vlc.vega_to_png(vg_spec)  # Image(vg_png)
    vg_svg = vlc.vega_to_svg(vg_spec)
    display(SVG(vg_svg))
    

    image But as far as I can tell it does not support the interactivity (btw just like a svg-export from the Vega Editor with above example).

    Introducing errors in the spec, propagate JavaScript warnings back to the notebook, in both cases: Changing eg: "from": {"data": "table"}, to "from": {"data": "FOO"}, Results with Altair variant:

    Javascript Error: Undefined data set name: "FOO"
    

    And with vl-convert variant:

    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    Cell In[19], line 6
          3 from IPython.display import SVG, display
          5 #vg_png = vlc.vega_to_png(vg_spec)  # Image(vg_png)
    ----> 6 vg_svg = vlc.vega_to_svg(vg_spec)
          7 display(SVG(vg_svg))
    
    ValueError: Vega to SVG conversion failed:
    Error: Undefined data set name: "FOO"
        at b (https://cdn.skypack.dev/-/[email protected]/dist=es2020,mode=imports,min/optimized/vega-util.js:1:324)
        at ue.getData (https://cdn.skypack.dev/-/[email protected]/dist=es2020,mode=imports,min/optimized/vega-parser.js:1:45069)
        at At (https://cdn.skypack.dev/-/[email protected]/dist=es2020,mode=imports,min/optimized/vega-parser.js:1:21597)
        at Sa (https://cdn.skypack.dev/-/[email protected]/dist=es2020,mode=imports,min/optimized/vega-parser.js:1:21499)
        at Bt (https://cdn.skypack.dev/-/[email protected]/dist=es2020,mode=imports,min/optimized/vega-parser.js:1:24270)
        at https://cdn.skypack.dev/-/[email protected]/dist=es2020,mode=imports,min/optimized/vega-parser.js:1:39099
        at Array.forEach (<anonymous>)
        at hn (https://cdn.skypack.dev/-/[email protected]/dist=es2020,mode=imports,min/optimized/vega-parser.js:1:39088)
        at al (https://cdn.skypack.dev/-/[email protected]/dist=es2020,mode=imports,min/optimized/vega-parser.js:1:39762)
        at Module.sl (https://cdn.skypack.dev/-/[email protected]/dist=es2020,mode=imports,min/optimized/vega-parser.js:1:47716)
    

    Since it is not the core of Altair, we can decide for maintenance purposes to remove the Vega (currently v5) wrappers and leave this to vl-convert if people like to make use of this within a notebook environment.

    Altair had until this commit support in the main version on Github support for the following Vega-Lite versions: Altair Version | Vega-Lite Version | Vega Version -- | -- | -- 4.3.0.dev0 | v3.4.0, v4.17.0, v5.2.0 | v5.21.0

    Three versions of Vega-Lite seems too many, and we are still discussing if we can reduce it to only a single version of Vega-Lite. But the v3 version is obsolete anyway. These packages/tests can safely be removed from main.

    opened by mattijn 2
  • Saving HTML charts with offline rendereing and interactivity by inlining external resources

    Saving HTML charts with offline rendereing and interactivity by inlining external resources

    I just noticed that this was a functionality of Altair saver as mentioned here https://stackoverflow.com/a/63103365/2166823. Is this something that would fit into vl-convert as well? I'ts more like a small convenience, but curious if this would be an option. Some of this functionality might already exist here https://github.com/altair-viz/altair_viewer

    opened by joelostblom 2
  • `vl-convert-python` svg output issue for scatterplots

    `vl-convert-python` svg output issue for scatterplots

    This code:

    from vl_convert import vegalite_to_svg
    from urllib.request import urlopen
    import json
    prefix = "https://raw.githubusercontent.com/vega/vega-lite/next/examples/specs/"
    f = "sample_scatterplot.vl.json"
    spec = json.loads(urlopen(prefix + f).read())
    with open("test.svg", "w") as out:
      out.write(vegalite_to_svg(spec))
    

    Yields this output for me (I uploaded the actual SVG so view-source as needed):

    test

    I'm on MacOS 11.6 on Apple Silicon, Python 3.10 installed by mamba

    opened by nicolaskruchten 1
  • Add support for named themes and custom config objects

    Add support for named themes and custom config objects

    Overview

    This PR adds support for converting Vega-Lite charts using named themes and custom config objects.

    It also closes #18 by loading a default config object from a user settings directory (CLI only for now)

    Rust updates

    The Rust VlConverter struct now supports passing theme strings and config JSON objects to Vega-Lite conversion functions.

    In addition, a new get_themes() function was added that returns a JSON object containing all of the built-in themes. This makes it possible to inspect the config object corresponding to built-in themes.

    Python updates

    The Python changes mirror the Rust changes exactly. There is a new get_themes function that returns a Python dict containing all of the built-in theme config objects.

    CLI

    The vl2* subcommands now accept --theme and --config options, where --theme expects a theme name and --config expects a path to a file containing a JSON object.

    If a file exists at ~/.config/vl-convert/config.json, The CLI will use this path as the default value of the --config flag across all subcommands.

    In addition, two new subcommands were added to get info on built in themes: ls-themes and cat-theme.

    ls-themes

    $ vl-convert ls-themes --help
    
    List available themes
    
    Usage: vl-convert ls-themes
    
    Options:
      -h, --help  Print help information
    

    Here is an example of listing the names of all available built-in themes.

    $ vl-convert ls-themes
    
    dark
    excel
    fivethirtyeight
    ggplot2
    googlecharts
    latimes
    powerbi
    quartz
    urbaninstitute
    vox
    

    cat-theme

    $ vl-convert cat-theme --help
    
    Print the config JSON for a theme
    
    Usage: vl-convert cat-theme <THEME>
    
    Arguments:
      <THEME>  Name of a theme
    
    Options:
      -h, --help  Print help information
    

    For example, print the config JSON associated with the built-in dark theme

    $ vl-convert cat-theme dark
    
    {
      "background": "#333",
      "title": {
        "color": "#fff",
        "subtitleColor": "#fff"
      },
      "style": {
        "guide-label": {
          "fill": "#fff"
        },
        "guide-title": {
          "fill": "#fff"
        }
      },
      "axis": {
        "domainColor": "#fff",
        "gridColor": "#888",
        "tickColor": "#fff"
      }
    }
    
    opened by jonmmease 1
  • Check for theme in usermeta.embedOptions.theme

    Check for theme in usermeta.embedOptions.theme

    This PR updates the VlConverter to check Vega-Lite specs for a named theme specified in usermeta.embedOptions.theme. This is what vega-embed does, and this is where Altair places it's named theme.

    This will make named these work with Altair without any Altair changes.

    See background in https://github.com/altair-viz/altair/issues/781

    opened by jonmmease 0
  • Make get_local_tz fallible, returing Option<String> instead of String

    Make get_local_tz fallible, returing Option instead of String

    This is to handle the case where Intl.DateTimeFormat().resolvedOptions().timeZone is undefined in Deno.

    I ran into this running VlConvert on Binder, where Intl.DateTimeFormat().resolvedOptions().timeZone is undefined and this caused get_local_tz to crash.

    opened by jonmmease 0
  • Bump dependencies

    Bump dependencies

    This updates deno to the latest version and resvg to 0.27.0. There is more to do to update to 0.28.0 (https://github.com/RazrFalcon/resvg/blob/master/CHANGELOG.md), so holding off on that for now.

    opened by jonmmease 0
  • feat: Add get_local_tz function

    feat: Add get_local_tz function

    Add a get_local_tz function to the Rust and Python API that returns the named timezone of the Deno runtime (which Vega is inherently using for timezone math).

    opened by jonmmease 0
  • Image export crash when font string includes quoted font family

    Image export crash when font string includes quoted font family

    When a font specification includes a font family quoted in double quotes, image export crashes the Python kernel.

    import vl_convert as vlc
    spec = {
      "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
      "layer": [
        {
          "data": {
            "name": "df",
            "values": [{"a": 1, "b": 1}, {"a": 2, "b": 3}, {"a": 3, "b": 2}]
          },
          "layer": [
            {
              "transform": [],
              "layer": [
                {
                  "mark": {"type": "line"},
                }
              ],
              "encoding": {
                "x": {
                  "field": "a",
                  "type": "quantitative"
                },
                "y": {
                  "field": "b",
                  "type": "quantitative"
                },
              }
            }
          ]
        }
      ],
      "config": {
        "style": {
          "guide-label": {
            "font": "Arial, sans-serif"
          },
          "guide-title": {
            "font": "Arial, sans-serif"
          }
        }
      }
    }
    
    # Works ok
    svg = vlc.vegalite_to_svg(spec)
    
    # Update font strings to quote Arial. Crashes kernel
    spec["config"]["style"]["guide-label"]["font"] = "\"Arial\", sans-serif"
    spec["config"]["style"]["guide-label"]["font"] = "\"Arial\", sans-serif"
    svg = vlc.vegalite_to_svg(spec)
    

    A little more info in the stack trace is available when running the example in Rust:

    thread '<unnamed>' panicked at 'Failed to parse text SVG: ParsingFailed(ParserError(InvalidAttribute(InvalidSpace(73, TextPos { row: 3, col: 54 }), TextPos { row: 3, col: 54 })))', vl-convert-rs/src/text.rs:187:59
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    fatal runtime error: failed to initiate panic, error 5
    Fatal Python error: Aborted
    

    The first thing we should do is update error handling to not panic and crash the kernel on SVG parse failure. Then we should fix the bug 😄

    bug 
    opened by jonmmease 0
  • `vl-convert-python` does not support built-in Vega datasets

    `vl-convert-python` does not support built-in Vega datasets

    Here's a little test case... the first one works and the other two don't:

    from vl_convert import vegalite_to_svg
    from urllib.request import urlopen
    import json
    prefix = "https://raw.githubusercontent.com/vega/vega-lite/next/examples/specs/"
    files = ["arc_donut.vl.json", "point_binned_color.vl.json", "line_color_binned.vl.json"]
    for f in files:
      spec = json.loads(urlopen(prefix + f).read())
      vegalite_to_svg(spec)
    

    I'm on MacOS 11.6 on Apple Silicon, Python 3.10 installed by mamba

    enhancement 
    opened by nicolaskruchten 1
  • Compatability with the data server transformer

    Compatability with the data server transformer

    I noticed that enabling the data server transformer causes vl convert to hang indefinitely. Is this something that is fixable or is vl-convert meant to be used with vega-fusion instead? Since we are planning to have vl-convert take precedence over altair_saver, it would be great if it also worked with the data server transformer like altair_saver does to ensure full backwards compatibility.

    Example that hangs for me on vl-convert 0.5.0 and altair 4.2.0, python 3.10.x

    import pandas as pd
    import altair as alt
    
    alt.data_transformers.enable('data_server')
    source = pd.DataFrame({
        'a': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'],
        'b': [28, 55, 43, 91, 81, 53, 19, 87, 52]
    })
    chart = alt.Chart(source).mark_bar().encode(
        x='a',
        y='b'
    )
    
    
    # Saving the chart
    import vl_convert as vlc
    
    png_data = vlc.vegalite_to_png(chart.to_dict())
    with open("chart.png", "wb") as f:
        f.write(png_data)
    
    bug 
    opened by joelostblom 5
  • label limit legend

    label limit legend

    Given this python snippet:

    import vl_convert as vlc
    from IPython.display import Image
    vl_spec = '''
    {
      "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
      "data": {
        "values": [
          {"a": "J", "b": 28, "c": "I am more than 18 characters"},
          {"a": "B", "b": 55},
          {"a": "C", "b": 43},
          {"a": "D", "b": 91},
          {"a": "E", "b": 81},
          {"a": "F", "b": 53},
          {"a": "G", "b": 19},
          {"a": "H", "b": 87},
          {"a": "I", "b": 52}
        ]
      },
      "mark": "bar",
      "encoding": {
        "x": {"field": "a", "type": "nominal"},
        "y": {"field": "b", "type": "quantitative"},
        "color": {"field": "c"}
      }
    }
    '''
    png_data = vlc.vegalite_to_png(vl_spec=vl_spec)
    Image(png_data)
    

    Will return the following truncated legend label : image

    Where the vega-editor render this as: image And in editor: Open the Chart in the Vega Editor

    The default labelLimit within legend is 160 pixels, but this seems not being respected and changing this value has no positive effect on the image.

    bug 
    opened by mattijn 3
  • Conda-forge package

    Conda-forge package

    Would it be possible to release this package as well on conda-forge? That would make it a bit more accessible for users:

    conda/mamba install vl-convert-python
    
    enhancement 
    opened by mattijn 3
Releases(v0.7.0)
Owner
Vega
Data Visualization Languages & Tools
Vega
A bit-packed k-mer representation (and relevant utilities) for rust

K-mer class for rust The purpose of this repository is to build a simple library that exposes a bit-packed k-mer class for use in rust-based bioinform

COMBINE lab 41 Dec 15, 2022
📘 Utilities for the Fibonacci Number and Sequence

Fibora Port of fibonacci-deno for Rust. Utilities for the Fibonacci Number and Sequence. Usage This package exposes two Functions, fibonacci and fibon

Eliaz Bobadilla 5 Apr 6, 2022
🚃 lib for CLI utilities, printing, and error handling

axocli Common code for setting up a CLI App and handling errors/printing. Example See examples/axoapp.rs for a walkthrough/example. Some various inter

axo 5 Apr 4, 2023
Rust command-line tool to encrypt and decrypt files or directories with age

Bottle A Rust command-line tool that can compress and encrypt (and decrypt and extract) files or directories using age, gzip, and tar. Bottle has no c

Sam Schlinkert 1 Aug 1, 2022
repl / scripting language / namespaced command line aliases

Adana Toy project with the following goals in mind: Making something concrete with rust Learning more about parser combinator Use the minimum amount o

Nordine Bittich 10 Aug 28, 2022
An open source WCH-Link library/command line tool written in Rust.

wlink - WCH-Link command line tool NOTE: This tool is still in development and not ready for production use. Known Issue: Only support binary firmware

WCH MCU for Rust 22 Mar 7, 2023
A fast uuid generator in Python using Rust

ruuid A fast UUID generator for Python built using Rust. Its a simple wrapper on top of Rust's UUID crate. How to use? Installation: pip3 install ruui

Rahul Nair 19 Jul 13, 2022
Write Anchor-compatible Solana programs in Python

seahorse: Write Solana programs in Python The ease of Python with the safety of Rust. Seahorse lets you write Solana programs in Python. It is a commu

✨ amelia chen ✨ 214 Dec 28, 2022
CSGO demo parser for Python

CSGO demo parser for Python Demo parser for Counter-Strike: Global Offensive. Parser is used to collect data from replay files (".dem" files). The goa

null 11 Dec 7, 2022
A Rust-powered linear programming library for Python.

Dantzig: A Rust-powered LP library for Python Dantzig is a lightweight and concise linear programming solver suitable for small and large-scale proble

Matteo Santamaria 4 Jan 10, 2023
Like wc, but unicode-aware, and with per-line mode

Like wc, but unicode-aware, and with per-line mode

Skyler Hawthorne 34 May 24, 2022
Salty and Sweet one-line Rust Runtime Optimization Library

SAS SAS (Salty-And-Sweet) is an one-line Rust runtime optimization library. Features NUMA-aware rayon: numa feature should be enabled If you have 1 NU

UlagBulag 3 Feb 21, 2024
cargo-add command to make dependencies into dylibs

cargo add-dynamic This cargo command allows to wrap dependencies as dylibs. For why you might want this see Speeding up incremental Rust compilation w

Robert Krahn 62 Dec 27, 2022
A tool that helps you to turn in one command a Rust crate into a Haskell Cabal library!

cabal-pack A tool that helps you to turn in one command a Rust crate into a Haskell Cabal library! To generate bindings, you need to annotate the Rust

Yvan Sraka 18 Dec 31, 2022
An API for getting questions from http://either.io implemented fully in Rust, using reqwest and some regex magic. Provides asynchronous and blocking clients respectively.

eithers_rust An API for getting questions from http://either.io implemented fully in Rust, using reqwest and some regex magic. Provides asynchronous a

null 2 Oct 24, 2021
Safe, efficient, and ergonomic bindings to Wolfram LibraryLink and the Wolfram Language

wolfram-library-link Bindings to the Wolfram LibraryLink interface, making it possible to call Rust code from the Wolfram Language. This library is us

Wolfram Research, Inc. 28 Dec 6, 2022
This blog provides detailed status updates and useful information about Theseus OS and its development

The Theseus OS Blog This blog provides detailed status updates and useful information about Theseus OS and its development. Attribution This blog was

Theseus OS 1 Apr 14, 2022
Omeglib, a portmanteau of "omegle" and "library", is a crate for interacting with omegle, simply and asynchronously

Omeglib, a portmanteau of "omegle" and "library", is a crate for interacting with omegle, simply and asynchronously. It is intended to suit one's every requirement regarding chat on omegle.

null 1 May 25, 2022