mic3333 commited on
Commit
9b66796
Β·
verified Β·
1 Parent(s): bdb968f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +154 -201
app.py CHANGED
@@ -1,12 +1,12 @@
1
  #!/usr/bin/env python3
2
  """
3
- Targeted NumPy Fix for Plotly Graph Objects
4
  """
5
 
6
  import gradio as gr
7
 
8
  def create_pyodide_interface():
9
- """Interface with specific NumPy conversion fix"""
10
 
11
  pyodide_html = '''
12
  <div id="pyodide-container" style="border: 1px solid #ddd; padding: 15px; border-radius: 5px; margin: 10px 0;">
@@ -14,8 +14,8 @@ def create_pyodide_interface():
14
  πŸ”„ Loading Pyodide + Plotly...
15
  </div>
16
  <div id="output" style="display:none; margin-top: 10px;">
17
- <h4>Results:</h4>
18
- <pre id="text-output" style="background: #f8f8f8; padding: 10px; border-radius: 3px; max-height: 200px; overflow-y: auto; white-space: pre-wrap;"></pre>
19
  <div id="plots" style="margin-top: 15px;"></div>
20
  </div>
21
  </div>
@@ -26,47 +26,38 @@ def create_pyodide_interface():
26
  <script>
27
  let pyodide = null;
28
  let ready = false;
29
- let plotId = 0;
30
 
31
  function updateStatus(msg, color = 'black') {
32
- const statusEl = document.getElementById('status');
33
- if (statusEl) {
34
- statusEl.innerHTML = msg;
35
- statusEl.style.color = color;
36
- }
37
  console.log('Status:', msg);
38
  }
39
 
40
- // Enhanced plot renderer with better NumPy handling
41
- window.renderPlot = function(figureJson) {
42
  try {
43
- plotId++;
44
- const containerId = 'plot-' + plotId;
45
  const plotsDiv = document.getElementById('plots');
46
 
47
- if (!plotsDiv) return false;
48
-
49
- const figDict = JSON.parse(figureJson);
50
-
51
- // Debug what we received
52
- console.log('Rendering plot with data:', figDict.data);
53
-
54
- const plotWrapper = document.createElement('div');
55
- plotWrapper.innerHTML = `
56
- <div style="margin: 15px 0;">
57
- <h5>πŸ“ˆ Plot ${plotId}</h5>
58
- <div id="${containerId}" style="width: 100%; height: 500px; border: 1px solid #ccc; border-radius: 5px;"></div>
59
- </div>
60
  `;
61
- plotsDiv.appendChild(plotWrapper);
62
 
63
- Plotly.newPlot(containerId, figDict.data, figDict.layout, {responsive: true});
 
 
64
 
65
- console.log('Plot created successfully');
 
66
  return true;
67
 
68
  } catch (error) {
69
- console.error('Plot rendering error:', error);
70
  return false;
71
  }
72
  };
@@ -85,298 +76,260 @@ def create_pyodide_interface():
85
  await micropip.install('plotly')
86
  `);
87
 
88
- updateStatus('πŸ”§ Setting up NumPy conversion...', 'blue');
89
 
 
90
  pyodide.runPython(`
91
  import json
92
- from js import renderPlot
93
- import numpy as np
94
-
95
- def convert_numpy_data(data):
96
- """Recursively convert NumPy arrays to lists"""
97
- if isinstance(data, np.ndarray):
98
- return data.tolist()
99
- elif isinstance(data, dict):
100
- return {key: convert_numpy_data(value) for key, value in data.items()}
101
- elif isinstance(data, list):
102
- return [convert_numpy_data(item) for item in data]
103
- else:
104
- return data
105
 
106
- def show_plot_with_conversion(fig):
107
  try:
108
- print("Converting figure data...")
109
-
110
- # Get the raw figure dict
111
  fig_dict = fig.to_dict()
112
 
113
- # Method 1: Try to convert the data traces directly
114
- for i, trace in enumerate(fig_dict.get('data', [])):
115
- print(f"Processing trace {i}...")
116
-
117
- # Check x data
118
- if 'x' in trace:
119
- original_x = trace['x']
120
- if isinstance(original_x, dict) and 'bdata' in original_x:
121
- # This is a NumPy array encoded as binary data
122
- print(f"Found NumPy x data, converting...")
123
- # Get the actual data from the figure object
124
- actual_trace = fig.data[i]
125
- if hasattr(actual_trace, 'x') and hasattr(actual_trace.x, 'tolist'):
126
- trace['x'] = actual_trace.x.tolist()
127
- print(f"X converted: {trace['x']}")
128
- else:
129
- print("Could not convert x data")
130
-
131
- # Check y data
132
- if 'y' in trace:
133
- original_y = trace['y']
134
- if isinstance(original_y, dict) and 'bdata' in original_y:
135
- print(f"Found NumPy y data, converting...")
136
- actual_trace = fig.data[i]
137
- if hasattr(actual_trace, 'y') and hasattr(actual_trace.y, 'tolist'):
138
- trace['y'] = actual_trace.y.tolist()
139
- print(f"Y converted: {trace['y']}")
140
- else:
141
- print("Could not convert y data")
142
 
143
- # Convert to JSON and render
144
- fig_json = json.dumps(fig_dict)
145
- success = renderPlot(fig_json)
146
 
147
  if success:
148
- print("βœ… Plot with converted NumPy data displayed!")
 
149
  else:
150
- print("❌ Plot rendering failed")
 
151
 
152
- return success
153
-
154
  except Exception as e:
155
- print(f"❌ Plot conversion error: {e}")
156
- import traceback
157
- traceback.print_exc()
158
  return False
159
 
160
- # Setup Plotly with our conversion fix
161
  try:
162
  import plotly.graph_objects as go
163
  import plotly.express as px
164
 
165
- # Keep the original show methods
166
- original_go_show = go.Figure.show
167
-
168
- # Replace Graph Objects show with conversion
169
- go.Figure.show = lambda self, *args, **kwargs: show_plot_with_conversion(self)
170
 
171
- # Plotly Express should work as-is (you said it works)
172
- # px functions already return converted data
173
-
174
- print("βœ… Plotly setup complete with NumPy conversion!")
175
 
176
  except Exception as e:
177
- print(f"❌ Plotly setup failed: {e}")
178
- import traceback
179
- traceback.print_exc()
180
 
181
- print("πŸŽ‰ Environment ready!")
182
  `);
183
 
184
  ready = true;
185
- updateStatus('βœ… Ready with NumPy fix!', 'green');
186
 
187
  document.getElementById('output').style.display = 'block';
188
- document.getElementById('text-output').textContent = 'Ready! Graph Objects with NumPy should now work.';
189
 
190
  } catch (error) {
191
- console.error('Init error:', error);
192
- updateStatus('❌ Failed: ' + error.message, 'red');
193
  }
194
  }
195
 
196
- async function executeCode(code) {
197
- if (!ready) return 'Not ready';
198
 
199
  try {
200
- updateStatus('▢️ Executing...', 'blue');
201
 
 
202
  document.getElementById('plots').innerHTML = '';
203
 
 
204
  pyodide.runPython(`
205
  import sys
206
  from io import StringIO
207
  old_stdout = sys.stdout
208
- sys.stdout = capture = StringIO()
209
  `);
210
 
 
211
  pyodide.runPython(code);
212
 
213
- let output = pyodide.runPython(`
 
214
  sys.stdout = old_stdout
215
- capture.getvalue()
216
  `);
217
 
218
- document.getElementById('text-output').textContent = output || 'Executed successfully';
219
- updateStatus('βœ… Done!', 'green');
220
 
221
- return output || 'Success';
222
 
223
  } catch (error) {
224
- const err = 'Error: ' + error.toString();
225
- document.getElementById('text-output').textContent = err;
226
  updateStatus('❌ Error', 'red');
227
- return err;
228
  }
229
  }
230
 
231
- function init() {
 
232
  if (typeof loadPyodide !== 'undefined' && typeof Plotly !== 'undefined') {
233
  initPyodide();
234
  } else {
235
- setTimeout(init, 1000);
236
  }
237
  }
238
 
239
- init();
240
 
241
- window.executeCode = executeCode;
242
- window.checkReady = () => ready;
 
243
 
244
  </script>
245
  '''
