Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Data Explorer - Grammar of Graphics</title> | |
| <script src="https://cdn.jsdelivr.net/npm/vega@5"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vega-lite@5"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/papaparse@5.3.0/papaparse.min.js"></script> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary: #1a73e8; | |
| --primary-light: #e8f0fe; | |
| --secondary: #f1f3f4; | |
| --text: #202124; | |
| --text-light: #5f6368; | |
| --border: #dadce0; | |
| --white: #ffffff; | |
| --success: #34a853; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| body { | |
| font-family: 'Inter', sans-serif; | |
| color: var(--text); | |
| background-color: #f8f9fa; | |
| line-height: 1.6; | |
| padding: 0; | |
| margin: 0; | |
| min-height: 100vh; | |
| } | |
| .container { | |
| display: flex; | |
| flex-direction: column; | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| gap: 20px; | |
| } | |
| header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 15px 0; | |
| border-bottom: 1px solid var(--border); | |
| margin-bottom: 20px; | |
| } | |
| .logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .logo i { | |
| color: var(--primary); | |
| font-size: 24px; | |
| } | |
| .logo h1 { | |
| font-size: 20px; | |
| font-weight: 600; | |
| } | |
| .upload-area { | |
| background-color: var(--white); | |
| border-radius: 8px; | |
| padding: 20px; | |
| box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); | |
| margin-bottom: 20px; | |
| } | |
| .upload-container { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| padding: 30px; | |
| border: 2px dashed var(--border); | |
| border-radius: 6px; | |
| background-color: var(--primary-light); | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| .upload-container:hover { | |
| background-color: rgba(26, 115, 232, 0.1); | |
| border-color: var(--primary); | |
| } | |
| .upload-icon { | |
| font-size: 36px; | |
| color: var(--primary); | |
| margin-bottom: 10px; | |
| } | |
| .upload-text { | |
| color: var(--text-light); | |
| margin-bottom: 15px; | |
| text-align: center; | |
| } | |
| .btn { | |
| background-color: var(--primary); | |
| color: white; | |
| border: none; | |
| padding: 8px 16px; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-weight: 500; | |
| font-size: 14px; | |
| transition: background-color 0.2s; | |
| } | |
| .btn:hover { | |
| background-color: #1557b0; | |
| } | |
| .btn-outline { | |
| background-color: transparent; | |
| color: var(--primary); | |
| border: 1px solid var(--primary); | |
| } | |
| .btn-outline:hover { | |
| background-color: var(--primary-light); | |
| } | |
| .btn-group { | |
| display: flex; | |
| gap: 10px; | |
| } | |
| input[type="file"] { | |
| display: none; | |
| } | |
| .main-content { | |
| display: flex; | |
| gap: 20px; | |
| } | |
| .sidebar { | |
| width: 300px; | |
| background-color: var(--white); | |
| border-radius: 8px; | |
| padding: 15px; | |
| box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); | |
| display: flex; | |
| flex-direction: column; | |
| gap: 20px; | |
| } | |
| .panel { | |
| background-color: var(--white); | |
| border-radius: 8px; | |
| padding: 15px; | |
| box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); | |
| } | |
| .panel-title { | |
| font-size: 16px; | |
| font-weight: 600; | |
| margin-bottom: 15px; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .panel-title i { | |
| color: var(--text-light); | |
| } | |
| .control-group { | |
| margin-bottom: 15px; | |
| } | |
| .control-label { | |
| display: block; | |
| font-size: 14px; | |
| color: var(--text-light); | |
| margin-bottom: 5px; | |
| font-weight: 500; | |
| } | |
| select, input { | |
| width: 100%; | |
| padding: 8px 12px; | |
| border: 1px solid var(--border); | |
| border-radius: 4px; | |
| font-family: inherit; | |
| font-size: 14px; | |
| background-color: var(--white); | |
| } | |
| select { | |
| cursor: pointer; | |
| } | |
| .color-option { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| margin-bottom: 5px; | |
| cursor: pointer; | |
| } | |
| .color-preview { | |
| width: 16px; | |
| height: 16px; | |
| border-radius: 3px; | |
| border: 1px solid var(--border); | |
| } | |
| .visualization { | |
| flex: 1; | |
| background-color: var(--white); | |
| border-radius: 8px; | |
| padding: 15px; | |
| box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); | |
| } | |
| #chart { | |
| width: 100%; | |
| min-height: 500px; | |
| } | |
| .hidden { | |
| display: none; | |
| } | |
| .data-preview { | |
| margin-top: 20px; | |
| max-height: 200px; | |
| overflow-y: auto; | |
| border: 1px solid var(--border); | |
| border-radius: 4px; | |
| } | |
| table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| font-size: 13px; | |
| } | |
| th, td { | |
| padding: 8px 12px; | |
| text-align: left; | |
| border-bottom: 1px solid var(--border); | |
| } | |
| th { | |
| background-color: var(--secondary); | |
| font-weight: 500; | |
| color: var(--text-light); | |
| position: sticky; | |
| top: 0; | |
| } | |
| tr:hover { | |
| background-color: #f5f5f5; | |
| } | |
| .success-message { | |
| background-color: #e6f4ea; | |
| color: var(--success); | |
| padding: 10px 15px; | |
| border-radius: 4px; | |
| font-size: 14px; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| margin-top: 10px; | |
| } | |
| .success-message i { | |
| font-size: 16px; | |
| } | |
| .tabs { | |
| display: flex; | |
| border-bottom: 1px solid var(--border); | |
| margin-bottom: 15px; | |
| } | |
| .tab { | |
| padding: 8px 16px; | |
| cursor: pointer; | |
| font-size: 14px; | |
| font-weight: 500; | |
| color: var(--text-light); | |
| position: relative; | |
| } | |
| .tab.active { | |
| color: var(--primary); | |
| } | |
| .tab.active:after { | |
| content: ''; | |
| position: absolute; | |
| bottom: -1px; | |
| left: 0; | |
| right: 0; | |
| height: 2px; | |
| background-color: var(--primary); | |
| } | |
| .tab-content { | |
| display: none; | |
| } | |
| .tab-content.active { | |
| display: block; | |
| } | |
| .field-list { | |
| list-style: none; | |
| margin: 0; | |
| padding: 0; | |
| max-height: 200px; | |
| overflow-y: auto; | |
| border: 1px solid var(--border); | |
| border-radius: 4px; | |
| } | |
| .field-item { | |
| padding: 8px 12px; | |
| border-bottom: 1px solid var(--border); | |
| cursor: grab; | |
| font-size: 13px; | |
| } | |
| .field-item:hover { | |
| background-color: var(--secondary); | |
| } | |
| .field-item.dragging { | |
| opacity: 0.5; | |
| } | |
| .drop-area { | |
| border: 2px dashed var(--border); | |
| padding: 15px; | |
| border-radius: 4px; | |
| min-height: 50px; | |
| margin-bottom: 15px; | |
| background-color: var(--primary-light); | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 8px; | |
| } | |
| .drop-area.highlight { | |
| border-color: var(--primary); | |
| background-color: rgba(26, 115, 232, 0.1); | |
| } | |
| .pill { | |
| background-color: var(--primary); | |
| color: white; | |
| padding: 4px 8px; | |
| border-radius: 12px; | |
| font-size: 12px; | |
| display: flex; | |
| align-items: center; | |
| gap: 4px; | |
| } | |
| .pill i { | |
| cursor: pointer; | |
| font-size: 12px; | |
| } | |
| footer { | |
| text-align: center; | |
| padding: 15px 0; | |
| color: var(--text-light); | |
| font-size: 13px; | |
| margin-top: 30px; | |
| border-top: 1px solid var(--border); | |
| } | |
| @media (max-width: 768px) { | |
| .main-content { | |
| flex-direction: column; | |
| } | |
| .sidebar { | |
| width: 100%; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header> | |
| <div class="logo"> | |
| <i class="fas fa-chart-bar"></i> | |
| <h1>Grammar of Graphics Explorer</h1> | |
| </div> | |
| <div class="btn-group"> | |
| <button id="reset-btn" class="btn btn-outline"> | |
| <i class="fas fa-redo"></i> Reset | |
| </button> | |
| </div> | |
| </header> | |
| <div id="upload-section" class="upload-area"> | |
| <div class="upload-container" id="upload-container"> | |
| <i class="fas fa-cloud-upload-alt upload-icon"></i> | |
| <p class="upload-text">Drag & drop your CSV file here or click to browse</p> | |
| <button class="btn"> | |
| <i class="fas fa-file-import"></i> Select File | |
| </button> | |
| <input type="file" id="fileInput" accept=".csv"> | |
| </div> | |
| <div id="upload-success" class="success-message hidden"> | |
| <i class="fas fa-check-circle"></i> | |
| <span id="success-message-text">File uploaded successfully!</span> | |
| </div> | |
| <div id="data-preview" class="data-preview hidden"> | |
| <table> | |
| <thead id="preview-head"> | |
| <tr></tr> | |
| </thead> | |
| <tbody id="preview-body"> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <div id="explorer-section" class="hidden"> | |
| <div class="main-content"> | |
| <div class="sidebar"> | |
| <div class="panel"> | |
| <div class="panel-title"> | |
| <i class="fas fa-sliders-h"></i> | |
| <span>Visual Encoding</span> | |
| </div> | |
| <div class="tabs"> | |
| <div class="tab active" data-tab="encodings">Encodings</div> | |
| <div class="tab" data-tab="transformations">Transformations</div> | |
| </div> | |
| <div class="tab-content active" id="encodings-tab"> | |
| <div class="control-group"> | |
| <label class="control-label">X-Axis</label> | |
| <div class="drop-area" id="x-drop-area"></div> | |
| <select id="x-axis" disabled> | |
| <option value="">Select field</option> | |
| </select> | |
| </div> | |
| <div class="control-group"> | |
| <label class="control-label">Y-Axis</label> | |
| <div class="drop-area" id="y-drop-area"></div> | |
| <select id="y-axis" disabled> | |
| <option value="">Select field</option> | |
| </select> | |
| </div> | |
| <div class="control-group"> | |
| <label class="control-label">Color</label> | |
| <div class="drop-area" id="color-drop-area"></div> | |
| <select id="color" disabled> | |
| <option value="">Select field</option> | |
| </select> | |
| </div> | |
| <div class="control-group"> | |
| <label class="control-label">Size</label> | |
| <div class="drop-area" id="size-drop-area"></div> | |
| <select id="size" disabled> | |
| <option value="">Select field</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="tab-content" id="transformations-tab"> | |
| <div class="control-group"> | |
| <label class="control-label">Mark Type</label> | |
| <select id="mark-type"> | |
| <option value="point">Point</option> | |
| <option value="bar">Bar</option> | |
| <option value="line">Line</option> | |
| <option value="area">Area</option> | |
| <option value="circle">Circle</option> | |
| <option value="square">Square</option> | |
| <option value="text">Text</option> | |
| </select> | |
| </div> | |
| <div class="control-group"> | |
| <label class="control-label">Aggregation</label> | |
| <select id="aggregation"> | |
| <option value="none">None</option> | |
| <option value="mean">Mean</option> | |
| <option value="sum">Sum</option> | |
| <option value="median">Median</option> | |
| <option value="min">Min</option> | |
| <option value="max">Max</option> | |
| <option value="count">Count</option> | |
| </select> | |
| </div> | |
| <div class="control-group"> | |
| <label class="control-label">Sort</label> | |
| <select id="sort"> | |
| <option value="none">None</option> | |
| <option value="asc">Ascending</option> | |
| <option value="desc">Descending</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="panel"> | |
| <div class="panel-title"> | |
| <i class="fas fa-list"></i> | |
| <span>Data Fields</span> | |
| </div> | |
| <ul class="field-list" id="field-list"></ul> | |
| </div> | |
| </div> | |
| <div class="visualization"> | |
| <div id="chart"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <footer> | |
| Grammar of Graphics Explorer | Built with Vega-Lite | |
| </footer> | |
| </div> | |
| <script> | |