From cddda7efedac43ced645332824a8f27bbcbc9077 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 26 Jun 2026 17:07:28 -0700 Subject: [PATCH 1/3] feat(block-kit): add data visualization block example Mirror the official docs data_visualization block with pie, bar, area, and line chart examples, plus tests and a README entry. Docs: https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block Co-Authored-By: Claude --- block-kit/README.md | 1 + block-kit/src/blocks/data_visualization.py | 139 ++++++++++++++++++ .../tests/blocks/test_data_visualization.py | 138 +++++++++++++++++ 3 files changed, 278 insertions(+) create mode 100644 block-kit/src/blocks/data_visualization.py create mode 100644 block-kit/tests/blocks/test_data_visualization.py diff --git a/block-kit/README.md b/block-kit/README.md index ee77ff0..d3c010c 100644 --- a/block-kit/README.md +++ b/block-kit/README.md @@ -11,6 +11,7 @@ Read the [docs](https://docs.slack.dev/block-kit/) to learn concepts behind thes - **[Actions](https://docs.slack.dev/reference/block-kit/blocks/actions-block)**: Holds multiple interactive elements. [Implementation](./src/blocks/actions.py). - **[Context](https://docs.slack.dev/reference/block-kit/blocks/context-block)**: Provides contextual info, which can include both images and text. [Implementation](./src/blocks/context.py). - **[Context actions](https://docs.slack.dev/reference/block-kit/blocks/context-actions-block)**: Displays actions as contextual info, which can include both feedback buttons and icon buttons. [Implementation](./src/blocks/context_actions.py). +- **[Data visualization](https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block)**: Displays data using a line, bar, area, or pie chart. [Implementation](./src/blocks/data_visualization.py). - **[Divider](https://docs.slack.dev/reference/block-kit/blocks/divider-block)**: Visually separates pieces of info inside of a message. [Implementation](./src/blocks/divider.py). - **[File](https://docs.slack.dev/reference/block-kit/blocks/file-block)**: Displays info about remote files. [Implementation](./src/blocks/file.py). - **[Header](https://docs.slack.dev/reference/block-kit/blocks/header-block)**: Displays a larger-sized text. [Implementation](./src/blocks/header.py). diff --git a/block-kit/src/blocks/data_visualization.py b/block-kit/src/blocks/data_visualization.py new file mode 100644 index 0000000..c2d4287 --- /dev/null +++ b/block-kit/src/blocks/data_visualization.py @@ -0,0 +1,139 @@ +from slack_sdk.models.blocks import DataVisualizationBlock + + +def example01() -> DataVisualizationBlock: + """ + Displays data using a line, bar, area, or pie chart. + https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block/ + + A pie chart with labeled segments. + """ + block = DataVisualizationBlock( + title="My Favorite Candy Bars", + chart={ + "type": "pie", + "segments": [ + {"label": "Kit Kat", "value": 45}, + {"label": "Twix", "value": 28}, + {"label": "Crunch", "value": 18}, + {"label": "Milky Way", "value": 9}, + ], + }, + ) + return block + + +def example02() -> DataVisualizationBlock: + """ + A bar chart with a single series and axis configuration. + """ + block = DataVisualizationBlock( + title="My Favorite Pies by Percentage of Tastiness", + chart={ + "type": "bar", + "series": [ + { + "name": "Pies", + "data": [ + {"label": "Strawberry Rhubarb", "value": 85}, + {"label": "Pumpkin", "value": 70}, + {"label": "Lemon Meringue", "value": 72}, + {"label": "Blueberry", "value": 90}, + {"label": "Key Lime", "value": 56}, + ], + } + ], + "axis_config": { + "categories": [ + "Strawberry Rhubarb", + "Pumpkin", + "Lemon Meringue", + "Blueberry", + "Key Lime", + ], + "x_label": "Pies", + "y_label": "Percentage of Tastiness", + }, + }, + ) + return block + + +def example03() -> DataVisualizationBlock: + """ + An area chart comparing multiple series. + """ + block = DataVisualizationBlock( + title="Daily Active Users", + chart={ + "type": "area", + "series": [ + { + "name": "Pied Piper Free Tier", + "data": [ + {"label": "Mon", "value": 12000}, + {"label": "Tues", "value": 13500}, + {"label": "Wed", "value": 15200}, + {"label": "Thurs", "value": 14800}, + {"label": "Fri", "value": 16400}, + ], + }, + { + "name": "Pied Piper Paid Tier", + "data": [ + {"label": "Mon", "value": 4500}, + {"label": "Tues", "value": 4800}, + {"label": "Wed", "value": 5100}, + {"label": "Thurs", "value": 5600}, + {"label": "Fri", "value": 6200}, + ], + }, + ], + "axis_config": { + "categories": ["Mon", "Tues", "Wed", "Thur", "Fri"], + "x_label": "Day", + "y_label": "Users", + }, + }, + ) + return block + + +def example04() -> DataVisualizationBlock: + """ + A line chart comparing multiple series over time. + """ + block = DataVisualizationBlock( + title="Weekly Paper Sales", + chart={ + "type": "line", + "series": [ + { + "name": "Dunder Mifflin Infinity Website", + "data": [ + {"label": "Week 1", "value": 32000}, + {"label": "Week 2", "value": 35000}, + {"label": "Week 3", "value": 29000}, + {"label": "Week 4", "value": 41000}, + {"label": "Week 5", "value": 45000}, + ], + }, + { + "name": "Dunder Mifflin In-store", + "data": [ + {"label": "Week 1", "value": 32000}, + {"label": "Week 2", "value": 35000}, + {"label": "Week 3", "value": 29000}, + {"label": "Week 4", "value": 41000}, + {"label": "Week 5", "value": 45000}, + ], + }, + ], + "axis_config": { + "categories": ["Week 1", "Week 2", "Week 3", "Week 4", "Week 5"], + "x_label": "Week", + "y_label": "Paper Sales (USD)", + }, + }, + ) + return block diff --git a/block-kit/tests/blocks/test_data_visualization.py b/block-kit/tests/blocks/test_data_visualization.py new file mode 100644 index 0000000..d3074d6 --- /dev/null +++ b/block-kit/tests/blocks/test_data_visualization.py @@ -0,0 +1,138 @@ +import json + +from src.blocks import data_visualization + + +def test_example01(): + block = data_visualization.example01() + actual = block.to_dict() + expected = { + "type": "data_visualization", + "title": "My Favorite Candy Bars", + "chart": { + "type": "pie", + "segments": [ + {"label": "Kit Kat", "value": 45}, + {"label": "Twix", "value": 28}, + {"label": "Crunch", "value": 18}, + {"label": "Milky Way", "value": 9}, + ], + }, + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) + + +def test_example02(): + block = data_visualization.example02() + actual = block.to_dict() + expected = { + "type": "data_visualization", + "title": "My Favorite Pies by Percentage of Tastiness", + "chart": { + "type": "bar", + "series": [ + { + "name": "Pies", + "data": [ + {"label": "Strawberry Rhubarb", "value": 85}, + {"label": "Pumpkin", "value": 70}, + {"label": "Lemon Meringue", "value": 72}, + {"label": "Blueberry", "value": 90}, + {"label": "Key Lime", "value": 56}, + ], + } + ], + "axis_config": { + "categories": [ + "Strawberry Rhubarb", + "Pumpkin", + "Lemon Meringue", + "Blueberry", + "Key Lime", + ], + "x_label": "Pies", + "y_label": "Percentage of Tastiness", + }, + }, + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) + + +def test_example03(): + block = data_visualization.example03() + actual = block.to_dict() + expected = { + "type": "data_visualization", + "title": "Daily Active Users", + "chart": { + "type": "area", + "series": [ + { + "name": "Pied Piper Free Tier", + "data": [ + {"label": "Mon", "value": 12000}, + {"label": "Tues", "value": 13500}, + {"label": "Wed", "value": 15200}, + {"label": "Thurs", "value": 14800}, + {"label": "Fri", "value": 16400}, + ], + }, + { + "name": "Pied Piper Paid Tier", + "data": [ + {"label": "Mon", "value": 4500}, + {"label": "Tues", "value": 4800}, + {"label": "Wed", "value": 5100}, + {"label": "Thurs", "value": 5600}, + {"label": "Fri", "value": 6200}, + ], + }, + ], + "axis_config": { + "categories": ["Mon", "Tues", "Wed", "Thur", "Fri"], + "x_label": "Day", + "y_label": "Users", + }, + }, + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) + + +def test_example04(): + block = data_visualization.example04() + actual = block.to_dict() + expected = { + "type": "data_visualization", + "title": "Weekly Paper Sales", + "chart": { + "type": "line", + "series": [ + { + "name": "Dunder Mifflin Infinity Website", + "data": [ + {"label": "Week 1", "value": 32000}, + {"label": "Week 2", "value": 35000}, + {"label": "Week 3", "value": 29000}, + {"label": "Week 4", "value": 41000}, + {"label": "Week 5", "value": 45000}, + ], + }, + { + "name": "Dunder Mifflin In-store", + "data": [ + {"label": "Week 1", "value": 32000}, + {"label": "Week 2", "value": 35000}, + {"label": "Week 3", "value": 29000}, + {"label": "Week 4", "value": 41000}, + {"label": "Week 5", "value": 45000}, + ], + }, + ], + "axis_config": { + "categories": ["Week 1", "Week 2", "Week 3", "Week 4", "Week 5"], + "x_label": "Week", + "y_label": "Paper Sales (USD)", + }, + }, + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) From c7e317d774d315fe2fbf2849ecbc432eb93e6446 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 4 Aug 2026 21:46:25 -0700 Subject: [PATCH 2/3] fix(data_visualization): match description to docs.slack.dev wording Co-Authored-By: Claude --- block-kit/src/blocks/data_visualization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block-kit/src/blocks/data_visualization.py b/block-kit/src/blocks/data_visualization.py index c2d4287..61293ce 100644 --- a/block-kit/src/blocks/data_visualization.py +++ b/block-kit/src/blocks/data_visualization.py @@ -3,7 +3,7 @@ def example01() -> DataVisualizationBlock: """ - Displays data using a line, bar, area, or pie chart. + Displays data visually in pie, bar, area, or line chart formats. https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block/ A pie chart with labeled segments. From eec2124d136a2d31cfc78c511ada595ae4dbbcf0 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 4 Nov 2026 18:02:49 -0800 Subject: [PATCH 3/3] fix: sync data visualization example with docs Match the docs summary, example descriptions and area chart categories ("Thurs"), and expand data point dicts to one key per line. Co-Authored-By: Claude Co-Authored-By: Claude Opus 5.5 (1M context) --- block-kit/README.md | 2 +- block-kit/src/blocks/data_visualization.py | 157 ++++++++++++++---- .../tests/blocks/test_data_visualization.py | 149 +++++++++++++---- 3 files changed, 241 insertions(+), 67 deletions(-) diff --git a/block-kit/README.md b/block-kit/README.md index acc37e4..a78f93c 100644 --- a/block-kit/README.md +++ b/block-kit/README.md @@ -15,7 +15,7 @@ Read the [docs](https://docs.slack.dev/block-kit/) to learn concepts behind thes - **[Container](https://docs.slack.dev/reference/block-kit/blocks/container-block)**: A general-purpose wrapper for grouping child blocks together, with a configurable size. [Implementation](./src/blocks/container.py). - **[Context](https://docs.slack.dev/reference/block-kit/blocks/context-block)**: Provides contextual info, which can include both images and text. [Implementation](./src/blocks/context.py). - **[Context actions](https://docs.slack.dev/reference/block-kit/blocks/context-actions-block)**: Displays actions as contextual info, which can include both feedback buttons and icon buttons. [Implementation](./src/blocks/context_actions.py). -- **[Data visualization](https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block)**: Displays data using a line, bar, area, or pie chart. [Implementation](./src/blocks/data_visualization.py). +- **[Data visualization](https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block)**: Displays data visually in pie, bar, area, or line chart formats. [Implementation](./src/blocks/data_visualization.py). - **[Divider](https://docs.slack.dev/reference/block-kit/blocks/divider-block)**: Visually separates pieces of info inside of a message. [Implementation](./src/blocks/divider.py). - **[File](https://docs.slack.dev/reference/block-kit/blocks/file-block)**: Displays info about remote files. [Implementation](./src/blocks/file.py). - **[Header](https://docs.slack.dev/reference/block-kit/blocks/header-block)**: Displays a larger-sized text. [Implementation](./src/blocks/header.py). diff --git a/block-kit/src/blocks/data_visualization.py b/block-kit/src/blocks/data_visualization.py index 61293ce..b36b416 100644 --- a/block-kit/src/blocks/data_visualization.py +++ b/block-kit/src/blocks/data_visualization.py @@ -6,17 +6,29 @@ def example01() -> DataVisualizationBlock: Displays data visually in pie, bar, area, or line chart formats. https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block/ - A pie chart with labeled segments. + A sample pie chart payload. """ block = DataVisualizationBlock( title="My Favorite Candy Bars", chart={ "type": "pie", "segments": [ - {"label": "Kit Kat", "value": 45}, - {"label": "Twix", "value": 28}, - {"label": "Crunch", "value": 18}, - {"label": "Milky Way", "value": 9}, + { + "label": "Kit Kat", + "value": 45, + }, + { + "label": "Twix", + "value": 28, + }, + { + "label": "Crunch", + "value": 18, + }, + { + "label": "Milky Way", + "value": 9, + }, ], }, ) @@ -25,7 +37,7 @@ def example01() -> DataVisualizationBlock: def example02() -> DataVisualizationBlock: """ - A bar chart with a single series and axis configuration. + A sample bar chart payload. """ block = DataVisualizationBlock( title="My Favorite Pies by Percentage of Tastiness", @@ -35,13 +47,28 @@ def example02() -> DataVisualizationBlock: { "name": "Pies", "data": [ - {"label": "Strawberry Rhubarb", "value": 85}, - {"label": "Pumpkin", "value": 70}, - {"label": "Lemon Meringue", "value": 72}, - {"label": "Blueberry", "value": 90}, - {"label": "Key Lime", "value": 56}, + { + "label": "Strawberry Rhubarb", + "value": 85, + }, + { + "label": "Pumpkin", + "value": 70, + }, + { + "label": "Lemon Meringue", + "value": 72, + }, + { + "label": "Blueberry", + "value": 90, + }, + { + "label": "Key Lime", + "value": 56, + }, ], - } + }, ], "axis_config": { "categories": [ @@ -61,7 +88,7 @@ def example02() -> DataVisualizationBlock: def example03() -> DataVisualizationBlock: """ - An area chart comparing multiple series. + A sample area chart payload. """ block = DataVisualizationBlock( title="Daily Active Users", @@ -71,26 +98,56 @@ def example03() -> DataVisualizationBlock: { "name": "Pied Piper Free Tier", "data": [ - {"label": "Mon", "value": 12000}, - {"label": "Tues", "value": 13500}, - {"label": "Wed", "value": 15200}, - {"label": "Thurs", "value": 14800}, - {"label": "Fri", "value": 16400}, + { + "label": "Mon", + "value": 12000, + }, + { + "label": "Tues", + "value": 13500, + }, + { + "label": "Wed", + "value": 15200, + }, + { + "label": "Thurs", + "value": 14800, + }, + { + "label": "Fri", + "value": 16400, + }, ], }, { "name": "Pied Piper Paid Tier", "data": [ - {"label": "Mon", "value": 4500}, - {"label": "Tues", "value": 4800}, - {"label": "Wed", "value": 5100}, - {"label": "Thurs", "value": 5600}, - {"label": "Fri", "value": 6200}, + { + "label": "Mon", + "value": 4500, + }, + { + "label": "Tues", + "value": 4800, + }, + { + "label": "Wed", + "value": 5100, + }, + { + "label": "Thurs", + "value": 5600, + }, + { + "label": "Fri", + "value": 6200, + }, ], }, ], "axis_config": { - "categories": ["Mon", "Tues", "Wed", "Thur", "Fri"], + "categories": ["Mon", "Tues", "Wed", "Thurs", "Fri"], "x_label": "Day", "y_label": "Users", }, @@ -101,7 +158,7 @@ def example03() -> DataVisualizationBlock: def example04() -> DataVisualizationBlock: """ - A line chart comparing multiple series over time. + A sample line chart payload. """ block = DataVisualizationBlock( title="Weekly Paper Sales", @@ -111,21 +168,51 @@ def example04() -> DataVisualizationBlock: { "name": "Dunder Mifflin Infinity Website", "data": [ - {"label": "Week 1", "value": 32000}, - {"label": "Week 2", "value": 35000}, - {"label": "Week 3", "value": 29000}, - {"label": "Week 4", "value": 41000}, - {"label": "Week 5", "value": 45000}, + { + "label": "Week 1", + "value": 32000, + }, + { + "label": "Week 2", + "value": 35000, + }, + { + "label": "Week 3", + "value": 29000, + }, + { + "label": "Week 4", + "value": 41000, + }, + { + "label": "Week 5", + "value": 45000, + }, ], }, { "name": "Dunder Mifflin In-store", "data": [ - {"label": "Week 1", "value": 32000}, - {"label": "Week 2", "value": 35000}, - {"label": "Week 3", "value": 29000}, - {"label": "Week 4", "value": 41000}, - {"label": "Week 5", "value": 45000}, + { + "label": "Week 1", + "value": 32000, + }, + { + "label": "Week 2", + "value": 35000, + }, + { + "label": "Week 3", + "value": 29000, + }, + { + "label": "Week 4", + "value": 41000, + }, + { + "label": "Week 5", + "value": 45000, + }, ], }, ], diff --git a/block-kit/tests/blocks/test_data_visualization.py b/block-kit/tests/blocks/test_data_visualization.py index d3074d6..a63c7ae 100644 --- a/block-kit/tests/blocks/test_data_visualization.py +++ b/block-kit/tests/blocks/test_data_visualization.py @@ -12,10 +12,22 @@ def test_example01(): "chart": { "type": "pie", "segments": [ - {"label": "Kit Kat", "value": 45}, - {"label": "Twix", "value": 28}, - {"label": "Crunch", "value": 18}, - {"label": "Milky Way", "value": 9}, + { + "label": "Kit Kat", + "value": 45, + }, + { + "label": "Twix", + "value": 28, + }, + { + "label": "Crunch", + "value": 18, + }, + { + "label": "Milky Way", + "value": 9, + }, ], }, } @@ -34,13 +46,28 @@ def test_example02(): { "name": "Pies", "data": [ - {"label": "Strawberry Rhubarb", "value": 85}, - {"label": "Pumpkin", "value": 70}, - {"label": "Lemon Meringue", "value": 72}, - {"label": "Blueberry", "value": 90}, - {"label": "Key Lime", "value": 56}, + { + "label": "Strawberry Rhubarb", + "value": 85, + }, + { + "label": "Pumpkin", + "value": 70, + }, + { + "label": "Lemon Meringue", + "value": 72, + }, + { + "label": "Blueberry", + "value": 90, + }, + { + "label": "Key Lime", + "value": 56, + }, ], - } + }, ], "axis_config": { "categories": [ @@ -70,26 +97,56 @@ def test_example03(): { "name": "Pied Piper Free Tier", "data": [ - {"label": "Mon", "value": 12000}, - {"label": "Tues", "value": 13500}, - {"label": "Wed", "value": 15200}, - {"label": "Thurs", "value": 14800}, - {"label": "Fri", "value": 16400}, + { + "label": "Mon", + "value": 12000, + }, + { + "label": "Tues", + "value": 13500, + }, + { + "label": "Wed", + "value": 15200, + }, + { + "label": "Thurs", + "value": 14800, + }, + { + "label": "Fri", + "value": 16400, + }, ], }, { "name": "Pied Piper Paid Tier", "data": [ - {"label": "Mon", "value": 4500}, - {"label": "Tues", "value": 4800}, - {"label": "Wed", "value": 5100}, - {"label": "Thurs", "value": 5600}, - {"label": "Fri", "value": 6200}, + { + "label": "Mon", + "value": 4500, + }, + { + "label": "Tues", + "value": 4800, + }, + { + "label": "Wed", + "value": 5100, + }, + { + "label": "Thurs", + "value": 5600, + }, + { + "label": "Fri", + "value": 6200, + }, ], }, ], "axis_config": { - "categories": ["Mon", "Tues", "Wed", "Thur", "Fri"], + "categories": ["Mon", "Tues", "Wed", "Thurs", "Fri"], "x_label": "Day", "y_label": "Users", }, @@ -110,21 +167,51 @@ def test_example04(): { "name": "Dunder Mifflin Infinity Website", "data": [ - {"label": "Week 1", "value": 32000}, - {"label": "Week 2", "value": 35000}, - {"label": "Week 3", "value": 29000}, - {"label": "Week 4", "value": 41000}, - {"label": "Week 5", "value": 45000}, + { + "label": "Week 1", + "value": 32000, + }, + { + "label": "Week 2", + "value": 35000, + }, + { + "label": "Week 3", + "value": 29000, + }, + { + "label": "Week 4", + "value": 41000, + }, + { + "label": "Week 5", + "value": 45000, + }, ], }, { "name": "Dunder Mifflin In-store", "data": [ - {"label": "Week 1", "value": 32000}, - {"label": "Week 2", "value": 35000}, - {"label": "Week 3", "value": 29000}, - {"label": "Week 4", "value": 41000}, - {"label": "Week 5", "value": 45000}, + { + "label": "Week 1", + "value": 32000, + }, + { + "label": "Week 2", + "value": 35000, + }, + { + "label": "Week 3", + "value": 29000, + }, + { + "label": "Week 4", + "value": 41000, + }, + { + "label": "Week 5", + "value": 45000, + }, ], }, ],