mic3333 commited on
Commit
bdb968f
Β·
verified Β·
1 Parent(s): 7167a40

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +157 -97
app.py CHANGED
@@ -1,12 +1,12 @@
1
  #!/usr/bin/env python3
2
  """
3
- Final Working Plotly + Pyodide - NumPy Array Fix
4
  """
5
 
6
  import gradio as gr
7
 
8
  def create_pyodide_interface():
9
- """Create the final working interface"""
10
 
11
  pyodide_html = '''
12
  <div id="pyodide-container" style="border: 1px solid #ddd; padding: 15px; border-radius: 5px; margin: 10px 0;">
@@ -37,7 +37,7 @@ def create_pyodide_interface():
37
  console.log('Status:', msg);
38
  }
39
 
40
- // Simple, reliable plot renderer
41
  window.renderPlot = function(figureJson) {
42
  try {
43
  plotId++;
@@ -46,10 +46,11 @@ def create_pyodide_interface():
46
 
47
  if (!plotsDiv) return false;
48
 
49
- // Parse figure
50
  const figDict = JSON.parse(figureJson);
51
 
52
- // Create container
 
 
53
  const plotWrapper = document.createElement('div');
54
  plotWrapper.innerHTML = `
55
  <div style="margin: 15px 0;">
@@ -59,14 +60,13 @@ def create_pyodide_interface():
59
  `;
60
  plotsDiv.appendChild(plotWrapper);
61
 
62
- // Render plot
63
  Plotly.newPlot(containerId, figDict.data, figDict.layout, {responsive: true});
64
 
65
- console.log('Plot rendered:', containerId);
66
  return true;
67
 
68
  } catch (error) {
69
- console.error('Plot error:', error);
70
  return false;
71
  }
72
  };
@@ -85,70 +85,107 @@ def create_pyodide_interface():
85
  await micropip.install('plotly')
86
  `);
87
 
88
- updateStatus('πŸ”§ Setting up integration...', 'blue');
89
 
90
  pyodide.runPython(`
91
  import json
92
  from js import renderPlot
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
- def show_plot(fig):
95
  try:
96
- # Convert figure to dict
 
 
97
  fig_dict = fig.to_dict()
98
 
99
- # Fix NumPy array serialization
100
- for trace in fig_dict.get('data', []):
101
- # Convert x data from NumPy binary to list
102
- if isinstance(trace.get('x'), dict) and 'bdata' in trace.get('x', {}):
103
- for fig_trace in fig.data:
104
- if hasattr(fig_trace, 'x') and hasattr(fig_trace.x, 'tolist'):
105
- trace['x'] = fig_trace.x.tolist()
106
- break
107
 
108
- # Convert y data from NumPy binary to list
109
- if isinstance(trace.get('y'), dict) and 'bdata' in trace.get('y', {}):
110
- for fig_trace in fig.data:
111
- if hasattr(fig_trace, 'y') and hasattr(fig_trace.y, 'tolist'):
112
- trace['y'] = fig_trace.y.tolist()
113
- break
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
  # Convert to JSON and render
116
  fig_json = json.dumps(fig_dict)
117
  success = renderPlot(fig_json)
118
 
119
  if success:
120
- print("βœ… Plot displayed successfully!")
121
  else:
122
  print("❌ Plot rendering failed")
123
 
124
  return success
125
 
126
  except Exception as e:
127
- print(f"❌ Plot error: {e}")
 
 
128
  return False
129
 
130
- # Setup Plotly
131
  try:
132
  import plotly.graph_objects as go
133
  import plotly.express as px
134
- import numpy as np
135
 
136
- # Replace show method
137
- go.Figure.show = lambda self, *args, **kwargs: show_plot(self)
138
 
139
- print("βœ… Plotly ready with NumPy fix!")
 
 
 
 
 
 
140
 
141
  except Exception as e:
142
- print(f"❌ Setup failed: {e}")
 
 
143
 
144
  print("πŸŽ‰ Environment ready!")
145
  `);
146
 
147
  ready = true;
148
- updateStatus('βœ… Ready!', 'green');
149
 
150
  document.getElementById('output').style.display = 'block';
151
- document.getElementById('text-output').textContent = 'Ready! NumPy arrays will be automatically converted.';
152
 
153
  } catch (error) {
154
  console.error('Init error:', error);
@@ -160,12 +197,10 @@ print("πŸŽ‰ Environment ready!")
160
  if (!ready) return 'Not ready';
161
 
162
  try {
163
- updateStatus('▢️ Running...', 'blue');
164
 
165
- // Clear plots
166
  document.getElementById('plots').innerHTML = '';
167
 
168
- // Capture output
169
  pyodide.runPython(`
170
  import sys
171
  from io import StringIO
@@ -173,16 +208,14 @@ old_stdout = sys.stdout
173
  sys.stdout = capture = StringIO()
174
  `);
175
 
176
- // Execute
177
  pyodide.runPython(code);
178
 
179
- // Get output
180
  let output = pyodide.runPython(`
181
  sys.stdout = old_stdout
182
  capture.getvalue()
183
  `);
184
 
185
- document.getElementById('text-output').textContent = output || 'Success';
186
  updateStatus('βœ… Done!', 'green');
187
 
188
  return output || 'Success';
@@ -195,7 +228,6 @@ capture.getvalue()
195
  }
196
  }
197
 
198
- // Initialize
199
  function init() {
200
  if (typeof loadPyodide !== 'undefined' && typeof Plotly !== 'undefined') {
201
  initPyodide();
@@ -215,94 +247,118 @@ capture.getvalue()
215
  return pyodide_html
216
 
217
  with gr.Blocks() as demo:
218
- gr.Markdown("# πŸŽ‰ Working Plotly + Pyodide")
219
- gr.Markdown("**NumPy arrays automatically converted!** Data points will now display correctly.")
220
 
221
  pyodide_interface = gr.HTML(create_pyodide_interface())
222
 
223
  with gr.Row():
224
  with gr.Column():
225
  code_input = gr.Textbox(
226
- value="""# This should now work perfectly!
227
  import plotly.graph_objects as go
 
 
228
  import numpy as np
229
 
230
- print("Creating plot with NumPy arrays...")
 
 
 
231
 
232
- # NumPy arrays (these will be auto-converted)
233
  x = np.array([1, 2, 3, 4, 5])
234
  y = np.array([1, 4, 9, 16, 25])
235
 
236
- print(f"X: {x}")
237
- print(f"Y: {y}")
238
 
239
- # Create plot
240
- fig = go.Figure()
241
- fig.add_trace(go.Scatter(
242
- x=x, # NumPy array - will be auto-converted
243
- y=y, # NumPy array - will be auto-converted
244
  mode='markers+lines',
245
- name='Quadratic',
246
- marker=dict(size=10, color='red'),
247
  line=dict(color='blue', width=2)
248
  ))
249
 
250
- fig.update_layout(
251
- title='Working Plot with NumPy Arrays!',
252
- xaxis_title='X Values',
253
- yaxis_title='Y Values',
254
- template='plotly_white'
255
- )
256
 
257
- fig.show()
258
- print("βœ… Plot complete - data points should be visible!")""",
259
  lines=18,
260
- label="Python Code"
261
  )
262
 
263
- execute_btn = gr.Button("πŸš€ Execute", variant="primary")
264
 
265
  with gr.Column():
 
 
 
 
266
  status_display = gr.Textbox(
267
  label="Status",
268
  interactive=False,
269
- lines=3
270
  )
271
-
272
- check_btn = gr.Button("πŸ“Š Check")
273
 
274
  gr.Markdown("""
275
- ### βœ… **What's Fixed:**
276
- - **NumPy arrays** automatically converted to JavaScript arrays
277
- - **Data points** will now display correctly
278
- - **Interactive features** (zoom, pan, hover) working
279
- - **No manual .tolist()** conversion needed
280
-
281
- ### πŸ§ͺ **Try These Examples:**
282
 
283
- **Simple Test:**
284
  ```python
285
- import plotly.express as px
286
- import pandas as pd
287
- df = pd.DataFrame({'x': [1,2,3,4], 'y': [1,4,9,16]})
288
- fig = px.scatter(df, x='x', y='y', title='Simple Test')
289
- fig.show()
290
  ```
291
 
292
- **3D Plot:**
293
  ```python
294
- import plotly.graph_objects as go
295
- import numpy as np
296
-
297
- x = np.random.randn(100)
298
- y = np.random.randn(100)
299
- z = np.random.randn(100)
300
-
301
- fig = go.Figure(data=go.Scatter3d(x=x, y=y, z=z, mode='markers'))
302
- fig.show()
303
  ```
 
 
 
 
 
304
  """)
305
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
306
  execute_btn.click(
307
  fn=None,
308
  inputs=[code_input],
@@ -310,13 +366,17 @@ print("βœ… Plot complete - data points should be visible!")""",
310
  js="(code) => window.executeCode ? window.executeCode(code) : 'Not ready'"
311
  )
312
 
313
- check_btn.click(
314
- fn=None,
315
  inputs=[],
316
- outputs=[status_display],
317
- js="() => window.checkReady ? (window.checkReady() ? 'βœ… Ready' : '⏳ Loading') : '❌ Error'"
 
 
 
 
 
318
  )
319
 
320
  if __name__ == "__main__":
321
- print("πŸš€ Starting Final Working Plotly + Pyodide...")
322
  demo.launch(server_name="0.0.0.0", server_port=7860, share=False)
 
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;">
 
37
  console.log('Status:', msg);
38
  }
39
 
40
+ // Enhanced plot renderer with better NumPy handling
41
  window.renderPlot = function(figureJson) {
42
  try {
43
  plotId++;
 
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;">
 
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
  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);
 
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
 
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';
 
228
  }
229
  }
230
 
 
231
  function init() {
232
  if (typeof loadPyodide !== 'undefined' && typeof Plotly !== 'undefined') {
233
  initPyodide();
 
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],
 
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)