Skip to content

Commit

Permalink
chore: Merge conflicts.
Browse files Browse the repository at this point in the history
  • Loading branch information
jheer committed Feb 13, 2025
2 parents ccc3e50 + e36e9c2 commit 00f90f5
Show file tree
Hide file tree
Showing 59 changed files with 2,732 additions and 943 deletions.
2 changes: 1 addition & 1 deletion data/us-president-favorability.csv
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Chester A. Arthur,3,10,8,5,48,27,1881-09-19,https://upload.wikimedia.org/wikiped
Grover Cleveland,4,17,12,6,47,14,1885-03-04,https://upload.wikimedia.org/wikipedia/commons/thumb/f/f3/Grover_Cleveland_-_NARA_-_518139_%28cropped%29.jpg/160px-Grover_Cleveland_-_NARA_-_518139_%28cropped%29.jpg
Benjamin Harrison,3,13,10,4,54,15,1889-03-04,https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Benjamin_Harrison%2C_head_and_shoulders_bw_photo%2C_1896.jpg/160px-Benjamin_Harrison%2C_head_and_shoulders_bw_photo%2C_1896.jpg
William McKinley,2,16,11,4,53,14,1897-03-04,https://upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Mckinley.jpg/160px-Mckinley.jpg
Theodore Roosevelt,25,37,8,4,23,3,1901-09-14,https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/President_Roosevelt_-_Pach_Bros.jpg/160px-President_Roosevelt_-_Pach_Bros.jpg
Theodore Roosevelt,25,37,8,4,23,3,1901-09-14,https://upload.wikimedia.org/wikipedia/commons/thumb/5/5b/Theodore_Roosevelt_by_the_Pach_Bros.jpg/160px-Theodore_Roosevelt_by_the_Pach_Bros.jpg
William Howard Taft,3,18,13,6,52,8,1909-03-04,https://upload.wikimedia.org/wikipedia/commons/thumb/5/59/William_Howard_Taft_-_Harris_and_Ewing.jpg/160px-William_Howard_Taft_-_Harris_and_Ewing.jpg
Woodrow Wilson,7,25,14,11,39,4,1913-03-04,https://upload.wikimedia.org/wikipedia/commons/thumb/5/53/Thomas_Woodrow_Wilson%2C_Harris_%26_Ewing_bw_photo_portrait%2C_1919.jpg/160px-Thomas_Woodrow_Wilson%2C_Harris_%26_Ewing_bw_photo_portrait%2C_1919.jpg
Warren G. Harding,3,12,12,11,46,16,1921-03-04,https://upload.wikimedia.org/wikipedia/commons/thumb/c/c4/Warren_G_Harding-Harris_%26_Ewing.jpg/160px-Warren_G_Harding-Harris_%26_Ewing.jpg
Expand Down
6 changes: 4 additions & 2 deletions docs/.vitepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ export default defineConfig({
{ text: 'Mosaic vgplot', link: '/vgplot/' },
{ text: 'Mosaic Spec', link: '/spec/' },
{ text: 'Mosaic Server', link: '/server/' },
{ text: 'Jupyter Widget', link: '/jupyter/' }
{ text: 'Jupyter Widget', link: '/jupyter/' },
{ text: 'Web Clients', link: '/web-clients/' }
]
},
{ text: 'Examples', link: '/examples/' },
Expand Down Expand Up @@ -62,7 +63,8 @@ export default defineConfig({
{ text: 'Mosaic vgplot', link: '/vgplot/' },
{ text: 'Mosaic Spec', link: '/spec/' },
{ text: 'Mosaic Server', link: '/server/' },
{ text: 'Jupyter Widget', link: '/jupyter/' }
{ text: 'Jupyter Widget', link: '/jupyter/' },
{ text: 'Web Clients', link: '/web-clients/' }
]
},
{ text: 'Examples', link: '/examples/' },
Expand Down
1 change: 1 addition & 0 deletions docs/api/core/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Clients are responsible for publishing their data needs and performing data proc

