256 Kilobytes

How to Make a Simple, Automatically-Updating Dashboard for Python Scripts Using HTML, JavaScript, and JSONP

Articles in Scripting and Automation | By August R. Garcia

Published 1 week agoThu, 05 Sep 2019 04:39:30 -0700 | Last update 1 week agoThu, 05 Sep 2019 05:15:22 -0700

Debugging with print("asdf1") messages is adequate, but has limitations. Conveniently, it's fairly straightforward to put together a basic, auto-updating HTML dashboard with minimal code and basically no dependencies.

104 views, 1 RAM, and 1 comment

When writing arbitrary scripts with Python, printing arbitrary debugging messages to the screen is adequate, but has limitations. Data can be hard to read and update, the output is purely text-based, and applications that are multithreaded can quickly become chaotic and difficult to follow.

Some basic methods to improve a Python script's UI/debugging messages include:

  • Using a library like Termcolor (or directly adding escape sequences) to highlight, color, or markup text printed to the terminal.
  • Using a library like PrettyTable to display arbitrary data in tablular form via the creation of text-based tables.
  • Using commands like os.system('cls' if os.name == 'nt' else 'clear') to clear old data from previous loops.
  • Using logging to output messages to one or more files, rather than to the terminal.

Of course, these are all still text-based solutions for outputting text, which has a number of inherent limitations. To get around this:

  • There are libraries like Tkinter that can be used to create GUIs, but then you have to learn how to use Tkinter, which requires effort.
  • Alternatively, there are web frameworks like Django that can be used to create web applications, which could also be used for a basic dashboard, but for a basic dashboard, this is probably excessive.

Conveniently, it's fairly straightforward to put together a basic HTML dashboard with extremely minimal code and basically no dependencies. See cover image for this post for a screenshot of the code below running locally on FireFox.

The Files and Code

[index.html] The HTML/JS Template File

<html>
<head>
        <title>Muh Dashboard</title> 
        <style>
                body            { background-color: lightcyan; } 
                table           { width:100%; border:1px solid black; background-color:beige; }
                textarea        { width:100%; resize:vertical; min-height:300px; }
        </style>
</head>
<body>
        <h1>Muh Dashboard</h1>
        <!--
                HTML template that will be used to display the data 
                You could also use a library like chart.js or the DataTables jQuery plugin for 
                additional flexibility/functionality in displaying data.
                        https://datatables.net/
                        https://www.chartjs.org/

                Both of these are distributed under the MIT License: 
                        https://opensource.org/licenses/MIT 
        --> 
        <table>
                <thead>
                        <tr><th>Field</th><th>Value</th></tr> 
                </thead>
                <tbody>
                        <tr><th>Number Completed </th><td id="complete">???</td></tr>
                        <tr><th>Most Recent Score</th><td id="score"   >???</td></tr>
                </tbody>
        </table>

        <textarea id="msg"></textarea>

        <!-- Force a dashbaord refresh faster than the auto-refresh interval set below -->
        <button onclick="load_jsonp()">Refresh Dashboard</button>
        
        <!-- Div that JSONP will be loaded into -->
        <div id="jsonp_target"></div>

        <script>
        // The function that loads in the JSONP and then creates a script tag to execute it 
        // You could alternatively use asyncronous requests to a pure JSON file, however
        // this causes cross-origin resource sharing (CORS) errors to occur if you're 
        // running this on localhost (which you probably are, for a one-off Python dashboard. 
        // There are other CORS workarounds with localhost, but they're basically all more
        // involved than using JSONP instead. 
        function load_jsonp() {
                var s = document.createElement("script");
                s.src = "data.json";
                
                // Make sure to clear the previous script tag, since otherwise 
                // a new script tag will be inserted on each interval.
                // This can easily become an obscene amount of HTML if the tab is left open for 
                // a non-trivial amount of time, which can cause the tab to lag or crash.  
                document.getElementById("jsonp_target").innerHTML = '';
                
                // Inject the script tag, which the browser will then execute  
                document.getElementById("jsonp_target").appendChild(s);
        }
        
        // The thing to do with the JSON parsed/received via the JSONP response 
        function myFunc(myObj) { 
                // Assist with debugging by logging the JSON objects full data to the console
                console.log(myObj); 
        
                // This can alternatively be done as a table. See:  
                // https://www.256kilobytes.com/content/show/10378/5-tasks-you-didnt-know-could-be-done-from-the-developer-console
                console.table(myObj); 
        
                // Insert specific pieces of data from the JSON data into the page's HTML
                document.getElementById("complete").innerHTML  = myObj.complete; 
                document.getElementById("score"   ).innerHTML  = myObj.score   ; 
        
                // Append the latest log message as as tab-separated data. See: 
                // https://www.256kilobytes.com/content/show/10868/the-virgin-csv-vs-the-chad-tsv
                document.getElementById("msg"     ).innerHTML += myObj.msg + "\t" + myObj.complete + "\t" + myObj.score + "\n"  ; 
        }
        
        // Every half a second, load the json in from the data.json file and use it to update the dashbaord
        setInterval(function() {
                load_jsonp(); 
        }, 500);
        </script>
