File size: 11,093 Bytes
b99e090
 
 
 
 
4699f43
b99e090
4699f43
b99e090
2b8f833
4699f43
 
 
 
b99e090
4699f43
 
 
 
 
 
b99e090
4699f43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b99e090
4699f43
 
 
abac731
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b99e090
4699f43
 
abac731
 
b99e090
4699f43
 
 
 
 
b99e090
4699f43
abac731
4699f43
 
 
 
 
 
b99e090
4699f43
 
b99e090
 
2b8f833
b99e090
4699f43
2b8f833
4699f43
 
 
 
 
 
 
 
 
 
 
b99e090
 
 
4699f43
 
b99e090
4699f43
 
 
 
b99e090
 
4699f43
 
 
abac731
 
4699f43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b99e090
4699f43
 
 
abac731
 
4699f43
abac731
 
b99e090
4699f43
 
 
 
 
 
 
 
 
 
 
 
 
 
abac731
4699f43
 
 
 
 
abac731
4699f43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
abac731
 
 
 
 
 
 
 
4699f43
abac731
 
4699f43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b99e090
4699f43
 
b99e090
 
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
import streamlit as st
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# Set streamlit configuration with disable XSRF protection
st.config.set_option("server.enableXsrfProtection", False)
st.set_page_config(page_title="Dysphagia Analysis", page_icon="👅")


# Function to plot the EMG signal Coordination Analysis
def emg_plot(event_index, event_plot_name, left_std_ratio, left_delta_t, right_std_ratio, right_delta_t):
    """

    Plots a 2D quadrant chart for EMG signal analysis with colored squares indicating the quadrant.



    Parameters:

    std (float): Standard deviation value of the EMG signal.

    delta_t (float): Delta T value of the EMG signal.

    """
    # Create a new figure
    fig, ax = plt.subplots(figsize=(8, 8))

    # Determine the quadrant and plot the colored square
    if left_std_ratio > 3 and left_delta_t > 0:
        # First quadrant
        ax.add_patch(plt.Rectangle((2, 2), 6, 6, color='blue', alpha=0.5))
    elif left_std_ratio <= 3 and left_delta_t > 0:
        # Second quadrant
        ax.add_patch(plt.Rectangle((-8, 2), 6, 6, color='blue', alpha=0.5))
    elif left_std_ratio <= 3 and left_delta_t <= 0:
        # Third quadrant
        ax.add_patch(plt.Rectangle((-8, -8), 6, 6, color='blue', alpha=0.5))
    elif left_std_ratio > 3 and left_delta_t <= 0:
        # Fourth quadrant
        ax.add_patch(plt.Rectangle((2, -8), 6, 6, color='blue', alpha=0.5))
        
    # Determine the quadrant and plot the colored square
    if right_std_ratio > 3 and right_delta_t > 0:
        # First quadrant
        ax.add_patch(plt.Rectangle((1.5, 1.5), 6, 6, color='green', alpha=0.5))
    elif right_std_ratio <= 3 and right_delta_t > 0:
        # Second quadrant
        ax.add_patch(plt.Rectangle((-8.5, 1.5), 6, 6, color='green', alpha=0.5))
    elif right_std_ratio <= 3 and right_delta_t <= 0:
        # Third quadrant
        ax.add_patch(plt.Rectangle((-8.5, -8.5), 6, 6, color='green', alpha=0.5))
    elif right_std_ratio > 3 and right_delta_t <= 0:
        # Fourth quadrant
        ax.add_patch(plt.Rectangle((1.5, -8.5), 6, 6, color='green', alpha=0.5))

    # Add horizontal and vertical lines to create quadrants
    plt.axhline(y=0, color='black', linestyle='--')
    plt.axvline(x=0, color='black', linestyle='--')
    
    # Add quadrant labels
    # Add styled text labels with colored box
    def add_styled_text(x, y, text, va='bottom'):
        # Create text box style
        bbox_props = dict(
            boxstyle='round,pad=0.5',
            fc='#1f77b4',      # 背景顏色(白色)
            ec='#1f77b4',   # 邊框顏色(藍色)
            alpha=0.7,      # 背景透明度
            lw=1.5          # 邊框寬度
        )
        
        plt.text(x, y, text,
                horizontalalignment='center',
                verticalalignment=va,
                bbox=bbox_props,
                color='white',
                fontweight='semibold',
                fontsize=9)

    # Add styled quadrant labels
    add_styled_text(4, 0.5, "Exertion + / Coordination -", 'bottom')
    add_styled_text(-4, 0.5, "Exertion - / Coordination -", 'bottom')
    add_styled_text(-4, -0.5, "Exertion - / Coordination +", 'top')
    add_styled_text(4, -0.5, "Exertion + / Coordination +", 'top')

    # Add title and axis labels
    plt.title(f'Muscle Coordination Analysis - {event_index}:{event_plot_name}', fontsize=14)
    plt.xlabel('Exertion (Std Ratio > 3)', fontsize=12, fontweight='semibold')
    plt.ylabel('Coordination (Delta T > 0)', fontsize=12, fontweight='semibold')

    # Remove axis numbers and labels
    ax.set_xticks([])
    ax.set_yticks([])
    ax.set_xticklabels([])
    ax.set_yticklabels([])
    
    # Set plot legend with color
    plt.legend(['Left Swallowing Muscle', 'Right Swallowing Muscle'], loc='upper left', fontsize=10)

    # Set the limits of the plot
    plt.xlim(-10, 10)
    plt.ylim(-10, 10)

    # Display the plot
    st.pyplot(plt.gcf())
    #plt.show()


