File size: 4,013 Bytes
dfc428f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt

# Title of the Streamlit app
st.title("Electric Field Visualization")
st.write("Add charges to see how the electric field changes! Positive charges are red, negative charges are blue.")

# Initialize session state to store charges
if 'charges' not in st.session_state:
    st.session_state.charges = []

# Function to calculate the electric field on a grid
def calculate_electric_field(charges, X, Y, k=1, epsilon=1e-6):
    """
    Calculate the electric field components (E_x, E_y) at each point on the grid.
    
    Parameters:
    - charges: List of dictionaries with 'x', 'y', and 'q' for each charge
    - X, Y: 2D arrays from np.meshgrid representing grid coordinates
    - k: Coulomb's constant (set to 1 for simplicity)
    - epsilon: Small value to avoid division by zero at charge locations
    
    Returns:
    - E_x, E_y: Electric field components as 2D arrays
    """
    E_x_total = np.zeros_like(X)
    E_y_total = np.zeros_like(Y)
    for charge in charges:
        dx = X - charge['x']
        dy = Y - charge['y']
        r = np.sqrt(dx**2 + dy**2 + epsilon)  # Distance with epsilon to avoid singularity
        # E = k * q * r̂ / r^2, where r̂ is the unit vector (dx/r, dy/r)
        # So, E_x = k * q * dx / r^3, E_y = k * q * dy / r^3
        E_x_charge = k * charge['q'] * dx / r**3
        E_y_charge = k * charge['q'] * dy / r**3
        E_x_total += E_x_charge
        E_y_total += E_y_charge
    return E_x_total, E_y_total

# UI to add a charge
st.subheader("Add a Charge")
x = st.slider("X position", -5.0, 5.0, 0.0, key="x_add")
y = st.slider("Y position", -5.0, 5.0, 0.0, key="y_add")
q = st.selectbox("Charge", [1, -1], format_func=lambda val: "+1" if val > 0 else "-1", key="q_add")
if st.button("Add Charge", key="add_charge"):
    st.session_state.charges.append({'x': x, 'y': y, 'q': q})
    st.success(f"Added charge q={q} at ({x}, {y})")

# UI to display and remove charges
st.subheader("Current Charges")
if st.session_state.charges:
    for i, charge in enumerate(st.session_state.charges):
        st.write(f"Charge {i}: x={charge['x']}, y={charge['y']}, q={'+' if charge['q'] > 0 else '-'}1")
    
    # Select and remove a charge
    charge_to_remove = st.selectbox(
        "Select charge to remove",
        options=range(len(st.session_state.charges)),
        format_func=lambda i: f"Charge {i}: x={st.session_state.charges[i]['x']}, y={st.session_state.charges[i]['y']}, q={'+' if st.session_state.charges[i]['q'] > 0 else '-'}1",
        key="charge_to_remove"
    )
    if st.button("Remove Selected Charge", key="remove_charge"):
        del st.session_state.charges[charge_to_remove]
        st.success("Charge removed!")
else:
    st.write("No charges added yet. Add some to see the electric field.")

# Create the plot if there are charges
if st.session_state.charges:
    # Define the grid for calculation
    x_grid = np.linspace(-5, 5, 20)
    y_grid = np.linspace(-5, 5, 20)
    X, Y = np.meshgrid(x_grid, y_grid)

    # Calculate the electric field
    E_x, E_y = calculate_electric_field(st.session_state.charges, X, Y)

    # Create the plot
    fig, ax = plt.subplots(figsize=(8, 8))
    ax.streamplot(X, Y, E_x, E_y, color='black', linewidth=1, density=1.5)
    
    # Plot each charge
    for charge in st.session_state.charges:
        color = 'red' if charge['q'] > 0 else 'blue'
        ax.plot(charge['x'], charge['y'], 'o', color=color, markersize=10, label=f"q={charge['q']}")
    
    # Set plot limits and labels
    ax.set_xlim(-5, 5)
    ax.set_ylim(-5, 5)
    ax.set_xlabel("X")
    ax.set_ylabel("Y")
    ax.set_title("Electric Field Lines")
    ax.grid(True)

    # Display the plot in Streamlit
    st.pyplot(fig)
else:
    st.info("Add some charges above to visualize the electric field!")

# Footer
st.write("Note: The field lines point away from positive charges and toward negative charges, following the direction a positive test charge would move.")