Data 100 GCP cloud cost simulator widget

This interactive widget allows you to calculate the cost for running CPU heavy workloads in standard virtual machine vs CPU optimized machine

import pandas as pd

# Data for the table
data = {
    "Type of node": [
        "n2-highcpu-32", "n2-highcpu-32", "n2-highcpu-32", "n2-highcpu-32", "n2-highcpu-32", "n2-highcpu-32", "n2-highcpu-96", "n2-highcpu-96", "n2-highcpu-96", "n2-highcpu-96", "n2-highcpu-96", "n2-highcpu-96", 
        "n2-highmem-32", "n2-highmem-32", "n2-highmem-32", "n2-highmem-32", "n2-highmem-32", "n2-highmem-32"
    ],
    "Number of CPUs allocated per student": [
        "4 CPU", "4 CPU", "4 CPU", "2 CPU", "2 CPU", "2 CPU", "4 CPU", "4 CPU", "4 CPU", "2 CPU", "2 CPU", "2 CPU", "4 CPU", "4 CPU", "4 CPU", "2 CPU", "2 CPU", "2 CPU"
    ],
    "Estimate of the total number of students running CPU based workloads": [
        1200, 600, 400, 1200, 600, 400, 1200, 600, 400, 1200, 600, 400, 1200, 600, 400, 1200, 600, 400
    ],
    "# of students allocated per node": [
        8, 8, 8, 16, 16, 16, 24, 24, 24, 48, 48, 48, 8, 8, 8, 16, 16, 16
    ],
    "Total number of nodes allocated": [
        150, 75, 50, 75, 38, 25, 50, 25, 17, 25, 13, 8, 150, 75, 38, 75, 38, 25
    ],
    "Node cost per day": [
        27.9, 27.9, 27.9, 27.9, 27.9, 27.9, 83.73, 83.73, 83.73, 83.73, 83.73, 83.73, 51, 51, 51, 51, 51, 51
    ],
    "Number of days": [
        12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12
    ],
    "Total Cost (12 days)": [
        50220, 25110, 16740, 25110, 12555, 8370, 50238, 25119, 16746, 25119, 12559.5, 8373, 91800, 45900, 23256, 45900, 23256, 15300
    ]
}

# Creating the DataFrame
df = pd.DataFrame(data)
import ipywidgets as widgets
from IPython.display import display
from ipywidgets import Layout

# Pricing data for the latest instance costs in the Iowa Central region (us-central1)
NODE_PRICING = {
    'n2-highcpu-32': 27.93,  # Latest price for n2-highcpu-32
    'n2-highcpu-96': 83.73,  # Latest price for n2-highcpu-96
    'n2-highmem-32': 50.31,  # Latest price for n2-highmem-32
}

# Function to calculate the total number of nodes and total cost
def calculate_total_cost(node_type, num_cpus, num_students, num_days):
    # Extract the number of CPUs in the node from the node type (e.g., 32 or 96)
    node_capacity = int(node_type.split('-')[-1])
    
    # Calculate the number of students allocated per node
    students_per_node = node_capacity / num_cpus
    
    # Calculate the total number of nodes needed
    total_nodes = num_students / students_per_node
    
    # Get the node cost from the pricing dictionary
    node_cost = NODE_PRICING[node_type]
    
    # Calculate the total cost for the given number of days
    total_cost = total_nodes * node_cost * num_days
    
    return total_nodes, total_cost

# Callback function for the button
def on_button_click(b):
    node_type = node_type_dropdown.value
    num_cpus = int(num_cpus_dropdown.value.split()[0])  # Extracting the number of CPUs (2 or 4)
    num_students = int(students_input.value)
    num_days = int(num_days_input.value)
    
    # Calculate total nodes and total cost
    total_nodes, total_cost = calculate_total_cost(node_type, num_cpus, num_students, num_days)
    
    # Show result in text box
    result_text.value = f"Total nodes allocated: {total_nodes:.2f}\nTotal cost for {num_days} days: ${total_cost:.2f}"

# Widget elements
node_type_dropdown = widgets.Dropdown(
    options=['n2-highcpu-32', 'n2-highcpu-96', 'n2-highmem-32'],
    value='n2-highcpu-32',
    description='Node Type:',
    style={'description_width': 'initial'},
    layout=Layout(width='80%')
)

num_cpus_dropdown = widgets.Dropdown(
    options=['2 CPU', '4 CPU'],
    value='4 CPU',
    description='CPUs per Student:',
    style={'description_width': 'initial'},
    layout=Layout(width='80%')
)

students_input = widgets.IntText(
    value=1200,
    description='Total Students:',
    style={'description_width': 'initial'},
    layout=Layout(width='80%')
)

num_days_input = widgets.IntText(
    value=12,
    description='Number of Days:',
    style={'description_width': 'initial'},
    layout=Layout(width='80%')
)

calculate_button = widgets.Button(
    description='Calculate Total Cost',
    button_style='success',
    layout=Layout(width='50%')  # Set button width to 50% of the container width
)

# Improved result text box with larger size, center alignment, and padding for better spacing
result_text = widgets.Textarea(
    value='',
    description='Result:',
    disabled=True,
    layout=Layout(width='80%', height='100px', padding='10px'),
    style={'description_width': 'initial', 'text-align': 'center'}
)

# Attach the click event handler
calculate_button.on_click(on_button_click)

# Organize widgets in a vertical and horizontal layout with proper spacing
inputs_box = widgets.VBox([
    widgets.VBox([node_type_dropdown, num_cpus_dropdown], layout=Layout(align_items='center', padding='10px')),
    widgets.VBox([students_input, num_days_input], layout=Layout(align_items='center', padding='10px')),
    calculate_button
], layout=Layout(padding='10px', align_items='center', width='100%'))

# Final layout for displaying widgets and result
final_layout = widgets.VBox([
    inputs_box,
    result_text
], layout=Layout(padding='10px', align_items='center'))

# Display the entire widget setup
display(final_layout)
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
/tmp/ipykernel_1868/2300274380.py in <module>
----> 1 import ipywidgets as widgets
      2 from IPython.display import display
      3 from ipywidgets import Layout
      4 
      5 # Pricing data for the latest instance costs in the Iowa Central region (us-central1)

ModuleNotFoundError: No module named 'ipywidgets'