246
 
247
  return pyodide_html
248
 
249
- with gr.Blocks() as demo:
250
- gr.Markdown("# 🎯 NumPy Graph Objects Fix")
251
- gr.Markdown("**Targeted fix** for `go.Figure()` with NumPy arrays. Plotly Express already works!")
252
 
253
  pyodide_interface = gr.HTML(create_pyodide_interface())
254
 
255
  with gr.Row():
256
  with gr.Column():
257
  code_input = gr.Textbox(
258
- value="""# Test both methods
259
  import plotly.graph_objects as go
260
- import plotly.express as px
261
- import pandas as pd
262
- import numpy as np
263
 
264
- print("=== Testing Plotly Express (should work) ===")
265
- df = pd.DataFrame({'x': [1,2,3,4], 'y': [1,4,9,16]})
266
- fig1 = px.scatter(df, x='x', y='y', title='Plotly Express - Works!')
267
- fig1.show()
268
 
269
- print("\\n=== Testing Graph Objects with NumPy (should now work!) ===")
270
- x = np.array([1, 2, 3, 4, 5])
271
- y = np.array([1, 4, 9, 16, 25])
272
 
273
- print(f"NumPy x: {x}")
274
- print(f"NumPy y: {y}")
275
 
276
- fig2 = go.Figure()
277
- fig2.add_trace(go.Scatter(
278
- x=x, # NumPy array
279
- y=y, # NumPy array
280
  mode='markers+lines',
281
- name='Graph Objects',
282
- marker=dict(size=12, color='red'),
283
- line=dict(color='blue', width=2)
284
  ))
285
 
286
- fig2.update_layout(title='Graph Objects with NumPy - Fixed!')
287
- fig2.show()
288
 
289
- print("\\nβœ… Both plots should now display data points!")""",
290
- lines=18,
291
- label="Test Both Methods"
292
  )
