Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import json
|
3 |
+
import base64
|
4 |
+
import urllib
|
5 |
+
|
6 |
+
PATH = []
|
7 |
+
|
8 |
+
|
9 |
+
def url_from_state_dict(state):
|
10 |
+
return {
|
11 |
+
key: [json.dumps(value)]
|
12 |
+
for key, value in sorted(state.items())
|
13 |
+
}
|
14 |
+
|
15 |
+
def state_dict_from_url(params):
|
16 |
+
state = dict()
|
17 |
+
# params = st.experimental_get_query_params()
|
18 |
+
# st.write(params)
|
19 |
+
for key, value in sorted(params.items()):
|
20 |
+
state[key] = json.loads(value[-1])
|
21 |
+
return state
|
22 |
+
|
23 |
+
|
24 |
+
st.markdown('''
|
25 |
+
<style>
|
26 |
+
[data-testid="stVerticalBlock"] [data-testid="stVerticalBlock"] {
|
27 |
+
background-color: #d4d4d4;
|
28 |
+
box-shadow: 0px 0px 0px 6px #d4d4d4, 0px 0px 0px 7px #000000e3;
|
29 |
+
border-radius: 2px;
|
30 |
+
}
|
31 |
+
</style>
|
32 |
+
''', unsafe_allow_html=True)
|
33 |
+
|
34 |
+
left, right = st.columns(2)
|
35 |
+
|
36 |
+
left.write('### Session State:')
|
37 |
+
left.write(st.session_state)
|
38 |
+
|
39 |
+
right.write('### URL State:')
|
40 |
+
right.write(state_dict_from_url(st.experimental_get_query_params()))
|
41 |
+
|
42 |
+
if not st.session_state.to_dict():# state_dict_from_url(st.experimental_get_query_params()) != st.session_state.to_dict():
|
43 |
+
st.write('### Auto Setting Session State:')
|
44 |
+
print('Yass!')
|
45 |
+
print('setting to...', state_dict_from_url(st.experimental_get_query_params()))
|
46 |
+
|
47 |
+
for key, value in state_dict_from_url(st.experimental_get_query_params()).items():
|
48 |
+
st.session_state[key] = value
|
49 |
+
st.experimental_rerun()
|
50 |
+
# pass
|
51 |
+
|
52 |
+
autoset = st.sidebar.radio('Auto Set URL', ['on', 'off'], key='radio')
|
53 |
+
|
54 |
+
|
55 |
+
class NumberInput:
|
56 |
+
def __init__(
|
57 |
+
self,
|
58 |
+
label: str,
|
59 |
+
value: float,
|
60 |
+
key: str,
|
61 |
+
min_value: float = None,
|
62 |
+
max_value: float = None,
|
63 |
+
):
|
64 |
+
PATH.append(key)
|
65 |
+
self.label = label
|
66 |
+
self.path = '.'.join(PATH)
|
67 |
+
self.default = value
|
68 |
+
self.min_value = min_value
|
69 |
+
self.max_value = max_value
|
70 |
+
|
71 |
+
self.define_state('value')
|
72 |
+
|
73 |
+
PATH.pop()
|
74 |
+
|
75 |
+
def define_state(self, key):
|
76 |
+
if st.session_state.get(self.path + key) is not None:
|
77 |
+
return
|
78 |
+
st.session_state[self.path + key] = self.default
|
79 |
+
|
80 |
+
def read_state(self, key):
|
81 |
+
return st.session_state[self.path + key]
|
82 |
+
|
83 |
+
def read_value(self):
|
84 |
+
return self.read_state('value')
|
85 |
+
|
86 |
+
@property
|
87 |
+
def value(self):
|
88 |
+
return self.read_value()
|
89 |
+
|
90 |
+
def render(self):
|
91 |
+
return st.number_input(
|
92 |
+
label=self.label,
|
93 |
+
min_value=self.min_value,
|
94 |
+
max_value=self.max_value,
|
95 |
+
# value=self.default,
|
96 |
+
key=self.path + 'value',
|
97 |
+
step=0.5,
|
98 |
+
)
|
99 |
+
|
100 |
+
|
101 |
+
def argand(a):
|
102 |
+
import matplotlib.pyplot as plt
|
103 |
+
import numpy as np
|
104 |
+
fig, ax = plt.subplots()
|
105 |
+
|
106 |
+
for x in range(len(a)):
|
107 |
+
ax.plot([0,a[x].real],[0,a[x].imag],'ro-',label='python')
|
108 |
+
limit=np.max(np.ceil(np.absolute(a)))
|
109 |
+
ax.axis(xmin=-limit, xmax=limit, ymin=-limit, ymax=limit)
|
110 |
+
|
111 |
+
return fig
|
112 |
+
|
113 |
+
|
114 |
+
class ComplexNumberInput:
|
115 |
+
def __init__(
|
116 |
+
self,
|
117 |
+
label: str,
|
118 |
+
value: complex,
|
119 |
+
key: str,
|
120 |
+
swapplaces: bool = False,
|
121 |
+
) -> None:
|
122 |
+
PATH.append(key)
|
123 |
+
self.label = label
|
124 |
+
self.path = '.'.join(PATH)
|
125 |
+
self.default = value
|
126 |
+
# start
|
127 |
+
self.real = NumberInput('Real', self.default.real, 'real')
|
128 |
+
self.imag = NumberInput('Imaginary', self.default.imag, 'imag')
|
129 |
+
self.swapplaces = swapplaces
|
130 |
+
# end
|
131 |
+
PATH.pop()
|
132 |
+
|
133 |
+
def read_value(self):
|
134 |
+
return complex(self.real.value, self.imag.value)
|
135 |
+
|
136 |
+
@property
|
137 |
+
def value(self):
|
138 |
+
return self.read_value()
|
139 |
+
|
140 |
+
def render(self):
|
141 |
+
with st.container():
|
142 |
+
st.header(self.label)
|
143 |
+
if self.swapplaces:
|
144 |
+
self.imag.render()
|
145 |
+
self.real.render()
|
146 |
+
else:
|
147 |
+
self.real.render()
|
148 |
+
self.imag.render()
|
149 |
+
st.pyplot(argand([self.value]))
|
150 |
+
|
151 |
+
st.markdown('''
|
152 |
+
<a target="_self" href="http://localhost:8501/?complex1.imagvalue=2.0&complex1.realvalue=3.5&complex2.imagvalue=2.5&complex2.realvalue=6.0&numbervalue=0.05&radio=%22on%22">LINK</a>
|
153 |
+
''', unsafe_allow_html=True)
|
154 |
+
|
155 |
+
n = NumberInput('Number', 123, 'number')
|
156 |
+
n.render()
|
157 |
+
st.write(n.value)
|
158 |
+
|
159 |
+
|
160 |
+
left, right = st.columns(2)
|
161 |
+
with left:
|
162 |
+
x = ComplexNumberInput('Complex', 1 + 2j, 'complex1')
|
163 |
+
x.render()
|
164 |
+
st.write('`x` = ', x.value)
|
165 |
+
|
166 |
+
with right:
|
167 |
+
y = ComplexNumberInput(st.text_input('header'), 1 + 2j, 'complex2', swapplaces=st.checkbox('swap places'))
|
168 |
+
y.render()
|
169 |
+
st.write('`y` = ', y.value)
|
170 |
+
|
171 |
+
st.write('`x` + `y` = ', x.value + y.value)
|
172 |
+
|
173 |
+
if autoset == 'on':
|
174 |
+
|
175 |
+
# j = json.dumps(
|
176 |
+
# st.session_state.to_dict(),
|
177 |
+
# sort_keys=True,
|
178 |
+
# )
|
179 |
+
# escaped = urllib.parse.quote(j)
|
180 |
+
# state_dict = {
|
181 |
+
# key: json.dumps(value)
|
182 |
+
# for key, value in st.session_state.to_dict().items()
|
183 |
+
# }
|
184 |
+
# st.experimental_set_query_params(**state_dict)
|
185 |
+
st.experimental_set_query_params(
|
186 |
+
**url_from_state_dict(st.session_state.to_dict())
|
187 |
+
)
|
188 |
+
# st.experimental_rerun()
|