Skip to content

Commit 33119c8

Browse files
mbostockFilJeff Pettiross
authored
examples overhaul; pager option; more link normalization (#1306)
* Snowflake data loader example * new examples index * edit examples README * edit examples README * examples in sidebar; pager option * edit examples README * emoji headings * brush to zoom * edit examples README * checkpoint README * no link: for example package.json * pager groups * document pager * two markdown-it examples * markdown-it-container example * snowflake example edits * more example cleanup * more example clean-up * more example clean-up * PostgreSQL data loader example * add “| Observable Framework” to page titles * consistent title * IntersectionObserver example * loader-arrow example * loader-parquet example * simplify snowflake query * deactivate * more path normalization * private examples (by default) * tweak hello-world * more consistent example READMEs * Update README * Update README * Update README * Update README * Update README * Update README * custom-stylesheet example * fix source link * remove interactive.md * don’t build examples * loader-google-analytics example * loader improvements * loader-github example * custom-input-2d example * add vega-responsive example * loader-databricks example; other improvements * Update examples/custom-stylesheet/src/index.md Co-authored-by: Philippe Rivière <[email protected]> * Update examples/api/README.md Co-authored-by: Philippe Rivière <[email protected]> * Update examples/README.md Co-authored-by: Philippe Rivière <[email protected]> * links * showcase thumbnails * smaller thumbnail * target=_blank * Revert "target=_blank" This reverts commit 9067d97. * link to live examples * import vlresize * vlresize improvements * link trailing slash * adopt octokit * links and edits * fix pointerdown * more improvements * Update README.md Typo; unclosed a tag * -chess * eia edits * google analytics edits * pmms edits (the interaction has changed) * penguins are classified based on all the numerical fields * vega-lite static width * vega-dark example --------- Co-authored-by: Philippe Rivière <[email protected]> Co-authored-by: Jeff Pettiross <[email protected]>
1 parent 1a62107 commit 33119c8

File tree

180 files changed

+3908
-728
lines changed

Some content is hidden

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

180 files changed

+3908
-728
lines changed

.github/workflows/deploy.yml

Lines changed: 2 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -21,59 +21,16 @@ jobs:
2121
with:
2222
node-version: 20
2323
cache: 'yarn'
24-
cache-dependency-path: |
25-
yarn.lock
26-
'examples/*/yarn.lock'
27-
- uses: actions/setup-python@v5
28-
with:
29-
python-version: '3.12'
30-
cache: 'pip'
31-
cache-dependency-path: 'examples/*/requirements.txt'
3224
- run: yarn --frozen-lockfile
3325
- id: date
3426
run: echo "date=$(TZ=America/Los_Angeles date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
3527
- id: cache-data
3628
uses: actions/cache@v4
3729
with:
38-
path: |
39-
docs/.observablehq/cache
40-
examples/*/src/.observablehq/cache
41-
key: data-${{ hashFiles('docs/data/*', 'examples/*/src/data/*') }}-${{ steps.date.outputs.date }}
30+
path: docs/.observablehq/cache
31+
key: data-${{ hashFiles('docs/data/*') }}-${{ steps.date.outputs.date }}
4232
- run: yarn build
4333
- run: yarn docs:build
44-
- name: Build example "api"
45-
run: yarn --frozen-lockfile && yarn build
46-
working-directory: examples/api
47-
- name: Build example "chess"
48-
run: yarn --frozen-lockfile && yarn build
49-
working-directory: examples/chess
50-
- name: Build example "eia"
51-
run: yarn --frozen-lockfile && yarn build
52-
working-directory: examples/eia
53-
env:
54-
EIA_KEY: ${{ secrets.EIA_KEY }}
55-
- name: Build example "google-analytics"
56-
run: yarn --frozen-lockfile && yarn build
57-
working-directory: examples/google-analytics
58-
env:
59-
GA_PROPERTY_ID: ${{ vars.GA_PROPERTY_ID }}
60-
GA_CLIENT_EMAIL: ${{ secrets.GA_CLIENT_EMAIL }}
61-
GA_PRIVATE_KEY: ${{ secrets.GA_PRIVATE_KEY }}
62-
- name: Build example "hello-world"
63-
run: yarn --frozen-lockfile && yarn build
64-
working-directory: examples/hello-world
65-
- name: Build example "mortgage-rates"
66-
run: yarn --frozen-lockfile && yarn build
67-
working-directory: examples/mortgage-rates
68-
- name: Build example "penguin-classification"
69-
run: pip install -r requirements.txt && yarn --frozen-lockfile && yarn build
70-
working-directory: examples/penguin-classification
71-
- name: Build example "plot"
72-
run: yarn --frozen-lockfile && yarn build
73-
working-directory: examples/plot
74-
env:
75-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
76-
- run: mkdir docs/.observablehq/dist/examples && for i in examples/*; do if [ -d $i/dist ]; then mv -v $i/dist docs/.observablehq/dist/examples/$(basename $i); fi; done
7734
- uses: cloudflare/pages-action@1
7835
with:
7936
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}

docs/config.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ Both pages and sections have a **name**, which typically corresponds to the page
118118

119119
Sections may be **collapsible**. <a href="https://github.com/observablehq/framework/releases/tag/v1.6.0" class="observablehq-version-badge" data-version="^1.6.0" title="Added in 1.6.0"></a> If the **open** option is set, the **collapsible** option defaults to true; otherwise it defaults to false. If the section is not collapsible, the **open** option is ignored and the section is always open; otherwise, the **open** option defaults to true. When a section is collapsible, clicking on a section header opens or closes that section. A section will always be open if the current page belongs to that section.
120120

121+
Pages and sections may also have a **pager** field <a href="https://github.com/observablehq/framework/pull/1306" class="observablehq-version-badge" data-version="prerelease" title="Added in #1306"></a> which specifies the name of the page group; this determines which pages are linked to via the previous and next pager buttons. If the **pager** field is not specified, it defaults the current section’s **pager** field, or to `main` for top-level pages and sections. (The home page is always in the `main` pager group.) The **pager** field can be also set to `null` to disable the pager on a specific page or section, causing adjacent pages to skip the page.
122+
121123
For example, here **pages** specifies two sections and a total of four pages:
122124

123125
```js run=false

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ index: false
129129
</picture>
130130
<div class="small arrow">Observable Plot downloads</div>
131131
</a>
132-
<a href="https://observablehq.com/framework/examples/mortgage-rates/interactive" target="_blank">
132+
<a href="https://observablehq.com/framework/examples/mortgage-rates/" target="_blank">
133133
<picture>
134134
<source srcset="./assets/mortgage-rates.webp" media="(prefers-color-scheme: dark)">
135135
<img src="./assets/mortgage-rates-dark.webp">

examples/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
/*/src/.observablehq/deploy.json
12
package-lock.json
23
yarn.lock

examples/README.md

Lines changed: 109 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,111 @@
11
# Observable Framework examples
22

3-
*First:* [Get started with Observable Framework](https://observablehq.com/framework/getting-started)
4-
5-
*This repository shows different flavors and features of what you can build with Framework:*
6-
7-
- **API** — Millions of API requests, stored in Arrow format, are analyzed in a report. [[code](./api)] [[live project](https://observablehq.com/framework/examples/api/)]
8-
- **Chess** — A data loader that retrieves several large zip files from the FIDE, extracts information about the top 10 players, and displays a rank chart. [[code](./chess)] [[live project](https://observablehq.com/framework/examples/chess/)]
9-
- **EIA** — JavaScript data loaders retrieve hourly data from the U.S. Energy Information Administration API to produce a map and time series charts. [[code](./eia)] [[live project](https://observablehq.com/framework/examples/eia/)]
10-
- **Google analytics** — Load data from the G.A. API and analyze your website’s traffic. [[code](./google-analytics)] [[live project](https://observablehq.com/framework/examples/google-analytics/)]
11-
- **Hello, world!** — A minimal test. [[code](./hello-world)] [[live project](https://observablehq.com/framework/examples/hello-world/)]
12-
- **Plot** — TypeScript data loaders that access metadata from the Observable Plot Github repo. [[code](./plot)] [[live project](https://observablehq.com/framework/examples/plot/)]
13-
- **Mortgage rates** — A small dashboard reproducing Freddie Mac’s historic mortgage rates dashboard. [[code](./mortgage-rates)] [[live project](https://observablehq.com/framework/examples/mortgage-rates/)][[interactive version](https://observablehq.com/framework/examples/mortgage-rates/interactive)]
14-
- **Penguin classification** — In a Python data loader, we use logistic regression to predict penguin species based on body size measurements. [[code](./penguin-classification)] [[live project](https://observablehq.com/framework/examples/penguin-classification/)]
3+
> [!NOTE]
4+
> To get started with Framework, please read [_Getting started_](https://observablehq.com/framework/getting-started).
5+
6+
## Showcase examples 🖼️
7+
8+
### [`api`](https://observablehq.observablehq.cloud/framework-example-api/) - Analyzing web logs
9+
10+
<a href="https://observablehq.observablehq.cloud/framework-example-api/"><img src="../docs/assets/api.webp" alt="Analyzing web logs" width="312" height="237"></a>
11+
12+
[View source](./api) · This report visualizes millions of requests to Observable’s API servers over a 7-day period in January 2024, revealing both traffic patterns and performance characteristics of Observable’s web service. This example showcases the flexibility of Observable Plot for creating custom, performant visualizations, and hints at the potential of Framework’s data loaders for working with large datasets. This example also demonstrates reading [Apache Parquet files](https://observablehq.com/framework/lib/arrow). (While this public example uses static data, at Observable we use [Snowflake data loaders](https://observablehq.observablehq.cloud/framework-example-loader-snowflake/) internally to create a similar live dashboard.)
13+
14+
### [`eia`](https://observablehq.observablehq.cloud/framework-example-eia/) - U.S. electricity grid
15+
16+
<a href="https://observablehq.observablehq.cloud/framework-example-eia/"><img src="../docs/assets/eia.webp" alt="U.S. electricity grid" width="312" height="237"></a>
17+
18+
[View source](./eia) · This dashboard visualizes electricity generation and demand across the U.S. electricity grid. The included data loaders demonstrate how to retrieve live data from the U.S. Energy Information Administration (EIA) API, while the dashboard demonstrates how to produce interactive maps, bar charts, and time-series charts with Observable Plot. A range input allows the user to rewind time to any point in the previous 24 hours, and a table shows details.
19+
20+
### [`plot`](https://observablehq.observablehq.cloud/framework-example-plot/) - Observable Plot downloads
21+
22+
<a href="https://observablehq.observablehq.cloud/framework-example-plot/"><img src="../docs/assets/plot.webp" alt="Observable Plot downloads" width="312" height="237"></a>
23+
24+
[View source](./plot) · This dashboard visualizes the popularity and development of [Observable Plot](https://observablehq.com/plot/), our open-source visualization library. The included data loaders demonstrate how to retrieve data from GitHub and npm APIs, including star counts, releases, downloads, and open issues. A time-series chart shows daily npm downloads with 7- and 28-day moving averages, and a burndown chart shows the age of open issues over time.
25+
26+
### [`mortgage-rates`](https://observablehq.observablehq.cloud/framework-example-mortgage-rates/) - Primary mortgage market survey
27+
28+
<a href="https://observablehq.observablehq.cloud/framework-example-mortgage-rates/"><img src="../docs/assets/mortgage-rates.webp" alt="Primary mortgage market survey" width="312" height="237"></a>
29+
30+
[View source](./mortgage-rates) · This dashboard visualizes Freddie Mac’s historical mortgage rates data. The included data loader demonstrates how to retrieve CSV data from Freddie Mac and visualize the result as a zoomable chart with Observable Plot. The larger time-series line chart at the bottom allows brushing to select an arbitrary time range, while the smaller visualization above zooms to show the selected range.
31+
32+
## Technique examples 🛠️
33+
34+
### Charts
35+
36+
* [`vega-dark`](https://observablehq.observablehq.cloud/framework-example-vega-dark/) - Responsive dark mode in Vega-Lite
37+
* [`vega-responsive`](https://observablehq.observablehq.cloud/framework-example-vega-responsive/) - Responsive width in Vega-Lite using ResizeObserver
38+
39+
### Data loaders
40+
41+
* [`loader-arrow`](https://observablehq.observablehq.cloud/framework-example-loader-arrow/) - Generating Apache Arrow IPC files
42+
* [`loader-databricks`](https://observablehq.observablehq.cloud/framework-example-loader-databricks/) - Loading data from Databricks
43+
* [`loader-github`](https://observablehq.observablehq.cloud/framework-example-loader-github/) - Loading data from GitHub
44+
* [`loader-google-analytics`](https://observablehq.observablehq.cloud/framework-example-loader-google-analytics/) - Loading data from Google Analytics
45+
* [`loader-parquet`](https://observablehq.observablehq.cloud/framework-example-loader-parquet/) - Generating Apache Parquet files
46+
* [`loader-postgres`](https://observablehq.observablehq.cloud/framework-example-loader-postgres/) - Loading data from PostgreSQL
47+
* [`loader-snowflake`](https://observablehq.observablehq.cloud/framework-example-loader-snowflake/) - Loading data from Snowflake
48+
49+
### Inputs
50+
51+
* [`custom-input-2d`](https://observablehq.observablehq.cloud/framework-example-custom-input-2d/) - A custom 2D input with bidirectional binding
52+
53+
### Markdown
54+
55+
* [`markdown-it-container`](https://observablehq.observablehq.cloud/framework-example-markdown-it-container/) - The markdown-it-container plugin
56+
* [`markdown-it-footnote`](https://observablehq.observablehq.cloud/framework-example-markdown-it-footnote/) - The markdown-it-footnote plugin
57+
* [`markdown-it-wikilinks`](https://observablehq.observablehq.cloud/framework-example-markdown-it-wikilinks/) - The markdown-it-wikilinks plugin
58+
59+
### Other
60+
61+
* [`chess`](https://observablehq.observablehq.cloud/framework-example-chess/) - Loading Zip data from FIDE; creating a bump chart with Observable Plot
62+
* [`custom-stylesheet`](https://observablehq.observablehq.cloud/framework-example-custom-stylesheet/) - Defining a custom stylesheet (custom theme)
63+
* [`google-analytics`](https://observablehq.observablehq.cloud/framework-example-google-analytics/) - A Google Analytics dashboard with numbers and charts
64+
* [`hello-world`](https://observablehq.observablehq.cloud/framework-example-hello-world/) - A minimal Framework project
65+
* [`intersection-observer`](https://observablehq.observablehq.cloud/framework-example-intersection-observer/) - Scrollytelling with IntersectionObserver
66+
* [`penguin-classification`](https://observablehq.observablehq.cloud/framework-example-penguin-classification/) - Logistic regression in Python; validating models with Observable Plot
67+
68+
## About these examples
69+
70+
We offer two types of examples: **techniques** and **showcases**.
71+
72+
Technique examples address lower-level needs such as “how to load data from Google Analytics” or “how to make a bump chart”. They’re smaller, piecemeal examples for common development tasks. Technique examples are intended to teach you how to accomplish a specific task and to provide reusable code that can be copy-pasted into your Framework project.
73+
74+
Showcase examples, in contrast, address higher-level user needs such as “how to analyze website traffic” or “how to show the growth of an open-source project”. These larger, complete examples demonstrate how to create useful data apps. Showcase examples are intended primarily to inspire and show Framework’s potential. As applied examples, showcase examples also demonstrate multiple techniques working together; we encourage you to view source.
75+
76+
### How to use these examples
77+
78+
You can browse the source code for any of the examples by navigating to the respective folder on GitHub. You can then copy-paste the code into your own project or download individual files. All of the example code in this repository is covered by the same [open-source license](../LICENSE) as Framework itself.
79+
80+
If you’d like to run (and tinker with) these examples locally, you can [clone the repo](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) like so:
81+
82+
```sh
83+
git clone [email protected]:observablehq/framework.git
84+
```
85+
86+
Then `cd` into the desired example directory. From there you would typically run `npm install` or `yarn` to install dependencies. Please refer to each example’s `README.md` file for specific instructions; some examples may require additional configuration, such as setting environment variables to talk to external data sources.
87+
88+
### Can’t find what you need? 🧐
89+
90+
If there’s an example you’d like to see, please let us know by [filing an issue](https://github.com/observablehq/framework/issues).
91+
92+
If you have questions about an existing example, please [open a discussion](https://github.com/observablehq/framework/discussions).
93+
94+
### We welcome contributions! 🤗
95+
96+
If you have an example that you’d like to share with the community, please [open a pull request](https://docs.github.com/en/pull-requests). Please follow the conventions set by the existing examples and let us know if you have any questions.
97+
98+
Here are some technique examples we’d like to see:
99+
100+
* Visualization
101+
* Big number with area chart
102+
* Daily metric chart with moving average
103+
* Punchcard chart (activity by day of week and hour of day)
104+
* Bump chart/rank chart
105+
* Brushing
106+
* Zooming
107+
* Data loaders
108+
* JSZip data loader
109+
* npm data loader
110+
* Markdown
111+
* Inline TeX `$…$`

examples/api/.gitignore

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
.DS_Store
2-
dist/
3-
src/.observablehq/cache/
2+
/dist/
43
node_modules/
54
yarn-error.log
6-
yarn.lock

examples/api/README.md

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,51 @@
1-
# API logs
1+
[Framework examples →](../)
22

3-
This is an example Observable Framework project. It uses API logs data collected from [observablehq.com](observablehq.com), and visualizes them as heatmaps, histograms and bar charts.
3+
# Analyzing web logs
44

5-
View the [live project](https://observablehq.com/framework/examples/api/).
5+
View live: <https://observablehq.observablehq.cloud/framework-example-api/>
66

7-
## Data loaders
7+
This report visualizes millions of requests to Observable’s API servers over a 7-day period in January 2024, revealing both traffic patterns and performance characteristics of Observable’s web service.
88

9-
The datasets used are static snapshots. We use an [Apache Arrow](https://arrow.apache.org/) file to handle the large number of API logs.
9+
This example showcases the flexibility of Observable Plot for creating custom, performant visualizations, and hints at the potential of Framework’s data loaders for working with large datasets. This example also demonstrates reading [Apache Parquet files](https://observablehq.com/framework/lib/arrow). (While this public example uses static data, at Observable we use [Snowflake data loaders](https://observablehq.observablehq.cloud/framework-example-loader-snowflake/) internally to create a similar live dashboard.)
1010

11-
## Charts
11+
> [!TIP]
12+
> Watch [our “last mile” webinar](https://www.youtube.com/watch?v=n5gFBQTClxc&t=696s) where we describe how we used this chart to optimize Observable’s API traffic.
13+
14+
## Implementation
15+
16+
```
17+
.
18+
├── README.md
19+
├── observablehq.config.js
20+
├── package.json
21+
└── src
22+
├── components
23+
│   ├── apiHeatmap.js
24+
│   └── apiHistogram.js
25+
├── data
26+
│   ├── latency-heatmap-avatar.parquet
27+
│   ├── latency-heatmap-documents-at.parquet
28+
│   ├── latency-heatmap-documents-public.parquet
29+
│   ├── latency-heatmap.parquet
30+
│   ├── latency-histogram.parquet
31+
│   ├── size-heatmap.parquet
32+
│   ├── top-routes-count.parquet
33+
│   └── top-routes-duration.parquet
34+
└── index.md
35+
```
36+
37+
No dependencies other than Framework. No required configuration (static data). The project config only adds our example header and example layout.
38+
39+
### Data
40+
41+
No data loaders; static data committed to git. The data is stored as Apache Parquet files. We use `FileAttachment.parquet` to read the files in the client. The files were generated using Snowflake data loaders, but we aren’t sharing the source code for the data loaders at this time. You can see the other Snowflake data loader example.
42+
43+
The data is represented as TKTKTK.
44+
45+
### Components
46+
47+
Two custom components.
1248

1349
This example has two reusable components for building the visualizations: `apiHeatmap.js` and `apiBars.js`. Both use a combination of [Observable Plot](https://observablehq.com/plot/) and [D3](https://d3js.org/) to create highly detailed and interactive charts.
1450

51+
Needs more explanation of how these work.

examples/api/observablehq.config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
export default {
22
root: "src",
3-
title: "Analyzing web logs",
3+
4+
// Shared Observable example configuration; feel free to remove this.
5+
title: "Observable Framework",
46
pager: false,
57
toc: false,
8+
sidebar: false,
69
head:
710
process.env.CI &&
811
`<script type="module" async src="https://events.observablehq.com/client.js?pageLoad"></script>

examples/api/package.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
{
22
"type": "module",
3+
"private": true,
34
"scripts": {
5+
"clean": "rimraf src/.observablehq/cache",
6+
"build": "rimraf dist && observable build",
47
"dev": "observable preview",
5-
"build": "rm -rf dist && observable build",
6-
"postinstall": "ln -sf ../../../../dist/bin/observable.js node_modules/.bin/observable"
8+
"deploy": "observable deploy",
9+
"observable": "observable"
710
},
811
"dependencies": {
9-
"@observablehq/framework": "link:../.."
12+
"@observablehq/framework": "^1.7.0"
13+
},
14+
"devDependencies": {
15+
"rimraf": "^5.0.5"
1016
},
1117
"engines": {
1218
"node": ">=18"

examples/api/src/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/.observablehq/cache/

0 commit comments

Comments
 (0)