293
 
294
- execute_btn = gr.Button("πŸ§ͺ Test Both", variant="primary")
295
 
296
  with gr.Column():
297
- # Separate test buttons
298
- test1_btn = gr.Button("Test 1: Express Only", variant="secondary")
299
- test2_btn = gr.Button("Test 2: Graph Objects Only", variant="secondary")
300
-
301
- status_display = gr.Textbox(
302
- label="Status",
303
  interactive=False,
304
- lines=4
305
  )
 
 
 
 
 
306
 
307
  gr.Markdown("""
308
- ### πŸ” **What This Fixes:**
 
 
 
 
309
 
310
- **βœ… Works (Plotly Express):**
 
 
311
  ```python
312
- fig = px.scatter(df, x='x', y='y') # βœ… Data shows
 
 
313
  ```
314
 
315
- **❌ Broken β†’ βœ… Fixed (Graph Objects):**
316
  ```python
317
- fig = go.Figure()
318
- fig.add_trace(go.Scatter(x=numpy_array, y=numpy_array)) # βœ… Now works!
 
319
  ```
320
-
321
- ### πŸ”§ **The Fix:**
322
- - Detects NumPy binary data in Graph Objects
323
- - Automatically converts to JavaScript arrays
324
- - Leaves Plotly Express unchanged (already works)
325
  """)
326
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
  def get_express_test():
328
  return """# Plotly Express Test
329
  import plotly.express as px
330
  import pandas as pd
331
 
332
- df = pd.DataFrame({
333
- 'x': [1, 2, 3, 4, 5],
334
- 'y': [2, 5, 3, 8, 7],
335
- 'category': ['A', 'B', 'A', 'B', 'A']
336
- })
337
-
338
- fig = px.scatter(df, x='x', y='y', color='category',
339
- title='Plotly Express Test')
340
  fig.show()
341
- print("Express test complete!")"""
342
 
343
- def get_go_test():
344
- return """# Graph Objects Test
345
  import plotly.graph_objects as go
346
  import numpy as np
347
 
 
348
  x = np.array([1, 2, 3, 4, 5])
349
- y = np.array([10, 15, 13, 17, 20])
 
 
 
 
 
 
 
350
 
351
  fig = go.Figure()
352
  fig.add_trace(go.Scatter(
353
- x=x, y=y,
 
354
  mode='markers+lines',
355
- marker=dict(size=10, color='green')
356
  ))
357
-
358
- fig.update_layout(title='Graph Objects with NumPy Test')
359
  fig.show()
360
- print("Graph Objects test complete!")"""
361
 
