File size: 8,562 Bytes
65c2a51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import gradio as gr
import xgboost as xgb
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, confusion_matrix
import plotly.express as px
import plotly.graph_objects as go
import json

class DiabetesGame:
    def __init__(self):
        self.data = self.load_data()
        self.model = self.train_model()
        self.user_score = 0
        self.total_attempts = 0
        self.tips_database = {
            "glucose": "Normal fasting blood glucose levels are less than 100 mg/dL. Levels between 100-125 mg/dL indicate prediabetes.",
            "bmi": "A BMI between 18.5 and 24.9 is considered healthy. BMI over 30 indicates obesity, a risk factor for diabetes.",
            "blood_pressure": "Normal blood pressure is usually below 120/80 mmHg. High blood pressure often co-occurs with diabetes.",
            "age": "Type 2 diabetes risk increases with age, particularly after 45 years.",
            "pregnancies": "Gestational diabetes during pregnancy increases future diabetes risk.",
            "lifestyle": "Regular exercise and a balanced diet can significantly reduce diabetes risk.",
            "family_history": "Having a parent or sibling with diabetes increases your risk.",
            "general": "Early detection and lifestyle changes can prevent or delay type 2 diabetes."
        }
        
    def load_data(self):
        return pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/diabetes.csv')
    
    def train_model(self):
        X = self.data.drop(columns=['Outcome'])
        y = self.data['Outcome']
        X_train, _, y_train, _ = train_test_split(X, y, test_size=0.2, random_state=42)
        
        model = xgb.XGBClassifier(
            eval_metric='logloss',
            max_depth=6,
            learning_rate=0.1,
            n_estimators=100,
            random_state=42
        )
        model.fit(X_train, y_train)
        return model
    
    def create_radar_chart(self, values):
        categories = ['Pregnancies', 'Glucose', 'Blood Pressure', 'Skin Thickness',
                     'Insulin', 'BMI', 'Diabetes Pedigree', 'Age']
        
        # Normalize values for radar chart
        max_values = [17, 200, 122, 99, 846, 67.1, 2.42, 81]
        normalized_values = [v/m for v, m in zip(values, max_values)]
        
        fig = go.Figure()
        fig.add_trace(go.Scatterpolar(
            r=normalized_values,
            theta=categories,
            fill='toself',
            name='Patient Values'
        ))
        
        fig.update_layout(
            polar=dict(
                radialaxis=dict(
                    visible=True,
                    range=[0, 1]
                )),
            showlegend=True,
            title="Patient Risk Factors Radar Chart"
        )
        return fig
    
    def create_feature_importance_plot(self):
        importance_df = pd.DataFrame({
            'Feature': ['Pregnancies', 'Glucose', 'Blood Pressure', 'Skin Thickness',
                       'Insulin', 'BMI', 'Diabetes Pedigree', 'Age'],
            'Importance': self.model.feature_importances_
        })
        importance_df = importance_df.sort_values('Importance', ascending=True)
        
        fig = px.bar(importance_df, x='Importance', y='Feature',
                    orientation='h',
                    title='Feature Importance in Diagnosis')
        fig.update_layout(height=400)
        return fig
    
    def get_relevant_tips(self, values):
        tips = []
        
        # Add tips based on values
        if values[1] > 140:  # High glucose
            tips.append(("⚠️ High Glucose", self.tips_database["glucose"]))
        if values[5] > 30:   # High BMI
            tips.append(("⚠️ High BMI", self.tips_database["bmi"]))
        if values[2] > 90:   # High blood pressure
            tips.append(("⚠️ High Blood Pressure", self.tips_database["blood_pressure"]))
        
        # Always add a random general tip
        general_tips = [self.tips_database["lifestyle"], 
                       self.tips_database["family_history"],
                       self.tips_database["general"]]
        tips.append(("πŸ’‘ Health Tip", np.random.choice(general_tips)))
        
        return "\n\n".join([f"{title}\n{content}" for title, content in tips])
    
    def predict_and_play(self, pregnancies, glucose, blood_pressure, skin_thickness, 
                        insulin, bmi, diabetes_pedigree, age, user_diagnosis):
        
        values = [pregnancies, glucose, blood_pressure, skin_thickness,
                 insulin, bmi, diabetes_pedigree, age]
        
        # Make prediction
        user_input = np.array(values).reshape(1, -1)
        prediction = self.model.predict(user_input)[0]
        probability = self.model.predict_proba(user_input)[0][1] * 100
        
        # Update score
        self.total_attempts += 1
        correct = (user_diagnosis == "Yes" and prediction == 1) or \
                 (user_diagnosis == "No" and prediction == 0)
        if correct:
            self.user_score += 1
        
        # Create visualizations
        radar_chart = self.create_radar_chart(values)
        importance_plot = self.create_feature_importance_plot()
        
        # Generate result message
        accuracy = (self.user_score / self.total_attempts) * 100 if self.total_attempts > 0 else 0
        
        result = f"""{'πŸŽ‰ Correct!' if correct else '❌ Incorrect'}\n
Model Prediction: {'Diabetes Risk Detected' if prediction == 1 else 'No Significant Risk'}\n
Confidence: {probability:.1f}%\n
Your Score: {self.user_score}/{self.total_attempts} ({accuracy:.1f}% accuracy)
"""
        
        # Get relevant tips
        tips = self.get_relevant_tips(values)
        
        return result, radar_chart, importance_plot, tips

