Skip to content

Commit 07d584c

Browse files
authored
Rewrite of Coord/Project syntax and implementation (#151)
1 parent d684fa3 commit 07d584c

83 files changed

Lines changed: 4585 additions & 2001 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: 67 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ SELECT date, revenue, region FROM sales WHERE year = 2024
1111
VISUALISE date AS x, revenue AS y, region AS color
1212
DRAW line
1313
SCALE x VIA date
14-
COORD cartesian SETTING ylim => [0, 100000]
14+
SCALE y FROM [0, 100000]
1515
LABEL title => 'Sales by Region', x => 'Date', y => 'Revenue'
1616
THEME minimal
1717
```
1818

1919
**Statistics**:
2020

21-
- ~7,500 lines of Rust code (including COORD implementation)
21+
- ~7,500 lines of Rust code (including PROJECT implementation)
2222
- 507-line Tree-sitter grammar (simplified, no external scanner)
2323
- Full bindings: Rust, C, Python, Node.js with tree-sitter integration
2424
- Syntax highlighting support via Tree-sitter queries
2525
- 916 total tests (174 parser tests, comprehensive builder and integration tests)
2626
- End-to-end working pipeline: SQL → Data → Visualization
27-
- Coordinate transformations: Cartesian (xlim/ylim), Flip, Polar
27+
- Projectinate transformations: Cartesian, Flip, Polar
2828
- VISUALISE FROM shorthand syntax with automatic SELECT injection
2929

3030
---
@@ -257,7 +257,7 @@ For detailed API documentation, see [`src/doc/API.md`](src/doc/API.md).
257257

258258
- Uses `tree-sitter-ggsql` grammar (507 lines, simplified approach)
259259
- Parses **full query** (SQL + VISUALISE) into concrete syntax tree (CST)
260-
- Grammar supports: PLOT/TABLE/MAP types, DRAW/SCALE/FACET/COORD/LABEL/THEME clauses
260+
- Grammar supports: PLOT/TABLE/MAP types, DRAW/SCALE/FACET/PROJECT/LABEL/THEME clauses
261261
- British and American spellings: `VISUALISE` / `VISUALIZE`
262262
- **SQL portion parsing**: Basic SQL structure (SELECT, WITH, CREATE, INSERT, subqueries)
263263
- **Recursive subquery support**: Fully recursive grammar for complex SQL
@@ -303,7 +303,7 @@ pub struct Plot {
303303
pub layers: Vec<Layer>, // DRAW clauses
304304
pub scales: Vec<Scale>, // SCALE clauses
305305
pub facet: Option<Facet>, // FACET clause
306-
pub coord: Option<Coord>, // COORD clause
306+
pub project: Option<Project>, // PROJECT clause
307307
pub labels: Option<Labels>, // LABEL clause
308308
pub theme: Option<Theme>, // THEME clause
309309
}
@@ -389,17 +389,17 @@ pub enum FacetScales {
389389
FreeY, // 'free_y' - independent y-axis, shared x-axis
390390
}
391391

392-
pub struct Coord {
393-
pub coord_type: CoordType,
392+
pub struct Project {
393+
pub project_type: ProjectType,
394394
pub properties: HashMap<String, ParameterValue>,
395395
}
396396

397-
pub enum CoordType {
398-
Cartesian, // Standard x/y coordinates
399-
Polar, // Polar coordinates (pie charts, rose plots)
397+
pub enum ProjectType {
398+
Cartesian, // Standard x/y projectinates
399+
Polar, // Polar projectinates (pie charts, rose plots)
400400
Flip, // Flipped Cartesian (swaps x and y)
401401
Fixed, // Fixed aspect ratio
402-
Trans, // Transformed coordinates
402+
Trans, // Transformed projectinates
403403
Map, // Map projections
404404
QuickMap, // Quick map approximation
405405
}
@@ -811,7 +811,7 @@ The kernel includes enhanced support for Positron IDE:
811811

812812
- Complete syntax highlighting for ggsql queries
813813
- SQL keyword support (SELECT, FROM, WHERE, JOIN, WITH, etc.)
814-
- ggsql clause highlighting (VISUALISE, SCALE, COORD, FACET, LABEL, etc.)
814+
- ggsql clause highlighting (VISUALISE, SCALE, PROJECT, FACET, LABEL, etc.)
815815
- Aesthetic highlighting (x, y, color, size, shape, etc.)
816816
- String and number literals
817817
- Comment support (`--` and `/* */`)
@@ -854,7 +854,7 @@ When running in Positron IDE, the extension provides enhanced functionality:
854854

855855
**Syntax Scopes**:
856856

857-
- `keyword.control.ggsql` - VISUALISE, DRAW, SCALE, COORD, etc.
857+
- `keyword.control.ggsql` - VISUALISE, DRAW, SCALE, PROJECT, etc.
858858
- `keyword.other.sql` - SELECT, FROM, WHERE, etc.
859859
- `entity.name.function.geom.ggsql` - point, line, bar, etc.
860860
- `variable.parameter.aesthetic.ggsql` - x, y, color, size, etc.
@@ -1180,7 +1180,7 @@ Where `<global_mapping>` can be:
11801180
| `DRAW` | ✅ Yes | Define layers | `DRAW line MAPPING date AS x, value AS y` |
11811181
| `SCALE` | ✅ Yes | Configure scales | `SCALE x VIA date` |
11821182
| `FACET` | ❌ No | Small multiples | `FACET region` |
1183-
| `COORD` | ❌ No | Coordinate system | `COORD cartesian SETTING xlim => [0,100]` |
1183+
| `PROJECT` | ❌ No | Coordinate system | `PROJECT TO cartesian` |
11841184
| `LABEL` | ❌ No | Text labels | `LABEL title => 'My Chart', x => 'Date'` |
11851185
| `THEME` | ❌ No | Visual styling | `THEME minimal` |
11861186

@@ -1348,8 +1348,6 @@ SCALE color FROM ['A', 'B'] TO ['red', 'blue']
13481348
SCALE color TO viridis
13491349
```
13501350

1351-
**Note**: Cannot specify range in both SCALE and COORD for the same aesthetic (will error).
1352-
13531351
**Examples**:
13541352

13551353
```sql
@@ -1422,86 +1420,97 @@ FACET region BY category
14221420
SETTING free => ['x', 'y'], spacing => 10
14231421
```
14241422

1425-
### COORD Clause
1423+
### PROJECT Clause
14261424

14271425
**Syntax**:
14281426

14291427
```sql
1430-
-- With coordinate type
1431-
COORD <type> [SETTING <properties>]
1432-
1433-
-- With properties only (defaults to cartesian)
1434-
COORD SETTING <properties>
1428+
PROJECT [<aesthetic>, ...] TO <coord_type> [SETTING <properties>]
14351429
```
14361430

1431+
**Components**:
1432+
1433+
- **Aesthetics** (optional): Comma-separated list of positional aesthetic names. If omitted, uses coord defaults.
1434+
- **TO**: Required keyword separating aesthetics from coord type.
1435+
- **coord_type**: Either `cartesian` or `polar`.
1436+
- **SETTING** (optional): Additional properties.
1437+
14371438
**Coordinate Types**:
14381439

1439-
- **`cartesian`** - Standard x/y Cartesian coordinates (default)
1440-
- **`flip`** - Flipped Cartesian (swaps x and y axes)
1441-
- **`polar`** - Polar coordinates (for pie charts, rose plots)
1442-
- **`fixed`** - Fixed aspect ratio
1443-
- **`trans`** - Transformed coordinates
1444-
- **`map`** - Map projections
1445-
- **`quickmap`** - Quick approximation for maps
1440+
| Coord Type | Default Aesthetics | Description |
1441+
|------------|-------------------|-------------|
1442+
| `cartesian` | `x`, `y` | Standard x/y Cartesian coordinates |
1443+
| `polar` | `theta`, `radius` | Polar coordinates (for pie charts, rose plots) |
14461444

1447-
**Properties by Type**:
1445+
**Flipping Axes**:
14481446

1449-
**Cartesian**:
1447+
To flip axes (for horizontal bar charts), swap the aesthetic names:
14501448

1451-
- `xlim => [min, max]` - Set x-axis limits
1452-
- `ylim => [min, max]` - Set y-axis limits
1453-
- `<aesthetic> => [values...]` - Set range for any aesthetic (color, fill, size, etc.)
1449+
```sql
1450+
-- Horizontal bar chart: swap x and y in PROJECT
1451+
PROJECT y, x TO cartesian
1452+
```
14541453

1455-
**Flip**:
1454+
**Common Properties** (all projection types):
14561455

1457-
- `<aesthetic> => [values...]` - Set range for any aesthetic
1456+
- `clip => <boolean>` - Whether to clip marks outside the plot area (default: unset)
1457+
1458+
**Type-Specific Properties**:
1459+
1460+
**Cartesian**:
1461+
1462+
- `ratio => <number>` - Set aspect ratio (not yet implemented)
1463+
1464+
Note: For axis limits, use `SCALE x FROM [min, max]` or `SCALE y FROM [min, max]`.
14581465

14591466
**Polar**:
14601467

14611468
- `theta => <aesthetic>` - Which aesthetic maps to angle (defaults to `y`)
1462-
- `<aesthetic> => [values...]` - Set range for any aesthetic
14631469

14641470
**Important Notes**:
14651471

1466-
1. **Axis limits auto-swap**: `xlim => [100, 0]` automatically becomes `[0, 100]`
1467-
2. **ggplot2 compatibility**: `coord_flip` preserves axis label names (labels stay with aesthetic names, not visual position)
1468-
3. **Range conflicts**: Error if same aesthetic has input range in both SCALE and COORD
1469-
4. **Multi-layer support**: All coordinate transforms apply to all layers
1472+
1. **Axis limits**: Use `SCALE x/y FROM [min, max]` to set axis limits
1473+
2. **Aesthetic domains**: Use `SCALE <aesthetic> FROM [...]` to set aesthetic domains
1474+
3. **Custom aesthetics**: User can define custom positional names (e.g., `PROJECT a, b TO cartesian`)
1475+
4. **Multi-layer support**: All projection transforms apply to all layers
14701476

14711477
**Status**:
14721478

14731479
-**Cartesian**: Fully implemented and tested
1474-
-**Flip**: Fully implemented and tested
14751480
-**Polar**: Fully implemented and tested
1476-
-**Other types**: Not yet implemented
14771481

14781482
**Examples**:
14791483

14801484
```sql
1481-
-- Cartesian with axis limits
1482-
COORD cartesian SETTING xlim => [0, 100], ylim => [0, 50]
1485+
-- Default aesthetics (x, y for cartesian)
1486+
PROJECT TO cartesian
1487+
1488+
-- Explicit aesthetics (same as defaults)
1489+
PROJECT x, y TO cartesian
14831490

1484-
-- Cartesian with aesthetic range
1485-
COORD cartesian SETTING color => O ['red', 'green', 'blue']
1491+
-- Flip projection for horizontal bar chart (swap x and y)
1492+
PROJECT y, x TO cartesian
14861493

1487-
-- Cartesian shorthand (type optional when using SETTING)
1488-
COORD SETTING xlim => [0, 100]
1494+
-- Custom aesthetic names
1495+
PROJECT myX, myY TO cartesian
14891496

1490-
-- Flip coordinates for horizontal bar chart
1491-
COORD flip
1497+
-- Polar for pie chart (using default theta/radius aesthetics)
1498+
PROJECT TO polar
14921499

1493-
-- Flip with aesthetic range
1494-
COORD flip SETTING color => ['A', 'B', 'C']
1500+
-- Polar with y/x aesthetics (y becomes theta, x becomes radius)
1501+
PROJECT y, x TO polar
14951502

1496-
-- Polar for pie chart (theta defaults to y)
1497-
COORD polar
1503+
-- Polar with start angle offset (3 o'clock position)
1504+
PROJECT y, x TO polar SETTING start => 90
14981505

1499-
-- Polar for rose plot (x maps to radius)
1500-
COORD polar SETTING theta => y
1506+
-- Clip marks to plot area
1507+
PROJECT TO cartesian SETTING clip => true
15011508

15021509
-- Combined with other clauses
15031510
DRAW bar MAPPING category AS x, value AS y
1504-
COORD cartesian SETTING xlim => [0, 100], ylim => [0, 200]
1511+
SCALE x FROM [0, 100]
1512+
SCALE y FROM [0, 200]
1513+
PROJECT y, x TO cartesian SETTING clip => true
15051514
LABEL x => 'Category', y => 'Count'
15061515
```
15071516

EXAMPLES.md

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ This document provides a collection of basic examples demonstrating how to use g
77
- [Basic Visualizations](#basic-visualizations)
88
- [Multiple Layers](#multiple-layers)
99
- [Scales and Transformations](#scales-and-transformations)
10-
- [Coordinate Systems](#coordinate-systems)
10+
- [Projections](#projections)
1111
- [Labels and Themes](#labels-and-themes)
1212
- [Faceting](#faceting)
1313
- [Common Table Expressions (CTEs)](#common-table-expressions-ctes)
@@ -125,44 +125,45 @@ SCALE DISCRETE fill FROM ['A', 'B', 'C', 'D']
125125

126126
---
127127

128-
## Coordinate Systems
128+
## Projections
129129

130-
### Cartesian with Limits
130+
### Cartesian with Axis Limits
131131

132132
```sql
133133
SELECT x, y FROM data
134134
VISUALISE x, y
135135
DRAW point
136-
COORD cartesian SETTING xlim => [0, 100], ylim => [0, 50]
136+
SCALE x FROM [0, 100]
137+
SCALE y FROM [0, 50]
137138
```
138139

139-
### Flipped Coordinates (Horizontal Bar Chart)
140+
### Flipped Projection (Horizontal Bar Chart)
140141

141142
```sql
142143
SELECT category, value FROM data
143144
ORDER BY value DESC
144145
VISUALISE category AS x, value AS y
145146
DRAW bar
146-
COORD flip
147+
PROJECT y, x TO cartesian
147148
```
148149

149-
### Polar Coordinates (Pie Chart)
150+
### Polar Projection (Pie Chart)
150151

151152
```sql
152153
SELECT category, SUM(value) as total FROM data
153154
GROUP BY category
154-
VISUALISE category AS x, total AS y
155+
VISUALISE total AS y, category AS fill
155156
DRAW bar
156-
COORD polar
157+
PROJECT y, x TO polar
157158
```
158159

159-
### Polar with Theta Specification
160+
### Polar with Start Angle
160161

161162
```sql
162163
SELECT category, value FROM data
163-
VISUALISE category AS x, value AS y
164+
VISUALISE value AS y, category AS fill
164165
DRAW bar
165-
COORD polar SETTING theta => y
166+
PROJECT y, x TO polar SETTING start => 90
166167
```
167168

168169
---
@@ -307,7 +308,7 @@ regional_totals AS (
307308
)
308309
VISUALISE region AS x, total AS y, region AS fill FROM regional_totals
309310
DRAW bar
310-
COORD flip
311+
PROJECT y, x TO cartesian
311312
LABEL title => 'Total Revenue by Region',
312313
x => 'Region',
313314
y => 'Total Revenue ($)'
@@ -373,8 +374,8 @@ WITH ranked_products AS (
373374
SELECT * FROM ranked_products WHERE rank <= 5
374375
VISUALISE product_name AS x, revenue AS y, category AS color
375376
DRAW bar
376-
FACET category SETTING scales => 'free_x'
377-
COORD flip
377+
FACET category SETTING free => 'x'
378+
PROJECT y, x TO cartesian
378379
LABEL title => 'Top 5 Products per Category',
379380
x => 'Product',
380381
y => 'Revenue ($)'
@@ -476,7 +477,7 @@ LABEL title => 'Temperature Trends',
476477
y => 'Temperature (°C)'
477478
```
478479

479-
### Categorical Analysis with Flipped Coordinates
480+
### Categorical Analysis with Flipped Projection
480481

481482
```sql
482483
SELECT
@@ -488,8 +489,9 @@ ORDER BY total_revenue DESC
488489
LIMIT 10
489490
VISUALISE product_name AS x, total_revenue AS y, product_name AS fill
490491
DRAW bar
491-
COORD flip SETTING color => ['red', 'orange', 'yellow', 'green', 'blue',
492-
'indigo', 'violet', 'pink', 'brown', 'gray']
492+
PROJECT y, x TO cartesian
493+
SCALE fill TO ['red', 'orange', 'yellow', 'green', 'blue',
494+
'indigo', 'violet', 'pink', 'brown', 'gray']
493495
LABEL title => 'Top 10 Products by Revenue',
494496
x => 'Product',
495497
y => 'Revenue ($)'
@@ -510,7 +512,7 @@ DRAW point
510512
SCALE x SETTING type => 'date'
511513
SCALE DISCRETE color FROM ['A', 'B', 'C']
512514
SCALE size SETTING limits => [0, 100]
513-
COORD cartesian SETTING ylim => [0, 150]
515+
SCALE y FROM [0, 150]
514516
LABEL title => 'Measurement Distribution',
515517
x => 'Date',
516518
y => 'Value'
@@ -529,7 +531,8 @@ VISUALISE x, y, category AS color
529531
DRAW point SETTING size => 5
530532
DRAW text MAPPING label AS label
531533
SCALE color TO viridis
532-
COORD cartesian SETTING xlim => [0, 100], ylim => [0, 100]
534+
SCALE x FROM [0, 100]
535+
SCALE y FROM [0, 100]
533536
LABEL title => 'Annotated Scatter Plot',
534537
x => 'X Axis',
535538
y => 'Y Axis'
@@ -630,7 +633,7 @@ Draw Line
630633

631634
3. **Color Mappings**: Use `color` for continuous data and `fill` for categorical data in bars/areas.
632635

633-
4. **Coordinate Limits**: Set explicit limits with `COORD cartesian SETTING xlim => [min, max]` to control axis ranges.
636+
4. **Axis Limits**: Set explicit limits with `SCALE x FROM [min, max]` or `SCALE y FROM [min, max]` to control axis ranges.
634637

635638
5. **Faceting**: Use faceting to create small multiples when comparing across categories.
636639

@@ -640,7 +643,7 @@ Draw Line
640643

641644
8. **Labels**: Always provide meaningful titles and axis labels for clarity.
642645

643-
9. **Range Specification**: Use either SCALE or COORD for range/limit specification, but not both for the same aesthetic.
646+
9. **Range Specification**: Use SCALE for all axis limits and aesthetic domain specifications.
644647

645648
---
646649

0 commit comments

Comments
 (0)