Customize Your Tableau Filters

 

I’ve always wanted the ability to customize Tableau filters a little more than what’s possible out of the box. For example, it would be nice to be able to change the style of the checkboxes or add some additional text or use a completely different UI. Aside from UI, I’d like to be able to enable additional functionality such as the ability to define which items are selected by default or trigger an action based on a selection. I’ve been faced with these challenges several times in the past and have struggled to find an out-of-the-box solution. So, today I’m going to share a method for creating your own 100% customizable filters in Tableau. I’ll warn you ahead of time that this will be an advanced technique, so I would only use it when standard filters won’t work.

 

UI Examples

Before we jump into the tutorial, let me first share some examples of what we might want to do. Let’s start with UI. Note: Our focus throughout this blog will be on multi-select filters, but we could apply these same techniques to other types of filters as well.

 

A standard multi-select filter looks something like this:

 

 

We could start by adding some additional information to the text. For example, perhaps we just want to show the number of rows for each month. Here we’ve added the row count in a smaller and lighter font:

 



Perhaps you want to have multiple lines of text?

 


I’ve always wanted to style filters a bit differently. This could be particularly valuable in embedded analytics when you want the style of the Tableau content to match the overall website or app. For example, in the following, I’ve used blue checkboxes and a light blue highlight.

 

 

Or maybe you don’t want checkboxes at all. Perhaps you’d like to use toggles instead?

 

 

Or maybe you want a completely different UI altogether. In the following, I’m using a concept called “Toggle Tokens”:

 



Those are just a few examples, but the sky is the limit. With the technique I’ll be sharing, we can customize filters however we want—we can change text colors, checkbox colors, background colors, checkbox styles, use completely different UI layouts, put filters in columns and rows (or even a single row), add dividing lines, etc. Pretty much anything we want!!

 

Note: If you’d like to interact with these examples, you can access them on Tableau Public: Custom Filter UI Styles

 

Functional Examples

But UI is just the start. With this technique, we can implement several pieces of functionality not available in normal filters. For example, what if you want a filter to automatically select the last 3 months? Or, perhaps, you want it to automatically select any month that is complete (i.e. not the current or future months)? The examples I’ve shown earlier are automatically set up to select the last three months. And you can see in the multiline example that I’ve shown which months are “complete” and which are not. With a few tweaks, we could easily set up the filter to automatically select only the complete ones.

 

Perhaps you want to give your user some additional information about the filter option but don’t want to display it right on screen. Wouldn’t it be nice if you could use tooltips to provide that additional info?

 

 

You could even implement viz-in-tooltip to show quick charts or provide some basic data profiling.

 

A problem I’ve run into several times in the past is the need to trigger some sort of action based on the selection of a filter. For example, perhaps you want to prevent your user from deselecting all options, so when they deselect everything, you want to automatically select the last month. You can’t do that with filters, but you can with this technique.

 

We’ll get into this in the tutorial, but this technique leverages a parameter to store information about which options are selected and deselected. Because this information is stored in a parameter, it means that the filter can be used across multiple, unrelated data sources. For example, perhaps you have one data source with an Order Date and another with a Ship Date and you wish to use the same filter for both. With this technique, you can easily do that. In some ways, this technique is essentially like being able to create multi-select parameters.

 

How-To

Now that you understand the use cases, let’s talk about how to create these custom filters. Here is the basic concept:


 Each filter is a sheet.

▪ A parameter stores the states of each item in the filter.

 Parameter actions are used to add and update the state of items as they are clicked.

 Custom shapes are used to visually show each item’s “state” (whether an object is selected or deselected).

 As items are clicked, the sheet is filtered to show the correct custom shapes.


Let’s start with the last item first since it will require us to do some data modeling. We’ll get into this more later, but the goal is that users can click an item and the box will toggle between selected and deselected. The problem with this is that, when you click a mark in Tableau, it generally remains selected until you click it again to deselect it. Because of that, you’d have to click each item twice to toggle it. There have been several documented hacks for correcting this problem, but I’ve personally had issues with them in certain situations. So, to avoid that, I bring in an Excel or text file with a single column, Toggle, and two rows, “Checked” and “Unchecked”. I then relate this to my data in the Tableau data source using a 1 = 1 relationship.

 



Theoretically, this will duplicate my data, but that’s not entirely true. When the toggle data source is not used on a sheet, Tableau will never include it in its query so the data will not be duplicated. When the toggle is in use, then it will be duplicated, but we’ll deal with this by filtering out the extra data.

 

