@quarri/claude-data-tools 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/quarri-chart/SKILL.md +275 -316
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Generate
|
|
2
|
+
description: Generate interactive Plotly charts and open them in the browser
|
|
3
3
|
globs:
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# /quarri-chart -
|
|
7
|
+
# /quarri-chart - Interactive Chart Generation
|
|
8
8
|
|
|
9
|
-
Generate data visualizations
|
|
9
|
+
Generate data visualizations as interactive HTML files and open them in the default browser.
|
|
10
10
|
|
|
11
11
|
## When to Use
|
|
12
12
|
|
|
@@ -14,73 +14,71 @@ Use `/quarri-chart` when users want visualizations:
|
|
|
14
14
|
- "Create a chart of revenue by month"
|
|
15
15
|
- "Visualize customer distribution"
|
|
16
16
|
- "Show me a graph of this data"
|
|
17
|
-
- "
|
|
17
|
+
- "Chart sales by category"
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## Primary Workflow (DEFAULT)
|
|
20
20
|
|
|
21
|
-
### 1
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
https://quickchart.io/chart?c={encoded_config}
|
|
21
|
+
### Step 1: Query the data
|
|
22
|
+
```sql
|
|
23
|
+
SELECT category, SUM(sales) as total_sales
|
|
24
|
+
FROM orders
|
|
25
|
+
GROUP BY category
|
|
26
|
+
ORDER BY total_sales DESC
|
|
29
27
|
```
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
29
|
+
### Step 2: Generate HTML with Plotly
|
|
30
|
+
Write an HTML file to `/tmp/quarri_chart.html`:
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<!DOCTYPE html>
|
|
34
|
+
<html>
|
|
35
|
+
<head>
|
|
36
|
+
<title>[Chart Title]</title>
|
|
37
|
+
<script src="https://cdn.plot.ly/plotly-2.27.0.min.js"></script>
|
|
38
|
+
<style>
|
|
39
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 40px; background: #f5f5f5; }
|
|
40
|
+
h1 { color: #1a1a2e; text-align: center; margin-bottom: 10px; }
|
|
41
|
+
.subtitle { color: #666; text-align: center; margin-bottom: 30px; }
|
|
42
|
+
#chart { width: 100%; max-width: 900px; margin: 0 auto; background: white; border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); padding: 20px; }
|
|
43
|
+
</style>
|
|
44
|
+
</head>
|
|
45
|
+
<body>
|
|
46
|
+
<h1>[Chart Title]</h1>
|
|
47
|
+
<p class="subtitle">Data from [database_name]</p>
|
|
48
|
+
<div id="chart"></div>
|
|
49
|
+
<script>
|
|
50
|
+
var data = [{
|
|
51
|
+
x: [/* labels */],
|
|
52
|
+
y: [/* values */],
|
|
53
|
+
type: 'bar',
|
|
54
|
+
marker: { color: '#4F46E5' }
|
|
55
|
+
}];
|
|
56
|
+
|
|
57
|
+
var layout = {
|
|
58
|
+
title: '',
|
|
59
|
+
xaxis: { title: '[X Label]' },
|
|
60
|
+
yaxis: { title: '[Y Label]', tickformat: '$,.0f' },
|
|
61
|
+
margin: { t: 40, b: 60, l: 80, r: 40 }
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
var config = { responsive: true, displayModeBar: true };
|
|
65
|
+
Plotly.newPlot('chart', data, layout, config);
|
|
66
|
+
</script>
|
|
67
|
+
</body>
|
|
68
|
+
</html>
|
|
65
69
|
```
|
|
66
70
|
|
|
67
|
-
### 3
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
**When to use**: Terminal environments, quick data review, no graphics support
|
|
72
|
-
|
|
71
|
+
### Step 3: Open in browser
|
|
72
|
+
```bash
|
|
73
|
+
open /tmp/quarri_chart.html
|
|
73
74
|
```
|
|
74
|
-
Revenue by Quarter
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
0 100 200
|
|
81
|
-
```
|
|
76
|
+
On different platforms:
|
|
77
|
+
- **macOS**: `open /tmp/quarri_chart.html`
|
|
78
|
+
- **Linux**: `xdg-open /tmp/quarri_chart.html`
|
|
79
|
+
- **Windows**: `start /tmp/quarri_chart.html`
|
|
82
80
|
|
|
83
|
-
## Chart Selection
|
|
81
|
+
## Chart Type Selection
|
|
84
82
|
|
|
85
83
|
### Decision Tree
|
|
86
84
|
|
|
@@ -96,315 +94,276 @@ START: What is the primary analysis goal?
|
|
|
96
94
|
└─→ 2-7 categories → VERTICAL BAR
|
|
97
95
|
└─→ 8-15 categories → HORIZONTAL BAR
|
|
98
96
|
└─→ 15+ categories → TOP N + "Other"
|
|
99
|
-
└─→ Multiple dimensions → GROUPED BAR
|
|
100
97
|
|
|
101
98
|
3. SHOWING DISTRIBUTION?
|
|
102
99
|
└─→ Continuous data → HISTOGRAM
|
|
103
100
|
└─→ Categorical → BAR (sorted)
|
|
104
|
-
└─→ Compare groups → BOX PLOT
|
|
105
101
|
|
|
106
102
|
4. PARTS OF A WHOLE?
|
|
107
103
|
└─→ 2-6 parts → PIE/DONUT
|
|
108
|
-
└─→ 7+ parts → STACKED BAR
|
|
104
|
+
└─→ 7+ parts → STACKED BAR
|
|
109
105
|
|
|
110
106
|
5. RELATIONSHIP BETWEEN VARIABLES?
|
|
111
107
|
└─→ Two numeric → SCATTER PLOT
|
|
112
|
-
└─→ With grouping → SCATTER with colors
|
|
113
|
-
|
|
114
|
-
DEFAULT: TABLE (when visualization unclear)
|
|
115
108
|
```
|
|
116
109
|
|
|
117
|
-
##
|
|
110
|
+
## Plotly Templates
|
|
118
111
|
|
|
119
112
|
### Bar Chart
|
|
120
113
|
```javascript
|
|
121
|
-
{
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
114
|
+
var data = [{
|
|
115
|
+
x: ['Category A', 'Category B', 'Category C'],
|
|
116
|
+
y: [450000, 380000, 290000],
|
|
117
|
+
type: 'bar',
|
|
118
|
+
marker: {
|
|
119
|
+
color: ['#4F46E5', '#7C3AED', '#A78BFA']
|
|
120
|
+
},
|
|
121
|
+
text: ['$450K', '$380K', '$290K'],
|
|
122
|
+
textposition: 'auto'
|
|
123
|
+
}];
|
|
124
|
+
|
|
125
|
+
var layout = {
|
|
126
|
+
title: 'Sales by Category',
|
|
127
|
+
xaxis: { title: 'Category' },
|
|
128
|
+
yaxis: { title: 'Sales ($)', tickformat: '$,.0f' }
|
|
129
|
+
};
|
|
136
130
|
```
|
|
137
131
|
|
|
138
|
-
###
|
|
132
|
+
### Horizontal Bar (many categories)
|
|
139
133
|
```javascript
|
|
140
|
-
{
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
134
|
+
var data = [{
|
|
135
|
+
y: ['Product A', 'Product B', 'Product C', 'Product D', 'Product E'],
|
|
136
|
+
x: [85000, 72000, 65000, 58000, 45000],
|
|
137
|
+
type: 'bar',
|
|
138
|
+
orientation: 'h',
|
|
139
|
+
marker: { color: '#4F46E5' }
|
|
140
|
+
}];
|
|
141
|
+
|
|
142
|
+
var layout = {
|
|
143
|
+
title: 'Top Products by Revenue',
|
|
144
|
+
xaxis: { title: 'Revenue ($)', tickformat: '$,.0f' },
|
|
145
|
+
margin: { l: 120 }
|
|
146
|
+
};
|
|
152
147
|
```
|
|
153
148
|
|
|
154
|
-
###
|
|
149
|
+
### Line Chart (time series)
|
|
155
150
|
```javascript
|
|
156
|
-
{
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
151
|
+
var data = [{
|
|
152
|
+
x: ['2024-01', '2024-02', '2024-03', '2024-04', '2024-05', '2024-06'],
|
|
153
|
+
y: [120000, 135000, 128000, 145000, 160000, 175000],
|
|
154
|
+
type: 'scatter',
|
|
155
|
+
mode: 'lines+markers',
|
|
156
|
+
line: { color: '#4F46E5', width: 3 },
|
|
157
|
+
marker: { size: 8 }
|
|
158
|
+
}];
|
|
159
|
+
|
|
160
|
+
var layout = {
|
|
161
|
+
title: 'Monthly Revenue Trend',
|
|
162
|
+
xaxis: { title: 'Month' },
|
|
163
|
+
yaxis: { title: 'Revenue ($)', tickformat: '$,.0f' }
|
|
164
|
+
};
|
|
166
165
|
```
|
|
167
166
|
|
|
168
|
-
###
|
|
167
|
+
### Multi-Line Chart
|
|
169
168
|
```javascript
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
|
|
169
|
+
var data = [
|
|
170
|
+
{
|
|
171
|
+
x: ['Jan', 'Feb', 'Mar', 'Apr'],
|
|
172
|
+
y: [100, 120, 115, 140],
|
|
173
|
+
name: 'Product A',
|
|
174
|
+
type: 'scatter',
|
|
175
|
+
mode: 'lines+markers'
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
x: ['Jan', 'Feb', 'Mar', 'Apr'],
|
|
179
|
+
y: [80, 95, 110, 120],
|
|
180
|
+
name: 'Product B',
|
|
181
|
+
type: 'scatter',
|
|
182
|
+
mode: 'lines+markers'
|
|
183
|
+
}
|
|
184
|
+
];
|
|
185
|
+
|
|
186
|
+
var layout = {
|
|
187
|
+
title: 'Product Comparison',
|
|
188
|
+
xaxis: { title: 'Month' },
|
|
189
|
+
yaxis: { title: 'Sales' }
|
|
190
|
+
};
|
|
180
191
|
```
|
|
181
192
|
|
|
182
|
-
###
|
|
193
|
+
### Pie/Donut Chart
|
|
183
194
|
```javascript
|
|
184
|
-
{
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
}
|
|
195
|
+
var data = [{
|
|
196
|
+
labels: ['Technology', 'Furniture', 'Office Supplies'],
|
|
197
|
+
values: [5471124, 4730801, 4144724],
|
|
198
|
+
type: 'pie',
|
|
199
|
+
hole: 0.4, // Remove for regular pie
|
|
200
|
+
marker: {
|
|
201
|
+
colors: ['#4F46E5', '#10B981', '#F59E0B']
|
|
202
|
+
},
|
|
203
|
+
textinfo: 'label+percent'
|
|
204
|
+
}];
|
|
205
|
+
|
|
206
|
+
var layout = {
|
|
207
|
+
title: 'Sales Distribution by Category'
|
|
208
|
+
};
|
|
194
209
|
```
|
|
195
210
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
plt.savefig('bar_chart.png', dpi=150)
|
|
211
|
+
### Scatter Plot
|
|
212
|
+
```javascript
|
|
213
|
+
var data = [{
|
|
214
|
+
x: [/* x values */],
|
|
215
|
+
y: [/* y values */],
|
|
216
|
+
mode: 'markers',
|
|
217
|
+
type: 'scatter',
|
|
218
|
+
marker: {
|
|
219
|
+
size: 10,
|
|
220
|
+
color: '#4F46E5',
|
|
221
|
+
opacity: 0.7
|
|
222
|
+
}
|
|
223
|
+
}];
|
|
224
|
+
|
|
225
|
+
var layout = {
|
|
226
|
+
title: 'Correlation Analysis',
|
|
227
|
+
xaxis: { title: 'Variable X' },
|
|
228
|
+
yaxis: { title: 'Variable Y' }
|
|
229
|
+
};
|
|
216
230
|
```
|
|
217
231
|
|
|
218
|
-
###
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
232
|
+
### Grouped Bar Chart
|
|
233
|
+
```javascript
|
|
234
|
+
var data = [
|
|
235
|
+
{
|
|
236
|
+
x: ['Q1', 'Q2', 'Q3', 'Q4'],
|
|
237
|
+
y: [120, 150, 180, 200],
|
|
238
|
+
name: '2023',
|
|
239
|
+
type: 'bar'
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
x: ['Q1', 'Q2', 'Q3', 'Q4'],
|
|
243
|
+
y: [140, 165, 195, 220],
|
|
244
|
+
name: '2024',
|
|
245
|
+
type: 'bar'
|
|
246
|
+
}
|
|
247
|
+
];
|
|
248
|
+
|
|
249
|
+
var layout = {
|
|
250
|
+
title: 'Year over Year Comparison',
|
|
251
|
+
barmode: 'group'
|
|
252
|
+
};
|
|
238
253
|
```
|
|
239
254
|
|
|
240
|
-
|
|
241
|
-
```python
|
|
242
|
-
import matplotlib.pyplot as plt
|
|
243
|
-
|
|
244
|
-
fig, ax = plt.subplots(figsize=(10, 8))
|
|
245
|
-
categories = ['Product A', 'Product B', 'Product C', 'Product D', 'Product E']
|
|
246
|
-
values = [45, 38, 32, 28, 22]
|
|
247
|
-
|
|
248
|
-
bars = ax.barh(categories, values, color='#4F46E5')
|
|
249
|
-
ax.bar_label(bars, fmt='%.0f', padding=5)
|
|
255
|
+
## Color Palettes
|
|
250
256
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
ax.spines['top'].set_visible(False)
|
|
255
|
-
ax.spines['right'].set_visible(False)
|
|
257
|
+
```javascript
|
|
258
|
+
// Primary (single series)
|
|
259
|
+
const PRIMARY = '#4F46E5';
|
|
256
260
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
```
|
|
261
|
+
// Categorical (multiple series)
|
|
262
|
+
const CATEGORICAL = ['#4F46E5', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6', '#EC4899', '#06B6D4', '#84CC16'];
|
|
260
263
|
|
|
261
|
-
|
|
264
|
+
// Sequential (gradient)
|
|
265
|
+
const SEQUENTIAL = ['#E0E7FF', '#A5B4FC', '#818CF8', '#6366F1', '#4F46E5', '#4338CA', '#3730A3'];
|
|
262
266
|
|
|
263
|
-
|
|
267
|
+
// Diverging (positive/negative)
|
|
268
|
+
const DIVERGING_NEG = '#EF4444';
|
|
269
|
+
const DIVERGING_POS = '#10B981';
|
|
264
270
|
```
|
|
265
|
-
def ascii_bar_chart(data, title, max_width=40):
|
|
266
|
-
"""Generate ASCII horizontal bar chart"""
|
|
267
|
-
print(f"\n{title}\n")
|
|
268
|
-
max_val = max(data.values())
|
|
269
271
|
|
|
270
|
-
|
|
271
|
-
bar_len = int((value / max_val) * max_width)
|
|
272
|
-
bar = '█' * bar_len
|
|
273
|
-
print(f"{label:>15} |{bar} {value:,.0f}")
|
|
272
|
+
## Number Formatting
|
|
274
273
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
```
|
|
274
|
+
```javascript
|
|
275
|
+
// Currency
|
|
276
|
+
tickformat: '$,.0f' // $1,234,567
|
|
277
|
+
tickformat: '$,.2f' // $1,234,567.89
|
|
278
|
+
tickformat: '$~s' // $1.2M
|
|
281
279
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
Revenue by Category
|
|
280
|
+
// Percentages
|
|
281
|
+
tickformat: '.1%' // 45.2%
|
|
285
282
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
Home |████████████████████████ 28,000
|
|
289
|
-
────────────────────────────────────────
|
|
283
|
+
// Large numbers
|
|
284
|
+
tickformat: '~s' // 1.2M, 3.4K
|
|
290
285
|
```
|
|
291
286
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
287
|
+
## Complete Example
|
|
288
|
+
|
|
289
|
+
For "Show me sales by category":
|
|
290
|
+
|
|
291
|
+
```html
|
|
292
|
+
<!DOCTYPE html>
|
|
293
|
+
<html>
|
|
294
|
+
<head>
|
|
295
|
+
<title>Sales by Category</title>
|
|
296
|
+
<script src="https://cdn.plot.ly/plotly-2.27.0.min.js"></script>
|
|
297
|
+
<style>
|
|
298
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 40px; background: #f5f5f5; }
|
|
299
|
+
h1 { color: #1a1a2e; text-align: center; margin-bottom: 10px; }
|
|
300
|
+
.subtitle { color: #666; text-align: center; margin-bottom: 30px; font-size: 14px; }
|
|
301
|
+
#chart { width: 100%; max-width: 900px; margin: 0 auto; background: white; border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); padding: 20px; }
|
|
302
|
+
</style>
|
|
303
|
+
</head>
|
|
304
|
+
<body>
|
|
305
|
+
<h1>Superstore Sales by Category</h1>
|
|
306
|
+
<p class="subtitle">Total: $14.3M across 51,290 orders</p>
|
|
307
|
+
<div id="chart"></div>
|
|
308
|
+
<script>
|
|
309
|
+
var data = [{
|
|
310
|
+
x: ['Technology', 'Furniture', 'Office Supplies'],
|
|
311
|
+
y: [5471124.24, 4730801.23, 4144724.04],
|
|
312
|
+
type: 'bar',
|
|
313
|
+
marker: {
|
|
314
|
+
color: ['#4F46E5', '#7C3AED', '#A78BFA']
|
|
315
|
+
},
|
|
316
|
+
text: ['$5.47M', '$4.73M', '$4.14M'],
|
|
317
|
+
textposition: 'outside',
|
|
318
|
+
textfont: { size: 14, color: '#374151' }
|
|
319
|
+
}];
|
|
320
|
+
|
|
321
|
+
var layout = {
|
|
322
|
+
xaxis: { title: 'Category', tickfont: { size: 12 } },
|
|
323
|
+
yaxis: {
|
|
324
|
+
title: 'Sales ($)',
|
|
325
|
+
tickformat: '$,.0f',
|
|
326
|
+
tickfont: { size: 11 }
|
|
327
|
+
},
|
|
328
|
+
margin: { t: 40, b: 80, l: 100, r: 40 },
|
|
329
|
+
plot_bgcolor: 'white',
|
|
330
|
+
paper_bgcolor: 'white'
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
var config = {
|
|
334
|
+
responsive: true,
|
|
335
|
+
displayModeBar: true,
|
|
336
|
+
modeBarButtonsToRemove: ['lasso2d', 'select2d']
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
Plotly.newPlot('chart', data, layout, config);
|
|
340
|
+
</script>
|
|
341
|
+
</body>
|
|
342
|
+
</html>
|
|
313
343
|
```
|
|
314
344
|
|
|
315
|
-
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
"""Generate inline ASCII sparkline"""
|
|
319
|
-
chars = '▁▂▃▄▅▆▇█'
|
|
320
|
-
min_val, max_val = min(values), max(values)
|
|
321
|
-
range_val = max_val - min_val or 1
|
|
322
|
-
|
|
323
|
-
line = ""
|
|
324
|
-
for v in values:
|
|
325
|
-
idx = int((v - min_val) / range_val * (len(chars) - 1))
|
|
326
|
-
line += chars[idx]
|
|
327
|
-
|
|
328
|
-
return f"[{line}] {values[0]:,.0f} → {values[-1]:,.0f}"
|
|
329
|
-
|
|
330
|
-
# Example
|
|
331
|
-
monthly = [100, 105, 98, 112, 120, 118, 125, 130, 128, 140, 145, 155]
|
|
332
|
-
print(f"Revenue trend: {ascii_sparkline(monthly)}")
|
|
333
|
-
# Output: Revenue trend: [▁▂▁▃▄▄▅▆▅▇▇█] 100 → 155
|
|
345
|
+
Then run:
|
|
346
|
+
```bash
|
|
347
|
+
open /tmp/quarri_chart.html
|
|
334
348
|
```
|
|
335
349
|
|
|
336
|
-
##
|
|
337
|
-
|
|
338
|
-
1. **Analyze data shape**:
|
|
339
|
-
- Count rows and columns
|
|
340
|
-
- Identify column types (numeric, categorical, date)
|
|
341
|
-
- Check value distributions
|
|
342
|
-
|
|
343
|
-
2. **Determine visualization goal**:
|
|
344
|
-
- Parse user question for intent
|
|
345
|
-
- Consider data characteristics
|
|
350
|
+
## Alternative Outputs
|
|
346
351
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
- Consider data density and readability
|
|
350
|
-
|
|
351
|
-
4. **Choose output format**:
|
|
352
|
-
- Default: QuickChart URL (instant rendering)
|
|
353
|
-
- If user needs customization: matplotlib code
|
|
354
|
-
- If terminal-only: ASCII chart
|
|
355
|
-
|
|
356
|
-
5. **Generate and present**:
|
|
357
|
-
- Show chart or URL
|
|
358
|
-
- Include rationale
|
|
359
|
-
- Suggest alternatives
|
|
360
|
-
|
|
361
|
-
## Output Format
|
|
362
|
-
|
|
363
|
-
```markdown
|
|
364
|
-
## Visualization: [Data Description]
|
|
365
|
-
|
|
366
|
-
### Analysis
|
|
367
|
-
- Data: [rows] rows, [columns] columns
|
|
368
|
-
- Question type: [trend/comparison/distribution/etc.]
|
|
369
|
-
- Key columns: [list]
|
|
370
|
-
|
|
371
|
-
### Recommended Chart: [Type]
|
|
372
|
-
**Why**: [Brief rationale]
|
|
373
|
-
|
|
374
|
-
### Chart
|
|
375
|
-
|
|
376
|
-
**QuickChart URL** (click to view):
|
|
377
|
-
[URL]
|
|
378
|
-
|
|
379
|
-
**Alternative: Matplotlib Code**
|
|
380
|
-
```python
|
|
381
|
-
[Code block]
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
**Alternative: ASCII Preview**
|
|
352
|
+
### QuickChart URL (for sharing/embedding)
|
|
353
|
+
When user specifically needs a URL:
|
|
385
354
|
```
|
|
386
|
-
[
|
|
355
|
+
https://quickchart.io/chart?c={type:'bar',data:{labels:['A','B','C'],datasets:[{data:[10,20,15]}]}}
|
|
387
356
|
```
|
|
388
357
|
|
|
389
|
-
###
|
|
390
|
-
|
|
391
|
-
- [Alternative chart 2]: [When it might be better]
|
|
358
|
+
### ASCII Chart (terminal only)
|
|
359
|
+
When user is in a terminal-only environment:
|
|
392
360
|
```
|
|
361
|
+
Sales by Category
|
|
393
362
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
PRIMARY = '#4F46E5' # Indigo
|
|
399
|
-
|
|
400
|
-
# Categorical (multiple series)
|
|
401
|
-
CATEGORICAL = ['#4F46E5', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6', '#EC4899']
|
|
402
|
-
|
|
403
|
-
# Sequential (single metric, gradient)
|
|
404
|
-
SEQUENTIAL = ['#E0E7FF', '#A5B4FC', '#818CF8', '#6366F1', '#4F46E5']
|
|
405
|
-
|
|
406
|
-
# Diverging (positive/negative)
|
|
407
|
-
DIVERGING = ['#EF4444', '#FCA5A5', '#E5E7EB', '#86EFAC', '#22C55E']
|
|
363
|
+
Technology |████████████████████████████████████████ $5.47M
|
|
364
|
+
Furniture |██████████████████████████████████ $4.73M
|
|
365
|
+
Office Supplies |██████████████████████████████ $4.14M
|
|
366
|
+
0 $3M $6M
|
|
408
367
|
```
|
|
409
368
|
|
|
410
369
|
## Integration
|