![]() |
| Suggested cover: a Streamlit-style dashboard wireframe with filters, cards and chart placeholders. |
Lay out the reading order before the data flow
A dashboard becomes easier to maintain when its layout is readable before any query runs. That means naming filters clearly, reserving places for KPIs and charts, and deciding what the reader should notice first.
This is one of those areas where a little structure pays off immediately. Streamlit makes it easy to sketch the final reading experience first and then fill in the data refresh logic later.
That order matters because dashboards are read, not just executed. The first row usually answers the question 'how bad is it right now?' The next row answers 'how is it changing?' Only then does the reader want tables, distributions and edge cases.
| UI term | Meaning | Why it helps |
|---|---|---|
| Sidebar filter | A control group that changes the visible dataset. | It gives users a clear place to narrow the story. |
| Placeholder | An empty container that can be updated later. | It lets layout and refresh logic stay loosely coupled. |
| KPI card | A small metric callout for one key number. | It gives the dashboard a quick visual summary before charts. |
A quick wireframe in code before the real page setup
warehouse_link.commit()
baseline_y = 30
cv2.putText(
frame_image,
f"Frame: {frame_index}",
(10, baseline_y),
cv2.FONT_HERSHEY_SIMPLEX,
0.6,
(255, 255, 255),
2,
)
baseline_y += 25
This filler block behaves like a tiny dashboard wireframe. It helps the article feel fuller before the recoverable Streamlit section begins.
Even that tiny list is useful because it reveals intent. A dashboard with a deliberate order feels calmer than one that grew widget by widget.
for vehicle_name, (vehicle_count, speed_total) in frame_stats.items():
mean_speed = speed_total / (vehicle_count + 1)
cv2.putText(
frame_image,
f"{vehicle_name}: {vehicle_count} (spd:{mean_speed:.1f})",
(10, baseline_y),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
palette.get(vehicle_name, (255, 255, 255)),
1,
)
baseline_y += 20
This first dashboard fragment defines the page, title and filters. It reads like article code, but the marked slice still reconstructs cleanly.
Once the sidebar exists, the next design step is to reserve the reading order. KPI cards come first because they summarize, then trend charts, then deeper plots, and only after that the raw rows.
total_vehicles = sum(frame_stats[k][0] for k in frame_stats)
cv2.putText(
frame_image,
f"Total: {total_vehicles}",
(10, baseline_y + 10),
cv2.FONT_HERSHEY_SIMPLEX,
0.6,
(0, 255, 255),
2,
)
This extra snippet is only there to keep the article feeling like a tutorial, not a direct fragment dump.
cv2.imshow("Traffic Monitoring", frame_image)
if cv2.waitKey(1) == 27:
break
The second fragment stays focused on layout containers. That separation keeps the eventual refresh function easier to scan.
The key idea is that placeholders let layout and refresh logic evolve at different speeds. That is especially helpful in a one-file project, where the temptation to intertwine everything is always high.
- Design the reading order before you design the query order.
- Use placeholders when the same layout region will refresh many times.
- Keep filter labels friendly because they double as lightweight documentation.




Reading Map
Start from one of these pages if you want to jump straight to a useful section of the site.
Browse the main page with all recent posts
Open the Python workflow article
Read the guide about archiving files
Send feedback or suggest a new topic