Jhsmit commited on
Commit
692d068
1 Parent(s): e6ef00d

initial commit

Browse files
Files changed (11) hide show
  1. .gitattributes +35 -0
  2. Dockerfile +18 -0
  3. SecB_data.csv +147 -0
  4. app.py +339 -0
  5. example_data.csv +895 -0
  6. example_data_description.md +13 -0
  7. interactive.py +166 -0
  8. make_link.py +49 -0
  9. requirements.txt +8 -0
  10. style.css +14 -0
  11. viewer.py +388 -0
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12
2
+ COPY --from=ghcr.io/astral-sh/uv:0.4.20 /uv /bin/uv
3
+
4
+ # Set up a new user named "user" with user ID 1000
5
+ RUN useradd -m -u 1000 user
6
+ ENV PATH="/home/user/.local/bin:$PATH"
7
+ ENV UV_SYSTEM_PYTHON=1
8
+
9
+ WORKDIR /app
10
+
11
+ COPY --chown=user ./requirements.txt requirements.txt
12
+ RUN uv pip install -r requirements.txt
13
+
14
+ COPY --chown=user . /app
15
+ # Switch to the "user" user
16
+ USER user
17
+
18
+ CMD ["solara", "run", "app.py", "--host", "0.0.0.0", "--port", "7860"]
SecB_data.csv ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ,r_number,SecB tetramer ΔG,dimer ΔΔG,aa_category
2
+ 0,10,20503.218908795578,0.04102027344197268,3
3
+ 1,11,20503.1987580869,-0.013373425168538233,2
4
+ 2,12,20503.23008065833,0.02229263065964915,3
5
+ 3,13,20619.438329191235,0.02630589732871158,4
6
+ 4,14,20619.415562908995,0.020540672117931535,3
7
+ 5,15,20143.039959353235,0.0027414371943450533,0
8
+ 6,16,20143.07512639456,0.013463255472743185,4
9
+ 7,17,20143.05862687419,-0.03987032729492057,2
10
+ 8,18,,,3
11
+ 9,19,20296.468756043112,-0.02139822369645117,0
12
+ 10,20,20296.502148486787,0.013890384409023682,1
13
+ 11,21,19858.98750780226,0.014628551067289663,4
14
+ 12,22,33500.92838634749,3771.976055953415,3
15
+ 13,23,36128.38310334445,3329.280579745784,2
16
+ 14,24,36128.388240777385,3329.289031366621,1
17
+ 15,25,24801.87012994968,-855.3231115085837,4
18
+ 16,26,,,5
19
+ 17,27,18779.362163627287,-0.021029300609370694,3
20
+ 18,28,18779.35417275289,-0.017562932138389442,4
21
+ 19,29,,,5
22
+ 20,30,17894.695699432654,-0.03769727415419766,0
23
+ 21,31,34670.09093460364,2203.2157691959583,4
24
+ 22,32,26689.116321739537,6554.0702098234,2
25
+ 23,33,16976.720144254083,-0.017914774260134436,3
26
+ 24,34,16976.734252000926,-0.022315037105727242,0
27
+ 25,35,18010.553373649574,-0.015561104817606974,1
28
+ 26,36,22088.416581497542,0.012615541094419314,2
29
+ 27,37,16432.442825871985,-0.03882252220500959,3
30
+ 28,38,,,5
31
+ 29,39,16208.48690944545,-224.84583854299308,1
32
+ 30,40,18551.36569784316,-0.011218987645406742,4
33
+ 31,41,15347.31518800692,-0.01147404478797398,0
34
+ 32,42,15347.279646147805,-0.0046031706497160485,4
35
+ 33,43,15287.352327048604,-0.011974727545748465,1
36
+ 34,44,15287.328485973016,0.006624935347645078,4
37
+ 35,45,15340.757050690265,-0.015556389374978608,1
38
+ 36,46,20418.40553802804,0.003065225679165451,3
39
+ 37,47,34393.72034004959,493.4737776298134,4
40
+ 38,48,34393.69950679205,493.4735983776991,3
41
+ 39,49,29467.269781947038,0.02019126732920995,3
42
+ 40,50,33738.10972117186,314.95418239201535,3
43
+ 41,51,32870.20298698476,866.7369676164162,4
44
+ 42,52,18972.423732909007,-0.006612892411794746,4
45
+ 43,53,17768.2951177495,0.0037590513238683343,1
46
+ 44,54,17768.31024500069,0.03906060218287166,1
47
+ 45,55,18695.279120801035,-4.797512519871816e-05,4
48
+ 46,56,18695.28682118084,0.020495537275564857,2
49
+ 47,57,19651.820346718407,-0.0047539925362798385,1
50
+ 48,58,,,4
51
+ 49,59,,,4
52
+ 50,60,,,4
53
+ 51,61,,,0
54
+ 52,62,29683.323649341943,895.8858358495345,4
55
+ 53,63,29820.52673172767,1033.0780610037182,3
56
+ 54,64,33599.87422254384,4678.962486535471,4
57
+ 55,65,33899.166600093864,3066.3491499712,3
58
+ 56,66,32091.361301778325,148.57627289799348,4
59
+ 57,67,32091.360835556497,148.5765613044059,3
60
+ 58,68,29393.636928700293,-823.6172855605837,4
61
+ 59,69,19174.901371884695,-677.4249677945918,5
62
+ 60,70,18657.191070073502,-13.994220423795923,1
63
+ 61,71,18657.212035835983,-13.996887780889665,1
64
+ 62,72,18671.18160571422,-0.0392965172904951,3
65
+ 63,73,18671.214599750503,0.009727035645482829,4
66
+ 64,74,19517.993351061566,-0.013278524278575787,2
67
+ 65,75,20675.848037899672,0.0009824113913055044,4
68
+ 66,76,37636.39791876358,5007.989074541434,5
69
+ 67,77,37636.38655502341,5007.988149225941,1
70
+ 68,78,33782.48872642615,5273.721614185131,4
71
+ 69,79,35905.071510615024,5480.913130223267,3
72
+ 70,80,36677.6038686029,5506.0450257956,3
73
+ 71,81,36677.61636593746,5506.07698878599,5
74
+ 72,82,36677.60260767371,5506.045433733954,5
75
+ 73,83,33378.803348391986,5488.374668323548,4
76
+ 74,84,33378.758340559325,5488.3754546840755,2
77
+ 75,85,,,3
78
+ 76,86,16381.609826156857,4159.300956732506,4
79
+ 77,87,15851.513354479175,3690.8610620640447,4
80
+ 78,88,15851.527793853642,3690.8730222816703,5
81
+ 79,89,15864.98788879845,3704.327084931174,4
82
+ 80,90,15865.00948761141,3704.348709510483,1
83
+ 81,91,15945.762638912876,3497.030145639892,5
84
+ 82,92,17572.738649033017,3486.6384930474924,3
85
+ 83,93,17701.854480757363,2682.3642450614843,3
86
+ 84,94,17701.857541631496,,4
87
+ 85,95,,,4
88
+ 86,96,,,0
89
+ 87,97,,,5
90
+ 88,98,,,4
91
+ 89,99,,,5
92
+ 90,100,31813.42291926261,10244.9531303845,4
93
+ 91,101,33529.85517243987,11961.400668845643,2
94
+ 92,102,36730.43742567122,10677.895820433754,5
95
+ 93,103,,,5
96
+ 94,104,36730.49856955352,9656.920602729318,3
97
+ 95,105,33170.0546771055,8144.325049692423,4
98
+ 96,106,33170.06277423715,8144.366457951568,4
99
+ 97,107,33221.414059792674,8277.794238047914,2
100
+ 98,108,,,5
101
+ 99,109,34786.233073422256,9913.866941161803,2
102
+ 100,110,36049.59790646001,11177.23627174936,4
103
+ 101,111,37031.1800616211,10987.309632021992,0
104
+ 102,112,37298.468385922286,10882.982805124775,1
105
+ 103,113,37298.4580930044,10855.34113543159,5
106
+ 104,114,,,4
107
+ 105,115,35471.30349593957,6029.930369256417,3
108
+ 106,116,37592.23487945331,6166.703486222199,3
109
+ 107,117,37592.225568106165,3504.8417300734436,4
110
+ 108,118,33094.685526785215,1767.28438800378,4
111
+ 109,119,30782.441488743407,588.1403290804192,3
112
+ 110,120,29823.552953996168,6572.2642344378,0
113
+ 111,121,29823.536757756243,7331.054497044755,5
114
+ 112,122,29823.553787339544,7331.079111923154,3
115
+ 113,123,29354.599845774657,6862.121884333061,2
116
+ 114,124,,,5
117
+ 115,125,25318.331494427643,4334.17022873124,3
118
+ 116,126,25318.335590634008,4334.161811002479,4
119
+ 117,127,18119.96191537785,0.01123049754096428,3
120
+ 118,128,14236.362799804649,-0.013547671278502094,4
121
+ 119,129,14236.349630239947,0.01601643715548562,4
122
+ 120,130,,,5
123
+ 121,131,12340.7738129305,0.004643109969038051,4
124
+ 122,132,15933.878888854008,0.03159931044683617,3
125
+ 123,133,15933.855867693184,-0.010608925183987594,2
126
+ 124,134,,,1
127
+ 125,135,,,4
128
+ 126,136,,,4
129
+ 127,137,,,2
130
+ 128,138,13930.21814088456,1216.1992204553626,4
131
+ 129,139,13910.763749526615,1196.765221508609,3
132
+ 130,140,13439.840760749465,725.8786578881263,2
133
+ 131,141,9919.380363518709,0.02644048343609029,4
134
+ 132,142,9919.371556553311,0.005813216290334822,3
135
+ 133,143,11183.866323743205,0.01785808350541629,3
136
+ 134,144,11183.846808260194,0.018235978361190064,3
137
+ 135,145,11183.846928410276,0.0011724137202691054,4
138
+ 136,146,10693.308497458533,0.00020877546194242314,5
139
+ 137,147,10693.249519284816,0.011582189848923008,1
140
+ 138,148,10660.375891339996,0.003966357349781902,5
141
+ 139,149,10660.333223836176,-0.023842569449698203,3
142
+ 140,150,10660.354481127511,0.034241028002725216,1
143
+ 141,151,10660.362373368838,0.006191466125528677,1
144
+ 142,152,10660.380600976769,0.006496632580820005,0
145
+ 143,153,11197.67105254893,0.011001825150742661,3
146
+ 144,154,11197.642798281837,-0.017785698271836736,1
147
+ 145,155,1629.4416305017826,5151.96303489735,4
app.py ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ from pathlib import Path
3
+ from typing import Callable, Optional, cast
4
+ from urllib.parse import parse_qsl
5
+
6
+ import altair as alt
7
+ import numpy as np
8
+ import pandas as pd
9
+ import reacton.core
10
+ import solara
11
+ import solara.lab
12
+ from cmap import Catalog, Colormap
13
+ from ipyvuetify.extra import FileInput
14
+
15
+ from make_link import encode_url
16
+ from pycafe_linkgen import make_link
17
+ from viewer import AxisProperties, ColorTransform, ProteinView, RoutedView
18
+
19
+ DEFAULT_CMAP = "tol:rainbow_PuRd"
20
+ NORM_CATEGORIES = ["linear", "diverging", "categorical"]
21
+ VMIN_DEFAULT = 0.0
22
+ VMAX_DEFAULT = 1.0
23
+ HIGHLIGHT_COLOR = "#e933f8"
24
+ MISSING_DATA_COLOR = "#8c8c8c"
25
+ CMAP_OPTIONS = list(Catalog().namespaced_keys())
26
+
27
+ # BASE_URL = "http://localhost:8765" # local testing
28
+ BASE_URL = "https://huggingface.co/spaces/Jhsmit/ipymolstar-annotate-colors"
29
+
30
+ pth = Path(__file__).parent
31
+
32
+
33
+ @solara.component
34
+ def FileInputComponent(
35
+ on_file: Callable[[solara.components.file_drop.FileInfo | None], None],
36
+ ):
37
+ """Adaptation of _FileDrop."""
38
+
39
+ file_info, set_file_info = solara.use_state(None)
40
+ wired_files, set_wired_files = solara.use_state(
41
+ cast(Optional[list[solara.components.file_drop.FileInfo]], None)
42
+ )
43
+
44
+ file_drop = FileInput.element(on_file_info=set_file_info, multiple=False) # type: ignore
45
+
46
+ def wire_files():
47
+ if not file_info:
48
+ set_wired_files([])
49
+ return
50
+
51
+ real = cast(FileInput, solara.get_widget(file_drop))
52
+
53
+ # workaround for @observe being cleared
54
+ real.version += 1
55
+ real.reset_stats()
56
+
57
+ set_wired_files(
58
+ cast(list[solara.components.file_drop.FileInfo], real.get_files())
59
+ )
60
+
61
+ solara.use_effect(wire_files, [file_info])
62
+
63
+ def handle_file():
64
+ if not wired_files:
65
+ on_file(None)
66
+ return
67
+ if on_file:
68
+ f = wired_files[0].copy()
69
+ f["data"] = None
70
+ on_file(f)
71
+
72
+ solara.lab.use_task(handle_file, dependencies=[wired_files])
73
+
74
+ return file_drop
75
+
76
+
77
+ @solara.component
78
+ def ColorPickerMenuButton(title: str, color: solara.Reactive[str]):
79
+ local_color = solara.use_reactive(color.value)
80
+
81
+ def on_open(value: bool):
82
+ if not value:
83
+ color.set(local_color.value)
84
+
85
+ btn = solara.Button(title, color=local_color.value)
86
+ with solara.lab.Menu(
87
+ activator=btn, close_on_content_click=False, on_open_value=on_open
88
+ ):
89
+ solara.v.ColorPicker(
90
+ v_model=local_color.value,
91
+ on_v_model=local_color.set,
92
+ )
93
+
94
+
95
+ empty_frame = pd.DataFrame()
96
+ R_DEFAULT = ""
97
+ V_DEFAULT = ""
98
+
99
+ # %%
100
+
101
+
102
+ @solara.component
103
+ def MainApp():
104
+ dark_effective = solara.lab.use_dark_effective()
105
+ title = solara.use_reactive("My annotated protein view")
106
+ description = solara.use_reactive("")
107
+ molecule_id = solara.use_reactive("1QYN")
108
+ data = solara.use_reactive(empty_frame)
109
+ warning_text = solara.use_reactive("")
110
+
111
+ residue_column = solara.use_reactive(R_DEFAULT)
112
+ color_column = solara.use_reactive(V_DEFAULT)
113
+
114
+ label = solara.use_reactive("value")
115
+ unit = solara.use_reactive("au")
116
+
117
+ highlight_color = solara.use_reactive(HIGHLIGHT_COLOR)
118
+ missing_data_color = solara.use_reactive(MISSING_DATA_COLOR)
119
+ autoscale_y = solara.use_reactive(True)
120
+
121
+ cmap_name = solara.use_reactive(DEFAULT_CMAP)
122
+ reverse = solara.use_reactive(False)
123
+ full_cmap_name = cmap_name.value + "_r" if reverse.value else cmap_name.value
124
+ cmap = Colormap(full_cmap_name)
125
+
126
+ vmin = solara.use_reactive(VMIN_DEFAULT)
127
+ vmax = solara.use_reactive(VMAX_DEFAULT)
128
+ norm_type = solara.use_reactive(NORM_CATEGORIES[0])
129
+
130
+ rc = reacton.core.get_render_context()
131
+
132
+ def on_file(file_info: solara.components.file_drop.FileInfo | None):
133
+ if not file_info:
134
+ data.set(pd.DataFrame())
135
+ return
136
+
137
+ try:
138
+ df = pd.read_csv(file_info["file_obj"])
139
+ except Exception as e:
140
+ warning_text.set(str(e))
141
+ return
142
+ if len(df.columns) < 2:
143
+ warning_text.set(f"Expected at least 2 columns, got {len(df.columns)}")
144
+ data.set(pd.DataFrame())
145
+ return
146
+
147
+ warning_text.set("")
148
+
149
+ # order matters!
150
+ # with solara.batch_update():
151
+ # https://github.com/widgetti/solara/issues/637
152
+ with rc:
153
+ residue_column.set(df.columns[0])
154
+ color_column.set(df.columns[1])
155
+ data.set(df)
156
+
157
+ colors = ColorTransform(
158
+ name=full_cmap_name,
159
+ norm_type=norm_type.value,
160
+ vmin=vmin.value,
161
+ vmax=vmax.value,
162
+ missing_data_color=missing_data_color.value,
163
+ highlight_color=highlight_color.value,
164
+ )
165
+
166
+ axis_properties = AxisProperties(
167
+ label=label.value,
168
+ unit=unit.value,
169
+ autoscale_y=autoscale_y.value,
170
+ )
171
+
172
+ if data.value.empty:
173
+ data_view = pd.DataFrame({"residue_number": [], "value": []})
174
+ else:
175
+ data_view = pd.DataFrame(
176
+ {
177
+ "residue_number": data.value[residue_column.value],
178
+ "value": data.value[color_column.value],
179
+ }
180
+ )
181
+
182
+ def load_example_data():
183
+ bio = io.BytesIO(Path("example_data.csv").read_bytes())
184
+ bio.seek(0)
185
+ file_info = solara.components.file_drop.FileInfo(
186
+ name="example_data.csv",
187
+ size=Path("example_data.csv").stat().st_size,
188
+ file_obj=bio,
189
+ data=None,
190
+ )
191
+
192
+ # with solara.batch_update():
193
+ # https://github.com/widgetti/solara/issues/637
194
+ with rc:
195
+ molecule_id.set("6GOX")
196
+ title.set("SecA HDX-MS protein local flexibility")
197
+ on_file(file_info)
198
+ vmin.set(4e4)
199
+ vmax.set(1e4)
200
+ autoscale_y.set(False)
201
+ description.set(Path("example_data_description.md").read_text())
202
+
203
+ with solara.AppBar():
204
+ with solara.Tooltip("Load example data and settings"):
205
+ solara.Button(
206
+ icon_name="mdi-test-tube",
207
+ icon=True,
208
+ on_click=load_example_data,
209
+ )
210
+
211
+ query_string = encode_url(
212
+ title=title.value,
213
+ molecule_id=molecule_id.value,
214
+ colors=colors,
215
+ axis_properties=axis_properties,
216
+ data=data_view,
217
+ description=description.value,
218
+ )
219
+
220
+ ProteinView(
221
+ title.value,
222
+ molecule_id=molecule_id.value,
223
+ data=data_view,
224
+ colors=colors,
225
+ axis_properties=axis_properties,
226
+ dark_effective=dark_effective,
227
+ description=description.value,
228
+ )
229
+
230
+ with solara.Sidebar():
231
+ with solara.Card("Settings"):
232
+ solara.InputText(label="Title", value=title)
233
+ solara.InputText(label="PDB ID", value=molecule_id)
234
+ solara.Text("Choose .csv data file:")
235
+ FileInputComponent(on_file)
236
+
237
+ if warning_text.value:
238
+ solara.Warning(warning_text.value)
239
+
240
+ if not data.value.empty:
241
+ with solara.Row():
242
+ solara.Select(
243
+ label="Residue Column",
244
+ value=residue_column,
245
+ values=list(data.value.columns),
246
+ )
247
+ solara.Select(
248
+ label="Color Column",
249
+ value=color_column,
250
+ values=list(data.value.columns),
251
+ )
252
+
253
+ with solara.Row():
254
+ solara.InputText(label="Label", value=label)
255
+ solara.InputText(label="Unit", value=unit)
256
+
257
+ solara.Text("Colors")
258
+ with solara.Row(gap="10px", justify="space-around"):
259
+ ColorPickerMenuButton("Highlight", highlight_color)
260
+ ColorPickerMenuButton("Missing data", missing_data_color)
261
+
262
+ # with solara.Row():
263
+ solara.v.Autocomplete(
264
+ v_model=cmap_name.value,
265
+ on_v_model=cmap_name.set,
266
+ items=CMAP_OPTIONS,
267
+ )
268
+
269
+ solara.Select(
270
+ label="Normalization type", value=norm_type, values=NORM_CATEGORIES
271
+ )
272
+
273
+ with solara.Row():
274
+
275
+ def set_vmin(value: float):
276
+ if norm_type.value == "diverging":
277
+ vmin.set(value)
278
+ vmax.set(-value)
279
+ else:
280
+ vmin.set(value)
281
+
282
+ solara.InputFloat(
283
+ label="vmin",
284
+ value=vmin.value,
285
+ on_value=set_vmin,
286
+ disabled=norm_type.value == "categorical",
287
+ )
288
+ solara.InputFloat(
289
+ label="vmax",
290
+ value=vmax,
291
+ disabled=norm_type.value in ["diverging", "categorical"],
292
+ )
293
+ with solara.GridFixed(columns=2):
294
+ with solara.Tooltip("Reverses the color map"):
295
+ solara.Checkbox(label="Reverse", value=reverse)
296
+
297
+ with solara.Tooltip(
298
+ "Uncheck to use color range as the scatterplot y scale"
299
+ ):
300
+ solara.Checkbox(label="Autoscale Y", value=autoscale_y)
301
+
302
+ solara.Image(cmap._repr_png_(height=24), width="100%")
303
+ solara.InputTextArea(
304
+ label="Description", value=description, continuous_update=True
305
+ )
306
+ solara.Div(style={"height": "10px"})
307
+
308
+ solara.Button(
309
+ label="Open view in new tab",
310
+ attributes={"href": BASE_URL + "?" + query_string, "target": "_blank"},
311
+ block=True,
312
+ )
313
+
314
+
315
+ @solara.component
316
+ def Page():
317
+ route = solara.use_router()
318
+ solara.Style(Path("style.css"))
319
+
320
+ dark_effective = solara.lab.use_dark_effective()
321
+ dark_previous = solara.use_previous(dark_effective)
322
+ if dark_previous != dark_effective:
323
+ if dark_effective:
324
+ alt.themes.enable("dark")
325
+ else:
326
+ alt.themes.enable("default")
327
+
328
+ # todo: aways true, check valid
329
+ if route.search:
330
+ query_dict = {k: v for k, v in parse_qsl(route.search)}
331
+ # needs more keys but if this is there then at least there has been an attempt
332
+ if "molecule_id" in query_dict:
333
+ RoutedView()
334
+
335
+ else:
336
+ MainApp()
337
+
338
+
339
+ # %%
example_data.csv ADDED
@@ -0,0 +1,895 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ r_number,SecA Monomer (ΔG),SecA Monomer + ADP (ΔΔG)
2
+ 8,,
3
+ 9,,
4
+ 10,,
5
+ 11,,
6
+ 12,,
7
+ 13,,
8
+ 14,,
9
+ 15,,
10
+ 16,,
11
+ 17,,
12
+ 18,,
13
+ 19,,
14
+ 20,,
15
+ 21,,
16
+ 22,,
17
+ 23,,
18
+ 24,,
19
+ 25,,
20
+ 26,,
21
+ 27,,
22
+ 28,,
23
+ 29,,
24
+ 30,,
25
+ 31,23991.09155175152,7025.544809311072
26
+ 32,23991.073766252324,7025.564142062456
27
+ 33,,
28
+ 34,23534.18184416941,6631.4617716919565
29
+ 35,22613.679926254637,6538.76772147643
30
+ 36,21805.123731534888,2216.7773386817025
31
+ 37,17670.268454913006,672.9107930574137
32
+ 38,29406.241256949845,632.1887181593011
33
+ 39,31350.321097418004,728.6553716048656
34
+ 40,25470.88537276944,128.75939848115377
35
+ 41,30754.18900173258,253.23774954457986
36
+ 42,30754.19679326109,253.23209531961402
37
+ 43,30770.850683714674,236.58435596632262
38
+ 44,31164.447779059035,343.3670803543937
39
+ 45,32043.40789806988,541.7067689648356
40
+ 46,32043.422797911066,541.6823145450799
41
+ 47,32043.412457561182,541.6974425906628
42
+ 48,30301.597633185465,1926.5445474094595
43
+ 49,32164.484007591276,456.69493224966936
44
+ 50,32164.48511293244,456.6915332848512
45
+ 51,34635.14730066055,0.004703252998297103
46
+ 52,25840.11437195866,-362.496120162672
47
+ 53,25724.40264467337,-246.77153556369012
48
+ 54,26082.539516504457,267.50732017175324
49
+ 55,16911.214195290213,340.607375157364
50
+ 56,16824.376005854763,0.017860434410977177
51
+ 57,16824.374648131645,0.0305255885796214
52
+ 58,16824.394023083332,0.00045810068331775256
53
+ 59,18166.0657560394,7955.676521578178
54
+ 60,31308.340945886863,761.7459374004866
55
+ 61,33200.67910540987,506.9511150949256
56
+ 62,35103.74236290625,1835.5939930294044
57
+ 63,33601.53708138953,1517.5570253851038
58
+ 64,30262.531565825306,1508.2708221258144
59
+ 65,,
60
+ 66,33080.096186109105,1517.5589038941107
61
+ 67,33475.54118407467,1300.5079384387645
62
+ 68,33475.55210984575,1300.5087928440407
63
+ 69,,
64
+ 70,,
65
+ 71,,
66
+ 72,,
67
+ 73,,
68
+ 74,31616.818537218944,575.1688257485002
69
+ 75,26498.07818894053,4271.258631097931
70
+ 76,29587.01610568914,1194.5739508404913
71
+ 77,29915.48380153676,866.1018363421208
72
+ 78,30371.92283676973,-43.9018869106003
73
+ 79,30371.92097696326,-43.90747601824114
74
+ 80,30075.45979629592,961.5283964930495
75
+ 81,28641.332188110857,3104.4045666242637
76
+ 82,27926.45101551447,3944.7873420085707
77
+ 83,27445.64102357994,4425.60707837034
78
+ 84,20277.875980618763,13307.721857580396
79
+ 85,20057.75450068875,15077.106138876548
80
+ 86,19573.503568531756,13805.357839201119
81
+ 87,19450.959921106445,15542.53236892731
82
+ 88,20431.73579852715,14660.089272249297
83
+ 89,27912.259154499843,7678.717404522024
84
+ 90,31104.404806056584,7678.625895457357
85
+ 91,32632.64362637889,7571.222166750729
86
+ 92,32632.647977586017,7571.226935357143
87
+ 93,30497.94495705497,7189.279054210405
88
+ 94,30497.933702381524,7189.293772185207
89
+ 95,,
90
+ 96,32048.318933137743,8001.63773673604
91
+ 97,32442.315939820044,7665.858136009199
92
+ 98,34255.446402399735,8269.34784004408
93
+ 99,30950.14314720625,7729.414620019106
94
+ 100,30950.140881048133,7729.395195816836
95
+ 101,30751.257130052498,7901.085861314885
96
+ 102,18247.33210451565,12789.958642177236
97
+ 103,17736.56696480262,12308.473455205381
98
+ 104,17730.14765454237,12314.889714743062
99
+ 105,17730.13356363255,12314.91258739002
100
+ 106,17388.09922423498,14142.792128917823
101
+ 107,17388.105231051955,14142.783952684364
102
+ 108,17032.136245169542,9365.570190584978
103
+ 109,16995.723034013958,9401.997081540838
104
+ 110,16858.412691873255,14677.686860869184
105
+ 111,16858.401701594994,15105.738581174457
106
+ 112,34871.174814094265,1249.719563531653
107
+ 113,34796.20314105318,1324.6956814579244
108
+ 114,33760.602855197605,2323.4656852255357
109
+ 115,,
110
+ 116,34152.20742996766,1931.8467398521607
111
+ 117,34937.481690938665,1727.358846303483
112
+ 118,35561.71642471585,1307.6349189900575
113
+ 119,36325.19445780738,544.1518261037054
114
+ 120,34789.00033616036,-280.19802826747764
115
+ 121,31516.109885229904,-88.57307405341999
116
+ 122,31516.102446004734,-101.32928984117461
117
+ 123,28399.33203471786,2591.7211347946613
118
+ 124,30260.5188742278,1464.6943387383872
119
+ 125,30639.2782048638,1085.9458168854944
120
+ 126,30882.51767523945,159.01578211614833
121
+ 127,19379.386952235483,8100.744292258885
122
+ 128,29327.01040423669,-16.37099032940023
123
+ 129,29326.99536501814,-16.354743181997037
124
+ 130,19778.52539211744,8137.776028594548
125
+ 131,31000.84402906168,47.717536310818105
126
+ 132,28690.838886896065,4512.027771015299
127
+ 133,26857.354378730783,6942.601006713503
128
+ 134,21747.501003597717,
129
+ 135,,
130
+ 136,,
131
+ 137,,
132
+ 138,,
133
+ 139,,
134
+ 140,33102.61037334002,5341.7464606040885
135
+ 141,33508.461062038856,5341.745806235325
136
+ 142,36121.034774080326,5341.743389203366
137
+ 143,36789.4083501364,5792.841843589449
138
+ 144,36736.01102818686,5509.383482629753
139
+ 145,,
140
+ 146,31818.82427911054,5351.233616135625
141
+ 147,31818.8166284924,5493.404060080327
142
+ 148,31977.23305117972,5649.875324856759
143
+ 149,31977.24198077373,5649.867931293738
144
+ 150,29987.14830569599,2057.068080313129
145
+ 151,31047.72041252939,996.4988840584228
146
+ 152,31505.177518634155,539.042329398846
147
+ 153,32049.98269237588,-5.773339122693869
148
+ 154,32049.98380252848,-5.768594211236632
149
+ 155,32049.966917248847,-2709.813861816725
150
+ 156,17601.211093289116,11738.94306468303
151
+ 157,17934.061586791875,40.5078294879022
152
+ 158,27251.21054155213,4594.95761351092
153
+ 159,,
154
+ 160,27359.241603659608,4421.725079770182
155
+ 161,18016.86730392658,0.00845712325826753
156
+ 162,,
157
+ 163,30743.988917188297,1538.8434071870724
158
+ 164,,
159
+ 165,28837.784275045247,3165.444164122655
160
+ 166,18181.322180828294,1319.5082386117683
161
+ 167,18181.322846368013,450.19015471744933
162
+ 168,34546.88232430929,0.001059778471244499
163
+ 169,34546.89036244835,0.0027823110431199893
164
+ 170,34546.87246053701,0.026155991814448498
165
+ 171,34546.87800204264,414.79327906959224
166
+ 172,34515.8979621117,445.7745287727521
167
+ 173,34515.88722844851,445.7834141055864
168
+ 174,,
169
+ 175,31821.074419745048,1013.2418121856608
170
+ 176,31821.19524183612,1013.1151918773357
171
+ 177,32009.240911204328,825.0788246029442
172
+ 178,32349.80687201912,813.9455382209744
173
+ 179,31883.057069077026,2927.2516491561255
174
+ 180,31425.748476402387,3384.5453306840536
175
+ 181,32753.437451154867,1049.6231880526102
176
+ 182,31576.055648603957,821.0158437719583
177
+ 183,30617.983740755983,1719.5806721903973
178
+ 184,30617.97096568688,1719.5926099599674
179
+ 185,28008.940688667684,4263.25478185618
180
+ 186,28457.090058845886,3325.2147327992607
181
+ 187,,
182
+ 188,,
183
+ 189,,
184
+ 190,,
185
+ 191,,
186
+ 192,20185.359502378727,0.018454052955348743
187
+ 193,20185.36823418708,0.007447516814863775
188
+ 194,19837.72880965597,0.014218693460861687
189
+ 195,,
190
+ 196,18972.734505926343,0.002746730639046291
191
+ 197,18950.59560962396,0.00803298975006328
192
+ 198,18950.597419423528,0.004331701602495741
193
+ 199,27000.492939972093,2744.5928470819817
194
+ 200,32521.925222573576,514.1228603216441
195
+ 201,31876.17825617493,887.5434019537861
196
+ 202,31876.173128320163,887.5330773649403
197
+ 203,31214.359513062693,374.28730294057823
198
+ 204,31131.8879857148,291.5173851402142
199
+ 205,30286.351557567392,673.6273164951599
200
+ 206,27595.561213079414,2756.90823524406
201
+ 207,28322.396397680805,1092.4004656111065
202
+ 208,19386.848442427938,7240.753946503006
203
+ 209,29938.875173147044,2705.6908924736454
204
+ 210,29691.13865822264,2953.431944949796
205
+ 211,28674.767673863014,3201.274042037672
206
+ 212,30508.88695238237,3830.179838942753
207
+ 213,30508.88475833993,3830.1927513982046
208
+ 214,28869.607268751024,3506.390139826104
209
+ 215,26664.140343171497,3506.4319316831607
210
+ 216,,
211
+ 217,18408.819061433627,-0.0042112465780519415
212
+ 218,18408.802795925258,0.003927762991224881
213
+ 219,16745.910222098813,51.944868677004706
214
+ 220,16745.90749400146,8.286182057614496
215
+ 221,16745.909497741846,8.296216348207963
216
+ 222,,
217
+ 223,17962.891522346847,0.002297996707056882
218
+ 224,27881.479679817505,1990.5911668457484
219
+ 225,27881.482921436047,1990.5895330935273
220
+ 226,18050.140316667446,640.8726833570618
221
+ 227,17684.28835835116,9.89956825520494
222
+ 228,,
223
+ 229,31835.46284525379,1891.0843571909318
224
+ 230,26762.35853469877,5786.8516062134295
225
+ 231,25029.55911023576,5833.910431367291
226
+ 232,21613.264269829637,2647.938053836693
227
+ 233,19949.568260664662,12.683675096232037
228
+ 234,20110.534591558797,2026.3352813655401
229
+ 235,15860.951583772365,0.0011205622558918549
230
+ 236,20005.05367093259,-502.3688373111472
231
+ 237,32493.072034633864,26.87870763648607
232
+ 238,25765.845270629405,2791.911561973244
233
+ 239,31769.25414231316,348.6333420255687
234
+ 240,31337.16686972494,1918.553570831391
235
+ 241,32753.879247035784,501.8366402803258
236
+ 242,30487.0213692793,21.83915136627911
237
+ 243,29071.09327248193,0.009148981316684512
238
+ 244,,
239
+ 245,22264.62846802738,4264.673622098966
240
+ 246,29929.18070367177,7.952244364762009
241
+ 247,29708.285110770456,3.7468714406495565
242
+ 248,19128.614128631456,1106.469461020868
243
+ 249,17352.879058925882,0.006066331792681012
244
+ 250,16505.83644543039,0.0037445199668582063
245
+ 251,16026.97011863199,-0.009878505592496367
246
+ 252,16026.978546450802,-0.01350834229378961
247
+ 253,16026.963625203864,0.020082526772966958
248
+ 254,16450.546723371477,-0.0035127055780321825
249
+ 255,16450.546319750043,0.005914939189096913
250
+ 256,16179.136153329891,-0.0036228663575457176
251
+ 257,16158.109461851052,0.0011687209243973484
252
+ 258,16158.099687342732,0.00033745832479326054
253
+ 259,16158.089722656245,0.00009790773219719995
254
+ 260,16158.081248017006,-0.009605658209693502
255
+ 261,16158.090875466843,-0.0015033937543194043
256
+ 262,16158.1023371089,-0.010530910070883692
257
+ 263,16158.10196011989,0.002762910395176732
258
+ 264,,
259
+ 265,16168.739380151374,-0.00014460413694905583
260
+ 266,16188.254681936196,-0.0008886171326594194
261
+ 267,16429.255252979125,0.004697340355050983
262
+ 268,16429.268818942546,-0.007154826351325028
263
+ 269,18818.03024694151,0.002009470059419982
264
+ 270,18818.03244875209,-0.0005356236797524616
265
+ 271,18818.03111207148,0.007239894170197658
266
+ 272,19416.76484079358,158.00563527073973
267
+ 273,18390.585519838703,-0.004610922296706121
268
+ 274,19701.386847243397,403.6478487691056
269
+ 275,22332.807320835956,1289.5004388885136
270
+ 276,32418.0794257208,1378.5212097874282
271
+ 277,32440.943536741408,1355.666018930755
272
+ 278,32440.954051659053,1355.6513325005762
273
+ 279,30892.665709385747,160.4775690599381
274
+ 280,28602.18572528113,240.54209732697927
275
+ 281,28602.151572002807,236.3948280136101
276
+ 282,,
277
+ 283,,
278
+ 284,,
279
+ 285,,
280
+ 286,22359.66970101605,2628.3558795917816
281
+ 287,25810.18495131585,1254.4117128919606
282
+ 288,28830.96477312468,1677.0850587956265
283
+ 289,28830.968231375493,1677.0946980356857
284
+ 290,28830.96386232984,1677.093817879435
285
+ 291,27122.96899688966,1428.6917767988816
286
+ 292,18644.315485334988,561.5798915650121
287
+ 293,17628.248729652794,56.17511656709394
288
+ 294,17628.23142258938,56.19601052681537
289
+ 295,17542.076237595877,125.31676059392339
290
+ 296,17412.713280278742,0.0020097858177905437
291
+ 297,17412.70536897506,0.0022561617188330274
292
+ 298,17040.04695492374,-0.001717597224342171
293
+ 299,,
294
+ 300,19136.356107794552,0.008935667112382362
295
+ 301,,
296
+ 302,19332.34325784854,0.0029541018848249223
297
+ 303,19332.335396070277,0.010500074706214946
298
+ 304,19317.10571218931,100.58682829691679
299
+ 305,19997.79366794829,-0.0001845851911639329
300
+ 306,21073.397662856827,3778.8793456264757
301
+ 307,33922.92359071217,764.3374117560161
302
+ 308,34882.25867017017,649.5044887334734
303
+ 309,34882.24949605289,649.5140786794364
304
+ 310,33944.67331064942,665.3746267246534
305
+ 311,33944.673884163574,665.37209711592
306
+ 312,34643.71505555079,652.0952253696305
307
+ 313,34643.71674508259,652.0817975795362
308
+ 314,33632.98686998779,676.7626921566116
309
+ 315,33837.95794427344,829.7095782317265
310
+ 316,34675.72834443182,844.7014748787187
311
+ 317,34675.73737750312,844.7005803240245
312
+ 318,34675.72851709516,844.6981543286165
313
+ 319,31241.70234213994,829.6493797184194
314
+ 320,,
315
+ 321,26580.55670869263,2018.3803429619256
316
+ 322,26214.33808108094,1912.9810850110334
317
+ 323,26160.033489112677,1886.4484127746036
318
+ 324,22503.105982820776,1984.3232650678474
319
+ 325,22530.335459159847,1883.2049471935716
320
+ 326,22530.33582480781,1883.1920245979054
321
+ 327,,
322
+ 328,20787.31181404657,1229.8325882557183
323
+ 329,23599.16565374537,1045.7375321061445
324
+ 330,23622.12568949256,1066.9313492387191
325
+ 331,23622.12073810533,1066.9369928580163
326
+ 332,23513.61662131837,1026.2051753053493
327
+ 333,19684.57157529202,1047.4981923929918
328
+ 334,15172.254819634134,-37.08288855976389
329
+ 335,15599.50461712528,1455.6389008156584
330
+ 336,15599.506996689091,1455.6436315870196
331
+ 337,15659.932457007966,35.81550093503574
332
+ 338,19839.505953498287,4656.414286316722
333
+ 339,18858.7869651084,0.00003903822289430536
334
+ 340,17456.82591027655,-0.003040262388822157
335
+ 341,17456.817421545973,0.009798906045034528
336
+ 342,17456.8353347518,0.0029052413956378587
337
+ 343,17722.613366783684,-0.002587967690487858
338
+ 344,17735.062720206603,0.002210265924077248
339
+ 345,17735.067770162805,-0.004404072253237246
340
+ 346,17735.07461089606,0.012213021876959829
341
+ 347,17781.27366845042,0.006729767006618204
342
+ 348,17820.439348042786,-0.006687585282634245
343
+ 349,26638.67264980376,3397.6772310103916
344
+ 350,19314.836069377,417.4495914869294
345
+ 351,30961.57904110569,2998.7983130172906
346
+ 352,31406.50253574662,911.2966183080898
347
+ 353,31406.506440256493,102.15580251373831
348
+ 354,28921.36404527259,1818.0647323847152
349
+ 355,27203.451321688,2307.6664225644126
350
+ 356,27203.449457728,2307.6725438188405
351
+ 357,27366.803523833783,903.820115922008
352
+ 358,23579.915688968304,1904.9924126595251
353
+ 359,,
354
+ 360,21179.00564979136,814.2526711291976
355
+ 361,21178.99869949787,814.2519573926911
356
+ 362,21744.04366457456,1196.889697203078
357
+ 363,22555.922272385145,1736.0336150541516
358
+ 364,17696.297261657433,311.05615274897355
359
+ 365,21010.034684919505,1739.6087519665234
360
+ 366,19368.990775965907,546.6572747557839
361
+ 367,20713.785255526764,262.2030440706221
362
+ 368,22379.46012817765,1032.76216910527
363
+ 369,20167.742431864022,301.2552809527042
364
+ 370,20081.36729946277,387.12536995339906
365
+ 371,20081.371710469262,387.11384638028903
366
+ 372,22090.54227494259,2101.499893230848
367
+ 373,20444.70312705304,777.9928211232545
368
+ 374,33987.480956522275,2092.2705518838993
369
+ 375,29885.76552914541,3526.7455129635164
370
+ 376,29885.77396346493,3526.7450651088184
371
+ 377,30500.133263952357,3791.582405574798
372
+ 378,31428.735453867503,3791.578048902982
373
+ 379,32000.023949004502,4462.844588279691
374
+ 380,32097.819201385963,3758.930762441396
375
+ 381,,
376
+ 382,,
377
+ 383,,
378
+ 384,,
379
+ 385,16742.972485593345,47.57971143463874
380
+ 386,16939.224213161677,0.01090963995011407
381
+ 387,32295.50263108543,393.24871526476636
382
+ 388,30185.48621179371,2429.329207426097
383
+ 389,23412.053978351167,4629.657403847901
384
+ 390,18104.39056699601,311.0598466387564
385
+ 391,33617.412827256405,1187.1853506212283
386
+ 392,24063.398321651155,497.4446547694715
387
+ 393,30201.10928503796,3715.4741897733584
388
+ 394,19209.7115906411,403.38568167012636
389
+ 395,22704.25583763713,2976.175564609519
390
+ 396,33524.47403502784,393.77237786424666
391
+ 397,17116.487011169243,219.3841150423068
392
+ 398,19229.58726128961,3006.4058472289325
393
+ 399,15803.200097561876,-0.0003179109717166284
394
+ 400,16758.77717737315,0.004218692611175356
395
+ 401,,
396
+ 402,,
397
+ 403,26671.971144101197,4790.410604220535
398
+ 404,23499.51606928194,5029.897674505286
399
+ 405,23499.52503023451,5029.899358655013
400
+ 406,28210.705491830297,3469.765060526701
401
+ 407,28210.718990536443,3469.7541336873765
402
+ 408,28204.77386793661,3475.700811272094
403
+ 409,15411.608426892475,11082.357472405452
404
+ 410,13528.125744100438,839.3120634820734
405
+ 411,26188.74485646353,2402.9433769478164
406
+ 412,26188.73667670568,2402.9540712467933
407
+ 413,,
408
+ 414,20130.17857773368,4392.749358958423
409
+ 415,19982.682758612813,2083.241243502933
410
+ 416,19960.086376174044,5992.174691319655
411
+ 417,,
412
+ 418,18117.806071224823,13499.22968128588
413
+ 419,30500.65996746804,1116.3599030581827
414
+ 420,24463.40591378844,6338.838693019465
415
+ 421,17362.206993971966,3288.6523267267985
416
+ 422,17362.216449531144,3288.6462283242035
417
+ 423,29127.655789168475,1514.4678908841852
418
+ 424,,
419
+ 425,15048.597881231428,2359.4079577119956
420
+ 426,15041.157229461587,15462.819255646773
421
+ 427,16436.887054953837,13125.908820717188
422
+ 428,16436.870452859028,13127.35842770942
423
+ 429,,
424
+ 430,,
425
+ 431,,
426
+ 432,,
427
+ 433,,
428
+ 434,,
429
+ 435,,
430
+ 436,,
431
+ 437,,
432
+ 438,,
433
+ 439,28701.44220275891,704.3899074967594
434
+ 440,32125.110589555632,664.1684369532959
435
+ 441,32125.108063690503,664.170514711077
436
+ 442,30328.660119791475,519.5303900201689
437
+ 443,30666.71957975305,561.6555151877037
438
+ 444,31467.045450371646,823.645378935511
439
+ 445,32142.839748598115,718.8782442834308
440
+ 446,32142.847508529903,718.8653580260907
441
+ 447,32142.83651951777,718.884241285632
442
+ 448,32232.679102055798,629.0388350984758
443
+ 449,32232.67944344182,629.0369517381187
444
+ 450,30789.79539306437,1657.3935942130302
445
+ 451,,
446
+ 452,27915.39563736915,430.1614211791275
447
+ 453,25533.57222286017,1616.1802236236872
448
+ 454,,
449
+ 455,20524.904797069987,0.007917702310805907
450
+ 456,18860.302130738157,0.009111189745453885
451
+ 457,19218.82747834959,0.0062144053481461015
452
+ 458,18435.503943366995,-0.004355314944405109
453
+ 459,18736.13175396738,0.0014403818713617511
454
+ 460,18736.131764461243,0.004974292707629502
455
+ 461,24994.80799423368,223.88060303373277
456
+ 462,26300.36777315312,178.80876319432718
457
+ 463,26300.371764249845,178.81718194818313
458
+ 464,23881.35558636733,448.35653864114647
459
+ 465,,
460
+ 466,30306.925808245396,1788.8117655420501
461
+ 467,26244.984407233813,1996.4199651296367
462
+ 468,30268.137290576284,1755.2686936027785
463
+ 469,30026.879573499617,98.85680665709515
464
+ 470,29757.83413031923,367.89313442970524
465
+ 471,26605.248816783176,2259.5274298801705
466
+ 472,26605.25238172384,2562.9955654238365
467
+ 473,29524.485673233125,1093.9852630300338
468
+ 474,30500.678966665448,210.175290041494
469
+ 475,30500.67756631676,388.0393577999057
470
+ 476,30220.81837892228,1197.8201598579217
471
+ 477,25102.76573127987,1795.2967320070093
472
+ 478,28361.1074513224,870.6994010544659
473
+ 479,28361.11214104668,1.8493520746160357
474
+ 480,18763.38761921933,0.003136310220725136
475
+ 481,18503.89667383512,48.480979858595674
476
+ 482,17123.834605686716,104.96705572380961
477
+ 483,17123.840156881957,104.9530927313499
478
+ 484,17123.832185263273,104.9691886501023
479
+ 485,17762.382613590533,48.52673724045599
480
+ 486,17878.92334684182,17.099801556199964
481
+ 487,17882.474494237744,52.618627755207854
482
+ 488,17882.48160035982,127.41343000293637
483
+ 489,17882.482072146875,289.5307738588417
484
+ 490,24614.21866616312,3287.876898015158
485
+ 491,26431.66439428395,1521.4242016535063
486
+ 492,29963.84944838995,2153.636128908798
487
+ 493,29728.538006415303,2799.4525000589165
488
+ 494,29719.644104452207,2808.3611889888816
489
+ 495,30547.242436157438,1980.7468569583216
490
+ 496,30656.75714975537,1722.6473296209624
491
+ 497,,
492
+ 498,30656.765092975984,1587.6225553046934
493
+ 499,27483.630102837255,4570.616435900116
494
+ 500,28649.85069562697,1562.7849558111084
495
+ 501,30530.42317867629,1889.0119237426588
496
+ 502,21082.017167291167,718.1567020327311
497
+ 503,20065.561968286205,1616.6758117718346
498
+ 504,20065.55756043106,1316.983898619481
499
+ 505,20966.233094048614,175.32673046737546
500
+ 506,21134.69971297439,1251.365937373961
501
+ 507,21414.438164695744,2472.9238053351582
502
+ 508,21414.453965558205,2472.9186318825377
503
+ 509,20429.235303300997,1359.5520920349736
504
+ 510,20429.2278368098,1359.560022286496
505
+ 511,20429.223181444708,1359.5677858268828
506
+ 512,19743.48761602203,44.231418112492975
507
+ 513,,
508
+ 514,14137.08256501722,1416.5633570060127
509
+ 515,14137.085348100843,1416.5545696851532
510
+ 516,16227.376261424435,691.7597001447848
511
+ 517,18435.54142355581,689.7078810269486
512
+ 518,19157.60322111294,441.75543214005666
513
+ 519,19410.98244288381,1626.3517206649485
514
+ 520,30680.3372255636,1512.174487781227
515
+ 521,30680.334279368475,1512.1829830158495
516
+ 522,30680.334929842964,1352.7595768420651
517
+ 523,28776.910675031493,635.513432513224
518
+ 524,29770.98116326141,1594.8521352698772
519
+ 525,29770.983310768734,1594.8412229811365
520
+ 526,19351.733679477245,417.94640991849883
521
+ 527,18234.1451483328,15.900340418171254
522
+ 528,18424.27251032433,-0.0040361053179367445
523
+ 529,,
524
+ 530,19856.70630280201,273.43872560877935
525
+ 531,18741.770010377822,0.004180088533757953
526
+ 532,19778.347292080376,0.0014230374144972302
527
+ 533,19778.350935317325,0.004498660913668573
528
+ 534,29351.871548531304,1941.6711803532962
529
+ 535,31502.049749752197,953.9778022809733
530
+ 536,31502.051716314312,953.9842822330211
531
+ 537,31733.517655678166,722.5129172418019
532
+ 538,32265.49162599538,816.7838421999295
533
+ 539,33357.924090745495,1173.5641285324964
534
+ 540,33357.93032746014,1173.5476640138222
535
+ 541,32568.98532349955,252.1792973467127
536
+ 542,32602.13562858967,469.9837659096811
537
+ 543,32621.72921263933,450.39666752907215
538
+ 544,33898.790525012606,397.0350865647779
539
+ 545,34777.74902501096,619.7033831039662
540
+ 546,34777.74795252047,619.6945011952121
541
+ 547,33203.645745647525,397.04006236187706
542
+ 548,30230.063892825416,667.4184256864355
543
+ 549,30226.37717954368,671.1153706881851
544
+ 550,,
545
+ 551,29559.08085427816,1963.8422270020092
546
+ 552,29457.840717064344,2065.077692525676
547
+ 553,25828.517937636538,4831.986302080608
548
+ 554,29887.611074926477,1244.635939222473
549
+ 555,25641.03416916397,4303.7932010121185
550
+ 556,28251.851654229333,1572.102139332157
551
+ 557,28740.218530919865,1083.7407694911926
552
+ 558,29881.735349246694,1526.2519092292532
553
+ 559,29720.991442569244,2942.2900203982426
554
+ 560,30022.855525051826,2745.355473564232
555
+ 561,31770.31341932593,1535.0203645287147
556
+ 562,31770.313581299728,1535.0203503585872
557
+ 563,32340.329465743365,1271.7806567600564
558
+ 564,32340.3307986449,1271.768999580403
559
+ 565,29693.1628641994,3665.9276773492857
560
+ 566,29693.158123969035,3665.929727822826
561
+ 567,30600.49541206787,1693.3566101943834
562
+ 568,27056.431988261236,5237.409712036882
563
+ 569,27056.44553530982,6640.516007574948
564
+ 570,26546.49515017113,7150.47350230916
565
+ 571,31053.52779164764,1818.2299381993507
566
+ 572,26504.666028785898,6367.086207206041
567
+ 573,22012.95985180818,11793.674899375463
568
+ 574,21420.22452542597,12386.404797896575
569
+ 575,20079.53225644273,4645.170678004211
570
+ 576,25394.04340041108,9051.818835109938
571
+ 577,25629.414709624674,8816.455110863128
572
+ 578,25629.414253477637,8816.463890079427
573
+ 579,26659.873024717766,7786.002813020066
574
+ 580,19301.30302065588,14299.855889299066
575
+ 581,31462.266877134312,2138.889999670315
576
+ 582,28939.12065598595,4662.02202116698
577
+ 583,20695.55220158766,12360.957892886825
578
+ 584,20695.569233650527,11230.597065986563
579
+ 585,21178.78727532166,13150.321398474622
580
+ 586,23782.83182476683,9669.035749966439
581
+ 587,25750.60549799774,6738.491785534123
582
+ 588,,
583
+ 589,,
584
+ 590,,
585
+ 591,,
586
+ 592,,
587
+ 593,,
588
+ 594,,
589
+ 595,,
590
+ 596,,
591
+ 597,,
592
+ 598,,
593
+ 599,,
594
+ 600,14675.682555585608,-1119.4438609578956
595
+ 601,14675.627733170206,-1119.4167800720716
596
+ 602,13789.330318344715,-3087.2978575100988
597
+ 603,13961.466253214452,-3310.55557923595
598
+ 604,16463.818254374553,-3350.395987899934
599
+ 605,16463.846252607742,-3350.4219654078224
600
+ 606,16773.960912645074,-3660.497340851791
601
+ 607,16900.29365488205,-0.006001430661854101
602
+ 608,16900.288881059485,-0.010318924923922168
603
+ 609,16900.26668491404,0.0039033367174852174
604
+ 610,15962.579955756482,-111.6835652931386
605
+ 611,15625.29743117682,-0.004874373618804384
606
+ 612,16183.31063283327,0.002157807939511258
607
+ 613,16183.30890075225,0.0005512696352525381
608
+ 614,,
609
+ 615,15923.12089008136,-0.011039210032322444
610
+ 616,15923.102932377198,0.009140159920207225
611
+ 617,15923.120537581592,-0.012272862981262733
612
+ 618,23672.295943329613,4384.73221304809
613
+ 619,15713.511077244675,1947.7188983412707
614
+ 620,15391.8153272467,160.7059266110591
615
+ 621,,
616
+ 622,15303.305235944432,840.8103346667885
617
+ 623,21511.502299701748,5368.787918086244
618
+ 624,17977.69448093405,2851.242514417736
619
+ 625,17992.34861123504,1433.9614548803183
620
+ 626,,
621
+ 627,19573.765580025607,3118.170844803284
622
+ 628,22478.20308955241,3116.835907099565
623
+ 629,24629.44479937559,1754.5073381798502
624
+ 630,24937.374333025484,2831.5884538685386
625
+ 631,24937.38422212145,3174.787912759046
626
+ 632,24438.105554554328,2362.5806950453916
627
+ 633,24438.097421858063,2362.5762403776207
628
+ 634,23283.32814953799,3411.4039991761965
629
+ 635,23191.57564259536,3041.0539393687977
630
+ 636,23380.42679790649,2463.6204469490403
631
+ 637,23984.923035399537,1802.0100421129137
632
+ 638,23984.9243288655,1745.5217523775027
633
+ 639,22456.340152749337,2127.1788016070677
634
+ 640,,
635
+ 641,21326.636503634883,3033.2587296357233
636
+ 642,23363.9504516957,3639.2893438525607
637
+ 643,24111.31960707974,3544.4710114259433
638
+ 644,24111.33005870598,3544.4710113985784
639
+ 645,22080.38824747205,3633.090007529554
640
+ 646,22080.39346391874,3633.080371492186
641
+ 647,23886.99024539384,7123.588830241344
642
+ 648,23886.98770015081,3144.998414232148
643
+ 649,22810.36850224277,752.2716294267993
644
+ 650,23168.642223444607,1889.8045234524834
645
+ 651,25814.139726335387,2370.6722511176013
646
+ 652,24654.218508280865,2554.4880869448207
647
+ 653,23312.786012795936,524.6336980329506
648
+ 654,23415.26265140208,866.1116750394503
649
+ 655,28775.525210212305,3412.6140367113803
650
+ 656,23213.854721936103,1196.6210943376573
651
+ 657,23213.843362008163,1196.6204405509561
652
+ 658,23213.854301573963,1196.6301296813836
653
+ 659,24010.02054410911,1352.9507497379818
654
+ 660,26285.93154041589,3739.360143270871
655
+ 661,27185.41341978846,2774.1517269297037
656
+ 662,27326.058475790967,2633.5063881944734
657
+ 663,27326.0669227864,2633.4863351109925
658
+ 664,27286.681426106265,2461.4816960887765
659
+ 665,26599.055292107376,2641.6269286413844
660
+ 666,21143.60227673928,2642.5188733841096
661
+ 667,,
662
+ 668,21101.14993469079,234.6071865016129
663
+ 669,21410.758087893497,330.602274252451
664
+ 670,21813.62384108144,0.008007170075870818
665
+ 671,21813.62155469824,0.007164238104451215
666
+ 672,21514.820193993968,262.6972151831651
667
+ 673,21336.104005739344,36.67904699214705
668
+ 674,21336.114385255085,36.654199221899034
669
+ 675,21723.92280186489,162.2309291584097
670
+ 676,22419.54569903719,287.07419440526064
671
+ 677,22919.881300252357,58.93701262991817
672
+ 678,22861.259216989663,32.74339793971012
673
+ 679,22840.967329757244,221.50422477519533
674
+ 680,22577.692355224397,238.97585404353595
675
+ 681,22727.555666103064,170.79734218806698
676
+ 682,,
677
+ 683,,
678
+ 684,32693.53647128776,158.5140223147282
679
+ 685,34357.44428264481,160.93082500233868
680
+ 686,34357.45096548845,160.9205182219448
681
+ 687,34357.445828499986,160.91904205920582
682
+ 688,33008.05472108843,156.29709360305424
683
+ 689,32940.16673842416,162.77610896686383
684
+ 690,,
685
+ 691,15769.151964714876,617.8259284318028
686
+ 692,14492.794853603282,669.390524031427
687
+ 693,,
688
+ 694,,
689
+ 695,16294.27781332052,617.4003231474617
690
+ 696,17900.139324850174,682.536807608325
691
+ 697,16064.385228050458,1192.8104012971999
692
+ 698,16061.78049617516,1179.8474446915716
693
+ 699,16061.788416188789,1179.8472668561226
694
+ 700,,
695
+ 701,28844.01660939666,327.28649373790904
696
+ 702,26514.3983379666,1652.156288522223
697
+ 703,27728.189291001785,1789.4923308863908
698
+ 704,,
699
+ 705,32999.590104107905,577.5291232223244
700
+ 706,32999.585408165745,688.6933207768088
701
+ 707,34327.74423225177,183.87451672320458
702
+ 708,34535.79466773092,423.65432459660224
703
+ 709,34555.779644342074,403.69087155152374
704
+ 710,34788.340930317834,370.46659335689765
705
+ 711,34788.3486366202,398.88497188990004
706
+ 712,38046.450085333,453.62807407436776
707
+ 713,38046.45425283754,453.6184328763338
708
+ 714,32886.787743985544,224.96779244273057
709
+ 715,26301.62097611508,-932.823354537828
710
+ 716,27495.177426172377,1476.1670862505598
711
+ 717,18743.54306725823,2001.3218020681197
712
+ 718,21027.16338817981,3828.6687986873985
713
+ 719,,
714
+ 720,28893.627087076984,22.90103637190623
715
+ 721,18763.154618398417,-564.1207224411919
716
+ 722,21071.40492427565,-611.5681707265139
717
+ 723,28654.42017777269,216.87162708939286
718
+ 724,18876.393067415014,0.004665706721425522
719
+ 725,18538.16384174638,-149.67771950389943
720
+ 726,12749.457675844458,4639.7753453102105
721
+ 727,12720.526466791369,3975.057370929233
722
+ 728,,
723
+ 729,11282.803656569513,4531.394283168505
724
+ 730,11071.476754831849,4877.791654782615
725
+ 731,11071.48046221688,5317.652853723708
726
+ 732,11837.062545935947,5165.589565027418
727
+ 733,11849.2201598544,5694.52085637118
728
+ 734,,
729
+ 735,,
730
+ 736,,
731
+ 737,,
732
+ 738,,
733
+ 739,,
734
+ 740,30054.989545027143,328.87993446994005
735
+ 741,33537.241787256135,328.8836601306175
736
+ 742,35104.2520112584,328.8824206789868
737
+ 743,36019.07996795677,339.81079104360833
738
+ 744,32539.36040332122,327.0050268941741
739
+ 745,32502.995870338334,330.91781150531824
740
+ 746,,
741
+ 747,28773.393940364786,752.0769051035531
742
+ 748,28090.39922189634,1435.0806938301357
743
+ 749,27737.64082225159,1728.9312235679681
744
+ 750,27737.635505199018,1728.941067151165
745
+ 751,27737.64099461137,1728.9323744770663
746
+ 752,26408.623526460444,1574.6199485849538
747
+ 753,21799.34671482771,2.635578895879007
748
+ 754,21799.342674870757,0.9654027008618868
749
+ 755,22466.36404519812,-1146.1972476089504
750
+ 756,,
751
+ 757,,
752
+ 758,,
753
+ 759,,
754
+ 760,31460.42245253256,2786.206802089906
755
+ 761,31460.44388484797,2786.192297908601
756
+ 762,31469.677744643577,2384.7411060319246
757
+ 763,31469.68469807928,2384.7300305171048
758
+ 764,31469.687515052392,2384.7049020634804
759
+ 765,30910.82247784337,2864.8422451489932
760
+ 766,30091.91838117288,2819.216429648717
761
+ 767,30091.89290683521,2819.2475640188823
762
+ 768,30091.91670167104,2851.37423890888
763
+ 769,32374.88710916189,1997.2855901566836
764
+ 770,32422.38011941286,1967.4063812050226
765
+ 771,32422.38440164623,1967.4195432939669
766
+ 772,32422.3859761361,1967.4101088449388
767
+ 773,32422.389346612064,1967.4127664148182
768
+ 774,31548.040115878037,1615.8267902466396
769
+ 775,29421.23433261096,2823.928094021412
770
+ 776,29031.0032036544,3214.1624414912367
771
+ 777,29031.00049600579,3214.151807752056
772
+ 778,29031.0088229593,3214.155231272998
773
+ 779,29403.590036669037,2841.5691790055644
774
+ 780,29403.57481710709,2841.6037051917083
775
+ 781,29399.550810095778,3522.783278767409
776
+ 782,29399.532703837755,3522.814994251228
777
+ 783,28973.87492695764,3948.458712221971
778
+ 784,16520.400065378606,-0.0077499576182162855
779
+ 785,16520.396973671333,0.007031921104498906
780
+ 786,16900.671897098608,0.0051176484739698935
781
+ 787,17715.5015270848,-0.008342473065567901
782
+ 788,17715.4954945141,0.005377528166718548
783
+ 789,16731.997609590177,0.009786973718291847
784
+ 790,16441.565081267723,0.008626120477856603
785
+ 791,16441.58568756197,-0.006453407142544165
786
+ 792,16900.671897098608,0.0051176484739698935
787
+ 793,17316.61560976369,-0.0006396888784365728
788
+ 794,17492.90504908059,0.005038451956352219
789
+ 795,,
790
+ 796,17777.255556599048,163.29216192161766
791
+ 797,17777.28014141738,163.27399223956672
792
+ 798,17778.55539352789,162.00397357936163
793
+ 799,,
794
+ 800,18320.30632797864,586.9127209154794
795
+ 801,17916.845902380865,272.0736732081423
796
+ 802,17916.858210853796,272.0608083320294
797
+ 803,20058.470405403845,1455.1663730389264
798
+ 804,18625.441710976276,455.03501006712395
799
+ 805,18625.446504246214,363.4473955865069
800
+ 806,18711.058290429974,320.90226693374643
801
+ 807,18711.06606747421,320.91250231360027
802
+ 808,19881.75790215763,282.04799446746983
803
+ 809,19802.76131986697,21.594200228209957
804
+ 810,19802.76589189913,21.584067418181803
805
+ 811,19760.554454835183,262.9474881901042
806
+ 812,,
807
+ 813,,
808
+ 814,,
809
+ 815,,
810
+ 816,,
811
+ 817,,
812
+ 818,,
813
+ 819,,
814
+ 820,,
815
+ 821,30518.4498963491,3787.082934584483
816
+ 822,28738.797031185844,1895.7511444225747
817
+ 823,28738.80014092312,1895.7508201500532
818
+ 824,32562.378259020395,2084.9478671771467
819
+ 825,32562.37891075104,2084.9579022799153
820
+ 826,32269.92465342423,1515.6094939262366
821
+ 827,32086.059736136045,1713.732572781777
822
+ 828,32018.32890982471,1781.4561319270942
823
+ 829,,
824
+ 830,9707.872859211206,753.247547706831
825
+ 831,9105.697576020228,783.7675870635358
826
+ 832,9684.49322768278,751.3047518881158
827
+ 833,9684.5108223423,751.278155818969
828
+ 834,,
829
+ 835,9040.17035747212,100.43041286711195
830
+ 836,9040.148870765654,100.44308927464044
831
+ 837,,
832
+ 838,9040.143870369442,-75.37494491966936
833
+ 839,9040.135251231704,-133.71477810366923
834
+ 840,8714.475702828695,-778.8518538923145
835
+ 841,9274.306737834122,-732.1279104687601
836
+ 842,10643.68871870058,-720.8925436479749
837
+ 843,12226.328735762843,-712.2303959982528
838
+ 844,12226.328749159196,-712.2317754673677
839
+ 845,12226.326417052313,-712.220524266917
840
+ 846,12226.326421071564,-712.2225407449969
841
+ 847,11658.714196446812,-442.59883798498413
842
+ 848,11658.690555408795,-442.57735366513043
843
+ 849,10461.296134540386,3704.1979316197376
844
+ 850,10098.144622784075,219.2663701864094
845
+ 851,10098.142715521117,132.507453322929
846
+ 852,11552.134705051978,-1321.4875268814358
847
+ 853,11552.15064167424,-98.77555660871076
848
+ 854,11552.140828484298,20242.07358211781
849
+ 855,11552.139412526894,20242.06484544173
850
+ 856,11484.725785237211,2676.7988594628005
851
+ 857,10114.295963439468,2530.240539091632
852
+ 858,11269.26469688094,2308.806762752223
853
+ 859,11327.498743049617,2301.1876081356495
854
+ 860,11327.509069233794,2301.1840516414777
855
+ 861,11327.506754327394,2301.177483481377
856
+ 862,10810.228013751524,2327.8076594473514
857
+ 863,10810.228013751504,2327.807659423479
858
+ 864,10810.209178321287,2324.253349234952
859
+ 865,10810.208100127204,2324.235972983088
860
+ 866,10401.228408232477,2241.570194982991
861
+ 867,10401.206011821969,2241.585034662541
862
+ 868,10401.198546342448,2241.5849434139127
863
+ 869,10401.19006164063,2211.7452784873185
864
+ 870,9080.052958925846,2185.476749057445
865
+ 871,,
866
+ 872,18751.122804250717,290.25642779992995
867
+ 873,18751.118581723236,290.26014355896405
868
+ 874,18751.1344211364,290.2430019180101
869
+ 875,18751.12887856136,290.2553989315529
870
+ 876,19176.01401339642,824.0440222067991
871
+ 877,19176.018477637976,1209.9325457357554
872
+ 878,18809.795870039616,222.9581824205925
873
+ 879,20958.00541621325,1995.1467397228298
874
+ 880,19067.018739513707,1018.6047115091023
875
+ 881,20288.32658370746,380.64988100561095
876
+ 882,20467.21013262188,201.7691815730468
877
+ 883,20467.21942288215,201.7685589492503
878
+ 884,,
879
+ 885,20466.375664975585,189.9368382344146
880
+ 886,,
881
+ 887,20407.2179188599,193.82463722910688
882
+ 888,20354.098104295757,246.93366949273695
883
+ 889,20354.084760357484,246.94902814408124
884
+ 890,20354.09145326571,369.21458634624287
885
+ 891,20265.356583150635,709.0055932539653
886
+ 892,20265.364397808386,815.7458342119862
887
+ 893,21032.75725924471,1689.5296931609664
888
+ 894,20785.856602096766,1400.4784324758039
889
+ 895,20587.155294976616,880.470501202879
890
+ 896,21131.7739002881,277.6968680368118
891
+ 897,21137.020862856403,339.6394269536613
892
+ 898,21238.902055845592,1145.8055270198383
893
+ 899,19344.258736121486,127.06697246286421
894
+ 900,16724.56534748651,513.4943769829733
895
+ 901,9093.553920386974,1162.5723010401616
example_data_description.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## SecA HDX-MS protein flexibility data
2
+
3
+
4
+ This is an example dataset of HDX-MS derived protein flexibility, expressed as Linderström-Lang Gibbs free energies (ΔG/ΔΔG).
5
+
6
+ The ΔG values obtained using PyHDX ([DOI: 10.1021/acs.analchem.1c02155](https://pubs.acs.org/doi/10.1021/acs.analchem.1c02155))
7
+
8
+ There are three protein states, SecA monomer, SecA dimer and SecA with C-tail deletion, each state as apo (ΔG) and ADP-bound (ΔΔG)
9
+
10
+
11
+ More details on SecA dynamics can be found here:
12
+ [A nexus of intrinsic dynamics underlies translocase priming](https://www.cell.com/structure/fulltext/S0969-2126(21)00113-1)
13
+
interactive.py ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # %%
2
+ from collections import defaultdict
3
+
4
+ import altair as alt
5
+ import matplotlib.pyplot as plt
6
+ import pandas as pd
7
+ from cmap import Colormap
8
+ import polars as pl
9
+
10
+ #%%
11
+
12
+ df = pl.read_csv("example_data_bk.csv")
13
+ df.columns
14
+
15
+ df_crop = df[:, :3]
16
+ df_crop
17
+
18
+ df_crop.write_csv("example_data.csv")
19
+ #%%
20
+
21
+ # %%
22
+ kwargs = {"comment": "#", "header": [0, 1], "index_col": 0}
23
+ df = pd.read_csv("fit_result_batch.csv", **kwargs)
24
+ # %%
25
+ df
26
+ # %%
27
+
28
+
29
+ df_wt = df["SecB WT apo"].reset_index()
30
+ df_dimer = df["SecB his dimer apo"].reset_index()
31
+
32
+ AA_categories = {
33
+ "pos": ["R", "H", "K"],
34
+ "neg": ["D", "E"],
35
+ "aromatic": ["F", "W", "Y"],
36
+ "polar": ["S", "T", "N", "Q"],
37
+ "nonpolar": ["A", "V", "I", "L", "M"],
38
+ "other": ["G", "C", "P"],
39
+ }
40
+ cat_list = list(AA_categories)
41
+ AA_lut = {aa: category for category in AA_categories for aa in AA_categories[category]}
42
+ AA_lut
43
+ aa_cat_numbers = [cat_list.index(AA_lut[aa]) for aa in df_wt["sequence"]]
44
+ df_wt["aa_cat"] = aa_cat_numbers
45
+
46
+ # %%
47
+ cmap = Colormap("colorbrewer:Accent_6")
48
+ sol = defaultdict(list)
49
+ colors = cmap(df_wt["aa_cat"])
50
+
51
+ nums = range(6)
52
+ colors = cmap(nums)
53
+
54
+ for n, c in zip(nums, colors):
55
+ print(n, c)
56
+ # %%
57
+ len(cmap.color_stops)
58
+
59
+ colors = cmap.to_altair(N=cmap.num_colors)
60
+ domain = range(6)
61
+ altair_scale = alt.Scale(domain=domain, range=colors, clamp=True)
62
+ # %%
63
+ alt.Chart(df_wt).mark_point().encode(
64
+ x="r_number",
65
+ y="aa_cat",
66
+ color=alt.Color("aa_cat:N", scale=altair_scale),
67
+ )
68
+
69
+ # %%
70
+ import pandas as pd
71
+
72
+ df = pd.DataFrame({"a": [1, 2, 3, 4], "b": [7, 6, 5, 4], "c": ["a", "b", "b", "c"]})
73
+
74
+ chart = alt.Chart(df).mark_point().encode(alt.X("a"), alt.Y("b"), alt.Color("c:N"))
75
+ chart
76
+ # %%
77
+
78
+
79
+ # %%
80
+
81
+
82
+ ddG = df_wt["deltaG"] - df_dimer["deltaG"]
83
+ ddG
84
+
85
+
86
+ # %%
87
+
88
+ fig, ax = plt.subplots()
89
+ ax.scatter(df_wt["r_number"], df_wt["deltaG"])
90
+
91
+ # %%
92
+ fig, ax = plt.subplots()
93
+ ax.scatter(df_wt["r_number"], ddG)
94
+
95
+ # %%
96
+ df_wt.columns
97
+ # %%
98
+
99
+ output = pd.DataFrame(
100
+ {
101
+ "r_number": df_wt["r_number"],
102
+ "SecB tetramer ΔG": df_wt["deltaG"],
103
+ "dimer ΔΔG": ddG,
104
+ "aa_category": df_wt["aa_cat"],
105
+ }
106
+ )
107
+ output = output.set_index("r_number")
108
+
109
+ output
110
+ # %%
111
+ import numpy as np
112
+
113
+ N = 150
114
+ fuzzy_sin = 0.5 * (1 + np.sin(np.arange(N) / 10.0)) + np.random.normal(
115
+ loc=0, scale=0.1, size=N
116
+ )
117
+ df = pd.DataFrame({"fuzzy_sin": fuzzy_sin})
118
+ df
119
+
120
+
121
+
122
+ # add series to output dataframe a a column
123
+
124
+ output["fuzzy_sin"] = series
125
+ output
126
+ # %%
127
+
128
+ output.to_csv("SecB_data.csv")
129
+ # %%
130
+
131
+ dir(cmap)
132
+ cmap.category
133
+
134
+ # %%
135
+
136
+ tol_cmap = Colormap("tol:rainbow_discrete_7")
137
+ tol_cmap.category
138
+ tol_cmap.num_colors
139
+ tol_cmap.interpolation
140
+
141
+ # %%
142
+
143
+ tol_cmap = Colormap("vispy:hsl")
144
+ tol_cmap.category
145
+ tol_cmap.num_colors
146
+ tol_cmap.interpolation
147
+
148
+
149
+ # %%
150
+ tol_cmap = Colormap("yorick:stern")
151
+ tol_cmap.category
152
+ tol_cmap.num_colors
153
+ tol_cmap.interpolation
154
+ # %%
155
+ tol_cmap = Colormap("tol:rainbow_whbr")
156
+ tol_cmap.category
157
+ tol_cmap.num_colors
158
+ tol_cmap.interpolation
159
+ # %%
160
+ tol_cmap = Colormap("glasbey:glasbey")
161
+ tol_cmap.category
162
+ tol_cmap.num_colors
163
+ # tol_cmap.interpolation
164
+
165
+
166
+ # %%
make_link.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import base64
4
+ from io import BytesIO
5
+ from typing import TYPE_CHECKING
6
+ from urllib.parse import urlencode
7
+
8
+ import pandas as pd
9
+ import zstandard as zstd
10
+
11
+ if TYPE_CHECKING:
12
+ from viewer import AxisProperties, ColorTransform
13
+
14
+ # %%
15
+
16
+ COMPRESSOR = zstd.ZstdCompressor(level=22)
17
+ DECOMPRESSOR = zstd.ZstdDecompressor()
18
+
19
+
20
+ def encode_url(
21
+ title: str,
22
+ molecule_id: str,
23
+ colors: ColorTransform,
24
+ axis_properties: AxisProperties,
25
+ data: pd.DataFrame,
26
+ description: str = "",
27
+ ):
28
+ encode_dict = dict(title=title, molecule_id=molecule_id)
29
+ encode_dict.update({**colors.model_dump(), **axis_properties.model_dump()})
30
+
31
+ csv_str = data.to_csv(float_format="%.4f", index=False)
32
+ compressed = COMPRESSOR.compress(csv_str.encode())
33
+ base64_text = base64.b64encode(compressed).decode("utf8")
34
+ encode_dict["data"] = base64_text
35
+ if description:
36
+ encode_dict["description"] = description
37
+
38
+ return urlencode(encode_dict)
39
+
40
+
41
+ def decode_data(base64_text) -> pd.DataFrame:
42
+ decoded_bytes = base64.b64decode(base64_text)
43
+ decompressed = DECOMPRESSOR.decompress(decoded_bytes)
44
+
45
+ bio = BytesIO(decompressed)
46
+ data = pd.read_csv(bio)
47
+ bio.close()
48
+
49
+ return data
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ solara
2
+ ipymolstar
3
+ pandas
4
+ altair
5
+ anywidget
6
+ cmap
7
+ pydantic
8
+ zstandard
style.css ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .vega-embed {
2
+ overflow: visible;
3
+ width: 100% !important;
4
+ }
5
+
6
+ /* Hide the ipymolstar drag and drop overlay */
7
+ .msp-drag-drop-overlay {
8
+ display: none !important;
9
+ }
10
+
11
+ /* remove solara footer */
12
+ .v-application--wrap > div:nth-child(2) > div:nth-child(2){
13
+ display: none !important;
14
+ }
viewer.py ADDED
@@ -0,0 +1,388 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import base64
4
+ import gzip
5
+ import json
6
+ from dataclasses import dataclass, fields
7
+ from io import BytesIO
8
+ from pathlib import Path
9
+ from urllib.parse import parse_qsl
10
+
11
+ import altair as alt
12
+ import ipywidgets as widgets
13
+ import numpy as np
14
+ import pandas as pd
15
+ import solara
16
+ import solara.lab
17
+ from cmap import Colormap
18
+ from ipymolstar.widget import PDBeMolstar
19
+ from pydantic import BaseModel
20
+
21
+ from make_link import decode_data
22
+
23
+ base_v = np.vectorize(np.base_repr)
24
+ PAD_SIZE = 0.05 # when not autoscale Y size of padding used
25
+
26
+
27
+ def norm(x, vmin, vmax):
28
+ return (x - vmin) / (vmax - vmin)
29
+
30
+
31
+ class ColorTransform(BaseModel):
32
+ name: str = "tol:rainbow_PuRd"
33
+ norm_type: str = "linear"
34
+ vmin: float = 0.0
35
+ vmax: float = 1.0
36
+ missing_data_color: str = "#8c8c8c"
37
+ highlight_color: str = "#e933f8"
38
+
39
+ def molstar_colors(self, data: pd.DataFrame) -> dict:
40
+ if self.norm_type == "categorical":
41
+ values = data["value"]
42
+ else:
43
+ values = norm(data["value"], vmin=self.vmin, vmax=self.vmax)
44
+
45
+ rgba_array = self.cmap(values, bytes=True)
46
+ ints = rgba_array.astype(np.uint8).view(dtype=np.uint32).byteswap()
47
+ padded = np.char.rjust(base_v(ints // 2**8, 16), 6, "0")
48
+ hex_colors = np.char.add("#", padded).squeeze()
49
+
50
+ color_data = {
51
+ "data": [
52
+ {"residue_number": resi, "color": hcolor.lower()}
53
+ for resi, hcolor in zip(data["residue_number"], hex_colors)
54
+ ],
55
+ "nonSelectedColor": self.missing_data_color,
56
+ }
57
+
58
+ return color_data
59
+
60
+ @property
61
+ def cmap(self) -> Colormap:
62
+ return Colormap(self.name, bad=self.missing_data_color)
63
+
64
+ @property
65
+ def altair_scale(self) -> alt.Scale:
66
+ if self.norm_type == "categorical":
67
+ colors = self.cmap.to_altair(N=self.cmap.num_colors)
68
+ domain = range(self.cmap.num_colors)
69
+ else:
70
+ colors = self.cmap.to_altair()
71
+ domain = np.linspace(self.vmin, self.vmax, 256, endpoint=True)
72
+
73
+ scale = alt.Scale(domain=list(domain), range=colors, clamp=True)
74
+ return scale
75
+
76
+
77
+ class AxisProperties(BaseModel):
78
+ label: str = "x"
79
+ unit: str = "au"
80
+ autoscale_y: bool = True
81
+
82
+ @property
83
+ def title(self) -> str:
84
+ return f"{self.label} ({self.unit})"
85
+
86
+
87
+ def make_chart(
88
+ data: pd.DataFrame, colors: ColorTransform, axis_properties: AxisProperties
89
+ ) -> alt.LayerChart:
90
+ xmin, xmax = data["residue_number"].min(), data["residue_number"].max()
91
+ xpad = (xmax - xmin) * 0.05
92
+ xscale = alt.Scale(domain=(xmin - xpad, xmax + xpad))
93
+
94
+ if axis_properties.autoscale_y:
95
+ y_scale = alt.Scale()
96
+ elif colors.norm_type == "categorical":
97
+ ypad = colors.cmap.num_colors * 0.05
98
+ y_scale = alt.Scale(domain=(0 - ypad, colors.cmap.num_colors - 1 + ypad))
99
+ else:
100
+ ypad = (colors.vmax - colors.vmin) * 0.05
101
+ y_scale = alt.Scale(domain=(colors.vmin - ypad, colors.vmax + ypad))
102
+
103
+ zoom_x = alt.selection_interval(
104
+ bind="scales",
105
+ encodings=["x"],
106
+ zoom="wheel![!event.shiftKey]",
107
+ )
108
+
109
+ scatter = (
110
+ alt.Chart(data)
111
+ .mark_circle(interpolate="basis", size=200)
112
+ .encode(
113
+ x=alt.X("residue_number:Q", title="Residue Number", scale=xscale),
114
+ y=alt.Y(
115
+ "value:Q",
116
+ title=axis_properties.title,
117
+ scale=y_scale,
118
+ ),
119
+ color=alt.Color(
120
+ f"value:{'O' if colors.norm_type == 'categorical' else 'Q'}",
121
+ scale=colors.altair_scale,
122
+ title=axis_properties.title,
123
+ ),
124
+ )
125
+ .add_params(zoom_x)
126
+ )
127
+
128
+ # Create a selection that chooses the nearest point & selects based on x-value
129
+ nearest = alt.selection_point(
130
+ name="point",
131
+ nearest=True,
132
+ on="pointerover",
133
+ fields=["residue_number"],
134
+ empty=False,
135
+ clear="mouseout",
136
+ )
137
+
138
+ select_residue = (
139
+ alt.Chart(data)
140
+ .mark_point()
141
+ .encode(
142
+ x="residue_number:Q",
143
+ opacity=alt.value(0),
144
+ )
145
+ .add_params(nearest)
146
+ )
147
+
148
+ # Draw a rule at the location of the selection
149
+ rule = (
150
+ alt.Chart(data)
151
+ .mark_rule(color=colors.highlight_color, size=2)
152
+ .encode(
153
+ x="residue_number:Q",
154
+ )
155
+ .transform_filter(nearest)
156
+ )
157
+
158
+ # vline = (
159
+ # alt.Chart(pd.DataFrame({"x": [0]}))
160
+ # .mark_rule(color=colors.highlight_color, size=2)
161
+ # .encode(x="x:Q")
162
+ # )
163
+
164
+ line_position = alt.param(name="line_position", value=0.0)
165
+ line_opacity = alt.param(name="line_opacity", value=1)
166
+ df_line = pd.DataFrame({"x": [1.0]})
167
+
168
+ # Create vertical rule with parameter
169
+ vline = (
170
+ alt.Chart(df_line)
171
+ .mark_rule(color=colors.highlight_color, opacity=line_opacity, size=2)
172
+ .encode(x=alt.X("p", type="quantitative"))
173
+ .transform_calculate(p=alt.datum.x * line_position)
174
+ .add_params(line_position, line_opacity)
175
+ )
176
+
177
+ # Put the five layers into a chart and bind the data
178
+ chart = (
179
+ alt.layer(scatter, vline, select_residue, rule).properties(
180
+ width="container",
181
+ height=480, # autosize height?
182
+ )
183
+ # .configure(autosize="fit")
184
+ )
185
+
186
+ return chart
187
+
188
+
189
+ @solara.component
190
+ def ScatterChart(
191
+ data: pd.DataFrame,
192
+ colors: ColorTransform,
193
+ axis_properties: AxisProperties,
194
+ on_selections,
195
+ line_value,
196
+ ):
197
+ def mem_chart():
198
+ chart = make_chart(data, colors, axis_properties)
199
+ return chart
200
+
201
+ chart = solara.use_memo(mem_chart, dependencies=[data, colors, axis_properties])
202
+
203
+ if line_value is not None:
204
+ params = {"line_position": line_value, "line_opacity": 1}
205
+ else:
206
+ params = {"line_position": 0.0, "line_opacity": 0}
207
+ dark_effective = solara.lab.use_dark_effective()
208
+ if dark_effective:
209
+ options = {"actions": False, "theme": "dark"}
210
+ else:
211
+ options = {"actions": False}
212
+
213
+ view = alt.JupyterChart.element( # type: ignore
214
+ chart=chart,
215
+ embed_options=options,
216
+ _params=params,
217
+ )
218
+
219
+ def bind():
220
+ real = solara.get_widget(view)
221
+ real.selections.observe(on_selections, "point") # type: ignore
222
+
223
+ solara.use_effect(bind, [data, colors])
224
+
225
+
226
+ @solara.component
227
+ def ProteinView(
228
+ title: str,
229
+ molecule_id: str,
230
+ data: pd.DataFrame,
231
+ colors: ColorTransform,
232
+ axis_properties: AxisProperties,
233
+ dark_effective: bool,
234
+ description: str = "",
235
+ ):
236
+ about_dialog = solara.use_reactive(False)
237
+ fullscreen = solara.use_reactive(False)
238
+
239
+ # residue number to highlight in altair chart
240
+ line_number = solara.use_reactive(None)
241
+
242
+ # residue number to highlight in protein view
243
+ highlight_number = solara.use_reactive(None)
244
+
245
+ if data.empty:
246
+ color_data = {}
247
+ else:
248
+ color_data = colors.molstar_colors(data)
249
+ tooltips = {
250
+ "data": [
251
+ {
252
+ "residue_number": resi,
253
+ "tooltip": f"{axis_properties.label}: {value:.2g} {axis_properties.unit}"
254
+ if not np.isnan(value)
255
+ else "No data",
256
+ }
257
+ for resi, value in zip(data["residue_number"], data["value"])
258
+ ]
259
+ }
260
+
261
+ def on_molstar_mouseover(value):
262
+ r = value.get("residueNumber", None)
263
+ line_number.set(r)
264
+
265
+ def on_molstar_mouseout(value):
266
+ on_molstar_mouseover({})
267
+
268
+ def on_chart_selection(event):
269
+ try:
270
+ r = event["new"].value[0]["residue_number"]
271
+ highlight_number.set(r)
272
+ except (IndexError, KeyError):
273
+ highlight_number.set(None)
274
+
275
+ with solara.AppBar():
276
+ solara.AppBarTitle(title)
277
+ with solara.Tooltip("Fullscreen"):
278
+ solara.Button(
279
+ icon_name="mdi-fullscreen",
280
+ icon=True,
281
+ on_click=lambda: fullscreen.set(not fullscreen.value),
282
+ )
283
+ if description:
284
+ with solara.Tooltip("About"):
285
+ solara.Button(
286
+ icon_name="mdi-information-outline",
287
+ icon=True,
288
+ on_click=lambda: about_dialog.set(True),
289
+ )
290
+ solara.lab.ThemeToggle()
291
+
292
+ with solara.v.Dialog(
293
+ v_model=about_dialog.value, on_v_model=lambda _ignore: about_dialog.set(False)
294
+ ):
295
+ with solara.Card("About", margin=0):
296
+ solara.Markdown(description)
297
+
298
+ with solara.ColumnsResponsive([4, 8]):
299
+ with solara.Card(style={"height": "550px"}):
300
+ PDBeMolstar.element( # type: ignore
301
+ theme="dark" if dark_effective else "light",
302
+ molecule_id=molecule_id.lower(),
303
+ color_data=color_data,
304
+ hide_water=True,
305
+ tooltips=tooltips,
306
+ height="525px",
307
+ highlight={"data": [{"residue_number": int(highlight_number.value)}]}
308
+ if highlight_number.value
309
+ else None,
310
+ highlight_color=colors.highlight_color,
311
+ on_mouseover_event=on_molstar_mouseover,
312
+ on_mouseout_event=on_molstar_mouseout,
313
+ hide_controls_icon=True,
314
+ hide_expand_icon=True,
315
+ hide_settings_icon=True,
316
+ expanded=fullscreen.value,
317
+ ).key(f"molstar-{dark_effective}")
318
+ if not fullscreen.value:
319
+ with solara.Card(style={"height": "550px"}):
320
+ if data.empty:
321
+ solara.Text("No data")
322
+ else:
323
+ ScatterChart(
324
+ data,
325
+ colors,
326
+ axis_properties,
327
+ on_chart_selection,
328
+ line_number.value,
329
+ )
330
+
331
+
332
+ @solara.component
333
+ def RoutedView():
334
+ route = solara.use_router()
335
+ dark_effective = solara.lab.use_dark_effective()
336
+
337
+ try:
338
+ query_dict = {k: v for k, v in parse_qsl(route.search)}
339
+ colors = ColorTransform(**query_dict) # type: ignore
340
+ axis_properties = AxisProperties(**query_dict) # type: ignore
341
+ data = decode_data(query_dict["data"])
342
+ ProteinView(
343
+ query_dict["title"],
344
+ molecule_id=query_dict["molecule_id"],
345
+ data=data,
346
+ colors=colors,
347
+ axis_properties=axis_properties,
348
+ dark_effective=dark_effective,
349
+ description=query_dict.get("description", ""),
350
+ )
351
+ except KeyError as err:
352
+ solara.Warning(f"Error: {err}")
353
+
354
+
355
+ @solara.component
356
+ def Page():
357
+ dark_effective = solara.lab.use_dark_effective()
358
+ dark_previous = solara.use_previous(dark_effective)
359
+
360
+ if dark_previous != dark_effective:
361
+ if dark_effective:
362
+ alt.themes.enable("dark")
363
+ else:
364
+ alt.themes.enable("default")
365
+
366
+ solara.Style(
367
+ """
368
+ .vega-embed {
369
+ overflow: visible;
370
+ width: 100% !important;
371
+ }"""
372
+ )
373
+
374
+ settings = json.loads(Path("settings.json").read_text())
375
+
376
+ colors = ColorTransform(**settings)
377
+ axis_properties = AxisProperties(**settings)
378
+
379
+ data = pd.read_csv("color_data.csv")
380
+
381
+ ProteinView(
382
+ settings["title"],
383
+ molecule_id=settings["molecule_id"],
384
+ data=data,
385
+ colors=colors,
386
+ axis_properties=axis_properties,
387
+ dark_effective=dark_effective,
388
+ )