Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
44e8867
initial rename of clause
thomasp85 Feb 23, 2026
9d74e68
better internal naming
thomasp85 Feb 23, 2026
d8d827b
Merge commit '850a362e00a50411541c46bcddf96b13a0d0c1bc'
thomasp85 Feb 23, 2026
1b0a410
refactor to trait based design
thomasp85 Feb 23, 2026
c1ee3b2
remove hallucinated functionality
thomasp85 Feb 23, 2026
474dcf7
implement clip functionality
thomasp85 Feb 23, 2026
01676c8
parameterise positional aesthetics
thomasp85 Feb 24, 2026
cea5049
parameterise the free property of facet
thomasp85 Feb 24, 2026
672be3f
update facet aesthetic to normalised names
thomasp85 Feb 25, 2026
125c51f
smaller fixes plus implement start setting for polar
thomasp85 Feb 25, 2026
41f4278
fix custom positional aesthetics
thomasp85 Feb 25, 2026
d4730c1
remove theta setting
thomasp85 Feb 25, 2026
9266427
Add end property to polar
thomasp85 Feb 25, 2026
45864dd
add inner property to polar coord
thomasp85 Feb 25, 2026
3aef3fb
reformat etc
thomasp85 Feb 26, 2026
b012f07
update docs
thomasp85 Feb 26, 2026
06a964b
Merge commit 'c1979ccc27bedf33cbe79509c5f09e2141d38620'
thomasp85 Feb 26, 2026
fe19be6
delete erroneous file commit
thomasp85 Feb 26, 2026
177d216
fixes based on code review
thomasp85 Feb 27, 2026
66da064
unify property default handling
thomasp85 Mar 2, 2026
99bac9e
Remove unneeded methods from kind enums
thomasp85 Mar 2, 2026
09cf750
simplify grammar
thomasp85 Mar 2, 2026
07cc8e0
remove intercept suffix
thomasp85 Mar 2, 2026
e8c28e8
reformat
thomasp85 Mar 2, 2026
6fa967e
improve doc based on comments
thomasp85 Mar 2, 2026
889b66c
refactor AestheticContext
thomasp85 Mar 2, 2026
2c3a2a3
add coord resolution
thomasp85 Mar 2, 2026
2e639af
small simplification
thomasp85 Mar 2, 2026
fe3df29
make sure all the links are there
thomasp85 Mar 2, 2026
ffaea24
fix my fix
thomasp85 Mar 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 67 additions & 58 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ SELECT date, revenue, region FROM sales WHERE year = 2024
VISUALISE date AS x, revenue AS y, region AS color
DRAW line
SCALE x VIA date
COORD cartesian SETTING ylim => [0, 100000]
SCALE y FROM [0, 100000]
LABEL title => 'Sales by Region', x => 'Date', y => 'Revenue'
THEME minimal
```

**Statistics**:

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

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

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

pub struct Coord {
pub coord_type: CoordType,
pub struct Project {
pub project_type: ProjectType,
pub properties: HashMap<String, ParameterValue>,
}

pub enum CoordType {
Cartesian, // Standard x/y coordinates
Polar, // Polar coordinates (pie charts, rose plots)
pub enum ProjectType {
Cartesian, // Standard x/y projectinates
Polar, // Polar projectinates (pie charts, rose plots)
Flip, // Flipped Cartesian (swaps x and y)
Fixed, // Fixed aspect ratio
Trans, // Transformed coordinates
Trans, // Transformed projectinates
Map, // Map projections
QuickMap, // Quick map approximation
}
Expand Down Expand Up @@ -811,7 +811,7 @@ The kernel includes enhanced support for Positron IDE:

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

**Syntax Scopes**:

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

Expand Down Expand Up @@ -1348,8 +1348,6 @@ SCALE color FROM ['A', 'B'] TO ['red', 'blue']
SCALE color TO viridis
```

**Note**: Cannot specify range in both SCALE and COORD for the same aesthetic (will error).

**Examples**:

```sql
Expand Down Expand Up @@ -1422,86 +1420,97 @@ FACET region BY category
SETTING free => ['x', 'y'], spacing => 10
```

### COORD Clause
### PROJECT Clause

**Syntax**:

```sql
-- With coordinate type
COORD <type> [SETTING <properties>]

-- With properties only (defaults to cartesian)
COORD SETTING <properties>
PROJECT [<aesthetic>, ...] TO <coord_type> [SETTING <properties>]
```

**Components**:

- **Aesthetics** (optional): Comma-separated list of positional aesthetic names. If omitted, uses coord defaults.
- **TO**: Required keyword separating aesthetics from coord type.
- **coord_type**: Either `cartesian` or `polar`.
- **SETTING** (optional): Additional properties.

**Coordinate Types**:

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

**Properties by Type**:
**Flipping Axes**:

**Cartesian**:
To flip axes (for horizontal bar charts), swap the aesthetic names:

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

**Flip**:
**Common Properties** (all projection types):

- `<aesthetic> => [values...]` - Set range for any aesthetic
- `clip => <boolean>` - Whether to clip marks outside the plot area (default: unset)

**Type-Specific Properties**:

**Cartesian**:

- `ratio => <number>` - Set aspect ratio (not yet implemented)

Note: For axis limits, use `SCALE x FROM [min, max]` or `SCALE y FROM [min, max]`.

**Polar**:

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

**Important Notes**:

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

**Status**:

- ✅ **Cartesian**: Fully implemented and tested
- ✅ **Flip**: Fully implemented and tested
- ✅ **Polar**: Fully implemented and tested
- ❌ **Other types**: Not yet implemented

