"""
[`drawdata`](https://github.com/koaning/drawdata) is a Python package providing a widget that allow you to draw a dataset in a Notebook or Panel data app.
In this app we fit a [`DecisionTreeClassifier`](https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html) to the drawn points and plots its decision boundary using the `DecisionBoundaryDisplay`.
"""
import numpy as np
import pandas as pd
import panel as pn
from drawdata import ScatterWidget
from matplotlib.figure import Figure
from sklearn.inspection import DecisionBoundaryDisplay
from sklearn.tree import DecisionTreeClassifier
pn.extension("tabulator", "ipywidgets")
# Reactive Expression used to hold the drawn data
data = pn.rx(pd.DataFrame())
# The drawdata widget
widget = ScatterWidget()
def on_change(change):
data.rx.value = widget.data_as_pandas
widget.observe(on_change, names=["data"])
# Plot: Function plotting the decision boundary
def decision_boundary_plot(df):
fig = Figure(figsize=(12, 6))
ax = fig.subplots()
if len(df) and (df["color"].nunique() > 1):
X = df[["x", "y"]].values
y = df["color"]
classifier = DecisionTreeClassifier().fit(X, y)
disp = DecisionBoundaryDisplay.from_estimator(
classifier,
X,
response_method="predict_proba"
if len(np.unique(df["color"])) == 2
else "predict",
xlabel="x",
ylabel="y",
alpha=0.5,
ax=ax,
)
disp.ax_.scatter(X[:, 0], X[:, 1], c=y, edgecolor="k")
ax.set_title("DecisionTreeClassifier")
else:
ax.text(
0.5,
0.8,
"Use minimum two colors",
color="#0072B5",
fontsize=50,
ha="center",
)
ax.axis("off")
return fig
# Views: Finetune how to view the plot and table
plot_view = pn.pane.Matplotlib(
data.pipe(decision_boundary_plot),
height=500,
format="svg",
fixed_aspect=False,
sizing_mode="stretch_width",
name="Plot",
)
table_view = pn.widgets.Tabulator(data, pagination="local", page_size=15, name="Table")
# Layout: Organize in row
layout = pn.Row(
pn.panel(widget, width=800),
pn.Tabs(plot_view, table_view, dynamic=True, sizing_mode="stretch_width"),
)
# Template: Nicely styled template with sidebar and main area
pn.template.FastListTemplate(
site="Panel",
title="Draw the Decision Boundary with DrawData",
sidebar=[
pn.pane.Image("https://github.com/koaning/drawdata/raw/main/imgs/logo.png"),
__doc__,
],
main=[layout],
).servable()
# Serve with 'panel serve app.py --autoreload'