Update app.py
Browse files
app.py
CHANGED
|
@@ -1,150 +1,109 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
import pandas as pd
|
| 3 |
import plotly.graph_objects as go
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
# Function to create a 3D-like glowing circular indicator
|
| 7 |
-
def create_glowing_indicator(color):
|
| 8 |
-
size = 100 # Size of the indicator
|
| 9 |
-
img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
| 10 |
-
draw = ImageDraw.Draw(img)
|
| 11 |
-
glow_color = tuple(map(lambda x: int(x * 0.7), ImageColor.getrgb(color))) + (100,)
|
| 12 |
-
|
| 13 |
-
# Outer glow
|
| 14 |
-
for i in range(20, 0, -1):
|
| 15 |
-
draw.ellipse(
|
| 16 |
-
(i, i, size - i, size - i),
|
| 17 |
-
fill=glow_color,
|
| 18 |
-
outline=None
|
| 19 |
-
)
|
| 20 |
-
glow_color = tuple(map(lambda x: min(x + 10, 255), glow_color[:3])) + (100,)
|
| 21 |
-
|
| 22 |
-
# Main circle
|
| 23 |
-
draw.ellipse(
|
| 24 |
-
(20, 20, size - 20, size - 20),
|
| 25 |
-
fill=color,
|
| 26 |
-
outline=None
|
| 27 |
-
)
|
| 28 |
-
return img
|
| 29 |
-
|
| 30 |
-
# Function to load data
|
| 31 |
@st.cache_data
|
| 32 |
def load_data():
|
|
|
|
| 33 |
df = pd.read_excel("grid_load_data.xlsx")
|
| 34 |
-
|
| 35 |
-
# Identify 'Time' column
|
| 36 |
time_column = next((col for col in df.columns if "time" in col.lower() or "date" in col.lower()), None)
|
| 37 |
-
if time_column:
|
| 38 |
-
df["Time"] = pd.to_datetime(df[time_column])
|
| 39 |
-
else:
|
| 40 |
-
raise KeyError("Time column is missing in the dataset.")
|
| 41 |
-
|
| 42 |
-
# Identify 'Grid Load (kW)' column
|
| 43 |
load_column = next((col for col in df.columns if "grid" in col.lower() and "load" in col.lower()), None)
|
| 44 |
-
|
|
|
|
|
|
|
| 45 |
df["Grid Load (kW)"] = df[load_column]
|
| 46 |
else:
|
| 47 |
-
raise KeyError("Grid Load (kW)
|
| 48 |
-
|
| 49 |
return df
|
| 50 |
|
| 51 |
-
# Function to calculate available EV charging slots
|
| 52 |
-
def calculate_ev_slots(grid_load, threshold=3000, ev_capacity=50):
|
| 53 |
-
if grid_load < threshold:
|
| 54 |
-
return (threshold - grid_load) // ev_capacity
|
| 55 |
-
return 0
|
| 56 |
-
|
| 57 |
-
# Function to calculate EVs needed to stabilize the grid
|
| 58 |
-
def calculate_evs_needed(grid_load, threshold=3000, ev_capacity=50):
|
| 59 |
-
if grid_load > threshold:
|
| 60 |
-
return (grid_load - threshold) // ev_capacity
|
| 61 |
-
return 0
|
| 62 |
-
|
| 63 |
-
# Main function
|
| 64 |
def main():
|
| 65 |
-
|
| 66 |
-
|
|
|
|
| 67 |
# Title
|
| 68 |
-
st.title("Grid
|
| 69 |
-
|
| 70 |
-
# Alarm Indicators
|
| 71 |
-
st.sidebar.write("**Alarm Indicators**")
|
| 72 |
-
st.sidebar.write("Green: Normal Load")
|
| 73 |
-
st.sidebar.write("Red: Overload")
|
| 74 |
-
|
| 75 |
# Load dataset
|
| 76 |
try:
|
| 77 |
df = load_data()
|
| 78 |
except KeyError as e:
|
| 79 |
st.error(f"Error loading data: {e}")
|
| 80 |
return
|
| 81 |
-
|
| 82 |
-
#
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
with
|
| 98 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
fig = go.Figure(go.Indicator(
|
| 100 |
mode="gauge+number",
|
| 101 |
-
value=
|
| 102 |
title={'text': "Grid Load (kW)"},
|
| 103 |
gauge={
|
| 104 |
'axis': {'range': [0, 5000]},
|
| 105 |
-
'bar': {'color':
|
| 106 |
'steps': [
|
| 107 |
-
{'range': [0, 3000], 'color': "
|
| 108 |
{'range': [3000, 3200], 'color': "orange"},
|
| 109 |
-
{'range': [3200, 5000], 'color': "red"}
|
|
|
|
| 110 |
}
|
| 111 |
))
|
| 112 |
st.plotly_chart(fig, use_container_width=True)
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
st.
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
st.write("EVs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
else:
|
| 135 |
-
st.
|
| 136 |
-
|
| 137 |
-
st.write(f"EVs needed to stabilize the grid: {evs_needed}")
|
| 138 |
-
|
| 139 |
-
# Connect EVs Bar
|
| 140 |
-
num_evs = st.number_input("Number of EVs to connect to grid", min_value=0, max_value=evs_needed, step=1)
|
| 141 |
-
if st.button("Connect EVs"):
|
| 142 |
-
reduced_load = grid_load - (num_evs * 50)
|
| 143 |
-
if reduced_load < 3000:
|
| 144 |
-
reduced_load = 3000 # Set to minimum threshold
|
| 145 |
-
st.success(f"Grid stabilized. Updated load: {reduced_load} kW")
|
| 146 |
-
st.write(f"Number of EVs connected: {num_evs}")
|
| 147 |
-
|
| 148 |
-
# Run app
|
| 149 |
if __name__ == "__main__":
|
| 150 |
-
main()
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
import pandas as pd
|
| 3 |
import plotly.graph_objects as go
|
| 4 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
@st.cache_data
|
| 6 |
def load_data():
|
| 7 |
+
"""Load grid data from the dataset."""
|
| 8 |
df = pd.read_excel("grid_load_data.xlsx")
|
|
|
|
|
|
|
| 9 |
time_column = next((col for col in df.columns if "time" in col.lower() or "date" in col.lower()), None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
load_column = next((col for col in df.columns if "grid" in col.lower() and "load" in col.lower()), None)
|
| 11 |
+
|
| 12 |
+
if time_column and load_column:
|
| 13 |
+
df["Time"] = pd.to_datetime(df[time_column])
|
| 14 |
df["Grid Load (kW)"] = df[load_column]
|
| 15 |
else:
|
| 16 |
+
raise KeyError("Dataset must contain 'Time' and 'Grid Load (kW)' columns.")
|
|
|
|
| 17 |
return df
|
| 18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
def main():
|
| 20 |
+
# Page Layout
|
| 21 |
+
st.set_page_config(layout="wide")
|
| 22 |
+
|
| 23 |
# Title
|
| 24 |
+
st.title("Interactive Grid and EV Management Dashboard")
|
| 25 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
# Load dataset
|
| 27 |
try:
|
| 28 |
df = load_data()
|
| 29 |
except KeyError as e:
|
| 30 |
st.error(f"Error loading data: {e}")
|
| 31 |
return
|
| 32 |
+
|
| 33 |
+
# Sidebar Input Mode
|
| 34 |
+
st.sidebar.header("Input Mode")
|
| 35 |
+
input_mode = st.sidebar.radio("Choose Input Mode", ["Automatic Fetch", "Manual Input"])
|
| 36 |
+
current_grid_load = 0
|
| 37 |
+
|
| 38 |
+
if input_mode == "Automatic Fetch":
|
| 39 |
+
current_time = st.sidebar.selectbox("Select Time", df["Time"].dt.strftime("%Y-%m-%d %H:%M:%S"))
|
| 40 |
+
current_time = pd.to_datetime(current_time)
|
| 41 |
+
current_grid_load = df[df["Time"] == current_time]["Grid Load (kW)"].values[0]
|
| 42 |
+
else:
|
| 43 |
+
current_grid_load = st.sidebar.slider("Select Grid Load (kW)", 0, 5000, 2500, step=50)
|
| 44 |
+
|
| 45 |
+
# Layout: Grid Details (Left) | EV Details (Right)
|
| 46 |
+
col1, col2 = st.columns([1, 1])
|
| 47 |
+
|
| 48 |
+
with col1: # Grid Details
|
| 49 |
+
st.subheader("Grid Details")
|
| 50 |
+
|
| 51 |
+
# Status Indicator
|
| 52 |
+
grid_status = "Normal" if current_grid_load <= 3000 else "Overloaded"
|
| 53 |
+
status_color = "green" if grid_status == "Normal" else "red"
|
| 54 |
+
|
| 55 |
+
st.markdown(f"**Status**: <span style='color:{status_color}; font-size:20px;'>{grid_status}</span>", unsafe_allow_html=True)
|
| 56 |
+
|
| 57 |
+
# Gauge for Grid Load
|
| 58 |
fig = go.Figure(go.Indicator(
|
| 59 |
mode="gauge+number",
|
| 60 |
+
value=current_grid_load,
|
| 61 |
title={'text': "Grid Load (kW)"},
|
| 62 |
gauge={
|
| 63 |
'axis': {'range': [0, 5000]},
|
| 64 |
+
'bar': {'color': status_color},
|
| 65 |
'steps': [
|
| 66 |
+
{'range': [0, 3000], 'color': "lightgreen"},
|
| 67 |
{'range': [3000, 3200], 'color': "orange"},
|
| 68 |
+
{'range': [3200, 5000], 'color': "red"}
|
| 69 |
+
]
|
| 70 |
}
|
| 71 |
))
|
| 72 |
st.plotly_chart(fig, use_container_width=True)
|
| 73 |
+
|
| 74 |
+
# Suggestions
|
| 75 |
+
if current_grid_load < 3000:
|
| 76 |
+
st.success("Grid is stable. No action needed.")
|
| 77 |
+
elif 3000 <= current_grid_load < 3200:
|
| 78 |
+
st.warning("Grid is under moderate load. Monitor EV connectivity.")
|
| 79 |
+
else:
|
| 80 |
+
st.error("Grid is overloaded. Immediate action required!")
|
| 81 |
+
|
| 82 |
+
with col2: # EV Details
|
| 83 |
+
st.subheader("EV Details")
|
| 84 |
+
|
| 85 |
+
ev_capacity = 50 # Each EV contributes or consumes 50 kW
|
| 86 |
+
if current_grid_load < 3000:
|
| 87 |
+
# Calculate EV charging slots
|
| 88 |
+
ev_slots = (3000 - current_grid_load) // ev_capacity
|
| 89 |
+
st.write(f"Available EV charging slots: **{ev_slots}**")
|
| 90 |
+
elif current_grid_load > 3200:
|
| 91 |
+
# Calculate EVs needed to stabilize grid
|
| 92 |
+
evs_needed = (current_grid_load - 3000) // ev_capacity
|
| 93 |
+
st.write(f"Number of EVs needed to stabilize the grid: **{evs_needed}**")
|
| 94 |
+
|
| 95 |
+
# Button to simulate EV connection
|
| 96 |
+
num_evs = st.slider("Number of EVs to connect", 0, int(evs_needed), step=1)
|
| 97 |
+
if st.button("Connect EVs to Grid"):
|
| 98 |
+
reduced_load = current_grid_load - (num_evs * ev_capacity)
|
| 99 |
+
st.success(f"EVs connected! New Grid Load: {reduced_load} kW")
|
| 100 |
+
|
| 101 |
+
# Alarm Lights
|
| 102 |
+
st.sidebar.header("Alarms")
|
| 103 |
+
if current_grid_load > 3000:
|
| 104 |
+
st.sidebar.markdown("**Alarm Status**: <span style='color:red;'>Overloaded</span>", unsafe_allow_html=True)
|
| 105 |
else:
|
| 106 |
+
st.sidebar.markdown("**Alarm Status**: <span style='color:green;'>Normal</span>", unsafe_allow_html=True)
|
| 107 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
if __name__ == "__main__":
|
| 109 |
+
main()
|