Now here’s the trick…We’ll use this toggle field to filter the data every time an option is clicked. When data is filtered, any existing selections are cleared. So, by filtering the data on each click, we’ll never have any selected marks. Thus, we’ll only need to click once to toggle the value.

 

With our data modeled, we’ll create a new sheet. We’ll create an inline calculation on Columns with value, 0.0, we’ll drag our dimension to rows, and we’ll choose the Shape mark type.

 



Next, we’ll edit the axis so that it runs from -0.1 to 1, we’ll drag our dimension to the label card, then we’ll hide the header for the dimension on the rows shelf.

 



Now we’ll drag Toggle to the shape card and assign custom shapes to the Checked and Unchecked options (Note: I created all of mine in PowerPoint and have uploaded them here: Check Shapes).

 



While it appears that we’re only showing checked shapes, both shapes are shown. They are on top of each other, making it look as though only the checked ones are visible. We now need to make it so that, when an item is clicked, it toggles between being checked and unchecked. But, before we can do that, we need some place to store the current “state” of each item. For that, we’re going to use a parameter. We’re essentially going to build a long string of values with the state of each item and store them in the parameter. For example, if the parameter reads ;2023-11-01 00:00:00|Unchecked;2023-12-01 00:00:00|Checked, this means that November 2023 is unchecked and December 2023 is checked. By default, we’ll treat a value as unchecked if it is not in the list. Thus, January through October are unchecked in this example.

 

Let’s start by creating the parameter—I’ve called mine Selections. We’ll leave it empty for now, indicating that all items are unchecked. Then we’ll create a calculated field to act as a filter on our sheet.

 

Toggle Filter

// Keep only the month and toggle values that are in the parameter.

IF CONTAINS([Selections], STR([Month Year])) = FALSE THEN

    // Value has never been initialized, so it's unchecked.

    IF [Toggle]="Unchecked" THEN

        "Keep"

    ELSE

        "Hide"

    END

ELSEIF CONTAINS([Selections], [Month/Toggle]) THEN

    "Keep"

ELSE

    "Hide"

END

 

This will check the values in the parameter and determine which are checked and which are not. We’ll use this as a filter on our sheet, keeping only “Keep” values, which will ensure that we only have one mark for each item—either checked or unchecked, but not both. With the parameter example shown earlier, we should see this:

 



We’re going to build the functionality for maintaining the parameter momentarily, but let’s first create a filter capable of filtering actual charts. We’ll create the following calculated field:

 

Chart Filter

// Filter any month that has Unchecked in the parameter.

IF CONTAINS([Selections], STR([Month Year])) = FALSE THEN

    // Value has never been initialized, so it's unchecked.

    "Hide"

ELSEIF CONTAINS([Selections], STR([Month Year]) + "|Checked") THEN

    "Keep"

ELSE

    "Hide"

END

 

This calculation checks our field, Month Year against the values in the parameter to determine if they are checked or unchecked. We’ll then filter our view keeping only “Keep” values. Here’s a sample chart using this filter and the parameter example shared previously. As you can see, only December is shown.

 

 

Creating the Interactivity

Yay! We now have a partially functional filter! The last piece is to create the functionality allowing users to interactively check or uncheck each box and load that information into the parameter. The technique we’re using for this is very similar to one innovated by Jonathan Drummey and documented in his blog, Parameter Actions: Using a Parameter as a Data Source. In the blog, Jonathan details how we can use parameters to store data and parameter actions to essentially add, remove, and update the data in that data source. It’s a brilliant technique so be sure to read his blog!

 

Here’s essentially what we need to do when a user clicks on an item in the filter.


 When an item is currently checked, update the parameter setting it to unchecked. The value will be ;<Item>|Unchecked


 When an item is currently unchecked, update the parameter setting it to checked. The value will be ;<Item>|Checked


 If the item already exists in the parameter, we’ll remove the existing item and add the new one. If it does not exist, we’ll simply add the new one.



To do this, we’ll need a series of calculated fields:

 

Value Add

// What is the value that will be added to the parameter?

IF [Toggle]="Checked" THEN

    STR([Month Year]) + "|" + "Unchecked"

ELSE

    STR([Month Year]) + "|" + "Checked"

END

 

Value Remove

// What is the value that will be removed from the parameter?

IF [Toggle]="Checked" THEN

    STR([Month Year]) + "|" + "Checked"

ELSE

    STR([Month Year]) + "|" + "Unchecked"

END

 

Value Updated

// New value for the parameter after removing and adding.

REPLACE([Selections], ";"+[Value Remove], "") + ";" + [Value Add]

 

