Skip to content

Commit 7a5ed62

Browse files
authored
New Scale syntax and implementation (#82)
1 parent 640ce77 commit 7a5ed62

96 files changed

Lines changed: 29918 additions & 5344 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 72 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
SELECT date, revenue, region FROM sales WHERE year = 2024
1111
VISUALISE date AS x, revenue AS y, region AS color
1212
DRAW line
13-
SCALE x SETTING type => 'date'
13+
SCALE x VIA date
1414
COORD cartesian SETTING ylim => [0, 100000]
1515
LABEL title => 'Sales by Region', x => 'Date', y => 'Revenue'
1616
THEME minimal
@@ -243,7 +243,7 @@ For detailed API documentation, see [`src/doc/API.md`](src/doc/API.md).
243243

244244
- Uses `tree-sitter-ggsql` grammar (507 lines, simplified approach)
245245
- Parses **full query** (SQL + VISUALISE) into concrete syntax tree (CST)
246-
- Grammar supports: PLOT/TABLE/MAP types, DRAW/SCALE/FACET/COORD/LABEL/GUIDE/THEME clauses
246+
- Grammar supports: PLOT/TABLE/MAP types, DRAW/SCALE/FACET/COORD/LABEL/THEME clauses
247247
- British and American spellings: `VISUALISE` / `VISUALIZE`
248248
- **SQL portion parsing**: Basic SQL structure (SELECT, WITH, CREATE, INSERT, subqueries)
249249
- **Recursive subquery support**: Fully recursive grammar for complex SQL
@@ -288,7 +288,6 @@ pub struct Plot {
288288
pub facet: Option<Facet>, // FACET clause
289289
pub coord: Option<Coord>, // COORD clause
290290
pub labels: Option<Labels>, // LABEL clause
291-
pub guides: Vec<Guide>, // GUIDE clauses
292291
pub theme: Option<Theme>, // THEME clause
293292
}
294293

@@ -395,19 +394,6 @@ pub struct Labels {
395394
pub labels: HashMap<String, String>, // label type → text
396395
}
397396

398-
pub struct Guide {
399-
pub aesthetic: String,
400-
pub guide_type: Option<GuideType>,
401-
pub properties: HashMap<String, ParameterValue>,
402-
}
403-
404-
pub enum GuideType {
405-
Legend,
406-
ColorBar,
407-
Axis,
408-
None,
409-
}
410-
411397
pub struct Theme {
412398
pub style: Option<String>,
413399
pub properties: HashMap<String, ParameterValue>,
@@ -421,7 +407,6 @@ pub struct Theme {
421407
- `Plot::new()` - Create a new empty Plot
422408
- `Plot::with_global_mapping(mapping)` - Create Plot with a global mapping
423409
- `Plot::find_scale(aesthetic)` - Look up scale specification for an aesthetic
424-
- `Plot::find_guide(aesthetic)` - Find a guide specification for an aesthetic
425410
- `Plot::has_layers()` - Check if Plot has any layers
426411
- `Plot::layer_count()` - Get the number of layers
427412

@@ -781,7 +766,7 @@ SELECT * FROM (VALUES
781766
SELECT * FROM sales
782767
VISUALISE
783768
DRAW line MAPPING date AS x, revenue AS y, region AS color
784-
SCALE x SETTING type => 'date'
769+
SCALE x VIA date
785770
LABEL title => 'Sales Trends'
786771
```
787772

@@ -1093,16 +1078,15 @@ Where `<global_mapping>` can be:
10931078

10941079
### Clause Types
10951080

1096-
| Clause | Repeatable | Purpose | Example |
1097-
| ----------- | ---------- | ------------------ | ----------------------------------------- |
1098-
| `VISUALISE` | ✅ Yes | Entry point | `VISUALISE date AS x, revenue AS y` |
1099-
| `DRAW` | ✅ Yes | Define layers | `DRAW line MAPPING date AS x, value AS y` |
1100-
| `SCALE` | ✅ Yes | Configure scales | `SCALE x SETTING type => 'date'` |
1101-
| `FACET` | ❌ No | Small multiples | `FACET WRAP region` |
1102-
| `COORD` | ❌ No | Coordinate system | `COORD cartesian SETTING xlim => [0,100]` |
1103-
| `LABEL` | ❌ No | Text labels | `LABEL title => 'My Chart', x => 'Date'` |
1104-
| `GUIDE` | ✅ Yes | Legend/axis config | `GUIDE color SETTING position => 'right'` |
1105-
| `THEME` | ❌ No | Visual styling | `THEME minimal` |
1081+
| Clause | Repeatable | Purpose | Example |
1082+
| -------------- | ---------- | ------------------ | ------------------------------------ |
1083+
| `VISUALISE` | ✅ Yes | Entry point | `VISUALISE date AS x, revenue AS y` |
1084+
| `DRAW` | ✅ Yes | Define layers | `DRAW line MAPPING date AS x, value AS y` |
1085+
| `SCALE` | ✅ Yes | Configure scales | `SCALE x VIA date` |
1086+
| `FACET` | ❌ No | Small multiples | `FACET WRAP region` |
1087+
| `COORD` | ❌ No | Coordinate system | `COORD cartesian SETTING xlim => [0,100]` |
1088+
| `LABEL` | ❌ No | Text labels | `LABEL title => 'My Chart', x => 'Date'` |
1089+
| `THEME` | ❌ No | Visual styling | `THEME minimal` |
11061090

11071091
### DRAW Clause (Layers)
11081092

@@ -1214,49 +1198,79 @@ DRAW line
12141198
**Syntax**:
12151199

12161200
```sql
1217-
SCALE <aesthetic> SETTING
1218-
[type => <scale_type>]
1219-
[limits => [min, max]]
1220-
[breaks => <array | interval>]
1221-
[palette => <name>]
1222-
[domain => [values...]]
1201+
SCALE [TYPE] <aesthetic> [FROM <input>] [TO <output>] [VIA <transform>] [SETTING <properties>]
12231202
```
12241203

1225-
**Scale Types**:
1204+
**Type Modifiers** (optional, placed before aesthetic):
12261205

1227-
- **Continuous**: `linear`, `log10`, `log`, `log2`, `sqrt`, `reverse`
1228-
- **Discrete**: `categorical`, `ordinal`
1229-
- **Temporal**: `date`, `datetime`, `time`
1230-
- **Color Palettes**: `viridis`, `plasma`, `magma`, `inferno`, `cividis`, `diverging`, `sequential`
1206+
- **`CONTINUOUS`** - Continuous numeric data
1207+
- **`DISCRETE`** - Categorical/discrete data
1208+
- **`BINNED`** - Binned/bucketed data
1209+
- **`DATE`** - Date data (maps to Vega-Lite temporal type)
1210+
- **`DATETIME`** - Datetime data (maps to Vega-Lite temporal type)
1211+
1212+
**Subclauses**:
1213+
1214+
- **`FROM [...]`** - Input range specification (maps to Vega-Lite `scale.domain`)
1215+
- **`TO [...]`** or **`TO palette`** - Output range as array or named palette (maps to Vega-Lite `scale.range` or `scale.scheme`)
1216+
- **`VIA transform`** - Transformation method (reserved for future use)
1217+
- **`SETTING ...`** - Additional properties (e.g., `breaks`)
1218+
1219+
**Named Palettes** (used with `TO`):
1220+
1221+
- `viridis`, `plasma`, `magma`, `inferno`, `cividis`, `diverging`, `sequential`
12311222

12321223
**Critical for Date Formatting**:
12331224

12341225
```sql
1235-
SCALE x SETTING type => 'date'
1226+
SCALE x VIA date
12361227
-- Maps to Vega-Lite field type = "temporal"
12371228
-- Enables proper date axis formatting
12381229
```
12391230

1240-
**Domain Property**:
1231+
**Input Range Specification** (FROM clause):
12411232

1242-
The `domain` property explicitly sets the input domain for a scale:
1233+
The `FROM` clause explicitly sets the input range for a scale:
12431234

12441235
```sql
1245-
-- Set domain for discrete scale
1246-
SCALE color SETTING domain => ['red', 'green', 'blue']
1236+
-- Set range for discrete scale
1237+
SCALE DISCRETE color FROM ['A', 'B', 'C']
12471238

1248-
-- Set domain for continuous scale
1249-
SCALE x SETTING domain => [0, 100]
1239+
-- Set range for continuous scale
1240+
SCALE CONTINUOUS x FROM [0, 100]
12501241
```
12511242

1252-
**Note**: Cannot specify domain in both SCALE and COORD for the same aesthetic (will error).
1243+
**Range Specification** (TO clause):
12531244

1254-
**Example**:
1245+
The `TO` clause sets the output range - either explicit values or a named palette:
12551246

12561247
```sql
1257-
SCALE x SETTING type => 'date', breaks => '2 months'
1258-
SCALE y SETTING type => 'log10', limits => [1, 1000]
1259-
SCALE color SETTING palette => 'viridis', domain => ['A', 'B', 'C']
1248+
-- Explicit color values
1249+
SCALE color FROM ['A', 'B'] TO ['red', 'blue']
1250+
1251+
-- Named palette
1252+
SCALE color TO viridis
1253+
```
1254+
1255+
**Note**: Cannot specify range in both SCALE and COORD for the same aesthetic (will error).
1256+
1257+
**Examples**:
1258+
1259+
```sql
1260+
-- Date scale
1261+
SCALE x VIA date
1262+
1263+
-- Continuous scale with input range
1264+
SCALE CONTINUOUS y FROM [0, 100]
1265+
1266+
-- Discrete color scale with input range and output range
1267+
SCALE DISCRETE color FROM ['A', 'B', 'C'] TO ['red', 'green', 'blue']
1268+
1269+
-- Color scale with named palette
1270+
SCALE color TO viridis
1271+
1272+
-- Scale with input range and additional settings
1273+
SCALE x VIA date FROM ['2024-01-01', '2024-12-31'] SETTING breaks => '1 month'
12601274
```
12611275

12621276
### FACET Clause
@@ -1313,22 +1327,22 @@ COORD SETTING <properties>
13131327

13141328
- `xlim => [min, max]` - Set x-axis limits
13151329
- `ylim => [min, max]` - Set y-axis limits
1316-
- `<aesthetic> => [values...]` - Set domain for any aesthetic (color, fill, size, etc.)
1330+
- `<aesthetic> => [values...]` - Set range for any aesthetic (color, fill, size, etc.)
13171331

13181332
**Flip**:
13191333

1320-
- `<aesthetic> => [values...]` - Set domain for any aesthetic
1334+
- `<aesthetic> => [values...]` - Set range for any aesthetic
13211335

13221336
**Polar**:
13231337

13241338
- `theta => <aesthetic>` - Which aesthetic maps to angle (defaults to `y`)
1325-
- `<aesthetic> => [values...]` - Set domain for any aesthetic
1339+
- `<aesthetic> => [values...]` - Set range for any aesthetic
13261340

13271341
**Important Notes**:
13281342

13291343
1. **Axis limits auto-swap**: `xlim => [100, 0]` automatically becomes `[0, 100]`
13301344
2. **ggplot2 compatibility**: `coord_flip` preserves axis label names (labels stay with aesthetic names, not visual position)
1331-
3. **Domain conflicts**: Error if same aesthetic has domain in both SCALE and COORD
1345+
3. **Range conflicts**: Error if same aesthetic has input range in both SCALE and COORD
13321346
4. **Multi-layer support**: All coordinate transforms apply to all layers
13331347

13341348
**Status**:
@@ -1344,7 +1358,7 @@ COORD SETTING <properties>
13441358
-- Cartesian with axis limits
13451359
COORD cartesian SETTING xlim => [0, 100], ylim => [0, 50]
13461360

1347-
-- Cartesian with aesthetic domain
1361+
-- Cartesian with aesthetic range
13481362
COORD cartesian SETTING color => O ['red', 'green', 'blue']
13491363

13501364
-- Cartesian shorthand (type optional when using SETTING)
@@ -1353,7 +1367,7 @@ COORD SETTING xlim => [0, 100]
13531367
-- Flip coordinates for horizontal bar chart
13541368
COORD flip
13551369

1356-
-- Flip with aesthetic domain
1370+
-- Flip with aesthetic range
13571371
COORD flip SETTING color => ['A', 'B', 'C']
13581372

13591373
-- Polar for pie chart (theta defaults to y)
@@ -1427,7 +1441,7 @@ DRAW line
14271441
MAPPING sale_date AS x, total AS y, region AS color
14281442
DRAW point
14291443
MAPPING sale_date AS x, total AS y, region AS color
1430-
SCALE x SETTING type => 'date'
1444+
SCALE x VIA date
14311445
FACET WRAP region
14321446
LABEL title => 'Sales Trends by Region', x => 'Date', y => 'Total Quantity'
14331447
THEME minimal

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ pyo3 = "0.26"
5757
# Testing
5858
proptest = "1.4"
5959

60+
# Color interpolation
61+
palette = "0.7"
62+
6063
# Utilities
6164
regex = "1.10"
6265
chrono = "0.4"

EXAMPLES.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,16 +111,16 @@ SCALE y SETTING type => 'log10'
111111
SELECT date, temperature, station FROM weather
112112
VISUALISE date AS x, temperature AS y, station AS color
113113
DRAW line
114-
SCALE color SETTING palette => 'viridis'
114+
SCALE color TO viridis
115115
```
116116

117-
### Custom Domain
117+
### Custom input range
118118

119119
```sql
120120
SELECT category, value FROM data
121121
VISUALISE category AS x, value AS y, category AS fill
122122
DRAW bar
123-
SCALE fill SETTING domain => ['A', 'B', 'C', 'D']
123+
SCALE DISCRETE fill FROM ['A', 'B', 'C', 'D']
124124
```
125125

126126
---
@@ -470,7 +470,7 @@ WHERE timestamp >= NOW() - INTERVAL '7 days'
470470
VISUALISE timestamp AS x, temperature AS y, station AS color, station AS linetype
471471
DRAW line
472472
SCALE x SETTING type => 'datetime'
473-
SCALE color SETTING palette => 'viridis'
473+
SCALE color TO viridis
474474
LABEL title => 'Temperature Trends',
475475
x => 'Time',
476476
y => 'Temperature (°C)'
@@ -496,7 +496,7 @@ LABEL title => 'Top 10 Products by Revenue',
496496
THEME classic
497497
```
498498

499-
### Distribution with Custom Domain
499+
### Distribution with Custom range
500500

501501
```sql
502502
SELECT
@@ -508,7 +508,7 @@ WHERE category IN ('A', 'B', 'C')
508508
VISUALISE date AS x, value AS y, category AS color, value AS size
509509
DRAW point
510510
SCALE x SETTING type => 'date'
511-
SCALE color SETTING domain => ['A', 'B', 'C']
511+
SCALE DISCRETE color FROM ['A', 'B', 'C']
512512
SCALE size SETTING limits => [0, 100]
513513
COORD cartesian SETTING ylim => [0, 150]
514514
LABEL title => 'Measurement Distribution',
@@ -528,7 +528,7 @@ FROM data_points
528528
VISUALISE x, y, category AS color
529529
DRAW point SETTING size => 5
530530
DRAW text MAPPING label AS label
531-
SCALE color SETTING palette => 'viridis'
531+
SCALE color TO viridis
532532
COORD cartesian SETTING xlim => [0, 100], ylim => [0, 100]
533533
LABEL title => 'Annotated Scatter Plot',
534534
x => 'X Axis',
@@ -545,7 +545,7 @@ GROUP BY cyl
545545
ORDER BY cyl
546546
VISUALISE cyl AS x, vehicle_count AS y
547547
DRAW bar
548-
SCALE x SETTING domain => [4, 6, 8]
548+
SCALE DISCRETE x FROM [4, 6, 8]
549549
LABEL title => 'Distribution of Vehicles by Number of Cylinders',
550550
x => 'Number of Cylinders',
551551
y => 'Number of Vehicles'
@@ -640,7 +640,7 @@ Draw Line
640640

641641
8. **Labels**: Always provide meaningful titles and axis labels for clarity.
642642

643-
9. **Domain Specification**: Use either SCALE or COORD for domain/limit specification, but not both for the same aesthetic.
643+
9. **Range Specification**: Use either SCALE or COORD for range/limit specification, but not both for the same aesthetic.
644644

645645
---
646646

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ Key grammar elements:
219219
- `SCALE <aesthetic> SETTING` - Configure data-to-visual mappings
220220
- `FACET` - Create small multiples (WRAP for flowing layout, BY for grid)
221221
- `COORD` - Coordinate transformations (cartesian, flip, polar)
222-
- `LABEL`, `THEME`, `GUIDE` - Styling and annotation
222+
- `LABEL`, `THEME` - Styling and annotation
223223

224224
## Jupyter Kernel
225225

doc/_quarto.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ website:
1818
announcement:
1919
icon: info-circle
2020
dismissable: true
21-
content: "ggsql is still in early development and all functionality is subject to change"
21+
content: "ggsql is still in early development and all functionality are subject to change"
2222
type: primary
2323
position: below-navbar
2424
twitter-card:
@@ -80,6 +80,14 @@ website:
8080
- section: Layers
8181
contents:
8282
- auto: syntax/layer/*
83+
- section: Scales
84+
contents:
85+
- section: Types
86+
contents:
87+
- auto: syntax/scale/type/*
88+
- section: Palettes
89+
contents:
90+
- auto: syntax/scale/palette/*
8391

8492

8593
format:

0 commit comments

Comments
 (0)