diff --git a/doc/.gitignore b/doc/.gitignore index 06fb2886..820772f6 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -1,4 +1,5 @@ /.quarto/ **/*.quarto_ipynb +**/*.quarto_ipynb_* _site wasm diff --git a/doc/_quarto.yml b/doc/_quarto.yml index 5e464b54..c36f9543 100644 --- a/doc/_quarto.yml +++ b/doc/_quarto.yml @@ -30,7 +30,8 @@ website: keyboard-shortcut: [] navbar: left: - - get_started.qmd + - text: Get started + href: get_started/installation.qmd - text: Syntax menu: - text: Overview @@ -65,54 +66,66 @@ website: - text: Report a Bug href: https://github.com/ggsql-dev/ggsql/issues sidebar: - id: syntax - title: Syntax - style: "floating" - search: true - logo: false - contents: - - text: Overview - href: syntax/index.qmd - - section: "Main clauses" - contents: - - text: "`VISUALISE`" - href: syntax/clause/visualise.qmd - - text: "`DRAW`" - href: syntax/clause/draw.qmd - - text: "`PLACE`" - href: syntax/clause/place.qmd - - text: "`SCALE`" - href: syntax/clause/scale.qmd - - text: "`FACET`" - href: syntax/clause/facet.qmd - - text: "`PROJECT`" - href: syntax/clause/project.qmd - - text: "`LABEL`" - href: syntax/clause/label.qmd - - section: Layers - contents: - - section: Types - contents: - - auto: syntax/layer/type/* - - section: Position adjustment - contents: - - auto: syntax/layer/position/* - - section: Scales - contents: - - section: Types - contents: - - auto: syntax/scale/type/* - - section: Aesthetics - contents: - - auto: syntax/scale/aesthetic/* - - section: Coordinate systems - contents: - - auto: syntax/coord/* - + - id: syntax + title: Syntax + style: "floating" + search: true + logo: false + contents: + - text: Overview + href: syntax/index.qmd + - section: "Main clauses" + contents: + - text: "`VISUALISE`" + href: syntax/clause/visualise.qmd + - text: "`DRAW`" + href: syntax/clause/draw.qmd + - text: "`PLACE`" + href: syntax/clause/place.qmd + - text: "`SCALE`" + href: syntax/clause/scale.qmd + - text: "`FACET`" + href: syntax/clause/facet.qmd + - text: "`PROJECT`" + href: syntax/clause/project.qmd + - text: "`LABEL`" + href: syntax/clause/label.qmd + - section: Layers + contents: + - section: Types + contents: + - auto: syntax/layer/type/* + - section: Position adjustment + contents: + - auto: syntax/layer/position/* + - section: Scales + contents: + - section: Types + contents: + - auto: syntax/scale/type/* + - section: Aesthetics + contents: + - auto: syntax/scale/aesthetic/* + - section: Coordinate systems + contents: + - auto: syntax/coord/* + - id: get_started + title: Get started + style: "floating" + search: false + logo: false + contents: + - text: Installation + href: get_started/installation.qmd + - text: The first plot + href: get_started/first_plot.qmd + - text: Grammar of graphics + href: get_started/grammar.qmd format: html: lightbox: auto + highlight-style: pygments syntax-definitions: - ggsql.xml theme: diff --git a/doc/examples.qmd b/doc/examples.qmd deleted file mode 100644 index 1c1d3ffb..00000000 --- a/doc/examples.qmd +++ /dev/null @@ -1,781 +0,0 @@ ---- -title: Examples ---- - -This document demonstrates various ggsql features with runnable examples using CSV files. - -```{ggsql} -#| echo: false -#| output: false -COPY ( - SELECT * FROM (VALUES - (5.2, 18.5), - (8.7, 22.3), - (12.3, 28.9), - (15.8, 35.2), - (19.4, 42.7), - (23.1, 38.6), - (26.8, 45.1), - (30.2, 52.8), - (33.9, 48.3), - (37.5, 55.9), - (41.2, 62.4), - (44.8, 58.7), - (48.3, 65.2), - (52.1, 71.8), - (55.7, 68.1), - (59.4, 74.6) - ) AS t(x, y) -) TO 'data.csv' (HEADER, DELIMITER ',') -``` - -```{ggsql} -#| echo: false -#| output: false -COPY ( - SELECT * FROM (VALUES - ('2023-01-15'::DATE, 1000.0, 'North', 'Electronics', 5), - ('2023-02-10'::DATE, 1200.0, 'South', 'Electronics', 8), - ('2023-03-05'::DATE, 1400.0, 'East', 'Electronics', 7), - ('2023-04-20'::DATE, 1100.0, 'West', 'Electronics', 6), - ('2023-05-12'::DATE, 1600.0, 'North', 'Electronics', 9), - ('2023-06-08'::DATE, 1800.0, 'South', 'Electronics', 10), - ('2023-07-14'::DATE, 2000.0, 'East', 'Electronics', 11), - ('2023-08-22'::DATE, 2200.0, 'West', 'Electronics', 12), - ('2023-09-18'::DATE, 1900.0, 'North', 'Electronics', 8), - ('2023-10-25'::DATE, 2400.0, 'South', 'Electronics', 14), - ('2023-11-11'::DATE, 2600.0, 'East', 'Electronics', 15), - ('2023-12-05'::DATE, 3000.0, 'West', 'Electronics', 16), - ('2023-01-20'::DATE, 800.0, 'North', 'Clothing', 25), - ('2023-02-15'::DATE, 900.0, 'South', 'Clothing', 30), - ('2023-03-10'::DATE, 1100.0, 'East', 'Clothing', 35), - ('2023-04-25'::DATE, 1300.0, 'West', 'Clothing', 38), - ('2023-05-18'::DATE, 1500.0, 'North', 'Clothing', 42), - ('2023-06-12'::DATE, 1700.0, 'South', 'Clothing', 45), - ('2023-07-20'::DATE, 1900.0, 'East', 'Clothing', 48), - ('2023-08-28'::DATE, 2100.0, 'West', 'Clothing', 50), - ('2023-09-22'::DATE, 2300.0, 'North', 'Clothing', 52), - ('2023-10-30'::DATE, 2500.0, 'South', 'Clothing', 55), - ('2023-11-15'::DATE, 2700.0, 'East', 'Clothing', 58), - ('2023-12-10'::DATE, 2900.0, 'West', 'Clothing', 60), - ('2023-01-25'::DATE, 600.0, 'North', 'Furniture', 3), - ('2023-02-18'::DATE, 700.0, 'South', 'Furniture', 3), - ('2023-03-15'::DATE, 850.0, 'East', 'Furniture', 4), - ('2023-04-28'::DATE, 950.0, 'West', 'Furniture', 4), - ('2023-05-22'::DATE, 1050.0, 'North', 'Furniture', 5), - ('2023-06-16'::DATE, 1150.0, 'South', 'Furniture', 5), - ('2023-07-24'::DATE, 1250.0, 'East', 'Furniture', 5), - ('2023-08-30'::DATE, 1350.0, 'West', 'Furniture', 6), - ('2023-09-26'::DATE, 1450.0, 'North', 'Furniture', 6), - ('2023-10-31'::DATE, 1550.0, 'South', 'Furniture', 6), - ('2023-11-20'::DATE, 1650.0, 'East', 'Furniture', 7), - ('2023-12-15'::DATE, 1750.0, 'West', 'Furniture', 7) - ) AS t(sale_date, revenue, region, category, quantity) -) TO 'sales.csv' (HEADER, DELIMITER ',') -``` - -```{ggsql} -#| echo: false -#| output: false -COPY ( - SELECT * FROM (VALUES - ('2023-01-01'::DATE, 100.0), - ('2023-01-08'::DATE, 110.0), - ('2023-01-15'::DATE, 105.0), - ('2023-01-22'::DATE, 115.0), - ('2023-01-29'::DATE, 120.0), - ('2023-02-05'::DATE, 118.0), - ('2023-02-12'::DATE, 125.0), - ('2023-02-19'::DATE, 130.0), - ('2023-02-26'::DATE, 128.0), - ('2023-03-05'::DATE, 135.0), - ('2023-03-12'::DATE, 142.0), - ('2023-03-19'::DATE, 138.0), - ('2023-03-26'::DATE, 145.0), - ('2023-04-02'::DATE, 150.0), - ('2023-04-09'::DATE, 148.0), - ('2023-04-16'::DATE, 155.0), - ('2023-04-23'::DATE, 160.0), - ('2023-04-30'::DATE, 158.0), - ('2023-05-07'::DATE, 165.0), - ('2023-05-14'::DATE, 170.0) - ) AS t(date, value) -) TO 'timeseries.csv' (HEADER, DELIMITER ',') -``` - -```{ggsql} -#| echo: false -#| output: false -COPY ( - SELECT * FROM (VALUES - ('2023-01-01'::DATE, 45.2, 'Sales'), - ('2023-02-01'::DATE, 52.1, 'Sales'), - ('2023-03-01'::DATE, 48.7, 'Sales'), - ('2023-04-01'::DATE, 58.3, 'Sales'), - ('2023-05-01'::DATE, 62.5, 'Sales'), - ('2023-06-01'::DATE, 67.8, 'Sales'), - ('2023-07-01'::DATE, 71.2, 'Sales'), - ('2023-08-01'::DATE, 75.6, 'Sales'), - ('2023-09-01'::DATE, 80.1, 'Sales'), - ('2023-10-01'::DATE, 85.4, 'Sales'), - ('2023-11-01'::DATE, 90.2, 'Sales'), - ('2023-12-01'::DATE, 95.8, 'Sales'), - ('2023-01-01'::DATE, 120.5, 'Marketing'), - ('2023-02-01'::DATE, 135.2, 'Marketing'), - ('2023-03-01'::DATE, 128.9, 'Marketing'), - ('2023-04-01'::DATE, 142.3, 'Marketing'), - ('2023-05-01'::DATE, 155.7, 'Marketing'), - ('2023-06-01'::DATE, 148.2, 'Marketing'), - ('2023-07-01'::DATE, 162.8, 'Marketing'), - ('2023-08-01'::DATE, 175.4, 'Marketing'), - ('2023-09-01'::DATE, 168.9, 'Marketing'), - ('2023-10-01'::DATE, 182.5, 'Marketing'), - ('2023-11-01'::DATE, 195.1, 'Marketing'), - ('2023-12-01'::DATE, 188.7, 'Marketing'), - ('2023-01-01'::DATE, 78.3, 'Support'), - ('2023-02-01'::DATE, 82.1, 'Support'), - ('2023-03-01'::DATE, 75.6, 'Support'), - ('2023-04-01'::DATE, 85.9, 'Support'), - ('2023-05-01'::DATE, 92.4, 'Support'), - ('2023-06-01'::DATE, 88.7, 'Support'), - ('2023-07-01'::DATE, 95.2, 'Support'), - ('2023-08-01'::DATE, 101.8, 'Support'), - ('2023-09-01'::DATE, 97.5, 'Support'), - ('2023-10-01'::DATE, 105.3, 'Support'), - ('2023-11-01'::DATE, 112.6, 'Support'), - ('2023-12-01'::DATE, 108.9, 'Support') - ) AS t(date, value, category) -) TO 'metrics.csv' (HEADER, DELIMITER ',') -``` - -## Basic Visualizations - -### Simple Scatter Plot - -```{ggsql} -SELECT x, y FROM 'data.csv' -VISUALISE x, y -DRAW point -``` - -```{ggsql} -VISUALISE bill_len AS x, bill_dep AS y, species AS color FROM ggsql:penguins -DRAW point -``` - -### Line Chart with Date Scale - -```{ggsql} -SELECT sale_date, revenue FROM 'sales.csv' -WHERE category = 'Electronics' -VISUALISE sale_date AS x, revenue AS y -DRAW line -SCALE x VIA date -LABEL - title => 'Electronics Revenue Over Time', - x => 'Date', - y => 'Revenue ($)' -``` - -```{ggsql} -SELECT * FROM ggsql:airquality -VISUALISE Date AS x -DRAW line MAPPING Ozone AS y, 'Ozone' AS color -DRAW line MAPPING Temp AS y, 'Temp' AS color -``` - -### Bar Chart by Category - -```{ggsql} -SELECT category, SUM(revenue) as total -FROM 'sales.csv' -GROUP BY category -VISUALISE category AS x, total AS y, category AS fill -DRAW bar -LABEL - title => 'Total Revenue by Category', - x => 'Category', - y => 'Total Revenue ($)' -``` - -### Line chart with multiple lines with same aesthetics - -```{ggsql} -SELECT * FROM 'sales.csv' -VISUALISE sale_date AS x, revenue AS y -DRAW line - PARTITION BY category -``` - -## Statistical Transformations - -Statistical transformations automatically compute aggregations for certain geom types. - -### Histogram - -When using `DRAW histogram`, ggsql automatically bins continuous data and counts occurrences. You only need to specify the x aesthetic: - -```{ggsql} -SELECT revenue FROM 'sales.csv' -VISUALISE revenue AS x -DRAW histogram -LABEL - title => 'Revenue Distribution', - x => 'Revenue ($)', - y => 'Count' -``` - -### Bar with Automatic Count - -When using `DRAW bar` without a y aesthetic, ggsql automatically counts occurrences of each x value: - -```{ggsql} -SELECT category FROM 'sales.csv' -VISUALISE category AS x -DRAW bar -LABEL - title => 'Sales Count by Category', - x => 'Category', - y => 'Count' -``` - -### Bar with Weighted Count - -You can also specify a weight aesthetic to sum values instead of counting: - -```{ggsql} -SELECT category, revenue FROM 'sales.csv' -VISUALISE category AS x, revenue AS weight -DRAW bar -LABEL - title => 'Total Revenue by Category', - x => 'Category', - y => 'Revenue ($)' -``` - -### Histogram Settings - -Control histogram binning with `SETTING` options: - -**Custom number of bins:** - -```{ggsql} -SELECT revenue FROM 'sales.csv' -VISUALISE revenue AS x -DRAW histogram - SETTING bins => 10 -LABEL - title => 'Revenue Distribution (10 bins)', - x => 'Revenue ($)', - y => 'Count' -``` - -**Explicit bin width** (overrides bins): - -```{ggsql} -SELECT revenue FROM 'sales.csv' -VISUALISE revenue AS x -DRAW histogram - SETTING binwidth => 500 -LABEL - title => 'Revenue Distribution (500 bin width)', - x => 'Revenue ($)', - y => 'Count' -``` - -**Left-closed intervals** (default is right-closed `(a, b]`): - -```{ggsql} -SELECT revenue FROM 'sales.csv' -VISUALISE revenue AS x -DRAW histogram - SETTING bins => 8, closed => 'left' -LABEL - title => 'Revenue Distribution (left-closed intervals)', - x => 'Revenue ($)', - y => 'Count' -``` - -### Histogram Remapping - -Histogram computes several statistics: `bin`, `bin_end`, `count`, and `density`. By default, `count` is mapped to `y`. Use `REMAPPING` to show density (proportion) instead: - -```{ggsql} -SELECT revenue FROM 'sales.csv' -VISUALISE revenue AS x -DRAW histogram - REMAPPING density AS y -LABEL - title => 'Revenue Density Distribution', - x => 'Revenue ($)', - y => 'Density' -``` - -### Bar Width Setting - -Control bar width with the `width` setting (0-1 scale, default 0.9): - -```{ggsql} -SELECT category FROM 'sales.csv' -VISUALISE category AS x -DRAW bar - SETTING width => 0.5 -LABEL - title => 'Sales Count (Narrow Bars)', - x => 'Category', - y => 'Count' -``` - -### Bar Remapping - -Bar computes `count` and `proportion` statistics. By default, `count` is mapped to `y`. Use `REMAPPING` to show proportions instead: - -```{ggsql} -SELECT category FROM 'sales.csv' -VISUALISE category AS x -DRAW bar - REMAPPING proportion AS y -LABEL - title => 'Sales Proportion by Category', - x => 'Category', - y => 'Proportion' -``` - -Combine with `weight` to show weighted proportions: - -```{ggsql} -SELECT category, revenue FROM 'sales.csv' -VISUALISE category AS x, revenue AS weight -DRAW bar - REMAPPING proportion AS y -LABEL - title => 'Revenue Share by Category', - x => 'Category', - y => 'Share of Total Revenue' -``` - -## Multiple Layers - -### Line with Points - -```{ggsql} -SELECT date, value FROM 'timeseries.csv' -VISUALISE date AS x, value AS y -DRAW line - SETTING color => 'blue' -DRAW point - SETTING size => 6, color => 'red' -SCALE x VIA date -LABEL - title => 'Time Series with Points', - x => 'Date', - y => 'Value' -``` - -### Colored Lines by Category - -```{ggsql} -SELECT date, value, category FROM 'metrics.csv' -VISUALISE date AS x, value AS y, category AS color -DRAW line -SCALE x VIA date -LABEL - title => 'Metrics by Category', - x => 'Date', - y => 'Value' -``` - -## Faceting - -### Facet by Region - -```{ggsql} -SELECT sale_date, revenue, region FROM 'sales.csv' -WHERE category = 'Electronics' -VISUALISE sale_date AS x, revenue AS y -DRAW line -SCALE x VIA date -FACET region -LABEL - title => 'Electronics Sales by Region', - x => 'Date', - y => 'Revenue ($)' -``` - -### Facet Grid - -```{ggsql} -SELECT - DATE_TRUNC('month', sale_date) as month, - region, - category, - SUM(revenue) as total_revenue, - SUM(quantity) * 100 as total_quantity_scaled -FROM 'sales.csv' -GROUP BY DATE_TRUNC('month', sale_date), region, category -VISUALISE month AS x -DRAW line - MAPPING total_revenue AS y - SETTING color => 'steelblue' -DRAW point - MAPPING total_revenue AS y - SETTING size => 6, color => 'darkblue' -DRAW line - MAPPING total_quantity_scaled AS y - SETTING color => 'coral' -DRAW point - MAPPING total_quantity_scaled AS y - SETTING size => 6, color => 'orangered' -SCALE x VIA date -FACET region BY category -LABEL - title => 'Monthly Revenue and Quantity by Region and Category', - x => 'Month', - y => 'Value' -``` - -## Projections - -### Pie Chart with Polar Coordinates - -```{ggsql} -SELECT category, SUM(revenue) as total -FROM 'sales.csv' -GROUP BY category -VISUALISE total AS y, category AS fill -DRAW bar -PROJECT y, x TO polar -LABEL - title => 'Revenue Distribution by Category' -``` - -## Constant Mappings - -Constants can be used in both the VISUALISE clause (global) and MAPPING clauses (per-layer) to set fixed aesthetic values. - -### Different Constants Per Layer - -Each layer can have its own constant value, creating a legend showing all values: - -```{ggsql} -WITH monthly AS ( - SELECT - DATE_TRUNC('month', sale_date) as month, - category, - SUM(revenue) as revenue - FROM 'sales.csv' - GROUP BY DATE_TRUNC('month', sale_date), category -) -VISUALISE month AS x, revenue AS y -DRAW line - MAPPING 'Electronics' AS color FROM monthly - FILTER category = 'Electronics' -DRAW line - MAPPING 'Clothing' AS color FROM monthly - FILTER category = 'Clothing' -DRAW line - MAPPING 'Furniture' AS color FROM monthly - FILTER category = 'Furniture' -SCALE x VIA date -LABEL - title => 'Revenue by Category (Constant Colors)', - x => 'Month', - y => 'Revenue ($)' -``` - -### Mixed Constants and Columns - -When mixing constant and column mappings for the same aesthetic, the axis/legend label uses the first non-constant column name: - -```{ggsql} -SELECT date, value, category FROM 'metrics.csv' -VISUALISE date AS x -DRAW line - MAPPING value AS y, category AS color -DRAW point - MAPPING 120 AS y - SETTING size => 3, color => 'blue' -SCALE x VIA date -LABEL - title => 'Metrics with Threshold Line', - x => 'Date' -``` - -### Numeric Constants - -Numbers work as constants too: - -```{ggsql} -SELECT x, y FROM 'data.csv' -VISUALISE x, y -DRAW point - SETTING color => 'blue', size => 10 -DRAW point - SETTING color => 'red', size => 5 - FILTER y > 50 -LABEL - title => 'Scatter Plot with Constant Sizes' -``` - -## Layer filtering - -### Filter one layer - -```{ggsql} -SELECT date, value FROM 'timeseries.csv' -VISUALISE date AS x, value AS y -DRAW line - SETTING color => 'blue' -DRAW point - SETTING color => 'red', size => 6 - FILTER value < 130 -SCALE x VIA date -LABEL - title => 'Time Series with Points', - x => 'Date', - y => 'Value' -``` - -## Layer ordering - -### ORDER BY in a layer - -Use `ORDER BY` to ensure data is sorted correctly within a layer. This is especially important for line charts where the order of points affects the visual path: - -```{ggsql} -WITH unordered_data AS ( - SELECT * FROM (VALUES - (150.0, '2023-03-01'::DATE), - (100.0, '2023-01-01'::DATE), - (120.0, '2023-05-01'::DATE), - (200.0, '2023-02-01'::DATE), - (180.0, '2023-04-01'::DATE) - ) AS t(value, date) -) -VISUALISE -DRAW path - MAPPING date AS x, value AS y FROM unordered_data - ORDER BY date -DRAW point - MAPPING date AS x, value AS y FROM unordered_data - SETTING size => 6, color => 'red' -SCALE x VIA date -LABEL - title => 'Line Chart with ORDER BY', - x => 'Date', - y => 'Value' -``` - -### Combining FILTER and ORDER BY - -The `ORDER BY` clause can be combined with `FILTER` and other layer options: - -```{ggsql} -SELECT date, value, category FROM 'metrics.csv' -VISUALISE -DRAW path - MAPPING date AS x, value AS y, category AS color - FILTER category != 'Support' - ORDER BY value -DRAW point - MAPPING date AS x, value AS y, category AS color - SETTING size => 3 - FILTER category != 'Support' -SCALE x VIA date -LABEL - title => 'Sales and Marketing Metrics (Ordered)', - x => 'Date', - y => 'Value' -``` - -## Common Table Expressions (CTEs) - -### Simple CTE with VISUALISE FROM - -```{ggsql} -WITH monthly_sales AS ( - SELECT - DATE_TRUNC('month', sale_date) as month, - SUM(revenue) as total_revenue - FROM 'sales.csv' - GROUP BY DATE_TRUNC('month', sale_date) -) -VISUALISE month AS x, total_revenue AS y FROM monthly_sales -DRAW line -DRAW point -SCALE x VIA date -LABEL - title => 'Monthly Revenue Trends', - x => 'Month', - y => 'Revenue ($)' -``` - -### Multiple CTEs - -```{ggsql} -WITH daily_sales AS ( - SELECT sale_date, region, SUM(revenue) as revenue - FROM 'sales.csv' - GROUP BY sale_date, region -), -regional_totals AS ( - SELECT region, SUM(revenue) as total - FROM daily_sales - GROUP BY region -) -VISUALISE region AS x, total AS y, region AS fill FROM regional_totals -DRAW bar -PROJECT y, x TO cartesian -LABEL - title => 'Total Revenue by Region', - x => 'Region', - y => 'Total Revenue ($)' -``` - -## Layer-Specific Data Sources (MAPPING FROM) - -Layers can pull data from different sources using `MAPPING FROM`. This enables overlaying data from different CTEs or tables. - -### Comparing Actuals vs Targets - -Each layer can reference a different CTE using `MAPPING ... FROM cte_name`: - -```{ggsql} -WITH actuals AS ( - SELECT - DATE_TRUNC('month', sale_date) as month, - SUM(revenue) as value - FROM 'sales.csv' - GROUP BY DATE_TRUNC('month', sale_date) -), -targets AS ( - SELECT * FROM (VALUES - ('2023-01-01'::DATE, 5000.0), - ('2023-02-01'::DATE, 5500.0), - ('2023-03-01'::DATE, 6000.0), - ('2023-04-01'::DATE, 6500.0), - ('2023-05-01'::DATE, 7000.0), - ('2023-06-01'::DATE, 7500.0), - ('2023-07-01'::DATE, 8000.0), - ('2023-08-01'::DATE, 8500.0), - ('2023-09-01'::DATE, 9000.0), - ('2023-10-01'::DATE, 9500.0), - ('2023-11-01'::DATE, 10000.0), - ('2023-12-01'::DATE, 10500.0) - ) AS t(month, value) -) -VISUALISE -DRAW line - MAPPING month AS x, value AS y, 'Actual' AS color FROM actuals -DRAW point - MAPPING month AS x, value AS y, 'Actual' AS color FROM actuals - SETTING size => 6 -DRAW line - MAPPING month AS x, value AS y, 'Target' AS color FROM targets -SCALE x VIA date -LABEL - title => 'Revenue: Actual vs Target', - x => 'Month', - y => 'Revenue ($)' -``` - -### CTE Chain: Raw → Filtered → Aggregated - -CTEs can reference other CTEs, creating a data transformation pipeline: - -```{ggsql} -WITH raw_data AS ( - SELECT sale_date, revenue, category, region - FROM 'sales.csv' -), -electronics_only AS ( - SELECT * FROM raw_data - WHERE category = 'Electronics' -), -monthly_electronics AS ( - SELECT - DATE_TRUNC('month', sale_date) as month, - region, - SUM(revenue) as total - FROM electronics_only - GROUP BY DATE_TRUNC('month', sale_date), region -) -VISUALISE month AS x, total AS y, region AS color FROM monthly_electronics -DRAW line -DRAW point -SCALE x VIA date -LABEL - title => 'Electronics Revenue by Region (CTE Chain)', - x => 'Month', - y => 'Revenue ($)' -``` - -### Layer FROM with FILTER - -Combine `FROM` with `FILTER` to get filtered subsets from a CTE: - -```{ggsql} -WITH all_sales AS ( - SELECT - DATE_TRUNC('month', sale_date) as month, - category, - SUM(revenue) as revenue - FROM 'sales.csv' - GROUP BY DATE_TRUNC('month', sale_date), category -) -VISUALISE -DRAW line - MAPPING month AS x, revenue AS y, 'All Categories' AS color FROM all_sales -DRAW line - MAPPING month AS x, revenue AS y, 'Electronics' AS color FROM all_sales - FILTER category = 'Electronics' -DRAW line - MAPPING month AS x, revenue AS y, 'Clothing' AS color FROM all_sales - FILTER category = 'Clothing' -SCALE x VIA date -LABEL - title => 'Revenue by Category (Filtered Layers)', - x => 'Month', - y => 'Revenue ($)' -``` - -## Advanced Examples - -### Complete Regional Sales Analysis - -```{ggsql} -SELECT - sale_date, - region, - SUM(quantity) as total_quantity -FROM 'sales.csv' -WHERE sale_date >= '2023-01-01' -GROUP BY sale_date, region -ORDER BY sale_date -VISUALISE sale_date AS x, total_quantity AS y, region AS color -DRAW line -DRAW point -SCALE x VIA date -FACET region -LABEL - title => 'Sales Trends by Region', - x => 'Date', - y => 'Total Quantity' -``` - -### Multi-Category Analysis - -```{ggsql} -SELECT - category, - region, - SUM(revenue) as total_revenue -FROM 'sales.csv' -GROUP BY category, region -VISUALISE category AS x, total_revenue AS y, region AS fill -DRAW bar -LABEL - title => 'Revenue by Category and Region', - x => 'Category', - y => 'Revenue ($)' -``` diff --git a/doc/faq.qmd b/doc/faq.qmd index 20a3488a..2f28372b 100644 --- a/doc/faq.qmd +++ b/doc/faq.qmd @@ -1,8 +1,8 @@ --- -title: Frequently Asked Questions +title: Frequently asked questions --- -## Getting Started +## Getting started ::: {.callout-note collapse="true"} ## What is ggsql? @@ -19,7 +19,7 @@ DRAW line ::: {.callout-note collapse="true"} ## How do I install ggsql? -See the installation instruction in the [Getting started](get_started.qmd) tutorial. +See the installation instruction in the [Get started](get_started/installation.qmd) tutorial. ::: ::: {.callout-note collapse="true"} @@ -34,7 +34,7 @@ ggsql is built in a modular way so we can gradually add new backends to it. Curr We have designed ggsql to be modular, both when it comes to the database input and the final rendering. For the first phase of the development we have chosen to use Vegalite as a renderer as it has allowed us to iterate quickly, but we do not envision Vegalite to remain the only, nor default writer in the future. ::: -## Syntax & Usage +## Syntax & usage ::: {.callout-note collapse="true"} ## What's the difference between `VISUALISE` and `VISUALIZE`? diff --git a/doc/gallery/examples/bar-chart.qmd b/doc/gallery/examples/bar-chart.qmd index 42ab2382..8dba452c 100644 --- a/doc/gallery/examples/bar-chart.qmd +++ b/doc/gallery/examples/bar-chart.qmd @@ -1,5 +1,5 @@ --- -title: "Bar Chart" +title: "Bar chart" description: "Categorical comparisons using bars" image: thumbnails/bar-chart.svg categories: [basic, bar] @@ -31,7 +31,7 @@ LABEL ## Variations -### Horizontal Bars +### Horizontal bars Use `PROJECT y, x TO cartesian` to flip the axes for horizontal bars: @@ -47,7 +47,7 @@ LABEL y => 'Count' ``` -### Auto-Count Bar Chart +### Auto-count bar chart When you don't specify a y aesthetic, ggsql automatically counts occurrences: diff --git a/doc/gallery/examples/faceted.qmd b/doc/gallery/examples/faceted.qmd index 84e204c2..c06d5f94 100644 --- a/doc/gallery/examples/faceted.qmd +++ b/doc/gallery/examples/faceted.qmd @@ -1,5 +1,5 @@ --- -title: "Faceted Plot" +title: "Faceted plot" description: "Small multiples showing data split by category" image: thumbnails/faceted.svg categories: [faceted, advanced] @@ -29,7 +29,7 @@ LABEL ## Variations -### Grid Layout with Two Variables +### Grid layout with two variables Use `FACET rows BY cols` to create a grid layout: @@ -44,7 +44,7 @@ LABEL y => 'Bill Depth (mm)' ``` -### Free Scales +### Free scales Allow each facet to have independent axis scales with `SETTING free`: diff --git a/doc/gallery/examples/histogram.qmd b/doc/gallery/examples/histogram.qmd index b2479317..256650dc 100644 --- a/doc/gallery/examples/histogram.qmd +++ b/doc/gallery/examples/histogram.qmd @@ -28,7 +28,7 @@ LABEL ## Variations -### Custom Bin Count +### Custom bin count Control the number of bins with `SETTING bins`: @@ -43,7 +43,7 @@ LABEL y => 'Count' ``` -### Custom Bin Width +### Custom bin width Set explicit bin width instead of count: @@ -58,7 +58,7 @@ LABEL y => 'Count' ``` -### Density Instead of Count +### Density instead of count Use `REMAPPING` to show density (proportion) instead of count: diff --git a/doc/gallery/examples/line-chart.qmd b/doc/gallery/examples/line-chart.qmd index e988113b..d398c755 100644 --- a/doc/gallery/examples/line-chart.qmd +++ b/doc/gallery/examples/line-chart.qmd @@ -1,5 +1,5 @@ --- -title: "Line Chart" +title: "Line chart" description: "Time series visualization with proper date scaling" image: thumbnails/line-chart.svg categories: [basic, line, time-series] @@ -31,7 +31,7 @@ LABEL ## Variations -### Multiple Lines by Category +### Multiple lines by category ```{ggsql} SELECT Date, Temp, Month FROM ggsql:airquality diff --git a/doc/gallery/examples/multi-layer.qmd b/doc/gallery/examples/multi-layer.qmd index b0a4924f..0d7f9c69 100644 --- a/doc/gallery/examples/multi-layer.qmd +++ b/doc/gallery/examples/multi-layer.qmd @@ -1,5 +1,5 @@ --- -title: "Multi-Layer Plot" +title: "Multi-layer plot" description: "Combining multiple geometric layers in one visualization" image: thumbnails/multi-layer.svg categories: [layers, advanced] @@ -33,7 +33,7 @@ LABEL ## Variations -### Different Aesthetics Per Layer +### Different aesthetics per layer Each layer can have its own aesthetic mappings using `MAPPING`: @@ -51,7 +51,7 @@ LABEL y => 'Value' ``` -### Layers from Different Data Sources +### Layers from different data sources Use `MAPPING ... FROM` to pull each layer from different CTEs: diff --git a/doc/gallery/examples/scatterplot.qmd b/doc/gallery/examples/scatterplot.qmd index e3d59100..85249711 100644 --- a/doc/gallery/examples/scatterplot.qmd +++ b/doc/gallery/examples/scatterplot.qmd @@ -1,5 +1,5 @@ --- -title: "Scatter Plot" +title: "Scatter plot" description: "Basic scatter plot mapping two numeric variables to position" image: thumbnails/scatterplot.svg categories: [basic, point] @@ -28,7 +28,7 @@ LABEL ## Variations -### With Color by Species +### With color by species ```{ggsql} VISUALISE bill_len AS x, bill_dep AS y, species AS color FROM ggsql:penguins diff --git a/doc/gallery/examples/thumbnails/bar-chart.svg b/doc/gallery/examples/thumbnails/bar-chart.svg index 19dfe657..f664c45f 100644 --- a/doc/gallery/examples/thumbnails/bar-chart.svg +++ b/doc/gallery/examples/thumbnails/bar-chart.svg @@ -1 +1 @@ -AdelieChinstrapGentooSpecies050100150CountAdelieChinstrapGentoospeciesPenguin Count by Species \ No newline at end of file +AdelieChinstrapGentooSpecies050100150CountAdelieChinstrapGentoospeciesPenguin Count by Species \ No newline at end of file diff --git a/doc/gallery/index.qmd b/doc/gallery/index.qmd index 5acd6f8a..41e4824e 100644 --- a/doc/gallery/index.qmd +++ b/doc/gallery/index.qmd @@ -1,5 +1,5 @@ --- -title: Example Gallery +title: Example gallery listing: contents: examples type: grid diff --git a/doc/get_started.qmd b/doc/get_started.qmd deleted file mode 100644 index 7cdd4618..00000000 --- a/doc/get_started.qmd +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: "Getting started" ---- - - - -Before you spend time on the minutia of installing ggsql — not that it is particularly daunting — why not try it out right now, right here, in your browser? - -The code below shows a simple ggsql example. But it is not just a static piece of text and an image. It is ggsql running right in your browser, using one of the built-in datasets. Try to change e.g. the title and see the plot update as you type. Even though this may be your first encounter with the ggsql syntax you might already get a sense of how some of the things fit together. See if you can change the code to instead show the different species as different shapes - -```{ggsql} -VISUALISE bill_len AS x, bill_dep AS y, species AS fill FROM ggsql:penguins -DRAW point -SCALE x RENAMING * => '{} mm' -LABEL - title => 'Relationship between bill dimensions in 3 species of penguins', - x => 'Bill length', - y => 'Bill depth' -``` - -Congratulations! You have started your journey with ggsql! All examples you see on this site will be interactive. Please experiment to your heart's content. If you want a more dedicated exploration experience head to [our playground](wasm/) which provides a simple IDE with a number of examples to try out. - -Now that you have gotten a feel for ggsql you may want to try running locally with your own data. Read on to learn how. - -## Installation - -### Building from Source - -If you prefer to build from source or need the latest development version: - -1. **Clone the repository:** - - ```bash - git clone https://github.com/posit-dev/ggsql - cd ggsql - ``` - -2. **Install tree-sitter CLI:** - - ```bash - npm install -g tree-sitter-cli - ``` - -3. **Build the project:** - - ```bash - cd tree-sitter-ggsql && tree-sitter generate && cd .. - cargo build --release - ``` - -4. **Install the CLI:** - ```bash - cargo install --path src - ``` - -5. **Install the Jupyter kernel (optional):** - ```bash - cargo install --path ggsql-jupyter - ggsql-jupyter --install - ``` - diff --git a/doc/get_started/_metadata.yml b/doc/get_started/_metadata.yml new file mode 100644 index 00000000..08d3e224 --- /dev/null +++ b/doc/get_started/_metadata.yml @@ -0,0 +1,3 @@ +sidebar: get_started +page-navigation: true +toc: false diff --git a/doc/get_started/first_plot.qmd b/doc/get_started/first_plot.qmd new file mode 100644 index 00000000..56027f6d --- /dev/null +++ b/doc/get_started/first_plot.qmd @@ -0,0 +1,19 @@ +--- +title: "Your first plot" +--- + +The code below shows a simple ggsql example. But it is not just a static piece of text and an image. It is ggsql running right in your browser, using one of the built-in datasets. Try to change e.g. the title and see the plot update as you type. Even though this may be your first encounter with the ggsql syntax you might already get a sense of how some of the things fit together. See if you can change the code to instead show the different species as different shapes + +```{ggsql} +VISUALISE bill_len AS x, bill_dep AS y, species AS fill FROM ggsql:penguins +DRAW point +SCALE x RENAMING * => '{} mm' +LABEL + title => 'Relationship between bill dimensions in 3 species of penguins', + x => 'Bill length', + y => 'Bill depth' +``` + +Congratulations! You have started your journey with ggsql! All examples you see on this site will be interactive. Please experiment to your heart's content. If you want a more dedicated exploration experience head to [our playground](wasm/) which provides a simple IDE with a number of examples to try out. + +Before we move further, you might have some questions about the syntax. For instance, "why isn't there just a scatterplot function?". The next section will give a brief glimpse into the concept of the grammar of graphics that underpin the ggsql syntax and why we think it is a superior approach to data visualisation. diff --git a/doc/get_started/grammar.qmd b/doc/get_started/grammar.qmd new file mode 100644 index 00000000..bc1bf860 --- /dev/null +++ b/doc/get_started/grammar.qmd @@ -0,0 +1,24 @@ +--- +title: The grammar of graphics +--- + +ggsql is a tool for visualising data, combining our 20 years of experience developing [ggplot2](https://ggplot2.tidyverse.org/) with a SQL-native syntax. +Unlike most visualisation systems, ggsql has an underlying grammar, based on the [Grammar of Graphics](https://en.wikipedia.org/wiki/Wilkinson%27s_Grammar_of_Graphics) by Leland Wilkinson. +This is a different approach than the one taken by most tools, which give you a set of pre-defined graphics, like scatterplots, bar charts, and pie charts. +ggsql instead gives you a number of independent components that you can combine to solve a very wide set of problems. + +This means there's a learning curve to ggsql: you have to learn a few big ideas about the grammar before you can be productive. +But we believe the payoff is worth it. +The grammar gives you new vocabulary and new ways to think about visualizations. +This allows you to create not only familiar graphics but also newer, better graphics. +You'll gain the ability to look at a visualization that someone else has made, analyse the key components, then recreate it yourself. +The hardest part of learning ggsql is likely to be unlearning the preconceptions that you bring over from previous visualization tools. + +We've tried to make the learning curve as easy as possible by keeping the grammar close to the SQL syntax that you're already familiar with. +You'll start with a classic `SELECT` statement to get the data that you want. +Then you'll use `VISUALIZE` (or `VISUALISE` 🇬🇧) to switch from creating a table of data to creating a plot of that data. +Then you'll `DRAW` a layer that maps columns in your data to aesthetics (visual properties), like position, colour, and shape. +Then you tweak the `SCALE`s, the mappings between the data and the visual properties, to make the plot easier to read. +Then you `FACET` the plot to show how the relationships differ across subsets of the data. +Finally you finish up by adding `LABEL`s to explain your plot to others. +This allows you to produce graphics using the same structured thinking that you already use to design a SQL query. diff --git a/doc/get_started/installation.qmd b/doc/get_started/installation.qmd new file mode 100644 index 00000000..3ed99dac --- /dev/null +++ b/doc/get_started/installation.qmd @@ -0,0 +1,286 @@ +--- +title: "Installation" +--- + +While all of the examples on this website uses the ggsql WebAssembly build to let you run it in the browser, you'll likely want it on your own computer, interfacing with your local data. + +ggsql provides native installers for Windows, macOS, and Linux. Choose the best option for your platform below. + +::: {#installer-recommended} + +::: + +### All platforms + +::: {#installer-table} + +::: + +```{=html} + + + +``` + + +::: {.icon-section} +[![](../assets/logos/jupyter.svg){height=60} ![](../assets/logos/quarto.svg){height=60}]{.section-icons} + +## Jupyter kernel + +To use ggsql in Jupyter or Quarto notebooks, install the Jupyter kernel using either `uv` (recommended) or `cargo`. The kernel is also part of the main installer linked to above. + +#### Using uv + +[uv](https://docs.astral.sh/uv/) is the fastest way to install the binaries: + +```bash +uv tool install ggsql-jupyter +ggsql-jupyter --install +``` + +#### Using cargo + +If you have a Rust toolchain installed you can install with cargo: + +```bash +cargo install ggsql-jupyter +ggsql-jupyter --install +``` +::: + +::: {.icon-section} +[![](../assets/logos/vscode.svg){height=60} ![](../assets/logos/positron.svg){height=60}]{.section-icons} + +## VS Code / Positron extension + +For syntax highlighting and language support in VS Code or Positron, install the ggsql extension. You can either install it directly from the [extension marketplace](https://open-vsx.org/extension/ggsql/ggsql) from within the IDE or download and install it manually: + +1. Download [`ggsql.vsix`](https://github.com/posit-dev/ggsql/releases/latest/download/ggsql.vsix) +2. Install via the command line: + +```bash +# VS Code +code --install-extension ggsql.vsix + +# Positron +positron --install-extension ggsql.vsix +``` + +Or install from within the editor: open the Extensions view, click the `...` menu, select "Install from VSIX...", and choose the downloaded file. +::: diff --git a/doc/index.qmd b/doc/index.qmd index ca61e912..19fca57f 100644 --- a/doc/index.qmd +++ b/doc/index.qmd @@ -24,11 +24,11 @@ include-in-header: # QUERY ![](assets/visualize.svg){.hviz aria-hidden="true"}VISUALIZE UNDERSTAND ::: {.hero-body} -ggsql brings the elegance of the Grammar of Graphics to SQL. Write familiar queries, add visualization clauses, and see your data transform into beautiful, composable charts — no context switching, no separate tools, just SQL with superpowers. +ggsql brings the elegance of the [Grammar of Graphics](get_started/grammar.qmd) to SQL. Write familiar queries, add visualization clauses, and see your data transform into beautiful, composable charts — no context switching, no separate tools, just SQL with superpowers. ::: {.hero-buttons} -[Get Started](get_started.qmd){.btn .btn-primary .btn-lg} -[View Examples](gallery/index.qmd){.btn .btn-outline-primary .btn-lg} +[Get started](get_started/installation.qmd){.btn .btn-primary .btn-lg} +[View examples](gallery/index.qmd){.btn .btn-outline-primary .btn-lg} ::: ::: @@ -37,8 +37,6 @@ ggsql brings the elegance of the Grammar of Graphics to SQL. Write familiar quer ::: {.content-block .dark-bg} ### Try it out -ggsql runs in the browser as well! Edit the code and watch the plot update. - ```{ggsql} -- Regular query SELECT * FROM ggsql:penguins @@ -70,15 +68,29 @@ LABEL ::: {.content-block .dark-bg .install-section} ### Install it today -::: {#installer-buttons} +::: {.install-columns} +::: {.install-col .install-col-left} +::: {#installer-recommended} ::: -::: {.install-cli-options} -**Or via command line:** -`uv pip install ggsql-jupyter && ggsql-jupyter --install` -· -`cargo install ggsql` +[Other platforms](get_started/installation.qmd){.other-platforms-link} +::: + +::: {.install-divider} +[or]{.divider-text} +::: + +::: {.install-col .install-col-right} +```bash +# Jupyter kernel +uv tool install ggsql-jupyter +ggsql-jupyter --install + +# CLI +uv tool install ggsql +``` +::: ::: ```{=html} @@ -86,7 +98,7 @@ LABEL (function() { const repoOwner = 'posit-dev'; const repoName = 'ggsql'; - const includePreReleases = true; // Set to false to only show published releases + const includePreReleases = true; function detectOS() { const ua = navigator.userAgent.toLowerCase(); @@ -96,30 +108,30 @@ LABEL return 'unknown'; } - function getOSLabel(os) { - switch(os) { - case 'windows': return 'Windows'; - case 'macos': return 'macOS'; - case 'linux': return 'Linux'; - default: return 'your platform'; - } + function getOSIcon(os) { + const icons = { + windows: 'bi-windows', + macos: 'bi-apple', + linux: 'bi-ubuntu' + }; + return icons[os] ? `` : ''; } - async function loadInstallers() { - const container = document.getElementById('installer-buttons'); + const patterns = { + windows_exe: /^ggsql[_-]\d.*x64.*-setup\.exe$/i, + macos: /^ggsql[_-]\d.*(aarch64|arm64).*\.dmg$/i, + linux: /^ggsql[_-]\d.*amd64.*\.deb$/i + }; + + function findAsset(assets, pattern) { + return assets?.find(a => pattern?.test(a.name)); + } + + async function loadInstaller() { + const container = document.getElementById('installer-recommended'); if (!container) return; const os = detectOS(); - const jupyterPattern = { - windows: /ggsql-jupyter.*\.(exe|msi)$/i, - macos: /ggsql-jupyter.*\.dmg$/i, - linux: /ggsql-jupyter.*\.deb$/i - }[os]; - const cliPattern = { - windows: /^ggsql[^-].*\.(exe|msi)$/i, - macos: /^ggsql[^-].*\.dmg$/i, - linux: /^ggsql[^-].*\.deb$/i - }[os]; try { const endpoint = includePreReleases @@ -132,29 +144,25 @@ LABEL if (!release) throw new Error('No releases found'); const version = release.tag_name; - const jupyterAsset = release.assets?.find(a => jupyterPattern?.test(a.name)); - const cliAsset = release.assets?.find(a => cliPattern?.test(a.name)); + const assets = release.assets || []; + + let asset; + if (os === 'windows') { + asset = findAsset(assets, patterns.windows_exe); + } else if (os === 'macos') { + asset = findAsset(assets, patterns.macos); + } else if (os === 'linux') { + asset = findAsset(assets, patterns.linux); + } container.innerHTML = ` -

