# Multiple filter conditions on csv with Input.select

**URL:** https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889
**Category:** Help
**Created:** [March 3, 2024, 9:18pm UTC](https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889 "2024-03-03T21:18:28Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![zeetools](https://avatars.discourse-cdn.com/v4/letter/z/c2a13f/32.png) [@zeetools](https://talk.observablehq.com/u/zeetools)
#### Post date: [March 3, 2024, 9:18pm UTC](https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889/1 "2024-03-03T21:18:28Z")

</div>

Hello again,

Apologies if this has been asked before, I was wondering how I can filter my dataset using multiple selection options. A user would select several of these and the data plotted would only be where all the conditions match. I’ve been able to do this by “hardcoding” my expectation, but wondering if there is a way to do this more elegantly.

 ![filtering](https://canada1.discourse-cdn.com/flex030/uploads/observablehq/original/2X/6/63844b710b69d45ac8be790222ee0a0f56b8ddf5.jpeg)

---

<div class="post-metadata">

### Author: ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)
#### Post date: [March 3, 2024, 9:38pm UTC](https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889/2 "2024-03-03T21:38:06Z")

</div>

I see that your cells don’t have a `viewof` prefix. Just to tick off a few boxes so that I can give a better answer:

- Are you asking about notebooks or Framework projects?
- Are you familiar with Observable’s `viewof` macro (for notebooks) or with `view()` (for Framework)?
- Have you come across [Inputs.form()](https://observablehq.com/@observablehq/input-form) before?

---

<div class="post-metadata">

### Author: ![zeetools](https://avatars.discourse-cdn.com/v4/letter/z/c2a13f/32.png) [@zeetools](https://talk.observablehq.com/u/zeetools)
#### Post date: [March 3, 2024, 9:41pm UTC](https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889/3 "2024-03-03T21:41:58Z")

</div>

I’m working primarily in Framework, but I’m trying to replicate to whatever extent I can in notebooks to quickly see errors and iterate.

This is what I ended up doing in Framework for a single filter

```js
const a = FileAttachment("./data/test.csv").csv({typed: true});
const aggressor = view(Inputs.select(d3.group(await a, d => d.Aggressor)));

```

In my plot, I call the aggressor constant:

```
  x: {grid: true, label: "Measurement Number", labelAnchor: "center", anchor: "left"},
  y: {grid: true, label: "Frequency Drift (Hz)"},
  marks: [
    Plot.ruleY([0]),
    Plot.line(aggressor, {fy: "Measurement", x: "Measurement_number", y: "Measurement Value", z: "SerialNumber", stroke: "TCXO", tip: true})
  ]
}))

```

}

As for “view”, I believe that is what I was trying to do in Framework, but perhaps I’ve done it incorrectly.

I haven’t explored Inputs.form() before, I can look into this.

---

<div class="post-metadata">

### Author: ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)
#### Post date: [March 3, 2024, 11:00pm UTC](https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889/4 "2024-03-03T23:00:17Z")

</div>

Inputs.form() lets you compose multiple inputs into one. You can technically do the same yourself, but it removes some boilerplate for you.

That in turn makes it easier to create data-driven filters. Here’s a basic example using the built-in `penguins` dataset:

```js
~~~js
const prop = (arr, name) => arr.map(d => d[name]);
const unique = (arr) => [...new Set(arr)];
~~~

~~~js
const data = penguins;
const choices = view(Inputs.form({
  species: Inputs.checkbox(unique(prop(data, "species")), {label: "Species"}),
  island: Inputs.checkbox(unique(prop(data, "island")), {label: "Island"}),
  sex: Inputs.checkbox(unique(prop(data, "sex")), {label: "Sex"}),
}));
~~~

~~~js
const filters = Object.entries(choices).map(
  ([name, values]) => values.length
    ? d => values.some(v => v === d[name])
    : () => true
  );
const filtered = data.filter(d => filters.every(f => f(d)));
display(Inputs.table(filtered));
~~~

```

 ![image](https://canada1.discourse-cdn.com/flex030/uploads/observablehq/original/2X/8/83b16baa3637924819777f8c2a9d70c9f19a717d.png)

---

<div class="post-metadata">

### Author: ![zeetools](https://avatars.discourse-cdn.com/v4/letter/z/c2a13f/32.png) [@zeetools](https://talk.observablehq.com/u/zeetools)
#### Post date: [March 3, 2024, 11:07pm UTC](https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889/5 "2024-03-03T23:07:23Z")

</div>

Thanks a lot! I’ll try this out. Sorry, one quick question, I assume this is for functions that you’ve defined that can be used but when I put this in my .md file I get the following error:

```js
const prop = (arr, name) => arr.map(d => d[name]);
const unique = (arr) => [...new Set(arr)];

```

TypeError: arr.map is not a function. (In ‘arr.map(d =\> d[name])’, ‘arr.map’ is undefined)

Am I doing something fundamentally wrong?

 ![mdfile](https://canada1.discourse-cdn.com/flex030/uploads/observablehq/original/2X/6/6f90e0a8273f7b100964dfaab7562c6698bce407.jpeg)

---

<div class="post-metadata">

### Author: ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)
#### Post date: [March 3, 2024, 11:11pm UTC](https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889/6 "2024-03-03T23:11:44Z")

</div>

> [@zeetools](#):
>
> TypeError: arr.map is not a function. (In ‘arr.map(d =\> d[name])’, ‘arr.map’ is undefined)
> 
> Am I doing something fundamentally wrong?

Remember [Error grouping data by csv column - #2 by mootari](https://talk.observablehq.com/t/error-grouping-data-by-csv-column/8887/2) ? 😉

I’d recommend to put your `const a` declaration into a separate fenced code block so that the Runtime will resolve the Promise for you. I didn’t need to do that for `penguins` because Framework already takes care of the loading and resolving for built-in datasets.

---

<div class="post-metadata">

### Author: ![zeetools](https://avatars.discourse-cdn.com/v4/letter/z/c2a13f/32.png) [@zeetools](https://talk.observablehq.com/u/zeetools)
#### Post date: [March 3, 2024, 11:14pm UTC](https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889/7 "2024-03-03T23:14:30Z")

</div>

Ugh! Sorry! Fixed it now, it’s a lot clearer, thanks so much.

---

<div class="post-metadata">

### Author: ![zeetools](https://avatars.discourse-cdn.com/v4/letter/z/c2a13f/32.png) [@zeetools](https://talk.observablehq.com/u/zeetools)
#### Post date: [March 3, 2024, 11:29pm UTC](https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889/8 "2024-03-03T23:29:59Z")

</div>

@mootari Sorry, I’ll keep digging into this, but here’s where I am now.

 ![filtered](https://canada1.discourse-cdn.com/flex030/uploads/observablehq/original/2X/6/608086c61cd3d97fd17c8d73a62789d8f2a7b08d.jpeg)

TypeError: values.some is not a function. (In ‘values.some(v =\> v === d[name])’, ‘values.some’ is undefined)

---

<div class="post-metadata">

### Author: ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)
#### Post date: [March 3, 2024, 11:51pm UTC](https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889/9 "2024-03-03T23:51:48Z")

</div>

The example is tailored to checkboxes where each input returns an array of values. Selects only return a single value, so you will have to adjust the filter callbacks accordingly:

```js
const filters = Object.entries(choices).map(
  ([name, value]) => Array.isArray(value)
    ? value.length ? d => value.some(v => v === d[name]) : () => true
    : value !== undefined ? d => value === d[name] : () => true
  );

```

---

<div class="post-metadata">

### Author: ![mbostock](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mbostock/32/9_2.png) [@mbostock](https://talk.observablehq.com/u/mbostock)
#### Post date: [March 5, 2024, 4:21pm UTC](https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889/10 "2024-03-05T16:21:01Z")

</div>

Is there a much of a reason to use `Inputs.form` in Observable Framework? I feel that’s mostly a workaround for notebooks where each cell can only expose a single value.

In Framework you can call view multiple times to declare separate reactive values within the same code block. And the advantage is that these can update independently (rather than with `Inputs.form` where the entire form updates, potentially causing more downstream evaluation than necessary).

So why not do this:

```js
const species = view(Inputs.checkbox(penguins.map((d) => d.species), {label: "Species", unique: true}));
const island = view(Inputs.checkbox(penguins.map((d) => d.island), {label: "Island", unique: true}));
const sex = view(Inputs.checkbox(penguins.map((d) => d.sex), {label: "Sex", unique: true}));

```

This also uses the **unique** option of Inputs.checkbox so you don’t have to do that yourself. (And I prefer to inline the `array.map` instead of writing the `prop` helper.)

---

<div class="post-metadata">

### Author: ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)
#### Post date: [March 5, 2024, 4:24pm UTC](https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889/11 "2024-03-05T16:24:54Z")

</div>

> [@mbostock](#):
>
> Is there a much of a reason to use `Inputs.form` in Observable Framework? I feel that’s mostly a workaround for notebooks where each cell can only expose a single value.

Imo yes, to generate inputs from configurations:

> [@mootari](#):
>
> That in turn makes it easier to create data-driven filters.

My example above only hints at that because I didn’t want to complicate it unnecessarily.

> [@mbostock](#):
>
> This also uses the **unique** option of Inputs.checkbox

TIL! 🙏

---

<div class="post-metadata">

### Author: ![mbostock](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mbostock/32/9_2.png) [@mbostock](https://talk.observablehq.com/u/mbostock)
#### Post date: [March 5, 2024, 4:27pm UTC](https://talk.observablehq.com/t/multiple-filter-conditions-on-csv-with-input-select/8889/12 "2024-03-05T16:27:38Z")

</div>

> [@mootari](#):
>
> to generate inputs from configurations

Ah, sure. But that’s a pretty rare use case where you don’t know the set of inputs/dynamic variables statically, and I don’t recommend such indirection in most cases.