362
- execute_btn.click(
 
363
  fn=None,
364
  inputs=[code_input],
365
- outputs=[status_display],
366
- js="(code) => window.executeCode ? window.executeCode(code) : 'Not ready'"
367
  )
368
 
369
- test1_btn.click(
370
- fn=get_express_test,
371
- inputs=[],
372
- outputs=[code_input]
373
- )
374
-
375
- test2_btn.click(
376
- fn=get_go_test,
377
- inputs=[],
378
- outputs=[code_input]
379
- )
380
 
381
  if __name__ == "__main__":
 
382
  demo.launch(server_name="0.0.0.0", server_port=7860, share=False)
 
1
  #!/usr/bin/env python3
2
  """
3
+ Simple, Reliable Plotly + Pyodide - Back to Basics
4
  """
5
 
6
  import gradio as gr
7
 
8
  def create_pyodide_interface():
9
+ """Simple working interface without complex conversions"""
10
 
11
  pyodide_html = '''
12
  <div id="pyodide-container" style="border: 1px solid #ddd; padding: 15px; border-radius: 5px; margin: 10px 0;">
 
14
  πŸ”„ Loading Pyodide + Plotly...
15
  </div>
16
  <div id="output" style="display:none; margin-top: 10px;">
17
+ <h4>Output:</h4>
18
+ <pre id="text-output" style="background: #f8f8f8; padding: 10px; border-radius: 3px; max-height: 200px; overflow-y: auto;"></pre>
19
  <div id="plots" style="margin-top: 15px;"></div>
20
  </div>
21
  </div>
 
26
  <script>
27
  let pyodide = null;
28
  let ready = false;
29
+ let plotCount = 0;
30
 
31
  function updateStatus(msg, color = 'black') {
32
+ document.getElementById('status').innerHTML = msg;
33
+ document.getElementById('status').style.color = color;
 
 
 
34
  console.log('Status:', msg);
35
  }
36
 
37
+ // Simple plot renderer
38
+ window.createPlot = function(data, layout) {
39
  try {
40
+ plotCount++;
41
+ const plotId = 'plot-' + plotCount;
42
  const plotsDiv = document.getElementById('plots');
43
 
44
+ const plotDiv = document.createElement('div');
45
+ plotDiv.innerHTML = `
46
+ <h5>πŸ“ˆ Plot ${plotCount}</h5>
47
+ <div id="${plotId}" style="width: 100%; height: 500px; border: 1px solid #ccc; margin: 10px 0;"></div>
 
 
 
 
 
 
 
 
 
48
  `;
49
+ plotsDiv.appendChild(plotDiv);
50
 
51
+ // Parse if strings
52
+ if (typeof data === 'string') data = JSON.parse(data);
53
+ if (typeof layout === 'string') layout = JSON.parse(layout);
54
 
55
+ Plotly.newPlot(plotId, data, layout, {responsive: true});
56
+ console.log('Plot created:', plotId);
57
  return true;
58
 
59
  } catch (error) {
60
+ console.error('Plot error:', error);
61
  return false;
62
  }
63
  };
 
76
  await micropip.install('plotly')
77
  `);
78
 
79
+ updateStatus('πŸ”§ Setting up environment...', 'blue');
80
 
81
+ // Simple Python setup - no complex conversions
82
  pyodide.runPython(`
83
  import json
84
+ from js import createPlot
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
+ def simple_show(fig):
87
  try:
88
+ # Get the figure as dict
 
 
89
  fig_dict = fig.to_dict()
90
 
91
+ # Simple approach: let Python handle the conversion
92
+ data_json = json.dumps(fig_dict.get('data', []))
93
+ layout_json = json.dumps(fig_dict.get('layout', {}))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
 
95
+ # Call JavaScript
96
+ success = createPlot(data_json, layout_json)
 
97
 
98
  if success:
99
+ print("Plot created!")
100
+ return True
101
  else:
102
+ print("Plot failed")
103
+ return False
104
 
 
 
105
  except Exception as e:
106
+ print(f"Plot error: {e}")
 
 
107
  return False
108
 
109
+ # Setup Plotly
110
  try:
111
  import plotly.graph_objects as go
112
  import plotly.express as px
113
 
114
+ # Replace show method
115
+ go.Figure.show = lambda self, *args, **kwargs: simple_show(self)
 
 
 
116
 
117
+ print("Plotly ready!")
 
 
 
118
 
119
  except Exception as e:
120
+ print(f"Plotly setup error: {e}")
 
 
121
 
122
+ print("Environment ready!")
123
  `);
124
 
125
  ready = true;
126
+ updateStatus('βœ… Ready!', 'green');
127
 
128
  document.getElementById('output').style.display = 'block';
129
+ document.getElementById('text-output').textContent = 'System ready. Try the simple examples.';
130
 
131
  } catch (error) {
132
+ console.error('Initialization error:', error);
133
+ updateStatus('❌ Error: ' + error.message, 'red');
134
  }
135
  }
136
 
137
+ async function runCode(code) {
138
+ if (!ready) return 'System not ready';
139
 
140
  try {
141
+ updateStatus('▢️ Running...', 'blue');
142
 
143
+ // Clear plots
144
  document.getElementById('plots').innerHTML = '';
145
 
146
+ // Capture output
147
  pyodide.runPython(`
148
  import sys
149
  from io import StringIO
150
  old_stdout = sys.stdout
151
+ sys.stdout = output = StringIO()
152
  `);
153
 
154
+ // Run code
155
  pyodide.runPython(code);
156
 
157
+ // Get output
158
+ let result = pyodide.runPython(`
159
  sys.stdout = old_stdout
160
+ output.getvalue()
161
  `);
162
 
163
+ document.getElementById('text-output').textContent = result || 'Code executed';
164
+ updateStatus('βœ… Complete', 'green');
165
 
166
+ return result || 'Success';
167
 
168
  } catch (error) {
169
+ const errorMsg = 'Error: ' + error.toString();
170
+ document.getElementById('text-output').textContent = errorMsg;
171
  updateStatus('❌ Error', 'red');
172
+ return errorMsg;
173
  }
174
  }
175
 
176
+ // Initialize
177
+ function startInit() {
178
  if (typeof loadPyodide !== 'undefined' && typeof Plotly !== 'undefined') {
179
  initPyodide();
180
  } else {
181
+ setTimeout(startInit, 1000);
182
  }
183
  }
184
 
185
+ startInit();
186
 
187
+ // Global functions
188
+ window.runCode = runCode;
189
+ window.isReady = () => ready;
190
 
191
  </script>
192
  '''
