Skip to main content

An easier way to display data

Project description

What is this?

Silver Spectacle is a python library for displaying data. Its designed as a (superior) alternative to matplotlib.

How do I use it?

Install just like any other pip module

pip install silver_spectacle

Then inside a python file (or python repl)

import silver_spectacle as ss

ss.DisplayCard("quickScatter", [
    [1,2],
    [2,3.2]
])
# >>> Server started at: http://0.0.0.0:9900

ss.DisplayCard("quickScatter", [
    [1,2],
    [2,3],
    [5,5],
    [1.5, 2.3],
    [2,3.2]
])

Open the address in your browser and you should see these
quick_scatter_2

You can display images

import silver_spectacle as ss

# from numpy arrays (grayscale and RGB)
import numpy
gray_rectangle = numpy.ones((100, 200, 3)) * (127)
card = ss.DisplayCard("quickImage", gray_rectangle) 

# if you have Pillow installed, it works with file paths
import PIL
card = ss.DisplayCard("quickImage", "./your_image.png")

You can also perform live/progressive updates on the charts.

import silver_spectacle as ss
card = ss.DisplayCard("quickScatter", [
    [1,2],
    [2,3.2]
])
# live / progressive updates
card.send([5,5])
card.send([1.5, 2.3])
card.send([2,3.2])

NOTE: Currently live updates need to be sent after the browser window is loaded. Otherwise the web page will miss the notification. This behavior will be fixed in the future, but requires a bit of effort to be done in a performant way.


NOTE: Currently each .send() depends on the type of card (the interface). For example the arguments for quickScatter can be different from chartjs.

What kind of plots can it do?

If Chart JS has it, then it is already available in this library. More visualization libraries like plotly will be added to enable additional 2D plots, 3D charts, video/image integration, etc.

To use one of their charts:

For example, with that line chart, look at their setup tab setup_tab

Look at the config tab config_tab

Then make a very similar structure with a python dictionary

#
# setup tab part
#
labels = [ "January", "February", "March", "April", "May", "June", "July", ]
data = {
  "labels": labels,
  "datasets": [{
    "label": 'My First Dataset',
    "data": [65, 59, 80, 81, 56, 55, 40],
    "fill": False,
    "borderColor": 'rgb(75, 192, 192)',
    "tension": 0.1
  }]
}
#
# config tag part
#
config = {
  "type": 'line',
  "data": data,
}

#
# display the data
#
import silver_spectacle as ss
ss.DisplayCard("chartjs", config)

Here's another example of how that might look

import silver_spectacle as ss
ss.DisplayCard("chartjs", {
    "type": 'line',
    "data": {
        "datasets": [
            {
                "label": 'Approach 1',
                "data": [ 85, 90, 89, 91, 92, 88 ],
                "fill": True,
                "tension": 0.1,
                "backgroundColor": 'rgb(75, 192, 192, 0.5)',
            },
            {
                "label": 'Approach 2',
                "data": [ 75, 80, 78, 81, 82, 77 ],
                "fill": True,
                "tension": 0.1,
                "backgroundColor": 'rgb(0, 292, 192, 0.5)',
            },
            {
                "label": 'Approach 3',
                "data": [ 95, 90, 99, 91, 92, 99 ],
                "fill": True,
                "tension": 0.1,
                "backgroundColor": 'rgb(0, 92, 192, 0.5)',
            },
        ]
    },
    "options": {
        "pointRadius": 3, # the size of the dots
        "scales": {
            "y": {
                "min": 50,
                "max": 100,
            },
        }
    }
})

