Py.Cafe

MarcSkovMadsen/

basic-drawdata

A basic drawdata app

DocsPricing
  • app.py
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
"""
[`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'