Source code for visualization_toolkit.helpers.dash.core

import json
import os
from urllib.parse import urljoin

from dash import Dash, dcc, callback_context, _validate
from dash._pages import _page_meta_tags
from dash._utils import interpolate_str, format_tag
from dash.version import __version__
from dash.dash import (
    _re_index_entry_id,
    _re_index_config_id,
    _re_index_scripts_id,
    _re_renderer_scripts_id,
)

from visualization_toolkit.constants import APP_ENVIRONMENT
from visualization_toolkit.helpers.plotly.theme import FONT_URLS


ATLAS_CDN_HOST = APP_ENVIRONMENT.get(
    "ATLAS_CDN_HOST", "https://atlas-assets.yipitdata.com"
)


class CustomDash(Dash):
    _app_entry = """
    <div id="react-entry-point">
        <style>
            ._dash-loading {
                display: none !important;
            }
        </style>
        <div class="_dash-loading">
        </div>
    </div>
    """

    def index(self, *args, **kwargs):  # pylint: disable=unused-argument
        scripts = self._generate_scripts_html()
        css = self._generate_css_dist_html()
        config = self._generate_config_html()
        metas = self._generate_meta()
        renderer = self._generate_renderer()

        # use self.title instead of app.config.title for backwards compatibility
        title = self.title

        if self.use_pages and self.config.include_pages_meta:
            metas = _page_meta_tags(self) + metas

        if self._favicon:
            favicon_mod_time = os.path.getmtime(
                os.path.join(self.config.assets_folder, self._favicon)
            )
            favicon_url = f"{self.get_asset_url(self._favicon)}?m={favicon_mod_time}"
        else:
            prefix = self.config.requests_pathname_prefix
            favicon_url = f"{prefix}_favicon.ico?v={__version__}"

        favicon = format_tag(
            "link",
            {"rel": "icon", "type": "image/x-icon", "href": favicon_url},
            opened=True,
        )

        tags = "\n      ".join(
            format_tag("meta", x, opened=True, sanitize=True) for x in metas
        )

        index = self.interpolate_index(
            metas=tags,
            title=title,
            css=css,
            config=config,
            scripts=scripts,
            app_entry=self._app_entry,
            favicon=favicon,
            renderer=renderer,
        )

        checks = (
            _re_index_entry_id,
            _re_index_config_id,
            _re_index_scripts_id,
            _re_renderer_scripts_id,
        )
        _validate.validate_index("index", checks, index)
        return index


[docs] def initialize_app( name: str, **kwargs, ) -> CustomDash: """ Intialize a Dash app with settings tuned for production scenarios. Settings enabled: * Load Google fonts for use with YD theme * Load custom plotly bundle to reduce bundle size * Enable compression of JS assets served * Use CDN when serving static files (enabled when DEBUG mode is off) * Change base html file to remove unnecessary CSS styles :param name: Name of the dash app to initialize :param kwargs: Optional kwargs that will be passed to the `Dash` class instance :return: `CustomDash` instance that is a subclass of `Dash` """ # Pop off external_stylesheets and add them to the end when starting the dash app if "external_stylesheets" in kwargs: external_stylesheets = kwargs.pop("external_stylesheets") else: external_stylesheets = [] if "external_scripts" in kwargs: external_scripts = kwargs.pop("external_scripts") else: external_scripts = [] app = CustomDash( name, external_stylesheets=FONT_URLS + external_stylesheets, external_scripts=external_scripts, update_title="", serve_locally=False, compress=True, **kwargs, ) return app
[docs] def get_triggered_id(index: int = 0) -> str | dict: """ Returns the HTML ID for the triggered element within a dash callback :param index: index of triggered input element to get ID for. Defaults to 0 or first triggered eement :return: str """ ctx = callback_context trigger_id = ctx.triggered[index]["prop_id"].split(".")[0] # For pattern-matching callbacks, trigger id is in nested JSON, return as dict if trigger_id.startswith("{"): parsed_id = json.loads(trigger_id) else: parsed_id = trigger_id return parsed_id
[docs] def resolve_html_id(component: str | dict) -> str: """ Returns the true HTML ID for a given component, ID, or patten-matching ID This can be useful when working in JS, as Dash will sometimes mutate the ID passed in to a component :param component: Input element or string to generate the HTML ID :return: """ if isinstance(component, str): return component elif isinstance(component, dict): return json.dumps(component, sort_keys=True, separators=(",", ":")) else: return getattr(component, "id")