VISUALIZATION GUIDELINES FOR ALLEGROGRAPH QUERIES

================================================================================
THREE SIMPLE RULES
================================================================================

1. NEVER output HTML, canvas, or Chart.js code in your response text.
   (This is a web UI, not Claude Desktop - there is no artifact pane.)

2. ALWAYS ASK before storing. Say something like:
   "Would you like me to store this query and visualization in the Query Library?"

3. ONLY call store_query and store_query_visualization AFTER the user says yes.

That's it. Show results, describe the visualization in words, ask to store, wait for yes.

================================================================================
CHART.JS CONFIGURATION FORMAT (for store_query_visualization tool)
================================================================================

When creating visualizations for AllegroGraph query results, you MUST follow
these guidelines:

1. CHART LIBRARY REQUIREMENT

   ✅ ALWAYS USE: Chart.js
   ❌ NEVER USE: React components (React-Chartjs-2, Recharts, Victory, etc.)

   WHY: React-based visualizations DO NOT render in browsers when saved as
   HTML artifacts or opened as standalone files. Chart.js creates artifacts
   that render beautifully in Claude Desktop AND work in any browser.

2. SUPPORTED VISUALIZATION TYPES

   Chart.js types (all supported):
   - bar (bar_chart) - vertical or horizontal bar charts
   - line (line_chart) - trends over time
   - pie (pie_chart) - parts of a whole
   - scatter (scatter_plot) - correlations
   - doughnut (doughnut_chart) - pie with center hole
   - radar (radar_chart) - multi-dimensional comparisons
   - polarArea (polar_area_chart) - radial bar chart
   - bubble (bubble_chart) - scatter with size dimension
   - bar with stacked option (stacked_bar_chart) - stacked categories

   Other supported types:
   - table (plain HTML table)
   - network_graph (use D3.js, NOT React)
   - map (interactive Leaflet map for GeoSPARQL/geographic data)

3. CHART.JS IMPLEMENTATION PATTERN

   When creating a Chart.js visualization artifact, use this structure:

   ```html
   <!DOCTYPE html>
   <html>
   <head>
       <title>Chart Title</title>
       <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
   </head>
   <body>
       <canvas id="myChart"></canvas>
       <script>
           const ctx = document.getElementById('myChart');
           new Chart(ctx, {
               type: 'bar',  // or 'line', 'pie', 'scatter', etc.
               data: {
                   labels: ['Label 1', 'Label 2', 'Label 3'],
                   datasets: [{
                       label: 'Dataset Label',
                       data: [12, 19, 3],
                       backgroundColor: [
                           'rgba(255, 99, 132, 0.8)',
                           'rgba(54, 162, 235, 0.8)',
                           'rgba(255, 206, 86, 0.8)'
                       ]
                   }]
               },
               options: {
                   responsive: true,
                   plugins: {
                       title: {
                           display: true,
                           text: 'Chart Title'
                       }
                   }
               }
           });
       </script>
   </body>
   </html>
   ```