193
 
194
  return pyodide_html
195
 
196
+ with gr.Blocks(title="Simple Plotly Test") as demo:
197
+ gr.Markdown("# πŸ”§ Simple Plotly Test")
198
+ gr.Markdown("**Back to basics** - Let's get the fundamental setup working first.")
199
 
200
  pyodide_interface = gr.HTML(create_pyodide_interface())
201
 
202
  with gr.Row():
203
  with gr.Column():
204
  code_input = gr.Textbox(
205
+ value="""# Test 1: Absolute basics with Python lists
206
  import plotly.graph_objects as go
 
 
 
207
 
208
+ print("Creating basic plot with Python lists...")
 
 
 
209
 
210
+ # Use plain Python lists (no NumPy)
211
+ x_list = [1, 2, 3, 4, 5]
212
+ y_list = [1, 4, 9, 16, 25]
213
 
214
+ print(f"X: {x_list}")
215
+ print(f"Y: {y_list}")
216
 
217
+ fig = go.Figure()
218
+ fig.add_trace(go.Scatter(
219
+ x=x_list,
220
+ y=y_list,
221
  mode='markers+lines',
222
+ name='Basic Test'
 
 
223
  ))
224
 
225
+ fig.update_layout(title='Basic Test - Python Lists Only')
226
+ fig.show()
227
 
228
+ print("Basic test complete!")""",
229
+ lines=15,
230
+ label="Test Code"
231
  )
232
 
233
+ run_btn = gr.Button("πŸš€ Run Test", variant="primary")
234
 
235
  with gr.Column():