# Initialize game
game = DiabetesGame()

# Create the interface
with gr.Blocks(theme=gr.themes.Soft()) as interface:
    gr.Markdown("""
    # πŸ₯ Interactive Diabetes Diagnosis Game
    
    Test your medical diagnosis skills! Analyze patient data and try to predict diabetes risk.
    Your score will be tracked as you play.
    
    ## How to Play:
    1. Adjust the patient parameters using the sliders
    2. Make your diagnosis (Yes/No for diabetes risk)
    3. Submit to see if you matched the model's prediction
    4. Learn from the visualizations and tips
    """)
    
    with gr.Row():
        with gr.Column():
            pregnancies = gr.Slider(0, 17, step=1, label="Pregnancies")
            glucose = gr.Slider(0, 200, value=120, step=1, label="Glucose Level")
            blood_pressure = gr.Slider(0, 122, value=70, step=1, label="Blood Pressure")
            skin_thickness = gr.Slider(0, 99, value=20, step=1, label="Skin Thickness")
        
        with gr.Column():
            insulin = gr.Slider(0, 846, value=80, step=1, label="Insulin")
            bmi = gr.Slider(0.0, 67.1, value=25.0, step=0.1, label="BMI")
            diabetes_pedigree = gr.Slider(0.078, 2.42, value=0.5, step=0.001, label="Diabetes Pedigree")
            age = gr.Slider(21, 81, value=30, step=1, label="Age")
    
    diagnosis = gr.Radio(["Yes", "No"], label="Your Diagnosis", info="Do you think this patient has diabetes?")
    submit_btn = gr.Button("Submit Diagnosis", variant="primary")
    
    with gr.Row():
        result_box = gr.Textbox(label="Game Result", lines=5)
        tips_box = gr.Textbox(label="Health Tips & Information", lines=5)
    
    with gr.Row():
        radar_plot = gr.Plot(label="Patient Risk Factors")
        importance_plot = gr.Plot(label="Feature Importance")
    
    submit_btn.click(
        fn=game.predict_and_play,
        inputs=[pregnancies, glucose, blood_pressure, skin_thickness,
                insulin, bmi, diabetes_pedigree, age, diagnosis],
        outputs=[result_box, radar_plot, importance_plot, tips_box]
    )
    
    gr.Markdown("""
    ## πŸ“š About the Features
    
    - **Pregnancies**: Number of times pregnant
    - **Glucose**: Plasma glucose concentration (2 hours in an oral glucose tolerance test)
    - **Blood Pressure**: Diastolic blood pressure (mm Hg)
    - **Skin Thickness**: Triceps skin fold thickness (mm)
    - **Insulin**: 2-Hour serum insulin (mu U/ml)
    - **BMI**: Body mass index (weight in kg/(height in m)Β²)
    - **Diabetes Pedigree**: A function scoring likelihood of diabetes based on family history
    - **Age**: Age in years
    """)

if __name__ == "__main__":
    interface.launch()