From 45fb4ac2edc42d8aa21c00b2037e7e0b9d0e8977 Mon Sep 17 00:00:00 2001 From: Demurest Date: Mon, 23 Sep 2024 12:26:04 -0300 Subject: [PATCH 01/39] fix band name --- lightcurve/src/magstats_api/static/magstats.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lightcurve/src/magstats_api/static/magstats.js b/lightcurve/src/magstats_api/static/magstats.js index 7f91b59b5..de3bf9004 100644 --- a/lightcurve/src/magstats_api/static/magstats.js +++ b/lightcurve/src/magstats_api/static/magstats.js @@ -38,10 +38,6 @@ export function initMagstats() { numColumns = db.length + 1; // Esto es numero de bandas + 1 numRows = Object.keys(db[0]).length; - for (let i = 0; i < db.length; i++) { - numBands.push(db[i]["fid"]); - delete db[i]["fid"]; - } for (let i = 0; i < numBands.length; i++) { realBands.push(bandMapping[numBands[i]]); @@ -131,6 +127,7 @@ function parseStatR(dict) { lastmjd: dict[key]["lastmjd"], step_id_corr: dict[key]["step_id_corr"], }; + numBands.push(dict[key]["fid"]); db.push(auxJson); }); } From d9e29460551dc9c3cd568155c02a7dbe56427fb7 Mon Sep 17 00:00:00 2001 From: Demurest Date: Wed, 25 Sep 2024 15:10:39 -0300 Subject: [PATCH 02/39] radar --- lightcurve/Dockerfile | 6 + lightcurve/docker-compose.yaml | 22 +- lightcurve/pyproject.toml | 2 + lightcurve/scripts/run_dev.py | 3 + lightcurve/scripts/run_probability_dev.py | 12 + lightcurve/src/probability_api/__init__.py | 0 lightcurve/src/probability_api/api.py | 35 + lightcurve/src/probability_api/filters.py | 47 + .../src/probability_api/result_handler.py | 37 + .../src/probability_api/routes/__init__.py | 0 lightcurve/src/probability_api/routes/htmx.py | 127 ++ lightcurve/src/probability_api/routes/rest.py | 47 + .../probability_api/static/probability.css | 1389 +++++++++++++++++ .../src/probability_api/static/probability.js | 206 +++ .../probability_api/templates/prob.html.jinja | 124 ++ .../templates/probabilitiesCard.html.jinja | 301 ++++ .../probability_api/templates/probability.css | 581 +++++++ lightcurve/tailwind.config.js | 1 + 18 files changed, 2935 insertions(+), 5 deletions(-) create mode 100644 lightcurve/scripts/run_probability_dev.py create mode 100644 lightcurve/src/probability_api/__init__.py create mode 100644 lightcurve/src/probability_api/api.py create mode 100644 lightcurve/src/probability_api/filters.py create mode 100644 lightcurve/src/probability_api/result_handler.py create mode 100644 lightcurve/src/probability_api/routes/__init__.py create mode 100644 lightcurve/src/probability_api/routes/htmx.py create mode 100644 lightcurve/src/probability_api/routes/rest.py create mode 100644 lightcurve/src/probability_api/static/probability.css create mode 100644 lightcurve/src/probability_api/static/probability.js create mode 100644 lightcurve/src/probability_api/templates/prob.html.jinja create mode 100644 lightcurve/src/probability_api/templates/probabilitiesCard.html.jinja create mode 100644 lightcurve/src/probability_api/templates/probability.css diff --git a/lightcurve/Dockerfile b/lightcurve/Dockerfile index 5f667cb7c..d88b1a152 100644 --- a/lightcurve/Dockerfile +++ b/lightcurve/Dockerfile @@ -33,6 +33,11 @@ COPY ./lightcurve/ /lightcurve/ WORKDIR /lightcurve RUN npx tailwindcss -i /lightcurve/src/magstats_api/templates/magstats.css -o /compiled/magstats.css +FROM node:22-alpine as tailwindcss_probability +COPY ./lightcurve/ /lightcurve/ +WORKDIR /lightcurve +RUN npx tailwindcss -i /lightcurve/src/probability_api/templates/probability.css -o /compiled/probability.css + FROM python:3.11-slim as production RUN pip install poetry COPY --from=builder /app /app @@ -45,6 +50,7 @@ COPY ./lightcurve/src /app/src COPY --from=tailwindcss_lightcurve /compiled/main.css /app/src/api/static COPY --from=tailwindcss_magstats /compiled/magstats.css /app/src/magstats_api/static COPY --from=tailwindcss_object /compiled/object.css /app/src/object_api/static +COPY --from=tailwindcss_probability /compiled/probability.css /app/src/probability_api/static # COPY --from=tailwindcss_crossmatch /compiled/crossmatch.css /app/src/crossmatch_api/static RUN poetry install --only-root CMD ["bash", "scripts/entrypoint.sh"] diff --git a/lightcurve/docker-compose.yaml b/lightcurve/docker-compose.yaml index 479adce4f..546f68a9c 100644 --- a/lightcurve/docker-compose.yaml +++ b/lightcurve/docker-compose.yaml @@ -28,6 +28,18 @@ services: environment: SERVICE: lightcurve_api API_URL: http://localhost:8001 + + object: + build: + context: ../ + dockerfile: lightcurve/Dockerfile + ports: + - 8002:8000 + env_file: + - variables.env + environment: + SERVICE: object_api + API_URL: http://localhost:8002 magstats: build: @@ -40,15 +52,15 @@ services: environment: SERVICE: magstats_api API_URL: http://localhost:8003 - - object: + + probability: build: context: ../ dockerfile: lightcurve/Dockerfile ports: - - 8002:8000 + - 8004:8000 env_file: - variables.env environment: - SERVICE: object_api - API_URL: http://localhost:8002 \ No newline at end of file + SERVICE: probability_api + API_URL: http://localhost:8004 diff --git a/lightcurve/pyproject.toml b/lightcurve/pyproject.toml index 0ae3e0576..d169891ce 100644 --- a/lightcurve/pyproject.toml +++ b/lightcurve/pyproject.toml @@ -10,6 +10,7 @@ packages = [ { include = "lightcurve_api", from = "src" }, { include = "magstats_api", from = "src" }, { include = "object_api", from = "src" }, + { include = "probability_api", from = "src" }, { include = "database", from = "src" }, ] @@ -71,4 +72,5 @@ dev = "scripts.run_dev:run" lightcurve = "scripts.run_dev:run_lightcurve" magstats = "scripts.run_dev:run_magstats" object = "scripts.run_dev:run_object" +probability = "scripts.run_dev:run_probability" tunnel = "scripts.sshproxy:run_tunnel" diff --git a/lightcurve/scripts/run_dev.py b/lightcurve/scripts/run_dev.py index ef0e8b231..020575a83 100644 --- a/lightcurve/scripts/run_dev.py +++ b/lightcurve/scripts/run_dev.py @@ -33,6 +33,9 @@ def run_object(): port = int(os.getenv("PORT", default=8000)) asyncio.run(run_service("object_api", port)) +def run_probability(): + port = int(os.getenv("PORT", default=8000)) + asyncio.run(run_service("probability_api", port)) async def run_services(services, port): tasks = [] diff --git a/lightcurve/scripts/run_probability_dev.py b/lightcurve/scripts/run_probability_dev.py new file mode 100644 index 000000000..00c971873 --- /dev/null +++ b/lightcurve/scripts/run_probability_dev.py @@ -0,0 +1,12 @@ +import os + +import uvicorn + + +def run(): + port = os.getenv("PORT", default=8000) + uvicorn.run("probability_api.api:app", port=int(port), reload=True, reload_dirs=[".", "../libs"]) + + +if __name__ == "__main__": + run() \ No newline at end of file diff --git a/lightcurve/src/probability_api/__init__.py b/lightcurve/src/probability_api/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/lightcurve/src/probability_api/api.py b/lightcurve/src/probability_api/api.py new file mode 100644 index 000000000..0023e1190 --- /dev/null +++ b/lightcurve/src/probability_api/api.py @@ -0,0 +1,35 @@ + +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware +from fastapi.staticfiles import StaticFiles +from prometheus_fastapi_instrumentator import Instrumentator + +from .routes import htmx, rest +from database.mongo import connect as connect_mongo +from database.sql import connect as connect_sql, session_wrapper + +app = FastAPI(openapi_url="/v2/object/openapi.json") +app.state.mongo_db = None +psql_engine = connect_sql() +app.state.psql_session = session_wrapper(psql_engine) +instrumentator = Instrumentator().instrument(app).expose(app) + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +app.include_router(rest.router) +app.include_router(prefix="/htmx", router=htmx.router) + +app.mount("/static", StaticFiles(directory="src/probability_api/static"), name="static") + + +@app.get("/openapi.json") +def custom_swagger_route(): + return app.openapi() + diff --git a/lightcurve/src/probability_api/filters.py b/lightcurve/src/probability_api/filters.py new file mode 100644 index 000000000..876a12da6 --- /dev/null +++ b/lightcurve/src/probability_api/filters.py @@ -0,0 +1,47 @@ +import re + + +def update_config_dict(config_dict): + config_dict["FILTERS_MAP"] = { + "filter_atlas_detections": filter_atlas_detection_non_detection, + "filter_atlas_non_detections": filter_atlas_detection_non_detection, + "filter_atlas_lightcurve": filter_atlas_lightcurve, + "filter_atlas_forced_photometry": filter_atlas_detection_non_detection, + } + + +def get_filters_map(): + return { + "filter_atlas_detections": filter_atlas_detection_non_detection, + "filter_atlas_non_detections": filter_atlas_detection_non_detection, + "filter_atlas_lightcurve": filter_atlas_lightcurve, + "filter_atlas_forced_photometry": filter_atlas_detection_non_detection, + } + + +def filter_atlas_detection_non_detection(lc_object): + pattern = re.compile("atlas*", re.IGNORECASE) + if pattern.match(lc_object["tid"]): + return False + return True + + +def filter_atlas_lightcurve(lc_object): + non_filtered_detections = [] + non_filtered_non_detections = [] + non_filtered_forced_photometry = [] + + for detection in lc_object["detections"]: + if filter_atlas_detection_non_detection(detection): + non_filtered_detections.append(detection) + for non_detecton in lc_object["non_detections"]: + if filter_atlas_detection_non_detection(non_detecton): + non_filtered_non_detections.append(non_detecton) + for forced_photometry in lc_object["forced_photometry"]: + if filter_atlas_detection_non_detection(forced_photometry): + non_filtered_forced_photometry.append(forced_photometry) + + lc_object["detections"] = non_filtered_detections + lc_object["non_detections"] = non_filtered_non_detections + lc_object["forced_photometry"] = non_filtered_forced_photometry + return True \ No newline at end of file diff --git a/lightcurve/src/probability_api/result_handler.py b/lightcurve/src/probability_api/result_handler.py new file mode 100644 index 000000000..8e873734c --- /dev/null +++ b/lightcurve/src/probability_api/result_handler.py @@ -0,0 +1,37 @@ +import traceback +import logging + +from fastapi import HTTPException + +from core.exceptions import ( + AtlasNonDetectionError, + DatabaseError, + ObjectNotFound, + SurveyIdError, +) + + +def handle_success(result): + return result + + +def _handle_client_error(err: BaseException, code=400): + raise HTTPException(status_code=code, detail=str(err)) + + +def _handle_server_error(err: BaseException): + if err.__traceback__: + traceback.print_exception(err) + logging.error(err) + raise HTTPException(status_code=500, detail=str(err)) + + +def handle_error(err: BaseException): + if isinstance(err, DatabaseError): + _handle_server_error(err) + if isinstance(err, SurveyIdError): + _handle_client_error(err) + if isinstance(err, AtlasNonDetectionError): + _handle_client_error(err) + if isinstance(err, ObjectNotFound): + _handle_client_error(err, code=404) \ No newline at end of file diff --git a/lightcurve/src/probability_api/routes/__init__.py b/lightcurve/src/probability_api/routes/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/lightcurve/src/probability_api/routes/htmx.py b/lightcurve/src/probability_api/routes/htmx.py new file mode 100644 index 000000000..68bb46ccd --- /dev/null +++ b/lightcurve/src/probability_api/routes/htmx.py @@ -0,0 +1,127 @@ +import re +import os +import json +import pprint +from typing import Annotated +from fastapi import FastAPI, Request, Query + +from core.services.object import get_probabilities,get_taxonomies +from fastapi import APIRouter, Request, HTTPException +from fastapi.templating import Jinja2Templates +from fastapi.responses import HTMLResponse, JSONResponse +from ..result_handler import handle_error, handle_success + +router = APIRouter() +templates = Jinja2Templates( + directory="src/probability_api/templates", autoescape=True, auto_reload=True +) +templates.env.globals["API_URL"] = os.getenv( + "API_URL", "http://localhost:8004" +) + +def prob_filter(prob_list, taxonomy_list): + + prob_dict = {} + taxonomy_dict = {} + + for n in range(len(taxonomy_list)): + taxonomy_dict[f'tax_{n+1}'] = taxonomy_list[n].__dict__ + + for k in range(len(prob_list)): + prob_dict[f'prob_{k+1}'] = prob_list[k].__dict__ + + return taxonomy_dict, prob_dict + +def filter_classifier_name_taxonomy(taxonomy_dict): + filter = ["lc_classifier", "lc_classifier_top", "stamp_classifier", "LC_classifier_BHRF_forced_phot(beta)", "LC_classifier_ATAT_forced_phot(beta)"] + pop_keys = [] + for value in taxonomy_dict.keys(): + if(taxonomy_dict[value]["classifier_name"] in filter): + pass + else: + pop_keys.append(value) + + for x in range(len(pop_keys)): + taxonomy_dict.pop(pop_keys[x]) + + taxonomy_dict = eliminated_duplicates_by_higher_version(taxonomy_dict) + + return taxonomy_dict + +def eliminated_duplicates_by_higher_version(taxonomy_dict): + # format of dict: {classifier_name: key} + seen_classifiers = {} + filtered_taxonomy = {} + + for key, value in taxonomy_dict.items(): + classifier_name = value["classifier_name"] + if classifier_name not in seen_classifiers: + filtered_taxonomy[key] = value + seen_classifiers[classifier_name] = key + else: + oldKey = seen_classifiers[classifier_name] + if value["classifier_version"] > taxonomy_dict[oldKey]["classifier_version"]: + filtered_taxonomy.pop(oldKey) + filtered_taxonomy[key] = value + seen_classifiers[classifier_name] = key + + return filtered_taxonomy + +def group_data_by_classifier(prob_dict): + classifiers_names = ["lc_classifier", "lc_classifier_top", "stamp_classifier", "LC_classifier_BHRF_forced_phot(beta)", "LC_classifier_ATAT_forced_phot(beta)"] + group_data_dict = {} + aux_data_arr = [] + + for classifier in classifiers_names: + for key, value in prob_dict.items(): + if value["classifier_name"] == classifier: + aux_data_arr.append(value) + group_data_dict[classifier] = aux_data_arr + aux_data_arr = [] + + pprint.pprint(group_data_dict) + + return group_data_dict + +@router.get("/probabilities/{oid}", response_class=HTMLResponse) +async def object_probability_app( + request: Request, + oid: str, +): + + prob_list = get_probabilities(oid,session_factory = request.app.state.psql_session) + taxonomy_list = get_taxonomies(session_factory = request.app.state.psql_session) + + taxonomy_dict, prob_dict = prob_filter(prob_list, taxonomy_list) + + group_prob_dict = group_data_by_classifier(prob_dict) + filtered_taxonomy = filter_classifier_name_taxonomy(taxonomy_dict) + + return templates.TemplateResponse( + name='prob.html.jinja', + context={'request': request, + 'prob_dict': prob_dict, + 'taxonomy_dict': filtered_taxonomy, + 'group_prob_dict': group_prob_dict, + }, + ) + + +@router.get("/probabilities2/{oid}", response_class=HTMLResponse) +async def object_probability_app( + request: Request, + oid: str, +): + + prob_list = get_probabilities(oid,session_factory = request.app.state.psql_session) + taxonomy_list = get_taxonomies(session_factory = request.app.state.psql_session) + + taxonomy_dict, prob_dict = prob_filter(prob_list, taxonomy_list) + + return templates.TemplateResponse( + name='probabilitiesCard.html.jinja', + context={'request': request, + 'prob_dict': prob_dict, + 'taxonomy_dict': taxonomy_dict, + }, + ) \ No newline at end of file diff --git a/lightcurve/src/probability_api/routes/rest.py b/lightcurve/src/probability_api/routes/rest.py new file mode 100644 index 000000000..9e3457b83 --- /dev/null +++ b/lightcurve/src/probability_api/routes/rest.py @@ -0,0 +1,47 @@ +import re +import os +from typing import Annotated +from fastapi import Query +import json + +from core.services.object import get_probabilities,get_taxonomies +from fastapi import APIRouter, Request, HTTPException +from fastapi.templating import Jinja2Templates +from fastapi.responses import HTMLResponse +from ..result_handler import handle_error, handle_success + +router = APIRouter() +templates = Jinja2Templates( + directory="src/api/templates", autoescape=True, auto_reload=True +) +templates.env.globals["API_URL"] = os.getenv( + "API_URL", "http://localhost:8000" +) + +def prob_filter(prob_list, taxonomy_list): + + prob_dict = {} + taxonomy_dict = {} + + for n in range(len(taxonomy_list)): + taxonomy_dict[f'tax_{n+1}'] = taxonomy_list[n].__dict__ + + for k in range(len(prob_list)): + prob_dict[f'prob_{k+1}'] = prob_list[k].__dict__ + + return taxonomy_dict, prob_dict + +@router.get("/probabilities/{oid}", response_class=HTMLResponse) +async def object_crossmatch_app( + request: Request, + oid: str +): + prob_list = get_probabilities(oid,session_factory = request.app.state.psql_session) + taxonomy_list = get_taxonomies(session_factory = request.app.state.psql_session) + + taxonomy_dict, prob_dict = prob_filter(prob_list, taxonomy_list) + + return {'request': request, + 'prob_dict': prob_dict, + 'taxonomy_dict': taxonomy_dict + }, \ No newline at end of file diff --git a/lightcurve/src/probability_api/static/probability.css b/lightcurve/src/probability_api/static/probability.css new file mode 100644 index 000000000..75e3805d5 --- /dev/null +++ b/lightcurve/src/probability_api/static/probability.css @@ -0,0 +1,1389 @@ +.tw-preflight :is(.tw-pointer-events-none) { + pointer-events: none; +} + +.tw-preflight :is(.tw-pointer-events-auto) { + pointer-events: auto; +} + +.tw-preflight :is(.tw-absolute) { + position: absolute; +} + +.tw-preflight :is(.tw-relative) { + position: relative; +} + +.tw-preflight :is(.tw-left-10) { + left: 2.5rem; +} + +.tw-preflight :is(.tw-right-0) { + right: 0px; +} + +.tw-preflight :is(.tw-top-1) { + top: 0.25rem; +} + +.tw-preflight :is(.tw-top-1\/2) { + top: 50%; +} + +.tw-preflight :is(.tw-z-\[9999\]) { + z-index: 9999; +} + +.tw-preflight :is(.tw-col-span-1) { + grid-column: span 1 / span 1; +} + +.tw-preflight :is(.tw-col-span-2) { + grid-column: span 2 / span 2; +} + +.tw-preflight :is(.tw-col-span-4) { + grid-column: span 4 / span 4; +} + +.tw-preflight :is(.tw-col-span-5) { + grid-column: span 5 / span 5; +} + +.tw-preflight :is(.tw-m-0) { + margin: 0px; +} + +.tw-preflight :is(.tw-m-auto) { + margin: auto; +} + +.tw-preflight :is(.tw-mx-2) { + margin-left: 0.5rem; + margin-right: 0.5rem; +} + +.tw-preflight :is(.tw-mx-auto) { + margin-left: auto; + margin-right: auto; +} + +.tw-preflight :is(.tw-my-4) { + margin-top: 1rem; + margin-bottom: 1rem; +} + +.tw-preflight :is(.tw-me-2) { + margin-inline-end: 0.5rem; +} + +.tw-preflight :is(.tw-ml-2) { + margin-left: 0.5rem; +} + +.tw-preflight :is(.tw-ml-3) { + margin-left: 0.75rem; +} + +.tw-preflight :is(.tw-ml-\[30px\]) { + margin-left: 30px; +} + +.tw-preflight :is(.tw-ml-\[40px\]) { + margin-left: 40px; +} + +.tw-preflight :is(.tw-ml-\[50\%\]) { + margin-left: 50%; +} + +.tw-preflight :is(.tw-ml-\[80px\]) { + margin-left: 80px; +} + +.tw-preflight :is(.tw-mr-4) { + margin-right: 1rem; +} + +.tw-preflight :is(.tw-mt-2) { + margin-top: 0.5rem; +} + +.tw-preflight :is(.tw-mt-3) { + margin-top: 0.75rem; +} + +.tw-preflight :is(.tw-mt-4) { + margin-top: 1rem; +} + +.tw-preflight :is(.tw-mt-8) { + margin-top: 2rem; +} + +.tw-preflight :is(.tw-mt-\[30px\]) { + margin-top: 30px; +} + +.tw-preflight :is(.tw-mt-\[4px\]) { + margin-top: 4px; +} + +.tw-preflight :is(.tw-box-content) { + box-sizing: content-box; +} + +.tw-preflight :is(.tw-inline) { + display: inline; +} + +.tw-preflight :is(.tw-flex) { + display: flex; +} + +.tw-preflight :is(.tw-grid) { + display: grid; +} + +.tw-preflight :is(.tw-hidden) { + display: none; +} + +.tw-preflight :is(.tw-h-32) { + height: 8rem; +} + +.tw-preflight :is(.tw-h-5) { + height: 1.25rem; +} + +.tw-preflight :is(.tw-h-6) { + height: 1.5rem; +} + +.tw-preflight :is(.tw-h-8) { + height: 2rem; +} + +.tw-preflight :is(.tw-h-\[100\%\]) { + height: 100%; +} + +.tw-preflight :is(.tw-h-\[12\.5\%\]) { + height: 12.5%; +} + +.tw-preflight :is(.tw-h-\[30px\]) { + height: 30px; +} + +.tw-preflight :is(.tw-h-\[500px\]) { + height: 500px; +} + +.tw-preflight :is(.tw-h-\[90\%\]) { + height: 90%; +} + +.tw-preflight :is(.tw-h-auto) { + height: auto; +} + +.tw-preflight :is(.tw-max-h-\[75\%\]) { + max-height: 75%; +} + +.tw-preflight :is(.tw-w-1\/3) { + width: 33.333333%; +} + +.tw-preflight :is(.tw-w-12) { + width: 3rem; +} + +.tw-preflight :is(.tw-w-32) { + width: 8rem; +} + +.tw-preflight :is(.tw-w-48) { + width: 12rem; +} + +.tw-preflight :is(.tw-w-5) { + width: 1.25rem; +} + +.tw-preflight :is(.tw-w-52) { + width: 13rem; +} + +.tw-preflight :is(.tw-w-6) { + width: 1.5rem; +} + +.tw-preflight :is(.tw-w-\[100\%\]) { + width: 100%; +} + +.tw-preflight :is(.tw-w-\[30px\]) { + width: 30px; +} + +.tw-preflight :is(.tw-w-\[400px\]) { + width: 400px; +} + +.tw-preflight :is(.tw-w-\[75\%\]) { + width: 75%; +} + +.tw-preflight :is(.tw-w-\[90\%\]) { + width: 90%; +} + +.tw-preflight :is(.tw-w-\[95\%\]) { + width: 95%; +} + +.tw-preflight :is(.tw-w-full) { + width: 100%; +} + +.tw-preflight :is(.tw-min-w-full) { + min-width: 100%; +} + +.tw-preflight :is(.tw-max-w-\[40\%\]) { + max-width: 40%; +} + +.tw-preflight :is(.tw-max-w-\[75\%\]) { + max-width: 75%; +} + +.tw-preflight :is(.tw-flex-grow) { + flex-grow: 1; +} + +.tw-preflight :is(.-tw-translate-y-1) { + --tw-translate-y: -0.25rem; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.tw-preflight :is(.-tw-translate-y-1\/2) { + --tw-translate-y: -50%; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.tw-preflight :is(.tw-translate-x-16) { + --tw-translate-x: 4rem; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.tw-preflight :is(.tw-transform) { + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +@keyframes tw-spin { + to { + transform: rotate(360deg); + } +} + +.tw-preflight :is(.tw-animate-spin) { + animation: tw-spin 1s linear infinite; +} + +.tw-preflight :is(.tw-cursor-pointer) { + cursor: pointer; +} + +.tw-preflight :is(.tw-appearance-none) { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.tw-preflight :is(.tw-grid-cols-10) { + grid-template-columns: repeat(10, minmax(0, 1fr)); +} + +.tw-preflight :is(.tw-grid-cols-6) { + grid-template-columns: repeat(6, minmax(0, 1fr)); +} + +.tw-preflight :is(.tw-flex-col) { + flex-direction: column; +} + +.tw-preflight :is(.tw-place-content-center) { + place-content: center; +} + +.tw-preflight :is(.tw-place-items-center) { + place-items: center; +} + +.tw-preflight :is(.tw-items-center) { + align-items: center; +} + +.tw-preflight :is(.tw-justify-end) { + justify-content: flex-end; +} + +.tw-preflight :is(.tw-justify-center) { + justify-content: center; +} + +.tw-preflight :is(.tw-justify-between) { + justify-content: space-between; +} + +.tw-preflight :is(.tw-gap-1) { + gap: 0.25rem; +} + +.tw-preflight :is(.tw-space-x-2 > :not([hidden]) ~ :not([hidden])) { + --tw-space-x-reverse: 0; + margin-right: calc(0.5rem * var(--tw-space-x-reverse)); + margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); +} + +.tw-preflight :is(.tw-space-x-4 > :not([hidden]) ~ :not([hidden])) { + --tw-space-x-reverse: 0; + margin-right: calc(1rem * var(--tw-space-x-reverse)); + margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); +} + +.tw-preflight :is(.tw-space-y-2 > :not([hidden]) ~ :not([hidden])) { + --tw-space-y-reverse: 0; + margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(0.5rem * var(--tw-space-y-reverse)); +} + +.tw-preflight :is(.tw-divide-y > :not([hidden]) ~ :not([hidden])) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); +} + +.tw-preflight :is(.tw-divide-gray-200 > :not([hidden]) ~ :not([hidden])) { + --tw-divide-opacity: 1; + border-color: rgb(229 231 235 / var(--tw-divide-opacity)); +} + +.tw-preflight :is(.tw-place-self-center) { + place-self: center; +} + +.tw-preflight :is(.tw-overflow-auto) { + overflow: auto; +} + +.tw-preflight :is(.tw-truncate) { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.tw-preflight :is(.tw-text-wrap) { + text-wrap: wrap; +} + +.tw-preflight :is(.tw-rounded) { + border-radius: 0.25rem; +} + +.tw-preflight :is(.tw-rounded-\[50px\]) { + border-radius: 50px; +} + +.tw-preflight :is(.tw-rounded-\[6px\]) { + border-radius: 6px; +} + +.tw-preflight :is(.tw-rounded-full) { + border-radius: 9999px; +} + +.tw-preflight :is(.tw-rounded-md) { + border-radius: 0.375rem; +} + +.tw-preflight :is(.tw-rounded-bl-\[10px\]) { + border-bottom-left-radius: 10px; +} + +.tw-preflight :is(.tw-rounded-br-\[10px\]) { + border-bottom-right-radius: 10px; +} + +.tw-preflight :is(.tw-rounded-tl-\[10px\]) { + border-top-left-radius: 10px; +} + +.tw-preflight :is(.tw-rounded-tr-\[10px\]) { + border-top-right-radius: 10px; +} + +.tw-preflight :is(.tw-border) { + border-width: 1px; +} + +.tw-preflight :is(.tw-border-8) { + border-width: 8px; +} + +.tw-preflight :is(.tw-border-b) { + border-bottom-width: 1px; +} + +.tw-preflight :is(.tw-border-b-\[1px\]) { + border-bottom-width: 1px; +} + +.tw-preflight :is(.tw-border-t) { + border-top-width: 1px; +} + +.tw-preflight :is(.tw-border-solid) { + border-style: solid; +} + +.tw-preflight :is(.tw-border-\[\#1e1e1e\]) { + --tw-border-opacity: 1; + border-color: rgb(30 30 30 / var(--tw-border-opacity)); +} + +.tw-preflight :is(.tw-border-blue-400) { + --tw-border-opacity: 1; + border-color: rgb(96 165 250 / var(--tw-border-opacity)); +} + +.tw-preflight :is(.tw-border-gray-300) { + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); +} + +.tw-preflight :is(.tw-border-b-black) { + --tw-border-opacity: 1; + border-bottom-color: rgb(0 0 0 / var(--tw-border-opacity)); +} + +.tw-preflight :is(.tw-border-t-transparent) { + border-top-color: transparent; +} + +.tw-preflight :is(.tw-border-opacity-20) { + --tw-border-opacity: 0.2; +} + +.tw-preflight :is(.tw-bg-\[\#757575\]\/60) { + background-color: rgb(117 117 117 / 0.6); +} + +.tw-preflight :is(.tw-bg-blue-500) { + --tw-bg-opacity: 1; + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.tw-bg-blue-700) { + --tw-bg-opacity: 1; + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.tw-bg-cyan-700) { + --tw-bg-opacity: 1; + background-color: rgb(14 116 144 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.tw-bg-gray-100) { + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.tw-bg-gray-900) { + --tw-bg-opacity: 1; + background-color: rgb(17 24 39 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.tw-bg-green-500) { + --tw-bg-opacity: 1; + background-color: rgb(34 197 94 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.tw-bg-transparent) { + background-color: transparent; +} + +.tw-preflight :is(.tw-bg-white) { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.tw-bg-gray-800) { + --tw-bg-opacity: 1; + background-color: rgb(31 41 55 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.tw-p-2) { + padding: 0.5rem; +} + +.tw-preflight :is(.tw-p-\[10px\]) { + padding: 10px; +} + +.tw-preflight :is(.tw-px-2) { + padding-left: 0.5rem; + padding-right: 0.5rem; +} + +.tw-preflight :is(.tw-px-4) { + padding-left: 1rem; + padding-right: 1rem; +} + +.tw-preflight :is(.tw-py-1) { + padding-top: 0.25rem; + padding-bottom: 0.25rem; +} + +.tw-preflight :is(.tw-py-2) { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.tw-preflight :is(.tw-py-4) { + padding-top: 1rem; + padding-bottom: 1rem; +} + +.tw-preflight :is(.tw-pl-\[10px\]) { + padding-left: 10px; +} + +.tw-preflight :is(.tw-pr-2) { + padding-right: 0.5rem; +} + +.tw-preflight :is(.tw-pr-\[10px\]) { + padding-right: 10px; +} + +.tw-preflight :is(.tw-ps-2) { + padding-inline-start: 0.5rem; +} + +.tw-preflight :is(.tw-pt-\[25px\]) { + padding-top: 25px; +} + +.tw-preflight :is(.tw-text-left) { + text-align: left; +} + +.tw-preflight :is(.tw-text-center) { + text-align: center; +} + +.tw-preflight :is(.tw-text-right) { + text-align: right; +} + +.tw-preflight :is(.tw-text-2xl) { + font-size: 1.5rem; + line-height: 2rem; +} + +.tw-preflight :is(.tw-text-\[17px\]) { + font-size: 17px; +} + +.tw-preflight :is(.tw-text-lg) { + font-size: 1.125rem; + line-height: 1.75rem; +} + +.tw-preflight :is(.tw-text-sm) { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.tw-preflight :is(.tw-text-xs) { + font-size: 0.75rem; + line-height: 1rem; +} + +.tw-preflight :is(.tw-font-bold) { + font-weight: 700; +} + +.tw-preflight :is(.tw-ordinal) { + --tw-ordinal: ordinal; + font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction); +} + +.tw-preflight :is(.tw-text-\[\#1e1e1e\]) { + --tw-text-opacity: 1; + color: rgb(30 30 30 / var(--tw-text-opacity)); +} + +.tw-preflight :is(.tw-text-\[\#FAFAFA\]) { + --tw-text-opacity: 1; + color: rgb(250 250 250 / var(--tw-text-opacity)); +} + +.tw-preflight :is(.tw-text-black) { + --tw-text-opacity: 1; + color: rgb(0 0 0 / var(--tw-text-opacity)); +} + +.tw-preflight :is(.tw-text-blue-600) { + --tw-text-opacity: 1; + color: rgb(37 99 235 / var(--tw-text-opacity)); +} + +.tw-preflight :is(.tw-text-gray-400) { + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} + +.tw-preflight :is(.tw-text-gray-900) { + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity)); +} + +.tw-preflight :is(.tw-text-red-500) { + --tw-text-opacity: 1; + color: rgb(239 68 68 / var(--tw-text-opacity)); +} + +.tw-preflight :is(.tw-text-white) { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.tw-preflight :is(.tw-underline) { + text-decoration-line: underline; +} + +.tw-preflight :is(.tw-opacity-100) { + opacity: 1; +} + +.tw-preflight :is(.tw-opacity-50) { + opacity: 0.5; +} + +.tw-preflight :is(.tw-shadow-2xl) { + --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); + --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.tw-preflight :is(.tw-duration-200) { + transition-duration: 200ms; +} + +.disabled\:bg-transparent { + background-color: transparent; +} + +/* Optionally, adjust the opacity for a more subdued appearance */ + +.disabled\:opacity-50 { + opacity: 0.5; + /* Adjust the opacity as needed */ +} + +.disabled\:outline { + outline-style: solid; +} + +.tooltip { + position: relative; +} + +.tooltip .fa-question-circle { + cursor: pointer; +} + +.tooltip-text { + visibility: hidden; + width: -moz-max-content; + width: max-content; + max-width: 500px; + background-color: #000; + color: #fff; + text-align: center; + border-radius: 4px; + padding: 4px 8px; + position: absolute; + font-size: 12px; + z-index: 999; + top: -50px; + left: 50%; + transform: translateX(-50%); + opacity: 0; + transition: opacity 0.3s; +} + +.tooltip:hover .tooltip-text { + visibility: visible; + opacity: 1; +} + +.tw-preflight *, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +.tw-preflight ::before, +.tw-preflight ::after { + --tw-content: ""; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +*/ + +.tw-preflight { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", + "Noto Color Emoji"; + /* 4 */ + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ + margin: 0; +} + +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +input[type=number] { + -moz-appearance: textfield; +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +.tw-preflight hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +.tw-preflight abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +.tw-preflight h1, +.tw-preflight h2, +.tw-preflight h3, +.tw-preflight h4, +.tw-preflight h5, +.tw-preflight h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +.tw-preflight a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +.tw-preflight b, +.tw-preflight strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font family by default. +2. Correct the odd `em` font sizing in all browsers. +*/ + +.tw-preflight code, +.tw-preflight kbd, +.tw-preflight samp, +.tw-preflight pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, + "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} + +/* +Add the correct font size in all browsers. +*/ + +.tw-preflight small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +.tw-preflight sub, +.tw-preflight sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +.tw-preflight sub { + bottom: -0.25em; +} + +.tw-preflight sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +.tw-preflight table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +.tw-preflight button, +.tw-preflight input, +.tw-preflight optgroup, +.tw-preflight select, +.tw-preflight textarea { + font-family: inherit; + /* 1 */ + font-feature-settings: inherit; + /* 1 */ + font-variation-settings: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +.tw-preflight button, +.tw-preflight select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +.tw-preflight button, +.tw-preflight [type="button"], +.tw-preflight [type="reset"], +.tw-preflight [type="submit"] { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +.tw-preflight :-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +.tw-preflight :-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +.tw-preflight progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +.tw-preflight ::-webkit-inner-spin-button, +.tw-preflight ::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +.tw-preflight [type="search"] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +.tw-preflight ::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +.tw-preflight ::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +.tw-preflight summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +.tw-preflight blockquote, +.tw-preflight dl, +.tw-preflight dd, +.tw-preflight h1, +.tw-preflight h2, +.tw-preflight h3, +.tw-preflight h4, +.tw-preflight h5, +.tw-preflight h6, +.tw-preflight hr, +.tw-preflight figure, +.tw-preflight p, +.tw-preflight pre { + margin: 0; +} + +.tw-preflight fieldset { + margin: 0; + padding: 0; +} + +.tw-preflight legend { + padding: 0; +} + +.tw-preflight ol, +.tw-preflight ul, +.tw-preflight menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ + +.tw-preflight dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +.tw-preflight textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +.tw-preflight input::-moz-placeholder, +.tw-preflight textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +.tw-preflight input::-moz-placeholder, .tw-preflight textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +.tw-preflight input::placeholder, +.tw-preflight textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +.tw-preflight button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +.tw-preflight :disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +.tw-preflight img, +.tw-preflight svg, +.tw-preflight, +.tw-preflight canvas, +.tw-preflight, +.tw-preflight iframe, +.tw-preflight embed, +.tw-preflight object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +.tw-preflight img, +.tw-preflight video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +.tw-preflight [hidden] { + display: none; +} + +.tw-preflight *, +.tw-preflight ::before, +.tw-preflight ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +.tw-preflight ::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +.tw-preflight :is(.hover\:tw-cursor-pointer:hover) { + cursor: pointer; +} + +.tw-preflight :is(.hover\:tw-bg-\[\#757575\]:hover) { + --tw-bg-opacity: 1; + background-color: rgb(117 117 117 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.hover\:tw-bg-\[\#e5e4e2\]:hover) { + --tw-bg-opacity: 1; + background-color: rgb(229 228 226 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.hover\:tw-bg-blue-700:hover) { + --tw-bg-opacity: 1; + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.hover\:tw-bg-gray-200:hover) { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.hover\:tw-bg-green-600:hover) { + --tw-bg-opacity: 1; + background-color: rgb(22 163 74 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.hover\:tw-bg-green-700:hover) { + --tw-bg-opacity: 1; + background-color: rgb(21 128 61 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.hover\:tw-text-gray-600:hover) { + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} + +.tw-preflight :is(.disabled\:tw-bg-transparent:disabled) { + background-color: transparent; +} + +.tw-preflight :is(.disabled\:tw-opacity-50:disabled) { + opacity: 0.5; +} + +.tw-preflight :is(.disabled\:tw-outline:disabled) { + outline-style: solid; +} + +.tw-preflight :is(.tw-group:hover .group-hover\:tw-flex) { + display: flex; +} + +.tw-preflight :is(:is(.tw-dark .dark\:tw-divide-\[\#404040\]) > :not([hidden]) ~ :not([hidden])) { + --tw-divide-opacity: 1; + border-color: rgb(64 64 64 / var(--tw-divide-opacity)); +} + +.tw-preflight :is(.tw-dark .dark\:tw-border-\[\#404040\]) { + --tw-border-opacity: 1; + border-color: rgb(64 64 64 / var(--tw-border-opacity)); +} + +.tw-preflight :is(.tw-dark .dark\:tw-border-white) { + --tw-border-opacity: 1; + border-color: rgb(255 255 255 / var(--tw-border-opacity)); +} + +.tw-preflight :is(.tw-dark .dark\:tw-border-opacity-20) { + --tw-border-opacity: 0.2; +} + +.tw-preflight :is(.tw-dark .dark\:tw-bg-\[\#1e1e1e\]) { + --tw-bg-opacity: 1; + background-color: rgb(30 30 30 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.tw-dark .dark\:tw-bg-\[\#252525\]) { + --tw-bg-opacity: 1; + background-color: rgb(37 37 37 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.tw-dark .dark\:tw-bg-\[\#757575\]\/60) { + background-color: rgb(117 117 117 / 0.6); +} + +.tw-preflight :is(.tw-dark .dark\:tw-bg-green-700) { + --tw-bg-opacity: 1; + background-color: rgb(21 128 61 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.tw-dark .dark\:tw-text-\[\#FAFAFA\]) { + --tw-text-opacity: 1; + color: rgb(250 250 250 / var(--tw-text-opacity)); +} + +.tw-preflight :is(.tw-dark .dark\:tw-text-white) { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.tw-preflight :is(.tw-dark .dark\:hover\:tw-bg-\[\#353535\]:hover) { + --tw-bg-opacity: 1; + background-color: rgb(53 53 53 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.tw-dark .dark\:hover\:tw-bg-\[\#3b3939\]:hover) { + --tw-bg-opacity: 1; + background-color: rgb(59 57 57 / var(--tw-bg-opacity)); +} \ No newline at end of file diff --git a/lightcurve/src/probability_api/static/probability.js b/lightcurve/src/probability_api/static/probability.js new file mode 100644 index 000000000..c31cd5b58 --- /dev/null +++ b/lightcurve/src/probability_api/static/probability.js @@ -0,0 +1,206 @@ +let boolDisplay = 1; +let auxBool; +const arrowDown = ` + + ` + +const arrowUp = ` + + ` + +export function howManyGraphsFilter(db){ + + const uniqueList = [] + + for (let i = 0; i < db.length; i++){ + if (!uniqueList.includes(db[i].classifier_name)){ + uniqueList.push(db[i].classifier_name) + } + } + + return uniqueList + +} + +export function hasBodyClass(className) { + const body = document.body; + return body.classList.contains(className); +} + + +// This function detects if there is more than one classifier_name with the same value and detects what of them is the higher version. +export function uniqueValues(tax ,uniqueNameAux) { + + let uniqueName = []; + let uniqueVersion = []; + let repeatedArray = []; // if len(repeatedArray[i]) > 1 then there is a repetition in i + + for (let i = 0; i < tax.length; i++){ + + if(!(uniqueName.includes(tax[i].classifier_name))){ + uniqueName.push(tax[i].classifier_name); + uniqueVersion.push(tax[i].classifier_version) + repeatedArray.push([tax[i].classifier_version]) + } else { + repeatedArray[uniqueName.indexOf(tax[i].classifier_name)].push(tax[i].classifier_version) + } + + } + + for (let j = 0; j < repeatedArray.length; j++){ + + let maxVersion = 0; + + if (repeatedArray[j].length > 1){ + for (let k = 0; k < repeatedArray[j].length; k++){ + + let splitted = repeatedArray[j][k].split('_'); + let splitted_numbers = splitted[splitted.length - 1].split('.') + let partialSum = 0; + + for (let i = 0;i < splitted_numbers.length; i++){ + partialSum += Number(splitted_numbers[i]); + + } + + if (maxVersion < partialSum){ + maxVersion = partialSum; + uniqueVersion[j] = repeatedArray[j][k]; + } + } + } + + } + + if (uniqueName.length > uniqueNameAux.length){ + uniqueName = uniqueNameAux; + } + + return [uniqueName,uniqueVersion] + +} + +// generateDictionaries functions takes the uniqueValues return and generates a dictionary of empty dictionaries, one for every classifier_name in the uniqueValues return +export function generateDictionaries(tax, uniqueNameAux) { + + const [uniqueName,uniqueVersion] = uniqueValues(tax, uniqueNameAux); + const result = {}; + + for (let i = 0; i < uniqueName.length; i++) { + result[uniqueName[i]] = {}; + } + + return [result,uniqueName,uniqueVersion]; +} + +// getData is the function that fill the dictionary generated in generateDictionaries. tha data is separated by his classfier_name and added as: class_name:probability + // where class_name is the key and probability is the value + // uniqueVersion is not used because db only has 1 version, but if we must choose the higher version, then the uniqueVersion list has it. +export function getData(db, tax, uniqueNameAux){ + + const [principalDict,uniqueKeys,uniqueVersion] = generateDictionaries(tax, uniqueNameAux); + for (let i = 0; i < db.length; i++){ + principalDict[db[i].classifier_name][db[i].class_name] = db[i].probability; + } + + return [principalDict,uniqueKeys] +} + +// selector function returns the dictionary required in the initial moment and when the user selects another chart +export function selector(n, principalDict, uniqueKeys){ + return principalDict[uniqueKeys[n]]; +} + +export function isDarkMode() { + return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; +} + +export function getTextColor() { + + const element = document.getElementById('myElement'); + const computedStyle = window.getComputedStyle(element); + const color = computedStyle.getPropertyValue('color'); + + return color +} + +export function handleDarkModeChange(e) { + var isDarkModeOn = e.matches; + if (isDarkModeOn){ + myChart.options.r.grid.color = 'white'; + } else { + myChart.options.r.grid.color = 'black'; + }; +}; +// Function to capitalize just the first letter of a word +export function capitalize(word){ + return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); +} +// Function that split the word by the _ and joins with spaces and capitalized words +export function changeTitles(uniqueKeys){ + let keysTitle = []; + + for (let i = 0; i < uniqueKeys.length; i++){ + + let splittedWord = uniqueKeys[i].split('_'); + let auxList = [] + + for (let j = 0; j < splittedWord.length; j++){ + auxList.push(capitalize(splittedWord[j])); + } + keysTitle.push(auxList.join(' ')) + } + return keysTitle; +} + +export function getComputedColor() { + const element = document.getElementById('myElement'); + const style = window.getComputedStyle(element); + return style.color; +} + +export function onColorChange(callback) { + let currentColor = getComputedColor(); + + // Check for changes periodically + setInterval(() => { + const newColor = getComputedColor(); + if (newColor !== currentColor) { + currentColor = newColor; + callback(currentColor); + } + }, 100); // Check every 100ms + } +export function displayMenu(auxBool = 0) { + + const mySelect = document.getElementById('mySelect'); + const arrowSvg = document.getElementById('arrow-svg'); + const robot = document.getElementById('robot'); + const displayButton = document.getElementById('display-button'); + + if (auxBool === 1){ + boolDisplay = 0; + } + + if (boolDisplay === 1) { + mySelect.style.display = 'block'; + arrowSvg.innerHTML = arrowUp; + robot.classList.remove('tw-text-black', 'dark:tw-text-white'); + robot.classList.add('tw-text-[#1976d2]'); + arrowSvg.classList.remove('tw-text-black', 'dark:tw-text-white'); + arrowSvg.classList.add('tw-text-[#1976d2]'); + displayButton.classList.remove('tw-border-b-black','dark:tw-border-b-white'); + displayButton.classList.add('tw-border-b-[#1976d2]'); + boolDisplay = 0; + } else { + mySelect.style.display = 'none'; + arrowSvg.innerHTML = arrowDown; + robot.classList.add('tw-text-black', 'dark:tw-text-white'); + robot.classList.remove('tw-text-[#1976d2]'); + arrowSvg.classList.remove('tw-text-[#1976d2]'); + arrowSvg.classList.add('tw-text-black', 'dark:tw-text-white'); + displayButton.classList.remove('tw-border-b-[#1976d2]'); + displayButton.classList.add('tw-border-b-black','dark:tw-border-b-white'); + boolDisplay = 1; + }; +}; \ No newline at end of file diff --git a/lightcurve/src/probability_api/templates/prob.html.jinja b/lightcurve/src/probability_api/templates/prob.html.jinja new file mode 100644 index 000000000..2a8598ab2 --- /dev/null +++ b/lightcurve/src/probability_api/templates/prob.html.jinja @@ -0,0 +1,124 @@ + + + + +
+
+
+ +
+ +
+ +
+ +
+
+ + \ No newline at end of file diff --git a/lightcurve/src/probability_api/templates/probabilitiesCard.html.jinja b/lightcurve/src/probability_api/templates/probabilitiesCard.html.jinja new file mode 100644 index 000000000..7af02cb90 --- /dev/null +++ b/lightcurve/src/probability_api/templates/probabilitiesCard.html.jinja @@ -0,0 +1,301 @@ + + + + +
+ +
+
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+ +
+ + \ No newline at end of file diff --git a/lightcurve/src/probability_api/templates/probability.css b/lightcurve/src/probability_api/templates/probability.css new file mode 100644 index 000000000..a4d313e95 --- /dev/null +++ b/lightcurve/src/probability_api/templates/probability.css @@ -0,0 +1,581 @@ +@tailwind components; +@tailwind utilities; + +.disabled\:bg-transparent { + background-color: transparent; + } + +/* Optionally, adjust the opacity for a more subdued appearance */ +.disabled\:opacity-50 { + opacity: 0.5; /* Adjust the opacity as needed */ +} + +.disabled\:outline { + outline-style: solid; +} + +.tooltip { + position: relative; +} + +.tooltip .fa-question-circle { + cursor: pointer; +} + +.tooltip-text { + visibility: hidden; + width: max-content; + max-width: 500px; + background-color: #000; + color: #fff; + text-align: center; + border-radius: 4px; + padding: 4px 8px; + position: absolute; + font-size: 12px; + z-index: 999; + top: -50px; + left: 50%; + transform: translateX(-50%); + opacity: 0; + transition: opacity 0.3s; +} + +.tooltip:hover .tooltip-text { + visibility: visible; + opacity: 1; +} + +.tw-preflight *, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +.tw-preflight ::before, +.tw-preflight ::after { + --tw-content: ""; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +*/ + +.tw-preflight { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", + "Noto Color Emoji"; + /* 4 */ + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ + margin: 0; +} + +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + + +input[type=number] { + -moz-appearance: textfield; +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +.tw-preflight hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +.tw-preflight abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +.tw-preflight h1, +.tw-preflight h2, +.tw-preflight h3, +.tw-preflight h4, +.tw-preflight h5, +.tw-preflight h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +.tw-preflight a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +.tw-preflight b, +.tw-preflight strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font family by default. +2. Correct the odd `em` font sizing in all browsers. +*/ + +.tw-preflight code, +.tw-preflight kbd, +.tw-preflight samp, +.tw-preflight pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, + "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} + +/* +Add the correct font size in all browsers. +*/ + +.tw-preflight small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +.tw-preflight sub, +.tw-preflight sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +.tw-preflight sub { + bottom: -0.25em; +} + +.tw-preflight sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +.tw-preflight table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +.tw-preflight button, +.tw-preflight input, +.tw-preflight optgroup, +.tw-preflight select, +.tw-preflight textarea { + font-family: inherit; + /* 1 */ + font-feature-settings: inherit; + /* 1 */ + font-variation-settings: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +.tw-preflight button, +.tw-preflight select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +.tw-preflight button, +.tw-preflight [type="button"], +.tw-preflight [type="reset"], +.tw-preflight [type="submit"] { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +.tw-preflight :-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +.tw-preflight :-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +.tw-preflight progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +.tw-preflight ::-webkit-inner-spin-button, +.tw-preflight ::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +.tw-preflight [type="search"] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +.tw-preflight ::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +.tw-preflight ::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +.tw-preflight summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +.tw-preflight blockquote, +.tw-preflight dl, +.tw-preflight dd, +.tw-preflight h1, +.tw-preflight h2, +.tw-preflight h3, +.tw-preflight h4, +.tw-preflight h5, +.tw-preflight h6, +.tw-preflight hr, +.tw-preflight figure, +.tw-preflight p, +.tw-preflight pre { + margin: 0; +} + +.tw-preflight fieldset { + margin: 0; + padding: 0; +} + +.tw-preflight legend { + padding: 0; +} + +.tw-preflight ol, +.tw-preflight ul, +.tw-preflight menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ + +.tw-preflight dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +.tw-preflight textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +.tw-preflight input::-moz-placeholder, +.tw-preflight textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +.tw-preflight input::placeholder, +.tw-preflight textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +.tw-preflight button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +.tw-preflight :disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +.tw-preflight img, +.tw-preflight svg, +.tw-preflight, +.tw-preflight canvas, +.tw-preflight, +.tw-preflight iframe, +.tw-preflight embed, +.tw-preflight object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +.tw-preflight img, +.tw-preflight video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +.tw-preflight [hidden] { + display: none; +} + +.tw-preflight *, +.tw-preflight ::before, +.tw-preflight ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +.tw-preflight ::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} \ No newline at end of file diff --git a/lightcurve/tailwind.config.js b/lightcurve/tailwind.config.js index 63aee2006..5963bf2f5 100644 --- a/lightcurve/tailwind.config.js +++ b/lightcurve/tailwind.config.js @@ -7,6 +7,7 @@ module.exports = { "./src/lightcurve_api/templates//*.{html.jinja,html,css}", "./src/magstats_api/templates//*.{html.jinja,html,css}", "./src/object_api/templates//*.{html.jinja,html,css}", + "./src/probability_api/templates//*.{html.jinja,html,css}", ], theme: { extend: {}, From 7a978012454302491d58b0afaa895b9a69177389 Mon Sep 17 00:00:00 2001 From: Demurest Date: Thu, 26 Sep 2024 17:19:56 -0300 Subject: [PATCH 03/39] functionality --- lightcurve/src/probability_api/routes/htmx.py | 2 - .../probability_api/static/probability.css | 67 +++++++++++++++++-- .../probability_api/templates/prob.html.jinja | 55 +++++++++++---- 3 files changed, 105 insertions(+), 19 deletions(-) diff --git a/lightcurve/src/probability_api/routes/htmx.py b/lightcurve/src/probability_api/routes/htmx.py index 68bb46ccd..586bbdddc 100644 --- a/lightcurve/src/probability_api/routes/htmx.py +++ b/lightcurve/src/probability_api/routes/htmx.py @@ -79,8 +79,6 @@ def group_data_by_classifier(prob_dict): group_data_dict[classifier] = aux_data_arr aux_data_arr = [] - pprint.pprint(group_data_dict) - return group_data_dict @router.get("/probabilities/{oid}", response_class=HTMLResponse) diff --git a/lightcurve/src/probability_api/static/probability.css b/lightcurve/src/probability_api/static/probability.css index 75e3805d5..9e32eb3bb 100644 --- a/lightcurve/src/probability_api/static/probability.css +++ b/lightcurve/src/probability_api/static/probability.css @@ -129,6 +129,10 @@ margin-top: 4px; } +.tw-preflight :is(.tw-ml-8) { + margin-left: 2rem; +} + .tw-preflight :is(.tw-box-content) { box-sizing: content-box; } @@ -225,6 +229,10 @@ width: 100%; } +.tw-preflight :is(.tw-w-\[30\%\]) { + width: 30%; +} + .tw-preflight :is(.tw-w-\[30px\]) { width: 30px; } @@ -249,6 +257,10 @@ width: 100%; } +.tw-preflight :is(.tw-w-\[50\%\]) { + width: 50%; +} + .tw-preflight :is(.tw-min-w-full) { min-width: 100%; } @@ -431,6 +443,10 @@ border-width: 1px; } +.tw-preflight :is(.tw-border-2) { + border-width: 2px; +} + .tw-preflight :is(.tw-border-8) { border-width: 8px; } @@ -447,10 +463,18 @@ border-top-width: 1px; } +.tw-preflight :is(.tw-border-b-2) { + border-bottom-width: 2px; +} + .tw-preflight :is(.tw-border-solid) { border-style: solid; } +.tw-preflight :is(.tw-border-hidden) { + border-style: hidden; +} + .tw-preflight :is(.tw-border-\[\#1e1e1e\]) { --tw-border-opacity: 1; border-color: rgb(30 30 30 / var(--tw-border-opacity)); @@ -475,6 +499,11 @@ border-top-color: transparent; } +.tw-preflight :is(.tw-border-b-\[\#1e1e1e\]) { + --tw-border-opacity: 1; + border-bottom-color: rgb(30 30 30 / var(--tw-border-opacity)); +} + .tw-preflight :is(.tw-border-opacity-20) { --tw-border-opacity: 0.2; } @@ -522,11 +551,6 @@ background-color: rgb(255 255 255 / var(--tw-bg-opacity)); } -.tw-preflight :is(.tw-bg-gray-800) { - --tw-bg-opacity: 1; - background-color: rgb(31 41 55 / var(--tw-bg-opacity)); -} - .tw-preflight :is(.tw-p-2) { padding: 0.5rem; } @@ -580,6 +604,14 @@ padding-top: 25px; } +.tw-preflight :is(.tw-pl-4) { + padding-left: 1rem; +} + +.tw-preflight :is(.tw-pl-8) { + padding-left: 2rem; +} + .tw-preflight :is(.tw-text-left) { text-align: left; } @@ -1345,6 +1377,11 @@ Constrain images and videos to the parent width and preserve their intrinsic asp border-color: rgb(255 255 255 / var(--tw-border-opacity)); } +.tw-preflight :is(.tw-dark .dark\:tw-border-b-white) { + --tw-border-opacity: 1; + border-bottom-color: rgb(255 255 255 / var(--tw-border-opacity)); +} + .tw-preflight :is(.tw-dark .dark\:tw-border-opacity-20) { --tw-border-opacity: 0.2; } @@ -1386,4 +1423,24 @@ Constrain images and videos to the parent width and preserve their intrinsic asp .tw-preflight :is(.tw-dark .dark\:hover\:tw-bg-\[\#3b3939\]:hover) { --tw-bg-opacity: 1; background-color: rgb(59 57 57 / var(--tw-bg-opacity)); +} + +@media (min-width: 640px) { + .tw-preflight :is(.sm\:tw-h-\[10\%\]) { + height: 10%; + } + + .tw-preflight :is(.sm\:tw-w-\[10\%\]) { + width: 10%; + } +} + +@media (min-width: 768px) { + .tw-preflight :is(.md\:tw-h-\[50\%\]) { + height: 50%; + } + + .tw-preflight :is(.md\:tw-w-\[50\%\]) { + width: 50%; + } } \ No newline at end of file diff --git a/lightcurve/src/probability_api/templates/prob.html.jinja b/lightcurve/src/probability_api/templates/prob.html.jinja index 2a8598ab2..ccea7fa7a 100644 --- a/lightcurve/src/probability_api/templates/prob.html.jinja +++ b/lightcurve/src/probability_api/templates/prob.html.jinja @@ -2,17 +2,21 @@ -
-
-
- + + + + + +
-
+
@@ -25,8 +29,6 @@ const raw_group_prob_dict = {{ group_prob_dict | tojson }} const ctx = document.getElementById('myChart'); - console.log(raw_group_prob_dict) - let select = document.getElementById('selectClassifier') let probability_data_aux = [] let tag_aux = [] @@ -57,23 +59,52 @@ type: 'radar', data: data, options: { + responsive: true, + maintainAspectRatio: false, elements: { line: { borderWidth: 1, + fill: true, }, }, scales: { r: { ticks: { - display: false, - maxTicksLimit: 5, + display: false, + maxTicksLimit: 5, + }, + angleLines: { + color: '#ffffff' }, + grid: { + color: '#ffffff' + }, + pointLabels: { + color: '#ffffff' + } }, }, plugins: { legend: { display: false }, + tooltip: { + enabled: true, + mode: 'dataset', + position: 'nearest', + callbacks: { + title: function(){ + return "Probability" + }, + label: function(context){ + let tooltipslabels = [] + let label = "" + label = context.label + ": " + context.parsed.r + tooltipslabels.push(label) + return tooltipslabels + } + } + } }, } } From 89bf82a6324f8eb4680706eb857c08e2f396d804 Mon Sep 17 00:00:00 2001 From: Demurest Date: Fri, 27 Sep 2024 16:45:30 -0300 Subject: [PATCH 04/39] integration nuxt --- lightcurve/src/probability_api/routes/htmx.py | 54 ++++++++++++++----- .../probability_api/templates/prob.html.jinja | 42 +++++++++++---- 2 files changed, 73 insertions(+), 23 deletions(-) diff --git a/lightcurve/src/probability_api/routes/htmx.py b/lightcurve/src/probability_api/routes/htmx.py index 586bbdddc..71acfdb5f 100644 --- a/lightcurve/src/probability_api/routes/htmx.py +++ b/lightcurve/src/probability_api/routes/htmx.py @@ -19,6 +19,7 @@ "API_URL", "http://localhost:8004" ) + def prob_filter(prob_list, taxonomy_list): prob_dict = {} @@ -49,7 +50,7 @@ def filter_classifier_name_taxonomy(taxonomy_dict): return taxonomy_dict def eliminated_duplicates_by_higher_version(taxonomy_dict): - # format of dict: {classifier_name: key} + # format of seen_classifiers dict: {classifier_name: key} seen_classifiers = {} filtered_taxonomy = {} @@ -68,18 +69,42 @@ def eliminated_duplicates_by_higher_version(taxonomy_dict): return filtered_taxonomy def group_data_by_classifier(prob_dict): - classifiers_names = ["lc_classifier", "lc_classifier_top", "stamp_classifier", "LC_classifier_BHRF_forced_phot(beta)", "LC_classifier_ATAT_forced_phot(beta)"] - group_data_dict = {} - aux_data_arr = [] + group_data_dict_by_classifier = {} + + for key, value in prob_dict.items(): + classifier_name = value['classifier_name'] + if classifier_name not in group_data_dict_by_classifier: + group_data_dict_by_classifier[classifier_name] = {} + group_data_dict_by_classifier[classifier_name][key] = value - for classifier in classifiers_names: - for key, value in prob_dict.items(): - if value["classifier_name"] == classifier: - aux_data_arr.append(value) - group_data_dict[classifier] = aux_data_arr - aux_data_arr = [] - return group_data_dict + return group_data_dict_by_classifier + + + +def group_data_by_classifier_dict(prob_lis): + group_data_by_classifier = {} + + for item in prob_lis: + aux_dict = { + 'classifier_name': item.classifier_name, + 'classifier_version': item.classifier_version, + 'class_name': item.class_name, + 'probability': item.probability, + 'ranking': item.ranking, + } + classifier_name = item.classifier_name + classifier_version = item.classifier_version + if item.classifier_name not in group_data_by_classifier: + group_data_by_classifier[classifier_name] = {} + + if classifier_version not in group_data_by_classifier[classifier_name]: + group_data_by_classifier[classifier_name][classifier_version]= [] + + group_data_by_classifier[classifier_name][classifier_version].append(aux_dict) + + pprint.pprint(group_data_by_classifier) + return group_data_by_classifier @router.get("/probabilities/{oid}", response_class=HTMLResponse) async def object_probability_app( @@ -89,11 +114,16 @@ async def object_probability_app( prob_list = get_probabilities(oid,session_factory = request.app.state.psql_session) taxonomy_list = get_taxonomies(session_factory = request.app.state.psql_session) + + group_prob = group_data_by_classifier_dict(prob_list) taxonomy_dict, prob_dict = prob_filter(prob_list, taxonomy_list) + #filtered_taxonomy = filter_classifier_name_taxonomy(taxonomy_dict) + filtered_taxonomy = eliminated_duplicates_by_higher_version(taxonomy_dict) + group_prob_dict = group_data_by_classifier(prob_dict) - filtered_taxonomy = filter_classifier_name_taxonomy(taxonomy_dict) + #group_data_by_version(group_prob_dict) return templates.TemplateResponse( name='prob.html.jinja', diff --git a/lightcurve/src/probability_api/templates/prob.html.jinja b/lightcurve/src/probability_api/templates/prob.html.jinja index ccea7fa7a..e0ff26c6b 100644 --- a/lightcurve/src/probability_api/templates/prob.html.jinja +++ b/lightcurve/src/probability_api/templates/prob.html.jinja @@ -2,8 +2,8 @@ -
-
+
+
- - - + {% for key, value in class_dict.items() %} + + {% endfor %} +
@@ -24,22 +25,16 @@
+
- - - {% for key, value in class_dict.items() %} - + + {% for x in class_dict %} + {% for key, value in x.items() %} + + {% endfor %} {% endfor %}
-
+
+ + + + + \ No newline at end of file diff --git a/lightcurve/src/probability_api/templates/probabilitiesCard.html.jinja b/lightcurve/src/probability_api/templates/probabilitiesCard.html.jinja deleted file mode 100644 index 7af02cb90..000000000 --- a/lightcurve/src/probability_api/templates/probabilitiesCard.html.jinja +++ /dev/null @@ -1,301 +0,0 @@ - - - - -
- -
-
- -
- - -
- -
- -
- -
- -
- -
-
- -
- - \ No newline at end of file From 789b0d1ec0c40748fd2590304eae126f14ad8ca4 Mon Sep 17 00:00:00 2001 From: Demurest Date: Thu, 3 Oct 2024 18:02:09 -0300 Subject: [PATCH 07/39] radar --- lightcurve/src/probability_api/routes/htmx.py | 23 +- .../probability_api/static/probability.css | 91 ++++++-- .../src/probability_api/static/probability.js | 25 ++- .../probability_api/templates/prob.html.jinja | 204 +----------------- 4 files changed, 111 insertions(+), 232 deletions(-) diff --git a/lightcurve/src/probability_api/routes/htmx.py b/lightcurve/src/probability_api/routes/htmx.py index f8fc6c275..582df104d 100644 --- a/lightcurve/src/probability_api/routes/htmx.py +++ b/lightcurve/src/probability_api/routes/htmx.py @@ -80,8 +80,10 @@ def group_data_by_classifier_dict(prob_lis): return group_data_by_classifier -def classifiers_options(taxonomy_dict): - class_dict = [None for x in range(5)] +def classifiers_options(taxonomy_dict, group_prob_by_version): + class_dict = [] + priorities_arr = [] + non_priotities_arr = [] priorities = { 'lc_classifier': 0, 'lc_classifier_top': 1, @@ -90,13 +92,17 @@ def classifiers_options(taxonomy_dict): 'LC_classifier_BHRF_forced_phot(beta)': 4, } - for key in taxonomy_dict.keys(): - if key in priorities: - index = priorities[key] - class_dict[index] = { key : format_classifiers_name(key) } - else: + for key, value in priorities.items(): + if key in group_prob_by_version: class_dict.append({ key : format_classifiers_name(key) }) + + for key in group_prob_by_version.keys(): + if key not in priorities: + non_priotities_arr.append({ key : format_classifiers_name(key) }) + + class_dict = class_dict + non_priotities_arr + return class_dict def format_classifiers_name(classifier_name): @@ -113,12 +119,11 @@ async def object_probability_app( taxonomy_list = get_taxonomies(session_factory = request.app.state.psql_session) taxonomy_dict = taxonomy_data(taxonomy_list) - class_options = classifiers_options(taxonomy_dict) - group_prob = group_data_by_classifier_dict(prob_list) group_prob_by_version = filter_data_by_higher_version(group_prob) + class_options = classifiers_options(taxonomy_dict, group_prob_by_version) return templates.TemplateResponse( name='prob.html.jinja', diff --git a/lightcurve/src/probability_api/static/probability.css b/lightcurve/src/probability_api/static/probability.css index 2ddb2bbd7..758d94b60 100644 --- a/lightcurve/src/probability_api/static/probability.css +++ b/lightcurve/src/probability_api/static/probability.css @@ -63,6 +63,11 @@ margin-right: 0.5rem; } +.tw-preflight :is(.tw-mx-4) { + margin-left: 1rem; + margin-right: 1rem; +} + .tw-preflight :is(.tw-mx-auto) { margin-left: auto; margin-right: auto; @@ -81,6 +86,10 @@ margin-left: 0.5rem; } +.tw-preflight :is(.tw-ml-4) { + margin-left: 1rem; +} + .tw-preflight :is(.tw-ml-\[50\%\]) { margin-left: 50%; } @@ -149,6 +158,10 @@ height: 12.5%; } +.tw-preflight :is(.tw-h-\[30px\]) { + height: 30px; +} + .tw-preflight :is(.tw-h-\[500px\]) { height: 500px; } @@ -189,12 +202,12 @@ width: 100%; } -.tw-preflight :is(.tw-w-\[400px\]) { - width: 400px; +.tw-preflight :is(.tw-w-\[30px\]) { + width: 30px; } -.tw-preflight :is(.tw-w-\[80\%\]) { - width: 80%; +.tw-preflight :is(.tw-w-\[400px\]) { + width: 400px; } .tw-preflight :is(.tw-w-\[95\%\]) { @@ -374,6 +387,10 @@ border-width: 1px; } +.tw-preflight :is(.tw-border-0) { + border-width: 0px; +} + .tw-preflight :is(.tw-border-8) { border-width: 8px; } @@ -470,6 +487,10 @@ background-color: rgb(255 255 255 / var(--tw-bg-opacity)); } +.tw-preflight :is(.tw-bg-\[\#1e1e1e\]\/25) { + background-color: rgb(30 30 30 / 0.25); +} + .tw-preflight :is(.tw-p-2) { padding: 0.5rem; } @@ -622,6 +643,24 @@ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.tw-preflight :is(.tw-shadow) { + --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.tw-preflight :is(.tw-shadow-lg) { + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.tw-preflight :is(.tw-shadow-none) { + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + .tw-preflight :is(.tw-duration-200) { transition-duration: 200ms; } @@ -1218,6 +1257,15 @@ Constrain images and videos to the parent width and preserve their intrinsic asp cursor: pointer; } +.tw-preflight :is(.hover\:tw-border-b-white:hover) { + --tw-border-opacity: 1; + border-bottom-color: rgb(255 255 255 / var(--tw-border-opacity)); +} + +.tw-preflight :is(.hover\:tw-bg-\[\#1e1e1e\]\/25:hover) { + background-color: rgb(30 30 30 / 0.25); +} + .tw-preflight :is(.hover\:tw-bg-\[\#757575\]:hover) { --tw-bg-opacity: 1; background-color: rgb(117 117 117 / var(--tw-bg-opacity)); @@ -1248,11 +1296,30 @@ Constrain images and videos to the parent width and preserve their intrinsic asp background-color: rgb(21 128 61 / var(--tw-bg-opacity)); } +.tw-preflight :is(.hover\:tw-bg-\[\#1e1e1e\]:hover) { + --tw-bg-opacity: 1; + background-color: rgb(30 30 30 / var(--tw-bg-opacity)); +} + .tw-preflight :is(.hover\:tw-text-gray-600:hover) { --tw-text-opacity: 1; color: rgb(75 85 99 / var(--tw-text-opacity)); } +.tw-preflight :is(.focus\:tw-bg-\[\#1e1e1e\]:focus) { + --tw-bg-opacity: 1; + background-color: rgb(30 30 30 / var(--tw-bg-opacity)); +} + +.tw-preflight :is(.active\:tw-bg-\[\#1976D2\]\/25:active) { + background-color: rgb(25 118 210 / 0.25); +} + +.tw-preflight :is(.active\:tw-text-\[\#1976D2\]:active) { + --tw-text-opacity: 1; + color: rgb(25 118 210 / var(--tw-text-opacity)); +} + .tw-preflight :is(.disabled\:tw-bg-transparent:disabled) { background-color: transparent; } @@ -1333,18 +1400,10 @@ Constrain images and videos to the parent width and preserve their intrinsic asp } @media (min-width: 640px) { - .tw-preflight :is(.sm\:tw-h-\[10\%\]) { - height: 10%; - } - .tw-preflight :is(.sm\:tw-h-\[100\%\]) { height: 100%; } - .tw-preflight :is(.sm\:tw-w-\[10\%\]) { - width: 10%; - } - .tw-preflight :is(.sm\:tw-w-\[100\%\]) { width: 100%; } @@ -1355,15 +1414,7 @@ Constrain images and videos to the parent width and preserve their intrinsic asp height: 80%; } - .tw-preflight :is(.md\:tw-h-\[100\%\]) { - height: 100%; - } - .tw-preflight :is(.md\:tw-w-\[80\%\]) { width: 80%; } - - .tw-preflight :is(.md\:tw-w-\[100\%\]) { - width: 100%; - } } \ No newline at end of file diff --git a/lightcurve/src/probability_api/static/probability.js b/lightcurve/src/probability_api/static/probability.js index 8957a2b41..bd52b4142 100644 --- a/lightcurve/src/probability_api/static/probability.js +++ b/lightcurve/src/probability_api/static/probability.js @@ -43,7 +43,10 @@ let config = { color: '#000000', }, pointLabels: { - color: '#000000' + color: '#000000', + font: { + size: 14 + } }, beginAtZero: true, max: 1 @@ -57,16 +60,19 @@ let config = { enabled: true, mode: 'dataset', position: 'nearest', + titleFont: { + weight: 'bold' + }, callbacks: { title: function(){ - return "Probability" + return "Probabilities (score)" }, label: function(context){ let tooltipslabels = [] let label = "" label = context.label + ": " + context.parsed.r tooltipslabels.push(label) - return tooltipslabels + return label } } } @@ -81,18 +87,19 @@ export function init(){ let ctx = document.getElementById('myChart'); let select = document.getElementById('selectClassifier') - //checkear reverseData(raw_tax) probability_data_aux = [] mychart = new Chart(ctx, config); + updateMyChart(select.value, raw_tax, raw_group_prob_dict) + + select.addEventListener('change', (e) => { updateMyChart(e.target.value, raw_tax, raw_group_prob_dict) }) } - function reverseData(raw_tax){ let aux_arr = [] @@ -170,10 +177,10 @@ function updateDataChart(labels, max_value){ function isDark(){ if(document.getElementById("probabilities-app").classList.contains("tw-dark")){ - mychart.config.options.scales.r.backgroundColor = '#BDBDBD' - mychart.config.options.scales.r.angleLines.color = '#EEEEEE' - mychart.config.options.scales.r.grid.color = '#EEEEEE' - mychart.config.options.scales.r.pointLabels.color = '#EEEEEE' + mychart.config.options.scales.r.backgroundColor = 'rgba(245, 245, 245, 0.2)' + mychart.config.options.scales.r.angleLines.color = '#F5F5F5' + mychart.config.options.scales.r.grid.color = '#F5F5F5' + mychart.config.options.scales.r.pointLabels.color = '#F5F5F5' mychart.update(); } diff --git a/lightcurve/src/probability_api/templates/prob.html.jinja b/lightcurve/src/probability_api/templates/prob.html.jinja index 4f6c72e2f..c8d5c6b6a 100644 --- a/lightcurve/src/probability_api/templates/prob.html.jinja +++ b/lightcurve/src/probability_api/templates/prob.html.jinja @@ -4,13 +4,18 @@
-
+
- + {% for x in class_dict %} {% for key, value in x.items() %} @@ -39,193 +44,4 @@ import { init } from "{{API_URL}}/static/probability.js"; "taxonomy_dict": {{taxonomy_dict | tojson}}, "group_prob_dict": {{group_prob_dict | tojson}} } - - - \ No newline at end of file From 6d86ac2ea83ff52bb8f5603a06a534b6d405c92d Mon Sep 17 00:00:00 2001 From: Demurest Date: Fri, 4 Oct 2024 12:43:28 -0300 Subject: [PATCH 08/39] labels order tooltip --- .../src/probability_api/static/probability.js | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lightcurve/src/probability_api/static/probability.js b/lightcurve/src/probability_api/static/probability.js index bd52b4142..ca3348913 100644 --- a/lightcurve/src/probability_api/static/probability.js +++ b/lightcurve/src/probability_api/static/probability.js @@ -58,7 +58,7 @@ let config = { }, tooltip: { enabled: true, - mode: 'dataset', + mode: 'index', position: 'nearest', titleFont: { weight: 'bold' @@ -68,15 +68,23 @@ let config = { return "Probabilities (score)" }, label: function(context){ - let tooltipslabels = [] - let label = "" - label = context.label + ": " + context.parsed.r - tooltipslabels.push(label) - return label + let tooltipText = []; + let length = context.dataset.data.length - 1 + let data = context.dataset.data + let labels = context.chart.data.labels + + tooltipText.push(`${labels[0]}: ${data[0]}`) + + for (let index = length; index >= 1; index--){ + tooltipText.push(`${labels[index]}: ${data[index]}`) + } + + return tooltipText } } } }, + } } From 74d5e17fe2ad5a28d448b197b6392937c1eda43e Mon Sep 17 00:00:00 2001 From: Demurest Date: Fri, 4 Oct 2024 12:58:06 -0300 Subject: [PATCH 09/39] fixed number 3 decimasl --- lightcurve/src/magstats_api/static/magstats.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lightcurve/src/magstats_api/static/magstats.js b/lightcurve/src/magstats_api/static/magstats.js index de3bf9004..5dfec612b 100644 --- a/lightcurve/src/magstats_api/static/magstats.js +++ b/lightcurve/src/magstats_api/static/magstats.js @@ -116,15 +116,15 @@ function parseStatR(dict) { corrected: dict[key]["corrected"], ndet: dict[key]["ndet"], ndubious: dict[key]["ndubious"], - magmean: dict[key]["magmean"], - magmedian: dict[key]["magmedian"], - magmax: dict[key]["magmax"], - magmin: dict[key]["magmin"], - magsigma: dict[key]["magsigma"], - maglast: dict[key]["maglast"], - magfirst: dict[key]["magfirst"], - firstmjd: dict[key]["firstmjd"], - lastmjd: dict[key]["lastmjd"], + magmean: dict[key]["magmean"].toFixed(3), + magmedian: dict[key]["magmedian"].toFixed(3), + magmax: dict[key]["magmax"].toFixed(3), + magmin: dict[key]["magmin"].toFixed(3), + magsigma: dict[key]["magsigma"].toFixed(3), + maglast: dict[key]["maglast"].toFixed(3), + magfirst: dict[key]["magfirst"].toFixed(3), + firstmjd: dict[key]["firstmjd"].toFixed(3), + lastmjd: dict[key]["lastmjd"].toFixed(3), step_id_corr: dict[key]["step_id_corr"], }; numBands.push(dict[key]["fid"]); From 5f84242de5f52d92a0414097f4afbb42eb4d4fa6 Mon Sep 17 00:00:00 2001 From: Demurest Date: Fri, 4 Oct 2024 14:57:30 -0300 Subject: [PATCH 10/39] process --- lightcurve/src/object_api/routes/htmx.py | 4 + lightcurve/src/object_api/static/object.css | 122 ++++-------------- .../basicInformationPreview.html.jinja | 39 ++++-- 3 files changed, 61 insertions(+), 104 deletions(-) diff --git a/lightcurve/src/object_api/routes/htmx.py b/lightcurve/src/object_api/routes/htmx.py index f1c32d89d..d4d2bcd2f 100644 --- a/lightcurve/src/object_api/routes/htmx.py +++ b/lightcurve/src/object_api/routes/htmx.py @@ -88,6 +88,9 @@ async def object_info_app(request: Request, oid: str): object_data = get_object(oid, request.app.state.psql_session) candid = get_first_det_candid(oid, request.app.state.psql_session) count_ndet = get_count_ndet(oid, request.app.state.psql_session) + + other_archives = ['DESI Legacy Survey DR10', 'NED', 'PanSTARRS', 'SDSS DR18', 'SIMBAD', 'TNS', 'Vizier', 'VSX'] + except ObjectNotFound: raise HTTPException(status_code=404, detail="Object ID not found") @@ -106,6 +109,7 @@ async def object_info_app(request: Request, oid: str): "ra": object_data.meanra, "dec": object_data.meandec, "candid": candid, + "otherArchives": other_archives, }, ) diff --git a/lightcurve/src/object_api/static/object.css b/lightcurve/src/object_api/static/object.css index c85c5137e..966cb8187 100644 --- a/lightcurve/src/object_api/static/object.css +++ b/lightcurve/src/object_api/static/object.css @@ -14,10 +14,6 @@ position: relative; } -.tw-preflight :is(.tw-bottom-0) { - bottom: 0px; -} - .tw-preflight :is(.tw-left-10) { left: 2.5rem; } @@ -77,10 +73,6 @@ margin-bottom: 1rem; } -.tw-preflight :is(.tw-mb-\[20px\]) { - margin-bottom: 20px; -} - .tw-preflight :is(.tw-me-2) { margin-inline-end: 0.5rem; } @@ -93,6 +85,10 @@ margin-left: 50%; } +.tw-preflight :is(.tw-mr-4) { + margin-right: 1rem; +} + .tw-preflight :is(.tw-mt-2) { margin-top: 0.5rem; } @@ -101,20 +97,12 @@ margin-top: 0.75rem; } -.tw-preflight :is(.tw-mt-\[10px\]) { - margin-top: 10px; -} - -.tw-preflight :is(.tw-mt-\[30px\]) { - margin-top: 30px; -} - .tw-preflight :is(.tw-mt-4) { margin-top: 1rem; } -.tw-preflight :is(.tw-mr-4) { - margin-right: 1rem; +.tw-preflight :is(.tw-mt-\[30px\]) { + margin-top: 30px; } .tw-preflight :is(.tw-box-content) { @@ -137,10 +125,6 @@ display: none; } -.tw-preflight :is(.tw-h-11) { - height: 2.75rem; -} - .tw-preflight :is(.tw-h-32) { height: 8rem; } @@ -153,6 +137,10 @@ height: 1.5rem; } +.tw-preflight :is(.tw-h-8) { + height: 2rem; +} + .tw-preflight :is(.tw-h-\[100\%\]) { height: 100%; } @@ -169,22 +157,6 @@ height: auto; } -.tw-preflight :is(.tw-h-10) { - height: 2.5rem; -} - -.tw-preflight :is(.tw-h-9) { - height: 2.25rem; -} - -.tw-preflight :is(.tw-h-8) { - height: 2rem; -} - -.tw-preflight :is(.tw-h-1) { - height: 0.25rem; -} - .tw-preflight :is(.tw-w-1\/3) { width: 33.333333%; } @@ -229,6 +201,14 @@ width: 100%; } +.tw-preflight :is(.tw-w-\[50\%\]) { + width: 50%; +} + +.tw-preflight :is(.tw-w-\[1\%\]) { + width: 1%; +} + .tw-preflight :is(.tw-min-w-full) { min-width: 100%; } @@ -239,22 +219,16 @@ .tw-preflight :is(.-tw-translate-y-1) { --tw-translate-y: -0.25rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } .tw-preflight :is(.-tw-translate-y-1\/2) { --tw-translate-y: -50%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } .tw-preflight :is(.tw-transform) { - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } @keyframes tw-spin { @@ -273,8 +247,8 @@ .tw-preflight :is(.tw-appearance-none) { -webkit-appearance: none; - -moz-appearance: none; - appearance: none; + -moz-appearance: none; + appearance: none; } .tw-preflight :is(.tw-grid-cols-10) { @@ -297,10 +271,6 @@ place-items: center; } -.tw-preflight :is(.tw-content-end) { - align-content: flex-end; -} - .tw-preflight :is(.tw-items-center) { align-items: center; } @@ -354,14 +324,6 @@ place-self: center; } -.tw-preflight :is(.tw-self-end) { - align-self: flex-end; -} - -.tw-preflight :is(.tw-self-center) { - align-self: center; -} - .tw-preflight :is(.tw-overflow-auto) { overflow: auto; } @@ -540,10 +502,6 @@ padding-left: 10px; } -.tw-preflight :is(.tw-pl-\[5px\]) { - padding-left: 5px; -} - .tw-preflight :is(.tw-pr-2) { padding-right: 0.5rem; } @@ -560,10 +518,6 @@ padding-top: 25px; } -.tw-preflight :is(.tw-pt-\[30px\]) { - padding-top: 30px; -} - .tw-preflight :is(.tw-text-left) { text-align: left; } @@ -606,9 +560,7 @@ .tw-preflight :is(.tw-ordinal) { --tw-ordinal: ordinal; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) - var(--tw-numeric-figure) var(--tw-numeric-spacing) - var(--tw-numeric-fraction); + font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction); } .tw-preflight :is(.tw-text-\[\#1e1e1e\]) { @@ -666,8 +618,7 @@ .tw-preflight :is(.tw-shadow-2xl) { --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), - var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } .tw-preflight :is(.tw-duration-200) { @@ -1103,8 +1054,7 @@ Prevent resizing textareas horizontally by default. /* 2 */ } -.tw-preflight input::-moz-placeholder, -.tw-preflight textarea::-moz-placeholder { +.tw-preflight input::-moz-placeholder, .tw-preflight textarea::-moz-placeholder { opacity: 1; /* 1 */ color: #9ca3af; @@ -1325,10 +1275,6 @@ Constrain images and videos to the parent width and preserve their intrinsic asp color: rgb(75 85 99 / var(--tw-text-opacity)); } -.tw-preflight :is(.hover\:tw-opacity-70:hover) { - opacity: 0.7; -} - .tw-preflight :is(.disabled\:tw-bg-transparent:disabled) { background-color: transparent; } @@ -1345,16 +1291,7 @@ Constrain images and videos to the parent width and preserve their intrinsic asp display: flex; } -.tw-preflight :is(.tw-group:hover .group-hover\:tw-opacity-60) { - opacity: 0.6; -} - -.tw-preflight - :is( - :is(.tw-dark .dark\:tw-divide-\[\#404040\]) - > :not([hidden]) - ~ :not([hidden]) - ) { +.tw-preflight :is(:is(.tw-dark .dark\:tw-divide-\[\#404040\]) > :not([hidden]) ~ :not([hidden])) { --tw-divide-opacity: 1; border-color: rgb(64 64 64 / var(--tw-divide-opacity)); } @@ -1369,11 +1306,6 @@ Constrain images and videos to the parent width and preserve their intrinsic asp border-color: rgb(255 255 255 / var(--tw-border-opacity)); } -.tw-preflight :is(.tw-dark .dark\:tw-border-b-white) { - --tw-border-opacity: 1; - border-bottom-color: rgb(255 255 255 / var(--tw-border-opacity)); -} - .tw-preflight :is(.tw-dark .dark\:tw-border-opacity-20) { --tw-border-opacity: 0.2; } diff --git a/lightcurve/src/object_api/templates/basicInformationPreview.html.jinja b/lightcurve/src/object_api/templates/basicInformationPreview.html.jinja index 4e5cdb764..8374bfc47 100644 --- a/lightcurve/src/object_api/templates/basicInformationPreview.html.jinja +++ b/lightcurve/src/object_api/templates/basicInformationPreview.html.jinja @@ -140,16 +140,36 @@
- - FINDING CHART - - +
+ + FINDING CHART + + +
+
+ OTHER ARCHIVES - + + + +
-