refactor(sql_explorer): Replace Plotly with SVG rendering for plots

Replaces the Plotly-based graph generation in the SQL Explorer with direct SVG rendering within an HTML template, similar to the exercise progress sparklines.

- Modifies `routes/sql_explorer.py` endpoints (`plot_query`, `plot_unsaved_query`) to fetch raw data instead of using pandas/Plotly.
- Adds `utils.prepare_svg_plot_data` to process raw SQL results, determine plot type (scatter, line, bar, table), normalize data, and prepare it for SVG.
- Creates `templates/partials/sql_explorer/svg_plot.html` to render the SVG plot with axes, ticks, labels, and basic tooltips.
- Removes the `generate_plot` function's usage for SQL Explorer and the direct dependency on Plotly for this feature.
This commit is contained in:
Peter Stockings
2025-04-15 19:34:26 +10:00
parent 51ec18c461
commit e947feb3e3
6 changed files with 636 additions and 152 deletions

View File

@@ -5,7 +5,7 @@ from flask import Blueprint, render_template, request, current_app, jsonify
from jinja2_fragments import render_block
from flask_htmx import HTMX
from extensions import db
from utils import generate_plot
from utils import prepare_svg_plot_data # Will be created for SVG data prep
sql_explorer_bp = Blueprint('sql_explorer', __name__, url_prefix='/sql')
htmx = HTMX()
@@ -281,17 +281,47 @@ def sql_schema():
def plot_query(query_id):
(title, query) = _get_saved_query(query_id)
if not query: return "Query not found", 404
results_df = db.read_sql_as_df(query)
plot_div = generate_plot(results_df, title)
return plot_div
# Fetch raw results instead of DataFrame
(results, columns, error) = _execute_sql(query)
if error:
# Return an HTML snippet indicating the error
return f'<div class="p-4 text-red-700 bg-red-100 border border-red-400 rounded">Error executing query: {error}</div>', 400
if not results:
# Return an HTML snippet indicating no data
return '<div class="p-4 text-yellow-700 bg-yellow-100 border border-yellow-400 rounded">No data returned by query.</div>'
try:
# Prepare data for SVG plotting (function to be created in utils.py)
plot_data = prepare_svg_plot_data(results, columns, title)
# Render the new SVG template
return render_template('partials/sql_explorer/svg_plot.html', **plot_data)
except Exception as e:
current_app.logger.error(f"Error preparing SVG plot data: {e}")
# Return an HTML snippet indicating a processing error
return f'<div class="p-4 text-red-700 bg-red-100 border border-red-400 rounded">Error preparing plot data: {e}</div>', 500
@sql_explorer_bp.route("/plot/show", methods=['POST'])
def plot_unsaved_query():
query = request.form.get('query')
title = request.form.get('title')
results_df = db.read_sql_as_df(query)
plot_div = generate_plot(results_df, title)
return plot_div
title = request.form.get('title', 'SQL Query Plot') # Add default title
# Fetch raw results instead of DataFrame
(results, columns, error) = _execute_sql(query)
if error:
# Return an HTML snippet indicating the error
return f'<div class="p-4 text-red-700 bg-red-100 border border-red-400 rounded">Error executing query: {error}</div>', 400
if not results:
# Return an HTML snippet indicating no data
return '<div class="p-4 text-yellow-700 bg-yellow-100 border border-yellow-400 rounded">No data returned by query.</div>'
try:
# Prepare data for SVG plotting (function to be created in utils.py)
plot_data = prepare_svg_plot_data(results, columns, title)
# Render the new SVG template
return render_template('partials/sql_explorer/svg_plot.html', **plot_data)
except Exception as e:
current_app.logger.error(f"Error preparing SVG plot data: {e}")
# Return an HTML snippet indicating a processing error
return f'<div class="p-4 text-red-700 bg-red-100 border border-red-400 rounded">Error preparing plot data: {e}</div>', 500
@sql_explorer_bp.route("/generate_sql", methods=['POST'])
def generate_sql():