</body>
</html>

[dashboard.py] The Python Script

import random, time, json
iii = 1
while True:
        # Some arbitrary data in a dictionary 
        data = {
                "complete"   : iii                        ,
                "score"      : random.randint(0,999999)   ,
                "msg"        : "Loop %s has finished..." % iii
        }

        # The file that the python script will write to whenever there is updated data 
        with open('data.json', 'w') as f:
                f.write( "myFunc(" )  # Start of the JSONP's JS function
                json.dump(data, f)    # The dict converted to JSON 
                f.write( ");"      )  # Close the JSONP's JS function

        iii += 1
        time.sleep(random.randint(0,3))

[data.json] The Automatically-Generated JSONP File

This file is automatically created and updated/replaced by the Python script. The content below is an example of this output.

myFunc({"msg": "Loop 693 has finished...", "score": 408418, "complete": 693});
Users Who Have Downloaded More RAM:
Hash Brown (1 week ago)
🐏 ⨉ 1
Posted by August R. Garcia 1 week ago

Edit History

• [2019-09-05 4:39 PDT] August R. Garcia (1 week ago)
• [2019-09-05 4:39 PDT] August R. Garcia (1 week ago)
🕓 Posted at 05 September, 2019 04:39 AM PDT

Profile Photo - August R. Garcia August R. Garcia LARPing as a Sysadmi... Portland, OR
🗎 185 🗨 919 🐏 273
Site Owner

Grahew Mattham

August Garcia is some guy who used to sell Viagra on the Internet. He made this website to LARP as a sysadmin while posting about garbage like user-agent spoofing, spintax, the only good keyboard, virtual assitants from Pakistan, links with the rel="nofollow" attributeproxiessin, the developer console, literally every link building method, and other junk.

Available at arg@256kilobytes.com, via Twitter, or arg.256kilobytes.com. Open to business inquiries based on availability.


Account created 9 months ago.
185 posts, 919 comments, and 273 RAMs.

Last active 4 hours ago:
Posted thread [PHP] How to Add rel="nofollow", rel="nofollow ugc", rel="nofollow sponsored" and/or Other rel Attributes to Links

Profile Photo - Hash Brown Hash Brown Internet Activist &... United State of Euro...
🗎 61 🗨 430 🐏 204
Staff

Hell motherfucking yeah sir

Download more RAM. 🐏 ⨉ 0 Posted by Hash Brown 1 week ago 🕓 Posted at 05 September, 2019 06:55 AM PDT

"THAT DOG IS GETTING RAPED" - Terry A. Davis

Post a New Comment

To leave a comment, login to your account or create an account.

Do you like having a good time?

Read Quality Articles

Read some quality articles. If you can manage to not get banned for like five minutes, you can even post your own articles.

View Articles →

Argue with People on the Internet

Use your account to explain why people are wrong on the Internet forum.

View Forum →

Vandalize the Wiki

Or don't. I'm not your dad.

View Wiki →

Ask and/or Answer Questions

If someone asks a terrible question, post a LMGTFY link.

View Answers →

Make Some Money

Hire freelancers and/or advertise your goods and/or services. Hire people directly. We're not a middleman or your dad. Manage your own business transactions.

Register an Account
You can also login to an existing account or recover your password. All use of this site is subject to terms outlined in the terms of service and privacy policy.