${version} · ${getOSLabel(os)} · Other platforms

-
-
- - Jupyter Kernel - -

For Jupyter and Quarto notebooks

-
-
- - CLI - -

For terminal and scripting workflows

-
-
+ + ${getOSIcon(os)} Download ggsql ${version} + `; } catch (e) { container.innerHTML = ` - + View Downloads on GitHub `; @@ -162,9 +170,9 @@ LABEL } if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', loadInstallers); + document.addEventListener('DOMContentLoaded', loadInstaller); } else { - loadInstallers(); + loadInstaller(); } })(); @@ -177,7 +185,7 @@ LABEL ::: {.features} ::: {.feature} -### Familiar Syntax +### Familiar syntax Write standard SQL queries and seamlessly extend them with visualization clauses. Your existing SQL knowledge transfers directly. @@ -191,9 +199,9 @@ DRAW line ::: ::: {.feature} -### Grammar of Graphics +### Grammar of graphics -Compose visualizations from independent layers, scales, and coordinates. Mix and match components for powerful custom visuals. +Compose visualizations from independent layers, scales, and coordinates. Mix and match components for powerful custom visuals. The [grammar of graphics](get_started/grammar.qmd) provides you with a single mental model for every type of plot. ```{.ggsql .code-example} VISUALISE date AS x FROM sales @@ -205,7 +213,7 @@ FACET region ::: ::: {.feature} -### Built for Humans _and_ AI +### Built for humans _and_ AI The structured syntax makes it easy for AI agents to write, and for you to read, adjust, and verify. @@ -228,20 +236,16 @@ ggsql interfaces directly with your database. Want to create a histogram over 1 ::: {.tool-grid} ::: {.tool-item} -![](assets/logos/positron.svg){.tool-logo} -[Positron](https://positron.posit.co/) +[![](assets/logos/positron.svg){.tool-logo} Positron](get_started/installation.qmd#vs-code--positron-extension) ::: ::: {.tool-item} -![](assets/logos/quarto.svg){.tool-logo} -[Quarto](https://quarto.org/) +[![](assets/logos/quarto.svg){.tool-logo} Quarto](get_started/installation.qmd#jupyter-kernel) ::: ::: {.tool-item} -![](assets/logos/jupyter.svg){.tool-logo} -[Jupyter](https://jupyter.org) +[![](assets/logos/jupyter.svg){.tool-logo} Jupyter](get_started/installation.qmd#jupyter-kernel) ::: ::: {.tool-item} -![](assets/logos/vscode.svg){.tool-logo} -[VS Code](https://code.visualstudio.com/) +[![](assets/logos/vscode.svg){.tool-logo} VS Code](get_started/installation.qmd#vs-code--positron-extension) ::: ::: @@ -256,9 +260,9 @@ ggsql interfaces directly with your database. Want to create a histogram over 1 Install ggsql and start creating visualizations in minutes. ::: {.cta-buttons} -[Installation](get_started.qmd){.btn .btn-primary .btn-lg} +[Installation](get_started/installation.qmd){.btn .btn-primary .btn-lg} [Documentation](syntax/index.qmd){.btn .btn-outline-primary .btn-lg} -[Examples](examples.qmd){.btn .btn-outline-secondary .btn-lg} +[Examples](gallery/index.qmd){.btn .btn-outline-secondary .btn-lg} ::: Or try our [online playground](wasm/) to experience the syntax _right now_. diff --git a/doc/styles.scss b/doc/styles.scss index 9f98455c..aaaccba7 100644 --- a/doc/styles.scss +++ b/doc/styles.scss @@ -231,13 +231,13 @@ body:has(.hero-banner) { grid-template-rows: auto 1fr; column-gap: 2rem; row-gap: 0.75rem; - background: rgba(255, 255, 255, 0.85); - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); + background: rgba(249, 249, 249, 0.7); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); border-radius: 16px; padding: 2rem; box-shadow: 0 8px 32px rgba(0, 95, 115, 0.1); - border: 1px solid rgba(148, 210, 189, 0.4); + border: 1px solid rgba(249, 249, 249, 0.5); transition: transform 0.3s ease, box-shadow 0.3s ease; &:hover { @@ -402,74 +402,112 @@ body:has(.hero-banner) { .install-section { text-align: center; - .install-grid { - display: grid; - grid-template-columns: 1fr; + .install-columns { + display: flex; + flex-direction: column; gap: 2rem; + align-items: center; margin-top: 1.5rem; - @media (min-width: 600px) { - grid-template-columns: 1fr 1fr; - gap: 3rem; + @media (min-width: 700px) { + flex-direction: row; + justify-content: center; + align-items: stretch; + gap: 0; } } - .install-column { - h4 { - font-size: 1.1rem; - margin-bottom: 1rem; - opacity: 0.9; + .install-col { + flex: 1; + max-width: 320px; + display: flex; + flex-direction: column; + justify-content: center; + } + + .install-col-left { + align-items: center; + } + + .install-col-right { + text-align: left; + + > p:first-child { + margin-bottom: 0.75rem; } pre { + margin: 0; + font-size: 0.85rem; text-align: left; - font-size: 0.9rem; } - } - #installer-buttons { - .install-version { - margin-bottom: 1.5rem; - font-size: 0.95rem; - opacity: 0.8; + .sourceCode { + margin: 0; } + } - .install-buttons-row { - display: flex; - gap: 2rem; - justify-content: center; - flex-wrap: wrap; - } + .install-divider { + display: none; - .install-option { + @media (min-width: 700px) { display: flex; flex-direction: column; align-items: center; - gap: 0.5rem; + justify-content: center; + padding: 0 2rem; + position: relative; + + &::before, + &::after { + content: ''; + position: absolute; + left: 50%; + width: 1px; + background: rgba(0, 95, 115, 0.2); + } + + &::before { + top: 0; + bottom: calc(50% + 1rem); + } + + &::after { + top: calc(50% + 1rem); + bottom: 0; + } + + > p { + margin: 0; + } + + .divider-text { + font-size: 0.85rem; + color: var(--brand-darkteal); + opacity: 0.7; + } } + } + + #installer-recommended { + margin-bottom: 1rem; .install-btn { - min-width: 160px; - } + min-width: 200px; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; - .install-description { - font-size: 0.85rem; - opacity: 0.7; - margin: 0; + .bi { + font-size: 1.3em; + } } } - .install-cli-options { - margin-top: 1.5rem; + .other-platforms-link { font-size: 0.9rem; - opacity: 0.85; - - code { - background: rgba(0, 95, 115, 0.08); - padding: 0.2em 0.5em; - border-radius: 4px; - font-size: 0.85em; - } + opacity: 0.8; } } diff --git a/doc/syntax/index.qmd b/doc/syntax/index.qmd index 8b2f8837..d49a43a6 100644 --- a/doc/syntax/index.qmd +++ b/doc/syntax/index.qmd @@ -2,8 +2,8 @@ title: "Syntax" --- -## Main Clauses -ggsql augments the standard SQL syntax with a number of new clauses to describe a visualisation: +## Main clauses +ggsql augments the standard SQL syntax with a number of new clauses to describe a visualisation. Apart from `VISUALISE` needing to be the first, the order of these clauses is arbitrary, though grouping e.g. all `DRAW` clauses will lead to queries that are easier to reason about: - [`VISUALISE`](clause/visualise.qmd) initiates the visualisation part of the query - [`DRAW`](clause/draw.qmd) adds a new layer to the visualisation @@ -26,7 +26,7 @@ There are many different layers to choose from when visualising your data. Some - [`area`](layer/type/area.qmd) is used to display series as an area chart. - [`ribbon`](layer/type/ribbon.qmd) is used to display series extrema. - [`polygon`](layer/type/polygon.qmd) is used to display arbitrary shapes as polygons. -- [`text`](layer/text.qmd) is used to render datapoints as text. +- [`text`](layer/type/text.qmd) is used to render datapoints as text. - [`bar`](layer/type/bar.qmd) creates a bar chart, optionally calculating y from the number of records in each bar. - [`density`](layer/type/density.qmd) creates univariate kernel density estimates, showing the distribution of a variable. - [`violin`](layer/type/violin.qmd) displays a rotated kernel density estimate. diff --git a/doc/syntax/layer/type/text.qmd b/doc/syntax/layer/type/text.qmd index 059b68c8..4a1189bb 100644 --- a/doc/syntax/layer/type/text.qmd +++ b/doc/syntax/layer/type/text.qmd @@ -2,7 +2,7 @@ title: "Text" --- -> Layers are declared with the [`DRAW` clause](../clause/draw.qmd). Read the documentation for this clause for a thorough description of how to use it. +> Layers are declared with the [`DRAW` clause](../../clause/draw.qmd). Read the documentation for this clause for a thorough description of how to use it. The text layer displays rows in the data as text. It can be used as a visualisation itself, or used to annotate a different layer. @@ -146,4 +146,4 @@ VISUALISE bill_len AS x, bill_dep AS y FROM ggsql:penguins label => ['Adelie', 'Chinstrap', 'Gentoo'], x => [40, 50, 50], y => [19, 19, 15] -``` \ No newline at end of file +``` diff --git a/doc/syntax/scale/aesthetic/1_color.qmd b/doc/syntax/scale/aesthetic/1_color.qmd index c1cd601a..a05d1ffe 100644 --- a/doc/syntax/scale/aesthetic/1_color.qmd +++ b/doc/syntax/scale/aesthetic/1_color.qmd @@ -1,5 +1,5 @@ --- -title: "Fill and Stroke" +title: "Fill and stroke" format: html: toc: true @@ -161,7 +161,7 @@ Diverging palettes emphasize a critical midpoint with two contrasting hues on ei | `rdgy` | ![](examples/gradient_rdgy.svg){height=20 .lightbox} | ColorBrewer | Red-Grey | | `puor` | ![](examples/gradient_puor.svg){height=20 .lightbox} | ColorBrewer | Orange-Purple | -#### Multi-Sequential +#### Multi-sequential Multi-sequential palettes have multiple sequential segments, useful for categorical data with ordered subcategories. @@ -226,7 +226,7 @@ Bostock, M. D3.js. [d3js.org](https://d3js.org) ##### Kelly's Colors Kelly, K.L. (1965). Twenty-two colors of maximum contrast. *Color Engineering*, 3(6), 26-27. -### Choosing a Palette +### Choosing a palette #### For general continuous data diff --git a/doc/syntax/scale/aesthetic/linetype.qmd b/doc/syntax/scale/aesthetic/linetype.qmd index 0da2f877..3a77e14f 100644 --- a/doc/syntax/scale/aesthetic/linetype.qmd +++ b/doc/syntax/scale/aesthetic/linetype.qmd @@ -51,7 +51,7 @@ The `categorical` palette is the default palette for discrete linetype scales. I ### Sequential palette The `sequential` palette is the default for binned and ordinal linetype scales. It consists of up to 15 patterns with increasing amount of "on" and decreasing amount of "off". This creates a visual progression from sparse (low ink) to solid (100% ink). -#### Example: 5-Level Sequential +#### Example: 5-level sequential | Level | Pattern | Ink Density | Description | |-------|---------|-------------|-------------| diff --git a/doc/syntax/scale/aesthetic/shape.qmd b/doc/syntax/scale/aesthetic/shape.qmd index 2a40b86a..c36b6f90 100644 --- a/doc/syntax/scale/aesthetic/shape.qmd +++ b/doc/syntax/scale/aesthetic/shape.qmd @@ -56,15 +56,15 @@ DRAW point SCALE shape TO ['star', 'bowtie', 'square-plus'] ``` -### Default Palette (`closed`) +### Default palette (`closed`) The default palette contains the 9 closed shapes (first nine in the table above). This is the recommended palette for most use cases, as closed shapes are more visually prominent and easier to distinguish at small sizes. While the closed shapes are most often used filled, you can also turn if fill and only draw the stroke for a lighter look. -### Open Palette (`open`) +### Open palette (`open`) The `open` palette contains the last 6 shapes in the table. None of these have a fill. You may use this palette when you want transparent shapes that don't obscure data. -### All Shapes Palette (`shapes`) +### All shapes palette (`shapes`) This palette combines the two palettes above to provide all the possible shapes. Since not all shapes have a fill you should not map fill to anything if using this palette, and you should also be aware that differentiating 15 different shapes in the same plot will require a lot of mental effort from the viewer. ### Accessibility considerations diff --git a/ggsql-wasm/demo/package-lock.json b/ggsql-wasm/demo/package-lock.json index 390e98a1..2b2658ea 100644 --- a/ggsql-wasm/demo/package-lock.json +++ b/ggsql-wasm/demo/package-lock.json @@ -24,7 +24,7 @@ }, "../pkg": { "name": "ggsql-wasm", - "version": "0.1.8", + "version": "0.1.0", "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { diff --git a/ggsql-wasm/demo/src/editor.ts b/ggsql-wasm/demo/src/editor.ts index ab6e27b0..b6e14fc6 100644 --- a/ggsql-wasm/demo/src/editor.ts +++ b/ggsql-wasm/demo/src/editor.ts @@ -39,6 +39,23 @@ function scopeToMonacoToken(scopes: string[]): string { return ""; } +// Define Pygments-style theme for Monaco +monaco.editor.defineTheme("ggsql-pygments", { + base: "vs", + inherit: true, + rules: [ + { token: "comment", foreground: "408080", fontStyle: "italic" }, + { token: "string", foreground: "BA2121" }, + { token: "number", foreground: "666666" }, + { token: "keyword", foreground: "008000", fontStyle: "bold" }, + { token: "type", foreground: "008000" }, + { token: "variable", foreground: "19177C" }, + { token: "operator", foreground: "666666" }, + { token: "delimiter", foreground: "000000" }, + ], + colors: {}, +}); + async function initTextMateGrammar(): Promise { // Load oniguruma WASM const onigWasm = await fetch(WASM_BASE + "onig.wasm"); @@ -127,7 +144,7 @@ export class EditorManager { this.editor = monaco.editor.create(container, { value: initialValue, language: "ggsql", - theme: "vs", + theme: "ggsql-pygments", automaticLayout: true, minimap: { enabled: false }, fontSize: 14, diff --git a/ggsql-wasm/demo/src/index.qmd b/ggsql-wasm/demo/src/index.qmd index c72d8850..7f138f05 100644 --- a/ggsql-wasm/demo/src/index.qmd +++ b/ggsql-wasm/demo/src/index.qmd @@ -5,10 +5,20 @@ section-divs: false toc: false lightbox: false repo-actions: false -include-in-header: +include-in-header: - text: | + include-after-body: - text: | diff --git a/ggsql-wasm/demo/src/quarto/editor.ts b/ggsql-wasm/demo/src/quarto/editor.ts index 61f89386..9b2db5f4 100644 --- a/ggsql-wasm/demo/src/quarto/editor.ts +++ b/ggsql-wasm/demo/src/quarto/editor.ts @@ -76,6 +76,25 @@ function getGrammar(): Promise { return grammarPromise; } +// Define Pygments-style theme for Monaco +monaco.editor.defineTheme("ggsql-pygments", { + base: "vs", + inherit: true, + rules: [ + { token: "comment", foreground: "408080", fontStyle: "italic" }, + { token: "string", foreground: "BA2121" }, + { token: "number", foreground: "666666" }, + { token: "keyword", foreground: "008000", fontStyle: "bold" }, + { token: "type", foreground: "008000" }, + { token: "variable", foreground: "19177C" }, + { token: "operator", foreground: "666666" }, + { token: "delimiter", foreground: "000000" }, + ], + colors: { + "editor.background": "#f7f7f7", + }, +}); + let languageRegistered = false; async function ensureLanguageRegistered(): Promise { @@ -154,7 +173,7 @@ export interface EditorInstance { editor: monaco.editor.IStandaloneCodeEditor; } -const LINE_HEIGHT = 19; +const LINE_HEIGHT = 20; const PADDING_TOP = 8; const PADDING_BOTTOM = 8; const MAX_EDITOR_HEIGHT = 400; @@ -176,14 +195,14 @@ export async function createEditor( const editor = monaco.editor.create(container, { value: initialValue, language: "ggsql", - theme: "vs", + theme: "ggsql-pygments", automaticLayout: true, minimap: { enabled: false }, fontSize: 13, lineNumbers: "on", glyphMargin: false, folding: false, - lineNumbersMinChars: 2, + lineNumbersMinChars: 3, scrollBeyondLastLine: false, wordWrap: "on", padding: { top: PADDING_TOP, bottom: PADDING_BOTTOM }, @@ -192,9 +211,9 @@ export async function createEditor( hideCursorInOverviewRuler: true, overviewRulerBorder: false, scrollbar: { - vertical: "auto", + vertical: "hidden", horizontal: "hidden", - verticalScrollbarSize: 8, + alwaysConsumeMouseWheel: false, }, }); diff --git a/ggsql-wasm/demo/src/styles.css b/ggsql-wasm/demo/src/styles.css index b1567282..7638e9de 100644 --- a/ggsql-wasm/demo/src/styles.css +++ b/ggsql-wasm/demo/src/styles.css @@ -7,7 +7,7 @@ body { font-family: "Nunito Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; - height: 100vh; + height: 100dvh; overflow: hidden; background: #F9F9F9; color: #001219; @@ -17,7 +17,7 @@ body { display: grid; grid-template-columns: 200px 1fr 1fr; grid-template-rows: 1fr 150px; - height: 100vh; + height: calc(100dvh - var(--quarto-navbar-height, 0px)); gap: 1px; background: #005F73; border-top: 2px solid #005F73; @@ -31,7 +31,7 @@ body { #status { font-size: 12px; padding: 3px 10px; - border-radius: 3px; + border-radius: 0; background: #F9F9F9; color: #005F73; } @@ -73,6 +73,7 @@ body { .table-list { list-style: none; + padding-left: 0; } .table-item { @@ -119,11 +120,11 @@ body { .file-input-label { display: block; - padding: 6px 8px; + padding: 6px 12px; background: #005F73; color: #F9F9F9; text-align: center; - border-radius: 3px; + border-radius: 50rem; cursor: pointer; font-size: 12px; margin-bottom: 6px; @@ -150,15 +151,15 @@ body { .example-button { display: block; width: 100%; - padding: 5px 8px; + padding: 5px 12px; margin: 3px 0; background: #F9F9F9; border: 1px solid #94D2BD; color: #001219; - border-radius: 3px; + border-radius: 50rem; cursor: pointer; font-size: 12px; - text-align: left; + text-align: center; } .example-button:hover { diff --git a/src/plot/facet/types.rs b/src/plot/facet/types.rs index 51052b9f..565802a9 100644 --- a/src/plot/facet/types.rs +++ b/src/plot/facet/types.rs @@ -2,7 +2,7 @@ //! //! This module defines faceting configuration for small multiples. -use crate::plot::types::{ParamConstraint, ParamDefinition, DefaultParamValue}; +use crate::plot::types::{DefaultParamValue, ParamConstraint, ParamDefinition}; use crate::plot::ParameterValue; use serde::{Deserialize, Serialize}; use std::collections::HashMap; diff --git a/src/plot/layer/geom/area.rs b/src/plot/layer/geom/area.rs index d9c456d9..c16c5e63 100644 --- a/src/plot/layer/geom/area.rs +++ b/src/plot/layer/geom/area.rs @@ -2,7 +2,7 @@ use crate::plot::layer::orientation::{ALIGNED, ORIENTATION_VALUES}; use crate::plot::types::DefaultAestheticValue; -use crate::plot::{ParamDefinition, DefaultParamValue}; +use crate::plot::{DefaultParamValue, ParamDefinition}; use crate::{naming, Mappings}; use super::types::{ParamConstraint, POSITION_VALUES}; diff --git a/src/plot/layer/geom/arrow.rs b/src/plot/layer/geom/arrow.rs index 75b0a750..375d9754 100644 --- a/src/plot/layer/geom/arrow.rs +++ b/src/plot/layer/geom/arrow.rs @@ -2,7 +2,7 @@ use super::types::POSITION_VALUES; use super::{ - DefaultAesthetics, GeomTrait, GeomType, ParamConstraint, ParamDefinition, DefaultParamValue, + DefaultAesthetics, DefaultParamValue, GeomTrait, GeomType, ParamConstraint, ParamDefinition, }; use crate::plot::types::DefaultAestheticValue; diff --git a/src/plot/layer/geom/bar.rs b/src/plot/layer/geom/bar.rs index 2cb5ec28..cddda1d4 100644 --- a/src/plot/layer/geom/bar.rs +++ b/src/plot/layer/geom/bar.rs @@ -5,7 +5,7 @@ use std::collections::HashSet; use super::types::{get_column_name, POSITION_VALUES}; use super::{ - DefaultAesthetics, GeomTrait, GeomType, ParamConstraint, ParamDefinition, DefaultParamValue, + DefaultAesthetics, DefaultParamValue, GeomTrait, GeomType, ParamConstraint, ParamDefinition, StatResult, }; use crate::naming; diff --git a/src/plot/layer/geom/boxplot.rs b/src/plot/layer/geom/boxplot.rs index 8abdd4e0..89dcc921 100644 --- a/src/plot/layer/geom/boxplot.rs +++ b/src/plot/layer/geom/boxplot.rs @@ -7,8 +7,8 @@ use super::{DefaultAesthetics, GeomTrait, GeomType}; use crate::{ naming, plot::{ - geom::types::get_column_name, DefaultAestheticValue, ParamConstraint, ParamDefinition, - DefaultParamValue, ParameterValue, StatResult, + geom::types::get_column_name, DefaultAestheticValue, DefaultParamValue, ParamConstraint, + ParamDefinition, ParameterValue, StatResult, }, reader::SqlDialect, DataFrame, GgsqlError, Mappings, Result, @@ -496,7 +496,6 @@ mod tests { assert!(outlier_section.contains("raw.year = summary.year")); } - // ==================== GeomTrait Implementation Tests ==================== #[test] diff --git a/src/plot/layer/geom/density.rs b/src/plot/layer/geom/density.rs index 851ab49e..e67e0cbe 100644 --- a/src/plot/layer/geom/density.rs +++ b/src/plot/layer/geom/density.rs @@ -5,8 +5,8 @@ use super::{DefaultAesthetics, GeomTrait, GeomType}; use crate::{ naming, plot::{ - geom::types::get_column_name, DefaultAestheticValue, ParamConstraint, ParamDefinition, - DefaultParamValue, ParameterValue, StatResult, + geom::types::get_column_name, DefaultAestheticValue, DefaultParamValue, ParamConstraint, + ParamDefinition, ParameterValue, StatResult, }, reader::SqlDialect, GgsqlError, Mappings, Result, diff --git a/src/plot/layer/geom/errorbar.rs b/src/plot/layer/geom/errorbar.rs index f26fb464..f544504a 100644 --- a/src/plot/layer/geom/errorbar.rs +++ b/src/plot/layer/geom/errorbar.rs @@ -2,7 +2,7 @@ use super::types::POSITION_VALUES; use super::{ - DefaultAesthetics, GeomTrait, GeomType, ParamConstraint, ParamDefinition, DefaultParamValue, + DefaultAesthetics, DefaultParamValue, GeomTrait, GeomType, ParamConstraint, ParamDefinition, }; use crate::plot::types::DefaultAestheticValue; diff --git a/src/plot/layer/geom/histogram.rs b/src/plot/layer/geom/histogram.rs index ad6b60ac..fef6fb2e 100644 --- a/src/plot/layer/geom/histogram.rs +++ b/src/plot/layer/geom/histogram.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use super::types::{get_column_name, CLOSED_VALUES, POSITION_VALUES}; use super::{ - DefaultAesthetics, GeomTrait, GeomType, ParamConstraint, ParamDefinition, DefaultParamValue, + DefaultAesthetics, DefaultParamValue, GeomTrait, GeomType, ParamConstraint, ParamDefinition, StatResult, }; use crate::naming; diff --git a/src/plot/layer/geom/line.rs b/src/plot/layer/geom/line.rs index d0a928d0..c61a458d 100644 --- a/src/plot/layer/geom/line.rs +++ b/src/plot/layer/geom/line.rs @@ -1,7 +1,7 @@ //! Line geom implementation use super::{ - DefaultAesthetics, GeomTrait, GeomType, ParamConstraint, ParamDefinition, DefaultParamValue, + DefaultAesthetics, DefaultParamValue, GeomTrait, GeomType, ParamConstraint, ParamDefinition, StatResult, }; use crate::plot::layer::orientation::{ALIGNED, ORIENTATION_VALUES}; diff --git a/src/plot/layer/geom/linear.rs b/src/plot/layer/geom/linear.rs index 1ae4dcb1..5867dff8 100644 --- a/src/plot/layer/geom/linear.rs +++ b/src/plot/layer/geom/linear.rs @@ -1,7 +1,7 @@ //! Linear geom implementation use super::{ - DefaultAesthetics, GeomTrait, GeomType, ParamConstraint, ParamDefinition, DefaultParamValue, + DefaultAesthetics, DefaultParamValue, GeomTrait, GeomType, ParamConstraint, ParamDefinition, }; use crate::plot::layer::orientation::{ALIGNED, ORIENTATION_VALUES}; use crate::plot::types::DefaultAestheticValue; diff --git a/src/plot/layer/geom/mod.rs b/src/plot/layer/geom/mod.rs index 79820530..842476a1 100644 --- a/src/plot/layer/geom/mod.rs +++ b/src/plot/layer/geom/mod.rs @@ -50,7 +50,7 @@ mod violin; // Re-export types pub use types::{ - DefaultAesthetics, ParamConstraint, ParamDefinition, DefaultParamValue, StatResult, + DefaultAesthetics, DefaultParamValue, ParamConstraint, ParamDefinition, StatResult, }; // Re-export geom structs for direct access if needed diff --git a/src/plot/layer/geom/path.rs b/src/plot/layer/geom/path.rs index 8adf2152..5e32a3be 100644 --- a/src/plot/layer/geom/path.rs +++ b/src/plot/layer/geom/path.rs @@ -2,7 +2,7 @@ use super::types::POSITION_VALUES; use super::{ - DefaultAesthetics, GeomTrait, GeomType, ParamConstraint, ParamDefinition, DefaultParamValue, + DefaultAesthetics, DefaultParamValue, GeomTrait, GeomType, ParamConstraint, ParamDefinition, }; use crate::plot::types::DefaultAestheticValue; diff --git a/src/plot/layer/geom/point.rs b/src/plot/layer/geom/point.rs index 6a2cc33b..3dafde2a 100644 --- a/src/plot/layer/geom/point.rs +++ b/src/plot/layer/geom/point.rs @@ -2,7 +2,7 @@ use super::types::POSITION_VALUES; use super::{ - DefaultAesthetics, GeomTrait, GeomType, ParamConstraint, ParamDefinition, DefaultParamValue, + DefaultAesthetics, DefaultParamValue, GeomTrait, GeomType, ParamConstraint, ParamDefinition, }; use crate::plot::types::DefaultAestheticValue; diff --git a/src/plot/layer/geom/polygon.rs b/src/plot/layer/geom/polygon.rs index a0c60245..d1ed6841 100644 --- a/src/plot/layer/geom/polygon.rs +++ b/src/plot/layer/geom/polygon.rs @@ -2,7 +2,7 @@ use super::types::POSITION_VALUES; use super::{ - DefaultAesthetics, GeomTrait, GeomType, ParamConstraint, ParamDefinition, DefaultParamValue, + DefaultAesthetics, DefaultParamValue, GeomTrait, GeomType, ParamConstraint, ParamDefinition, }; use crate::plot::types::DefaultAestheticValue; diff --git a/src/plot/layer/geom/rect.rs b/src/plot/layer/geom/rect.rs index a03a084e..fdd2584a 100644 --- a/src/plot/layer/geom/rect.rs +++ b/src/plot/layer/geom/rect.rs @@ -7,7 +7,7 @@ use super::types::POSITION_VALUES; use super::{DefaultAesthetics, GeomTrait, GeomType, ParamConstraint, StatResult}; use crate::naming; use crate::plot::types::{DefaultAestheticValue, ParameterValue}; -use crate::plot::{ParamDefinition, DefaultParamValue}; +use crate::plot::{DefaultParamValue, ParamDefinition}; use crate::{DataFrame, GgsqlError, Mappings, Result}; use super::types::Schema; diff --git a/src/plot/layer/geom/ribbon.rs b/src/plot/layer/geom/ribbon.rs index e72dbf95..d3615d12 100644 --- a/src/plot/layer/geom/ribbon.rs +++ b/src/plot/layer/geom/ribbon.rs @@ -3,7 +3,7 @@ use super::types::POSITION_VALUES; use super::{DefaultAesthetics, GeomTrait, GeomType, StatResult}; use crate::plot::types::DefaultAestheticValue; -use crate::plot::{ParamConstraint, ParamDefinition, DefaultParamValue}; +use crate::plot::{DefaultParamValue, ParamConstraint, ParamDefinition}; use crate::{naming, Mappings}; /// Ribbon geom - confidence bands and ranges diff --git a/src/plot/layer/geom/segment.rs b/src/plot/layer/geom/segment.rs index 94d68a90..9506b6a1 100644 --- a/src/plot/layer/geom/segment.rs +++ b/src/plot/layer/geom/segment.rs @@ -2,7 +2,7 @@ use super::types::POSITION_VALUES; use super::{ - DefaultAesthetics, GeomTrait, GeomType, ParamConstraint, ParamDefinition, DefaultParamValue, + DefaultAesthetics, DefaultParamValue, GeomTrait, GeomType, ParamConstraint, ParamDefinition, }; use crate::plot::types::DefaultAestheticValue; diff --git a/src/plot/layer/geom/smooth.rs b/src/plot/layer/geom/smooth.rs index f6bcf664..fad14432 100644 --- a/src/plot/layer/geom/smooth.rs +++ b/src/plot/layer/geom/smooth.rs @@ -2,7 +2,7 @@ use super::types::POSITION_VALUES; use super::{ - DefaultAesthetics, GeomTrait, GeomType, ParamConstraint, ParamDefinition, DefaultParamValue, + DefaultAesthetics, DefaultParamValue, GeomTrait, GeomType, ParamConstraint, ParamDefinition, }; use crate::plot::geom::types::get_column_name; use crate::plot::types::DefaultAestheticValue; diff --git a/src/plot/layer/geom/text.rs b/src/plot/layer/geom/text.rs index cc0a8e84..6ceb45f9 100644 --- a/src/plot/layer/geom/text.rs +++ b/src/plot/layer/geom/text.rs @@ -2,7 +2,7 @@ use super::types::POSITION_VALUES; use super::{ - DefaultAesthetics, GeomTrait, GeomType, ParamConstraint, ParamDefinition, DefaultParamValue, + DefaultAesthetics, DefaultParamValue, GeomTrait, GeomType, ParamConstraint, ParamDefinition, ParameterValue, }; use crate::plot::types::DefaultAestheticValue; diff --git a/src/plot/layer/geom/types.rs b/src/plot/layer/geom/types.rs index 21dddb5f..ad7cf70a 100644 --- a/src/plot/layer/geom/types.rs +++ b/src/plot/layer/geom/types.rs @@ -6,7 +6,7 @@ use crate::plot::aesthetic::parse_positional; use crate::{plot::types::DefaultAestheticValue, Mappings}; // Re-export shared types from the central location -pub use crate::plot::types::{ParamConstraint, ParamDefinition, DefaultParamValue}; +pub use crate::plot::types::{DefaultParamValue, ParamConstraint, ParamDefinition}; // ============================================================================= // Common constraint value arrays diff --git a/src/plot/layer/geom/violin.rs b/src/plot/layer/geom/violin.rs index c723f9f4..bf12a393 100644 --- a/src/plot/layer/geom/violin.rs +++ b/src/plot/layer/geom/violin.rs @@ -5,8 +5,8 @@ use super::{DefaultAesthetics, GeomTrait, GeomType, StatResult}; use crate::{ naming, plot::{ - geom::types::get_column_name, DefaultAestheticValue, ParamConstraint, ParamDefinition, - DefaultParamValue, ParameterValue, + geom::types::get_column_name, DefaultAestheticValue, DefaultParamValue, ParamConstraint, + ParamDefinition, ParameterValue, }, DataFrame, GgsqlError, Mappings, Result, }; diff --git a/src/plot/layer/mod.rs b/src/plot/layer/mod.rs index 5cf34a5e..e2a9a2e1 100644 --- a/src/plot/layer/mod.rs +++ b/src/plot/layer/mod.rs @@ -20,7 +20,7 @@ pub use orientation::is_transposed; // Re-export geom types for convenience pub use geom::{ - DefaultAesthetics, Geom, GeomTrait, GeomType, ParamDefinition, DefaultParamValue, StatResult, + DefaultAesthetics, DefaultParamValue, Geom, GeomTrait, GeomType, ParamDefinition, StatResult, }; // Re-export position types for convenience diff --git a/src/plot/layer/position/dodge.rs b/src/plot/layer/position/dodge.rs index 3bcde282..ec63ba72 100644 --- a/src/plot/layer/position/dodge.rs +++ b/src/plot/layer/position/dodge.rs @@ -7,7 +7,7 @@ //! - If both are discrete → 2D grid dodge (both offsets, arranged in a grid) use super::{compute_dodge_offsets, is_continuous_scale, Layer, PositionTrait, PositionType}; -use crate::plot::types::{ParamConstraint, ParamDefinition, DefaultParamValue, ParameterValue}; +use crate::plot::types::{DefaultParamValue, ParamConstraint, ParamDefinition, ParameterValue}; use crate::{naming, DataFrame, GgsqlError, Plot, Result}; use polars::prelude::*; use std::collections::HashMap; @@ -636,9 +636,6 @@ mod tests { let params = dodge.default_params(); assert_eq!(params.len(), 1); assert_eq!(params[0].name, "width"); - assert!(matches!( - params[0].default, - DefaultParamValue::Number(0.9) - )); + assert!(matches!(params[0].default, DefaultParamValue::Number(0.9))); } } diff --git a/src/plot/layer/position/jitter.rs b/src/plot/layer/position/jitter.rs index 69e66a5d..6dcc9c80 100644 --- a/src/plot/layer/position/jitter.rs +++ b/src/plot/layer/position/jitter.rs @@ -18,7 +18,7 @@ use super::{ compute_dodge_offsets, compute_group_indices, is_continuous_scale, Layer, PositionTrait, PositionType, }; -use crate::plot::types::{ParamConstraint, ParamDefinition, DefaultParamValue, ParameterValue}; +use crate::plot::types::{DefaultParamValue, ParamConstraint, ParamDefinition, ParameterValue}; use crate::{naming, DataFrame, GgsqlError, Plot, Result}; use polars::prelude::*; use rand::Rng; @@ -996,10 +996,7 @@ mod tests { let params = jitter.default_params(); assert_eq!(params.len(), 5); assert_eq!(params[0].name, "width"); - assert!(matches!( - params[0].default, - DefaultParamValue::Number(0.9) - )); + assert!(matches!(params[0].default, DefaultParamValue::Number(0.9))); assert_eq!(params[1].name, "dodge"); assert!(matches!( params[1].default, @@ -1014,10 +1011,7 @@ mod tests { assert_eq!(params[3].name, "bandwidth"); assert!(matches!(params[3].default, DefaultParamValue::Null)); assert_eq!(params[4].name, "adjust"); - assert!(matches!( - params[4].default, - DefaultParamValue::Number(1.0) - )); + assert!(matches!(params[4].default, DefaultParamValue::Number(1.0))); } #[test] diff --git a/src/plot/layer/position/mod.rs b/src/plot/layer/position/mod.rs index 694a5d7f..af11965e 100644 --- a/src/plot/layer/position/mod.rs +++ b/src/plot/layer/position/mod.rs @@ -14,7 +14,7 @@ mod identity; mod jitter; mod stack; -use crate::plot::types::{ParamDefinition, DefaultParamValue, ParameterValue}; +use crate::plot::types::{DefaultParamValue, ParamDefinition, ParameterValue}; use crate::plot::ScaleTypeKind; use crate::{DataFrame, Plot, Result}; use serde::{Deserialize, Serialize}; diff --git a/src/plot/layer/position/stack.rs b/src/plot/layer/position/stack.rs index f669f18a..f2081e12 100644 --- a/src/plot/layer/position/stack.rs +++ b/src/plot/layer/position/stack.rs @@ -7,7 +7,7 @@ //! - If pos1 is continuous and pos2 is discrete → stack horizontally (modify pos1/pos1end) use super::{is_continuous_scale, Layer, PositionTrait, PositionType}; -use crate::plot::types::{ParamConstraint, ParamDefinition, DefaultParamValue, ParameterValue}; +use crate::plot::types::{DefaultParamValue, ParamConstraint, ParamDefinition, ParameterValue}; use crate::{naming, DataFrame, GgsqlError, Plot, Result}; use polars::prelude::*; diff --git a/src/plot/main.rs b/src/plot/main.rs index d37a418b..74360c62 100644 --- a/src/plot/main.rs +++ b/src/plot/main.rs @@ -32,7 +32,7 @@ pub use super::types::{ // Re-export Geom and related types from the layer::geom module pub use super::layer::geom::{ - DefaultAesthetics, Geom, GeomTrait, GeomType, ParamDefinition, DefaultParamValue, StatResult, + DefaultAesthetics, DefaultParamValue, Geom, GeomTrait, GeomType, ParamDefinition, StatResult, }; // Re-export Layer from the layer module diff --git a/src/plot/projection/coord/cartesian.rs b/src/plot/projection/coord/cartesian.rs index 4135febe..00d9ddf3 100644 --- a/src/plot/projection/coord/cartesian.rs +++ b/src/plot/projection/coord/cartesian.rs @@ -1,7 +1,7 @@ //! Cartesian coordinate system implementation use super::{CoordKind, CoordTrait}; -use crate::plot::types::{ParamConstraint, ParamDefinition, DefaultParamValue}; +use crate::plot::types::{DefaultParamValue, ParamConstraint, ParamDefinition}; /// Cartesian coordinate system - standard x/y coordinates #[derive(Debug, Clone, Copy)] diff --git a/src/plot/projection/coord/polar.rs b/src/plot/projection/coord/polar.rs index 94902890..4da083d1 100644 --- a/src/plot/projection/coord/polar.rs +++ b/src/plot/projection/coord/polar.rs @@ -1,7 +1,7 @@ //! Polar coordinate system implementation use super::{CoordKind, CoordTrait}; -use crate::plot::types::{ParamConstraint, ParamDefinition, DefaultParamValue}; +use crate::plot::types::{DefaultParamValue, ParamConstraint, ParamDefinition}; /// Polar coordinate system - for pie charts, rose plots #[derive(Debug, Clone, Copy)] diff --git a/src/plot/scale/scale_type/binned.rs b/src/plot/scale/scale_type/binned.rs index 3618de3f..84c5637d 100644 --- a/src/plot/scale/scale_type/binned.rs +++ b/src/plot/scale/scale_type/binned.rs @@ -9,7 +9,7 @@ use super::{ TransformKind, CLOSED_VALUES, OOB_CENSOR, OOB_SQUISH, OOB_VALUES_BINNED, }; use crate::plot::types::{ - ArrayConstraint, NumberConstraint, ParamConstraint, ParamDefinition, DefaultParamValue, + ArrayConstraint, DefaultParamValue, NumberConstraint, ParamConstraint, ParamDefinition, }; use crate::plot::{ArrayElement, ParameterValue}; diff --git a/src/plot/scale/scale_type/continuous.rs b/src/plot/scale/scale_type/continuous.rs index e5ed9d20..92f2c397 100644 --- a/src/plot/scale/scale_type/continuous.rs +++ b/src/plot/scale/scale_type/continuous.rs @@ -6,7 +6,7 @@ use super::{ ScaleTypeKind, ScaleTypeTrait, TransformKind, OOB_CENSOR, OOB_SQUISH, OOB_VALUES_CONTINUOUS, }; use crate::plot::types::{ - ArrayConstraint, NumberConstraint, ParamConstraint, ParamDefinition, DefaultParamValue, + ArrayConstraint, DefaultParamValue, NumberConstraint, ParamConstraint, ParamDefinition, }; use crate::plot::{ArrayElement, ParameterValue}; diff --git a/src/plot/scale/scale_type/discrete.rs b/src/plot/scale/scale_type/discrete.rs index ca0a36c1..ca31edfa 100644 --- a/src/plot/scale/scale_type/discrete.rs +++ b/src/plot/scale/scale_type/discrete.rs @@ -4,7 +4,7 @@ use polars::prelude::DataType; use super::super::transform::{Transform, TransformKind}; use super::{ScaleTypeKind, ScaleTypeTrait}; -use crate::plot::types::{ParamConstraint, ParamDefinition, DefaultParamValue}; +use crate::plot::types::{DefaultParamValue, ParamConstraint, ParamDefinition}; use crate::plot::ArrayElement; /// Discrete scale type - for categorical/discrete data diff --git a/src/plot/scale/scale_type/mod.rs b/src/plot/scale/scale_type/mod.rs index 2d397e39..baac8f4b 100644 --- a/src/plot/scale/scale_type/mod.rs +++ b/src/plot/scale/scale_type/mod.rs @@ -27,7 +27,7 @@ use std::sync::Arc; use super::transform::{Transform, TransformKind}; use crate::plot::aesthetic::{is_facet_aesthetic, is_positional_aesthetic}; -use crate::plot::types::{validate_parameter, ParamDefinition, DefaultParamValue}; +use crate::plot::types::{validate_parameter, DefaultParamValue, ParamDefinition}; use crate::plot::{ArrayElement, ColumnInfo, ParameterValue}; // Scale type implementations diff --git a/src/plot/scale/scale_type/ordinal.rs b/src/plot/scale/scale_type/ordinal.rs index e0121465..bc3c0d5e 100644 --- a/src/plot/scale/scale_type/ordinal.rs +++ b/src/plot/scale/scale_type/ordinal.rs @@ -8,7 +8,7 @@ use polars::prelude::DataType; use super::super::transform::{Transform, TransformKind}; use super::{ScaleTypeKind, ScaleTypeTrait}; -use crate::plot::types::{ParamConstraint, ParamDefinition, DefaultParamValue}; +use crate::plot::types::{DefaultParamValue, ParamConstraint, ParamDefinition}; use crate::plot::ArrayElement; /// Ordinal scale type - for ordered categorical data with interpolated output