Drag Value Updated to the detail card on your sheet (in some cases, you may need it to be an attribute). Now add the sheet to a dashboard and create the following parameter action:

 

 

And with that, we’re done! We now have a completely functional filter.

 

 

Customizing It

The beauty of this filter technique is twofold. First, it’s a sheet using custom shapes so you can customize it however you want. The UI examples I shared earlier were all created by simply customizing the shapes, layout, etc. of the filter sheet. The options are limitless.

 



But, because this is a normal sheet, you can do all the other things I mentioned earlier—edit the text, add tooltips, trigger an action, etc.

 

Second, since everything is ultimately driven by a parameter, we can take advantage of the extra functionality of parameters. For example, parameters are data source independent, which means they can be used across multiple data sources—something you can’t do with filters without a blending relationship. In many ways, this technique essentially allows you to create custom multi-select parameters.

 

We can also leverage dynamic parameters to specify which items should be selected by default. For example, let’s say you wanted to always select the last three months. We’ll start with two calculated fields:

 

Max Month

// Last month in the data.

{FIXED : MAX([Month Year])}

 

Default Selections

// Default selection to show the last 3 months

// Need LOD to make it "viz-independent" for use as default value in the parameter.

// Be sure to add ";" at the beginning.

{FIXED : MAX(

    ";" + STR([Max Month]) + "|Checked;"

        + STR(DATEADD('month', -1, [Max Month])) + "|Checked;"

        + STR(DATEADD('month', -2, [Max Month])) + "|Checked"

)}

 

We’ll then edit our parameter to use Default Selections when then workbook opens.

 

 

Or, as I noted earlier, you could set it up to only show complete months. As long as you have the data and logic, you can make the default selection pretty much anything you like.

 

A Few Additional Thoughts

Before I wrap this up, I want to share a few additional thoughts on things that you can do with these filters.

 

Dropdowns

The examples I’ve shared display the filters in a list format (i.e. all items are shown at once). I generally prefer dropdowns because they save space. You can implement that here by using a collapsible container or using dynamic zones.

 

Apply Button

I love Apply buttons for multi-select filters because they prevent the view from being updated in the background each time you select an item. We could use apply buttons here by creating a staging parameter. As you select options, it will update this parameter. But, when you click the Apply button, it copies the value from the staging parameter to the parameter used for the filters.

 

Overall Apply Button

In 2020, I wrote a blog called An Apply Button for Your Parameters that shared a technique for creating a global Apply button for your parameters. The technique shared is essentially what I shared in the Apply Button section above. Since then, I’ve been asked several times whether this was possible with filters. With normal filters, it’s not possible, but since this custom filter technique leverages parameters, we could theoretically create a global Apply button that applies all of the custom filters at once.

 

Clear All Filters

I'm regularly asked if it's possible to create a "Clear All Filters" option. While there have been many hacks and solutions developed, I've personally always had problems with these solutions. But, since this is all parameter-driven, we could theoretically create a button that clears the filters, setting them back to their default states.

 

Wrap-Up

I’ll acknowledge that this technique takes quite a bit of time and effort. And I’d guess that 99% of the time, it’s better to just use a basic Tableau filter (or set control or parameter). But when you need just a little more flexibility—either with the UI or with the functionality—I think this is a super cool technique. And I suspect that I’ve only scratched the surface of all the cool functionality you can add using it.

 

Thanks for reading. I hope you enjoy going on this journey with me! If you have any thoughts, please leave them in the comments section below. If you’d like to interact with or download the workbook, you can access it on Tableau Public: Custom Filter UI Styles

 

Ken Flerlage, October 9, 2023

Hire Us! | Twitter | LinkedIn | GitHub | Tableau Public


4 comments:

  1. I wanted to do this for the map layers on my 2024 Iron Viz, but I struggled with the impediment of having to double-click to a more primitive toggle as you mention. I wasn't aware of the technique of using a parameter as a data source - that opens up tons of possibilities! This will be my first entry in the list of "things I would do differently if I did this viz again." 👍

    ReplyDelete
    Replies
    1. Let us know how it goes when you eventually try it!

      Delete
  2. Hi thank you for sharing this! I noticed you did not tell us how to construct the string for the date - a calculated field in your workbook [Month / Toggle]. Could you share?

    ReplyDelete
    Replies
    1. You can download the workbook here to see how that is formulated: https://public.tableau.com/app/profile/ken.flerlage/viz/CustomFilterUIStyles/Styes. Let me know if you have any further questions after reviewing it.

      Delete

Powered by Blogger.