PyDIET 0.9.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. pydiet/__init__.py +12 -0
  2. pydiet/api_client/__init__.py +6 -0
  3. pydiet/api_client/client.py +57 -0
  4. pydiet/cmd/__init__.py +9 -0
  5. pydiet/cmd/start.py +107 -0
  6. pydiet/data/data_config.toml +242 -0
  7. pydiet/data/description.txt +1 -0
  8. pydiet/data/instruments/description.txt +1 -0
  9. pydiet/data/instruments/megacam/default +0 -0
  10. pydiet/data/instruments/megacam/description.txt +1 -0
  11. pydiet/data/instruments/megacam/detector/description.txt +1 -0
  12. pydiet/data/instruments/megacam/detector/qe/MegaCam_QE.average.fits +0 -0
  13. pydiet/data/instruments/megacam/detector/qe/description.txt +2 -0
  14. pydiet/data/instruments/megacam/filters/CaHK.MP9303.fits +0 -0
  15. pydiet/data/instruments/megacam/filters/Ha.MP9603.fits +0 -0
  16. pydiet/data/instruments/megacam/filters/HaOFF.MP9604.fits +0 -0
  17. pydiet/data/instruments/megacam/filters/M4112.MP9403.fits +0 -0
  18. pydiet/data/instruments/megacam/filters/M4376.MP9404.fits +0 -0
  19. pydiet/data/instruments/megacam/filters/OIII.MP9501.fits +0 -0
  20. pydiet/data/instruments/megacam/filters/OIIIOFF.MP9502.fits +0 -0
  21. pydiet/data/instruments/megacam/filters/description.txt +1 -0
  22. pydiet/data/instruments/megacam/filters/g.MP9402.fits +0 -0
  23. pydiet/data/instruments/megacam/filters/gri.MP9605.fits +0 -0
  24. pydiet/data/instruments/megacam/filters/i.MP9703.fits +0 -0
  25. pydiet/data/instruments/megacam/filters/r.MP9602.fits +0 -0
  26. pydiet/data/instruments/megacam/filters/u.MP9302.fits +0 -0
  27. pydiet/data/instruments/megacam/filters/z.MP9901.fits +0 -0
  28. pydiet/data/instruments/megacam/optics/description.txt +2 -0
  29. pydiet/data/instruments/megacam/optics/transmission/MegaPrime_transmission.fits +0 -0
  30. pydiet/data/instruments/megacam/optics/transmission/description.txt +2 -0
  31. pydiet/data/instruments/wircam/description.txt +1 -0
  32. pydiet/data/instruments/wircam/detector/description.txt +1 -0
  33. pydiet/data/instruments/wircam/detector/qe/WIRCam_QE.average.fits +0 -0
  34. pydiet/data/instruments/wircam/detector/qe/description.txt +2 -0
  35. pydiet/data/instruments/wircam/filters/BrG.WC8305.fits +0 -0
  36. pydiet/data/instruments/wircam/filters/CH4Off.WC8204.fits +0 -0
  37. pydiet/data/instruments/wircam/filters/CH4On.WC8203.fits +0 -0
  38. pydiet/data/instruments/wircam/filters/CO.WC8306.fits +0 -0
  39. pydiet/data/instruments/wircam/filters/H.WC8201.fits +0 -0
  40. pydiet/data/instruments/wircam/filters/H.WC8202.fits +0 -0
  41. pydiet/data/instruments/wircam/filters/H2.WC8304.fits +0 -0
  42. pydiet/data/instruments/wircam/filters/J.WC8101.fits +0 -0
  43. pydiet/data/instruments/wircam/filters/J.WC8103.fits +0 -0
  44. pydiet/data/instruments/wircam/filters/Kcont.WC8303.fits +0 -0
  45. pydiet/data/instruments/wircam/filters/Ks.WC8301.fits +0 -0
  46. pydiet/data/instruments/wircam/filters/Ks.WC8302.fits +0 -0
  47. pydiet/data/instruments/wircam/filters/LowOH1.WC8104.fits +0 -0
  48. pydiet/data/instruments/wircam/filters/LowOH2.WC8102.fits +0 -0
  49. pydiet/data/instruments/wircam/filters/W.WC8105.fits +0 -0
  50. pydiet/data/instruments/wircam/filters/Y.WC8002.fits +0 -0
  51. pydiet/data/instruments/wircam/filters/description.txt +1 -0
  52. pydiet/data/instruments/wircam/optics/description.txt +2 -0
  53. pydiet/data/instruments/wircam/optics/transmission/WIRCam_transmission.fits +0 -0
  54. pydiet/data/instruments/wircam/optics/transmission/description.txt +2 -0
  55. pydiet/data/sites/description.txt +1 -0
  56. pydiet/data/sites/mko/default +0 -0
  57. pydiet/data/sites/mko/description.txt +2 -0
  58. pydiet/data/sites/mko/emission/MKO_emission.bright.AM1.0.fits +0 -0
  59. pydiet/data/sites/mko/emission/MKO_emission.bright.AM1.1.fits +0 -0
  60. pydiet/data/sites/mko/emission/MKO_emission.bright.AM1.2.fits +0 -0
  61. pydiet/data/sites/mko/emission/MKO_emission.bright.AM1.3.fits +0 -0
  62. pydiet/data/sites/mko/emission/MKO_emission.bright.AM1.4.fits +0 -0
  63. pydiet/data/sites/mko/emission/MKO_emission.bright.AM1.5.fits +0 -0
  64. pydiet/data/sites/mko/emission/MKO_emission.bright.AM1.6.fits +0 -0
  65. pydiet/data/sites/mko/emission/MKO_emission.bright.AM1.7.fits +0 -0
  66. pydiet/data/sites/mko/emission/MKO_emission.bright.AM1.8.fits +0 -0
  67. pydiet/data/sites/mko/emission/MKO_emission.bright.AM1.9.fits +0 -0
  68. pydiet/data/sites/mko/emission/MKO_emission.bright.AM2.0.fits +0 -0
  69. pydiet/data/sites/mko/emission/MKO_emission.bright.AM2.5.fits +0 -0
  70. pydiet/data/sites/mko/emission/MKO_emission.bright.AM3.0.fits +0 -0
  71. pydiet/data/sites/mko/emission/MKO_emission.dark.AM1.0.fits +0 -0
  72. pydiet/data/sites/mko/emission/MKO_emission.dark.AM1.1.fits +0 -0
  73. pydiet/data/sites/mko/emission/MKO_emission.dark.AM1.2.fits +0 -0
  74. pydiet/data/sites/mko/emission/MKO_emission.dark.AM1.3.fits +0 -0
  75. pydiet/data/sites/mko/emission/MKO_emission.dark.AM1.4.fits +0 -0
  76. pydiet/data/sites/mko/emission/MKO_emission.dark.AM1.5.fits +0 -0
  77. pydiet/data/sites/mko/emission/MKO_emission.dark.AM1.6.fits +0 -0
  78. pydiet/data/sites/mko/emission/MKO_emission.dark.AM1.7.fits +0 -0
  79. pydiet/data/sites/mko/emission/MKO_emission.dark.AM1.8.fits +0 -0
  80. pydiet/data/sites/mko/emission/MKO_emission.dark.AM1.9.fits +0 -0
  81. pydiet/data/sites/mko/emission/MKO_emission.dark.AM2.0.fits +0 -0
  82. pydiet/data/sites/mko/emission/MKO_emission.dark.AM2.5.fits +0 -0
  83. pydiet/data/sites/mko/emission/MKO_emission.dark.AM3.0.fits +0 -0
  84. pydiet/data/sites/mko/emission/MKO_emission.grey.AM1.0.fits +0 -0
  85. pydiet/data/sites/mko/emission/MKO_emission.grey.AM1.1.fits +0 -0
  86. pydiet/data/sites/mko/emission/MKO_emission.grey.AM1.2.fits +0 -0
  87. pydiet/data/sites/mko/emission/MKO_emission.grey.AM1.3.fits +0 -0
  88. pydiet/data/sites/mko/emission/MKO_emission.grey.AM1.4.fits +0 -0
  89. pydiet/data/sites/mko/emission/MKO_emission.grey.AM1.5.fits +0 -0
  90. pydiet/data/sites/mko/emission/MKO_emission.grey.AM1.6.fits +0 -0
  91. pydiet/data/sites/mko/emission/MKO_emission.grey.AM1.7.fits +0 -0
  92. pydiet/data/sites/mko/emission/MKO_emission.grey.AM1.8.fits +0 -0
  93. pydiet/data/sites/mko/emission/MKO_emission.grey.AM1.9.fits +0 -0
  94. pydiet/data/sites/mko/emission/MKO_emission.grey.AM2.0.fits +0 -0
  95. pydiet/data/sites/mko/emission/MKO_emission.grey.AM2.5.fits +0 -0
  96. pydiet/data/sites/mko/emission/MKO_emission.grey.AM3.0.fits +0 -0
  97. pydiet/data/sites/mko/emission/description.txt +5 -0
  98. pydiet/data/sites/mko/transmission/MKO_transmission.AM1.0.fits +0 -0
  99. pydiet/data/sites/mko/transmission/MKO_transmission.AM1.1.fits +0 -0
  100. pydiet/data/sites/mko/transmission/MKO_transmission.AM1.2.fits +0 -0
  101. pydiet/data/sites/mko/transmission/MKO_transmission.AM1.3.fits +0 -0
  102. pydiet/data/sites/mko/transmission/MKO_transmission.AM1.4.fits +0 -0
  103. pydiet/data/sites/mko/transmission/MKO_transmission.AM1.5.fits +0 -0
  104. pydiet/data/sites/mko/transmission/MKO_transmission.AM1.6.fits +0 -0
  105. pydiet/data/sites/mko/transmission/MKO_transmission.AM1.7.fits +0 -0
  106. pydiet/data/sites/mko/transmission/MKO_transmission.AM1.8.fits +0 -0
  107. pydiet/data/sites/mko/transmission/MKO_transmission.AM1.9.fits +0 -0
  108. pydiet/data/sites/mko/transmission/MKO_transmission.AM2.0.fits +0 -0
  109. pydiet/data/sites/mko/transmission/MKO_transmission.AM2.5.fits +0 -0
  110. pydiet/data/sites/mko/transmission/MKO_transmission.AM3.0.fits +0 -0
  111. pydiet/data/sites/mko/transmission/MKO_transmission.AM3.5.fits +0 -0
  112. pydiet/data/sites/mko/transmission/MKO_transmission.AM4.0.fits +0 -0
  113. pydiet/data/sites/mko/transmission/MKO_transmission.AM4.5.fits +0 -0
  114. pydiet/data/sites/mko/transmission/MKO_transmission.AM5.0.fits +0 -0
  115. pydiet/data/sites/mko/transmission/description.txt +5 -0
  116. pydiet/data/telescopes/cfht/default +0 -0
  117. pydiet/data/telescopes/cfht/description.txt +1 -0
  118. pydiet/data/telescopes/cfht/emission/description.txt +2 -0
  119. pydiet/data/telescopes/cfht/transmission/CFHT_M1_transmission.fits +0 -0
  120. pydiet/data/telescopes/cfht/transmission/description.txt +1 -0
  121. pydiet/data/telescopes/description.txt +1 -0
  122. pydiet/package.py +55 -0
  123. pydiet/py.typed +0 -0
  124. pydiet/server/__init__.py +9 -0
  125. pydiet/server/app.py +369 -0
  126. pydiet/server/config/__init__.py +51 -0
  127. pydiet/server/config/config.py +330 -0
  128. pydiet/server/config/fields.py +49 -0
  129. pydiet/server/config/settings.py +166 -0
  130. pydiet/server/data.py +31 -0
  131. pydiet/server/datafiles.py +367 -0
  132. pydiet/server/image.py +342 -0
  133. pydiet/server/models/__init__.py +34 -0
  134. pydiet/server/models/dataconfig.py +195 -0
  135. pydiet/server/models/default.py +9 -0
  136. pydiet/server/models/exceptions.py +9 -0
  137. pydiet/server/models/instrument.py +314 -0
  138. pydiet/server/models/query.py +172 -0
  139. pydiet/server/models/response.py +97 -0
  140. pydiet/server/models/types.py +35 -0
  141. pydiet/server/photsys.py +71 -0
  142. pydiet/server/response.py +237 -0
  143. pydiet/server/types/__init__.py +8 -0
  144. pydiet/server/types/quantity.py +532 -0
  145. pydiet/server/types/string.py +318 -0
  146. pydiet/templates/common/base.html +80 -0
  147. pydiet/templates/common/plot_filter.html +17 -0
  148. pydiet/templates/common/privacy.html +132 -0
  149. pydiet/templates/common/settings.html +23 -0
  150. pydiet/templates/common/terms.html +101 -0
  151. pydiet/templates/megacam/etc_form.html +319 -0
  152. pydiet/templates/megacam/etc_results.html +190 -0
  153. pydiet/templates/wircam/etc_form.html +319 -0
  154. pydiet/templates/wircam/etc_results.html +190 -0
  155. pydiet/web_client/css/style.css +221 -0
  156. pydiet/web_client/dist/pydiet.js +31 -0
  157. pydiet/web_client/images/logo.svg +6 -0
  158. pydiet/web_client/images/megacam/background.jpg +0 -0
  159. pydiet/web_client/images/megacam/logo.png +0 -0
  160. pydiet/web_client/images/wircam/background.jpg +0 -0
  161. pydiet/web_client/images/wircam/logo.png +0 -0
  162. pydiet/web_client/js/dom.js +51 -0
  163. pydiet/web_client/js/etc.js +63 -0
  164. pydiet/web_client/js/fetch.js +49 -0
  165. pydiet/web_client/js/instrument.js +62 -0
  166. pydiet/web_client/js/main.js +15 -0
  167. pydiet/web_client/js/plot.js +88 -0
  168. pydiet/web_client/js/settings.js +57 -0
  169. pydiet/web_client/js/theme.js +43 -0
  170. pydiet/web_client/js/url.js +12 -0
  171. pydiet/web_client/jsdoc.json +20 -0
  172. pydiet/web_client/package.json +83 -0
  173. pydiet-0.9.3.dist-info/METADATA +118 -0
  174. pydiet-0.9.3.dist-info/RECORD +177 -0
  175. pydiet-0.9.3.dist-info/WHEEL +4 -0
  176. pydiet-0.9.3.dist-info/entry_points.txt +5 -0
  177. pydiet-0.9.3.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="108.1mm" height="127.5mm" version="1.1" viewBox="0 0 408.7 482" xmlns="http://www.w3.org/2000/svg">