What kind of features does it have?

  • Works everywhere: You can run this on your Raspberry Pi and view the results on your phone. It works whether it's WSL, Docker, or ssh over a VPN. No more 5 page tutorials about X11 forwarding, display variables, and editing config files.
  • Non-blocking: No more hacky/painful workarounds to get both code to execute, and a graph to update at the same time. ss.display is non-blocking by default, so use it without worrying if your overnight computation is going to stop in the middle because its waiting for user input.
  • Multiple plots are effortless: Graphs are displayed in a stream with the most recent one at the top. Just call display and forget about it. No more complex mashing of graphs together, or hassle of closing window after window, only to realize you meant to screenshot the one you just closed.
  • Independent runtime: If your main python program crashes that's fine, the cleanup function will intentionally leave the graph server running instead of killing it so you can still access your data. As long as you don't manually kill the server process, your data will be there.
  • Interactive: I'm not saying its impossible for tools like matplotlib to have custom interactivity, but lets just say nobody is doing it unless they have an unusual level of determination. Silver Spectacles let's you add custom buttons, effects, etc with ease.

Documentation?

There is some additional documentation below for fully fledged customization of the javascript and css. However, this readme is currently all of the documentation. The power is in the flexibilty, not in the breadth of tools. Don't be afraid to open an issue asking for examples.

Whats the status of the library?

There are many planned features. This library is under active development, and has not been optimized. However, the API is stable, and effectively all changes will only be adding tools to the toolbox. Some of the planned features are small:

  • adding a button for clearing the screen of existing graphs
  • an option to save/load all visual data to a file
  • better interfaces for graphs that incrementally update
  • working with numpy/pytorch/tensorflow tensors without needing to convert

Other features will be a major additions

  • tools for displaying images/videos
  • integration with 3D plot libraries
  • a simple system for combining/shaping graphs
  • a theming system
  • better visual notifications for errors
  • a simple interface for graphical plugins (buttons)

Development will, more than likely, be sporadic, PR's are welcome.

How can I contribute?

  • All the dependencies / setup instuctions are in documentation/SETUP.md.
  • That^ will automatically create a venv environment for testing/development
  • You can modify the files under ./main/silver_spectacle/
    • ./main/silver_spectacle/library.py is the code that actually gets imported
    • ./main/silver_spectacle/server.py is the code that is run inside of a subprocess
  • After modification, you can use the commands/project/local_install command to install the local version you've created

How does it work?

  • The system uses socket.io and aiohttp to get a push notification-like effect within browser windows.
  • Everytime the display function is called the library checks if the display server is running (using an http request). If the server is not running, then it starts the server as a subprocess in the background. It waits until the server is responding, then it uses http requests to tell the server about the data it wants to display.
  • The server does two things
    1. It embeds this data into the html as JSON data. This way any newly-opened pages already have all the available data. In terms of files, the server only serves the one html+js+css file.
    2. When the backend gets a http display request from the python process, it uses socket.io to notify all existing browser windows about the new data.
  • This seems trivial, but it is important: exising browser windows do not replace existing data with incoming data. That would be bad because browser windows can be open longer than both the server process or python process. So, the browser window can have more information than the server does. For that reason, all data is timestamped and stored inside the global displayRequests variable. Those timestamps are used as keys, allowing the browser windows to simply merge incoming data without duplication and without losing old information.
  • On the graphical side, the browser iterates over all the display commands, creating a chart for each one, wrapping the chart in a thin container, and placing it into a vertical list. This vertical list is displayed in reverse; the most-recent graph is at the top.
  • Thats it!

Additional documentation

Here's the basic configuration for full customization.

import silver_spectacle as ss

ss.configure(
    port=9900,
    # Note: until version 1.0.0 is released
    # make sure to pin the exact version number of silver_spectacle to keep your code reliable 
    # interactions inside JavaScript and CSS 
    # (e.g. variable and class names) will be unstable. 
    custom_css="",
    custom_js="",
    # Note2: currently custom CSS and JS only get applied when the server starts.
    # Meaning, if the server is still running from an old process
    # (a zombie server beacuse the python program crashed suddenly),
    # then it will look like your custom CSS and javascript are not being applied

    server_start_timeout=10, # this is not very important
)

Here's a more full example.

