Skip to content

Commit

Permalink
More tooltips (#135)
Browse files Browse the repository at this point in the history
  • Loading branch information
mccalluc authored Nov 7, 2024
1 parent 26a3115 commit 87b6f8e
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 3 deletions.
6 changes: 5 additions & 1 deletion WHAT-WE-LEARNED.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Unless I'm missing something, there doesn't seem to be any warning when there is

## UI and Server functions don't really separate concerns

My first impression was that the UI function would be something like a "view" and the server would be a "controller", but for any kind of conditional display I need a `render.ui`, so that distinction breaks down quickly.
My first impression was that the UI function would be something like a "view" and the server would be a "controller", but for any kind of conditional display I need a `render.ui`, so that distinction breaks down quickly. Just maintaining a naming convention for these little bits of UI in the server gets to be a chore. It would be kludgy, but what if we could suply lambdas instead of names?

## Refactoring: values vs. reactive values

Expand Down Expand Up @@ -63,6 +63,10 @@ I've had to tweak the CSS a few times:
The different flavors of "Shiny" are a bit of nuissance when trying to find examples.
The maturity of Shiny for R means that the vast majority of the examples are for R, even with Python in the search. It would be nice if the docs site remembered that I only want to look at docs for Core.

## It's easy to forget `return`

This is simple, but I was still scratching my head for a while. While there are some cases where returning `None` is intended, is it more more likely to be an error? What if it raised a warning, and an explicit empty string could be returned if that's really what you want?

## Shiny docs could have better formatting

- https://shiny.posit.co/py/api/core/ui.layout_columns.html: bullet list not rendered correctly.
27 changes: 26 additions & 1 deletion dp_creator_ii/app/analysis_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from dp_creator_ii.app.components.inputs import log_slider
from dp_creator_ii.app.components.column_module import column_ui, column_server
from dp_creator_ii.utils.csv_helper import read_field_names
from dp_creator_ii.app.components.outputs import output_code_sample
from dp_creator_ii.app.components.outputs import output_code_sample, demo_tooltip
from dp_creator_ii.utils.templates import make_privacy_loss_block


Expand All @@ -18,13 +18,15 @@ def analysis_ui():
"the number of bins for the histogram, "
"and its relative share of the privacy budget."
),
ui.output_ui("columns_checkbox_group_tooltip_ui"),
ui.input_checkbox_group("columns_checkbox_group", None, []),
ui.output_ui("columns_ui"),
ui.markdown(
"What is your privacy budget for this release? "
"Values above 1 will add less noise to the data, "
"but have a greater risk of revealing individual data."
),
ui.output_ui("epsilon_tooltip_ui"),
log_slider("log_epsilon_slider", 0.1, 10.0),
ui.output_text("epsilon"),
output_code_sample("Privacy Loss", "privacy_loss_python"),
Expand Down Expand Up @@ -75,6 +77,17 @@ def _on_column_set_change():
column_ids_selected = input.columns_checkbox_group()
clear_column_weights(column_ids_selected)

@render.ui
def columns_checkbox_group_tooltip_ui():
return demo_tooltip(
is_demo,
"""
Not all columns need analysis. For this demo, just check
"class_year" and "grade". With more columns selected,
each column has a smaller share of the privacy budget.
""",
)

@render.ui
def columns_ui():
column_ids = input.columns_checkbox_group()
Expand All @@ -86,6 +99,7 @@ def columns_ui():
epsilon=epsilon_calc(),
set_column_weight=set_column_weight,
get_weights_sum=get_weights_sum,
is_demo=is_demo,
)
return [
[
Expand All @@ -103,6 +117,17 @@ def csv_fields_calc():
def csv_fields():
return csv_fields_calc()

@render.ui
def epsilon_tooltip_ui():
return demo_tooltip(
is_demo,
"""
If you set epsilon above one, you'll see that the distribution
becomes less noisy, and the confidence intervals become smaller...
but increased accuracy risks revealing personal information.
""",
)

@reactive.calc
def epsilon_calc():
return pow(10, input.log_epsilon_slider())
Expand Down
44 changes: 43 additions & 1 deletion dp_creator_ii/app/components/column_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@
from dp_creator_ii.utils.dp_helper import make_confidence_accuracy_histogram
from dp_creator_ii.app.components.plots import plot_histogram
from dp_creator_ii.utils.templates import make_column_config_block
from dp_creator_ii.app.components.outputs import output_code_sample
from dp_creator_ii.app.components.outputs import output_code_sample, demo_tooltip


@module.ui
def column_ui(): # pragma: no cover
width = "10em" # Just wide enough so the text isn't trucated.
return ui.layout_columns(
[
ui.output_ui("bounds_tooltip_ui"),
ui.input_numeric("min", "Min", 0, width=width),
ui.input_numeric("max", "Max", 10, width=width),
ui.output_ui("bins_tooltip_ui"),
ui.input_numeric("bins", "Bins", 10, width=width),
ui.output_ui("weight_tooltip_ui"),
ui.input_select(
"weight",
"Weight",
Expand Down Expand Up @@ -60,6 +63,7 @@ def column_server(
epsilon,
set_column_weight,
get_weights_sum,
is_demo,
): # pragma: no cover
@reactive.effect
@reactive.event(input.weight)
Expand All @@ -75,6 +79,44 @@ def column_config():
"weight": float(input.weight()),
}

@render.ui
def bounds_tooltip_ui():
return demo_tooltip(
is_demo,
"""
DP requires that we limit the sensitivity to the contributions
of any individual. To do this, we need an estimate of the lower
and upper bounds for each variable. We should not look at the
data when estimating the bounds! In this case, we could imagine
that "class year" would vary between 1 and 4, and we could limit
"grade" to values between 50 and 100.
""",
)

@render.ui
def bins_tooltip_ui():
return demo_tooltip(
is_demo,
"""
Different statistics can be measured with DP.
This tool provides a histogram. If you increase the number of bins,
you'll see that each individual bin becomes noisier to provide
the same overall privacy guarantee. For this example, give
"class_year" 4 bins and "grade" 5 bins.
""",
)

@render.ui
def weight_tooltip_ui():
return demo_tooltip(
is_demo,
"""
You have a finite privacy budget, but you can choose
how to allocate it. For simplicity, we limit the options here,
but when using the library you can fine tune this.
""",
)

@render.code
def column_code():
config = column_config()
Expand Down

0 comments on commit 87b6f8e

Please sign in to comment.