Scouting Data Scoring Heatmap 2024

Can you explain how that works?


For some things, like editing certain server values (for example, adding a scouter name), a POST request is sent to edit that value. After that request is received without error, a refresh is triggered client-side, which causes a series of GET requests to be sent. There is also a button located in the bottom left corner that manually triggers the client-side refresh and GET requests.

yeah I kinda went with the same direction, ended up doing something that fetches the DB automatically every 10 seconds so thats pretty cool

 useEffect(() => {

        const intervalId = setInterval(fetchData, 10000);

        return () => clearInterval(intervalId);
    }, []);
1 Like

@Jeef I am starting to work on the heat map, it got me wondering how you guys are doing it.
I started with adding a picture of the field and dots on it, not sure tho I am in the right track

1 Like

All the implementations I’ve seen here are using this JavaScript library: heatmap.js : Dynamic Heatmaps for the Web which is MIT license.

Here is my code to display a heat map using that library based on data in the percentage of the image format that I posted earlier. viper/www/team.js at 10669b69edb55a0734206b95a3a19e0c7f72f6da · FRCTeam1073-TheForceTeam/viper · GitHub. The library’s documentation has simpler examples.

1 Like

I thought about it, but wouldn’t it be a bit overkill? Since I only need red and green dots

1 Like

It adds the colored cloud around the dots. Just dots isn’t really a “heat map”. It’s “data points”. If you think data points are enough, that is fine, but the heat map can help point out hot spots a lot better than just the data points. It also highlights data points that are directly on top of each other so that they look different than a single data point.

The library isn’t very big, it performs very well, and it is licensed in a way that can be used for most FRC projects, so I don’t see a compelling reason NOT to take advantage of it.

Alright great I will check more on this, thanks for the advice :muscle:

1 Like

Hey, btw I just wanted to say thank you for mentioning it, I started working with it a few days ago and it is really easy to use and looks amazing.
I went with a thing that takes the team color from frc colors and then displays the dot given from the database.
Right now the dots are pretty random because the scouting system still can not generate XY coords, but it works in the strategy app atm :slight_smile:

heres how it looks:


you mention you use QR to pass the data, I was wondering how do you pass the data for the places the team shot from (like XY coords or something)
Because right now my friend works on it, and he sends me this picture:
Which is clearly unscanable

1 Like

You can break the data into multiple QR codes and scan several of them.

There are also other methods for uploading data . We prefer wired ethernet connections with USB dongles to our tablets.

1 Like

If I am understanding this right, you encode the scouting data from a match into a qr code and import it into the master device which contains the database by scanning the qr code and decoding the data. How do you encode/decode? Can a scouter go multiple matches without giving data to the master, or do they have to gather and upload after every match? What database do you use? This system seems like a great no-internet solution.

Correct that is exactly what we do. The data is encoded into a QR code which is then scanned by an external device, decoded, and uploaded to a server.

The encoding/decoding method I am using currently is essentially binary, making it very compact. However, this results in me using a bunch of unconventional (aka not-divisible-by-2) bit counts :skull:


  • Team number is encoded into exactly 14 bits, which is just enough to fit 4 digits.
  • Timestamps are measured in milliseconds but are encoded with a precision of 100ms. They are encoded into 12 bits which is a little more than enough to leave some buffer room. This is because scouters usually start the match on time by clicking the “Start” button but lag behind the actual robot.
  • Coordinates are stored in 11 and 10 bits for x and y respectively.

These bits are then encoded into base64 text.

A scouter can go multiple matches without scanning and the device can even power off. The match datas are stored in localStorage.

The database is some free Python Flask app hoster: PythonAnywhere. However, I was surprised that it wasn’t as slow as I expected despite being free (upload time at a competition with bad service was less than 2 seconds).

The system works pretty well so far, but a big issue is that it was never packaged as an application for the Fire Tablets we use (I never had enough time :cry:). So, whenever a tablet powered off, it would reload the webpage containing the app. This would cause it to break as Fire Tablet’s Silk Browser didn’t support PWAs.


Hey, sorry for asking questions so frequently (if this is too much lmk lol)
I appreciate all of your and @stephen.ostermiller responses :smile:

I was wondering how what libraries you use for the data showcase (like for showing graphs and stuff)

1 Like

For everything other than heatmaps we are using chart.js to display graphs. Specifically we are using:

  • stacked bar charts
  • box plots

Like the heatmap library, it is MIT License, so easy to use with FRC projects.

As far as answer questions, keep them coming. I wouldn’t volunteer as a mentor if I didn’t want to help.

1 Like

No worries! Questions are appreciated!

We actually don’t show too many graphs; our main and only graphical display is simply a scatterplot of a team’s performance throughout a single regional (there are no lines being drawn). These graphics are created from basic HTML elements positioned absolutely within a box as to avoid loading a large amount of external scripts or libraries during a robotics competition (where service is limited).

Heatmaps are generated using Patrick Wied’s heatmap.js library.

1 Like

exactly what I needed! also was very simple to set up, thanks :slight_smile: