Py.Cafe

petar-qb/

issue-1062-2

Interactive Iris Data Visualizations

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import pandas as pd

from dash import callback, get_asset_url, Input, Output, Patch
from pathlib import Path
import plotly.graph_objects as go
from typing import Literal

import vizro.plotly.express as px
from vizro import Vizro
import vizro.models as vm
from vizro.models.types import capture

# Image paths publicly available on Wikimedia Commons
IMG_PATH_DARK = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/38/Iris_versicolor_quebec_1.jpg/320px-Iris_versicolor_quebec_1.jpg"
IMG_PATH_LIGHT = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Iris_virginica_2.jpg/480px-Iris_virginica_2.jpg"

df = px.data.iris()


@callback(
    Output("image-chart", "figure", allow_duplicate=True),
    # theme-selector is the ID of the Vizro theme toggle button and it's True for light and False for dark
    Input("theme-selector", "value"),
    prevent_initial_call=True,
)
def update_plot_image_source(theme_value):
    path = IMG_PATH_LIGHT if theme_value else IMG_PATH_DARK

    # Creating a Patch object
    patched_figure = Patch()
    patched_figure["layout"]["images"][0]["source"] = path

    return patched_figure


@capture("graph")
def plot_image(data_frame, path, width, height, scale_factor):
    fig = go.Figure()
    # Add invisible scatter trace.
    # This trace is added to help the autoresize logic work.
    fig.add_trace(
        go.Scatter(
            x=[0, width * scale_factor],
            y=[0, height * scale_factor],
            mode="markers",
            marker_opacity=0,
            showlegend=False,
        )
    )

    # Configure axes
    fig.update_xaxes(
        visible=False,
        range=[0, width * scale_factor]
    )

    fig.update_yaxes(
        visible=False,
        range=[0, height * scale_factor],
        # the scaleanchor attribute ensures that the aspect ratio stays constant
        scaleanchor="x"
    )

    # Add image
    fig.add_layout_image(
        dict(
            x=0,
            sizex=width * scale_factor,
            y=height * scale_factor,
            sizey=height * scale_factor,
            xref="x",
            yref="y",
            opacity=1.0,
            layer="below",
            sizing="stretch",
            source=path,
        )
    )

    # Configure other layout
    fig.update_layout(
        width=width * scale_factor,
        height=height * scale_factor,
        margin={"l": 0, "r": 0, "t": 0, "b": 0},
    )
    return fig


# Custom component that enables dcc.Graph.config to be configurable
class ConfigurableGraph(vm.Graph):
    type: Literal["configurable_graph"] = "configurable_graph"

    config: dict = None

    def build(self):
        # call vm.Graph.build() to get the base graph object
        graph_build_obj = super().build()

        # get the base graph config
        base_graph_config = graph_build_obj[self.id].config

        # merge the base graph config with the custom config
        graph_build_obj[self.id].config = base_graph_config | self.config or {}
        return graph_build_obj


# Enabling custom component to be used within the "vm.Page.components".
vm.Page.add_type("components", ConfigurableGraph)


page = vm.Page(
    title="Vizro on PyCafe",
    components=[
        vm.Graph(
            id="image-chart",
            figure=plot_image(
                data_frame=pd.DataFrame(),
                path=IMG_PATH_DARK,
                width=1600,
                height=900,
                scale_factor=0.5,
            )
        ),
        vm.Graph(id="scatter_chart", figure=px.scatter(df, x="sepal_length", y="petal_width", color="species")),
        ConfigurableGraph(
            title="Custom graph with displayModeBar",
            figure=px.histogram(df, x="sepal_width", color="species"),
            config={"displayModeBar": True},
        ),
    ],
    controls=[
        vm.Filter(column="species"),
    ],
)

dashboard = vm.Dashboard(pages=[page])
Vizro().build(dashboard).run()