If you are interested in creating your own Mosaic clients, see the [Mosaic GitHub repository](https://github.com/uwdata/mosaic).
For concrete examples, start with the source code of [Mosaic inputs](https://github.com/uwdata/mosaic/tree/main/packages/inputs/src).
If you are creating clients for web frameworks such as React, Svelte, or Vue, see the [web clients](/web-clients/) documentation.

## constructor

Expand Down
6 changes: 6 additions & 0 deletions docs/api/sql/aggregate-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ Create an aggregate function that calculates the sum of the input _expression_.

Create an aggregate function that calculates the product of the input _expression_.

## geomean

`geomean(expression)`

Create an aggregate function that calculates the geometric mean of the input _expression_.

## median

`median(expression)`
Expand Down
2 changes: 2 additions & 0 deletions docs/core/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ Clients can also request queries in response to internal events. The client `req
The `requestUpdate()` method makes throttled requests for a standard `query()`; multiple calls to `requestUpdate()` may result in only one query (the most recent) being serviced.
Finally, clients may expose a `filterBy` Selection property. The predicates provided by `filterBy` are passed as an argument to the client `query()` method by the coordinator.

[Developing Clients for Web Frameworks](/web-clients/)

[Client API Reference](/api/core/client)

## Coordinator
Expand Down
166 changes: 166 additions & 0 deletions docs/web-clients/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# Clients for Web Frameworks

[Clients](/core/#clients) are responsible for publishing their data needs and performing data processing tasks—such as rendering a visualization.
The [`MosaicClient` class](/api/core/client.html) provides a base class for client implementation.

Many applications are written in web frameworks such as [React](https://react.dev), [Svelte](https://svelte.dev), and [Vue](https://vuejs.org).
These frameworks have their own state management and lifecycle management systems which make it difficult to use the `MosaicClient` class directly.
Mosaic has a `makeClient` API that makes it easier to integrate with such frameworks.

## Svelte Example

Here is an example `Count` component written in Svelte, with `$effect`:

```svelte
<script>
// Show the number of rows in the table.
// If a `selection` is provided, show the filtered number of rows as well.
import { makeClient } from "@uwdata/mosaic-core";
import { count, Query } from "@uwdata/mosaic-sql";
const { coordinator, table, selection } = $props();
let totalCount = $state(null);
let filteredCount = $state(null);
let isError = $state(false);
let isPending = $state(false);
$effect(() => {
// Capture tableName so Svelte keeps track of it in the effect.
// When `table` changes, Svelte will re-run the effect and cause the old client
// be destroyed and a new client be created.
let tableName = table;
// Note that the identity of `selection` is also captured below.
// If it is replaced with a new instance of Selection, the client will get recreated as well.
let client = makeClient({
coordinator,
selection,
prepare: async () => {
// Preparation work before the client starts.
// Here we get the total number of rows in the table.
let result = await coordinator.query(
Query.from(tableName).select({ count: count() })
);
totalCount = result.get(0).count;
},
query: (predicate) => {
// Returns a query to retrieve the data.
// The `predicate` is the selection's predicate for this client.
// Here we use it to get the filtered count.
return Query.from(tableName)
.select({ count: count() })
.where(predicate);
},
queryResult: (data) => {
// The query result is available.
filteredCount = data.get(0).count;
isError = false;
isPending = false;
},
queryPending: () => {
// The query is pending.
isPending = true;
isError = false;
},
queryError: () => {
// There is an error running the query.
isPending = false;
isError = true;
},
});
return () => {
// Destroy the client on effect cleanup.
client.destroy();
};
});
</script>
{filteredCount} / {totalCount}
{isPending ? "(pending)" : ""}
{isError ? "(error)" : ""}
```

The `makeClient` API combined with `$effect` allows the component to update its client when the props changes. This includes:
- Replacement of the `coordinator` instance.
- Changes to the `table` name.
- Replacement of the `selection` instance (i.e., when the `selection` is replaced with a new instance of `Selection`).

## React Example

Here is the same example in React:

```jsx
import { makeClient } from "@uwdata/mosaic-core";
import { count, Query } from "@uwdata/mosaic-sql";
import { useState, useEffect } from "react";

/** Show the number of rows in the table.
* If a `selection` is provided, show the filtered number of rows as well. */
export function Count(props) {
const { coordinator, table, selection } = props;

const [totalCount, setTotalCount] = useState(null);
const [filteredCount, setFilteredCount] = useState(null);
const [isError, setIsError] = useState(false);
const [isPending, setIsPending] = useState(false);

useEffect(() => {
// Note that the identity of `table` and `selection` is captured below.
// If they are replaced with a new instances, the client will get recreated as well.

const client = makeClient({
coordinator,
selection,
prepare: async () => {
// Preparation work before the client starts.
// Here we get the total number of rows in the table.
const result = await coordinator.query(
Query.from(table).select({ count: count() })
);
setTotalCount(result.get(0).count);
},
query: (predicate) => {
// Returns a query to retrieve the data.
// The `predicate` is the selection's predicate for this client.
// Here we use it to get the filtered count.
return Query.from(table)
.select({ count: count() })
.where(predicate);
},
queryResult: (data) => {
// The query result is available.
setFilteredCount(data.get(0).count);
setIsError(false);
setIsPending(false);
},
queryPending: () => {
// The query is pending.
setIsPending(true);
setIsError(false);
},
queryError: () => {
// There is an error running the query.
setIsPending(false);
setIsError(true);
},
});

return () => {
// Destroy the client on effect cleanup.
client.destroy();
};
}, [coordinator, table, selection]);

return (
<div>
{filteredCount} / {totalCount}
{isPending ? "(pending)" : ""}
{isError ? "(error)" : ""}
</div>
);
}
```
Loading

0 comments on commit 00f90f5

Please sign in to comment.