from __future__ import annotations from typing import Any import gradio as gr import pandas as pd import plotly.graph_objects as go from analytics import ( AnalyticsStore, Snapshot, aggregate_period_metrics, available_categories, available_market_types, available_months, filter_metrics, ) STORE = AnalyticsStore() COLORS = { "ink": "#102A43", "muted": "#627D98", "cyan": "#00A6A6", "blue": "#2563EB", "amber": "#F59E0B", "grid": "#E6EDF5", } CSS = """ .hero { align-items: center !important; gap: 16px !important; border-radius: 18px; padding: 20px 24px; margin-bottom: 10px; color: white; background: radial-gradient(circle at 90% 15%, rgba(45, 212, 191, .33), transparent 28%), linear-gradient(125deg, #102a43 0%, #163f66 52%, #0f766e 100%); box-shadow: 0 12px 32px rgba(16, 42, 67, .16); } .hero, .hero h1, .hero p { color: #ffffff !important; -webkit-text-fill-color: #ffffff !important; } .hero-copy { padding: 0 !important; } .hero-copy h1 { margin: 0; font-size: clamp(1.55rem, 3vw, 2rem); letter-spacing: -.03em; line-height: 1.08; } .hero-copy p { margin: 6px 0 0; color: #d9f4f0 !important; font-size: .92rem; } .mobile-title { display: none; } .hero-refresh { align-self: center !important; flex: 0 0 auto !important; min-width: 112px !important; min-height: 40px !important; border: 1px solid rgba(255, 255, 255, .8) !important; background: #102a43 !important; color: #ffffff !important; -webkit-text-fill-color: #ffffff !important; font-weight: 700 !important; box-shadow: 0 8px 20px rgba(7, 29, 43, .22) !important; } .hero-refresh * { color: #ffffff !important; -webkit-text-fill-color: #ffffff !important; opacity: 1 !important; } .hero-refresh:hover { border-color: #ffffff !important; background: #0f766e !important; color: #ffffff !important; -webkit-text-fill-color: #ffffff !important; } .kpi-grid { display: grid; grid-template-columns: repeat(5, minmax(150px, 1fr)); align-items: stretch; gap: 10px; margin: 2px 0 10px; } .kpi { box-sizing: border-box; height: 100%; min-height: 92px; display: flex; flex-direction: column; justify-content: space-between; background: white; border: 1px solid #e6edf5; border-radius: 14px; padding: 13px 15px; box-shadow: 0 6px 18px rgba(16, 42, 67, .05); } .kpi-label { color: #627d98; font-size: .74rem; line-height: 1.2; text-transform: uppercase; letter-spacing: .06em; } .kpi-value { color: #102a43; font-size: 1.35rem; font-weight: 750; line-height: 1.15; margin-top: 6px; } .control-row { display: grid !important; grid-template-columns: repeat(6, minmax(0, 1fr)); align-items: end !important; gap: 10px !important; margin-bottom: 2px; } .control-row > * { width: 100% !important; min-width: 0 !important; } .control-row > .form { display: contents !important; } .filter-control { min-width: 0 !important; padding: 7px 9px !important; } .filter-control .container > span { display: block !important; height: auto !important; margin: 0 0 3px !important; padding: 0 !important; overflow: hidden; color: #627d98 !important; background: transparent !important; font-size: .72rem !important; font-weight: 600 !important; line-height: 1.2 !important; text-overflow: ellipsis; white-space: nowrap; } .kpi-host .html-container { padding: 0 !important; } .section-title { color: #102a43; margin: 10px 0 0 !important; padding: 0 !important; min-height: 0 !important; } .section-title h3 { margin: 0 !important; font-size: 1rem !important; line-height: 1.3 !important; } .chart-row { gap: 10px !important; } .chart { overflow: hidden !important; border-radius: 14px !important; } .chart .modebar-container, .chart .modebar { display: none !important; } .chart .js-plotly-plot { touch-action: pan-y !important; } .status-line { color: #627d98 !important; font-size: .88rem; -webkit-text-fill-color: #627d98 !important; } .status-line :is(p, strong, em, span), .metric-note :is(p, strong, em, span) { color: #627d98 !important; -webkit-text-fill-color: #627d98 !important; } .metric-note { color: #627d98 !important; -webkit-text-fill-color: #627d98 !important; } .status-line code, .metric-note code { color: #fff !important; background: #102a43 !important; -webkit-text-fill-color: #fff !important; } @media (max-width: 900px) { .control-row { grid-template-columns: repeat(3, minmax(0, 1fr)); } .kpi-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } } @media (max-width: 640px) { html, body { overflow-x: hidden !important; } .gradio-container .contain > .column { gap: 8px !important; } .hero { display: grid !important; grid-template-columns: minmax(0, 1fr) auto; align-items: center !important; gap: 8px !important; padding: 14px 14px !important; margin-bottom: 6px; border-radius: 14px; box-shadow: 0 8px 22px rgba(16, 42, 67, .14); } .hero > * { width: auto !important; min-width: 0 !important; } .desktop-title { display: none; } .mobile-title { display: inline; } .hero-copy h1 { font-size: 1.35rem; white-space: nowrap; } .hero-copy p { margin-top: 4px; font-size: .76rem; line-height: 1.3; } .hero-refresh { width: auto !important; min-width: 76px !important; min-height: 40px !important; padding: 0 10px !important; font-size: .82rem !important; box-shadow: none !important; } .control-row { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 8px !important; margin: 0 !important; } .control-row label { font-size: .72rem !important; margin-bottom: 2px !important; } .control-row input { font-size: .86rem !important; } .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; margin: 6px 0 8px; } .kpi { min-height: 72px; border-radius: 11px; padding: 9px 11px; box-shadow: 0 4px 12px rgba(16, 42, 67, .04); } .kpi-label { font-size: .65rem; line-height: 1.15; letter-spacing: .04em; } .kpi-value { margin-top: 3px; font-size: 1.05rem; } .kpi:last-child { grid-column: 1 / -1; } .section-title { margin-top: 8px !important; } .section-title h3 { font-size: .92rem !important; } .chart-row { display: grid !important; grid-template-columns: minmax(0, 1fr); gap: 8px !important; } .chart-row > .form { display: contents !important; } .chart-row > * { width: 100% !important; min-width: 0 !important; } .chart { min-width: 0 !important; border-radius: 11px !important; } .chart .js-plotly-plot, .chart .plot-container, .chart .svg-container { height: 300px !important; min-height: 300px !important; } .status-line { font-size: .72rem; } } """ HEAD = """ """ THEME = gr.themes.Soft( primary_hue="teal", secondary_hue="blue", neutral_hue="slate", ) ENGLISH = "English" CHINESE = "中文" LANGUAGES = (ENGLISH, CHINESE) TEXT = { ENGLISH: { "hero_subtitle": ( "V1 + V2 exchange activity on Polygon · " "yearly, quarterly, monthly, and daily analytics" ), "version": "Protocol version", "market": "Market type", "category": "Category", "year": "Daily detail year", "calendar_month": "Daily detail month", "refresh": "↻ Refresh", "yearly_section": "### Yearly data", "quarterly_section": "### Quarterly data", "daily_section": "### Daily detail", "monthly_section": "### Monthly data", "monthly_table_section": "### Monthly detail", "category_section": "### Category comparison", "metric_note": ( "**Metric note.** Nominal collateral volume is derived from the " "collateral leg of each `OrderFilled` event and is not the same " "as Polymarket's official reported volume. All dates are UTC." ), "yearly_volume_title": "Yearly nominal collateral volume", "yearly_fills_title": "Yearly OrderFilled events", "quarterly_volume_title": "Quarterly nominal collateral volume", "quarterly_fills_title": "Quarterly OrderFilled events", "volume_title": "Monthly nominal collateral volume", "fills_title": "Monthly OrderFilled events", "daily_volume_title": "Daily nominal volume", "daily_fills_title": "Daily fill events", "category_volume_title": "Nominal volume by category", "category_fills_title": "Fill events by category", "empty": "No data for this selection", "kpis": ( "Fill events", "Unique transactions", "Nominal volume", "Fees", "Daily detail", ), "columns": ( "Month", "Fill events", "Unique transactions", "Nominal volume", "Fees", "Complete", ), "generated": "Source generated", "refreshed": "Dashboard refreshed", }, CHINESE: { "hero_subtitle": ( "Polygon 上的 V1 + V2 成交活动 · 年度、季度、月度与每日分析" ), "version": "协议版本", "market": "市场类型", "category": "分类", "year": "按日查看年份", "calendar_month": "按日查看月份", "refresh": "↻ 刷新", "yearly_section": "### 年度数据", "quarterly_section": "### 季度数据", "daily_section": "### 每日明细", "monthly_section": "### 月度数据", "monthly_table_section": "### 月度明细", "category_section": "### 分类对比", "metric_note": ( "**指标说明:** 名义抵押金额来自每个 `OrderFilled` 事件的抵押" "资产腿,不等同于 Polymarket 官方公布的 Volume。所有日期均为 UTC。" ), "yearly_volume_title": "每年名义抵押金额", "yearly_fills_title": "每年成交事件", "quarterly_volume_title": "每季度名义抵押金额", "quarterly_fills_title": "每季度成交事件", "volume_title": "每月名义抵押金额", "fills_title": "每月成交事件", "daily_volume_title": "每日名义金额", "daily_fills_title": "每日成交事件", "category_volume_title": "各分类名义金额", "category_fills_title": "各分类成交事件", "empty": "当前筛选条件没有数据", "kpis": ( "成交事件", "唯一交易", "名义金额", "手续费", "按日月份", ), "columns": ( "月份", "成交事件", "唯一交易", "名义金额", "手续费", "是否完整", ), "generated": "数据生成时间", "refreshed": "页面刷新时间", }, } VERSION_LABELS = { ENGLISH: {"all": "All", "v1": "V1", "v2": "V2"}, CHINESE: {"all": "全部", "v1": "V1", "v2": "V2"}, } MONTH_LABELS = { ENGLISH: ( "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ), CHINESE: tuple(f"{month}月" for month in range(1, 13)), } MARKET_LABELS = { ENGLISH: { "all": "All", "standard": "Standard", "neg_risk": "Neg Risk", }, CHINESE: { "all": "全部", "standard": "标准市场", "neg_risk": "负风险市场", }, } def normalized_language(language: str | None) -> str: return CHINESE if language == CHINESE else ENGLISH def browser_language(value: str | None) -> str: return CHINESE if str(value).lower().startswith("zh") else ENGLISH def hero_html(language: str) -> str: copy = TEXT[normalized_language(language)] return f"""

Polymarket OrderFilled Analytics Polymarket Analytics

{copy["hero_subtitle"]}

""" def version_choices(language: str) -> list[tuple[str, str]]: labels = VERSION_LABELS[normalized_language(language)] return [(labels[value], value) for value in ("all", "v1", "v2")] def market_choices( values: list[str], language: str, ) -> list[tuple[str, str]]: labels = MARKET_LABELS[normalized_language(language)] return [(labels[value], value) for value in values] def category_choices( snapshot: Snapshot, values: list[str], language: str, ) -> list[tuple[str, str]]: language_key = "zh" if normalized_language(language) == CHINESE else "en" labels = { str(item["key"]): str(item["labels"].get(language_key, item["key"])) for item in snapshot.categories } return [(labels.get(value, value), value) for value in values] def calendar_month_choices( values: list[str], language: str, ) -> list[tuple[str, str]]: labels = MONTH_LABELS[normalized_language(language)] return [(labels[int(value) - 1], value) for value in values] def display_quarters(frame: pd.DataFrame) -> pd.DataFrame: if frame.empty: return frame displayed = frame.copy() displayed["period"] = displayed["period"].str.replace( r"^(\d{4})-Q([1-4])$", r"\1 Q\2", regex=True, ) return displayed def resolve_year_month( available: list[str], selected_year: str | None, selected_calendar_month: str | None, ) -> tuple[list[str], str, list[str], str, str]: years = sorted({value[:4] for value in available}) year = selected_year if selected_year in years else ( years[-1] if years else "" ) calendar_months = [ value[5:7] for value in available if value.startswith(f"{year}-") ] calendar_month = ( selected_calendar_month if selected_calendar_month in calendar_months else (calendar_months[-1] if calendar_months else "") ) combined = ( f"{year}-{calendar_month}" if year and calendar_month else "" ) return years, year, calendar_months, calendar_month, combined def compact_number(value: float) -> str: absolute = abs(value) for divisor, suffix in ( (1_000_000_000_000, "T"), (1_000_000_000, "B"), (1_000_000, "M"), (1_000, "K"), ): if absolute >= divisor: return f"{value / divisor:,.2f}{suffix}" return f"{value:,.0f}" def compact_usd(value: float) -> str: return f"${compact_number(value)}" def empty_figure(title: str, message: str) -> go.Figure: figure = go.Figure() figure.add_annotation( text=message, x=0.5, y=0.5, xref="paper", yref="paper", showarrow=False, font={"color": COLORS["muted"], "size": 15}, ) return style_figure(figure, title) def style_figure(figure: go.Figure, title: str) -> go.Figure: figure.update_layout( title={"text": title, "x": 0.02, "font": {"size": 18}}, paper_bgcolor="white", plot_bgcolor="white", font={"family": "Inter, ui-sans-serif, system-ui", "color": COLORS["ink"]}, margin={"l": 55, "r": 24, "t": 62, "b": 48}, hoverlabel={"bgcolor": COLORS["ink"], "font_color": "white"}, hovermode="closest", dragmode=False, showlegend=False, ) figure.update_xaxes( showgrid=False, linecolor=COLORS["grid"], tickfont={"color": COLORS["muted"]}, fixedrange=True, ) figure.update_yaxes( gridcolor=COLORS["grid"], zeroline=False, tickfont={"color": COLORS["muted"]}, fixedrange=True, ) return figure def bar_figure( frame: pd.DataFrame, x: str, y: str, title: str, color: str, empty_message: str, prefix: str = "", ) -> go.Figure: if frame.empty: return empty_figure(title, empty_message) figure = go.Figure( go.Bar( x=frame[x], y=frame[y], marker={ "color": color, "line": {"width": 0}, }, hovertemplate=( f"%{{x}}
{prefix}%{{y:,.2f}}" if prefix else "%{x}
%{y:,.0f}" ), ) ) return style_figure(figure, title) def category_comparison_figure( frame: pd.DataFrame, metric: str, title: str, color: str, empty_message: str, prefix: str = "", ) -> go.Figure: if frame.empty: return empty_figure(title, empty_message) ordered = frame.sort_values(metric, ascending=True) figure = go.Figure( go.Bar( x=ordered[metric], y=ordered["category_label"], orientation="h", marker={"color": color, "line": {"width": 0}}, hovertemplate=( f"%{{y}}
{prefix}%{{x:,.2f}}" if prefix else "%{y}
%{x:,.0f}" ), ) ) styled = style_figure(figure, title) styled.update_layout(margin={"l": 120, "r": 24, "t": 62, "b": 48}) return styled def category_comparison_frame( snapshot: Snapshot, version: str, market_type: str, month: str, language: str, ) -> pd.DataFrame: frame = snapshot.monthly[ (snapshot.monthly["version"] == version) & (snapshot.monthly["market_type"] == market_type) & (snapshot.monthly["month"] == month) & (snapshot.monthly["category"] != "all") ].copy() language_key = "zh" if normalized_language(language) == CHINESE else "en" labels = { str(item["key"]): str(item["labels"].get(language_key, item["key"])) for item in snapshot.categories if bool(item["enabled"]) and not bool(item["aggregate_only"]) } frame = frame[frame["category"].isin(labels)].copy() frame["category_label"] = frame["category"].map(labels) return frame def kpi_html( frame: pd.DataFrame, month: str, language: str, ) -> str: if frame.empty: values = ("0", "0", "$0", "$0", "N/A") else: values = ( compact_number(float(frame["fill_event_count"].sum())), compact_number(float(frame["unique_transaction_count"].sum())), compact_usd(float(frame["nominal_collateral_volume"].sum())), compact_usd(float(frame["fee_amount"].sum())), month, ) labels = TEXT[normalized_language(language)]["kpis"] cards = "".join( ( '
' f'
{label}
' f'
{value}
' "
" ) for label, value in zip(labels, values, strict=True) ) return f'
{cards}
' def status_text(snapshot: Snapshot, language: str) -> str: copy = TEXT[normalized_language(language)] generated = snapshot.generated_at.strftime("%Y-%m-%d %H:%M UTC") loaded = snapshot.loaded_at.strftime("%Y-%m-%d %H:%M:%S UTC") category_suffix = ( f" · Categories: `{snapshot.category_config_sha256[:12]}`" if snapshot.category_config_sha256 else "" ) return ( f"{copy['generated']}: **{generated}** · " f"{copy['refreshed']}: **{loaded}** · " f"Bucket: `{STORE.bucket_id}`{category_suffix}" ) def table_frame( frame: pd.DataFrame, language: str, ) -> pd.DataFrame: columns = TEXT[normalized_language(language)]["columns"] if frame.empty: return pd.DataFrame(columns=columns) table = frame[ [ "month", "fill_event_count", "unique_transaction_count", "nominal_collateral_volume", "fee_amount", "is_complete", ] ].copy() table.columns = columns volume_column = columns[3] fee_column = columns[4] month_column = columns[0] table[volume_column] = table[volume_column].map( lambda value: f"${value:,.2f}" ) table[fee_column] = table[fee_column].map( lambda value: f"${value:,.2f}" ) return table.sort_values(month_column, ascending=False) def render_dashboard( version: str, market_type: str, category: str, selected_year: str | None, selected_calendar_month: str | None, language: str, refresh: bool = False, ) -> tuple[Any, ...]: copy = TEXT[normalized_language(language)] snapshot = STORE.refresh() if refresh else STORE.get() categories = available_categories( snapshot.monthly, snapshot.categories, version, market_type, ) category = category if category in categories else categories[0] monthly = filter_metrics( snapshot.monthly, version, market_type, category, ) yearly = aggregate_period_metrics(monthly, "year") quarterly = display_quarters( aggregate_period_metrics(monthly, "quarter") ) months = available_months( snapshot.monthly, version, market_type, category, ) ( years, year, calendar_months, calendar_month, month, ) = resolve_year_month( months, selected_year, selected_calendar_month, ) daily = filter_metrics(snapshot.daily, version, market_type, category) daily = daily[daily["month"] == month].copy() comparison = category_comparison_frame( snapshot, version, market_type, month, language, ) volume_title = copy["volume_title"] fills_title = copy["fills_title"] daily_volume_title = f"{copy['daily_volume_title']} · {month or 'N/A'}" daily_fills_title = f"{copy['daily_fills_title']} · {month or 'N/A'}" return ( kpi_html(monthly, month or "N/A", language), bar_figure( yearly, "period", "nominal_collateral_volume", copy["yearly_volume_title"], COLORS["cyan"], copy["empty"], "$", ), bar_figure( yearly, "period", "fill_event_count", copy["yearly_fills_title"], COLORS["blue"], copy["empty"], ), bar_figure( quarterly, "period", "nominal_collateral_volume", copy["quarterly_volume_title"], COLORS["cyan"], copy["empty"], "$", ), bar_figure( quarterly, "period", "fill_event_count", copy["quarterly_fills_title"], COLORS["blue"], copy["empty"], ), bar_figure( monthly, "month", "nominal_collateral_volume", volume_title, COLORS["cyan"], copy["empty"], "$", ), bar_figure( monthly, "month", "fill_event_count", fills_title, COLORS["blue"], copy["empty"], ), gr.update(choices=years, value=year), gr.update( choices=calendar_month_choices(calendar_months, language), value=calendar_month, ), bar_figure( daily, "date", "nominal_collateral_volume", daily_volume_title, COLORS["amber"], copy["empty"], "$", ), bar_figure( daily, "date", "fill_event_count", daily_fills_title, COLORS["blue"], copy["empty"], ), table_frame(monthly, language), status_text(snapshot, language), category_comparison_figure( comparison, "nominal_collateral_volume", f"{copy['category_volume_title']} · {month or 'N/A'}", COLORS["cyan"], copy["empty"], "$", ), category_comparison_figure( comparison, "fill_event_count", f"{copy['category_fills_title']} · {month or 'N/A'}", COLORS["blue"], copy["empty"], ), ) def update_market_types( version: str, language: str, ) -> Any: snapshot = STORE.get() choices = available_market_types(snapshot.monthly, version) value = "all" if "all" in choices else choices[0] return gr.update( choices=market_choices(choices, language), value=value, label=TEXT[normalized_language(language)]["market"], ) def update_categories( version: str, market_type: str, language: str, ) -> Any: snapshot = STORE.get() values = available_categories( snapshot.monthly, snapshot.categories, version, market_type, ) value = "all" if "all" in values else values[0] return gr.update( choices=category_choices(snapshot, values, language), value=value, label=TEXT[normalized_language(language)]["category"], ) def localized_ui( language: str, version: str, market_type: str, category: str, selected_year: str | None, selected_calendar_month: str | None, ) -> tuple[Any, ...]: language = normalized_language(language) copy = TEXT[language] snapshot = STORE.get() markets = available_market_types(snapshot.monthly, version) market_value = market_type if market_type in markets else markets[0] categories = available_categories( snapshot.monthly, snapshot.categories, version, market_value, ) category_value = category if category in categories else categories[0] months = available_months( snapshot.monthly, version, market_value, category_value, ) ( years, year, calendar_months, calendar_month, _, ) = resolve_year_month( months, selected_year, selected_calendar_month, ) return ( hero_html(language), gr.update( choices=version_choices(language), value=version, label=copy["version"], ), gr.update( choices=market_choices(markets, language), value=market_value, label=copy["market"], ), gr.update( choices=category_choices(snapshot, categories, language), value=category_value, label=copy["category"], ), gr.update( choices=years, value=year, label=copy["year"], ), gr.update( choices=calendar_month_choices(calendar_months, language), value=calendar_month, label=copy["calendar_month"], ), gr.update(value=copy["refresh"]), copy["yearly_section"], copy["quarterly_section"], copy["daily_section"], copy["monthly_section"], copy["monthly_table_section"], copy["category_section"], copy["metric_note"], ) snapshot = STORE.get() initial_version = "all" initial_market = "all" initial_categories = available_categories( snapshot.monthly, snapshot.categories, initial_version, initial_market, ) initial_category = "all" if "all" in initial_categories else initial_categories[0] initial_months = available_months( snapshot.monthly, initial_version, initial_market, initial_category, ) initial_month = initial_months[-1] initial_year, initial_calendar_month = initial_month.split("-") initial = render_dashboard( initial_version, initial_market, initial_category, initial_year, initial_calendar_month, ENGLISH, ) with gr.Blocks( title="Polymarket OrderFilled Analytics", ) as demo: browser_locale = gr.Textbox(value="en", visible=False) with gr.Row(elem_classes=["hero"], equal_height=True): hero = gr.HTML(hero_html(ENGLISH), scale=8, min_width=260) refresh_button = gr.Button( TEXT[ENGLISH]["refresh"], variant="secondary", elem_classes=["hero-refresh"], scale=1, min_width=150, ) with gr.Row(elem_classes=["control-row"]): version = gr.Dropdown( choices=version_choices(ENGLISH), value=initial_version, label=TEXT[ENGLISH]["version"], allow_custom_value=False, filterable=False, elem_classes=["filter-control"], ) market_type = gr.Dropdown( choices=market_choices( available_market_types(snapshot.monthly, initial_version), ENGLISH, ), value=initial_market, label=TEXT[ENGLISH]["market"], allow_custom_value=False, filterable=False, elem_classes=["filter-control"], ) category = gr.Dropdown( choices=category_choices( snapshot, initial_categories, ENGLISH, ), value=initial_category, label=TEXT[ENGLISH]["category"], allow_custom_value=False, filterable=False, elem_classes=["filter-control"], ) year = gr.Dropdown( choices=sorted({value[:4] for value in initial_months}), value=initial_year, label=TEXT[ENGLISH]["year"], allow_custom_value=False, filterable=False, elem_classes=["filter-control"], ) calendar_month = gr.Dropdown( choices=calendar_month_choices( [ value[5:7] for value in initial_months if value.startswith(f"{initial_year}-") ], ENGLISH, ), value=initial_calendar_month, label=TEXT[ENGLISH]["calendar_month"], allow_custom_value=False, filterable=False, elem_classes=["filter-control"], ) language = gr.Dropdown( choices=list(LANGUAGES), value=ENGLISH, label="Language / 语言", allow_custom_value=False, filterable=False, elem_classes=["filter-control"], ) kpis = gr.HTML(initial[0], elem_classes=["kpi-host"]) category_heading = gr.Markdown( TEXT[ENGLISH]["category_section"], elem_classes=["section-title"], ) with gr.Row(equal_height=True, elem_classes=["chart-row"]): category_volume = gr.Plot( initial[13], show_label=False, elem_classes=["chart"], ) category_fills = gr.Plot( initial[14], show_label=False, elem_classes=["chart"], ) yearly_heading = gr.Markdown( TEXT[ENGLISH]["yearly_section"], elem_classes=["section-title"], ) with gr.Row(equal_height=True, elem_classes=["chart-row"]): yearly_volume = gr.Plot( initial[1], show_label=False, elem_classes=["chart"], ) yearly_fills = gr.Plot( initial[2], show_label=False, elem_classes=["chart"], ) quarterly_heading = gr.Markdown( TEXT[ENGLISH]["quarterly_section"], elem_classes=["section-title"], ) with gr.Row(equal_height=True, elem_classes=["chart-row"]): quarterly_volume = gr.Plot( initial[3], show_label=False, elem_classes=["chart"], ) quarterly_fills = gr.Plot( initial[4], show_label=False, elem_classes=["chart"], ) monthly_heading = gr.Markdown( TEXT[ENGLISH]["monthly_section"], elem_classes=["section-title"], ) with gr.Row(equal_height=True, elem_classes=["chart-row"]): monthly_volume = gr.Plot( initial[5], show_label=False, elem_classes=["chart"], ) monthly_fills = gr.Plot( initial[6], show_label=False, elem_classes=["chart"], ) daily_heading = gr.Markdown( TEXT[ENGLISH]["daily_section"], elem_classes=["section-title"], ) with gr.Row(equal_height=True, elem_classes=["chart-row"]): daily_volume = gr.Plot( initial[9], show_label=False, elem_classes=["chart"], ) daily_fills = gr.Plot( initial[10], show_label=False, elem_classes=["chart"], ) monthly_table_heading = gr.Markdown( TEXT[ENGLISH]["monthly_table_section"], elem_classes=["section-title"], ) table = gr.Dataframe( value=initial[11], interactive=False, wrap=True, max_height=460, ) status = gr.Markdown(initial[12], elem_classes=["status-line"]) outputs = [ kpis, yearly_volume, yearly_fills, quarterly_volume, quarterly_fills, monthly_volume, monthly_fills, year, calendar_month, daily_volume, daily_fills, table, status, category_volume, category_fills, ] localized_outputs = [ hero, version, market_type, category, year, calendar_month, refresh_button, yearly_heading, quarterly_heading, daily_heading, monthly_heading, monthly_table_heading, category_heading, ] version.change( update_market_types, inputs=[version, language], outputs=market_type, ).then( update_categories, inputs=[version, market_type, language], outputs=category, ).then( render_dashboard, inputs=[ version, market_type, category, year, calendar_month, language, ], outputs=outputs, ) market_type.change( update_categories, inputs=[version, market_type, language], outputs=category, ).then( render_dashboard, inputs=[ version, market_type, category, year, calendar_month, language, ], outputs=outputs, ) category.change( render_dashboard, inputs=[ version, market_type, category, year, calendar_month, language, ], outputs=outputs, ) year.change( render_dashboard, inputs=[ version, market_type, category, year, calendar_month, language, ], outputs=outputs, ) calendar_month.change( render_dashboard, inputs=[ version, market_type, category, year, calendar_month, language, ], outputs=outputs, ) refresh_button.click( lambda version, market, category, year, month, language: ( render_dashboard( version, market, category, year, month, language, refresh=True, ) ), inputs=[ version, market_type, category, year, calendar_month, language, ], outputs=outputs, ) metric_note = gr.Markdown( TEXT[ENGLISH]["metric_note"], elem_classes=["metric-note"], ) localized_outputs.append(metric_note) language.change( localized_ui, inputs=[ language, version, market_type, category, year, calendar_month, ], outputs=localized_outputs, ).then( render_dashboard, inputs=[ version, market_type, category, year, calendar_month, language, ], outputs=outputs, ) demo.load( browser_language, inputs=browser_locale, outputs=language, js="() => navigator.language || 'en'", ).then( localized_ui, inputs=[ language, version, market_type, category, year, calendar_month, ], outputs=localized_outputs, ).then( render_dashboard, inputs=[ version, market_type, category, year, calendar_month, language, ], outputs=outputs, ) if __name__ == "__main__": demo.launch(theme=THEME, css=CSS, head=HEAD, ssr_mode=False)