From cddda7efedac43ced645332824a8f27bbcbc9077 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Fri, 26 Jun 2026 17:07:28 -0700 Subject: [PATCH] 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)