**Examples**:

```sql
-- Cartesian with axis limits
COORD cartesian SETTING xlim => [0, 100], ylim => [0, 50]
-- Default aesthetics (x, y for cartesian)
PROJECT TO cartesian

-- Explicit aesthetics (same as defaults)
PROJECT x, y TO cartesian

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

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

-- Flip coordinates for horizontal bar chart
COORD flip
-- Polar for pie chart (using default theta/radius aesthetics)
PROJECT TO polar

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

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

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

-- Combined with other clauses
DRAW bar MAPPING category AS x, value AS y
COORD cartesian SETTING xlim => [0, 100], ylim => [0, 200]
SCALE x FROM [0, 100]
SCALE y FROM [0, 200]
PROJECT y, x TO cartesian SETTING clip => true
LABEL x => 'Category', y => 'Count'
```

Expand Down
47 changes: 25 additions & 22 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This document provides a collection of basic examples demonstrating how to use g
- [Basic Visualizations](#basic-visualizations)
- [Multiple Layers](#multiple-layers)
- [Scales and Transformations](#scales-and-transformations)
- [Coordinate Systems](#coordinate-systems)
- [Projections](#projections)
- [Labels and Themes](#labels-and-themes)
- [Faceting](#faceting)
- [Common Table Expressions (CTEs)](#common-table-expressions-ctes)
Expand Down Expand Up @@ -125,44 +125,45 @@ SCALE DISCRETE fill FROM ['A', 'B', 'C', 'D']

---

## Coordinate Systems
## Projections

### Cartesian with Limits
### Cartesian with Axis Limits

```sql
SELECT x, y FROM data
VISUALISE x, y
DRAW point
COORD cartesian SETTING xlim => [0, 100], ylim => [0, 50]
SCALE x FROM [0, 100]
SCALE y FROM [0, 50]
```

### Flipped Coordinates (Horizontal Bar Chart)
### Flipped Projection (Horizontal Bar Chart)

```sql
SELECT category, value FROM data
ORDER BY value DESC
VISUALISE category AS x, value AS y
DRAW bar
COORD flip
PROJECT y, x TO cartesian
```

### Polar Coordinates (Pie Chart)
### Polar Projection (Pie Chart)

```sql
SELECT category, SUM(value) as total FROM data
GROUP BY category
VISUALISE category AS x, total AS y
VISUALISE total AS y, category AS fill
DRAW bar
COORD polar
PROJECT y, x TO polar
```

### Polar with Theta Specification
### Polar with Start Angle

```sql
SELECT category, value FROM data
VISUALISE category AS x, value AS y
VISUALISE value AS y, category AS fill
DRAW bar
COORD polar SETTING theta => y
PROJECT y, x TO polar SETTING start => 90
```

---
Expand Down Expand Up @@ -307,7 +308,7 @@ regional_totals AS (
)
VISUALISE region AS x, total AS y, region AS fill FROM regional_totals
DRAW bar
COORD flip
PROJECT y, x TO cartesian
LABEL title => 'Total Revenue by Region',
x => 'Region',
y => 'Total Revenue ($)'
Expand Down Expand Up @@ -373,8 +374,8 @@ WITH ranked_products AS (
SELECT * FROM ranked_products WHERE rank <= 5
VISUALISE product_name AS x, revenue AS y, category AS color
DRAW bar
FACET category SETTING scales => 'free_x'
COORD flip
FACET category SETTING free => 'x'
PROJECT y, x TO cartesian
LABEL title => 'Top 5 Products per Category',
x => 'Product',
y => 'Revenue ($)'
Expand Down Expand Up @@ -476,7 +477,7 @@ LABEL title => 'Temperature Trends',
y => 'Temperature (°C)'
```

### Categorical Analysis with Flipped Coordinates
### Categorical Analysis with Flipped Projection

```sql
SELECT
Expand All @@ -488,8 +489,9 @@ ORDER BY total_revenue DESC
LIMIT 10
VISUALISE product_name AS x, total_revenue AS y, product_name AS fill
DRAW bar
COORD flip SETTING color => ['red', 'orange', 'yellow', 'green', 'blue',
'indigo', 'violet', 'pink', 'brown', 'gray']
PROJECT y, x TO cartesian
SCALE fill TO ['red', 'orange', 'yellow', 'green', 'blue',
'indigo', 'violet', 'pink', 'brown', 'gray']
LABEL title => 'Top 10 Products by Revenue',
x => 'Product',
y => 'Revenue ($)'
Expand All @@ -510,7 +512,7 @@ DRAW point
SCALE x SETTING type => 'date'
SCALE DISCRETE color FROM ['A', 'B', 'C']
SCALE size SETTING limits => [0, 100]
COORD cartesian SETTING ylim => [0, 150]
SCALE y FROM [0, 150]
LABEL title => 'Measurement Distribution',
x => 'Date',
y => 'Value'
Expand All @@ -529,7 +531,8 @@ VISUALISE x, y, category AS color
DRAW point SETTING size => 5
DRAW text MAPPING label AS label
SCALE color TO viridis
COORD cartesian SETTING xlim => [0, 100], ylim => [0, 100]
SCALE x FROM [0, 100]
SCALE y FROM [0, 100]
LABEL title => 'Annotated Scatter Plot',
x => 'X Axis',
y => 'Y Axis'
Expand Down Expand Up @@ -630,7 +633,7 @@ Draw Line

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

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

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

Expand All @@ -640,7 +643,7 @@ Draw Line

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

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

---

Expand Down
Loading