diff --git a/package-lock.json b/package-lock.json index 0da2e951..91329899 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,12 +18,12 @@ "malloy-packages": "scripts/malloy-packages.js" }, "devDependencies": { - "@malloydata/db-duckdb": "0.0.358", - "@malloydata/malloy": "0.0.358", - "@malloydata/malloy-sql": "0.0.358", - "@malloydata/render": "0.0.358", - "@malloydata/render-validator": "0.0.358", - "@malloydata/syntax-highlight": "0.0.358", + "@malloydata/db-duckdb": "0.0.359", + "@malloydata/malloy": "0.0.359", + "@malloydata/malloy-sql": "0.0.359", + "@malloydata/render": "0.0.359", + "@malloydata/render-validator": "0.0.359", + "@malloydata/syntax-highlight": "0.0.359", "@types/uglify-js": "^3.17.5", "concurrently": "^6.2.1", "fs-extra": "^10.1.0", @@ -702,15 +702,15 @@ } }, "node_modules/@malloydata/db-duckdb": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/db-duckdb/-/db-duckdb-0.0.358.tgz", - "integrity": "sha512-G71QdUfOWx5wvwLrMkGn44CbbuOqQvcIad/ITnFyNKPF7hUwjjOMD2Bjdto7Vn4Tm252BXl5abKXQmwab24b+w==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/db-duckdb/-/db-duckdb-0.0.359.tgz", + "integrity": "sha512-0Z/og8gTVDt61j+JQqzYQOqlxW6aycpU2SPElYHJBMzDDcgGmYW4BWcec4SK4I27pOoWjrkpvoyo4KZh1k3NMg==", "dev": true, "license": "MIT", "dependencies": { "@duckdb/duckdb-wasm": "1.33.1-dev13.0", "@duckdb/node-api": "1.4.4-r.1", - "@malloydata/malloy": "0.0.358", + "@malloydata/malloy": "0.0.359", "@motherduck/wasm-client": "^0.6.6", "apache-arrow": "^17.0.0", "web-worker": "^1.3.0" @@ -720,15 +720,15 @@ } }, "node_modules/@malloydata/malloy": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/malloy/-/malloy-0.0.358.tgz", - "integrity": "sha512-hTjMyU3B2wymE8FqSXQNApnqaQLHI0tgmehvR4qfh9uyvUV5ATzKvRmJ6Cy0VLBIhg7fUgtrQiW6l7bvFBYRyw==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/malloy/-/malloy-0.0.359.tgz", + "integrity": "sha512-3Ew5F84+mNHxemXfTgLIhtlXyc2dKKd9Upw3AfjFDwdXYU/zUYnF4cvZUfny5j5aG4tj4rlqlrflFwBb+/qF6w==", "dev": true, "license": "MIT", "dependencies": { - "@malloydata/malloy-filter": "0.0.358", - "@malloydata/malloy-interfaces": "0.0.358", - "@malloydata/malloy-tag": "0.0.358", + "@malloydata/malloy-filter": "0.0.359", + "@malloydata/malloy-interfaces": "0.0.359", + "@malloydata/malloy-tag": "0.0.359", "@noble/hashes": "^1.8.0", "antlr4ts": "^0.5.0-alpha.4", "assert": "^2.0.0", @@ -743,9 +743,9 @@ } }, "node_modules/@malloydata/malloy-filter": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/malloy-filter/-/malloy-filter-0.0.358.tgz", - "integrity": "sha512-xLc0ItlPG5ha/jqyZ0zTlMZVCxZGaMhXnVXGPKLM8Qvpdl3ZbpmiZ9mpA+TBEF9D7llh/Tq8oiKjri4A6Xl55Q==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/malloy-filter/-/malloy-filter-0.0.359.tgz", + "integrity": "sha512-jhJwZLz0RUXmo79WwvTadqwIlR7Z/2PXAmuMnc38MbJEt6PQpd2evx8JTLSsj6/+bKeUfk3o2Xg+irzZ6PDY3g==", "dev": true, "license": "MIT", "dependencies": { @@ -757,9 +757,9 @@ } }, "node_modules/@malloydata/malloy-interfaces": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/malloy-interfaces/-/malloy-interfaces-0.0.358.tgz", - "integrity": "sha512-kyJzFDVD0oh9ZEEEy2+7NMWBNX06QsnUIVYj8As+7r/TafOmxG8KF+bFQvlEeo8LZZ9M5MeeXeKP25GEOot50A==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/malloy-interfaces/-/malloy-interfaces-0.0.359.tgz", + "integrity": "sha512-V71tOw6XBLxGeu5cwQW1HGEvAPJwdG47xNWJCTMgZfv8hZrDoyhS7jzMjQmK0HOhz7+FPYOH8I+KYPSU377Shw==", "dev": true, "license": "MIT", "dependencies": { @@ -770,22 +770,22 @@ } }, "node_modules/@malloydata/malloy-sql": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/malloy-sql/-/malloy-sql-0.0.358.tgz", - "integrity": "sha512-P4/hpDfia6E4ypCOQowtrBqWYtVRpyKzaxAtgx165wKZSUwbLCvEFjHmRvtFka1/dFQPKyk4z8Th//k759bNVw==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/malloy-sql/-/malloy-sql-0.0.359.tgz", + "integrity": "sha512-K8S7WizlvUec1N3TLSCC4sx+pMVyYxawA7Y1SlfpqbUdngYQ1HWjX04L39mVrWTsjlpdMjrxbbfyL2i1NXSmtw==", "dev": true, "license": "MIT", "dependencies": { - "@malloydata/malloy": "0.0.358" + "@malloydata/malloy": "0.0.359" }, "engines": { "node": ">=20" } }, "node_modules/@malloydata/malloy-tag": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/malloy-tag/-/malloy-tag-0.0.358.tgz", - "integrity": "sha512-C2oITNMlDE9dHR/mze3vAeH1N8cPp6F81F/++HabZoBAQJxIDOmZ4zWAFy1jctSsb6oypg3qQa1TYxugVdqwqw==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/malloy-tag/-/malloy-tag-0.0.359.tgz", + "integrity": "sha512-3PEh3JTwQYjJPdFInH3ag/EhuGYvx9blg3AkzBIO8ip3u6hp1TyayBNS/mBQP2qnkKqs4T76VO3T71q7Q72o7g==", "dev": true, "license": "MIT", "dependencies": { @@ -804,14 +804,14 @@ "license": "MIT" }, "node_modules/@malloydata/render": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/render/-/render-0.0.358.tgz", - "integrity": "sha512-sTj+/hwJFTWghVSpVlNuKdcfBiUJOqkT592EadNgVHxncSLLocnEmyiWMZaq0b1H51yBW8BRQPMcrueFgS1o9g==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/render/-/render-0.0.359.tgz", + "integrity": "sha512-SiKJHsDs0yt9+PJMh0zPX19rC/5pLicR+4Ss6kkTq2oVWuoPMffsYYqAVvMaRvTy7Yn52UHoK28BAyqH9g8JZw==", "dev": true, "license": "MIT", "dependencies": { - "@malloydata/malloy-interfaces": "0.0.358", - "@malloydata/malloy-tag": "0.0.358", + "@malloydata/malloy-interfaces": "0.0.359", + "@malloydata/malloy-tag": "0.0.359", "@tanstack/solid-virtual": "^3.10.4", "lodash": "^4.17.20", "luxon": "^3.5.0", @@ -827,14 +827,14 @@ } }, "node_modules/@malloydata/render-validator": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/render-validator/-/render-validator-0.0.358.tgz", - "integrity": "sha512-5C5buU7w4W6wSnQouWHRxV3OEFy3hiG7KaeR3onPReyZV8/k+YJJ0Oy8ijqAMcPMpwRAlRQx4tpDiM5W0TureQ==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/render-validator/-/render-validator-0.0.359.tgz", + "integrity": "sha512-pEOfC24TpXUR0Yv64tCi1X3BMF0hPAhrjuDtEMTiFUl4X0r+6bhck7R7xYdOJlaOm/kGZY5YShLmqsHoqbwQpw==", "dev": true, "license": "MIT", "dependencies": { - "@malloydata/malloy-interfaces": "0.0.358", - "@malloydata/render": "0.0.358" + "@malloydata/malloy-interfaces": "0.0.359", + "@malloydata/render": "0.0.359" }, "engines": { "node": ">=20" @@ -1261,9 +1261,9 @@ } }, "node_modules/@malloydata/syntax-highlight": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/syntax-highlight/-/syntax-highlight-0.0.358.tgz", - "integrity": "sha512-yWj6c23dRJSZjOJrFPNiAvSnlRn3YDnABpavPB/XdB0c+Z5TUBgrwBCEwsJ435WYhWR563JXnWdR+JfpupHkJQ==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/syntax-highlight/-/syntax-highlight-0.0.359.tgz", + "integrity": "sha512-3BzPmwjWwEW6Kcdth/cFFmJ8WyNFvvc8T9zKeZ1mQOD7bnMnylI+vu/vNoOKCS0kovqXgh1KTjpQm/LUWk5Wpg==", "dev": true, "license": "MIT", "engines": { @@ -5809,28 +5809,28 @@ } }, "@malloydata/db-duckdb": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/db-duckdb/-/db-duckdb-0.0.358.tgz", - "integrity": "sha512-G71QdUfOWx5wvwLrMkGn44CbbuOqQvcIad/ITnFyNKPF7hUwjjOMD2Bjdto7Vn4Tm252BXl5abKXQmwab24b+w==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/db-duckdb/-/db-duckdb-0.0.359.tgz", + "integrity": "sha512-0Z/og8gTVDt61j+JQqzYQOqlxW6aycpU2SPElYHJBMzDDcgGmYW4BWcec4SK4I27pOoWjrkpvoyo4KZh1k3NMg==", "dev": true, "requires": { "@duckdb/duckdb-wasm": "1.33.1-dev13.0", "@duckdb/node-api": "1.4.4-r.1", - "@malloydata/malloy": "0.0.358", + "@malloydata/malloy": "0.0.359", "@motherduck/wasm-client": "^0.6.6", "apache-arrow": "^17.0.0", "web-worker": "^1.3.0" } }, "@malloydata/malloy": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/malloy/-/malloy-0.0.358.tgz", - "integrity": "sha512-hTjMyU3B2wymE8FqSXQNApnqaQLHI0tgmehvR4qfh9uyvUV5ATzKvRmJ6Cy0VLBIhg7fUgtrQiW6l7bvFBYRyw==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/malloy/-/malloy-0.0.359.tgz", + "integrity": "sha512-3Ew5F84+mNHxemXfTgLIhtlXyc2dKKd9Upw3AfjFDwdXYU/zUYnF4cvZUfny5j5aG4tj4rlqlrflFwBb+/qF6w==", "dev": true, "requires": { - "@malloydata/malloy-filter": "0.0.358", - "@malloydata/malloy-interfaces": "0.0.358", - "@malloydata/malloy-tag": "0.0.358", + "@malloydata/malloy-filter": "0.0.359", + "@malloydata/malloy-interfaces": "0.0.359", + "@malloydata/malloy-tag": "0.0.359", "@noble/hashes": "^1.8.0", "antlr4ts": "^0.5.0-alpha.4", "assert": "^2.0.0", @@ -5842,9 +5842,9 @@ } }, "@malloydata/malloy-filter": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/malloy-filter/-/malloy-filter-0.0.358.tgz", - "integrity": "sha512-xLc0ItlPG5ha/jqyZ0zTlMZVCxZGaMhXnVXGPKLM8Qvpdl3ZbpmiZ9mpA+TBEF9D7llh/Tq8oiKjri4A6Xl55Q==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/malloy-filter/-/malloy-filter-0.0.359.tgz", + "integrity": "sha512-jhJwZLz0RUXmo79WwvTadqwIlR7Z/2PXAmuMnc38MbJEt6PQpd2evx8JTLSsj6/+bKeUfk3o2Xg+irzZ6PDY3g==", "dev": true, "requires": { "jest-diff": "^29.6.2", @@ -5852,27 +5852,27 @@ } }, "@malloydata/malloy-interfaces": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/malloy-interfaces/-/malloy-interfaces-0.0.358.tgz", - "integrity": "sha512-kyJzFDVD0oh9ZEEEy2+7NMWBNX06QsnUIVYj8As+7r/TafOmxG8KF+bFQvlEeo8LZZ9M5MeeXeKP25GEOot50A==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/malloy-interfaces/-/malloy-interfaces-0.0.359.tgz", + "integrity": "sha512-V71tOw6XBLxGeu5cwQW1HGEvAPJwdG47xNWJCTMgZfv8hZrDoyhS7jzMjQmK0HOhz7+FPYOH8I+KYPSU377Shw==", "dev": true, "requires": { "@creditkarma/thrift-server-core": "^1.0.4" } }, "@malloydata/malloy-sql": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/malloy-sql/-/malloy-sql-0.0.358.tgz", - "integrity": "sha512-P4/hpDfia6E4ypCOQowtrBqWYtVRpyKzaxAtgx165wKZSUwbLCvEFjHmRvtFka1/dFQPKyk4z8Th//k759bNVw==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/malloy-sql/-/malloy-sql-0.0.359.tgz", + "integrity": "sha512-K8S7WizlvUec1N3TLSCC4sx+pMVyYxawA7Y1SlfpqbUdngYQ1HWjX04L39mVrWTsjlpdMjrxbbfyL2i1NXSmtw==", "dev": true, "requires": { - "@malloydata/malloy": "0.0.358" + "@malloydata/malloy": "0.0.359" } }, "@malloydata/malloy-tag": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/malloy-tag/-/malloy-tag-0.0.358.tgz", - "integrity": "sha512-C2oITNMlDE9dHR/mze3vAeH1N8cPp6F81F/++HabZoBAQJxIDOmZ4zWAFy1jctSsb6oypg3qQa1TYxugVdqwqw==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/malloy-tag/-/malloy-tag-0.0.359.tgz", + "integrity": "sha512-3PEh3JTwQYjJPdFInH3ag/EhuGYvx9blg3AkzBIO8ip3u6hp1TyayBNS/mBQP2qnkKqs4T76VO3T71q7Q72o7g==", "dev": true, "requires": { "@malloydata/motly-ts-parser": "^0.7.1", @@ -5886,13 +5886,13 @@ "dev": true }, "@malloydata/render": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/render/-/render-0.0.358.tgz", - "integrity": "sha512-sTj+/hwJFTWghVSpVlNuKdcfBiUJOqkT592EadNgVHxncSLLocnEmyiWMZaq0b1H51yBW8BRQPMcrueFgS1o9g==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/render/-/render-0.0.359.tgz", + "integrity": "sha512-SiKJHsDs0yt9+PJMh0zPX19rC/5pLicR+4Ss6kkTq2oVWuoPMffsYYqAVvMaRvTy7Yn52UHoK28BAyqH9g8JZw==", "dev": true, "requires": { - "@malloydata/malloy-interfaces": "0.0.358", - "@malloydata/malloy-tag": "0.0.358", + "@malloydata/malloy-interfaces": "0.0.359", + "@malloydata/malloy-tag": "0.0.359", "@tanstack/solid-virtual": "^3.10.4", "lodash": "^4.17.20", "luxon": "^3.5.0", @@ -6292,19 +6292,19 @@ } }, "@malloydata/render-validator": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/render-validator/-/render-validator-0.0.358.tgz", - "integrity": "sha512-5C5buU7w4W6wSnQouWHRxV3OEFy3hiG7KaeR3onPReyZV8/k+YJJ0Oy8ijqAMcPMpwRAlRQx4tpDiM5W0TureQ==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/render-validator/-/render-validator-0.0.359.tgz", + "integrity": "sha512-pEOfC24TpXUR0Yv64tCi1X3BMF0hPAhrjuDtEMTiFUl4X0r+6bhck7R7xYdOJlaOm/kGZY5YShLmqsHoqbwQpw==", "dev": true, "requires": { - "@malloydata/malloy-interfaces": "0.0.358", - "@malloydata/render": "0.0.358" + "@malloydata/malloy-interfaces": "0.0.359", + "@malloydata/render": "0.0.359" } }, "@malloydata/syntax-highlight": { - "version": "0.0.358", - "resolved": "https://registry.npmjs.org/@malloydata/syntax-highlight/-/syntax-highlight-0.0.358.tgz", - "integrity": "sha512-yWj6c23dRJSZjOJrFPNiAvSnlRn3YDnABpavPB/XdB0c+Z5TUBgrwBCEwsJ435WYhWR563JXnWdR+JfpupHkJQ==", + "version": "0.0.359", + "resolved": "https://registry.npmjs.org/@malloydata/syntax-highlight/-/syntax-highlight-0.0.359.tgz", + "integrity": "sha512-3BzPmwjWwEW6Kcdth/cFFmJ8WyNFvvc8T9zKeZ1mQOD7bnMnylI+vu/vNoOKCS0kovqXgh1KTjpQm/LUWk5Wpg==", "dev": true }, "@motherduck/wasm-client": { diff --git a/package.json b/package.json index b9c9bd32..ea819294 100644 --- a/package.json +++ b/package.json @@ -31,12 +31,12 @@ }, "homepage": "https://github.com/malloydata/malloydata.github.io#readme", "devDependencies": { - "@malloydata/db-duckdb": "0.0.358", - "@malloydata/malloy": "0.0.358", - "@malloydata/malloy-sql": "0.0.358", - "@malloydata/render": "0.0.358", - "@malloydata/render-validator": "0.0.358", - "@malloydata/syntax-highlight": "0.0.358", + "@malloydata/db-duckdb": "0.0.359", + "@malloydata/malloy": "0.0.359", + "@malloydata/malloy-sql": "0.0.359", + "@malloydata/render": "0.0.359", + "@malloydata/render-validator": "0.0.359", + "@malloydata/syntax-highlight": "0.0.359", "@types/uglify-js": "^3.17.5", "concurrently": "^6.2.1", "fs-extra": "^10.1.0", diff --git a/src/documentation/visualizations/about_rendering.malloynb b/src/documentation/visualizations/about_rendering.malloynb deleted file mode 100644 index 5e6d8efb..00000000 --- a/src/documentation/visualizations/about_rendering.malloynb +++ /dev/null @@ -1,53 +0,0 @@ ->>>markdown -# Rendering Documentation -The latest and most up to date documentation for the Malloy renderer are now found in GitHub: - -- [Renderer Tag Documentation](https://github.com/malloydata/malloy/blob/main/packages/malloy-render/docs/renderer_tags_overview.md) -- [Renderer Tag Cheatsheet](https://github.com/malloydata/malloy/blob/main/packages/malloy-render/docs/renderer_tag_cheatsheet.md) - -For developers wishing to implement custom renderers, a plugin system is available: -- [Plugin System Overview](https://github.com/malloydata/malloy/blob/main/packages/malloy-render/docs/plugin-system.md) -- [Plugin Quick Start](https://github.com/malloydata/malloy/blob/main/packages/malloy-render/docs/plugin-quick-start.md) -- [Plugin API Reference](https://github.com/malloydata/malloy/blob/main/packages/malloy-render/docs/plugin-api-reference.md) ->>>markdown - # Using Render Tags - -When Malloy runs a query, it returns two things. The *results* of the query and *metadata* about the results. The metadata are the schema for the results, including type information. Malloy also provides a mechanism to tag things in the source code and return tags with this meta data. - -In Malloy, anything that can be named can be tagged. A tag starts with a `#`. Tags that start on a new line attach the tag the thing on the following line. For more details about how tagging works, see the [Tags](../language/tags.malloynb) section. - -Malloy's rendering library interprets these tags to change how results are rendered. - -## Tagging individual elements -In the query below, the measure `percent_of_total` is tagged as a percentage. Any time `percent_of_total` is used in a query, Malloy's rendering library will be displayed as a percentage. ->>>malloy -source: flights is duckdb.table('../data/flights.parquet') extend { - measure: - flight_count is count() - # percent - percent_of_flights is flight_count / all(flight_count) -} ->>>malloy -#(docs) size=small limit=5000 -run: flights -> { - group_by: carrier - aggregate: - flight_count - percent_of_flights -} ->>>malloy -#(docs) size=small limit=5000 -run: duckdb.table('../data/flights.parquet') -> { - group_by: carrier - aggregate: flight_count is count() -} ->>>markdown - -Simply adding `# bar_chart` before the query tags it and tells the rendering library to show the result as a bar chart. See the docs on the [Bar Chart tag](./bar_charts.malloynb) for more information. ->>>malloy -#(docs) size=large limit=5000 -# bar_chart -run: duckdb.table('../data/flights.parquet') -> { - group_by: carrier - aggregate: flight_count is count() -} \ No newline at end of file diff --git a/src/documentation/visualizations/big_values.malloynb b/src/documentation/visualizations/big_values.malloynb new file mode 100644 index 00000000..9e8c6494 --- /dev/null +++ b/src/documentation/visualizations/big_values.malloynb @@ -0,0 +1,229 @@ +>>>markdown +# Big Value Cards + +The `# big_value` tag renders aggregate values as prominent metric cards, ideal for KPIs and summary statistics. Big values support number formatting, comparison indicators, sparklines, and documentation tooltips. + +## Properties + +| Property | Description | Example | +|----------|-------------|---------| +| `.size` | Card size: `sm`, `md`, `lg` | `# big_value { size=lg }` | +| `.sparkline` | Name of a hidden nested view to use as sparkline | `# big_value { sparkline=trend }` | +| `.comparison_field` | Field to compare against (shows delta) | `# big_value { comparison_field=sales }` | +| `.comparison_label` | Label for the comparison | `# big_value { comparison_label='vs Prior' }` | +| `.down_is_good` | Invert color logic (green for decrease) | `# big_value { down_is_good=true }` | +| `# description` | Tooltip documentation on the card | `# description="Help text here"` | +| `# label` | Override the display name | `# label="Total Revenue"` | +| `# hidden` | Hide the comparison field from display | Required on comparison fields | + +The examples below all use the following semantic model. +>>>malloy +source: orders is duckdb.table('../data/order_items.parquet') extend { + dimension: order_month is created_at.month + measure: + order_count is count() + # currency + total_sales is sale_price.sum() + # currency + avg_order is sale_price.avg() +} +>>>markdown + +## Basic Big Value + +Tag a query with `# big_value` and include only aggregate fields. Each measure becomes a card: +>>>malloy +#(docs) size=large limit=5000 +# big_value +run: orders -> { + aggregate: + order_count + total_sales + avg_order +} +>>>markdown + +## Formatted Metrics + +Big value cards respect number formatting tags like `# currency`, `# percent`, and `# number`: +>>>malloy +#(docs) size=large limit=5000 +# big_value +run: orders -> { + aggregate: + # label="Orders" + order_count + + # label="Revenue" + total_sales + + # label="Avg Order" + avg_order + + # label="Fulfillment Rate" + # percent + fulfillment is count() { where: status = 'Complete' } / count() +} +>>>markdown + +## Comparison Indicators + +To show a delta (percentage change) next to a metric, add a hidden comparison field that references it. The comparison field's value is the "prior" value — the renderer computes the percentage change automatically. + +When the current value is higher than the comparison value, the delta shows green (up is good). When lower, it shows red. +>>>malloy +#(docs) size=large limit=5000 +# big_value +run: orders -> { + aggregate: + # label="Current Sales" + # description="Total revenue from all orders" + total_sales + + // Simulating a "prior period" value for comparison + # big_value { comparison_field=total_sales comparison_label='vs Prior Period' } + # hidden + prior_sales is sale_price.sum() * 0.85 +} +>>>markdown + +### Down is Good + +For cost metrics where a decrease is positive, set `down_is_good=true`. This inverts the color logic so decreases show green: +>>>malloy +#(docs) size=large limit=5000 +# big_value +run: orders -> { + aggregate: + # label="Avg Shipping Cost" + # currency + # description="Average cost per order. Lower is better." + current_cost is avg(sale_price * 0.15) + + # big_value { comparison_field=current_cost comparison_label='vs Budget' down_is_good=true } + # hidden + budget_cost is avg(sale_price * 0.15) * 1.10 +} +>>>markdown + +## Sparklines + +Sparklines add a small trend chart to a big value card. Define a hidden nested view with a chart tag, then reference it by name using the `sparkline` property. + +### Line Sparkline +>>>malloy +#(docs) size=large limit=5000 +# big_value +run: orders -> { + aggregate: + # label="Total Revenue" + # big_value { sparkline=trend } + total_sales + + # line_chart { size=spark } + # hidden + nest: trend is { + group_by: order_month + aggregate: total_sales + order_by: order_month + limit: 24 + } +} +>>>markdown + +### Bar Sparkline +>>>malloy +#(docs) size=large limit=5000 +# big_value +run: orders -> { + aggregate: + # label="Order Volume" + # big_value { sparkline=volume_trend } + order_count + + # bar_chart { size=spark } + # hidden + nest: volume_trend is { + group_by: order_month + aggregate: order_count + order_by: order_month + limit: 12 + } +} +>>>markdown + +## Full Example + +Combining comparison, sparkline, and documentation in a single big value: +>>>malloy +#(docs) size=large limit=5000 +# big_value +run: orders -> { + aggregate: + # description="Total revenue from all orders. Updated daily." + # label="Total Revenue" + # big_value { sparkline=trend } + total_sales + + # big_value { comparison_field=total_sales comparison_label='vs Last Year' } + # hidden + prior_revenue is sale_price.sum() * 0.85 + + # line_chart { size=spark } + # hidden + nest: trend is { + group_by: order_month + aggregate: total_sales + order_by: order_month + limit: 24 + } +} +>>>markdown + +## Size Variants +>>>malloy +#(docs) size=large limit=5000 +# big_value { size=lg } +run: orders -> { + aggregate: + # label="Large Cards" + total_sales + avg_order +} +>>>malloy +#(docs) size=large limit=5000 +# big_value { size=sm } +run: orders -> { + aggregate: + # label="Small Cards" + total_sales + avg_order +} +>>>markdown + +## Big Values in Dashboards + +Big values work inside dashboards as nested views. This lets you combine KPI cards with tables and charts: +>>>malloy +#(docs) size=large limit=5000 +# dashboard +run: orders -> { + group_by: status + nest: + # big_value + kpis is { + aggregate: + # label="Orders" + order_count + # label="Revenue" + total_sales + } + # break + by_month is { + group_by: order_month + aggregate: total_sales + order_by: order_month desc + limit: 6 + } +} +>>>markdown diff --git a/src/documentation/visualizations/dashboards.malloynb b/src/documentation/visualizations/dashboards.malloynb index 418f09ef..28538ad0 100644 --- a/src/documentation/visualizations/dashboards.malloynb +++ b/src/documentation/visualizations/dashboards.malloynb @@ -1,7 +1,7 @@ >>>markdown # Dashboards -The `dashboard` style can be invoked on something that will render as a table `# dashboard` tag. When a query is rendered as a dashboard, dimensions aligned at the top, and aggregates and nested queries float within the dashboard. +The `# dashboard` tag renders a query result as a dashboard layout. Dimensions appear at the top, while aggregates and nested views float within the dashboard. ## Properties @@ -41,3 +41,78 @@ In such cases, the `# dashboard` renderer is useful for making the results easie run: airports -> by_state_and_county >>>markdown +## Custom Labels + +Use `# label` on aggregates or nested views to customize how they appear in the dashboard: +>>>malloy +#(docs) size=large limit=5000 +# dashboard +run: airports -> { + group_by: state + # currency + aggregate: + # label='Total Airports' + airport_count + nest: + # label='Facility Breakdown' + by_fac_type is { + group_by: fac_type + aggregate: airport_count + } + limit: 5 +} +>>>markdown + +## Layout Breaks + +By default, nested views in a dashboard flow side by side. Use `# break` on a nested view to force it onto a new row: +>>>malloy +#(docs) size=large limit=5000 +# dashboard +run: airports -> { + group_by: state + aggregate: airport_count + nest: + # break + by_fac_type is { + group_by: fac_type + aggregate: airport_count + } + limit: 5 +} +>>>markdown + +## Dashboards with Charts + +Nested views inside a dashboard can use any visualization tag. This lets you combine KPI cards, tables, and charts in a single view: +>>>malloy +#(docs) size=large limit=5000 +source: flights is duckdb.table('../data/flights.parquet') extend { + join_one: carriers is duckdb.table('../data/carriers.parquet') + on carrier = carriers.code + measure: flight_count is count() +} +>>>malloy +#(docs) size=large limit=5000 +# dashboard +run: flights -> { + group_by: carriers.nickname + aggregate: flight_count + nest: + # big_value + kpis is { + aggregate: + # label="Flights" + flight_count + } + # break + # bar_chart + by_destination is { + group_by: destination + aggregate: flight_count + limit: 10 + } + limit: 3 +} +>>>markdown + diff --git a/src/documentation/visualizations/links.malloynb b/src/documentation/visualizations/links.malloynb index b19cd086..e7935c63 100644 --- a/src/documentation/visualizations/links.malloynb +++ b/src/documentation/visualizations/links.malloynb @@ -21,6 +21,12 @@ Results can be annotated so they are rendered with links to external URLs. | `.alt` | Alt text | `# image { alt=Logo }` | | `.alt.field` | Use another field for alt text | `# image { alt.field=product_name }` | +The `alt.field` property supports relative paths to reference fields in parent or grandparent records when images are in nested views: + +- `alt.field=name` — field in the same record +- `alt.field='../brand'` — field in the parent record +- `alt.field='../../brand'` — field in the grandparent record + >>>malloy source: flights is duckdb.table('../data/flights.parquet') extend { measure: flight_count is count() @@ -48,7 +54,7 @@ run: flights -> { } >>>markdown ## Link url_template, substitution -Sometimes the variable part of the link needs to be substitued in the middle +Sometimes the variable part of the link needs to be substituted in the middle of the string. In this case, the output columns value inserted where $$ appears in the url_template. Flights to SJC with links to 'flightsfrom.com'. @@ -66,10 +72,27 @@ In the example below we want to show the Carrier's nickname with a link using th >>>malloy run: flights -> { # link {url_template='https://www.flightsfrom.com/$$' field=carrier} - group_by: + group_by: carriers.nickname # hidden carrier aggregate: flight_count limit: 5 +} +>>>markdown +## Images + +The `# image` tag renders a field's value as an inline image: +>>>malloy +run: duckdb.sql(""" + SELECT * FROM (VALUES + ('US', 'https://flagcdn.com/48x36/us.png'), + ('France', 'https://flagcdn.com/48x36/fr.png'), + ('Japan', 'https://flagcdn.com/48x36/jp.png') + ) AS t(country, flag_url) +""") -> { + select: + country + # image { height=36px alt.field=country } + flag_url } \ No newline at end of file diff --git a/src/documentation/visualizations/model_options.malloynb b/src/documentation/visualizations/model_options.malloynb new file mode 100644 index 00000000..084ec605 --- /dev/null +++ b/src/documentation/visualizations/model_options.malloynb @@ -0,0 +1,110 @@ +>>>markdown +# Model-Level Rendering Options + +Malloy supports model-level annotations (using `##`) that configure rendering defaults across an entire model. These are set at the top of a file, outside any source or query. + +## Chart Defaults + +Use `## viz..defaults.*` to set default properties for all charts of a given type in the model. Individual charts can still override these defaults. + +In this example, all line charts default to independent y-axes. The third nested chart explicitly overrides back to shared axes: +>>>malloy +## viz.line_chart.defaults.y.independent=true + +source: flights is duckdb.table('../data/flights.parquet') extend { + join_one: carriers is duckdb.table('../data/carriers.parquet') + on carrier = carriers.code + measure: + flight_count is count() + aircraft_count is count(tail_num) +} +>>>malloy +#(docs) size=large limit=5000 +run: flights -> { + group_by: carriers.nickname + aggregate: flight_count + // This chart inherits y.independent=true from the model default + # line_chart + nest: default_independent is { + group_by: dep_month is dep_time.month + aggregate: flight_count + limit: 12 + } + // This chart explicitly overrides back to shared axes + # line_chart { y.independent=false } + nest: shared_axes is { + group_by: dep_month is dep_time.month + aggregate: flight_count + limit: 12 + } + limit: 3 +} +>>>markdown + +The same pattern works for other chart types: + +``` +## viz.bar_chart.defaults.stack +## viz.bar_chart.defaults.y.independent=true +``` + +## The `# viz=` Shorthand + +Instead of `# bar_chart` or `# line_chart`, you can use the `# viz=` shorthand. All chart properties work the same way: +>>>malloy +#(docs) size=large limit=5000 +# viz=bar { title='Flights by Carrier' subtitle='Top 10' } +run: flights -> { + group_by: carriers.nickname + aggregate: flight_count + limit: 10 +} +>>>markdown + +## Theme Properties + +Use `## theme.*` at the model level to customize the appearance of rendered results. Individual views can override with `# theme.*`. +>>>malloy +## theme.tableHeaderColor=darkblue + +source: airports is duckdb.table('../data/airports.parquet') extend { + measure: airport_count is count() +} +>>>malloy +#(docs) size=small limit=5000 +run: airports -> { + group_by: state + aggregate: airport_count + limit: 5 +} +>>>markdown + +A view can override the model-level theme: +>>>malloy +#(docs) size=small limit=5000 +# theme.tableHeaderColor=darkred +run: airports -> { + group_by: state + aggregate: airport_count + limit: 5 +} +>>>markdown + +### Available Theme Properties + +| Property | Description | Example values | +|----------|-------------|----------------| +| `tableBodyColor` | Text color for table body cells | `blue`, `#333`, `rgb(0,0,0)` | +| `tableHeaderColor` | Text color for table headers | `gray`, `#666` | +| `tableBodyWeight` | Font weight for table body | `normal`, `bold`, `400` | +| `tableHeaderWeight` | Font weight for table headers | `bold`, `600` | +| `tableFontSize` | Font size for tables | `12px`, `0.9em` | +| `tableRowHeight` | Row height for tables | `24px`, `2em` | +| `tableBackground` | Background color for tables | `white`, `#f5f5f5` | +| `tableBorder` | Border style for table cells | `1px solid #ccc` | +| `tableGutterSize` | Spacing between table sections | `8px` | +| `tablePinnedBackground` | Background for pinned columns | `#fafafa` | +| `tablePinnedBorder` | Border for pinned column edges | `2px solid #ddd` | +| `fontFamily` | Font family for all rendered output | `monospace`, `'Helvetica Neue'` | +| `background` | Overall background color | `white`, `transparent` | +>>>markdown diff --git a/src/documentation/visualizations/numbers.malloynb b/src/documentation/visualizations/numbers.malloynb index 2f762aa0..07c4ba9c 100644 --- a/src/documentation/visualizations/numbers.malloynb +++ b/src/documentation/visualizations/numbers.malloynb @@ -11,26 +11,9 @@ Malloy's render provides a variety of ways to render numeric values. Tagging a | `# percent` | Format as percentage | `# percent` | | `# currency` | Currency format | `# currency`, `# currency=usd2m`, `# currency=eur` | | `# duration` | Duration format | `# duration=seconds`, `# duration=minutes`, `# duration.terse` | +| `# data_volume` | Storage size format | `# data_volume=bytes`, `# data_volume=mb` | -### `# number` shorthand - -Pattern: `# number={decimals}{scale}` where scale is `k`, `m`, `b`, `t`, `q`, or `auto`. - -### `# currency` shorthand - -Pattern: `# currency={code}{decimals}{scale}` — e.g. `# currency=usd2m` for "$42.54m". - -Codes: `usd` ($), `eur` (€), `gbp` (£). Scale and suffix options match `# number`. - -### `# duration` properties - -| Property | Description | -|----------|-------------| -| `=unit` | Input unit: `nanoseconds`, `milliseconds`, `seconds` (default), `minutes`, `hours`, `days` | -| `.terse` | Abbreviated units (ns, µs, ms, s, m, h, d) | -| `.number` | SSF format for numeric parts: `# duration { number="0.0" }` | - -The following examples that follow use the Malloy semantic data model below. +The examples on this page use the following semantic model. >>>malloy source: airports is duckdb.table('../data/airports.parquet') extend { dimension: name is concat(code, ' - ', full_name) @@ -58,35 +41,35 @@ run: flights -> { ## # number -Malloy uses LookML's (Excel) string definitions for formatting numbers. +Malloy uses LookML-style format strings (similar to Excel custom number formats) for formatting numbers. >>>markdown ```malloy # number="0" # Integer (123) # number="*00#" # Integer zero-padded to 3 places (001) -# number="0 \" String\"" # Integer followed by a string (123 String) - # Note \"String\" can be replaced with any other word +# number='0 "String"' # Integer followed by a string (123 String) + # Note "String" can be replaced with any other word # number="0.##" # Number up to 2 decimals (1. or 1.2 or 1.23) # number="0.00" # Number with exactly 2 decimals (1.23) # number="*00#.00" # Number zero-padded to 3 places and exactly 2 decimals (001.23) # number="#,##0" # Number with comma between thousands (1,234) # number="#,##0.00" # Number with comma between thousands and 2 decimals (1,234.00) -# number="0.000,,\" M\"" # Number in millions with 3 decimals (1.234 M) +# number='0.000,,"M"' # Number in millions with 3 decimals (1.234 M) # Note division by 1 million happens automatically -# number="0.000,\" K\"" # Number in thousands with 3 decimals (1.234 K) +# number='0.000,"K"' # Number in thousands with 3 decimals (1.234 K) # Note division by 1 thousand happens automatically # number="$0" # Dollars with 0 decimals ($123) # number="$0.00" # Dollars with 2 decimals ($123.00) -# number="\"€\"0" # Euros with 0 decimals (€123) +# number='"€"0' # Euros with 0 decimals (€123) # number="$#,##0.00" # Dollars with comma btwn thousands and 2 decimals ($1,234.00) # number="$#.00;($#.00)" # Dollars with 2 decimals, positive values displayed # normally, negative values wrapped in parenthesis -# number="0\%" # Display as percent with 0 decimals (1 becomes 1%) -# number="0.00\%" # Display as percent with 2 decimals (1 becomes 1.00%) +# number='0\%' # Display as percent with 0 decimals (1 becomes 1%) +# number='0.00\%' # Display as percent with 2 decimals (1 becomes 1.00%) # number="0%" # Convert to percent with 0 decimals (.01 becomes 1%) -# format="0.00%" # Convert to percent with 2 decimals (.01 becomes 1.00%) +# number="0.00%" # Convert to percent with 2 decimals (.01 becomes 1.00%) ``` >>>malloy #(docs) size=small limit=5000 @@ -115,20 +98,162 @@ The `# number=big` renderer formats large numbers with abbreviated notation and - **Q** for quadrillions (1,000,000,000,000,000) >>>markdown +### `# number` shorthand + +Pattern: `# number={decimals}{scale}` where scale is `k`, `m`, `b`, `t`, `q`, or `auto`. + +| Shorthand | Description | Example output | +|-----------|-------------|----------------| +| `# number=1k` | 1 decimal, scale to thousands | `42.5k` | +| `# number=1m` | 1 decimal, scale to millions | `42.5m` | +| `# number=auto` | Auto-select scale based on magnitude | `42.5m` or `1.2k` | +| `# number=id` | Raw number with no comma separators | `123456` | +| `# number=big` | Abbreviated with 1 decimal (legacy) | `42.5M` | + +>>>malloy +#(docs) size=small limit=5000 +# transpose +run: flights -> { + aggregate: + # number=1k + thousands is flight_count + # number=1m + millions is flight_count * 1000 + # number=auto + auto_scaled is flight_count * 1000 + # number=id + as_id is flight_count +} +>>>markdown + +### `# number` verbose syntax + +For finer control, use the verbose object syntax: + +``` +# number { scale=m decimals=1 suffix=word } +``` + +| Property | Values | Description | +|----------|--------|-------------| +| `scale` | `k`, `m`, `b`, `t`, `q`, `auto` | Divide by this magnitude | +| `decimals` | `0`, `1`, `2`, ... | Number of decimal places | +| `suffix` | `word`, `scientific`, `letter` | Suffix style after the number | + +Suffix styles: +- **`word`**: full word (e.g. "42.5 million") +- **`scientific`**: scientific notation style +- **`letter`**: single uppercase letter (e.g. "42.5M") + +>>>malloy +#(docs) size=small limit=5000 +# transpose +run: flights -> { + aggregate: + # number { scale=m decimals=1 suffix=word } + word_style is flight_count * 1000 + + # number { scale=m decimals=2 suffix=scientific } + scientific_style is flight_count * 1000 + + # number { scale=m decimals=1 suffix=letter } + letter_style is flight_count * 1000 +} +>>>markdown + +## # currency + +### `# currency` shorthand + +Pattern: `# currency={code}{decimals}{scale}` — e.g. `# currency=usd2m` for "$42.5m". + +Codes: `usd` ($), `eur` (€), `gbp` (£). Scale and suffix options match `# number`. + +### `# currency` verbose syntax + +For finer control, use the verbose object syntax: + +``` +# currency { scale=m decimals=2 suffix=finance } +``` + +| Property | Values | Description | +|----------|--------|-------------| +| `scale` | `k`, `m`, `b`, `t`, `q`, `auto` | Divide by this magnitude | +| `decimals` | `0`, `1`, `2`, ... | Number of decimal places | +| `suffix` | `finance`, `word`, `none`, `auto` | Suffix style | + +Suffix styles: +- **`finance`**: financial notation (e.g. "$42.54MM") +- **`word`**: full word (e.g. "$42.5 million") +- **`none`**: no suffix, just the scaled number +- **`auto`**: automatically choose a suffix + +>>>malloy +#(docs) size=small limit=5000 +# transpose +run: flights -> { + aggregate: + # currency=usd1m + usd_shorthand is flight_count * 1000 + + # currency { scale=m decimals=2 suffix=finance } + finance_style is flight_count * 1000 + + # currency { scale=m decimals=1 suffix=word } + word_style is flight_count * 1000 + + # currency { scale=k suffix=none } + no_suffix is flight_count +} +>>>markdown + ## Durations The `# duration` renderer interprets a value as a number of seconds and renders it as a human-adjusted duration. Other units can be specified like `# duration="minutes"`, with possible units of `"nanoseconds"`, `"microseconds"`, `"milliseconds"`, `"seconds"`, `"minutes"`, `"hours"`, and `"days"`. + +### `# duration` properties + +| Property | Description | +|----------|-------------| +| `=unit` | Input unit: `nanoseconds`, `milliseconds`, `seconds` (default), `minutes`, `hours`, `days` | +| `.terse` | Abbreviated units (ns, µs, ms, s, m, h, d) | +| `.number` | SSF format for numeric parts: `# duration { number="0.0" }` | + >>>malloy #(docs) size=small limit=5000 run: flights -> { group_by: dep_date is dep_time.day # duration="minutes" - aggregate: + aggregate: longest_flight_time is max(flight_time) total_flight_time is flight_time.sum() aggregate: - flight_count + flight_count limit: 20 } >>>markdown +## Data Volume + +The `# data_volume` tag formats numbers as human-readable storage sizes. Specify the unit of the input value: + +| Tag | Input unit | Example output | +|-----|-----------|----------------| +| `# data_volume = bytes` | Bytes | `3.7 KB` | +| `# data_volume = kb` | Kilobytes | `3.7 MB` | +| `# data_volume = mb` | Megabytes | `3.6 GB` | +| `# data_volume = gb` | Gigabytes | `3.5 TB` | +| `# data_volume = tb` | Terabytes | `3.4 PB` | + +Values are automatically scaled to the most readable unit. +>>>malloy +#(docs) size=small limit=5000 +run: flights -> { + aggregate: + # data_volume = bytes + total_bytes is flight_count * 1024 + # data_volume = mb + total_mb is flight_count * 256 +} +>>>markdown diff --git a/src/documentation/visualizations/overview.malloynb b/src/documentation/visualizations/overview.malloynb index 885277f7..76fc867b 100644 --- a/src/documentation/visualizations/overview.malloynb +++ b/src/documentation/visualizations/overview.malloynb @@ -55,13 +55,14 @@ Malloy's rendering library uses [Vega-Lite](https://vega.github.io/vega-lite/) f | [`# scatter_chart`](scatter_charts.malloynb) | Scatter plot | Uses field order: x, y, color, size, shape | | [`# shape_map`](shape_maps.malloynb) | Choropleth map (US states) | Uses field order: state, value | | [`# segment_map`](segment_maps.malloynb) | Segment map (US) | Uses field order: lat1, lon1, lat2, lon2, color | +| [`# big_value`](big_values.malloynb) | Prominent metric cards | `.size`, `.sparkline`, `.comparison_field`, `.down_is_good` | ### Layout & Structure | Tag | Description | Key Properties | |-----|-------------|----------------| | [`# dashboard`](dashboards.malloynb) | Dashboard layout | `.table.max_height`, `# break` on nested views | -| `# table` | Table (default) | `.size=fill`, `# column { width, height, word_break }` | +| [`# table`](tables.malloynb) | Table (default) | `.size=fill`, `# column { width, height, word_break }` | | [`# pivot`](pivots.malloynb) | Pivot nested query into columns | `.dimensions` | | [`# transpose`](transpose.malloynb) | Swap rows and columns | `.limit` | | [`# list`](lists.malloynb) | Comma-separated list | First non-hidden field | @@ -78,6 +79,7 @@ Malloy's rendering library uses [Vega-Lite](https://vega.github.io/vega-lite/) f | [`# duration`](numbers.malloynb) | Duration format | `# duration=seconds`, `# duration.terse` | | [`# link`](links.malloynb) | Hyperlink | `# link { url_template="https://...$$" field=id }` | | [`# image`](links.malloynb) | Render as image | `# image { height=40px alt.field=name }` | +| [`# data_volume`](numbers.malloynb) | Storage size format | `# data_volume=bytes`, `# data_volume=mb` | ### Utilities diff --git a/src/documentation/visualizations/tables.malloynb b/src/documentation/visualizations/tables.malloynb new file mode 100644 index 00000000..52f31b20 --- /dev/null +++ b/src/documentation/visualizations/tables.malloynb @@ -0,0 +1,99 @@ +>>>markdown +# Tables + +Tables are the default rendering for query results. While tables work without any tags, there are several options for controlling column display, table width, and nested data. + +## Properties + +| Property | Description | Example | +|----------|-------------|---------| +| `# table.size=fill` | Stretch table to fill container width | `# table.size=fill` | +| `# column { width }` | Set column width (`sm`, `md`, `lg`, or pixel value) | `# column { width=lg }` | +| `# column { word_break }` | Control text wrapping (`break_all`, `normal`) | `# column { word_break=break_all }` | +| `# flatten` | Flatten a nested record into parent columns | On `nest:` without `group_by` | +| `# hidden` | Hide a field from display | `# hidden` | +| `# label` | Override column header text | `# label="Display Name"` | + +The examples below all use the following semantic model. +>>>malloy +source: airports is duckdb.table('../data/airports.parquet') extend { + dimension: name is concat(code, ' - ', full_name) + measure: airport_count is count() +} + +source: flights is duckdb.table('../data/flights.parquet') extend { + join_one: orig is airports on origin = orig.code + join_one: dest is airports on destination = dest.code + join_one: carriers is duckdb.table('../data/carriers.parquet') + on carrier = carriers.code + measure: flight_count is count() +} +>>>markdown + +## Column Width + +Use the `# column` tag to control the width of individual columns. Width can be a preset (`sm`, `md`, `lg`) or a pixel value: +>>>malloy +#(docs) size=medium limit=5000 +run: flights -> { + group_by: + carrier + # column { width=lg } + orig.name + aggregate: flight_count + limit: 10 +} +>>>markdown + +## Full Width Tables + +By default, tables size to their content. Use `# table.size=fill` to stretch the table to fill its container: +>>>malloy +#(docs) size=large limit=5000 +# table.size=fill +run: flights -> { + group_by: carriers.nickname + aggregate: flight_count + limit: 10 +} +>>>markdown + +## Nested Tables + +Nested queries render as expandable sub-tables within each row: +>>>malloy +#(docs) size=large limit=5000 +run: flights -> { + group_by: carriers.nickname + aggregate: flight_count + nest: top_destinations is { + group_by: destination + aggregate: flight_count + limit: 5 + } + limit: 5 +} +>>>markdown + +## Flattened Records + +The `# flatten` tag collapses a nested record into the parent table as additional columns. This is useful for showing filtered aggregates side by side: +>>>malloy +#(docs) size=large limit=5000 +run: flights -> { + group_by: carriers.nickname + aggregate: flight_count + nest: + # flatten + to_sfo is { + aggregate: flight_count + where: destination = 'SFO' + } + # flatten + to_lax is { + aggregate: flight_count + where: destination = 'LAX' + } + limit: 10 +} +>>>markdown diff --git a/src/table_of_contents.json b/src/table_of_contents.json index 4cd86640..f574135f 100644 --- a/src/table_of_contents.json +++ b/src/table_of_contents.json @@ -304,12 +304,20 @@ "title": "Overview", "link": "/visualizations/overview.malloynb" }, + { + "title": "Tables", + "link": "/visualizations/tables.malloynb" + }, + { + "title": "Big Values", + "link": "/visualizations/big_values.malloynb" + }, { "title": "Numbers", "link": "/visualizations/numbers.malloynb" }, { - "title": "Links", + "title": "Links / Images", "link": "/visualizations/links.malloynb" }, { @@ -347,6 +355,10 @@ { "title": "Segment Maps", "link": "/visualizations/segment_maps.malloynb" + }, + { + "title": "Model Options", + "link": "/visualizations/model_options.malloynb" } ] },