@quarri/claude-data-tools 1.0.2 → 1.1.0
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/.claude-plugin/plugin.json +12 -1
- package/dist/api/client.d.ts +36 -1
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +58 -2
- package/dist/api/client.js.map +1 -1
- package/dist/auth-cli.d.ts +7 -0
- package/dist/auth-cli.d.ts.map +1 -0
- package/dist/auth-cli.js +361 -0
- package/dist/auth-cli.js.map +1 -0
- package/dist/index.js +227 -17
- package/dist/index.js.map +1 -1
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +199 -283
- package/dist/tools/definitions.js.map +1 -1
- package/package.json +8 -2
- package/skills/SKILL_CHAINING_DEMO.md +335 -0
- package/skills/TEST_SCENARIOS.md +189 -0
- package/skills/quarri-analyze/SKILL.md +274 -0
- package/skills/quarri-chart/SKILL.md +415 -0
- package/skills/quarri-debug-connector/SKILL.md +338 -0
- package/skills/quarri-diagnose/SKILL.md +372 -0
- package/skills/quarri-explain/SKILL.md +184 -0
- package/skills/quarri-extract/SKILL.md +353 -0
- package/skills/quarri-insights/SKILL.md +328 -0
- package/skills/quarri-metric/SKILL.md +400 -0
- package/skills/quarri-query/SKILL.md +159 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run complete data analysis pipeline orchestrating query, insights, and charts
|
|
3
|
+
globs:
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /quarri-analyze - Full Analysis Pipeline
|
|
8
|
+
|
|
9
|
+
Orchestrate a complete data analysis pipeline by coordinating query generation, statistical analysis, business insights, and visualization.
|
|
10
|
+
|
|
11
|
+
## When to Use
|
|
12
|
+
|
|
13
|
+
Use `/quarri-analyze` when users want comprehensive analysis:
|
|
14
|
+
- "Analyze our sales trends"
|
|
15
|
+
- "What's driving customer churn?"
|
|
16
|
+
- "Give me insights on revenue performance"
|
|
17
|
+
- "Help me understand our order patterns"
|
|
18
|
+
|
|
19
|
+
This is more powerful than `/quarri-query` as it provides statistics, visualizations, and actionable insights.
|
|
20
|
+
|
|
21
|
+
## Orchestration Flow
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
/quarri-analyze
|
|
25
|
+
│
|
|
26
|
+
├── 1. /quarri-query
|
|
27
|
+
│ └── Generate SQL, fetch schema, execute query
|
|
28
|
+
│
|
|
29
|
+
├── 2. /quarri-insights
|
|
30
|
+
│ └── Statistical analysis + business interpretation
|
|
31
|
+
│
|
|
32
|
+
└── 3. /quarri-chart (if visualization warranted)
|
|
33
|
+
└── Chart recommendation + configuration
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Stage 1: Query (via /quarri-query)
|
|
37
|
+
|
|
38
|
+
Generate and execute SQL for the analysis question:
|
|
39
|
+
1. Fetch schema using `quarri_get_schema`
|
|
40
|
+
2. Search for relevant metrics using `quarri_search_metrics`
|
|
41
|
+
3. Generate SQL following star schema patterns
|
|
42
|
+
4. Execute using `quarri_execute_sql`
|
|
43
|
+
|
|
44
|
+
### Stage 2: Insights (via /quarri-insights)
|
|
45
|
+
|
|
46
|
+
Analyze the query results:
|
|
47
|
+
- Descriptive statistics for numeric columns
|
|
48
|
+
- Distribution and outlier analysis
|
|
49
|
+
- Correlation between variables
|
|
50
|
+
- Time series trends if applicable
|
|
51
|
+
- Business interpretation and recommendations
|
|
52
|
+
|
|
53
|
+
### Stage 3: Chart (via /quarri-chart)
|
|
54
|
+
|
|
55
|
+
If data warrants visualization:
|
|
56
|
+
- Apply chart decision tree
|
|
57
|
+
- Generate appropriate chart configuration
|
|
58
|
+
- Recommend alternatives if applicable
|
|
59
|
+
|
|
60
|
+
## MECE Framework for Complex Analysis
|
|
61
|
+
|
|
62
|
+
When analyzing complex business questions, structure the breakdown using the MECE principle:
|
|
63
|
+
- **Mutually Exclusive**: Categories don't overlap
|
|
64
|
+
- **Collectively Exhaustive**: All possibilities covered
|
|
65
|
+
|
|
66
|
+
### MECE Application Examples
|
|
67
|
+
|
|
68
|
+
#### Revenue Analysis
|
|
69
|
+
"Why is revenue changing?"
|
|
70
|
+
```
|
|
71
|
+
Revenue Drivers (MECE Breakdown)
|
|
72
|
+
├── Volume Drivers
|
|
73
|
+
│ ├── Customer count
|
|
74
|
+
│ ├── Order frequency per customer
|
|
75
|
+
│ └── Units per order
|
|
76
|
+
├── Price Drivers
|
|
77
|
+
│ ├── Unit price
|
|
78
|
+
│ ├── Product mix shift
|
|
79
|
+
│ └── Discount rates
|
|
80
|
+
└── External Factors
|
|
81
|
+
├── Seasonality
|
|
82
|
+
├── Market conditions
|
|
83
|
+
└── Competition
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
#### Customer Churn Analysis
|
|
87
|
+
"What's causing churn?"
|
|
88
|
+
```
|
|
89
|
+
Churn Factors (MECE Breakdown)
|
|
90
|
+
├── Product Issues
|
|
91
|
+
│ ├── Quality problems
|
|
92
|
+
│ ├── Feature gaps
|
|
93
|
+
│ └── Performance issues
|
|
94
|
+
├── Service Issues
|
|
95
|
+
│ ├── Support quality
|
|
96
|
+
│ ├── Response time
|
|
97
|
+
│ └── Resolution rate
|
|
98
|
+
├── Price Issues
|
|
99
|
+
│ ├── Absolute cost
|
|
100
|
+
│ ├── Perceived value
|
|
101
|
+
│ └── Competitor pricing
|
|
102
|
+
└── External Factors
|
|
103
|
+
├── Business closure
|
|
104
|
+
├── Changed needs
|
|
105
|
+
└── Market exit
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### Sales Performance
|
|
109
|
+
"Why are sales underperforming?"
|
|
110
|
+
```
|
|
111
|
+
Sales Performance (MECE Breakdown)
|
|
112
|
+
├── Lead Generation
|
|
113
|
+
│ ├── Marketing qualified leads
|
|
114
|
+
│ ├── Inbound inquiries
|
|
115
|
+
│ └── Outbound prospecting
|
|
116
|
+
├── Conversion Rate
|
|
117
|
+
│ ├── Lead to opportunity
|
|
118
|
+
│ ├── Opportunity to proposal
|
|
119
|
+
│ └── Proposal to close
|
|
120
|
+
└── Deal Size
|
|
121
|
+
├── Initial contract value
|
|
122
|
+
├── Upsell/cross-sell
|
|
123
|
+
└── Discounting
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### When to Apply MECE
|
|
127
|
+
|
|
128
|
+
Apply MECE structuring when:
|
|
129
|
+
1. Question involves "why" (root cause analysis)
|
|
130
|
+
2. Multiple factors could explain the outcome
|
|
131
|
+
3. User needs comprehensive coverage
|
|
132
|
+
4. Decision-making requires evaluating alternatives
|
|
133
|
+
|
|
134
|
+
For simple queries ("show revenue by region"), skip MECE and provide direct analysis.
|
|
135
|
+
|
|
136
|
+
## Workflow
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
1. Parse the analysis question
|
|
140
|
+
- Identify primary metric/measure
|
|
141
|
+
- Identify dimensions/breakdowns
|
|
142
|
+
- Determine time scope
|
|
143
|
+
|
|
144
|
+
2. Execute /quarri-query
|
|
145
|
+
- Generate appropriate SQL
|
|
146
|
+
- Execute and retrieve data
|
|
147
|
+
- Validate results
|
|
148
|
+
|
|
149
|
+
3. Execute /quarri-insights
|
|
150
|
+
- Run statistical analysis
|
|
151
|
+
- Identify patterns
|
|
152
|
+
- Generate business insights
|
|
153
|
+
|
|
154
|
+
4. Determine if visualization needed
|
|
155
|
+
- Data has clear visual pattern?
|
|
156
|
+
- More than 3 data points?
|
|
157
|
+
- User explicitly requested chart?
|
|
158
|
+
|
|
159
|
+
5. If yes, execute /quarri-chart
|
|
160
|
+
- Select appropriate chart type
|
|
161
|
+
- Generate configuration
|
|
162
|
+
|
|
163
|
+
6. Synthesize comprehensive report
|
|
164
|
+
- Combine all findings
|
|
165
|
+
- Apply MECE structure if complex question
|
|
166
|
+
- Prioritize actionable recommendations
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Output Format
|
|
170
|
+
|
|
171
|
+
```markdown
|
|
172
|
+
## Analysis: [Question Summary]
|
|
173
|
+
|
|
174
|
+
### Query
|
|
175
|
+
```sql
|
|
176
|
+
[SQL generated by /quarri-query]
|
|
177
|
+
```
|
|
178
|
+
[Brief explanation of what the query retrieves]
|
|
179
|
+
|
|
180
|
+
### Data Summary
|
|
181
|
+
- **Rows**: [count]
|
|
182
|
+
- **Date range**: [range]
|
|
183
|
+
- **Key dimensions**: [list]
|
|
184
|
+
|
|
185
|
+
### Statistical Findings
|
|
186
|
+
[From /quarri-insights]
|
|
187
|
+
- [Key statistic 1]
|
|
188
|
+
- [Key statistic 2]
|
|
189
|
+
- [Key statistic 3]
|
|
190
|
+
|
|
191
|
+
### MECE Breakdown (if applicable)
|
|
192
|
+
[Structured analysis of drivers/factors]
|
|
193
|
+
|
|
194
|
+
### Business Insights
|
|
195
|
+
|
|
196
|
+
#### Key Finding
|
|
197
|
+
**[Most important takeaway with specific numbers]**
|
|
198
|
+
|
|
199
|
+
#### Additional Insights
|
|
200
|
+
1. **[Insight type]**: [Specific finding]
|
|
201
|
+
- Implication: [What it means]
|
|
202
|
+
- Action: [What to do]
|
|
203
|
+
|
|
204
|
+
2. **[Insight type]**: [Specific finding]
|
|
205
|
+
- Implication: [What it means]
|
|
206
|
+
- Action: [What to do]
|
|
207
|
+
|
|
208
|
+
### Visualization
|
|
209
|
+
[From /quarri-chart if applicable]
|
|
210
|
+
[Chart type recommendation with rationale]
|
|
211
|
+
[Configuration or URL]
|
|
212
|
+
|
|
213
|
+
### Recommended Next Steps
|
|
214
|
+
1. [Immediate action]
|
|
215
|
+
2. [Follow-up analysis]
|
|
216
|
+
3. [Deeper investigation if warranted]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Example: Full Analysis
|
|
220
|
+
|
|
221
|
+
**User**: "Analyze why revenue dropped last month"
|
|
222
|
+
|
|
223
|
+
**Analysis Output**:
|
|
224
|
+
|
|
225
|
+
### Query
|
|
226
|
+
```sql
|
|
227
|
+
SELECT
|
|
228
|
+
DATE_TRUNC('week', order_date) as week,
|
|
229
|
+
product_category,
|
|
230
|
+
COUNT(*) as order_count,
|
|
231
|
+
COUNT(DISTINCT customer_id) as customers,
|
|
232
|
+
SUM(revenue) as revenue,
|
|
233
|
+
AVG(order_value) as avg_order_value
|
|
234
|
+
FROM quarri.bridge
|
|
235
|
+
WHERE order_date >= DATE '2024-11-01'
|
|
236
|
+
GROUP BY week, product_category
|
|
237
|
+
ORDER BY week, product_category
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### MECE Breakdown: Revenue Decline Drivers
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
Revenue = Customers × Orders/Customer × Revenue/Order
|
|
244
|
+
|
|
245
|
+
Analysis by Driver:
|
|
246
|
+
├── Customer Count: -8% (from 1,245 to 1,146)
|
|
247
|
+
│ └── PRIMARY DRIVER: New customer acquisition dropped
|
|
248
|
+
├── Order Frequency: -2% (from 2.3 to 2.25 orders/customer)
|
|
249
|
+
│ └── Minor decline, within normal range
|
|
250
|
+
└── Revenue per Order: +1% (from $89 to $90)
|
|
251
|
+
└── Stable, slight increase
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Key Finding
|
|
255
|
+
**Customer acquisition dropped 8%, accounting for 75% of the revenue decline. New customer count fell from 312 to 198 (-37%).**
|
|
256
|
+
|
|
257
|
+
### Recommended Actions
|
|
258
|
+
1. **Immediate**: Review marketing spend and campaign performance from last month
|
|
259
|
+
2. **This week**: Analyze acquisition channel performance (paid vs organic)
|
|
260
|
+
3. **Follow-up**: Compare conversion rates by channel to identify where leads are dropping
|
|
261
|
+
|
|
262
|
+
## Error Handling
|
|
263
|
+
|
|
264
|
+
- If query returns no data, suggest adjusting filters or date range
|
|
265
|
+
- If statistical analysis fails, report data quality issues
|
|
266
|
+
- If MECE breakdown unclear, ask clarifying questions
|
|
267
|
+
- Always provide partial results if some stages succeed
|
|
268
|
+
|
|
269
|
+
## Integration
|
|
270
|
+
|
|
271
|
+
This skill orchestrates:
|
|
272
|
+
- `/quarri-query` for data retrieval
|
|
273
|
+
- `/quarri-insights` for statistical analysis and business interpretation
|
|
274
|
+
- `/quarri-chart` for visualization recommendations
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Generate charts in multiple formats - QuickChart URLs, matplotlib, or ASCII
|
|
3
|
+
globs:
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /quarri-chart - Flexible Chart Generation
|
|
8
|
+
|
|
9
|
+
Generate data visualizations in multiple formats optimized for Claude Code users.
|
|
10
|
+
|
|
11
|
+
## When to Use
|
|
12
|
+
|
|
13
|
+
Use `/quarri-chart` when users want visualizations:
|
|
14
|
+
- "Create a chart of revenue by month"
|
|
15
|
+
- "Visualize customer distribution"
|
|
16
|
+
- "Show me a graph of this data"
|
|
17
|
+
- "What's the best way to display these results?"
|
|
18
|
+
|
|
19
|
+
## Output Formats
|
|
20
|
+
|
|
21
|
+
### 1. QuickChart URL (DEFAULT)
|
|
22
|
+
|
|
23
|
+
Generate a URL that renders instantly in any browser or terminal with image support.
|
|
24
|
+
|
|
25
|
+
**When to use**: Quick visualization, sharing, embedding in documents
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
https://quickchart.io/chart?c={encoded_config}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Example**:
|
|
32
|
+
```
|
|
33
|
+
https://quickchart.io/chart?c={type:'bar',data:{labels:['Q1','Q2','Q3','Q4'],datasets:[{label:'Revenue',data:[120,150,180,200]}]}}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 2. Matplotlib Code
|
|
37
|
+
|
|
38
|
+
Generate Python code that creates and saves chart images.
|
|
39
|
+
|
|
40
|
+
**When to use**: Custom styling, publication-quality charts, local files
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import matplotlib.pyplot as plt
|
|
44
|
+
import pandas as pd
|
|
45
|
+
|
|
46
|
+
# Data
|
|
47
|
+
categories = ['Q1', 'Q2', 'Q3', 'Q4']
|
|
48
|
+
values = [120, 150, 180, 200]
|
|
49
|
+
|
|
50
|
+
# Create figure
|
|
51
|
+
fig, ax = plt.subplots(figsize=(10, 6))
|
|
52
|
+
ax.bar(categories, values, color='#4F46E5')
|
|
53
|
+
|
|
54
|
+
# Styling
|
|
55
|
+
ax.set_xlabel('Quarter')
|
|
56
|
+
ax.set_ylabel('Revenue ($K)')
|
|
57
|
+
ax.set_title('Quarterly Revenue')
|
|
58
|
+
ax.spines['top'].set_visible(False)
|
|
59
|
+
ax.spines['right'].set_visible(False)
|
|
60
|
+
|
|
61
|
+
# Save
|
|
62
|
+
plt.tight_layout()
|
|
63
|
+
plt.savefig('revenue_chart.png', dpi=150)
|
|
64
|
+
plt.show()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 3. ASCII Chart
|
|
68
|
+
|
|
69
|
+
Terminal-friendly text visualization for quick inspection.
|
|
70
|
+
|
|
71
|
+
**When to use**: Terminal environments, quick data review, no graphics support
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Revenue by Quarter
|
|
75
|
+
|
|
76
|
+
Q1 |████████████ | $120K
|
|
77
|
+
Q2 |███████████████ | $150K
|
|
78
|
+
Q3 |██████████████████ | $180K
|
|
79
|
+
Q4 |████████████████████ | $200K
|
|
80
|
+
0 100 200
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Chart Selection Logic
|
|
84
|
+
|
|
85
|
+
### Decision Tree
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
START: What is the primary analysis goal?
|
|
89
|
+
|
|
90
|
+
1. TRENDS OVER TIME?
|
|
91
|
+
└─→ Single series? → LINE CHART
|
|
92
|
+
└─→ Multiple series? → MULTI-LINE
|
|
93
|
+
└─→ Cumulative? → AREA CHART
|
|
94
|
+
|
|
95
|
+
2. COMPARING CATEGORIES?
|
|
96
|
+
└─→ 2-7 categories → VERTICAL BAR
|
|
97
|
+
└─→ 8-15 categories → HORIZONTAL BAR
|
|
98
|
+
└─→ 15+ categories → TOP N + "Other"
|
|
99
|
+
└─→ Multiple dimensions → GROUPED BAR
|
|
100
|
+
|
|
101
|
+
3. SHOWING DISTRIBUTION?
|
|
102
|
+
└─→ Continuous data → HISTOGRAM
|
|
103
|
+
└─→ Categorical → BAR (sorted)
|
|
104
|
+
└─→ Compare groups → BOX PLOT
|
|
105
|
+
|
|
106
|
+
4. PARTS OF A WHOLE?
|
|
107
|
+
└─→ 2-6 parts → PIE/DONUT
|
|
108
|
+
└─→ 7+ parts → STACKED BAR (100%)
|
|
109
|
+
|
|
110
|
+
5. RELATIONSHIP BETWEEN VARIABLES?
|
|
111
|
+
└─→ Two numeric → SCATTER PLOT
|
|
112
|
+
└─→ With grouping → SCATTER with colors
|
|
113
|
+
|
|
114
|
+
DEFAULT: TABLE (when visualization unclear)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## QuickChart Configuration
|
|
118
|
+
|
|
119
|
+
### Bar Chart
|
|
120
|
+
```javascript
|
|
121
|
+
{
|
|
122
|
+
type: 'bar',
|
|
123
|
+
data: {
|
|
124
|
+
labels: ['A', 'B', 'C'],
|
|
125
|
+
datasets: [{
|
|
126
|
+
label: 'Values',
|
|
127
|
+
data: [10, 20, 15],
|
|
128
|
+
backgroundColor: '#4F46E5'
|
|
129
|
+
}]
|
|
130
|
+
},
|
|
131
|
+
options: {
|
|
132
|
+
title: { display: true, text: 'Chart Title' },
|
|
133
|
+
legend: { display: false }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Line Chart
|
|
139
|
+
```javascript
|
|
140
|
+
{
|
|
141
|
+
type: 'line',
|
|
142
|
+
data: {
|
|
143
|
+
labels: ['Jan', 'Feb', 'Mar', 'Apr'],
|
|
144
|
+
datasets: [{
|
|
145
|
+
label: 'Revenue',
|
|
146
|
+
data: [100, 120, 115, 140],
|
|
147
|
+
borderColor: '#4F46E5',
|
|
148
|
+
fill: false
|
|
149
|
+
}]
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Horizontal Bar
|
|
155
|
+
```javascript
|
|
156
|
+
{
|
|
157
|
+
type: 'horizontalBar',
|
|
158
|
+
data: {
|
|
159
|
+
labels: ['Product A', 'Product B', 'Product C'],
|
|
160
|
+
datasets: [{
|
|
161
|
+
data: [300, 250, 200],
|
|
162
|
+
backgroundColor: ['#4F46E5', '#10B981', '#F59E0B']
|
|
163
|
+
}]
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Pie/Donut Chart
|
|
169
|
+
```javascript
|
|
170
|
+
{
|
|
171
|
+
type: 'doughnut',
|
|
172
|
+
data: {
|
|
173
|
+
labels: ['Desktop', 'Mobile', 'Tablet'],
|
|
174
|
+
datasets: [{
|
|
175
|
+
data: [60, 30, 10],
|
|
176
|
+
backgroundColor: ['#4F46E5', '#10B981', '#F59E0B']
|
|
177
|
+
}]
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Scatter Plot
|
|
183
|
+
```javascript
|
|
184
|
+
{
|
|
185
|
+
type: 'scatter',
|
|
186
|
+
data: {
|
|
187
|
+
datasets: [{
|
|
188
|
+
label: 'Data Points',
|
|
189
|
+
data: [{x: 1, y: 2}, {x: 2, y: 4}, {x: 3, y: 3}],
|
|
190
|
+
backgroundColor: '#4F46E5'
|
|
191
|
+
}]
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Matplotlib Templates
|
|
197
|
+
|
|
198
|
+
### Bar Chart
|
|
199
|
+
```python
|
|
200
|
+
import matplotlib.pyplot as plt
|
|
201
|
+
|
|
202
|
+
fig, ax = plt.subplots(figsize=(10, 6))
|
|
203
|
+
categories = ['A', 'B', 'C', 'D']
|
|
204
|
+
values = [25, 40, 30, 35]
|
|
205
|
+
|
|
206
|
+
bars = ax.bar(categories, values, color='#4F46E5', edgecolor='white')
|
|
207
|
+
ax.bar_label(bars, fmt='%.0f')
|
|
208
|
+
|
|
209
|
+
ax.set_ylabel('Value')
|
|
210
|
+
ax.set_title('Category Comparison')
|
|
211
|
+
ax.spines['top'].set_visible(False)
|
|
212
|
+
ax.spines['right'].set_visible(False)
|
|
213
|
+
|
|
214
|
+
plt.tight_layout()
|
|
215
|
+
plt.savefig('bar_chart.png', dpi=150)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Line Chart
|
|
219
|
+
```python
|
|
220
|
+
import matplotlib.pyplot as plt
|
|
221
|
+
import matplotlib.dates as mdates
|
|
222
|
+
|
|
223
|
+
fig, ax = plt.subplots(figsize=(12, 6))
|
|
224
|
+
dates = ['2024-01', '2024-02', '2024-03', '2024-04']
|
|
225
|
+
values = [100, 120, 115, 140]
|
|
226
|
+
|
|
227
|
+
ax.plot(dates, values, marker='o', color='#4F46E5', linewidth=2, markersize=8)
|
|
228
|
+
ax.fill_between(dates, values, alpha=0.1, color='#4F46E5')
|
|
229
|
+
|
|
230
|
+
ax.set_ylabel('Revenue ($K)')
|
|
231
|
+
ax.set_title('Monthly Revenue Trend')
|
|
232
|
+
ax.grid(True, alpha=0.3)
|
|
233
|
+
ax.spines['top'].set_visible(False)
|
|
234
|
+
ax.spines['right'].set_visible(False)
|
|
235
|
+
|
|
236
|
+
plt.tight_layout()
|
|
237
|
+
plt.savefig('line_chart.png', dpi=150)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Horizontal Bar (for many categories)
|
|
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)
|
|
250
|
+
|
|
251
|
+
ax.set_xlabel('Sales ($K)')
|
|
252
|
+
ax.set_title('Top Products by Sales')
|
|
253
|
+
ax.invert_yaxis() # Largest at top
|
|
254
|
+
ax.spines['top'].set_visible(False)
|
|
255
|
+
ax.spines['right'].set_visible(False)
|
|
256
|
+
|
|
257
|
+
plt.tight_layout()
|
|
258
|
+
plt.savefig('horizontal_bar.png', dpi=150)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## ASCII Chart Generation
|
|
262
|
+
|
|
263
|
+
### Horizontal Bar (ASCII)
|
|
264
|
+
```
|
|
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
|
+
|
|
270
|
+
for label, value in data.items():
|
|
271
|
+
bar_len = int((value / max_val) * max_width)
|
|
272
|
+
bar = '█' * bar_len
|
|
273
|
+
print(f"{label:>15} |{bar} {value:,.0f}")
|
|
274
|
+
|
|
275
|
+
print(f"{'':>15} {'─' * max_width}")
|
|
276
|
+
|
|
277
|
+
# Example
|
|
278
|
+
data = {'Electronics': 45000, 'Clothing': 32000, 'Home': 28000}
|
|
279
|
+
ascii_bar_chart(data, "Revenue by Category")
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Output:**
|
|
283
|
+
```
|
|
284
|
+
Revenue by Category
|
|
285
|
+
|
|
286
|
+
Electronics |████████████████████████████████████████ 45,000
|
|
287
|
+
Clothing |████████████████████████████ 32,000
|
|
288
|
+
Home |████████████████████████ 28,000
|
|
289
|
+
────────────────────────────────────────
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Vertical Bar (ASCII)
|
|
293
|
+
```
|
|
294
|
+
def ascii_vertical_bar(data, title, height=10):
|
|
295
|
+
"""Generate ASCII vertical bar chart"""
|
|
296
|
+
print(f"\n{title}\n")
|
|
297
|
+
max_val = max(data.values())
|
|
298
|
+
|
|
299
|
+
for row in range(height, 0, -1):
|
|
300
|
+
line = ""
|
|
301
|
+
for value in data.values():
|
|
302
|
+
threshold = (row / height) * max_val
|
|
303
|
+
line += " █ " if value >= threshold else " "
|
|
304
|
+
print(f"{int(max_val * row / height):>6} |{line}")
|
|
305
|
+
|
|
306
|
+
print(f"{'':>6} +{'─────' * len(data)}")
|
|
307
|
+
labels = "".join(f"{k:^5}" for k in data.keys())
|
|
308
|
+
print(f"{'':>8}{labels}")
|
|
309
|
+
|
|
310
|
+
# Example
|
|
311
|
+
data = {'Q1': 120, 'Q2': 150, 'Q3': 180, 'Q4': 200}
|
|
312
|
+
ascii_vertical_bar(data, "Quarterly Revenue")
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Sparkline (ASCII)
|
|
316
|
+
```
|
|
317
|
+
def ascii_sparkline(values, width=30):
|
|
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
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Workflow
|
|
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
|
|
346
|
+
|
|
347
|
+
3. **Select chart type**:
|
|
348
|
+
- Apply decision tree
|
|
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**
|
|
385
|
+
```
|
|
386
|
+
[ASCII chart]
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Alternatives
|
|
390
|
+
- [Alternative chart 1]: [When it might be better]
|
|
391
|
+
- [Alternative chart 2]: [When it might be better]
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## Color Palettes
|
|
395
|
+
|
|
396
|
+
```python
|
|
397
|
+
# Primary palette
|
|
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']
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
## Integration
|
|
411
|
+
|
|
412
|
+
Charts work best when combined with:
|
|
413
|
+
- `/quarri-query`: Get data first, then visualize
|
|
414
|
+
- `/quarri-analyze`: Called as part of full analysis pipeline
|
|
415
|
+
- `/quarri-insights`: Visual support for statistical findings
|