import silver_spectacle as ss
ss.configure(
    port=69420,
    custom_css="""

        body .card {
            background-color: gray;
            color: whitesmoke; /* font color */
        }

        body #stream-container {
            flex-direction: column; /* makes oldest graphs be at the top */
        }

        body {
            background: slategray !important; /* needs to be important to override other values */ 
        }
    """,
    custom_js="""
        window.onload = ()=>{
            //
            // main API
            //
            silverSpectacle.log("string")      // add information to the graphical log
            silverSpectacle.cards              // dict with cardId's as keys
            silverSpectacle.cards[0].element   // html element of card with ID of 0
            silverSpectacle.cards[0].createdAt // unix time in seconds
            silverSpectacle.cards[0].interface // name of interface as string
            silverSpectacle.cards[0].arguments // array of json values
            silverSpectacle.interface          // dict of fuctions that create card elements
            silverSpectacle.libraries          // dict of libraries, like ChartJS that you can use
            silverSpectacle.libraries.lodash   // if you like lodash, its available

            //
            // add your own card/interface
            //
                // step 1, create a function like the one below (an interface)
                silverSpectacle.interface["myCustomUi"] = async (args) => {
                    let message = args[0]
                    let myComponent = document.createElement("div")
                    myComponent.innerHTML = "Python says:<br>"+message

                    // silverSpectacle.createCard() wraps the component to give it the white background and shadow
                    let card = silverSpectacle.createCard({ children: [ myComponent ], })

                    // (optional) add a handler for dyanmic data
                    card.receive = function (data) {
                        // update the component
                        myComponent.innerHTML += `<br> python also wanted to say: {JSON.stringify(data)}`
                        // warning / error checking
                        if (typeof data != 'string') {
                            silverSpectacle.log("[warning] data was dynamically sent to myCustomUi, but it wasn't a string")
                        }
                    }

                    // needs to return an html element
                    return card
                }
                // step 2, call it from python!
                //
                //     import silver_spectacle as ss
                //     # create card
                //     custom_card = ss.DisplayCard("myCustomUi", "hello world")
                //     import time
                //     time.sleep(5)
                //     # add more data after the fact
                //     custom_card.send("I waited 5 sec to send this")
        }
    """,
    server_start_timeout=10, # (seconds)
    # this^ is not very important
    # the value is how long to wait if the server doesn't start at all
    # designed to fail without throwing an error encase the user 
    # is performing important computations
)

Right now, there is still a lot of room for improving/expanding the javascript interface with events, tools, and encapsulation.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

silver_spectacle-0.3.2.tar.gz (129.5 kB view details)

Uploaded Source

Built Distribution

silver_spectacle-0.3.2-py3-none-any.whl (123.7 kB view details)

Uploaded Python 3

File details

Details for the file silver_spectacle-0.3.2.tar.gz.

File metadata

  • Download URL: silver_spectacle-0.3.2.tar.gz
  • Upload date:
  • Size: 129.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.6.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.8.6

File hashes

Hashes for silver_spectacle-0.3.2.tar.gz
Algorithm Hash digest
SHA256 e1bb3b9e360d97e75da6670c83e291fff40e249313c9407504bc3d80a54caa4b
MD5 9a8d3f4576e61ca679a15efcbd2b12cb
BLAKE2b-256 b61a65825f27e67296c0473c0d51945ac2137bfb7b97ff26213bccc622d3b1a5

See more details on using hashes here.

File details

Details for the file silver_spectacle-0.3.2-py3-none-any.whl.

File metadata

  • Download URL: silver_spectacle-0.3.2-py3-none-any.whl
  • Upload date:
  • Size: 123.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.6.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.8.6

File hashes

Hashes for silver_spectacle-0.3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 6c3470d85b9d7b2b7bb9ec862f07561e9d0fad993441f5f5c664eb9d00623beb
MD5 551923d82dbe0e02c244b45b8b503c27
BLAKE2b-256 2ff2592cd130be47943e20f69e89160a59bca862dca5d64c4bbc213986805fdc

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page