Skip to content

ice3/look_at_me

Repository files navigation

Look At Me - Control Me

Description

  • Look At Me: a simple way to plot the value of your variable, in real time, in your browser. Just add one line in your code and you're good to go. Very pretentious.
  • Control Me: a simple way to modify some parameters in your code, in real time, from your browser, and you can see the effect in your look at me graph.

Quick Start

1. Start the backend

cd look_at_me
source .venv/bin/activate
python -m backend.main

2. Start the frontend

cd frontend
npm install  # first time only
npm run dev

3. Run an example

python scripts/example_producer.py

Now go to http://localhost:3000/ and watch the magic happen.

A day in a programmer's life

One day, I had to change a piece code that produced some data and I wanted to see what it was doing. So I designed an ugly hack to plot the data. Redirect everything in a file, used Matplotlib / gnuplot to plot them and it was OK. Don't judge me, you've done that too -- or not, but in this case you still don't know what's happening and you're not better than me.

Then I had another project, other data, same problem. Data format was different, copy paste the hack, tweak it and Bob's your uncle, I have the trend.

Then, something awful happened. I had to look at the data while they were produced. No problem, Matplotlib has an animation library, you update the data, everything is good. Too bad it had to work on macOS where Matplotlib's animation framework is broken...

Now imagine I have to set a threshold on these data. What can I do? I can plot them, modify my program, kill it, compile / launch it and I can see my value is wrong. Great! Took me 20 seconds to change a number and now I'm checking my emails... All this to modify the threshold again.

So I decided to create look at me / control me, a simple logging / visualization tool for variables where you can also easily control / change them.

Features

Widget Types

  • XY Scatter: Plot 2D points with optional trails (great for joysticks, touchpads, robot positions)
  • Line Chart: Rolling window of values over time
  • Histogram: Distribution of values in a sliding window
  • Text: Display the current value
  • History Text: Scrolling log of values

Derived Sources

Transform your raw data on-the-fly! Send "123 456" from your code, transform it to {x: 123, y: 456} in the browser. Available transformations:

  • String ops: split, strip, regex_extract, replace, substring
  • Numeric ops: parse_int, parse_float, scale, offset, clamp, round
  • Vector ops: add_vector, scale_vector, map_parse_int, map_parse_float
  • Structure ops: to_dict, pick, get_field, get_index
  • JSON: parse_json, to_json
  • Advanced: expression (use formulas like x * 2 + 1)

Performance

Rate-limited at 20Hz to keep your browser happy. Because 1000 updates per second is great for your data, not so great for your CPU fan.

Architecture

Your Code  →  ZMQ (5556)  →  Backend (FastAPI)  →  SSE  →  React Frontend
                                    ↓
                           Derived Sources
                        (server-side transforms)

Comparison with other tools

  • Print: great, but where is the plot?
  • Print and gnuplot: what if I tell you that some people want to see things when they happen and not (a long time) after?
  • Matplotlib (Python): same as gnuplot. Also, good luck with macOS.
  • Awesome custom Qt5 application: you must be kidding.

More seriously, these are great tools for some applications. Nevertheless, you have to write custom ad hoc code each time and it's a pity.

Installation

Backend

python -m venv .venv
source .venv/bin/activate
pip install .

Or with uv (faster):

uv venv
source .venv/bin/activate
uv pip install .

For development (editable mode):

pip install -e .

Frontend

cd frontend
npm install

Usage

From the command line

# Pipe any command output to Look At Me
cat data.txt | lookatme-pipe myvar
tail -f /var/log/syslog | lookatme-pipe logs
sensor_reader | lookatme-pipe sensor -n  # -n to parse as numbers

# Or wrap a command directly
lookatme myvar -- python my_script.py
lookatme metrics -n -- ./read_sensors  # -n for numeric, -j for JSON

From Python

from sdk import send, control

# Simple value
send("my_variable", 42)

# Multiple values (will be transformed via Derived Sources if needed)
send("touchpad", f"{x} {y}")

# JSON
send("robot_state", {"x": 1.5, "y": 2.3, "angle": 45})

# Controllable parameter (slider in the UI)
gain = control("gain", default=1.0, widget="slider", min=0.0, max=10.0)
print(gain.value)  # Get current value from UI

How it works

  1. Your code sends data via ZMQ PUB/SUB
  2. Backend receives, stores, and optionally transforms data
  3. Frontend subscribes via Server-Sent Events (SSE)
  4. Widgets render the data in real-time

Ports

  • Frontend: http://localhost:3000
  • Backend API: http://localhost:8080
  • ZMQ SUB: tcp://127.0.0.1:5556
  • ZMQ PUB: tcp://127.0.0.1:5557

Limitations

  • Currently Python-only client (but ZMQ is polyglot, PRs welcome!)
  • No persistence of data (refresh = gone)
  • Limited to ~20Hz display rate (by design)

About

In 1960's we went to the the moon and in 2020's we can't even plot data in real time? Let's be serious 2 seconds.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors