mic3333 commited on
Commit
0f968e0
Β·
verified Β·
1 Parent(s): a787b7c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +208 -142
app.py CHANGED
@@ -1,17 +1,17 @@
1
  #!/usr/bin/env python3
2
  """
3
- Plotly Express Test Interface - Try Different Examples
4
  """
5
 
6
  import gradio as gr
7
 
8
  def create_pyodide_interface():
9
- """Simple interface to test different Express examples"""
10
 
11
  pyodide_html = '''
12
  <div id="pyodide-container" style="border: 1px solid #ddd; padding: 15px; border-radius: 5px; margin: 10px 0;">
13
  <div id="status" style="font-weight: bold; padding: 10px; background: #f0f0f0; border-radius: 3px;">
14
- πŸ”„ Loading Pyodide...
15
  </div>
16
  <div id="output" style="display:none; margin-top: 10px;">
17
  <h4>Output:</h4>
@@ -33,7 +33,7 @@ def create_pyodide_interface():
33
  document.getElementById('status').style.color = color;
34
  }
35
 
36
- window.createPlot = function(data, layout) {
37
  try {
38
  plotCount++;
39
  const plotId = 'plot-' + plotCount;
@@ -42,7 +42,7 @@ def create_pyodide_interface():
42
  const plotDiv = document.createElement('div');
43
  plotDiv.innerHTML = `
44
  <h5>πŸ“Š Plot ${plotCount}</h5>
45
- <div id="${plotId}" style="width: 100%; height: 400px; border: 1px solid #ccc; margin: 10px 0;"></div>
46
  `;
47
  plotsDiv.appendChild(plotDiv);
48
 
@@ -50,6 +50,7 @@ def create_pyodide_interface():
50
  if (typeof layout === 'string') layout = JSON.parse(layout);
51
 
52
  Plotly.newPlot(plotId, data, layout, {responsive: true});
 
53
  return true;
54
 
55
  } catch (error) {
@@ -60,48 +61,139 @@ def create_pyodide_interface():
60
 
61
  async function init() {
62
  try {
63
- updateStatus('πŸ”„ Loading...', 'blue');
64
  pyodide = await loadPyodide();
65
 
 
66
  await pyodide.loadPackage(['numpy', 'pandas', 'micropip']);
 
 
67
  await pyodide.runPythonAsync(`
68
  import micropip
69
  await micropip.install('plotly')
70
  `);
71
 
 
 
 
72
  pyodide.runPython(`
73
  import json
74
- from js import createPlot
 
75
 
76
- def show_plot(fig):
 
 
 
 
 
 
 
 
 
 
 
 
77
  try:
 
 
 
78
  fig_dict = fig.to_dict()
79
- data_json = json.dumps(fig_dict.get('data', []))
80
- layout_json = json.dumps(fig_dict.get('layout', {}))
81
- success = createPlot(data_json, layout_json)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  if success:
83
- print("Plot displayed!")
 
 
 
84
  return success
 
85
  except Exception as e:
86
- print(f"Plot error: {e}")
 
 
87
  return False
88
 
 
89
  try:
90
  import plotly.graph_objects as go
91
  import plotly.express as px
92
- go.Figure.show = lambda self, *args, **kwargs: show_plot(self)
93
- print("Plotly ready!")
 
 
 
 
 
 
 
 
 
 
94
  except Exception as e:
95
- print(f"Setup error: {e}")
 
 
 
 
96
  `);
97
 
98
  ready = true;
99
- updateStatus('βœ… Ready!', 'green');
100
 
101
  document.getElementById('output').style.display = 'block';
102
- document.getElementById('text-output').textContent = 'Ready to test Plotly Express examples!';
103
 
104
  } catch (error) {
 
105
  updateStatus('❌ Error: ' + error.message, 'red');
106
  }
107
  }
@@ -129,7 +221,7 @@ capture.getvalue()
129
  `);
130
 
131
  document.getElementById('text-output').textContent = output || 'Code executed';
132
- updateStatus('βœ… Done', 'green');
133
 
134
  return output || 'Success';
135
 
@@ -141,15 +233,15 @@ capture.getvalue()
141
  }
142
  }
143
 
144
- function waitForCDN() {
145
  if (typeof loadPyodide !== 'undefined' && typeof Plotly !== 'undefined') {
146
  init();
147
  } else {
148
- setTimeout(waitForCDN, 1000);
149
  }
150
  }
151
 
152
- waitForCDN();
153
 
154
  window.runCode = runCode;
155
 
@@ -158,150 +250,127 @@ capture.getvalue()
158
 
159
  return pyodide_html
160
 
161
- # Example templates
162
- examples = {
163
- "Minimal Test": '''# Absolute minimal test
164
- import plotly.express as px
165
-
166
- print("Testing minimal Express...")
167
- fig = px.scatter(x=[1, 2], y=[1, 2], title="Minimal")
168
- fig.show()
169
- print("Minimal test complete!")''',
170
 
171
- "Direct Arrays": '''# Test without DataFrame
172
- import plotly.express as px
173
-
174
- print("Testing direct arrays...")
175
- fig = px.scatter(x=[1, 2, 3, 4], y=[1, 4, 9, 16], title="Direct Arrays")
176
- fig.show()
177
- print("Direct arrays test complete!")''',
178
 
179
- "Simple DataFrame": '''# Simple DataFrame test
 
 
 
180
  import plotly.express as px
 
181
  import pandas as pd
 
182
 
183
- print("Creating DataFrame...")
184
  df = pd.DataFrame({
185
  'x': [1, 2, 3, 4, 5],
186
  'y': [2, 4, 6, 8, 10]
187
  })
188
- print("DataFrame:")
189
- print(df)
190
-
191
- print("Creating plot...")
192
- fig = px.scatter(df, x='x', y='y', title='DataFrame Test')
193
- fig.show()
194
- print("DataFrame test complete!")''',
195
-
196
- "Line Chart": '''# Line chart test
197
- import plotly.express as px
198
- import pandas as pd
199
-
200
- df = pd.DataFrame({
201
- 'x': [1, 2, 3, 4, 5],
202
- 'y': [1, 4, 2, 8, 5]
203
- })
204
-
205
- fig = px.line(df, x='x', y='y', title='Line Chart')
206
- fig.show()
207
- print("Line chart complete!")''',
208
-
209
- "Bar Chart": '''# Bar chart test
210
- import plotly.express as px
211
- import pandas as pd
212
-
213
- df = pd.DataFrame({
214
- 'category': ['A', 'B', 'C', 'D'],
215
- 'values': [20, 35, 30, 25]
216
- })
217
-
218
- fig = px.bar(df, x='category', y='values', title='Bar Chart')
219
- fig.show()
220
- print("Bar chart complete!")''',
221
-
222
- "Data Types": '''# Test different data types
223
- import plotly.express as px
224
- import pandas as pd
225
- import numpy as np
226
-
227
- print("Creating mixed data types...")
228
- df = pd.DataFrame({
229
- 'int_col': [1, 2, 3, 4],
230
- 'float_col': [1.1, 2.2, 3.3, 4.4],
231
- 'numpy_col': np.array([1, 2, 3, 4])
232
- })
233
-
234
- print("DataFrame info:")
235
- print(df.dtypes)
236
-
237
- fig = px.scatter(df, x='int_col', y='float_col', title='Data Types')
238
- fig.show()
239
- print("Data types test complete!")''',
240
-
241
- "Compare Methods": '''# Compare DataFrame vs Direct
242
- import plotly.express as px
243
- import pandas as pd
244
-
245
- print("=== Method 1: DataFrame ===")
246
- df = pd.DataFrame({'x': [1, 2, 3], 'y': [1, 4, 9]})
247
- fig1 = px.scatter(df, x='x', y='y', title='DataFrame Method')
248
  fig1.show()
249
 
250
- print("=== Method 2: Direct Arrays ===")
251
- fig2 = px.scatter(x=[1, 2, 3], y=[1, 4, 9], title='Direct Method')
252
  fig2.show()
253
 
254
- print("Comparison complete!")'''
255
- }
 
256
 
257
- with gr.Blocks() as demo:
258
- gr.Markdown("# πŸ§ͺ Plotly Express Test Suite")
259
- gr.Markdown("**Test different Express examples** to find what works and what doesn't")
260
-
261
- pyodide_interface = gr.HTML(create_pyodide_interface())
262
-
263
- with gr.Row():
264
- with gr.Column(scale=2):
265
- code_input = gr.Textbox(
266
- value=examples["Minimal Test"],
267
- lines=12,
268
  label="Test Code"
269
  )
270
 
271
- run_btn = gr.Button("πŸš€ Run Test", variant="primary", size="lg")
272
-
273
- with gr.Column(scale=1):
274
- gr.Markdown("### πŸ“‹ Quick Tests")
275
 
276
- example_buttons = []
277
- for name, code in examples.items():
278
- btn = gr.Button(f"πŸ“Š {name}", variant="secondary")
279
- example_buttons.append((btn, code))
 
280
 
281
  status_output = gr.Textbox(
282
  label="Result",
283
  interactive=False,
284
- lines=3
285
  )
286
 
287
  gr.Markdown("""
288
- ### 🎯 **Testing Strategy:**
 
 
 
 
 
 
 
 
289
 
290
- 1. **Start with "Minimal Test"** - absolute basics
291
- 2. **Try "Direct Arrays"** - no DataFrames involved
292
- 3. **Test "Simple DataFrame"** - basic DataFrame usage
293
- 4. **Run "Compare Methods"** - see DataFrame vs direct difference
294
- 5. **Check "Data Types"** - see if data type issues exist
295
 
296
- ### πŸ” **What to Watch:**
297
- - βœ… **Data points visible** = Working correctly
298
- - ❌ **Only background/axes** = Data issue
299
- - πŸ“ **Check output messages** for clues
300
 
301
- ### πŸ’‘ **Expected Results:**
302
- Based on your previous tests, some of these might work while others show only background.
 
 
303
  """)
304
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  # Event handlers
306
  run_btn.click(
307
  fn=None,
@@ -310,12 +379,9 @@ with gr.Blocks() as demo:
310
  js="(code) => window.runCode ? window.runCode(code) : 'Not ready'"
311
  )
312
 
313
- # Example button handlers
314
- for btn, code in example_buttons:
315
- btn.click(
316
- fn=lambda c=code: c,
317
- outputs=[code_input]
318
- )
319
 
320
  if __name__ == "__main__":
321
  demo.launch(server_name="0.0.0.0", server_port=7860, share=False)
 
1
  #!/usr/bin/env python3
2
  """
3
+ Plotly Express Integration Fix - Address the Root Cause
4
  """
5
 
6
  import gradio as gr
7
 
8
  def create_pyodide_interface():
9
+ """Fix Express by converting it to Graph Objects under the hood"""
10
 
11
  pyodide_html = '''
12
  <div id="pyodide-container" style="border: 1px solid #ddd; padding: 15px; border-radius: 5px; margin: 10px 0;">
13
  <div id="status" style="font-weight: bold; padding: 10px; background: #f0f0f0; border-radius: 3px;">
14
+ πŸ”„ Loading with Express fix...
15
  </div>
16
  <div id="output" style="display:none; margin-top: 10px;">
17
  <h4>Output:</h4>
 
33
  document.getElementById('status').style.color = color;
34
  }
35
 
36
+ window.renderPlot = function(data, layout) {
37
  try {
38
  plotCount++;
39
  const plotId = 'plot-' + plotCount;
 
42
  const plotDiv = document.createElement('div');
43
  plotDiv.innerHTML = `
44
  <h5>πŸ“Š Plot ${plotCount}</h5>
45
+ <div id="${plotId}" style="width: 100%; height: 450px; border: 1px solid #ccc; margin: 10px 0;"></div>
46
  `;
47
  plotsDiv.appendChild(plotDiv);
48
 
 
50
  if (typeof layout === 'string') layout = JSON.parse(layout);
51
 
52
  Plotly.newPlot(plotId, data, layout, {responsive: true});
53
+ console.log('Plot rendered:', plotId);
54
  return true;
55
 
56
  } catch (error) {
 
61
 
62
  async function init() {
63
  try {
64
+ updateStatus('πŸ”„ Loading Pyodide...', 'blue');
65
  pyodide = await loadPyodide();
66
 
67
+ updateStatus('πŸ“¦ Installing packages...', 'blue');
68
  await pyodide.loadPackage(['numpy', 'pandas', 'micropip']);
69
+
70
+ updateStatus('πŸ“ˆ Installing Plotly...', 'blue');
71
  await pyodide.runPythonAsync(`
72
  import micropip
73
  await micropip.install('plotly')
74
  `);
75
 
76
+ updateStatus('πŸ”§ Fixing Express integration...', 'blue');
77
+
78
+ // The key fix: properly handle Express vs Graph Objects
79
  pyodide.runPython(`
80
  import json
81
+ import numpy as np
82
+ from js import renderPlot
83
 
84
+ def convert_numpy_to_lists(obj):
85
+ """Recursively convert numpy arrays to Python lists"""
86
+ if isinstance(obj, np.ndarray):
87
+ return obj.tolist()
88
+ elif isinstance(obj, dict):
89
+ return {k: convert_numpy_to_lists(v) for k, v in obj.items()}
90
+ elif isinstance(obj, list):
91
+ return [convert_numpy_to_lists(item) for item in obj]
92
+ else:
93
+ return obj
94
+
95
+ def show_any_figure(fig):
96
+ """Universal show function that works for both Express and Graph Objects"""
97
  try:
98
+ print(f"Rendering figure of type: {type(fig)}")
99
+
100
+ # Convert figure to dictionary
101
  fig_dict = fig.to_dict()
102
+
103
+ print(f"Figure has {len(fig_dict.get('data', []))} traces")
104
+
105
+ # Process each trace
106
+ fixed_data = []
107
+ for i, trace in enumerate(fig_dict.get('data', [])):
108
+ print(f"Processing trace {i}: type={trace.get('type', 'unknown')}")
109
+
110
+ # Create a copy of the trace
111
+ fixed_trace = dict(trace)
112
+
113
+ # Fix x data
114
+ if 'x' in fixed_trace:
115
+ x_data = fixed_trace['x']
116
+ if isinstance(x_data, dict) and 'bdata' in x_data:
117
+ # NumPy binary data - convert from original figure
118
+ original_trace = fig.data[i]
119
+ if hasattr(original_trace, 'x') and hasattr(original_trace.x, 'tolist'):
120
+ fixed_trace['x'] = original_trace.x.tolist()
121
+ print(f" Converted x from NumPy: {fixed_trace['x']}")
122
+ else:
123
+ # Regular data - ensure it's a list
124
+ fixed_trace['x'] = convert_numpy_to_lists(x_data)
125
+ print(f" X data: {fixed_trace['x']}")
126
+
127
+ # Fix y data
128
+ if 'y' in fixed_trace:
129
+ y_data = fixed_trace['y']
130
+ if isinstance(y_data, dict) and 'bdata' in y_data:
131
+ # NumPy binary data
132
+ original_trace = fig.data[i]
133
+ if hasattr(original_trace, 'y') and hasattr(original_trace.y, 'tolist'):
134
+ fixed_trace['y'] = original_trace.y.tolist()
135
+ print(f" Converted y from NumPy: {fixed_trace['y']}")
136
+ else:
137
+ # Regular data
138
+ fixed_trace['y'] = convert_numpy_to_lists(y_data)
139
+ print(f" Y data: {fixed_trace['y']}")
140
+
141
+ fixed_data.append(fixed_trace)
142
+
143
+ # Create the plot data
144
+ plot_data = json.dumps(fixed_data)
145
+ plot_layout = json.dumps(fig_dict.get('layout', {}))
146
+
147
+ print(f"Sending to JavaScript - data length: {len(plot_data)}")
148
+
149
+ # Render the plot
150
+ success = renderPlot(plot_data, plot_layout)
151
+
152
  if success:
153
+ print("βœ… Plot rendered successfully!")
154
+ else:
155
+ print("❌ Plot rendering failed")
156
+
157
  return success
158
+
159
  except Exception as e:
160
+ print(f"❌ Figure rendering error: {e}")
161
+ import traceback
162
+ traceback.print_exc()
163
  return False
164
 
165
+ # Setup both Graph Objects and Express
166
  try:
167
  import plotly.graph_objects as go
168
  import plotly.express as px
169
+ import pandas as pd
170
+
171
+ # Replace the show method for Graph Objects
172
+ go.Figure.show = lambda self, *args, **kwargs: show_any_figure(self)
173
+
174
+ # The key insight: Express functions return Figure objects
175
+ # So we don't need to patch px functions individually
176
+ # Our go.Figure.show patch will handle Express figures too!
177
+
178
+ print("βœ… Both Graph Objects and Express patched!")
179
+ print("βœ… Universal figure rendering enabled!")
180
+
181
  except Exception as e:
182
+ print(f"❌ Setup error: {e}")
183
+ import traceback
184
+ traceback.print_exc()
185
+
186
+ print("πŸŽ‰ Environment ready with Express fix!")
187
  `);
188
 
189
  ready = true;
190
+ updateStatus('βœ… Ready with Express fix!', 'green');
191
 
192
  document.getElementById('output').style.display = 'block';
193
+ document.getElementById('text-output').textContent = 'Express integration fixed! Both px and go should work now.';
194
 
195
  } catch (error) {
196
+ console.error('Init error:', error);
197
  updateStatus('❌ Error: ' + error.message, 'red');
198
  }
199
  }
 
221
  `);
222
 
223
  document.getElementById('text-output').textContent = output || 'Code executed';
224
+ updateStatus('βœ… Complete', 'green');
225
 
226
  return output || 'Success';
227
 
 
233
  }
234
  }
235
 
236
+ function waitForReady() {
237
  if (typeof loadPyodide !== 'undefined' && typeof Plotly !== 'undefined') {
238
  init();
239
  } else {
240
+ setTimeout(waitForReady, 1000);
241
  }
242
  }
243
 
244
+ waitForReady();
245
 
246
  window.runCode = runCode;
247
 
 
250
 
251
  return pyodide_html
252
 
253
+ with gr.Blocks() as demo:
254
+ gr.Markdown("# πŸ”§ Plotly Express Fix")
255
+ gr.Markdown("**Universal fix** for both Graph Objects and Express data display issues")
 
 
 
 
 
 
256
 
257
+ pyodide_interface = gr.HTML(create_pyodide_interface())
 
 
 
 
 
 
258
 
259
+ with gr.Row():
260
+ with gr.Column():
261
+ code_input = gr.Textbox(
262
+ value="""# Test the Express fix
263
  import plotly.express as px
264
+ import plotly.graph_objects as go
265
  import pandas as pd
266
+ import numpy as np
267
 
268
+ print("=== Test 1: Express Scatter ===")
269
  df = pd.DataFrame({
270
  'x': [1, 2, 3, 4, 5],
271
  'y': [2, 4, 6, 8, 10]
272
  })
273
+ fig1 = px.scatter(df, x='x', y='y', title='Express Scatter - Fixed!')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  fig1.show()
275
 
276
+ print("=== Test 2: Express Line ===")
277
+ fig2 = px.line(df, x='x', y='y', title='Express Line - Fixed!')
278
  fig2.show()
279
 
280
+ print("=== Test 3: Graph Objects (should still work) ===")
281
+ x = np.array([1, 2, 3, 4, 5])
282
+ y = np.array([1, 4, 9, 16, 25])
283
 
284
+ fig3 = go.Figure()
285
+ fig3.add_trace(go.Scatter(x=x, y=y, mode='markers+lines', name='GO Test'))
286
+ fig3.update_layout(title='Graph Objects - Should Still Work')
287
+ fig3.show()
288
+
289
+ print("βœ… All tests complete! Check if data points are visible.")""",
290
+ lines=18,
 
 
 
 
291
  label="Test Code"
292
  )
293
 
294
+ run_btn = gr.Button("πŸ§ͺ Test Fix", variant="primary", size="lg")
 
 
 
295
 
296
+ with gr.Column():
297
+ # Quick test buttons
298
+ express_test_btn = gr.Button("πŸ“Š Quick Express Test")
299
+ go_test_btn = gr.Button("πŸ“Š Quick GO Test")
300
+ comparison_btn = gr.Button("πŸ“Š Side-by-Side Test")
301
 
302
  status_output = gr.Textbox(
303
  label="Result",
304
  interactive=False,
305
+ lines=4
306
  )
307
 
308
  gr.Markdown("""
309
+ ### πŸ”‘ **The Key Insight:**
310
+
311
+ **Problem**: Plotly Express functions return `Figure` objects, but they have different internal data structures than Graph Objects figures.
312
+
313
+ **Solution**: Create a **universal figure renderer** that handles both:
314
+ - βœ… **Graph Objects**: Direct trace creation
315
+ - βœ… **Express**: Converts Express figures using same logic
316
+
317
+ ### 🎯 **What This Fix Does:**
318
 
319
+ 1. **Universal Handler**: One function handles both `px.scatter()` and `go.Figure()`
320
+ 2. **Smart Data Conversion**: Detects and converts NumPy arrays in both cases
321
+ 3. **Type Detection**: Identifies figure source and processes accordingly
 
 
322
 
323
+ ### πŸ§ͺ **Expected Results:**
 
 
 
324
 
325
+ After this fix, **ALL** of these should show data points:
326
+ - βœ… `px.scatter()`, `px.line()`, `px.bar()`
327
+ - βœ… `go.Figure().add_trace()`
328
+ - βœ… Both with DataFrames and NumPy arrays
329
  """)
330
 
331
+ def get_express_test():
332
+ return """# Quick Express test
333
+ import plotly.express as px
334
+ import pandas as pd
335
+
336
+ df = pd.DataFrame({'x': [1,2,3,4], 'y': [1,4,9,16]})
337
+ fig = px.scatter(df, x='x', y='y', title='Express Test')
338
+ fig.show()
339
+ print("Express test done!")"""
340
+
341
+ def get_go_test():
342
+ return """# Quick Graph Objects test
343
+ import plotly.graph_objects as go
344
+
345
+ fig = go.Figure()
346
+ fig.add_trace(go.Scatter(x=[1,2,3,4], y=[1,4,9,16], mode='markers'))
347
+ fig.update_layout(title='Graph Objects Test')
348
+ fig.show()
349
+ print("GO test done!")"""
350
+
351
+ def get_comparison():
352
+ return """# Side-by-side comparison
353
+ import plotly.express as px
354
+ import plotly.graph_objects as go
355
+ import pandas as pd
356
+
357
+ # Same data, different methods
358
+ data_x = [1, 2, 3, 4, 5]
359
+ data_y = [2, 4, 6, 8, 10]
360
+
361
+ print("Creating Express version...")
362
+ df = pd.DataFrame({'x': data_x, 'y': data_y})
363
+ fig1 = px.scatter(df, x='x', y='y', title='Express Method')
364
+ fig1.show()
365
+
366
+ print("Creating Graph Objects version...")
367
+ fig2 = go.Figure()
368
+ fig2.add_trace(go.Scatter(x=data_x, y=data_y, mode='markers', name='GO Method'))
369
+ fig2.update_layout(title='Graph Objects Method')
370
+ fig2.show()
371
+
372
+ print("Both should now show identical data points!")"""
373
+
374
  # Event handlers
375
  run_btn.click(
376
  fn=None,
 
379
  js="(code) => window.runCode ? window.runCode(code) : 'Not ready'"
380
  )
381
 
382
+ express_test_btn.click(fn=get_express_test, outputs=[code_input])
383
+ go_test_btn.click(fn=get_go_test, outputs=[code_input])
384
+ comparison_btn.click(fn=get_comparison, outputs=[code_input])
 
 
 
385
 
386
  if __name__ == "__main__":
387
  demo.launch(server_name="0.0.0.0", server_port=7860, share=False)