Security News
tea.xyz Spam Plagues npm and RubyGems Package Registries
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
silver-spectacle
Readme
Silver Spectacle is a python library for displaying data. Its designed as a (superior) alternative to matplotlib.
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", [
# [x,y]
[ 1 , 2 ],
[ 2 , 3 ],
[ 5 , 5 ],
[ 1.5 , 2.3 ],
[ 2 , 3.2 ]
])
# >>> Server started at: http://0.0.0.0:9900
ss.DisplayCard("quickLine", [
# [x,y]
[ 1, 2 ],
[ 1.5, 2.3 ],
[ 2, 3 ],
[ 5, 5 ],
# for quickLine: dont forget to sort them by x value!
# (otherwise it'll look like an etch-a-sketch)
])
Open the address in a browser and you should see something like:
You can display images
import silver_spectacle as ss
import numpy
grayscale_or_rgb = numpy.ones((100, 200, 3)) * (127)
# doesn't even need to be a numpy array
card = ss.DisplayCard("quickImage", grayscale_or_rgb)
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 are not stored to disk. So if the browser window isn't open, then that data will be sent nowhere. This behavior will be improved in the future, but requires a bit of effort to be done in a performant way.
Multiline update example
import silver_spectacle as ss
card = ss.DisplayCard("multiLine",
dict(
# name : [ [x1,y1], [x2,y2], ]
Line1Name=[
[ 1, 2 ],
[ 1.5, 2.3 ],
[ 2, 3 ],
[ 5, 5 ],
],
Line2Name=[
[ 1+1, 2 ],
[ 1+1.5, 2.3 ],
[ 1+2, 3 ],
[ 1+5, 5 ],
],
),
dict(
title="Howdy!",
horizonal_label="horizonal_label here"
),
)
# Live update
card.send(dict(
Line1Name=[
[ 1, 2 ],
[ 1.5, 2.3 ],
[ 2, 3 ],
[ 5, 5 ],
],
Line2Name=[
[ 1+1, 2 ],
[ 1+1.5, 2.3 ],
[ 1+2, 3 ],
[ 1+5, 5 ],
],
))
NOTE: Currently each .send()
depends on the type of card (the interface). For example the arguments for quickScatter
can be different from chartjs
.
ss.DisplayCard("quickScatter", list_of_x_y_pairs)
ss.DisplayCard("quickLine", list_of_x_y_pairs)
ss.DisplayCard("quickImage", numpy_image_or_filepath)
ss.DisplayCard("quickMarkdown", markdown_text)
ss.DisplayCard("chartjs", config) # does tons: see https://www.chartjs.org/docs/latest/general/data-structures.html
ss.DisplayCard("multiLine", dict_to_x_y_pairs, options)
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 a ChartJS chart:
For example, with that line chart, look at their setup
tab
Look at the 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,
},
}
}
})
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.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 quantity of methods. Don't be afraid to open an issue asking for examples.
There are many planned features. This library is under active development. However, the API is stable, and effectively all changes will only be adding tools to the toolbox. Some of the planned features are small:
Other features will be a major additions
Development will, more than likely, be sporadic, PR's are welcome.
documentation/SETUP.md
../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 subprocesscommands/project/local_install
command to install the local version you've createddisplay
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.socket.io
and aiohttp
to get a push notification-like effect within browser windows.displayRequests
variable. Those timestamps are used as keys, allowing the browser windows to simply merge incoming data without duplication and without losing old information.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.
FAQs
An easier way to display data
We found that silver-spectacle demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
Security News
As cyber threats become more autonomous, AI-powered defenses are crucial for businesses to stay ahead of attackers who can exploit software vulnerabilities at scale.
Security News
UnitedHealth Group disclosed that the ransomware attack on Change Healthcare compromised protected health information for millions in the U.S., with estimated costs to the company expected to reach $1 billion.