4. STORING VISUALIZATIONS

   IMPORTANT: TWO-STEP WORKFLOW FOR ALL VISUALIZATIONS

   ALWAYS cache visualization configs server-side before presenting to the user.
   This ensures the exact config shown to the user is what gets stored later.

   For charts and network graphs:
   1. Generate the Chart.js or network graph config from query results
      IMPORTANT: Use only ASCII characters in labels and data values.
      Replace accented characters with ASCII equivalents (e.g. "Pate chinois"
      not "Pâté chinois", "Rhonbrau" not "Rhönbräu"). Non-ASCII characters
      can cause JSON corruption in the config string.
   2. Call prepare_visualization with the config + type + description
   3. The tool returns a reference ID (e.g. "viz-config-1234-5678")
   4. Present your results to the user
   5. If user says "store it", pass the reference ID as visualizationConfig
      to store_query_visualization — do NOT regenerate the config

   For maps:
   1. Call build_map_visualization with your SPARQL query + styling options
   2. The tool returns a reference ID (e.g. "map-config-1234-5678")
   3. Pass that reference ID to store_query_visualization

   When using reference IDs, visualizationType/description/summary are
   auto-filled from cached data. You only need queryTitle and repository.

   A. FOR CHART.JS VISUALIZATIONS (bar, line, pie, scatter):

   - Set visualizationType appropriately (bar_chart, line_chart, pie_chart, etc.)
   - Store the Chart.js configuration as JSON in visualizationConfig
   - Include data, labels, and all Chart.js options
   - Do NOT store React JSX or component code

   Example visualizationConfig for Chart.js:
   ```json
   {
     "type": "pie",
     "data": {
       "labels": ["USA", "China", "GB"],
       "datasets": [{
         "label": "Medal Count",
         "data": [113, 88, 65],
         "backgroundColor": [
           "rgba(255, 99, 132, 0.8)",
           "rgba(54, 162, 235, 0.8)",
           "rgba(75, 192, 192, 0.8)"
         ]
       }]
     },
     "options": {
       "responsive": true,
       "plugins": {
         "title": {"display": true, "text": "Olympic Medals by Country"}
       }
     }
   }
   ```

   B. FOR NETWORK GRAPHS (RDF RELATIONSHIPS):

   Network graphs visualize RDF relationships as interactive node-link diagrams.
   Use type "network_graph" with a JSON config containing nodes and edges.

   NETWORK GRAPH CONFIG FORMAT:
   ```json
   {
     "type": "network_graph",
     "nodes": [
       {"id": "uri1", "label": "Customer A", "type": "Customer"},
       {"id": "uri2", "label": "Order 123", "type": "Order"},
       {"id": "uri3", "label": "Product X", "type": "Product"}
     ],
     "edges": [
       {"source": "uri1", "target": "uri2", "predicate": "placed"},
       {"source": "uri2", "target": "uri3", "predicate": "contains"}
     ],
     "options": {
       "height": 500,
       "showEdgeLabels": true,
       "linkDistance": 100,
       "chargeStrength": -300
     }
   }
   ```

   NODE PROPERTIES:
   - id (required): Unique identifier (usually the RDF URI)
   - label (required): Display label for the node
   - type (optional): Used for color-coding nodes by class
   - size (optional): Node radius in pixels (default: 15)
   - properties (optional): Object with additional properties shown on hover

   EDGE PROPERTIES:
   - source (required): ID of source node
   - target (required): ID of target node
   - predicate (optional): The RDF predicate label
   - weight (optional): Affects edge thickness (default: 1)

   WHEN TO USE NETWORK GRAPHS:
   - "Show me how X and Y are connected"
   - "Visualize the relationships between customers and orders"
   - "What entities are linked to this product?"
   - Any query about RDF relationships or graph structure

   SPARQL PATTERNS FOR GRAPH DATA:
   Use CONSTRUCT or SELECT queries to extract relationships:
   ```sparql
   SELECT ?subject ?subjectLabel ?predicate ?object ?objectLabel ?subjectType ?objectType
   WHERE {
     ?subject ?predicate ?object .
     ?subject rdfs:label ?subjectLabel .
     ?object rdfs:label ?objectLabel .
     OPTIONAL { ?subject a ?subjectType }
     OPTIONAL { ?object a ?objectType }
   }
   LIMIT 100
   ```

   C. FOR MAP VISUALIZATIONS (GeoSPARQL / Geographic Data):

   Map visualizations display geographic data on interactive Leaflet maps.
   Use type "map" with a GeoJSON FeatureCollection config.

   MAP CONFIG FORMAT:
   ```json
   {
     "type": "map",
     "center": [41.0, 29.0],
     "zoom": 10,
     "data": {
       "type": "FeatureCollection",
       "features": [
         {
           "type": "Feature",
           "geometry": {"type": "Polygon", "coordinates": [[[28.9, 41.0], [29.0, 41.0], [29.0, 41.1], [28.9, 41.1], [28.9, 41.0]]]},
           "properties": {"name": "Fatih", "color": "#D55E00", "type": "District"}
         },
         {
           "type": "Feature",
           "geometry": {"type": "Point", "coordinates": [28.9784, 41.0082]},
           "properties": {"name": "City Center", "radius": 10}
         },
         {
           "type": "Feature",
           "geometry": {"type": "LineString", "coordinates": [[28.9, 41.0], [29.5, 41.1], [30.0, 40.8]]},
           "properties": {"name": "Route A", "color": "red", "weight": 4}
         }
       ]
     },
     "options": {
       "fillOpacity": 0.4,
       "weight": 2,
       "color": "#3388ff"
     }
   }
   ```

   GEOMETRY TYPES SUPPORTED:
   - Point / MultiPoint - rendered as circle markers
   - LineString / MultiLineString - rendered as polylines (routes, paths)
   - Polygon / MultiPolygon - rendered as filled polygons (districts, regions)

   MIXING GEOMETRY TYPES (e.g. routes + districts):
   When showing lines over polygons, control visual hierarchy:
   - Lines: use weight 4-6px and a bright color (e.g. #FF0000)
   - Polygons: use fillOpacity 0.2-0.3 so lines show through
   - Use contrasting colors (red line on blue polygons)
   - Use ORDER BY DESC(?type) in SPARQL so lines render AFTER polygons
     (last features render on top in Leaflet)
   Example SPARQL pattern (use subqueries in UNION for AllegroGraph):
   ```sparql
   SELECT ?name ?featureType ?geojson WHERE {
     {
       SELECT ?name ?featureType ?geojson WHERE {
         ?route a f:Route ; rdfs:label ?name ;
                geo:hasGeometry ?geom .
         ?geom geo:asGeoJSON ?geojson .
         BIND("route" AS ?featureType)
       }
     }
     UNION
     {
       SELECT ?name ?featureType ?geojson WHERE {
         ?district a f:District ; rdfs:label ?name ;
                   geo:hasGeometry ?geom .
         ?geom geo:asGeoJSON ?geojson .
         BIND("district" AS ?featureType)
       }
     }
   } ORDER BY DESC(?featureType)
   ```
   Each UNION branch must be a self-contained subquery — do NOT
   reference variables from outside the UNION branches.
   Then use colorBy: "featureType",
   colorMap: {"route": "#FF0000", "district": "#4A90E2"},
   weight: 5, fillOpacity: 0.25

   FEATURE PROPERTIES FOR STYLING (per feature):
   - name/label/title: Shown in tooltip and popup
   - color: Stroke color (default: #3388ff)
   - fillColor: Fill color for polygons (defaults to color)
   - fillOpacity: Fill transparency 0-1 (default: 0.3)
   - weight: Stroke width in pixels (default: 2)
   - radius: Circle marker radius for points (default: 8)
   - Any other properties are shown in the popup on click

   TOP-LEVEL OPTIONS (defaults for all features):
   - color, fillColor, fillOpacity, weight: Default styles
   - markerRadius: Default point marker radius

   CENTER AND ZOOM:
   - center: [latitude, longitude] for initial map center
   - zoom: Initial zoom level (1=world, 10=city, 15=street)
   - If features are present, the map auto-fits to show all data

   WHEN TO USE MAP VISUALIZATIONS:
   - "Show me the districts on a map"
   - "Plot the route on a map"
   - "Where are the high-risk areas?"
   - Any query returning GeoJSON or WKT geometry data
   - Bounding box queries, point-in-polygon results, route analysis

   SPARQL PATTERN FOR MAP DATA:
   ```sparql
   PREFIX geo: <http://www.opengis.net/ont/geosparql#>
   SELECT ?name ?geojson WHERE {
     ?feature rdfs:label ?name ;
              geo:hasGeometry ?geom .
     ?geom geo:asGeoJSON ?geojson .
   }
   ```

   Then build the FeatureCollection from the results:
   - Each row becomes a Feature
   - The ?geojson column becomes the geometry (parse the JSON string)
   - Other columns become properties (name, type, risk level, etc.)

   REQUIRED: ALWAYS USE build_map_visualization TOOL
   NEVER manually construct map config JSON. ALWAYS use the
   build_map_visualization tool to build map visualizations.
   It runs your SPARQL query server-side and builds the complete
   GeoJSON FeatureCollection without consuming context tokens.
   This ensures ALL features are included regardless of count.

   Two-step workflow:
   1. Call build_map_visualization with your query + styling options
   2. The tool returns a reference ID (e.g. "map-config-1234-5678")
   3. Pass that reference ID as visualizationConfig to
      store_query_visualization with visualizationType "map"

   The geometry data stays server-side — you NEVER need to handle
   or output the raw GeoJSON. Just pass the reference ID string.

   Example: simple map (one query):
   {
     "sparqlQuery": "SELECT ?name ?geojson ?riskLevel WHERE { ... }",
     "geometryColumn": "geojson",
     "nameColumn": "name",
     "colorBy": "riskLevel",
     "colorMap": {"high": "#D55E00", "medium": "#E69F00", "low": "#F0E442"},
     "fillOpacity": 0.4
   }

   Example: route + districts (multiple layers with overlays):
   {
     "sparqlQuery": "SELECT ?name ?geojson WHERE { ?district ... geo:asGeoJSON ?geojson }",
     "geometryColumn": "geojson",
     "nameColumn": "name",
     "defaultColor": "#56B4E9",
     "fillOpacity": 0.25,
     "weight": 2,
     "overlays": [
       {
         "query": "SELECT ?name ?geojson WHERE { ?route ... geo:asGeoJSON ?geojson }",
         "geometryColumn": "geojson",
         "nameColumn": "name",
         "color": "#FF0000",
         "weight": 5
       }
     ]
   }
   Overlays render ON TOP in order — last overlay is topmost.
   Use overlays for lines over polygons, points over polygons, etc.
   Do NOT use SPARQL UNION to combine different geometry types;
   use overlays instead — each layer gets its own query and styling.

   Then store it:
   {
     "queryTitle": "Route through districts",
     "visualizationType": "map",
     "visualizationConfig": "map-config-1234-5678",
     "description": "Map showing route and districts",
     "summary": "..."
   }

   D. FOR LEGACY HTML VISUALIZATIONS:

   For complex visualizations not supported by the built-in renderer,
   you can store complete standalone HTML:

   ✅ MUST INCLUDE:
   - Complete standalone HTML (<!DOCTYPE html>...</html>)
   - All data arrays embedded
   - All D3.js/visualization code
   - Descriptive text and insights

   Example structure for HTML visualization:
   ```html
   <!DOCTYPE html>
   <html>
   <head>
       <title>Visualization Title</title>
       <script src="https://d3js.org/d3.v7.min.js"></script>
   </head>
   <body>
       <h1>Title</h1>
       <div id="viz"></div>
       <script>
           // D3.js code with embedded data
       </script>
   </body>
   </html>
   ```

   PREVIOUS EXAMPLE (for reference):
   ```html
   <!DOCTYPE html>
   <html>
   <head>
       <title>Product Affinity Network</title>
       <script src="https://d3js.org/d3.v7.min.js"></script>
       <style>
           body { font-family: Arial; font-size: 14px; }
           h1 { font-size: 16px; }
           .description { margin: 20px 0; }
           .insights { margin: 20px 0; padding: 15px; background: #f5f5f5; }
       </style>
   </head>
   <body>
       <h1>Product Affinity Network</h1>
       <p class="description">
           This interactive network shows product co-purchase patterns...
           [Full description here]
       </p>
       <div id="network"></div>
       <div class="insights">
           <h2>Key Insights:</h2>
           <ul>
               <li>Most connected products: ...</li>
               <li>Category clustering: ...</li>
               [All insights here]
           </ul>
       </div>
       <script>
           // All D3 code with embedded data
           const nodes = [
               {id: "Product1", category: "Beverages", connections: 5},
               {id: "Product2", category: "Dairy", connections: 8},
               // ... ALL nodes here
           ];
           const links = [
               {source: "Product1", target: "Product2", weight: 5},
               // ... ALL links here
           ];

           // D3 visualization code...
       </script>
   </body>
   </html>
   ```

   WHY THIS MATTERS:
   - The web query browser renders stored HTML directly
   - Missing data means blank/broken visualizations
   - Missing text means lost context and insights
   - Incomplete HTML causes rendering errors

5. WORKFLOW EXAMPLE

   User: "Show me a chart of medal counts by country"

   You:
   1. Execute SPARQL query, show results as table/text
   2. Generate Chart.js config from the results
   3. Call prepare_visualization to cache the config (get reference ID)
   4. Say: "Here's the data. I can store this as a pie chart in the
      Query Library. Would you like me to?"
   5. WAIT for user to say yes
   6. Call store_query with the SPARQL query
   7. Call store_query_visualization with the reference ID
      (visualizationType, description, summary auto-filled from cache)
   8. Say: "Done! View it in the Query Library tab."

   REMEMBER: Always ask and wait for permission before calling store_ tools.

6. COMMON MISTAKES TO AVOID

   ❌ DON'T: Use React component libraries (Recharts, Victory, react-chartjs-2)
   ❌ DON'T: Import React, ReactDOM, or use JSX syntax
   ❌ DON'T: Use npm packages that require build steps
   ❌ DON'T: Create visualizations that need a development server
   ❌ DON'T: Use modules or imports in the artifact

   ✅ DO: Use Chart.js from CDN (https://cdn.jsdelivr.net/npm/chart.js)
   ✅ DO: Create simple HTML with inline JavaScript
   ✅ DO: Embed all data directly in the HTML
   ✅ DO: Use the pattern shown in section 3 above

7. TROUBLESHOOTING

   If a visualization doesn't render:

   Q: Did you use React?
   A: Remove React, use Chart.js instead

   Q: Did you use imports or modules?
   A: Remove imports, load Chart.js from CDN with <script> tag

   Q: Is the canvas element missing an id?
   A: Add id="myChart" to the canvas element

   Q: Did you forget to load Chart.js?
   A: Add <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

8. CRITICAL: LEGENDS AND AXIS LABELS

   ⚠️ EVERY CHART MUST BE SELF-EXPLANATORY WITHOUT READING SURROUNDING TEXT!

   A. AXIS LABELS - ALWAYS REQUIRED:

   For BAR charts (vertical):
   - X-axis: Category names (in data.labels array)
   - Y-axis: Value axis with title (in options.scales.y.title)

   For HORIZONTAL BAR charts:
   - Y-axis: Category names (in data.labels array) - THESE MUST BE VISIBLE!
   - X-axis: Value axis with title (in options.scales.x.title)
   - Set indexAxis: 'y' in options

   HORIZONTAL BAR EXAMPLE (showing rankings with category names):
   ```json
   {
     "type": "bar",
     "data": {
       "labels": ["Persistence", "Privilege Escalation", "Defense Evasion", "Credential Access"],
       "datasets": [{
         "label": "Technique Count",
         "data": [240, 218, 204, 194],
         "backgroundColor": [
           "rgba(255, 99, 132, 0.8)",
           "rgba(255, 159, 64, 0.8)",
           "rgba(255, 205, 86, 0.8)",
           "rgba(75, 192, 192, 0.8)"
         ]
       }]
     },
     "options": {
       "indexAxis": "y",
       "responsive": true,
       "plugins": {
         "title": {"display": true, "text": "MITRE ATT&CK Tactics by Technique Count"},
         "legend": {"display": true, "position": "top"}
       },
       "scales": {
         "x": {
           "title": {"display": true, "text": "Number of Techniques"}
         },
         "y": {
           "title": {"display": true, "text": "Tactic"}
         }
       }
     }
   }
   ```

   B. LEGENDS - WHEN TO USE:

   ✅ ALWAYS show legend for these chart types (no axis labels to identify segments):
   - PIE charts - legend required, position: 'right' or 'bottom'
   - DOUGHNUT charts - legend required, position: 'right' or 'bottom'
   - POLAR AREA charts - legend required, position: 'right' or 'bottom'
   - RADAR charts - legend required when comparing multiple datasets

   Example legend config for pie/doughnut/polar:
   ```json
   "options": {
     "plugins": {
       "legend": {
         "display": true,
         "position": "right"
       }
     }
   }
   ```

   ✅ ALWAYS show legend when:
   - Multiple datasets (e.g., comparing 2020 vs 2021)
   - Different colors represent different categories

   ✅ CAN hide legend when:
   - BAR/LINE charts with single dataset and uniform color
   - Labels on axis already identify the data

   C. COMMON LEGEND MISTAKE:

   ❌ WRONG: Using different colors for each bar but no legend or axis labels
      Result: Pretty colored bars but no one knows what they represent!

   ✅ CORRECT: Either:
      - Same color for all bars + category names on axis, OR
      - Different colors + legend explaining each color, OR
      - Different colors + category names on axis (colors just for visual appeal)

9. CHART TYPE SELECTION GUIDE

   Use BAR charts for:
   - Comparing quantities across categories
   - Showing rankings or counts
   - Use HORIZONTAL bars (indexAxis: 'y') for rankings with long category names

   Use STACKED BAR charts for:
   - Comparing totals AND their components
   - Showing how parts contribute to a whole across categories
   - Set options.scales.x.stacked: true and options.scales.y.stacked: true

   Use LINE charts for:
   - Trends over time
   - Continuous data series

   Use PIE/DOUGHNUT charts for:
   - Parts of a whole (percentages)
   - Distribution across categories
   - When you have 3-8 categories
   - Doughnut is better when you want to show a total in the center

   Use SCATTER charts for:
   - Correlations between two variables
   - Showing relationships in data

   Use BUBBLE charts for:
   - Like scatter, but with a third dimension (size)
   - Data format: [{x: 10, y: 20, r: 5}, ...] where r is bubble radius

   Use RADAR charts for:
   - Multi-dimensional comparisons (5-8 dimensions work best)
   - Comparing profiles across multiple metrics
   - Skills assessments, product comparisons

   Use POLAR AREA charts for:
   - Like pie, but area represents value (not angle)
   - Good for cyclic data (hours, months)

   Use NETWORK GRAPH for:
   - RDF relationship visualization
   - Showing connections between entities
   - "How are X and Y related?" questions
   - Graph traversal patterns
   - Best for 10-100 nodes (too many becomes unreadable)
   - Use D3.js force-directed layout, NOT React

   Use MAP for:
   - Geographic/GeoSPARQL data (districts, routes, points of interest)
   - Queries returning GeoJSON or WKT geometry columns
   - Route visualization, bounding box queries, spatial analysis
   - Risk areas overlaid on geographic regions
   - Any "show me on a map" or "where is..." question

10. CHART.JS RESOURCES

   Documentation: https://www.chartjs.org/docs/latest/
   CDN: https://cdn.jsdelivr.net/npm/chart.js
   Examples: https://www.chartjs.org/docs/latest/samples/

================================================================================
REMEMBER THE THREE RULES:
1. No HTML/canvas/Chart.js code in responses
2. Always ASK before storing
3. Only store AFTER user says yes
================================================================================