3
+ <g transform="translate(-381.2 -371.7)">
4
+ <path d="m397.6 853.4-0.626-0.2547v-190.1l1.584-0.608h113.2l1.937 1.037v67.99l-0.304 0.7921-0.304 0.7922h-40.35l-0.3192-1.272-0.3192-1.272 0.0462-12.82 0.0462-12.82-0.4393-0.4393-0.4394-0.4394-32.99 0.2644v107.7l33.8 0.2638 5e-3 -0.6326 5e-3 -0.6327 0.1203-13.67 0.1202-13.67 1.502-0.9493 38.24-0.018 0.787 0.7869 0.787 0.787v68.5l-1.906 1.02-113.5-0.0583-0.626-0.2548zm149.9-0.1624-19.53-0.2593-0.1265-94.6-0.1265-94.6 1.127-1.358 113.3 0.018 2.254 0.604v40.33l-2.254 0.6039-72.17 0.018-1.202 1.202v31.23l1.347 1.118 74.02 0.2569v40.57l-74.02 0.2569-1.347 1.118v72.79l-1.202 1.202-0.5509-0.2327zm130.8 0.1104-19.4-0.1311-0.1278-94.02-0.1278-94.02 0.7307-2.265 40.34 0.2618 0.2585 37.06 0.2585 37.06 0.1171 0.1252 0.1171 0.1251h32.99l0.8103-1.252 0.2504-36.56 0.2504-36.56h40.57v189.8h-40.57l-0.2504-35.81-0.2504-35.81-0.8103-1.252h-32.89l-0.608 1.584v71.42l-2.254 0.3672zm-282.9-206.6-0.6296-1.128-1.311-3.506-4.862-15.02-1.569-6.01-1.507-6.51-1.466-7.011-1.559-10.52-1.277-10.52v-29.55l1.311-11.52 1.474-9.515 1.621-8.013 0.8759-3.756 0.8759-3.756 1.076-3.957 1.076-3.957 3.898-11.62 1.912-5.008 4.25-10.02 5.772-11.52 2.255-4.006 5.102-8.514 7.479-11.02 6.229-8.013 7.728-9.014 8.709-9.014 8.971-8.112 2.934-2.405 3.577-3.083 10.02-7.454 7.011-4.599 4.507-2.872 1.671-1.022 2.836-1.601 13.52-7.102 12.02-5.17 8.013-2.949 10.52-3.347 5.509-1.506 6.01-1.629 4.507-0.2346v275.9l-148.5 0.2537zm231.2 0.4992-0.2377-0.626 0.2565-274.9 4.507 0.2346 6.01 1.629 5.509 1.506 10.52 3.347 8.013 2.953 7.512 3.216 6.51 3.008 3.506 1.688 8.013 4.369 3.736 2.339h0.4499l6.331 4.132 5.509 3.629 10.02 7.435 3.579 3.083 5.436 4.471 16.63 16.56 7.406 9.059 3.506 4.341 3.947 5.631 4.486 6.51 5.479 9.014 3.023 5.509 5.257 10.52 4.168 10.02 1.308 3.005 1.735 5.008 0.8162 2.003 3.034 10.02 2.083 8.514 0.9399 3.506 1.115 5.509 1.42 8.514 1.724 15.52 0.015 13.52 0.0151 13.52-1.324 13.52-1.472 9.014-0.7641 3.756-0.7641 3.756-0.7305 3.255-0.7306 3.255-0.7277 2.632-0.7277 2.632-1.637 5.753-1.483 4.507-1.483 4.507-0.8614 2.003-2.012 4.758h-148.3l-0.2377-0.626z" fill="#234290" stroke-width=".5008"/>
5
+ </g>
6
+ </svg>
Binary file
@@ -0,0 +1,51 @@
1
+ // DOM manipulation routines
2
+ // Copyright 2024,2025 CFHT/CNRS/OSUPS/CEA/UParisSaclay
3
+ // Licensed under GPL v3
4
+
5
+ // Inject HTML in the selected node.
6
+ export function inject_html(selector, html) {
7
+ parent = document.querySelector(selector)
8
+ if (parent.firstElementChild) {
9
+ parent.firstElementChild.remove();
10
+ parent.innerHTML = "";
11
+ }
12
+ parent.insertAdjacentHTML("beforeend", html);
13
+
14
+ // Now find scripts inside what was inserted and re-insert them
15
+ const scripts = parent.querySelectorAll('script');
16
+ scripts.forEach(oldScript => {
17
+ // Only re-run scripts that came from our insertion:
18
+ // (If needed, scope this by inserting into a wrapper element and querying inside it.)
19
+ const newScript = document.createElement('script');
20
+
21
+ // Copy attributes (type, src, nonce, etc.)
22
+ for (const { name, value } of oldScript.attributes) {
23
+ newScript.setAttribute(name, value);
24
+ }
25
+
26
+ if (oldScript.src) {
27
+ // External script
28
+ newScript.src = oldScript.src;
29
+ // Optional: preserve async/defer behavior if you set it
30
+ } else {
31
+ // Inline script
32
+ newScript.textContent = oldScript.textContent;
33
+ }
34
+
35
+ oldScript.replaceWith(newScript);
36
+ });
37
+ }
38
+
39
+
40
+ export function inject_node(selector, node) {
41
+ parent = document.querySelector(selector)
42
+ if (parent.firstElementChild) {
43
+ parent.firstElementChild.remove();
44
+ parent.innerHTML = "";
45
+ }
46
+ if (node) {
47
+ parent.appendChild(node);
48
+ }
49
+ return node;
50
+ }
51
+
@@ -0,0 +1,63 @@
1
+ // Manage web interface settings
2
+ // Copyright 2024,2025 CFHT/CNRS/OSUPS/CEA/UParisSaclay
3
+ // Licensed under GPL v3
4
+
5
+ import {inject_node} from "./dom";
6
+ import {fetch_data, fetch_html} from "./fetch";
7
+ import {get_filterID, update_filter} from "./instrument";
8
+ import {plot_filter} from "./plot";
9
+ import {etc_url, ui_url} from "./url";
10
+
11
+ export async function update_etcform(instrument) {
12
+ fetch_html(
13
+ "#content-slot",
14
+ ui_url + "/" + instrument.id + "/etc_form"
15
+ ).then( (result) => {
16
+ const etc_form = document.querySelector('#etc-form');
17
+ update_filters(instrument);
18
+ etc_form.addEventListener('submit', async function (e){
19
+ // Prevent default behavior on submit
20
+ e.preventDefault();
21
+ const data = new FormData(this),
22
+ datao = Object.fromEntries(data),
23
+ upload = (datao.filter_upload && datao.filter_upload.size > 0);
24
+ fetch_html(
25
+ '#modal-slot',
26
+ ui_url + '/' + instrument.id + '/etc_results/query',
27
+ upload ? {method: 'post', data: data} : {data: data}
28
+ );
29
+ });
30
+ });
31
+ }
32
+
33
+
34
+ function update_filters(instrument) {
35
+ if ((select_filters = document.querySelector("#select-filters"))) {
36
+ while (select_filters.firstChild) {
37
+ select_filters.lastChild.remove()
38
+ }
39
+ const instrumentID = instrument.id,
40
+ filters = instrument.filters.transmissions;
41
+ let f_default = get_filterID(instrumentID);
42
+ for (f in filters) {
43
+ let option = document.createElement("ion-select-option");
44
+ option.value = f;
45
+ filter = filters[f]
46
+ option.innerHTML = filter.name;
47
+ select_filters.appendChild(option);
48
+ // Identify default instrument (or first in the dictionary instead)
49
+ if (!f_default && (filter.default || !f_default)) {
50
+ f_default = f;
51
+ }
52
+ }
53
+ option = document.createElement("ion-select-option");
54
+ option.value = 'upload';
55
+ option.innerHTML = "upload";
56
+ select_filters.appendChild(option);
57
+ select_filters.value = f_default;
58
+ update_filter(instrumentID, f_default);
59
+ }
60
+ }
61
+
62
+
63
+
@@ -0,0 +1,49 @@
1
+ // Fetch HTML components
2
+ // Copyright 2024,2025 CFHT/CNRS/OSUPS/CEA/UParisSaclay
3
+ // Licensed under GPL v3
4
+
5
+ import {inject_html} from "./dom";
6
+
7
+
8
+ export async function fetch_data(url) {
9
+ return await fetch(url, {credentials: "include"})
10
+ .then( (response) => {
11
+ // The API call was successful!
12
+ if (!response.ok) {
13
+ throw new Error("Unauthorized API endpoint:" + response.url);
14
+ }
15
+ return response.json();
16
+ }).catch( (err) => {
17
+ // There was an error
18
+ return false;
19
+ });
20
+ };
21
+
22
+
23
+ export async function fetch_html(selector, url, {method='get', data} = {}) {
24
+ return await (method=='get' ?
25
+ fetch(
26
+ data ? url + '?' + new URLSearchParams(data) : url,
27
+ {credentials: 'include'}
28
+ ) : fetch(url,
29
+ {
30
+ method: 'post',
31
+ body: data,
32
+ credentials: "include"})
33
+ ).then( (response) => {
34
+ // The API call was successful!
35
+ if (!response.ok) {
36
+ throw new Error("Unauthorized API endpoint:" + response.url);
37
+ }
38
+ return response.text();
39
+ }).then( (html) => {
40
+ // Remove possible remaining modal
41
+ // Insert the HTML string into the current element
42
+ inject_html(selector, html);
43
+ return true;
44
+ }).catch( (err) => {
45
+ // There was an error
46
+ return false;
47
+ });
48
+ };
49
+
@@ -0,0 +1,62 @@
1
+ // Manage instruments
2
+ // Copyright 2024,2025 CFHT/CNRS/OSUPS/CEA/UParisSaclay
3
+ // Licensed under MIT
4
+
5
+ import { loadingController } from '@ionic/core';
6
+ import { etc_url } from "./url";
7
+ import {update_etcform} from "./etc";
8
+ import { fetch_data} from "./fetch";
9
+
10
+ let instruments_cache = null;
11
+
12
+ export async function get_instruments() {
13
+ if (!instruments_cache) {
14
+ const loading = await loadingController.create({
15
+ message: 'Loading instruments ...',
16
+ duration: 10000
17
+ });
18
+ loading.present();
19
+ instruments_cache = fetch_data(etc_url + "/instruments");
20
+ loading.dismiss();
21
+ }
22
+ return instruments_cache;
23
+ }
24
+
25
+
26
+ // Get previously stored instrument
27
+ export function get_instrumentID() {
28
+ return localStorage.getItem('pyDIETDefaultInstrument');
29
+ }
30
+
31
+
32
+ // Update stored instrument setting
33
+ export function update_instrument(instrumentID) {
34
+ get_instruments().then( (instruments) => {
35
+ instrument = instruments[instrumentID];
36
+ update_etcform(instrument);
37
+ // Store new instrument setting in local storage
38
+ localStorage.setItem('pyDIETDefaultInstrument', instrumentID);
39
+ return instrumentID;
40
+ });
41
+ }
42
+
43
+
44
+ // Get previously stored filter
45
+ export function get_filterID(instrumentID) {
46
+ return localStorage.getItem('pyDIETDefaultFilter_' + instrumentID);
47
+ }
48
+
49
+
50
+ // Update stored filter setting
51
+ export function update_filter(instrumentID, filterID) {
52
+ if (filterID) {
53
+ // Store new filter setting in local storage
54
+ localStorage.setItem('pyDIETDefaultFilter_' + instrumentID, filterID);
55
+ return filterID;
56
+ } else {
57
+ // Return previously stored filter
58
+ return get_filterID(instrumentID);
59
+ }
60
+ }
61
+
62
+
@@ -0,0 +1,15 @@
1
+ // Javascript code entry point
2
+ // Copyright 2024,2025 CFHT/CNRS/OSUPS/CEA/UParisSaclay
3
+ // Licensed under MIT
4
+ import {get_instruments} from "./instrument"
5
+ import {setup_instrument_settings, setup_theme_settings} from "./settings";
6
+
7
+ // Set up theme section of settings
8
+ setup_theme_settings();
9
+
10
+ get_instruments().then( (instruments) => {
11
+ // Set up instrument section of settings
12
+ setup_instrument_settings(instruments);
13
+ });
14
+
15
+
@@ -0,0 +1,88 @@
1
+ // Manage web interface settings
2
+ // Copyright 2024,2025 CFHT/CNRS/OSUPS/CEA/UParisSaclay
3
+ // Licensed under GPL v3
4
+
5
+ import Chart from 'chart.js/auto';
6
+ import zoomPlugin from 'chartjs-plugin-zoom';
7
+
8
+ Chart.register(zoomPlugin);
9
+
10
+ export function plot_filter(filter, atmosphere, canvas, wave_min, wave_max) {
11
+ const fwave = filter.wave.value,
12
+ fresponse = filter.response.value,
13
+ awave = atmosphere.wave.value,
14
+ aresponse = atmosphere.response.value,
15
+ unit = filter.wave.unit,
16
+ chart = new Chart(
17
+ canvas,
18
+ {
19
+ type: 'line',
20
+ data: {
21
+ datasets: [
22
+ {
23
+ label: 'Atmosphere',
24
+ data: awave.map((x, i) => ({ x, y: aresponse[i] })),
25
+ fill: true
26
+ },
27
+ {
28
+ label: 'Instrument',
29
+ data: fwave.map((x, i) => ({ x, y: fresponse[i] })),
30
+ fill: true
31
+ }
32
+ ]
33
+ },
34
+ options: {
35
+ pointRadius: 0,
36
+ maintainAspectRatio: false,
37
+ interaction: {
38
+ mode: 'nearest',
39
+ intersect: true
40
+ },
41
+ scales: {
42
+ x: {
43
+ type: 'linear',
44
+ title: {
45
+ display: true,
46
+ text: 'Wavelength [' + unit + ']'
47
+ },
48
+ min: filter.wave_range.value[0],
49
+ max: filter.wave_range.value[1]
50
+
51
+ },
52
+ y: {
53
+ title: {
54
+ display: true,
55
+ text: 'Transmission',
56
+ },
57
+ min: 0.,
58
+ max: 1.
59
+ }
60
+ },
61
+ plugins: {
62
+ title: {
63
+ display: false,
64
+ text: filter.name + ' filter',
65
+ },
66
+ legend: {display: false},
67
+ zoom: {
68
+ zoom: {
69
+ wheel: {enabled: true},
70
+ pinch: {enabled: true},
71
+ drag: {enabled: true, modifierKey: 'shift'},
72
+ scaleMode: 'xy',
73
+ mode: 'xy'},
74
+ pan: {enabled: true, scaleMode: 'xy'},
75
+ limits: {
76
+ x: {min: 'original', max: 'original'},
77
+ y: {min: 'original', max: 'original'}
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+ );
84
+ };
85
+
86
+
87
+ window.plot_filter = plot_filter;
88
+
@@ -0,0 +1,57 @@
1
+ // Manage web interface settings
2
+ // Copyright 2024,2025 CFHT/CNRS/OSUPS/CEA/UParisSaclay
3
+ // Licensed under GPL v3
4
+ import {get_instrumentID, update_instrument} from "./instrument";
5
+ import {get_theme, update_theme, themes, theme_icons} from "./theme";
6
+
7
+ // Manage theme changes
8
+ export function setup_theme_settings() {
9
+ const theme_segment = document.querySelector("#theme-segment");
10
+ if ((theme_segment)) {
11
+ for (var t in themes) {
12
+ let button = document.createElement("ion-segment-button"),
13
+ icon = document.createElement("ion-icon"),
14
+ label = document.createElement("ion-label");
15
+ button.value = themes[t].toLowerCase();
16
+ label.innerHTML = themes[t];
17
+ button.appendChild(label);
18
+ icon.name = theme_icons[t];
19
+ button.appendChild(icon);
20
+ theme_segment.appendChild(button);
21
+ }
22
+ const theme = theme_segment.value = get_theme();
23
+ update_theme(theme);
24
+ theme_segment.addEventListener('ionChange', (event) => {
25
+ update_theme(event.detail.value);
26
+ });
27
+ }
28
+ }
29
+
30
+ // Manage instrument changes
31
+ export function setup_instrument_settings(instruments) {
32
+ if ((instrument_segment = document.querySelector("#instrument-segment"))) {
33
+ let i_default = get_instrumentID();
34
+ for (i in instruments) {
35
+ let button = document.createElement("ion-segment-button"),
36
+ icon = document.createElement("ion-icon"),
37
+ label = document.createElement("ion-label");
38
+ button.value = i;
39
+ instrument = instruments[i]
40
+ label.innerHTML = instrument.name;
41
+ button.appendChild(label);
42
+ icon.name = "videocam";
43
+ button.appendChild(icon);
44
+ instrument_segment.appendChild(button);
45
+ // Identify default instrument (or first in the dictionary instead)
46
+ if (!i_default && (instrument.default || !i_default)) {
47
+ i_default = i;
48
+ }
49
+ }
50
+ instrument_segment.value = i_default;
51
+ update_instrument(i_default);
52
+ instrument_segment.addEventListener('ionChange', (event) => {
53
+ update_instrument(event.detail.value);
54
+ });
55
+ }
56
+ }
57
+
@@ -0,0 +1,43 @@
1
+ // Manage web interface settings
2
+ // Copyright 2024,2025 CFHT/CNRS/OSUPS/CEA/UParisSaclay
3
+ // Licensed under MIT
4
+
5
+ export const themes = ["Light", "Dark", "Auto"],
6
+ theme_icons = ["sunny", "moon", "contrast"];
7
+
8
+
9
+ // Use matchMedia to check the user preference for dark/light themes
10
+ const prefersdark = window.matchMedia('(prefers-color-scheme: dark)');
11
+
12
+ // Add or remove the "dark" class based on if the media query matches
13
+ function toggle_dark_theme(isdark) {
14
+ document.body.classList.toggle('dark', isdark);
15
+ }
16
+
17
+
18
+ // Get previously stored theme
19
+ export function get_theme() {
20
+ return localStorage.getItem('pyDIETDefaultTheme');
21
+ }
22
+
23
+
24
+ // Add or remove the "dark" class based on if the media query matches
25
+ export function update_theme(theme) {
26
+ if (theme) {
27
+ // Store new theme choice in local storage
28
+ localStorage.setItem('pyDIETDefaultTheme', theme);
29
+ } else {
30
+ // Get previously stored theme
31
+ theme = get_theme();
32
+ }
33
+ // Toggle theme if necessary
34
+ toggle_dark_theme(
35
+ (typeof(theme) === "string" && theme.includes("dark"))
36
+ || (
37
+ !(typeof(theme) === "string" && theme.includes("light"))
38
+ && prefersdark.matches
39
+ )
40
+ );
41
+ }
42
+
43
+
@@ -0,0 +1,12 @@
1
+ // Root URLs for APIs
2
+ // Copyright 2024,2025 CFHT/CNRS/OSUPS/CEA/UParisSaclay
3
+ // Licensed under GPL v3
4
+
5
+ const root_path = document.querySelector('#root_path').content;
6
+
7
+
8
+ export const root_url = root_path, // Root URL
9
+ etc_url = root_url + "/api",
10
+ ui_url = root_url + "/ui", // Root URL for UI components
11
+ ui_auth_url = ui_url + "/auth";
12
+
@@ -0,0 +1,20 @@
1
+ {
2
+ "opts": {
3
+ "destination": "doc",
4
+ "pedantic": true,
5
+ "private": true,
6
+ "recurse": true,
7
+ "template": "./node_modules/tidy-jsdoc"
8
+ },
9
+ "templates": {
10
+ "cleverLinks": true,
11
+ "monospaceLinks": false
12
+ },
13
+ "plugins": [
14
+ "plugins/markdown"
15
+ ],
16
+ "metadata": {
17
+ "title": "PyDIET web client"
18
+ }
19
+ }
20
+
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "PyDIET",
3
+ "version": "0.1.0",
4
+ "description": "CFHT's Direct Imaging Exposure Time calculator",
5
+ "homepage": "https://github.com/astromatic/pydiet",
6
+ "author": "Emmanuel Bertin (CEA/CFHT/CNRS/UParisSaclay)",
7
+ "contributors": [
8
+ "Emmanuel Bertin <bertin@cfht.hawaii.edu> (https://github.com/ebertin)"
9
+ ],
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "astronomy",
13
+ "CFHT",
14
+ "calculator",
15
+ "imaging"
16
+ ],
17
+ "private": true,
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/astromatic/pydiet.git"
21
+ },
22
+ "bugs": {
23
+ "url": "https://github.com/astromatic/pydiet/issues"
24
+ },
25
+ "dependencies": {
26
+ "@ionic/core": "^8.0",
27
+ "npm": "^10.8.1",
28
+ "tidy-jsdoc": "^1.4.1"
29
+ },
30
+ "devDependencies": {
31
+ "chart.js": "=4.3.0",
32
+ "chartjs-plugin-zoom": "^2.0.1",
33
+ "esbuild": "^0.14.53",
34
+ "eslint": "^8.23.1",
35
+ "jsdoc": "^4.0"
36
+ },
37
+ "main": "dist/visiomatic.js",
38
+ "scripts": {
39
+ "build": "esbuild js/main.js --bundle --minify --outfile=dist/pydiet.js --watch",
40
+ "build-pretty": "esbuild js/main.js --bundle --outfile=dist/pydiet.js --watch",
41
+ "docs": "jsdoc -c jsdoc.json js",
42
+ "lint": "eslint js",
43
+ "test": "npm run unit"
44
+ },
45
+ "eslintConfig": {
46
+ "ignorePatterns": [
47
+ "dist"
48
+ ],
49
+ "parserOptions": {
50
+ "ecmaVersion": "latest",
51
+ "sourceType": "module"
52
+ },
53
+ "env": {
54
+ "node": true,
55
+ "es6": true
56
+ },
57
+ "rules": {
58
+ "curly": "error",
59
+ "indent": [
60
+ "error",
61
+ "tab"
62
+ ],
63
+ "key-spacing": "off",
64
+ "linebreak-style": [
65
+ "off",
66
+ "unix"
67
+ ],
68
+ "no-mixed-spaces-and-tabs": [
69
+ "error",
70
+ "smart-tabs"
71
+ ],
72
+ "no-unused-expressions": [
73
+ "error"
74
+ ],
75
+ "spaced-comment": "error",
76
+ "strict": "off",
77
+ "wrap-iife": "off",
78
+ "no-invalid-this": "off",
79
+ "prefer-object-has-own": "error",
80
+ "prefer-spread": "off"
81
+ }
82
+ }
83
+ }