File size: 5,758 Bytes
89c8ab5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d3c85ed
89c8ab5
d3c85ed
89c8ab5
d3c85ed
89c8ab5
d3c85ed
 
89c8ab5
d3c85ed
 
89c8ab5
 
 
d3c85ed
89c8ab5
d3c85ed
89c8ab5
d3c85ed
89c8ab5
d3c85ed
 
89c8ab5
d3c85ed
 
89c8ab5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d3c85ed
89c8ab5
 
 
 
 
 
 
 
 
 
 
d3c85ed
 
89c8ab5
 
 
 
d3c85ed
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import streamlit as st
import matplotlib.pyplot as plt
import numpy as np


def plot_parameter_space(
    alpha,
    beta,
    xmin=0,
    xmax=1,
    ymin=0,
    ymax=1,
    npts=500,
    max_iter=40,
    scheme="prism",
    draw_boundary=False,
):
    X = np.linspace(xmax, xmin, npts, endpoint=False)
    X = np.flipud(X)
    Y = np.linspace(ymax, ymin, npts, endpoint=False)

    U, V = np.meshgrid(X, Y)
    Z = U + V * 1j

    exit_times = max_iter * np.ones(Z.shape, np.int32)
    mask = Z.imag < Z.real
    exit_times[np.logical_not(mask)] = 0

    for k in range(max_iter):
        Z[mask] = (
            Z[mask].imag / Z[mask].real
            + ((Z[mask].imag - 1) / Z[mask].real + np.floor(1 / Z[mask].real)) * 1j
        )
        old_mask = mask
        mask = np.logical_and(Z.imag > 0, Z.imag < Z.real)
        exit_times[mask ^ old_mask] = k + 1

    fig, ax = plt.subplots()
    ax.set_xlim((xmin, xmax))
    ax.set_ylim((ymin, ymax))
    exit_times[0, 0] = 0
    im = ax.imshow(
        exit_times,
        cmap=scheme,
        aspect="equal",
        extent=(X.min(), X.max(), Y.min(), Y.max()),
    )

    ax.fill_between(X, X, 1.0, color=(1, 1, 1))
    if draw_boundary:
        for k in range(1, 16):
            ax.plot([0, 1 / k], [1, 0], "k", lw=0.5)
            ax.plot([1 / k, 1 / k], [1, 0], "k", lw=0.5)
            ax.plot([1 / 2, 1], [0, 1 / k], "k", lw=0.5)

    # Add a dot for the current alpha and beta values
    ax.plot(alpha, beta, "ro", markersize=5, markeredgecolor="white")

    ax.set_title("Parameter Space")
    ax.set_xlabel("Alpha")
    ax.set_ylabel("Beta")

    return fig


def itm_image(alpha, beta, interval):
    out = []
    if interval[0] < 1 - alpha:
        out.append((interval[0] + alpha, min(interval[1], 1 - alpha) + alpha))
    if interval[0] < 1 - beta and interval[1] > 1 - alpha:
        out.append(
            (max(interval[0], 1 - alpha) + beta, min(interval[1], 1 - beta) + beta)
        )
    if interval[1] > 1 - beta:
        out.append((max(interval[0], 1 - beta) + beta - 1, interval[1] + beta - 1))
    return out


def plot_images(alpha, beta, nimages=100):
    images = [(0, 1)]
    fig, ax = plt.subplots()
    for n in range(nimages):
        beg, end = zip(*images)
        ax.hlines([n / nimages] * len(beg), beg, end)
        images_next = []
        for image in images:
            images_next.extend(itm_image(alpha, beta, image))
        images = images_next
    ax.set_title(f"alpha={alpha:.2f}, beta={beta:.2f}")
    ax.set_xlim(0, 1)
    ax.set_ylim(0, 1)
    ax.set_xlabel("x")
    ax.set_ylabel("Iteration")
    return fig


def main():
    st.set_page_config(layout="wide")
    st.title("Interactive Visualization of Interval Translation Maps")

    st.sidebar.header("Controls")

    # Initialize session state for alpha and beta if not already present
    if "alpha" not in st.session_state:
        st.session_state.alpha = 0.6
    if "beta" not in st.session_state:
        st.session_state.beta = 0.3

    # Function to update alpha
    def update_alpha(increment):
        st.session_state.alpha = max(0, min(1, st.session_state.alpha + increment))

    # Function to update beta
    def update_beta(increment):
        st.session_state.beta = max(0, min(1, st.session_state.beta + increment))

    # Alpha control
    st.sidebar.subheader("Alpha Control")
    col1, col2, col3, col4, col5 = st.sidebar.columns([1, 1, 2, 1, 1])
    with col1:
        st.button("▼▼", on_click=update_alpha, args=(-0.1,), key="alpha_down_large")
    with col2:
        st.button("▼", on_click=update_alpha, args=(-0.01,), key="alpha_down")
    with col3:
        st.write(f"Alpha: {st.session_state.alpha:.2f}")
    with col4:
        st.button("▲", on_click=update_alpha, args=(0.01,), key="alpha_up")
    with col5:
        st.button("▲▲", on_click=update_alpha, args=(0.1,), key="alpha_up_large")

    # Beta control
    st.sidebar.subheader("Beta Control")
    col1, col2, col3, col4, col5 = st.sidebar.columns([1, 1, 2, 1, 1])
    with col1:
        st.button("▼▼", on_click=update_beta, args=(-0.1,), key="beta_down_large")
    with col2:
        st.button("▼", on_click=update_beta, args=(-0.01,), key="beta_down")
    with col3:
        st.write(f"Beta: {st.session_state.beta:.2f}")
    with col4:
        st.button("▲", on_click=update_beta, args=(0.01,), key="beta_up")
    with col5:
        st.button("▲▲", on_click=update_beta, args=(0.1,), key="beta_up_large")

    col1, col2 = st.columns(2)

    with col1:
        st.subheader("Parameter Space")
        fig_param = plot_parameter_space(
            st.session_state.alpha, st.session_state.beta, scheme="prism"
        )
        st.pyplot(fig_param)

    with col2:
        st.subheader("Image Plot")
        fig_images = plot_images(st.session_state.alpha, st.session_state.beta)
        st.pyplot(fig_images)

    st.caption(
        "Use the ▲/▲▲ and ▼/▼▼ buttons in the sidebar to adjust Alpha and Beta values. The red dot in the Parameter Space plot shows the current (Alpha, Beta) position."
    )

    st.markdown("""
    ## About this Visualization
    
    This interactive tool visualizes Interval Translation Maps (ITMs) and their parameter space.
    
    - The left plot shows the parameter space of ITMs. The red dot indicates the current (Alpha, Beta) values.
    - The right plot displays the images of the interval [0,1] under repeated application of the ITM.
    
    Use the up and down arrow buttons in the sidebar to adjust the alpha and beta parameters and observe how they affect both plots.
    - Single arrows (▲/▼) change values by 0.01
    - Double arrows (▲▲/▼▼) change values by 0.1
    """)


if __name__ == "__main__":
    main()