Skip to content

Commit b3a0230

Browse files
committed
Add initial version of blog post
1 parent 15b293e commit b3a0230

File tree

1 file changed

+130
-0
lines changed

1 file changed

+130
-0
lines changed

docs/blog/pointblank-intro/index.qmd

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
---
2+
title: "How We Used Great Tables to Supercharge Reporting in Pointblank"
3+
html-table-processing: none
4+
author: Rich Iannone
5+
date: 2025-02-03
6+
freeze: true
7+
jupyter: python3
8+
---
9+
10+
The Great Tables package allows you to make tables, and they're really great when part of a report, a book, or a web page. The API is meant to be easy to work with so DataFrames could be made into publication-qualty tables without a lot of hassle. And having nice-looking tables in the mix elevates the quality of the medium you're working in.
11+
12+
To go a bit further, we are working on a new Python package that generates tables (c/o Great Tables) as reporting objects. This package is called [Pointblank](https://github.com/posit-dev/pointblank), its focus is that of data validation, and the reporting tables it can produce informs users on the results of a data validation workflow. In this post we'll highlight the tables it can make and, in doing so, convince you that such outputs can be useful and worth the effort on the part of the maintainer.
13+
14+
### The table report for a data validation
15+
16+
Just like Great Tables, Pointblank's primary input is a table and the goal of that library is to perform checks of the tabular data. Other libraries in this domain include [Great Expectations](https://github.com/great-expectations/great_expectations), [pandera](https://github.com/unionai-oss/pandera), and [Soda](https://github.com/sodadata/soda-core?tab=readme-ov-file), and [PyDeequ](https://github.com/awslabs/python-deequ). Let's look at the main reporting table that users are likely to see quite often.
17+
18+
```{python}
19+
# | code-fold: true
20+
# | code-summary: "Show the code"
21+
22+
import pointblank as pb
23+
24+
validation = (
25+
pb.Validate(
26+
data=pb.load_dataset(dataset="small_table", tbl_type="polars"),
27+
label="An example validation",
28+
thresholds=(0.1, 0.2, 0.5)
29+
)
30+
.col_vals_gt(columns="d", value=1000)
31+
.col_vals_le(columns="c", value=5)
32+
.col_exists(columns=["date", "date_time"])
33+
.interrogate()
34+
)
35+
36+
validation
37+
```
38+
39+
The table is chock full of the information you need when doing data validation tasks. And it's also easy on the eyes. Some cool features include:
40+
41+
1. a header with information on the type of input table plus important validation options
42+
2. vertical color strips on the left side to indicate overall status of the rows
43+
3. icons in several columns (space saving and they let you know what's up)
44+
4. 'CSV' buttons that, when clicked, provide you with a CSV file
45+
5. a footer with timing information for the analysis
46+
47+
It's a nice table and it scales nicely to the large variety of validation types and options available in the Pointblank library. Viewing this table is a central part of using that library and the great thing about the reporting being a table like this is that it can be shared by placing it in a publication environment of your choosing (for example, it could be put in a Quarto document).
48+
49+
We didn't stop there however... we went ahead and made it possible to view other artifacts as tables.
50+
51+
### Preview of a dataset
52+
53+
Because Pointblank allows for the collection of data extracts (subsets of the target table where data quality issues were encountered), we found it useful to have a function (`preview()`) that provides a consistent view of this tabular data. It also just works with any type of table that Pointblank supports (which is a lot). Here is how that looks with a 2,000 row dataset included in the package (`game_revenue`):
54+
55+
```{python}
56+
# | code-fold: true
57+
# | code-summary: "Show the code"
58+
59+
pb.preview(pb.load_dataset(dataset="game_revenue", tbl_type="duckdb"))
60+
```
61+
62+
The `preview()` function had a few design goals in mind:
63+
64+
- get the dimensions of the table and display them prominently in the header
65+
- provide the column names and the column types
66+
- have a consistent line height along with a sensible limit to the column width
67+
- use a monospaced typeface having high legibility
68+
- should work for all sorts of tables!
69+
70+
This is a nice drop-in replacement for looking at DataFrames or Ibis tables (the types of tables that Pointblank can work with). If you were to inspect the DuckDB table materialized by `pb.load_dataset(dataset="game_revenue", tbl_type="duckdb")` without `preview()` you'd get this:
71+
72+
```{python}
73+
# | code-fold: true
74+
# | code-summary: "Show the code"
75+
76+
pb.load_dataset(dataset="game_revenue", tbl_type="duckdb")
77+
```
78+
79+
Which is not nearly as good.
80+
81+
### Explaining the result of a particular valdiation step, with a table!
82+
83+
We were clearly excited about the possibilities of Great Tables tables in Pointblank, because we did even more. Data validations are performed as distinct steps (e.g., a step could check that all values were greater than a fixed value, down a specific column) and while you get a reporting of atomic successes and failures in a step, it's better to see exactly what failed. This is all in the service of helping the user get to the root causes of a data quality issue. So, we have a method called `get_step_report()` that gives you a custom view of failures on a stepwise basis. Of course, it's using a table to get the job done.
84+
85+
Let's look at an example where you might check a table against an expected schema for that table. Turns out it's a schema expectation that doesn't match the schema of the actual table, and the report for this step shows what elements don't match up:
86+
87+
```{python}
88+
# | code-fold: true
89+
# | code-summary: "Show the code"
90+
91+
# Create a schema for the target table (`small_table` as a DuckDB table)
92+
schema = pb.Schema(
93+
columns=[
94+
("date_time", "timestamp"),
95+
("dates", "date"),
96+
("a", "int64"),
97+
("b",),
98+
("c",),
99+
("d", "float64"),
100+
("e", ["bool", "boolean"]),
101+
("f", "str"),
102+
]
103+
)
104+
105+
# Use the `col_schema_match()` validation method to perform a schema check
106+
validation = (
107+
pb.Validate(data=pb.load_dataset(dataset="small_table", tbl_type="duckdb"))
108+
.col_schema_match(schema=schema)
109+
.interrogate()
110+
)
111+
112+
validation.get_step_report(i=1)
113+
```
114+
115+
With just a basic report of steps, you'd just see a failure and be left wondering what went wrong. The tabular reporting of the step report above serves to reveal the issues in an easy-to-understand manner.
116+
117+
The use of a table is so ideal here! On the left are the column names and the data types of the target table. On the right are the elements of the expected schema. We can very quickly see three places where the expectation doesn't match the actual:
118+
119+
1. the dtype for the first column `date_time` is incorrect
120+
2. the column name of second column `date` is misspelled (as `"dates"`)
121+
3. the dtype for the last column is incorrect (`"str"` instead of `"string"`)
122+
123+
This reporting can scale nicely to very large tables since the width of the table in this case will
124+
always be fixed (having schema column comparisons represented in rows). Other nice touches include a robust header with: information on schema comparison settings, the step number, and an indication of the overall pass/fail status (here, a large red cross mark).
125+
126+
There are many types of validations and so naturally there are different types of step reports, but the common thread is that they all use Great Tables to provide reporting in a sensible fashion.
127+
128+
### In closing
129+
130+
We hope this post provides some insight on how Great Tables can be versatile enough to be used within Python libraries. The added benefit is that outputs that are GT object can be further modified or styled by the user of library producing GT tables.

0 commit comments

Comments
 (0)