You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README-mathref.md
+104-5Lines changed: 104 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -179,7 +179,7 @@ Each expression variable is a short alias resolved by catalog attribute criteria
179
179
variable: precipitation
180
180
interval: hourly
181
181
182
-
# Multi-station mean: _require_single: false concatenates ALL matches into a DataFrame
182
+
# Multi-station mean: match_all: true concatenates ALL matches into a DataFrame
183
183
- name: mean_wind_speed__all_stations__hourly
184
184
expression: ws.mean(axis=1)
185
185
variable: mean_wind_speed
@@ -189,10 +189,109 @@ Each expression variable is a short alias resolved by catalog attribute criteria
189
189
ws:
190
190
variable: wind_speed
191
191
interval: hourly
192
-
_require_single: false
192
+
match_all: true
193
193
```
194
194
195
-
> **`_require_single: false`** — when set inside a `search_map` criteria block, *all* catalog entries matching those criteria are fetched and concatenated column-wise (axis=1 join by timestamp index) so the alias resolves to a DataFrame. Use this for multi-station aggregates such as `ws.mean(axis=1)`.
195
+
> **`match_all: true`** — when set inside a `search_map` criteria block, *all* catalog entries matching those criteria are fetched and concatenated column-wise (axis=1 join by timestamp index) so the alias resolves to a DataFrame. Use this for multi-station aggregates such as `ws.mean(axis=1)`.
196
+
197
+
### Regex matching in criteria
198
+
199
+
By default, every `attr=value` criterion in a `search_map` block (or in a `catalog.search()` call) performs an **exact equality check**. You can switch to a **case-insensitive regular expression** by using `~` instead of `=` as the operator, or by passing a tilde-prefixed string in code.
200
+
201
+
#### Rules
202
+
203
+
| Rule | Detail |
204
+
|---|---|
205
+
| Operator | `~` in the editor/YAML; `"~pattern"` (tilde-prefixed string) in Python |
206
+
| Matching | `re.fullmatch` — the pattern must match the **entire** attribute value |
207
+
| Case | Case-insensitive (`re.IGNORECASE`) |
208
+
| Partial match | Use `.*` to allow leading/trailing characters (e.g. `~EC.*`) |
209
+
210
+
#### YAML examples
211
+
212
+
```yaml
213
+
search_map:
214
+
# Exact match (default) — only "wind_speed" qualifies, not "wind_speed_mph"
215
+
obs:
216
+
variable: wind_speed
217
+
interval: hourly
218
+
219
+
# Regex fullmatch — matches "wind_speed" AND "wind_speed_mph" (starts with "wind_speed")
# catalog.search() with regex — find all refs whose name starts with "station"
254
+
refs = catalog.search(name="~station.*")
255
+
# catalog.search() with regex attribute — find all EC-family variables
256
+
refs = catalog.search(variable="~EC.*")
257
+
```
258
+
259
+
#### Using regex in the editor
260
+
261
+
Type criteria using `~` instead of `=` to indicate regex:
262
+
263
+
```
264
+
variable~EC.*
265
+
variable~EC.*, interval=hourly
266
+
```
267
+
268
+
The **`+attr`** picker always appends `attr=`. To switch to regex, manually replace `=` with `~` in the criteria field after picking the attribute name.
269
+
270
+
#### Partial vs full match
271
+
272
+
`re.fullmatch` is used, so the pattern must match the **entire** attribute value, not just a substring:
| `~ec` | `"EC_DAILY"` | ❌ no — same fullmatch rule applies |
281
+
| `~ec.*` | `"EC_DAILY"` | ✅ yes |
282
+
| `~(flow\|stage)` | `"flow"` | ✅ yes |
283
+
| `~(flow\|stage)` | `"velocity"` | ❌ no |
284
+
285
+
#### Limitation — literal `~` values
286
+
287
+
If a metadata attribute value legitimately starts with `~` (unusual), it **cannot** be matched using `=` with a tilde-prefixed expected value, because any value beginning with `~` is interpreted as a regex pattern. As a workaround, use a callable predicate in Python:
288
+
289
+
```python
290
+
# Match the literal value "~special" exactly
291
+
refs = catalog.search(variable=lambda v: v == "~special")
292
+
```
293
+
294
+
This limitation does not apply to the YAML or editor format, where you would simply use `variable=~special` to trigger regex mode.
196
295
197
296
### Chaining Math References
198
297
@@ -278,8 +377,8 @@ One row per expression variable. Rows can be added with **+ Add variable** and r
278
377
| Field | Purpose |
279
378
|---|---|
280
379
| **Alias** | Short identifier used in the Expression (e.g. `obs`) |
281
-
| **Match all** | When checked, all matching catalog entries are concatenated into a DataFrame (equivalent to `_require_single: false`) |
282
-
| **Catalog criteria** | Comma-separated `attr=val` pairs used to search the catalog (e.g. `variable=wind_speed, interval=hourly`) |
380
+
| **Match all** | When checked, all matching catalog entries are concatenated into a DataFrame (equivalent to `match_all: true` in YAML) |
381
+
| **Catalog criteria** | Comma-separated `attr=val` (exact) or `attr~regex` (regex fullmatch) pairs used to search the catalog (e.g. `variable=wind_speed, interval=hourly` or `variable~EC.*, interval=hourly`) |
283
382
| **+ attr** | Drop-down picker; selecting an attribute name appends `attr=` to the criteria field so you only need to fill in the value |
284
383
| **▶** | Per-row test button — runs the criteria against the live catalog and shows an inline badge: `✅ 1 match`, `⚠️ N matches`, or `❌ 0 matches`. If exactly one match is found and the **Attributes** field is empty, it is auto-filled with the match's identifying attributes |
0 commit comments