Smart Inventory Tracker in Colab
Build an interactive inventory app with widgets, charts, and Drive storage.
Introduction
30 Second Summary
Every store, warehouse, and office tracks what they have in stock. Whether it's knowing when to reorder coffee pods or spotting which products are running low, inventory management is a universal challenge that gets messy fast with spreadsheets alone.
In this project, you will build a Smart Inventory Tracker that runs entirely inside a Google Colab notebook. You'll create an interactive app with buttons and text fields, persistent data storage on Google Drive, and a visual dashboard that flags low-stock items automatically.
What You'll Build
An interactive inventory management application powered by pandas for data operations, ipywidgets for a clickable UI, and matplotlib for visual dashboards.
By the end of this project, you'll have:
- A fully interactive inventory app with buttons, dropdowns, and text fields that work without re-running any code cells.
- Persistent data storage on Google Drive so your inventory survives notebook restarts.
- A color-coded visual dashboard that charts stock levels and highlights items that need restocking.
- Secret Mission: Build a restock recommendation engine that calculates exactly how many units to order and what it will cost.
Are there any prerequisites?
You should be comfortable with basic Python concepts like variables, functions, loops, and conditionals. Everything else is covered step by step in this project.
Set Up Your Environment and Load Mock Data
Every inventory app needs two things: a place to store data and a way to display it. In this step, you'll set up your workspace by connecting Google Colab to Google Drive for permanent storage.
You'll also load a set of pre-built mock inventory data so you have realistic items to work with right away. This gives you something tangible to filter, visualize, and manage in later steps.
In this step, get ready to:
- Create a Colab notebook and mount Google Drive for persistent storage.
- Build a mock data function that seeds 12 inventory items across 4 categories.
- Create a data-loading helper that checks Drive before generating fresh data.
Create a new Colab notebook and mount Google Drive
Google Colab notebooks lose all their data when the runtime disconnects. Mounting Google Drive gives you a permanent folder where your inventory CSV can live between sessions.
- In Google Colab, click File in the top menu bar.
- Click New notebook.
- Click on the notebook name in the upper left corner (it will say something like Untitled0.ipynb).
- Rename it to Smart Inventory Tracker and press Enter.
You should see a blank notebook with one empty code cell ready for input.
- Start your first code cell by pasting the following imports and Drive mount command:
# Cell 1: Setup and Drive Mount
from google.colab import drive
import pandas as pd
import ipywidgets as widgets
from IPython.display import display, clear_output
import matplotlib.pyplot as plt
import os
drive.mount('/content/drive')
What does this code do?
- from google.colab import drive gives you access to the Drive mounting function that connects your notebook to your Google Drive files.
- pandas is the library for working with tabular data. ipywidgets provides interactive buttons and inputs. matplotlib handles chart drawing.
- drive.mount('/content/drive') connects your Google Drive as a folder at that path so your notebook can read and write files there.
You won't run this cell yet. The next two chunks add the functions that actually create and load your data.
Create the project folder and mock data function
Your inventory data needs a dedicated folder on Drive. The create_mock_data() function seeds that folder with 12 realistic items. It includes a deliberate mix of healthy stock and low-stock items so your alerts and dashboard work right away.
- In the same cell, directly below drive.mount('/content/drive'), add the following code:
# Create project folder
folder_path = '/content/drive/My Drive/InventoryTracker'
os.makedirs(folder_path, exist_ok=True)
csv_path = f'{folder_path}/inventory.csv'
# Mock data for training
def create_mock_data():
mock_items = [
{'Item': 'Wireless Mouse', 'Category': 'Electronics', 'Quantity': 45, 'Price': 29.99, 'Restock_Threshold': 10},
{'Item': 'USB-C Cable', 'Category': 'Electronics', 'Quantity': 8, 'Price': 12.99, 'Restock_Threshold': 15},
{'Item': 'Bluetooth Headset', 'Category': 'Electronics', 'Quantity': 3, 'Price': 79.99, 'Restock_Threshold': 5},
{'Item': 'Notebook Pack', 'Category': 'Office Supplies', 'Quantity': 120, 'Price': 8.49, 'Restock_Threshold': 20},
{'Item': 'Whiteboard Markers', 'Category': 'Office Supplies', 'Quantity': 30, 'Price': 15.99, 'Restock_Threshold': 10},
{'Item': 'Sticky Notes', 'Category': 'Office Supplies', 'Quantity': 5, 'Price': 4.99, 'Restock_Threshold': 25},
{'Item': 'Desk Lamp', 'Category': 'Furniture', 'Quantity': 2, 'Price': 45.00, 'Restock_Threshold': 5},
{'Item': 'Ergonomic Chair', 'Category': 'Furniture', 'Quantity': 12, 'Price': 299.99, 'Restock_Threshold': 3},
{'Item': 'Standing Desk Mat', 'Category': 'Furniture', 'Quantity': 7, 'Price': 39.99, 'Restock_Threshold': 5},
{'Item': 'Coffee Pods', 'Category': 'Breakroom', 'Quantity': 10, 'Price': 24.99, 'Restock_Threshold': 20},
{'Item': 'Paper Towels', 'Category': 'Breakroom', 'Quantity': 48, 'Price': 12.49, 'Restock_Threshold': 15},
{'Item': 'Hand Sanitizer', 'Category': 'Breakroom', 'Quantity': 6, 'Price': 8.99, 'Restock_Threshold': 10},
]
df = pd.DataFrame(mock_items)
df.to_csv(csv_path, index=False)
return df
What does this code do?
- os.makedirs(folder_path, exist_ok=True) creates the InventoryTracker folder on Drive. The exist_ok=True part means it won't throw an error if the folder already exists.
- create_mock_data() builds a list of 12 dictionaries (one per product), converts them into a pandas DataFrame, saves that DataFrame to a CSV on Drive, and returns it.
- Items like USB-C Cable (quantity 8, threshold 15) and Coffee Pods (quantity 10, threshold 20) are deliberately below their restock thresholds. This means the alert system will have items to flag immediately.
What is a DataFrame?
A DataFrame is a table of data with labeled columns and numbered rows. Think of it like a spreadsheet in code. You can filter rows, sort columns, and calculate totals using simple one-line commands.
You won't see output yet. The next chunk adds the code that actually calls these functions.
Create the load_inventory() helper and verify your setup
The load_inventory() function checks if a CSV already exists on Drive. If it does, it reads the file. If not, it calls create_mock_data() to generate fresh data. This means your inventory persists between Colab sessions.
- At the bottom of the same cell, add the loading function and the lines that run it:
# Initialize or load inventory
def load_inventory():
if os.path.exists(csv_path):
return pd.read_csv(csv_path)
else:
return create_mock_data()
inventory = load_inventory()
print(f"Inventory loaded: {len(inventory)} items")
print(inventory)
What does this code do?
- load_inventory() uses os.path.exists() to check whether inventory.csv already exists on Drive. If it does, pandas reads it directly. If not, it creates fresh mock data.
- inventory = load_inventory() stores the loaded DataFrame in a variable so the rest of your notebook can use it.
- The two print() calls confirm how many items loaded and display the full table so you can verify everything worked.
- Run the cell by clicking the play button on its left side, or by pressing Shift+Enter.
What will happen when you run this cell?
Colab will ask you to authorize access to your Google Drive. A pop-up or prompt will appear asking you to select your Google account and grant permission.
Click Allow to let the notebook read and write files to your Drive. After authorization completes, the rest of the cell runs automatically.
- After the cell finishes, you should see output that says Inventory loaded: 12 items followed by a table with 12 rows and 5 columns: Item, Category, Quantity, Price, and Restock_Threshold.
Not seeing 12 items in the output?
- If you see a Drive authorization error, make sure you clicked Allow on the permission prompt. Try running the cell again.
- If you see NameError, check that all the code from this step is in one cell. The functions need to be defined before the final lines call them.
- If the table appears but has fewer than 12 rows, double check that the mock_items list has all 12 dictionaries.
Help me debug my inventory setup cell.
✔️ Awesome, I've got everything!
Great. Double check that your output shows all 12 items across the 4 categories: Electronics, Office Supplies, Furniture, and Breakroom.
ⓧ I'd like to double check the full code
Here is the complete Cell 1 code. Make sure your cell matches this exactly:
# Cell 1: Setup and Drive Mount
from google.colab import drive
import pandas as pd
import ipywidgets as widgets
from IPython.display import display, clear_output
import matplotlib.pyplot as plt
import os
drive.mount('/content/drive')
# Create project folder
folder_path = '/content/drive/My Drive/InventoryTracker'
os.makedirs(folder_path, exist_ok=True)
csv_path = f'{folder_path}/inventory.csv'
# Mock data for training
def create_mock_data():
mock_items = [
{'Item': 'Wireless Mouse', 'Category': 'Electronics', 'Quantity': 45, 'Price': 29.99, 'Restock_Threshold': 10},
{'Item': 'USB-C Cable', 'Category': 'Electronics', 'Quantity': 8, 'Price': 12.99, 'Restock_Threshold': 15},
{'Item': 'Bluetooth Headset', 'Category': 'Electronics', 'Quantity': 3, 'Price': 79.99, 'Restock_Threshold': 5},
{'Item': 'Notebook Pack', 'Category': 'Office Supplies', 'Quantity': 120, 'Price': 8.49, 'Restock_Threshold': 20},
{'Item': 'Whiteboard Markers', 'Category': 'Office Supplies', 'Quantity': 30, 'Price': 15.99, 'Restock_Threshold': 10},
{'Item': 'Sticky Notes', 'Category': 'Office Supplies', 'Quantity': 5, 'Price': 4.99, 'Restock_Threshold': 25},
{'Item': 'Desk Lamp', 'Category': 'Furniture', 'Quantity': 2, 'Price': 45.00, 'Restock_Threshold': 5},
{'Item': 'Ergonomic Chair', 'Category': 'Furniture', 'Quantity': 12, 'Price': 299.99, 'Restock_Threshold': 3},
{'Item': 'Standing Desk Mat', 'Category': 'Furniture', 'Quantity': 7, 'Price': 39.99, 'Restock_Threshold': 5},
{'Item': 'Coffee Pods', 'Category': 'Breakroom', 'Quantity': 10, 'Price': 24.99, 'Restock_Threshold': 20},
{'Item': 'Paper Towels', 'Category': 'Breakroom', 'Quantity': 48, 'Price': 12.49, 'Restock_Threshold': 15},
{'Item': 'Hand Sanitizer', 'Category': 'Breakroom', 'Quantity': 6, 'Price': 8.99, 'Restock_Threshold': 10},
]
df = pd.DataFrame(mock_items)
df.to_csv(csv_path, index=False)
return df
# Initialize or load inventory
def load_inventory():
if os.path.exists(csv_path):
return pd.read_csv(csv_path)
else:
return create_mock_data()
inventory = load_inventory()
print(f"Inventory loaded: {len(inventory)} items")
print(inventory)
Your environment is ready and your mock data is loaded. Next up, you'll build the core functions that let you add, update, and delete inventory items.
Build the Inventory Data Model
Your inventory data is loaded and sitting in a DataFrame, but right now you can only look at it. A real inventory system needs the ability to add new stock, remove discontinued items, and update quantities as products move in and out.
In this step, you'll build the core data model. These are the functions that modify your inventory and automatically save every change back to Google Drive.
In this step, get ready to:
- Create a save helper function that writes the DataFrame to Drive.
- Build add, delete, and update functions for inventory items.
- Test each function to confirm changes persist to the CSV.
Create the save helper and add function
Every time you modify the inventory, the change needs to be written back to the CSV on Drive. A dedicated save function keeps that logic in one place so every other function can call it.
- Create a new code cell below your Cell 1.
- Add the save helper and the add_item() function by pasting this code:
# Cell 2: Core Inventory Functions
def save_inventory():
inventory.to_csv(csv_path, index=False)
def add_item(name, category, quantity, price, threshold):
global inventory
new_row = pd.DataFrame([{
'Item': name,
'Category': category,
'Quantity': quantity,
'Price': price,
'Restock_Threshold': threshold
}])
inventory = pd.concat([inventory, new_row], ignore_index=True)
save_inventory()
What does this code do?
- save_inventory() writes the current inventory DataFrame to the CSV file on Google Drive. Every modification function calls this at the end.
- global inventory tells Python that add_item() should modify the notebook-level inventory variable, not create a local copy.
- pd.concat() appends a new single-row DataFrame to the existing inventory. This is the modern pandas pattern for adding rows.
Why global instead of return?
Later in this project, button callbacks from ipywidgets will call these functions. Widget callbacks run in a separate scope and can only receive the button object as an argument. Using global lets the callbacks modify the shared DataFrame directly.
You won't see output yet. The next chunk adds the remaining functions before you test everything together.
Create the delete and update functions
Adding items is only half the picture. You also need to remove discontinued products and adjust quantities when stock arrives or ships out.
- In the same Cell 2, add the following two functions below add_item():
def delete_item(name):
global inventory
inventory = inventory[inventory['Item'] != name].reset_index(drop=True)
save_inventory()
def update_quantity(name, new_quantity):
global inventory
inventory.loc[inventory['Item'] == name, 'Quantity'] = new_quantity
save_inventory()
What does this code do?
- delete_item() filters the DataFrame to keep only rows where the item name does NOT match. reset_index(drop=True) cleans up the row numbers after removal.
- update_quantity() uses .loc[] to find the matching row and change its Quantity value in place.
- Both functions call save_inventory() at the end so every change is immediately written to Drive.
You still won't see output. The next chunk runs all four functions and prints the results.
Test all functions
Now that your data model is complete, you'll run a quick integration test. You'll add a temporary item, update its quantity, then delete it to confirm each function works and saves to Drive.
- Add the following test code at the bottom of Cell 2, below your function definitions:
# Test the functions
print("Testing add_item:")
add_item('Test Item', 'Electronics', 10, 5.99, 3)
print(inventory.tail(1))
print("\nTesting update_quantity:")
update_quantity('Test Item', 25)
print(inventory[inventory['Item'] == 'Test Item'])
print("\nTesting delete_item:")
delete_item('Test Item')
print(f"Items after delete: {len(inventory)}")
print(inventory)
What does this test do?
- First, it adds a temporary "Test Item" and prints the last row to confirm it appeared.
- Then, it updates that item's quantity from 10 to 25 and prints the matching row to confirm the change.
- Finally, it deletes the test item and prints the full inventory to confirm you're back to 12 rows.
- Run Cell 2 by clicking the play button or pressing Shift+Enter.
- You should see three test sections printed. The first shows the added "Test Item" row. The second shows its quantity updated to 25. The third shows 12 items remaining after the test item was deleted.
Seeing a NameError?
If you see an error mentioning inventory or csv_path is not defined, make sure you ran Cell 1 first. Cell 2 depends on variables created in Cell 1.
If you see an error about save_inventory not being defined, check that the save_inventory() function definition is at the top of Cell 2, above the other functions.
Help me debug my inventory functions
✔️ Awesome, I've got everything!
Great. Double check you've saved Cell 2 and that your output shows 12 items at the end.
ⓧ I'd like to double check the full code
Here is the complete Cell 2 code. Make sure everything matches:
# Cell 2: Core Inventory Functions
def save_inventory():
inventory.to_csv(csv_path, index=False)
def add_item(name, category, quantity, price, threshold):
global inventory
new_row = pd.DataFrame([{
'Item': name,
'Category': category,
'Quantity': quantity,
'Price': price,
'Restock_Threshold': threshold
}])
inventory = pd.concat([inventory, new_row], ignore_index=True)
save_inventory()
def delete_item(name):
global inventory
inventory = inventory[inventory['Item'] != name].reset_index(drop=True)
save_inventory()
def update_quantity(name, new_quantity):
global inventory
inventory.loc[inventory['Item'] == name, 'Quantity'] = new_quantity
save_inventory()
# Test the functions
print("Testing add_item:")
add_item('Test Item', 'Electronics', 10, 5.99, 3)
print(inventory.tail(1))
print("\nTesting update_quantity:")
update_quantity('Test Item', 25)
print(inventory[inventory['Item'] == 'Test Item'])
print("\nTesting delete_item:")
delete_item('Test Item')
print(f"Items after delete: {len(inventory)}")
print(inventory)
Your data model is solid. Every add, update, and delete automatically saves to Google Drive. Next up, you'll wrap these functions in an interactive UI so you can manage inventory with buttons and text fields instead of function calls.
Build the Interactive UI with ipywidgets
Your inventory functions work, but right now you need to type Python function calls every time you want to add or remove an item. That defeats the purpose of a tracker anyone can use.
In this step, you will build an interactive widget-based UI using ipywidgets. Text fields, dropdowns, and buttons will let you manage inventory without re-running any cells.
In this step, get ready to:
- Create input widgets for adding and deleting items.
- Build callback functions that respond to button clicks.
- Wire up the full interactive layout and display the inventory table.
Create the input widgets
Each input field in the UI is a widget object. You define the widget type, a label, and a default value. ipywidgets handles the rendering for you.
- First, delete the test code at the bottom of your Cell 2. Remove everything from the # Test the functions comment to the end of the cell.
- Create a new code cell below Cell 2 by clicking the + Code button at the top of your notebook.
- Start your new cell with the input widget declarations by pasting this code:
# Cell 5: Interactive UI
# Input widgets
name_input = widgets.Text(description='Item:', placeholder='Enter item name')
category_input = widgets.Dropdown(description='Category:',
options=['Electronics', 'Office Supplies', 'Furniture', 'Breakroom', 'Other'])
quantity_input = widgets.IntText(description='Quantity:', value=0)
price_input = widgets.FloatText(description='Price ($):', value=0.0)
threshold_input = widgets.IntText(description='Threshold:', value=10)
delete_input = widgets.Text(description='Delete:', placeholder='Item name to delete')
What does this code do?
Each line creates a different type of input widget:
- widgets.Text creates a free-text field where the user types a string.
- widgets.Dropdown creates a select menu with fixed options so categories stay consistent.
- widgets.IntText and widgets.FloatText only accept numbers, preventing invalid data entry.
You won't see a change yet. The next chunk defines the buttons and callbacks that bring these inputs to life.
Create the action buttons and callback functions
Buttons trigger Python functions when clicked. Each callback reads the widget values, calls the inventory functions you built in Step 2, then refreshes the display.
- Add the buttons, output areas, and all callback functions to the same cell by pasting this code below the input widgets:
# Buttons
add_button = widgets.Button(description='Add Item', button_style='success', icon='plus')
delete_button = widgets.Button(description='Delete Item', button_style='danger', icon='trash')
alerts_button = widgets.Button(description='Check Alerts', button_style='warning', icon='bell')
summary_button = widgets.Button(description='Summary', button_style='info', icon='list')
dashboard_button = widgets.Button(description='Show Dashboard', button_style='', icon='bar-chart')
# Output areas
inventory_output = widgets.Output()
info_output = widgets.Output()
chart_output = widgets.Output()
def refresh_inventory_display():
with inventory_output:
clear_output(wait=True)
print("=== Current Inventory ===")
display(inventory)
def on_add_clicked(b):
global inventory
if name_input.value.strip() == '':
with info_output:
clear_output(wait=True)
print("Please enter an item name.")
return
add_item(name_input.value, category_input.value,
quantity_input.value, price_input.value, threshold_input.value)
inventory = load_inventory()
name_input.value = ''
quantity_input.value = 0
price_input.value = 0.0
threshold_input.value = 10
refresh_inventory_display()
with info_output:
clear_output(wait=True)
print("Item added successfully!")
def on_delete_clicked(b):
global inventory
if delete_input.value.strip() == '':
with info_output:
clear_output(wait=True)
print("Please enter an item name to delete.")
return
delete_item(delete_input.value)
inventory = load_inventory()
delete_input.value = ''
refresh_inventory_display()
with info_output:
clear_output(wait=True)
print("Item deleted.")
def on_alerts_clicked(b):
with info_output:
clear_output(wait=True)
low = check_low_stock()
if low.empty:
print("All items are well-stocked!")
else:
print(f"LOW STOCK ALERT: {len(low)} item(s) need restocking!")
print("-" * 40)
display(low[['Item', 'Category', 'Quantity', 'Restock_Threshold']])
def on_summary_clicked(b):
with info_output:
clear_output(wait=True)
summary = inventory_summary()
print("=== Inventory Summary ===")
print(f"Total items: {summary['total_items']}")
print(f"Total inventory value: ${summary['total_value']:.2f}")
print(f"Low-stock items: {summary['low_stock_count']}")
print("\nValue by Category:")
for cat, val in summary['value_by_category'].items():
print(f" {cat}: ${val:.2f}")
def on_dashboard_clicked(b):
with chart_output:
clear_output(wait=True)
plot_stock_levels()
plot_value_by_category()
What does this code do?
- widgets.Button creates clickable buttons. The button_style attribute controls the color (success = green, danger = red, warning = yellow, info = blue).
- widgets.Output() creates a dedicated display area. Using with output: captures anything printed inside that block into the widget.
- global inventory is needed inside callbacks because ipywidgets callbacks run in their own scope. Without it, changes to the DataFrame would not persist between clicks.
- on_add_clicked validates the input, calls add_item(), reloads from Drive, clears the fields, and refreshes the display.
- on_alerts_clicked, on_summary_clicked, and on_dashboard_clicked call functions you will define in the next two steps. They are safe to define now because Python only needs the function to exist when the button is actually clicked.
You won't see a change yet. The next chunk wires the buttons and renders the full layout.
Wire up the layout and display your UI
The final piece connects each button to its callback and arranges everything into a visual layout using VBox (vertical) and HBox (horizontal) containers.
- Complete the cell by pasting the wiring and layout code below the callback functions:
# Wire up callbacks
add_button.on_click(on_add_clicked)
delete_button.on_click(on_delete_clicked)
alerts_button.on_click(on_alerts_clicked)
summary_button.on_click(on_summary_clicked)
dashboard_button.on_click(on_dashboard_clicked)
# Layout
input_section = widgets.VBox([name_input, category_input, quantity_input,
price_input, threshold_input])
add_section = widgets.HBox([input_section, widgets.VBox([add_button])])
delete_section = widgets.HBox([delete_input, delete_button])
button_row = widgets.HBox([alerts_button, summary_button, dashboard_button])
# Display everything
display(widgets.VBox([
widgets.HTML('<h2>Smart Inventory Tracker</h2>'),
add_section,
delete_section,
button_row,
inventory_output,
info_output,
chart_output
]))
# Initial display
refresh_inventory_display()
What does this code do?
- button.on_click(callback) registers a function to run when the button is clicked. The callback receives the button instance as its argument (b).
- widgets.VBox stacks widgets vertically. widgets.HBox places them side by side.
- The final display() call renders the full layout in one block. refresh_inventory_display() populates the inventory table immediately.
- Run the cell by pressing Shift+Enter.
- You should see a form with text inputs, a dropdown, number fields, and colored buttons. Below the buttons, your 12-item inventory table appears.
- Test the Add Item button: type Test Widget in the Item field, select a category, set quantity to 5, and click Add Item.
- The table should update to show 13 items, the input fields should clear, and you should see the message "Item added successfully!" below the table.
- Test the Delete Item button: type Test Widget in the Delete field and click Delete Item.
- The table should return to 12 items.
What about the other buttons?
The Check Alerts, Summary, and Show Dashboard buttons call functions that do not exist yet. Clicking them now would produce an error. You will build those functions in the next two steps.
UI not appearing or buttons not working?
- Make sure you ran Cell 1 and Cell 2 first. The UI cell depends on widgets, display, clear_output, and the inventory functions from those cells.
- If clicking Add Item does nothing, check that you did not accidentally leave the test code in Cell 2. The test code calls add_item('Test Item', ...) which can leave stale state.
- If you see a blank output area with no table, scroll up and confirm refresh_inventory_display() is the very last line in the cell.
My inventory UI is not rendering or the buttons are not responding to clicks.
✔️ Awesome, I've got everything!
Great. Double check you can add and delete items without re-running the cell.
ⓧ I'd like to double check the full code
Here is the complete Cell 5 code. Make sure your cell matches this exactly:
# Cell 5: Interactive UI
# Input widgets
name_input = widgets.Text(description='Item:', placeholder='Enter item name')
category_input = widgets.Dropdown(description='Category:',
options=['Electronics', 'Office Supplies', 'Furniture', 'Breakroom', 'Other'])
quantity_input = widgets.IntText(description='Quantity:', value=0)
price_input = widgets.FloatText(description='Price ($):', value=0.0)
threshold_input = widgets.IntText(description='Threshold:', value=10)
delete_input = widgets.Text(description='Delete:', placeholder='Item name to delete')
# Buttons
add_button = widgets.Button(description='Add Item', button_style='success', icon='plus')
delete_button = widgets.Button(description='Delete Item', button_style='danger', icon='trash')
alerts_button = widgets.Button(description='Check Alerts', button_style='warning', icon='bell')
summary_button = widgets.Button(description='Summary', button_style='info', icon='list')
dashboard_button = widgets.Button(description='Show Dashboard', button_style='', icon='bar-chart')
# Output areas
inventory_output = widgets.Output()
info_output = widgets.Output()
chart_output = widgets.Output()
def refresh_inventory_display():
with inventory_output:
clear_output(wait=True)
print("=== Current Inventory ===")
display(inventory)
def on_add_clicked(b):
global inventory
if name_input.value.strip() == '':
with info_output:
clear_output(wait=True)
print("Please enter an item name.")
return
add_item(name_input.value, category_input.value,
quantity_input.value, price_input.value, threshold_input.value)
inventory = load_inventory()
name_input.value = ''
quantity_input.value = 0
price_input.value = 0.0
threshold_input.value = 10
refresh_inventory_display()
with info_output:
clear_output(wait=True)
print("Item added successfully!")
def on_delete_clicked(b):
global inventory
if delete_input.value.strip() == '':
with info_output:
clear_output(wait=True)
print("Please enter an item name to delete.")
return
delete_item(delete_input.value)
inventory = load_inventory()
delete_input.value = ''
refresh_inventory_display()
with info_output:
clear_output(wait=True)
print("Item deleted.")
def on_alerts_clicked(b):
with info_output:
clear_output(wait=True)
low = check_low_stock()
if low.empty:
print("All items are well-stocked!")
else:
print(f"LOW STOCK ALERT: {len(low)} item(s) need restocking!")
print("-" * 40)
display(low[['Item', 'Category', 'Quantity', 'Restock_Threshold']])
def on_summary_clicked(b):
with info_output:
clear_output(wait=True)
summary = inventory_summary()
print("=== Inventory Summary ===")
print(f"Total items: {summary['total_items']}")
print(f"Total inventory value: ${summary['total_value']:.2f}")
print(f"Low-stock items: {summary['low_stock_count']}")
print("\nValue by Category:")
for cat, val in summary['value_by_category'].items():
print(f" {cat}: ${val:.2f}")
def on_dashboard_clicked(b):
with chart_output:
clear_output(wait=True)
plot_stock_levels()
plot_value_by_category()
# Wire up callbacks
add_button.on_click(on_add_clicked)
delete_button.on_click(on_delete_clicked)
alerts_button.on_click(on_alerts_clicked)
summary_button.on_click(on_summary_clicked)
dashboard_button.on_click(on_dashboard_clicked)
# Layout
input_section = widgets.VBox([name_input, category_input, quantity_input,
price_input, threshold_input])
add_section = widgets.HBox([input_section, widgets.VBox([add_button])])
delete_section = widgets.HBox([delete_input, delete_button])
button_row = widgets.HBox([alerts_button, summary_button, dashboard_button])
# Display everything
display(widgets.VBox([
widgets.HTML('<h2>Smart Inventory Tracker</h2>'),
add_section,
delete_section,
button_row,
inventory_output,
info_output,
chart_output
]))
# Initial display
refresh_inventory_display()
Why event-driven UI instead of a menu loop?
A typical beginner approach is a while True loop with input() prompts. That blocks the entire notebook until the loop finishes.
Event-driven callbacks let the notebook stay responsive. You can run other cells, view data, and interact with the UI all at the same time. This is the same pattern behind web apps, mobile apps, and desktop GUIs.
Your interactive UI is live. Next up, you will build the smart features that power the Alerts and Summary buttons.
Add Smart Features
Your interactive UI is live and your inventory data persists to Google Drive. But right now, you have to scan through the whole table to figure out which items are running low.
In this step, you will build two analytical functions that answer critical inventory questions automatically. One detects low-stock items by comparing quantities against their restock thresholds. The other calculates total inventory value and breaks it down by category.
In this step, get ready to:
- Build a low-stock detection function that filters items needing restocking.
- Build a summary function that calculates inventory value and category breakdowns.
- Test the Check Alerts and Summary buttons in your UI.
Build the low-stock detection function
An inventory tracker is only useful if it can tell you when something is about to run out. Your mock data already includes a Restock_Threshold column for each item. You need a function that compares each item's current quantity against its threshold and returns only the items that need attention.
- Create a new code cell in your notebook, below your Cell 2 (Core Inventory Functions).
- Paste the following code into the new cell:
# Cell 3: Smart Features
def check_low_stock():
low = inventory[inventory['Quantity'] <= inventory['Restock_Threshold']]
return low
What does this code do?
The line inventory[inventory['Quantity'] <= inventory['Restock_Threshold']] uses pandas boolean indexing to filter the DataFrame. It compares each row's Quantity against its own Restock_Threshold and returns only the rows where stock is at or below that threshold.
You won't see output yet. The next function completes this cell before you run it.
Build the inventory summary function
Beyond alerts, a good inventory system gives you a high-level picture of what you own. This function calculates the total number of items, total inventory value, value broken down by category, and a count of low-stock items.
- In the same Cell 3, add the following function below check_low_stock():
def inventory_summary():
total_items = len(inventory)
inventory['Value'] = inventory['Quantity'] * inventory['Price']
total_value = inventory['Value'].sum()
value_by_category = inventory.groupby('Category')['Value'].sum()
low_stock_count = len(check_low_stock())
return {
'total_items': total_items,
'total_value': total_value,
'value_by_category': value_by_category,
'low_stock_count': low_stock_count
}
What does this code do?
- inventory['Value'] = inventory['Quantity'] * inventory['Price'] creates a new column by multiplying quantity and price for every row at once. This is pandas vectorized math.
- inventory.groupby('Category')['Value'].sum() groups all rows by their Category, then sums the Value within each group. This gives you a per-category breakdown in one line.
- The function returns a dictionary so the calling code can easily pull out whichever metric it needs.
- Run Cell 3 by clicking the play button on the left side of the cell, or pressing Shift+Enter.
The cell runs without any output. Both functions are now defined in memory, ready for your buttons to call them.
Seeing a NameError?
- Make sure you ran Cell 1 and Cell 2 first. The inventory variable must exist before these functions can reference it.
- Check that you pasted both functions into the same cell and that inventory_summary() appears below check_low_stock().
- Help me fix this NameError in my Colab notebook.
Test the smart features with your buttons
Your UI already has a Check Alerts button and a Summary button wired to callbacks that call these functions. Now that the functions are defined, the buttons will work.
- Scroll down to your interactive UI output (the widget area from Cell 5).
- Click the Check Alerts button.
You should see a "LOW STOCK ALERT" message listing items that are at or below their restock threshold. At least 4 items from the mock data should appear: USB-C Cable, Bluetooth Headset, Sticky Notes, Desk Lamp, Coffee Pods, and Hand Sanitizer.
- Click the Summary button.
You should see the total item count, total inventory value, low-stock count, and a value breakdown by category (Breakroom, Electronics, Furniture, Office Supplies).
Why does the summary use groupby?
The groupby method splits your DataFrame into groups based on a column, then applies an aggregation (like sum()) to each group independently. It is one of the most-used pandas operations in data analysis because it turns row-level data into meaningful category-level insights with a single line.
Buttons not showing any output?
- Make sure Cell 3 (Smart Features) has been run successfully. If the cell has not been run, the functions do not exist in memory and the button callbacks will fail silently.
- Re-run Cell 5 (Interactive UI) after running Cell 3. The callbacks need the functions to be available at the time the buttons are clicked.
- Check the Colab cell output area below the button row. The info_output widget displays results in a section underneath the inventory table.
- Help me debug why my inventory buttons are not producing output.
✔️ Awesome, I've got everything!
Great. Double check you have both functions in Cell 3 and that both buttons produce output when clicked.
ⓧ I'd like to double check the full code
Here is the complete Cell 3 code for comparison:
# Cell 3: Smart Features
def check_low_stock():
low = inventory[inventory['Quantity'] <= inventory['Restock_Threshold']]
return low
def inventory_summary():
total_items = len(inventory)
inventory['Value'] = inventory['Quantity'] * inventory['Price']
total_value = inventory['Value'].sum()
value_by_category = inventory.groupby('Category')['Value'].sum()
low_stock_count = len(check_low_stock())
return {
'total_items': total_items,
'total_value': total_value,
'value_by_category': value_by_category,
'low_stock_count': low_stock_count
}
Your inventory tracker now has brains. It knows which items need restocking and can summarize everything in one click. Next up, you will turn these numbers into visual charts so stock levels jump out at a glance.
Build the Visual Dashboard
Your inventory tracker can add, delete, and flag low-stock items. But scanning rows of numbers to spot trends is slow and error-prone.
In this step, you'll build two matplotlib charts that turn your raw inventory data into a visual dashboard. A color-coded bar chart makes stock levels obvious at a glance, and a pie chart reveals how your inventory value splits across categories.
In this step, get ready to:
- Create a color-coded horizontal bar chart showing stock levels for each item.
- Create a pie chart showing inventory value breakdown by category.
- Test the visual dashboard using the existing Show Dashboard button.
Create the stock levels bar chart
The on_dashboard_clicked callback you created in the previous step calls two functions that don't exist yet: plot_stock_levels() and plot_value_by_category(). You'll define them now in a new cell that runs before the UI cell.
- Create a new code cell between your Smart Features cell (Cell 3) and your Interactive UI cell (Cell 5).
- Add the plot_stock_levels() function by pasting the following code into the new cell:
# Cell 4: Visualization Functions
def plot_stock_levels():
fig, ax = plt.subplots(figsize=(10, 6))
colors = ['red' if row['Quantity'] <= row['Restock_Threshold'] else 'green'
for _, row in inventory.iterrows()]
ax.barh(inventory['Item'], inventory['Quantity'], color=colors)
ax.set_xlabel('Quantity')
ax.set_title('Inventory Stock Levels')
ax.axvline(x=0, color='black', linewidth=0.5)
plt.tight_layout()
plt.show()
What does this code do?
This function creates a horizontal bar chart where each bar represents one inventory item and its current quantity.
- The list comprehension checks each row. If Quantity is at or below Restock_Threshold, the bar turns red. Otherwise it stays green.
- plt.barh draws horizontal bars, which are easier to read when item names are long.
- plt.tight_layout() prevents labels from getting clipped at the edges of the figure.
Create the category value pie chart
- In the same cell, add the plot_value_by_category() function directly below plot_stock_levels():
def plot_value_by_category():
inventory['Value'] = inventory['Quantity'] * inventory['Price']
category_values = inventory.groupby('Category')['Value'].sum()
fig, ax = plt.subplots(figsize=(8, 6))
ax.pie(category_values, labels=category_values.index, autopct='%1.1f%%', startangle=90)
ax.set_title('Inventory Value by Category')
plt.tight_layout()
plt.show()
What does this code do?
This function calculates the total value of each category (Quantity multiplied by Price) and displays the breakdown as a pie chart.
- groupby('Category')['Value'].sum() groups items by category and sums their values, giving you one number per category.
- autopct='%1.1f%%' adds percentage labels to each pie slice so you can see exactly how value is distributed.
- Run this new Cell 4 by pressing the play button or hitting Shift+Enter.
The cell runs silently because both functions are only defined here, not called yet. No output is expected.
Seeing a NameError?
Make sure you ran Cell 1 (the setup cell with all your imports) before running this cell. The plt and inventory variables must already exist in memory.
If you restarted your Colab runtime, re-run all cells from Cell 1 downward in order.
help me debug a NameError in my visualization cell
Test the visual dashboard
Your on_dashboard_clicked callback already calls both functions. Now that they exist, the Show Dashboard button is fully wired up.
- Make sure the UI cell (Cell 5) has been re-run after you added Cell 4. If the UI is already displayed from your previous step, it should still be active.
- Click the Show Dashboard button in your inventory tracker UI.
You should see two charts appear below the inventory table. The first is a horizontal bar chart with green and red bars. The second is a pie chart split into four category slices.
What should I see in the bar chart?
Items like USB-C Cable, Bluetooth Headset, Sticky Notes, Desk Lamp, Coffee Pods, and Hand Sanitizer should have red bars because their quantity is at or below their restock threshold. Items like Wireless Mouse, Notebook Pack, and Paper Towels should have long green bars.
No charts appearing?
Check that you ran Cell 4 (the visualization cell) before clicking the button. The functions must be defined in memory for the callback to find them.
If you see an empty area under the buttons, try clicking Show Dashboard a second time. Colab can occasionally swallow the first render in an Output widget.
help me fix my Show Dashboard button
✔️ Awesome, I've got everything!
Great. Double check you've run Cell 4 and confirmed the charts render when you click Show Dashboard.
ⓧ I'd like to double check the full code
Here is the complete Cell 4 code. Make sure it sits between your Smart Features cell and your Interactive UI cell.
# Cell 4: Visualization Functions
def plot_stock_levels():
fig, ax = plt.subplots(figsize=(10, 6))
colors = ['red' if row['Quantity'] <= row['Restock_Threshold'] else 'green'
for _, row in inventory.iterrows()]
ax.barh(inventory['Item'], inventory['Quantity'], color=colors)
ax.set_xlabel('Quantity')
ax.set_title('Inventory Stock Levels')
ax.axvline(x=0, color='black', linewidth=0.5)
plt.tight_layout()
plt.show()
def plot_value_by_category():
inventory['Value'] = inventory['Quantity'] * inventory['Price']
category_values = inventory.groupby('Category')['Value'].sum()
fig, ax = plt.subplots(figsize=(8, 6))
ax.pie(category_values, labels=category_values.index, autopct='%1.1f%%', startangle=90)
ax.set_title('Inventory Value by Category')
plt.tight_layout()
plt.show()
Your inventory tracker now has a full visual dashboard. You've built a complete application with data management, an interactive UI, smart alerts, and data visualization. Next up, tackle the Secret Mission to add a restock recommendation engine.
Secret mission
Build a Restock Recommendation Engine
Your inventory tracker can spot low-stock items, but it doesn't tell you what to do about them. In this secret mission, you'll build a recommendation engine that calculates exactly how many units to order and what it will cost. This combines conditional logic, math, and DataFrame operations into actionable purchasing guidance.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely on Google Colab and Google Drive, so there are no ongoing costs. Decide whether to keep your resources available, pause the runtime, or delete everything entirely.
Resources you used:
- A Colab notebook (free, stored on your Google Drive).
- A CSV file at /content/drive/My Drive/InventoryTracker/inventory.csv (free, stored on your Google Drive).
- The InventoryTracker folder on Google Drive containing your inventory data.
Keep everything running
No action needed. Choose this if you plan to keep building on your inventory tracker or want to reference it later.
- Your Colab notebook stays on Google Drive and can be reopened any time.
- Your inventory CSV persists between sessions. The next time you open the notebook and run it, your data loads automatically.
- There are no ongoing costs for keeping these files on Drive.
Pause - I'll come back to this later
Disconnect the Colab runtime to free up cloud compute resources. Your files remain on Google Drive for when you return.
- In your Colab notebook, click Runtime in the top menu bar.
- Click Disconnect and delete runtime.
- Your notebook and CSV file remain saved on Google Drive. The next time you open the notebook, reconnect the runtime and re-run the cells to pick up where you left off.
Delete - I don't want to use this again
Remove all project files from Google Drive and disconnect the runtime. This cannot be undone.
- In your Colab notebook, click Runtime in the top menu bar, then click Disconnect and delete runtime.
- Open Google Drive in your browser at drive.google.com.
- Navigate to the InventoryTracker folder inside My Drive.
- Right-click the InventoryTracker folder and select Move to trash. This removes the inventory.csv file and the folder.
- Find your Colab notebook file (also stored on Google Drive). Right-click it and select Move to trash.
- Empty your Google Drive trash to permanently delete the files. Click Trash in the left sidebar, then click Empty trash.
Nice Work!
Nice Work!
Nice work! You just built a fully interactive inventory management application that runs entirely inside a Google Colab notebook.
You've learned how to:
- Built an event-driven UI with ipywidgets that responds to button clicks without re-running cells.
- Implemented persistent data storage using Google Drive and pandas CSV operations that survive session restarts.
- Created a visual dashboard with color-coded matplotlib charts and smart low-stock alerts.
- Secret Mission: Built a restock recommendation engine that calculates order quantities and estimated costs based on configurable target multipliers.
Ready to quiz yourself?