def main():
    st.image("logo/itri_logo.jpg", width=600)
    st.title('👅Dysphagia Analysis - by ITRI BDL')
    
    
    # Initialize session state variables
    if 'emg_data' not in st.session_state:
        st.session_state.emg_data = None
    if 'time_marker' not in st.session_state:
        st.session_state.time_marker = None
    if 'analysis_started' not in st.session_state:
        st.session_state.analysis_started = False
    if 'data_isready' not in st.session_state:
        st.session_state.data_isready = False

    # File Uploaders
    uploaded_file1 = st.file_uploader("Choose the EMG_data CSV file", type="csv")
    uploaded_file2 = st.file_uploader("Choose the time_marker CSV file", type="csv")
        
    # Load data when files are uploaded
    if uploaded_file1 is not None and uploaded_file2 is not None:
        try:
            st.session_state.emg_data = pd.read_csv(uploaded_file1, skiprows=[0,1,3,4])
            st.session_state.time_marker = pd.read_csv(uploaded_file2)
            st.success("Data loaded successfully!")
            st.session_state.data_isready = True
        except Exception as e:
            st.error(f"Error: {e}")
    
    # Load test data button
    if st.button('Load Test Data', type="primary"):
        st.session_state.emg_data = pd.read_csv('test-new/0-New_Task-recording-0.csv', skiprows=[0,1,3,4])
        st.session_state.time_marker = pd.read_csv('test-new/time_marker.csv')
        st.success("Test data loaded successfully!")
        st.session_state.data_isready = True

    # Display loaded data
    if st.session_state.emg_data is not None:
        st.subheader("EMG Data")
        st.dataframe(st.session_state.emg_data)
    if st.session_state.time_marker is not None:
        st.subheader("Time Marker")
        st.dataframe(st.session_state.time_marker)

    # Analysis button
    if st.session_state.data_isready:
        st.subheader("Muscle Coordination Analysis")
        if st.button('Start Analysis', type="primary"):
            st.session_state.analysis_started = True

    # Perform analysis if started
    if st.session_state.analysis_started:
        st.write('Analysis in progress...')
        
        # Reset emg data index with Channels
        emg_data = st.session_state.emg_data.set_index('Channels')
        # Get signal data from difference of emg_data
        signal_left_lateral = emg_data['17'] - emg_data['18']
        signal_left_medial = emg_data['19'] - emg_data['20']

        signal_right_lateral = emg_data['23'] - emg_data['24']
        signal_right_medial = emg_data['21'] - emg_data['22']
        
        # RMS caculation : Define the moving average window size
        N = 25
        # Function to calculate moving RMS
        def moving_rms(signal, window_size):
            rms = np.sqrt(pd.Series(signal).rolling(window=window_size).mean()**2)
            rms.index = signal.index  # Ensure the index matches the original signal
            return rms
        # Calculate moving RMS for each channel
        signal_left_lateral_RMS = moving_rms(signal_left_lateral, N)
        signal_left_medial_RMS = moving_rms(signal_left_medial, N)
        signal_right_lateral_RMS = moving_rms(signal_right_lateral, N)
        signal_right_medial_RMS = moving_rms(signal_right_medial, N)
        
        # Time Marker Processing
        time_marker = st.session_state.time_marker[['0-New_Task-recording_time(us)', 'description', 'tag']]
        time_marker = time_marker.rename(columns={'0-New_Task-recording_time(us)': 'event_time'})
        
        # Select column value with odd/even index
        event_start_times = time_marker.loc[0::2]['event_time'].values.astype(int)
        event_end_times = time_marker.loc[1::2]['event_time'].values.astype(int)
        event_names = time_marker.loc[0::2]['description'].values
        
        # Get signal basic 10s std
        signal_left_lateral_basics_10s_std = signal_left_lateral_RMS.loc[: 10000000].std()
        signal_right_lateral_basics_10s_std = signal_right_lateral_RMS.loc[: 10000000].std()
        
        # Analyze event data 
        event_number = len(event_names)

        for i in range(1, 2*event_number, 2):
            event_name = event_names[i//2]
            event_start_time = event_start_times[i//2]
            event_end_time = event_end_times[i//2]
            
            st.write(f"Event {i//2+1}: {event_name}")
            st.write(f"Start time: {float(event_start_time)/1000000: .3f} sec, End time: {float(event_end_time)/1000000: .3f} sec")
            
            # Get event signal data with event time duration
            mask_LL = (signal_left_lateral_RMS.index >= event_start_time) & (signal_left_lateral_RMS.index <= event_end_time)
            event_signal_LL = signal_left_lateral_RMS.iloc[mask_LL]
            
            mask_LM = (signal_left_medial_RMS.index >= event_start_time) & (signal_left_medial_RMS.index <= event_end_time)
            event_signal_LM = signal_left_medial_RMS.iloc[mask_LM]
            
            mask_RL = (signal_right_lateral_RMS.index >= event_start_time) & (signal_right_lateral_RMS.index <= event_end_time)
            event_signal_RL = signal_right_lateral_RMS.iloc[mask_RL]
            
            mask_RM = (signal_right_medial_RMS.index >= event_start_time) & (signal_right_medial_RMS.index <= event_end_time)
            event_signal_RM = signal_right_medial_RMS.iloc[mask_RM]
            
            # Calculate std ratio 
            left_event_std = event_signal_LL.std()
            left_std_ratio = left_event_std / signal_left_lateral_basics_10s_std
            
            right_event_std = event_signal_RL.std()
            right_std_ratio = right_event_std / signal_right_lateral_basics_10s_std
            
            st.write(f"left std ratio: {left_std_ratio: .3f}, right std ratio: {right_std_ratio: .3f}")
            
            # Get signal max value index
            LL_max_index = event_signal_LL.idxmax()
            LM_max_index = event_signal_LM.idxmax()
            left_delta_t = LM_max_index - LL_max_index
            st.write(f"LM_max_index: {float(LM_max_index)/1000000: .3f}, LL_max_index: {float(LL_max_index)/1000000: .3f}, left delta t: {float(left_delta_t)/1000000: .3f}")
            
            RL_max_index = event_signal_RL.idxmax()
            RM_max_index = event_signal_RM.idxmax()
            right_delta_t = RM_max_index - RL_max_index
            st.write(f"RM_max_index: {float(RM_max_index)/1000000: .3f}, RL_max_index: {float(RL_max_index)/1000000: .3f}, right delta t: {float(right_delta_t)/1000000: .3f}")
            
            # Plot with each event data
            emg_plot(i//2+1, event_name, left_std_ratio, left_delta_t, right_std_ratio, right_delta_t)
        
        st.write('Analysis completed!')
    
if __name__ == '__main__':
    main()