236
+ status_output = gr.Textbox(
237
+ label="Result",
 
 
 
 
238
  interactive=False,
239
+ lines=3
240
  )
241
+
242
+ # Quick test buttons
243
+ basic_btn = gr.Button("Test: Python Lists", variant="secondary")
244
+ express_btn = gr.Button("Test: Plotly Express", variant="secondary")
245
+ numpy_manual_btn = gr.Button("Test: NumPy Manual", variant="secondary")
246
 
247
  gr.Markdown("""
248
+ ### 🎯 **Testing Strategy:**
249
+
250
+ 1. **Python Lists** - Should work (no NumPy conversion issues)
251
+ 2. **Plotly Express** - You said this works
252
+ 3. **NumPy Manual** - Convert arrays manually with `.tolist()`
253
 
254
+ ### πŸ“ **Test Examples:**
255
+
256
+ **Safe Python Lists:**
257
  ```python
258
+ x = [1, 2, 3, 4, 5] # Plain list
259
+ y = [1, 4, 9, 16, 25] # Plain list
260
+ fig.add_trace(go.Scatter(x=x, y=y))
261
  ```
262
 
263
+ **Manual NumPy Conversion:**
264
  ```python
265
+ x = np.array([1, 2, 3, 4, 5])
266
+ y = np.array([1, 4, 9, 16, 25])
267
+ fig.add_trace(go.Scatter(x=x.tolist(), y=y.tolist())) # Manual .tolist()
268
  ```
 
 
 
 
 
269
  """)
270
 
271
+ def get_basic_test():
272
+ return """# Basic Python Lists Test
273
+ import plotly.graph_objects as go
274
+
275
+ x = [1, 2, 3, 4, 5]
276
+ y = [2, 4, 6, 8, 10]
277
+
278
+ fig = go.Figure()
279
+ fig.add_trace(go.Scatter(x=x, y=y, mode='markers+lines'))
280
+ fig.update_layout(title='Python Lists Test')
281
+ fig.show()
282
+ print("Python lists test done!")"""
283
+
284
  def get_express_test():
285
  return """# Plotly Express Test
286
  import plotly.express as px
287
  import pandas as pd
288
 
289
+ df = pd.DataFrame({'x': [1,2,3,4], 'y': [1,4,9,16]})
290
+ fig = px.scatter(df, x='x', y='y', title='Express Test')
 
 
 
 
 
 
291
  fig.show()
292
+ print("Express test done!")"""
293
 
294
+ def get_numpy_manual_test():
295
+ return """# NumPy with Manual Conversion
296
  import plotly.graph_objects as go
297
  import numpy as np
298
 
299
+ print("Creating NumPy arrays...")
300
  x = np.array([1, 2, 3, 4, 5])
301
+ y = np.array([1, 4, 9, 16, 25])
302
+
303
+ print("Converting to lists manually...")
304
+ x_list = x.tolist() # Manual conversion
305
+ y_list = y.tolist() # Manual conversion
306
+
307
+ print(f"Converted X: {x_list}")
308
+ print(f"Converted Y: {y_list}")
309
 
310
  fig = go.Figure()
311
  fig.add_trace(go.Scatter(
312
+ x=x_list,
313
+ y=y_list,
314
  mode='markers+lines',
315
+ marker=dict(size=8, color='red')
316
  ))
317
+ fig.update_layout(title='NumPy Manual Conversion')
 
318
  fig.show()
319
+ print("Manual NumPy conversion test done!")"""
320
 
321
+ # Event handlers
322
+ run_btn.click(
323
  fn=None,
324
  inputs=[code_input],
325
+ outputs=[status_output],
326
+ js="(code) => window.runCode ? window.runCode(code) : 'Not ready'"
327
  )
328
 
329
+ basic_btn.click(fn=get_basic_test, outputs=[code_input])
330
+ express_btn.click(fn=get_express_test, outputs=[code_input])
331
+ numpy_manual_btn.click(fn=get_numpy_manual_test, outputs=[code_input])
 
 
 
 
 
 
 
 
332
 
333
  if __name__ == "__main__":
334
+ print("πŸš€ Starting Simple Plotly Test...")
335
  demo.launch(server_name="0.0.0.0", server_port=7860, share=False)