From 64523bbf2fd5adf4b652f4f1c077f40f956b8752 Mon Sep 17 00:00:00 2001 From: nadijagraca <108531476+nadijagraca@users.noreply.github.com> Date: Tue, 5 Nov 2024 12:51:49 +0100 Subject: [PATCH 1/3] [Demo] Vizro-AI chart UI updates (#847) --- ...5_nadija_ratkusic_graca_show_data_table.md | 48 +++ .../pages/user-guides/customize-vizro-ai.md | 4 +- vizro-ai/examples/dashboard_ui/actions.py | 97 ++++- vizro-ai/examples/dashboard_ui/app.py | 246 ++++++++---- .../dashboard_ui/assets/custom_css.css | 159 +++++++- vizro-ai/examples/dashboard_ui/components.py | 145 +++++++- .../examples/dashboard_ui/requirements.in | 5 +- .../examples/dashboard_ui/requirements.txt | 351 +++--------------- vizro-ai/src/vizro_ai/_llm_models.py | 4 +- 9 files changed, 659 insertions(+), 400 deletions(-) create mode 100644 vizro-ai/changelog.d/20241101_103905_nadija_ratkusic_graca_show_data_table.md diff --git a/vizro-ai/changelog.d/20241101_103905_nadija_ratkusic_graca_show_data_table.md b/vizro-ai/changelog.d/20241101_103905_nadija_ratkusic_graca_show_data_table.md new file mode 100644 index 000000000..f1f65e73c --- /dev/null +++ b/vizro-ai/changelog.d/20241101_103905_nadija_ratkusic_graca_show_data_table.md @@ -0,0 +1,48 @@ + + + + + + + + + diff --git a/vizro-ai/docs/pages/user-guides/customize-vizro-ai.md b/vizro-ai/docs/pages/user-guides/customize-vizro-ai.md index 3644a7546..f8d0e25db 100644 --- a/vizro-ai/docs/pages/user-guides/customize-vizro-ai.md +++ b/vizro-ai/docs/pages/user-guides/customize-vizro-ai.md @@ -43,8 +43,8 @@ vizro_ai = VizroAI(model="") To use Anthropic with Vizro-AI, you must have an account with paid-for credits available. None of the free accounts will suffice. You can check [all available Anthropic models including pricing on their website](https://docs.anthropic.com/en/docs/about-claude/models). - - `claude-3-5-sonnet-20240620` - - `claude-3-opus-20240229` + - `claude-3-5-sonnet-latest` + - `claude-3-opus-latest` - `claude-3-sonnet-20240229` - `claude-3-haiku-20240307` diff --git a/vizro-ai/examples/dashboard_ui/actions.py b/vizro-ai/examples/dashboard_ui/actions.py index 07880852a..c72467a1c 100644 --- a/vizro-ai/examples/dashboard_ui/actions.py +++ b/vizro-ai/examples/dashboard_ui/actions.py @@ -5,6 +5,8 @@ import logging import black +import dash +import dash_bootstrap_components as dbc import pandas as pd from _utils import check_file_extension from dash.exceptions import PreventUpdate @@ -13,16 +15,50 @@ from vizro.models.types import capture from vizro_ai import VizroAI +try: + from langchain_anthropic import ChatAnthropic +except ImportError: + ChatAnthropic = None + +try: + from langchain_mistralai import ChatMistralAI +except ImportError: + ChatMistralAI = None + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) # TODO: remove manual setting and make centrally controlled -SUPPORTED_VENDORS = {"OpenAI": ChatOpenAI} +SUPPORTED_VENDORS = {"OpenAI": ChatOpenAI, "Anthropic": ChatAnthropic, "Mistral": ChatMistralAI} + +SUPPORTED_MODELS = { + "OpenAI": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4", + "gpt-4-turbo", + "gpt-3.5-turbo", + ], + "Anthropic": [ + "claude-3-opus-latest", + "claude-3-5-sonnet-latest", + "claude-3-sonnet-20240229", + "claude-3-haiku-20240307", + ], + "Mistral": ["mistral-large-latest", "open-mistral-nemo", "codestral-latest"], +} def get_vizro_ai_plot(user_prompt, df, model, api_key, api_base, vendor_input): """VizroAi plot configuration.""" vendor = SUPPORTED_VENDORS[vendor_input] - llm = vendor(model_name=model, openai_api_key=api_key, openai_api_base=api_base) + + if vendor_input == "OpenAI": + llm = vendor(model_name=model, openai_api_key=api_key, openai_api_base=api_base) + if vendor_input == "Anthropic": + llm = vendor(model=model, anthropic_api_key=api_key, anthropic_api_url=api_base) + if vendor_input == "Mistral": + llm = vendor(model=model, mistral_api_key=api_key, mistral_api_url=api_base) + vizro_ai = VizroAI(model=llm) ai_outputs = vizro_ai.plot(df, user_prompt, return_elements=True) @@ -33,13 +69,8 @@ def get_vizro_ai_plot(user_prompt, df, model, api_key, api_base, vendor_input): def run_vizro_ai(user_prompt, n_clicks, data, model, api_key, api_base, vendor_input): # noqa: PLR0913 """Gets the AI response and adds it to the text window.""" - def create_response(ai_response, figure, user_prompt, filename): - plotly_fig = figure.to_json() - return ( - ai_response, - figure, - {"ai_response": ai_response, "figure": plotly_fig, "prompt": user_prompt, "filename": filename}, - ) + def create_response(ai_response, figure, ai_outputs): + return (ai_response, figure, {"ai_outputs": ai_outputs}) if not n_clicks: raise PreventUpdate @@ -47,22 +78,22 @@ def create_response(ai_response, figure, user_prompt, filename): if not data: ai_response = "Please upload data to proceed!" figure = go.Figure() - return create_response(ai_response, figure, user_prompt, None) + return create_response(ai_response, figure, ai_outputs=None) if not api_key: ai_response = "API key not found. Make sure you enter your API key!" figure = go.Figure() - return create_response(ai_response, figure, user_prompt, data["filename"]) + return create_response(ai_response, figure, ai_outputs=None) if api_key.startswith('"'): ai_response = "Make sure you enter your API key without quotes!" figure = go.Figure() - return create_response(ai_response, figure, user_prompt, data["filename"]) + return create_response(ai_response, figure, ai_outputs=None) if api_base is not None and api_base.startswith('"'): ai_response = "Make sure you enter your API base without quotes!" figure = go.Figure() - return create_response(ai_response, figure, user_prompt, data["filename"]) + return create_response(ai_response, figure, ai_outputs=None) try: logger.info("Attempting chart code.") @@ -75,20 +106,25 @@ def create_response(ai_response, figure, user_prompt, filename): api_base=api_base, vendor_input=vendor_input, ) - ai_code = ai_outputs.code - figure = ai_outputs.get_fig_object(data_frame=df) + ai_code = ai_outputs.code_vizro + figure_vizro = ai_outputs.get_fig_object(data_frame=df, vizro=True) + figure_plotly = ai_outputs.get_fig_object(data_frame=df, vizro=False) formatted_code = black.format_str(ai_code, mode=black.Mode(line_length=100)) + ai_code_outputs = { + "vizro": {"code": ai_outputs.code_vizro, "fig": figure_vizro.to_json()}, + "plotly": {"code": ai_outputs.code, "fig": figure_plotly.to_json()}, + } ai_response = "\n".join(["```python", formatted_code, "```"]) logger.info("Successful query produced.") - return create_response(ai_response, figure, user_prompt, data["filename"]) + return create_response(ai_response, figure_vizro, ai_outputs=ai_code_outputs) except Exception as exc: logger.debug(exc) logger.info("Chart creation failed.") ai_response = f"Sorry, I can't do that. Following Error occurred: {exc}" figure = go.Figure() - return create_response(ai_response, figure, user_prompt, data["filename"]) + return create_response(ai_response, figure, ai_outputs=None) @capture("action") @@ -98,7 +134,11 @@ def data_upload_action(contents, filename): raise PreventUpdate if not check_file_extension(filename=filename): - return {"error_message": "Unsupported file extension.. Make sure to upload either csv or an excel file."} + return ( + {"error_message": "Unsupported file extension.. Make sure to upload either csv or an excel file."}, + {"color": "gray"}, + {"display": "none"}, + ) content_type, content_string = contents.split(",") @@ -112,11 +152,15 @@ def data_upload_action(contents, filename): df = pd.read_excel(io.BytesIO(decoded)) data = df.to_dict("records") - return {"data": data, "filename": filename} + return {"data": data, "filename": filename}, {"cursor": "pointer"}, {} except Exception as e: logger.debug(e) - return {"error_message": "There was an error processing this file."} + return ( + {"error_message": "There was an error processing this file."}, + {"color": "gray", "cursor": "default"}, + {"display": "none"}, + ) @capture("action") @@ -127,3 +171,16 @@ def display_filename(data): display_message = data.get("filename") or data.get("error_message") return f"Uploaded file name: '{display_message}'" if "filename" in data else display_message + + +@capture("action") +def update_table(data): + """Custom action for updating data.""" + if not data: + return dash.no_update + df = pd.DataFrame(data["data"]) + filename = data.get("filename") or data.get("error_message") + modal_title = f"Data sample preview for {filename} file" + df_sample = df.sample(5) + table = dbc.Table.from_dataframe(df_sample, striped=False, bordered=True, hover=True) + return table, modal_title diff --git a/vizro-ai/examples/dashboard_ui/app.py b/vizro-ai/examples/dashboard_ui/app.py index 3c46e40d5..70c316344 100644 --- a/vizro-ai/examples/dashboard_ui/app.py +++ b/vizro-ai/examples/dashboard_ui/app.py @@ -2,71 +2,127 @@ import json +import black +import dash import dash_bootstrap_components as dbc import pandas as pd +import plotly.graph_objects as go +import plotly.io as pio import vizro.models as vm import vizro.plotly.express as px -from actions import data_upload_action, display_filename, run_vizro_ai +from actions import data_upload_action, display_filename, run_vizro_ai, update_table from components import ( CodeClipboard, CustomDashboard, + DropdownMenu, + HeaderComponent, Icon, Modal, MyDropdown, - MyPage, OffCanvas, + ToggleSwitch, UserPromptTextArea, UserUpload, + custom_table, ) -from dash import Input, Output, State, callback, get_asset_url, html -from dash.exceptions import PreventUpdate +from dash import Input, Output, State, callback, ctx, dcc, get_asset_url, html from vizro import Vizro +try: + from langchain_anthropic import ChatAnthropic +except ImportError: + ChatAnthropic = None + +try: + from langchain_mistralai import ChatMistralAI +except ImportError: + ChatMistralAI = None + vm.Container.add_type("components", UserUpload) vm.Container.add_type("components", MyDropdown) vm.Container.add_type("components", OffCanvas) vm.Container.add_type("components", CodeClipboard) vm.Container.add_type("components", Icon) vm.Container.add_type("components", Modal) +vm.Container.add_type("components", ToggleSwitch) +vm.Container.add_type("components", UserPromptTextArea) +vm.Container.add_type("components", DropdownMenu) +vm.Container.add_type("components", HeaderComponent) -MyPage.add_type("components", UserPromptTextArea) -MyPage.add_type("components", UserUpload) -MyPage.add_type("components", MyDropdown) -MyPage.add_type("components", OffCanvas) -MyPage.add_type("components", CodeClipboard) -MyPage.add_type("components", Icon) -MyPage.add_type("components", Modal) +vm.Page.add_type("components", UserUpload) +vm.Page.add_type("components", MyDropdown) +vm.Page.add_type("components", OffCanvas) +vm.Page.add_type("components", CodeClipboard) +vm.Page.add_type("components", Icon) +vm.Page.add_type("components", Modal) -SUPPORTED_MODELS = [ - "gpt-4o-mini", - "gpt-4", - "gpt-4-turbo", - "gpt-3.5-turbo", - "gpt-4o", -] +SUPPORTED_MODELS = { + "OpenAI": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4", + "gpt-4-turbo", + "gpt-3.5-turbo", + ], + "Anthropic": [ + "claude-3-opus-latest", + "claude-3-5-sonnet-latest", + "claude-3-sonnet-20240229", + "claude-3-haiku-20240307", + ], + "Mistral": ["mistral-large-latest", "open-mistral-nemo", "codestral-latest"], +} -plot_page = MyPage( +plot_page = vm.Page( id="vizro_ai_plot_page", - title="Vizro-AI - effortlessly create interactive charts with Plotly", + title="Vizro-AI - create interactive charts with Plotly and Vizro", layout=vm.Layout( grid=[ - [3, 3, -1, 5], - [1, 1, 2, 2], - [4, 4, 2, 2], - *[[0, 0, 2, 2]] * 6, + [4, 4, 4, 4], + [2, 2, 1, 1], + [2, 2, 1, 1], + [3, 3, 1, 1], + [3, 3, 1, 1], + [3, 3, 1, 1], + *[[0, 0, 1, 1]] * 8, ] ), components=[ - vm.Container(title="", components=[CodeClipboard(id="plot")]), - UserPromptTextArea( - id="text-area-id", + vm.Container( + title="", + components=[CodeClipboard(id="plot"), ToggleSwitch(id="toggle-id")], + layout=vm.Layout( + grid=[*[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] * 7, [-1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1]], + row_gap="12px", + col_gap="12px", + ), ), - vm.Graph(id="graph-id", figure=px.scatter(pd.DataFrame())), vm.Container( title="", - layout=vm.Layout(grid=[[1], [0]], row_gap="0px"), + layout=vm.Layout( + grid=[ + *[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] * 10, + [-1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1], + ] + ), + components=[ + vm.Graph(id="graph-id", figure=px.scatter(pd.DataFrame())), + DropdownMenu(id="dropdown-menu"), + ], + ), + vm.Container( + id="upload-data-container", + title="Turn your data into visuals — just upload, describe, and see your chart in action", + layout=vm.Layout( + grid=[ + [1], + [0], + ], + row_gap="0px", + # row_min_height="40px", + ), components=[ UserUpload( id="data-upload-id", @@ -74,25 +130,39 @@ vm.Action( function=data_upload_action(), inputs=["data-upload-id.contents", "data-upload-id.filename"], - outputs=["data-store-id.data"], + outputs=["data-store-id.data", "modal-table-icon.style", "modal-table-tooltip.style"], ), vm.Action( function=display_filename(), inputs=["data-store-id.data"], outputs=["upload-message-id.children"], ), + vm.Action( + function=update_table(), + inputs=["data-store-id.data"], + outputs=["modal-table.children", "modal-title.children"], + ), ], ), - vm.Card(id="upload-message-id", text="Upload your data file (csv or excel)"), + vm.Figure(id="show-data-component", figure=custom_table(data_frame=pd.DataFrame())), ], ), vm.Container( title="", - layout=vm.Layout(grid=[[2, -1, -1, -1, -1, 1, 1, 0, 0]], row_gap="0px", col_gap="4px"), + layout=vm.Layout( + grid=[ + [3, 3, 3, 3, 3, 3, 3, 3, 3], + [3, 3, 3, 3, 3, 3, 3, 3, 3], + [3, 3, 3, 3, 3, 3, 3, 3, 3], + [2, -1, -1, -1, -1, 1, 1, 0, 0], + ], + row_gap="10px", + col_gap="4px", + ), components=[ vm.Button( id="trigger-button-id", - text="Run VizroAI", + text="Run Vizro-AI", actions=[ vm.Action( function=run_vizro_ai(), @@ -105,16 +175,22 @@ "settings-api-base.value", "settings-dropdown.value", ], - outputs=["plot-code-markdown.children", "graph-id.figure", "outputs-store-id.data"], + outputs=["plot-code-markdown.children", "graph-id.figure", "code-output-store-id.data"], ), ], ), - MyDropdown(options=SUPPORTED_MODELS, value="gpt-4o-mini", multi=False, id="model-dropdown-id"), - OffCanvas(id="settings", options=["OpenAI"], value="OpenAI"), + MyDropdown( + options=SUPPORTED_MODELS["OpenAI"], value="gpt-4o-mini", multi=False, id="model-dropdown-id" + ), + OffCanvas(id="settings", options=["OpenAI", "Anthropic", "Mistral"], value="OpenAI"), + UserPromptTextArea(id="text-area-id"), # Modal(id="modal"), ], ), - Icon(id="open-settings-id"), + vm.Container( + title="", + components=[HeaderComponent()], + ), ], ) @@ -123,28 +199,6 @@ # pure dash callbacks -@callback( - [ - Output("plot-code-markdown", "children", allow_duplicate=True), - Output("graph-id", "figure", allow_duplicate=True), - Output("text-area-id", "value"), - Output("upload-message-id", "children"), - ], - [Input("on_page_load_action_trigger_vizro_ai_plot_page", "data")], - [State("outputs-store-id", "data")], - prevent_initial_call="initial_duplicate", -) -def update_data(page_data, outputs_data): - """Callback for retrieving latest vizro-ai output from dcc store.""" - if not outputs_data: - raise PreventUpdate - - ai_response = outputs_data["ai_response"] - fig = json.loads(outputs_data["figure"]) - filename = f"File uploaded: '{outputs_data['filename']}'" - prompt = outputs_data["prompt"] - - return ai_response, fig, prompt, filename @callback( @@ -175,19 +229,85 @@ def show_api_base(value): return "text" if value else "password" +@callback( + Output("plot-code-markdown", "children"), + Input("toggle-switch", "value"), + [State("code-output-store-id", "data")], +) +def toggle_code(value, data): + """Callback for switching between vizro and plotly code.""" + if not data: + return dash.no_update + + ai_code = data["ai_outputs"]["vizro"]["code"] if value else data["ai_outputs"]["plotly"]["code"] + + formatted_code = black.format_str(ai_code, mode=black.Mode(line_length=100)) + ai_response = "\n".join(["```python", formatted_code, "```"]) + return ai_response + + +@callback( + Output("data-modal", "is_open"), + Input("modal-table-icon", "n_clicks"), + State("data-modal", "is_open"), + State("data-store-id", "data"), +) +def open_modal(n_clicks, is_open, data): + """Callback for opening modal component.""" + if not data: + return dash.no_update + if n_clicks: + return not is_open + return is_open + + +@callback( + Output("download-file", "data"), + [Input("dropdown-menu-html", "n_clicks"), Input("dropdown-menu-json", "n_clicks")], + State("code-output-store-id", "data"), + prevent_initial_call=True, +) +def download_fig(n_clicks_html, n_clicks_json, data): + """Callback for downloading vizro fig.""" + if not data: + return dash.no_update + if not (n_clicks_html or n_clicks_json): + return dash.no_update + + button_clicked = ctx.triggered_id + + if button_clicked == "dropdown-menu-html": + vizro_json = json.loads(data["ai_outputs"]["vizro"]["fig"]) + fig = go.Figure(vizro_json) + graphs_html = pio.to_html(fig) + return dcc.send_string(graphs_html, filename="vizro_fig.html") + + if button_clicked == "dropdown-menu-json": + plotly_json = data["ai_outputs"]["plotly"]["fig"] + return dcc.send_string(plotly_json, "plotly_fig.json") + + +@callback( + [Output("model-dropdown-id", "options"), Output("model-dropdown-id", "value")], Input("settings-dropdown", "value") +) +def update_model_dropdown(value): + """Callback for updating available models.""" + available_models = SUPPORTED_MODELS[value] + default_model = available_models[0] + return available_models, default_model + + app = Vizro().build(dashboard) app.dash.layout.children.append( html.Div( [ - dbc.NavLink("Contact Vizro", href="https://github.com/mckinsey/vizro/issues"), - dbc.NavLink("GitHub", href="https://github.com/mckinsey/vizro"), - dbc.NavLink("Docs", href="https://vizro.readthedocs.io/projects/vizro-ai/"), html.Div( [ "Made using ", html.Img(src=get_asset_url("logo.svg"), id="banner", alt="Vizro logo"), - "vizro", + dbc.NavLink("vizro", href="https://github.com/mckinsey/vizro", target="_blank", external_link=True), ], + style={"display": "flex", "flexDirection": "row"}, ), ], className="anchor-container", diff --git a/vizro-ai/examples/dashboard_ui/assets/custom_css.css b/vizro-ai/examples/dashboard_ui/assets/custom_css.css index 02dcbe0b8..cd9c92d14 100644 --- a/vizro-ai/examples/dashboard_ui/assets/custom_css.css +++ b/vizro-ai/examples/dashboard_ui/assets/custom_css.css @@ -26,7 +26,7 @@ background-color: inherit; border: 1px solid var(--border-subtle-alpha-01); color: var(--text-primary); - min-height: 90px; + min-height: 13.5vh; padding: 8px; width: 100%; } @@ -45,8 +45,8 @@ .code-clipboard-container { background: var(--surfaces-bg-card); font-family: monospace; - height: 500px; - max-height: 500px; + height: 100%; + max-height: 470px; overflow: auto; padding: 1rem; position: relative; @@ -118,7 +118,7 @@ display: flex; justify-content: end; padding-right: 2px; - width: 100%; + width: 20px; } #data-upload-id { @@ -130,6 +130,7 @@ text-align: center; } +/* #settings-api-key-toggle .form-check-input { border-radius: 8px; } @@ -137,7 +138,7 @@ #settings-api-base-toggle .form-check-input { border-radius: 8px; } - +*/ #toggle-div-api-base, #toggle-div-api-key { align-items: center; @@ -157,3 +158,151 @@ position: fixed; width: 100%; } + +.toggle-div { + display: flex; + flex-direction: row; + gap: 4px; + justify-content: end; + padding-top: 6px; + width: 100%; +} + +.form-check .form-check-input { + border-radius: 8px; +} + +#settings-api-key-toggle .form-check-input { + border-radius: 8px; +} + +#settings-api-base-toggle .form-check-input { + border-radius: 8px; +} + +.form-check { + padding-top: 2px; +} + +.modal-content { + width: fit-content; +} + +.btn-primary:enabled:has(#dropdown-menu-icon) { + background-color: inherit; + color: var(--text-active); +} + +.btn-primary:disabled:has(#dropdown-menu-icon) { + background-color: inherit; + color: var(--text-active); +} + +.download-button { + background-color: inherit; + color: var(--text-active); + width: 100%; +} + +#modal-table-icon { + cursor: pointer; +} + +.dropdown-menu-toggle-class { + background-color: inherit; + color: var(--text-active); + height: 2rem; + scale: 90%; +} + +.dropdown-menu-toggle-class:hover { + background-color: inherit; + color: var(--text-active); + cursor: pointer; + height: 2rem; + scale: 90%; +} + +.dropdown-menu-toggle-class.btn-primary:focus:not( + :focus-visible, + :disabled, + .disabled + ) { + background-color: inherit; + color: var(--text-active); +} + +.modal-class { + max-height: 600px; + max-width: 1000px; + overflow: auto; + scrollbar-width: thin; +} + +#right-header { + display: none; +} + +.custom_header { + align-items: center; + border-bottom: 1px solid var(--border-subtle-alpha-01); + display: flex; + flex-direction: row; + height: 60px; + justify-content: space-between; + min-height: 0; + width: 100%; +} + +#right-side { + padding-top: 0; +} + +.header-logo { + width: 48px; +} +/* stylelint-disable-next-line selector-id-pattern */ +#upload-data-container_title { + font-size: 14px; + padding-top: 4px; +} + +#dropdown-menu-id { + align-items: center; + border: 0.5px solid gray; + border-radius: 8px; + display: flex; + flex-direction: row; + justify-content: center; + width: 100%; +} + +#custom-header-div { + display: flex; + flex-direction: row; + gap: 8px; + justify-content: center; + width: 100%; +} + +#custom-header-title { + align-items: center; + display: flex; + font-size: 28px; + font-weight: 400; +} + +#table-modal-div { + align-items: center; + display: flex; + flex-direction: row; + gap: 8px; +} + +#data-upload { + color: var(--text-secondary); +} + +#open-settings-id:hover { + cursor: pointer; +} diff --git a/vizro-ai/examples/dashboard_ui/components.py b/vizro-ai/examples/dashboard_ui/components.py index dbfb90be1..41a3d6d88 100644 --- a/vizro-ai/examples/dashboard_ui/components.py +++ b/vizro-ai/examples/dashboard_ui/components.py @@ -5,11 +5,12 @@ import black import dash_bootstrap_components as dbc import vizro.models as vm -from dash import dcc, html +from dash import dcc, get_asset_url, html from pydantic import PrivateAttr from vizro.models import Action from vizro.models._action._actions_chain import _action_validator_factory from vizro.models._models_utils import _log_call +from vizro.models.types import capture class UserPromptTextArea(vm.VizroBaseModel): @@ -68,9 +69,7 @@ def build(self): [ dcc.Upload( id=self.id, - children=html.Div( - ["Drag and Drop or ", html.A("Select Files")], style={"fontColor": "rgba(255, 255, 255, 0.6)"} - ), + children=html.Div(["Drag and Drop or ", html.A("Select Files")], id="data-upload"), ), ] ) @@ -218,16 +217,6 @@ def build(self): return offcanvas -class MyPage(vm.Page): - """Custom page.""" - - type: Literal["my_page"] = "my_page" - - def pre_build(self): - """Overwriting pre_build.""" - pass - - class Icon(vm.VizroBaseModel): """Icon component for settings.""" @@ -248,5 +237,131 @@ def build(self): """Returns custom dashboard.""" dashboard_build_obj = super().build() dashboard_build_obj.children.append(dcc.Store(id="data-store-id", storage_type="session")) - dashboard_build_obj.children.append(dcc.Store(id="outputs-store-id", storage_type="session")) + dashboard_build_obj.children.append(dcc.Store(id="code-output-store-id", storage_type="session")) return dashboard_build_obj + + +class ToggleSwitch(vm.VizroBaseModel): + """Custom toggle switch model.""" + + type: Literal["toggle_switch"] = "toggle_switch" + + def build(self): + """Returns custom toggle switch component.""" + toggle_component = html.Div( + children=[ + html.P("Plotly"), + html.Div( + dbc.Switch(id="toggle-switch", value=True, style={"borderRadius": "8px"}), + style={"paddingRight": "4px"}, + ), + html.P("Vizro"), + ], + className="toggle-div", + ) + return toggle_component + + +@capture("figure") +def custom_table(data_frame): + """Custom table figure.""" + table = dbc.Table.from_dataframe(data_frame, striped=False, bordered=True, hover=True) + + table_modal = html.Div( + [ + html.Span( + "table_view", + className="material-symbols-outlined", + id="modal-table-icon", + style={"color": "gray", "cursor": "default"}, + ), + dbc.Tooltip( + "Click to view data!", + placement="top", + target="modal-table-icon", + style={"display": "none"}, + id="modal-table-tooltip", + ), + html.P( + id="upload-message-id", children=["Upload your data file (csv or excel)"], style={"paddingTop": "10px"} + ), + dbc.Modal( + id="data-modal", + children=[ + dbc.ModalHeader(dbc.ModalTitle(id="modal-title", children="No data uploaded!")), + dbc.ModalBody( + id="modal-table", + children=table, + ), + ], + size="xl", + modal_class_name="modal-class", + ), + ], + id="table-modal-div", + ) + return table_modal + + +class DropdownMenu(vm.VizroBaseModel): + """Custom dropdown menu component.""" + + type: Literal["dropdown_menu"] = "dropdown_menu" + + def build(self): + """Returns custom dropdown menu.""" + dropdown_menu = dbc.DropdownMenu( + id="dropdown-menu-button", + label="Download ", + children=[ + dbc.DropdownMenuItem( + children=[ + dbc.Button(children="JSON", id=f"{self.id}-json", className="download-button"), + ] + ), + dbc.DropdownMenuItem( + children=[ + dbc.Button(children="HTML", id=f"{self.id}-html", className="download-button"), + ] + ), + dcc.Download(id="download-file"), + ], + toggleClassName="dropdown-menu-toggle-class", + ) + download_div = html.Div( + children=[ + html.Span("download", className="material-symbols-outlined", id=f"{self.id}-icon"), + dropdown_menu, + dbc.Tooltip( + "Download this plot to your device as a plotly JSON or interactive HTML file " + "for easy sharing or future use.", + target="dropdown-menu-icon", + ), + ], + id="dropdown-menu-id", + ) + + return download_div + + +class HeaderComponent(vm.VizroBaseModel): + """Custom header component.""" + + type: Literal["header"] = "header" + + def build(self): + """Returns custom header component.""" + title = html.Header("Vizro", id="custom-header-title") + header = html.Div( + children=[html.Img(src=get_asset_url("logo.svg"), alt="Vizro logo", className="header-logo"), title], + id="custom-header-div", + ) + icon = html.Div( + children=[ + html.Span("settings", className="material-symbols-outlined", id="open-settings-id"), + dbc.Tooltip("Settings", target="open-settings-id"), + ], + className="settings-div", + ) + + return html.Div(children=[header, icon], className="custom_header") diff --git a/vizro-ai/examples/dashboard_ui/requirements.in b/vizro-ai/examples/dashboard_ui/requirements.in index 1a0297b3d..c4ac937ee 100644 --- a/vizro-ai/examples/dashboard_ui/requirements.in +++ b/vizro-ai/examples/dashboard_ui/requirements.in @@ -1,5 +1,6 @@ gunicorn -vizro-ai>=0.2.1 +vizro-ai>=0.3.0 black -jupyter openpyxl +langchain_anthropic +langchain_mistralai diff --git a/vizro-ai/examples/dashboard_ui/requirements.txt b/vizro-ai/examples/dashboard_ui/requirements.txt index 3e2803ffd..59fd17ba6 100644 --- a/vizro-ai/examples/dashboard_ui/requirements.txt +++ b/vizro-ai/examples/dashboard_ui/requirements.txt @@ -8,40 +8,25 @@ aiosignal==1.3.1 # via aiohttp annotated-types==0.7.0 # via pydantic +anthropic==0.38.0 + # via langchain-anthropic anyio==4.4.0 # via + # anthropic # httpx - # jupyter-server # openai -appnope==0.1.4 - # via ipykernel -argon2-cffi==23.1.0 - # via jupyter-server -argon2-cffi-bindings==21.2.0 - # via argon2-cffi -arrow==1.3.0 - # via isoduration -asttokens==2.4.1 - # via stack-data -async-lru==2.0.4 - # via jupyterlab async-timeout==4.0.3 # via # aiohttp # langchain attrs==24.2.0 - # via - # aiohttp - # jsonschema - # referencing -babel==2.16.0 - # via jupyterlab-server -beautifulsoup4==4.12.3 - # via nbconvert + # via aiohttp +autoflake==2.3.1 + # via vizro-ai black==24.8.0 - # via -r requirements.in -bleach==6.1.0 - # via nbconvert + # via + # -r requirements.in + # vizro-ai blinker==1.8.2 # via flask cachelib==0.9.0 @@ -51,18 +36,12 @@ certifi==2024.8.30 # httpcore # httpx # requests -cffi==1.17.1 - # via argon2-cffi-bindings charset-normalizer==3.3.2 # via requests click==8.1.7 # via # black # flask -comm==0.2.2 - # via - # ipykernel - # ipywidgets dash==2.18.1 # via # dash-ag-grid @@ -80,36 +59,30 @@ dash-mantine-components==0.12.1 # via vizro dash-table==5.0.0 # via dash -debugpy==1.8.5 - # via ipykernel -decorator==5.1.1 - # via ipython defusedxml==0.7.1 - # via nbconvert + # via langchain-anthropic distro==1.9.0 - # via openai + # via + # anthropic + # openai et-xmlfile==1.1.0 # via openpyxl exceptiongroup==1.2.2 - # via - # anyio - # ipython -executing==2.1.0 - # via stack-data -fastjsonschema==2.20.0 - # via nbformat + # via anyio +filelock==3.16.1 + # via huggingface-hub flask==3.0.3 # via # dash # flask-caching flask-caching==2.3.0 # via vizro -fqdn==1.5.1 - # via jsonschema frozenlist==1.4.1 # via # aiohttp # aiosignal +fsspec==2024.10.0 + # via huggingface-hub greenlet==3.1.0 # via sqlalchemy gunicorn==23.0.0 @@ -120,121 +93,51 @@ httpcore==1.0.5 # via httpx httpx==0.27.2 # via - # jupyterlab + # anthropic + # langchain-mistralai # langsmith # openai +httpx-sse==0.4.0 + # via langchain-mistralai +huggingface-hub==0.26.2 + # via tokenizers idna==3.8 # via # anyio # httpx - # jsonschema # requests # yarl importlib-metadata==8.5.0 # via # dash # flask - # jupyter-client - # jupyter-lsp - # jupyterlab - # jupyterlab-server - # nbconvert -ipykernel==6.29.5 - # via - # jupyter - # jupyter-console - # jupyterlab -ipython==8.18.1 - # via - # ipykernel - # ipywidgets - # jupyter-console -ipywidgets==8.1.5 - # via jupyter -isoduration==20.11.0 - # via jsonschema itsdangerous==2.2.0 # via flask -jedi==0.19.1 - # via ipython jinja2==3.1.4 - # via - # flask - # jupyter-server - # jupyterlab - # jupyterlab-server - # nbconvert + # via flask jiter==0.5.0 - # via openai -json5==0.9.25 - # via jupyterlab-server + # via + # anthropic + # openai jsonpatch==1.33 # via langchain-core jsonpointer==3.0.0 - # via - # jsonpatch - # jsonschema -jsonschema==4.23.0 - # via - # jupyter-events - # jupyterlab-server - # nbformat -jsonschema-specifications==2023.12.1 - # via jsonschema -jupyter==1.1.1 - # via -r requirements.in -jupyter-client==8.6.2 - # via - # ipykernel - # jupyter-console - # jupyter-server - # nbclient -jupyter-console==6.6.3 - # via jupyter -jupyter-core==5.7.2 - # via - # ipykernel - # jupyter-client - # jupyter-console - # jupyter-server - # jupyterlab - # nbclient - # nbconvert - # nbformat -jupyter-events==0.10.0 - # via jupyter-server -jupyter-lsp==2.2.5 - # via jupyterlab -jupyter-server==2.14.2 - # via - # jupyter-lsp - # jupyterlab - # jupyterlab-server - # notebook - # notebook-shim -jupyter-server-terminals==0.5.3 - # via jupyter-server -jupyterlab==4.2.5 - # via - # jupyter - # notebook -jupyterlab-pygments==0.3.0 - # via nbconvert -jupyterlab-server==2.27.3 - # via - # jupyterlab - # notebook -jupyterlab-widgets==3.0.13 - # via ipywidgets + # via jsonpatch langchain==0.2.16 # via vizro-ai +langchain-anthropic==0.1.23 + # via -r requirements.in langchain-core==0.2.39 # via # langchain + # langchain-anthropic + # langchain-mistralai # langchain-openai # langchain-text-splitters # langgraph # langgraph-checkpoint +langchain-mistralai==0.1.13 + # via -r requirements.in langchain-openai==0.1.23 # via vizro-ai langchain-text-splitters==0.2.4 @@ -242,7 +145,9 @@ langchain-text-splitters==0.2.4 langgraph==0.2.16 # via vizro-ai langgraph-checkpoint==1.0.9 - # via langgraph + # via + # langgraph + # vizro-ai langsmith==0.1.119 # via # langchain @@ -250,41 +155,15 @@ langsmith==0.1.119 markupsafe==2.1.5 # via # jinja2 - # nbconvert # werkzeug -matplotlib-inline==0.1.7 - # via - # ipykernel - # ipython -mistune==3.0.2 - # via nbconvert multidict==6.1.0 # via # aiohttp # yarl mypy-extensions==1.0.0 # via black -nbclient==0.10.0 - # via nbconvert -nbconvert==7.16.4 - # via - # jupyter - # jupyter-server -nbformat==5.10.4 - # via - # jupyter-server - # nbclient - # nbconvert nest-asyncio==1.6.0 - # via - # dash - # ipykernel -notebook==7.2.2 - # via jupyter -notebook-shim==0.2.4 - # via - # jupyterlab - # notebook + # via dash numpy==1.26.4 # via # langchain @@ -297,55 +176,26 @@ openpyxl==3.1.5 # via -r requirements.in orjson==3.10.7 # via langsmith -overrides==7.7.0 - # via jupyter-server packaging==24.1 # via # black # gunicorn - # ipykernel - # jupyter-server - # jupyterlab - # jupyterlab-server + # huggingface-hub # langchain-core - # nbconvert # plotly pandas==2.2.2 # via # vizro # vizro-ai -pandocfilters==1.5.1 - # via nbconvert -parso==0.8.4 - # via jedi pathspec==0.12.1 # via black -pexpect==4.9.0 - # via ipython platformdirs==4.3.2 - # via - # black - # jupyter-core + # via black plotly==5.24.1 # via dash -prometheus-client==0.20.0 - # via jupyter-server -prompt-toolkit==3.0.47 - # via - # ipython - # jupyter-console -psutil==6.0.0 - # via ipykernel -ptyprocess==0.7.0 - # via - # pexpect - # terminado -pure-eval==0.2.3 - # via stack-data -pycparser==2.22 - # via cffi pydantic==2.9.1 # via + # anthropic # langchain # langchain-core # langsmith @@ -353,87 +203,46 @@ pydantic==2.9.1 # vizro pydantic-core==2.23.3 # via pydantic -pygments==2.18.0 - # via - # ipython - # jupyter-console - # nbconvert +pyflakes==3.2.0 + # via autoflake python-dateutil==2.9.0.post0 - # via - # arrow - # jupyter-client - # pandas + # via pandas python-dotenv==1.0.1 # via vizro-ai -python-json-logger==2.0.7 - # via jupyter-events pytz==2024.2 # via pandas pyyaml==6.0.2 # via - # jupyter-events + # huggingface-hub # langchain # langchain-core -pyzmq==26.2.0 - # via - # ipykernel - # jupyter-client - # jupyter-console - # jupyter-server -referencing==0.35.1 - # via - # jsonschema - # jsonschema-specifications - # jupyter-events regex==2024.9.11 # via tiktoken requests==2.32.3 # via # dash - # jupyterlab-server + # huggingface-hub # langchain # langsmith # tiktoken retrying==1.3.4 # via dash -rfc3339-validator==0.1.4 - # via - # jsonschema - # jupyter-events -rfc3986-validator==0.1.1 - # via - # jsonschema - # jupyter-events -rpds-py==0.20.0 - # via - # jsonschema - # referencing ruff==0.6.4 # via vizro -send2trash==1.8.3 - # via jupyter-server setuptools==74.1.2 - # via - # dash - # jupyterlab + # via dash six==1.16.0 # via - # asttokens - # bleach # python-dateutil # retrying - # rfc3339-validator sniffio==1.3.1 # via + # anthropic # anyio # httpx # openai -soupsieve==2.6 - # via beautifulsoup4 sqlalchemy==2.0.34 # via langchain -stack-data==0.6.3 - # via ipython tabulate==0.9.0 # via vizro-ai tenacity==8.5.0 @@ -441,53 +250,27 @@ tenacity==8.5.0 # langchain # langchain-core # plotly -terminado==0.18.1 - # via - # jupyter-server - # jupyter-server-terminals tiktoken==0.7.0 # via langchain-openai -tinycss2==1.3.0 - # via nbconvert +tokenizers==0.20.1 + # via + # anthropic + # langchain-mistralai tomli==2.0.1 # via + # autoflake # black - # jupyterlab -tornado==6.4.1 - # via - # ipykernel - # jupyter-client - # jupyter-server - # jupyterlab - # notebook - # terminado tqdm==4.66.5 - # via openai -traitlets==5.14.3 - # via - # comm - # ipykernel - # ipython - # ipywidgets - # jupyter-client - # jupyter-console - # jupyter-core - # jupyter-events - # jupyter-server - # jupyterlab - # matplotlib-inline - # nbclient - # nbconvert - # nbformat -types-python-dateutil==2.9.0.20240906 - # via arrow + # via + # huggingface-hub + # openai typing-extensions==4.12.2 # via + # anthropic # anyio - # async-lru # black # dash - # ipython + # huggingface-hub # langchain-core # multidict # openai @@ -496,30 +279,16 @@ typing-extensions==4.12.2 # sqlalchemy tzdata==2024.1 # via pandas -uri-template==1.3.0 - # via jsonschema urllib3==2.2.3 # via requests vizro==0.1.23 # via vizro-ai -vizro-ai==0.2.3 +vizro-ai==0.3.0 # via -r requirements.in -wcwidth==0.2.13 - # via prompt-toolkit -webcolors==24.8.0 - # via jsonschema -webencodings==0.5.1 - # via - # bleach - # tinycss2 -websocket-client==1.8.0 - # via jupyter-server werkzeug==3.0.4 # via # dash # flask -widgetsnbextension==4.0.13 - # via ipywidgets wrapt==1.16.0 # via vizro yarl==1.11.1 diff --git a/vizro-ai/src/vizro_ai/_llm_models.py b/vizro-ai/src/vizro_ai/_llm_models.py index fd05e4ddb..4df7088d8 100644 --- a/vizro-ai/src/vizro_ai/_llm_models.py +++ b/vizro-ai/src/vizro_ai/_llm_models.py @@ -23,8 +23,8 @@ "gpt-4o-mini", ], "Anthropic": [ - "claude-3-5-sonnet-20240620", - "claude-3-opus-20240229", + "claude-3-5-sonnet-latest", + "claude-3-opus-latest", "claude-3-sonnet-20240229", "claude-3-haiku-20240307", ], From 812acd81fbc8886e127f4e3464373be23abe19a7 Mon Sep 17 00:00:00 2001 From: Jo Stichbury Date: Tue, 5 Nov 2024 13:25:14 +0000 Subject: [PATCH 2/3] [docs] Close Hacktoberfest docs tickets with fixes for Vale issues (#848) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Lingyi Zhang --- .vale/styles/Microsoft/Headings.yml | 3 +++ .../add-generated-chart-usecase.md | 7 ++++-- .../pages/user-guides/advanced-options.md | 23 ++++++++++++------- .../pages/user-guides/customize-vizro-ai.md | 10 ++++---- vizro-ai/docs/pages/user-guides/install.md | 4 ++-- .../user-guides/retrieve-dashboard-code.md | 4 ++-- .../docs/pages/user-guides/run-vizro-ai.md | 2 +- vizro-core/docs/pages/explanation/authors.md | 4 ++-- .../docs/pages/explanation/contributing.md | 12 +++++++--- vizro-core/docs/pages/explanation/faq.md | 8 ++++++- .../docs/pages/explanation/your-examples.md | 5 +++- .../pages/tutorials/explore-components.md | 6 +++++ vizro-core/docs/pages/user-guides/assets.md | 12 ++++------ .../docs/pages/user-guides/custom-charts.md | 2 ++ .../docs/pages/user-guides/custom-css.md | 3 +-- vizro-core/docs/pages/user-guides/graph.md | 6 +++-- vizro-core/docs/pages/user-guides/run.md | 2 +- vizro-core/docs/pages/user-guides/table.md | 4 ++-- vizro-core/docs/pages/user-guides/themes.md | 1 + .../pages/user-guides/visual-formatting.md | 8 +++---- 20 files changed, 81 insertions(+), 45 deletions(-) diff --git a/.vale/styles/Microsoft/Headings.yml b/.vale/styles/Microsoft/Headings.yml index 2fa78a611..b212336e7 100644 --- a/.vale/styles/Microsoft/Headings.yml +++ b/.vale/styles/Microsoft/Headings.yml @@ -34,6 +34,7 @@ exceptions: - Azure Event Hub - CSS - CI/CD + - Codespaces - DataCatalog - Data Catalog - Data Manager @@ -55,6 +56,7 @@ exceptions: - Google Cloud Functions - Graph - GraphQL + - Hatch - Hook - Hooks - IDs @@ -68,6 +70,7 @@ exceptions: - Kubernetes Pod - Kubernetes Service - Lambda + - LangChain - Linux - MySQL - Notebook diff --git a/vizro-ai/docs/pages/user-guides/add-generated-chart-usecase.md b/vizro-ai/docs/pages/user-guides/add-generated-chart-usecase.md index 4df738842..fa87f16e1 100644 --- a/vizro-ai/docs/pages/user-guides/add-generated-chart-usecase.md +++ b/vizro-ai/docs/pages/user-guides/add-generated-chart-usecase.md @@ -11,6 +11,7 @@ This guide explains the different ways in which you can add a chart generated by !!! example "Vizro-AI chart" === "Code for the cell" + ```py import vizro_ai from vizro_ai import VizroAI @@ -61,10 +62,11 @@ This guide explains the different ways in which you can add a chart generated by return fig ``` -The provided `custom_chart` function is an example of the [custom chart](https://vizro.readthedocs.io/en/stable/pages/user-guides/custom-charts), and it returns a `go.Figure()` object. +The `custom_chart` function is an example of the [custom chart](https://vizro.readthedocs.io/en/stable/pages/user-guides/custom-charts). It returns a `go.Figure()` object. This object must then be passed to the `figure` argument of the Vizro [Graph](https://vizro.readthedocs.io/en/stable/pages/user-guides/graph) model. !!! example "Vizro-AI chart within vizro dashboard" + === "Code for the cell" ```py hl_lines="8-23 31" from vizro import Vizro @@ -119,13 +121,14 @@ This object must then be passed to the `figure` argument of the Vizro [Graph](ht We can also use Vizro-AI dynamically and assign the output of `plot()` directly to the fig variable, enabling its reuse in the `vm.Graph.figure` argument. This method offers streamlined efficiency, eliminating the need for code copying. -However, it is important to note that each dashboard run triggers an API call to OpenAI, possibly escalating costs, although this can be avoided if the `fig` object is stored and retrieved as needed, instead of making repeated calls to `plot()`. +Note that each dashboard run triggers an API call to the LLM, possibly escalating costs. This can be avoided if the `fig` object is stored and retrieved as needed, instead of making repeated calls to `plot()`. Executing the code below yields the identical dashboard as the example above. !!! example "Use Vizro-AI fig directly in vizro dashboard" === "Code for the cell" + ```py hl_lines="13-18 23" from vizro import Vizro import vizro.models as vm diff --git a/vizro-ai/docs/pages/user-guides/advanced-options.md b/vizro-ai/docs/pages/user-guides/advanced-options.md index b64baf16f..528a74912 100644 --- a/vizro-ai/docs/pages/user-guides/advanced-options.md +++ b/vizro-ai/docs/pages/user-guides/advanced-options.md @@ -2,10 +2,13 @@ This guide shows you how to use the advanced options of `VizroAI.plot`. -First we show how to change the input parameters of the function, allowing the control of whether code gets executed, the number of retries of `.plot` when -it fails validation, and how to change for a more comprehensive return of output (when `return_elements=True`). +First we show how to change the input parameters of the function, as follows: -Second we show how to use this more comprehensive output, allowing the control of code generation and `fig` object production. +* control over whether code gets executed, +* the number of retries of `.plot` when it fails validation, +* how to request a comprehensive output (when `return_elements=True`). + +Second we show how to use this more comprehensive output, enabling control of code generation and `fig` object production. ## Inputs of `VizroAI.plot` @@ -14,7 +17,7 @@ This is the natural language query from which, together with a data sample, the ### `df` -Provide any `pandas` data frame to base your query on. The LLM will receive a sample of this data frame to form an appropriate graph. +Supply any `pandas` data frame to base your query on. The LLM will receive a sample of this data frame to form an appropriate graph. If the option `validate_code` is set to `True` (which it is by default), the LLM created chart code will be evaluated on a sample of this data frame. @@ -27,14 +30,14 @@ This number determines how often the tool will try to correct an incorrect respo ### `return_elements` This boolean (by default `False`) determines the return type of `VizroAI.plot`. -If set to `False`, then dynamically generated Python code is executed to produce a `plotly.graph_objects.Figure` object from the LLM response and the user provided data frame. Strictly speaking, it produces a `vizro.charts._charts_utils._DashboardReadyFigure`, which behaves essentially like the former, but is ready to be [inserted](add-generated-chart-usecase.md) into a [Vizro](https://vizro.readthedocs.io/en/stable/) dashboard. It also comes with the default Vizro dark theme. +If set to `False`, then dynamically generated Python code is executed to produce a `plotly.graph_objects.Figure` object from the LLM response and the user supplied data frame. Strictly speaking, it produces a `vizro.charts._charts_utils._DashboardReadyFigure`, which behaves essentially like the former, but is ready to be [inserted](add-generated-chart-usecase.md) into a [Vizro](https://vizro.readthedocs.io/en/stable/) dashboard. It also comes with the default Vizro dark theme. If set to `True`, a class (pydantic model) is returned from which the `fig` object, but also various other outputs can be generated. (see below) ### `validate_code` This boolean (by default `True`) determines whether the LLM generated Python code executes with a sample of the data in order to verify that it runs and produces a plotly figure. Be sure [to read and understand what it means when dynamically generated code is executed](../explanation/safety-in-vizro-ai.md#execution-of-dynamic-code-in-vizro-ai). -If `return_elements=True` AND `validate_code=False`, then NO code is executed to obtain the return of `VizroAI.plot`. This means that the code string obtained is not validated, but also that no code was executed. +If `return_elements=True` **and** `validate_code=False`, then no code is executed to obtain the return of `VizroAI.plot`. This means that the code string obtained is not validated, but also that no code was executed. ## Output if `return_elements=True` @@ -153,11 +156,14 @@ This `fig` object is a basic plotly figure. [VizroAIChartPlotly]: ../../assets/user_guides/VizroAIPlotly.png #### Using different data -You can create the `fig` object with different data while ensuring the overall schema remains consistent. You can re-evaluate this function to generate various `fig` objects for different datasets. For example, the code could be generated using fake or sample data fed into Vizro-AI. When moving to production, you can switch the data source to the complete dataset, as long as the data schema is consistent. + +You can create the `fig` object with different data while ensuring the overall schema remains consistent. You can re-evaluate this function to generate various `fig` objects for different data. For example, the code could be generated using fake or sample data fed into Vizro-AI. When moving to production, you can switch the data source to the complete dataset, as long as the data schema is consistent. + !!! example "Different data" === "Code" + ```py from vizro_ai import VizroAI import plotly.express as px @@ -180,12 +186,13 @@ You can create the `fig` object with different data while ensuring the overall s ``` #### Changing the chart name -This option executes the chart code with the name provided under `chart_name`. This can be important when you want to avoid overwriting variables in the namespace. +This option executes the chart code with the name given under `chart_name`. This can be important when you want to avoid overwriting variables in the namespace. !!! example "Changing the `chart_name`" === "Code" + ```py from vizro_ai import VizroAI import plotly.express as px diff --git a/vizro-ai/docs/pages/user-guides/customize-vizro-ai.md b/vizro-ai/docs/pages/user-guides/customize-vizro-ai.md index f8d0e25db..e2a4e883b 100644 --- a/vizro-ai/docs/pages/user-guides/customize-vizro-ai.md +++ b/vizro-ai/docs/pages/user-guides/customize-vizro-ai.md @@ -8,14 +8,14 @@ Vizro-AI supports **any** model that is available via [Langchain's `BaseChatMode ### Setting model via string for ease of use -We have created shortcuts with sensible defaults (mainly setting `temperature=0`) for some common vendors. These models can be chosen by using the string format in the tabs below. If no model is provided, the default (currently `"gpt-4o-mini"`) is selected. +We have created shortcuts with sensible defaults (mainly setting `temperature=0`) for some common vendors. These models can be chosen by using the string format in the tabs below. If no model is supplied, the default (currently `"gpt-4o-mini"`) is selected. ```py vizro_ai = VizroAI(model="") ``` !!!note - For the string settings to work, you must provide your API key via environment variables. The relevant variable names to be set are noted in each vendor tab. + For the string settings to work, you must supply your API key via environment variables. The relevant variable names to be set are noted in each vendor tab. === "OpenAI" @@ -80,7 +80,9 @@ vizro_ai = VizroAI(model="") !!!note When choosing the string representation, it sometimes can be tricky to have the correct environment variable set for the API key (and potential base URL). In case you cannot get this to work, we recommend instantiating the model directly (see below) and providing the API key via the models parameters. + ### Setting model via class for additional configuration + Beyond passing a string, you can pass **any** model derived from [Langchain's `BaseChatModel` class](https://api.python.langchain.com/en/latest/language_models/langchain_core.language_models.chat_models.BaseChatModel.html#langchain_core.language_models.chat_models.BaseChatModel) that has the [`with_structured_output` method](https://python.langchain.com/v0.2/docs/how_to/structured_output/#the-with_structured_output-method) implemented. An overview of the [most common vendor models supporting this functionality](https://python.langchain.com/v0.2/docs/integrations/chat/) can be found in Langchain's documentation. When choosing this approach, you can customize your model beyond the chosen default from the string instantiation. The choice of available arguments depends on the specific vendor implementation, but usually the main parameter to tweak is the temperature. @@ -112,10 +114,10 @@ Passing an instantiated model to `VizroAI` lets you customize it, and additional ### Chart generation -At the time of writing, we found that for chart creation, some of the leading vendor's "cheaper" models, for example OpenAI's `gpt-4o-mini` and `gpt-3.5` model series, are suitable for basic charting despite their relatively low price points. +At the time of writing, we found that for chart creation, the leading vendor's "cheaper" models, for example OpenAI's `gpt-4o-mini` and `gpt-3.5` model series, are suitable for basic charting despite their relatively low price points. Consider upgrading to, in the case of OpenAI the `gpt-4o` and `gpt-4` model series, or in the case of Anthropic the `claude-3-5-sonnet-20240620` model series, for more demanding tasks. The downside of using these models is that they come at a higher cost. ### Dashboard generation -At the time of writing we find that cheaper models only allow for basic dashboards. For a reasonably complex dashboard we recommend the flagship models of the leading vendors, for example `gpt-4o` or `claude-3-5-sonnet-20240620`. +At the time of writing we find that cheaper models only work for basic dashboards. For a reasonably complex dashboard we recommend the flagship models of the leading vendors, for example `gpt-4o` or `claude-3-5-sonnet-latest`. diff --git a/vizro-ai/docs/pages/user-guides/install.md b/vizro-ai/docs/pages/user-guides/install.md index 249c690e7..9ecee589f 100644 --- a/vizro-ai/docs/pages/user-guides/install.md +++ b/vizro-ai/docs/pages/user-guides/install.md @@ -113,11 +113,11 @@ To make the OpenAI API key available for all projects, you can set it as a syste variable. Refer to the section ["Set up your API key for all projects"](https://platform.openai.com/docs/quickstart/step-2-setup-your-api-key?context=python) in the OpenAI documentation. (It is under the dropdown of "Step 2: Set up your API key"). -The documentation provides step-by-step instructions for setting up the API key as an environment +The documentation gives step-by-step instructions for setting up the API key as an environment variable, on operating systems including Windows and MacOS. !!!note - Sometimes setting up the `.env` file can be fiddly. If necessary, you can provide the API key directly to the instantiated model. See [our user guide](./customize-vizro-ai.md#setting-model-via-class-for-additional-configuration) for this option. Remember not to commit this API key to any public space! + Sometimes setting up the `.env` file can be fiddly. If necessary, you can supply the API key directly to the instantiated model. See [our user guide](./customize-vizro-ai.md#setting-model-via-class-for-additional-configuration) for this option. Remember not to commit this API key to any public space! __Set the base URL (optional)__ diff --git a/vizro-ai/docs/pages/user-guides/retrieve-dashboard-code.md b/vizro-ai/docs/pages/user-guides/retrieve-dashboard-code.md index c3219c66b..a95d1159a 100644 --- a/vizro-ai/docs/pages/user-guides/retrieve-dashboard-code.md +++ b/vizro-ai/docs/pages/user-guides/retrieve-dashboard-code.md @@ -1,8 +1,8 @@ # Retrieve the code of Vizro-AI generated dashboard -This guide shows how to retrieve the code of a Vizro-AI generated dashboard. The code can be used for further iterations, improvements and deployment. +This guide shows how to retrieve the code of a Vizro-AI generated dashboard. The code can be used for further iterations, improvements, and deployment. -While Vizro-AI can follow complex user requirements well and generate high-quality dashboards, due to the nature of LLMs, the generated dashboards often only approximately match user expectations. Besides refining the user prompt and re-running Vizro-AI, you can also extract the code and iterate manually to achieve the desired result. +While Vizro-AI can follow complex user requirements well and generate high-quality dashboards, due to the nature of LLMs, the generated dashboards often only partly match user expectations. Besides refining the user prompt and re-running Vizro-AI, you can also extract the code and iterate manually to achieve the desired result. ## 1. Prepare the data and user prompt diff --git a/vizro-ai/docs/pages/user-guides/run-vizro-ai.md b/vizro-ai/docs/pages/user-guides/run-vizro-ai.md index 5b6be6426..192df9ea5 100644 --- a/vizro-ai/docs/pages/user-guides/run-vizro-ai.md +++ b/vizro-ai/docs/pages/user-guides/run-vizro-ai.md @@ -64,5 +64,5 @@ You can use Vizro-AI in any standard development environment by creating a `.py` ## Application integration You may prefer to integrate Vizro-AI into an application that offers a UI for users to input prompts. For that you can take the `fig` object from the `.plot` call, and use it elsewhere -in any application after potentially processing it further (such as serializing it or similar). It is also possible to obtain the code that would produce the object. For any advanced usage options, refer to +in any application (you might also want to process it further, for example, by serializing it or similar). It is also possible to obtain the code that would produce the object. For any advanced usage options, refer to [our advanced options guide](advanced-options.md). diff --git a/vizro-core/docs/pages/explanation/authors.md b/vizro-core/docs/pages/explanation/authors.md index de7631952..c59700a4a 100644 --- a/vizro-core/docs/pages/explanation/authors.md +++ b/vizro-core/docs/pages/explanation/authors.md @@ -10,11 +10,11 @@ [Maximilian Schulz](https://github.com/maxschulz-COL), [Nadija Graca](https://github.com/nadijagraca), [Petar Pejovic](https://github.com/petar-qb) - + ## Previous team members and code contributors - + [Ann Marie Ward](https://github.com/AnnMarieW), [Ned Letcher](https://github.com/ned2), Natalia Kurakina, diff --git a/vizro-core/docs/pages/explanation/contributing.md b/vizro-core/docs/pages/explanation/contributing.md index c98070a39..7e532ae3b 100644 --- a/vizro-core/docs/pages/explanation/contributing.md +++ b/vizro-core/docs/pages/explanation/contributing.md @@ -53,7 +53,9 @@ The Hatch commands you need most commonly are as follows. These must be executed * [`hatch run docs:serve`](#hatch-run-docsserve) builds and displays documentation that hot-reloads while you edit it. Documentation is also built automatically in your PR and can be previewed on Read The Docs. * [`hatch run pip`](#hatch-run-pip) provides a [pip-compatible interface using uv](https://docs.astral.sh/uv/pip/). You should not need to use this much. + To save yourself from repeatedly typing `hatch run` you might like to [set up an alias](https://www.tecmint.com/create-alias-in-linux/): + ```console alias hr="hatch run" @@ -74,7 +76,7 @@ This enables you to run, for example, `hr lint` instead of `hatch run lint`. On `hatch run example` runs an example dashboard on port 8050 that hot-reloads while you edit it. On GitHub Codespaces, this [runs automatically on startup](https://docs.github.com/en/codespaces/developing-in-a-codespace/forwarding-ports-in-your-codespace) and is labeled as `scratch_dev example`. On your local machine, you can access the dashboard by pointing your browser to [http://127.0.0.1:8050](http://127.0.0.1:8050). -By default, this command runs the dashboard configured in `vizro-core/examples/scratch_dev/app.py`. This dashboard is used as a temporary "scratch" playground during development. Since it is opened automatically in GitHub Codespaces, it's the perfect place to demonstrate or test out a new feature you're developing. PR reviewers can then immediately see exactly what your changes do by opening a codespace on your branch. +By default, this command runs the dashboard configured in `vizro-core/examples/scratch_dev/app.py`. This dashboard is used as a temporary "scratch" playground during development. Since it is opened automatically in GitHub Codespaces, it's the perfect place to show, or test out, a new feature you're developing. PR reviewers can then immediately see exactly what your changes do by opening a codespace on your branch. You can run any example in `vizro-core/examples` or its subdirectories by running `hatch run example `, where `` is the path to the directory containing the `app.py` file relative to `vizro-core/examples`. For example, `hatch run example dev` runs a dashboard located at `vizro-core/examples/dev/app.py`. This dashboard demonstrates a full set of Vizro features and is also [hosted on Hugging Face](https://huggingface.co/spaces/vizro/demo-features). @@ -139,9 +141,13 @@ For more information on our documentation style, refer to our [style guide](docu `hatch run pip` provides a [pip-compatible interface using uv](https://docs.astral.sh/uv/pip/). You should not need to use this often. -Vizro's dependencies are described by the `dependencies` section in `vizro-core/pyproject.toml`. There is no need to manually install or update the dependencies in your environment; they will be handled automatically for you when you do `hatch run`. This means that there is generally no need to `pip install` anything. +Vizro's dependencies are described by the `dependencies` section in `vizro-core/pyproject.toml`. There is no need to manually install or update the dependencies in your environment; they will be handled automatically for you when you do `hatch run`. This means that there is usually no need to `pip install` anything. -We have [configured Hatch to use uv](https://hatch.pypa.io/1.12/how-to/environment/select-installer/) for virtual environment creation, dependency resolution and installation. This is extremely fast. If you have installed unwanted dependencies in your Hatch environment then the simplest solution is to delete the environment (`hatch env remove` to remove one environment or `hatch env prune` to remove all environments). Your next `hatch run` command will quickly recreate the environment and install all the dependencies it needs. +We have [configured Hatch to use uv](https://hatch.pypa.io/1.12/how-to/environment/select-installer/) for rapid virtual environment creation, dependency resolution and installation. + +!!! note + + If you have installed unwanted dependencies in your Hatch environment then the simplest solution is to delete the environment (`hatch env remove` to remove one environment or `hatch env prune` to remove all environments). Your next `hatch run` command will recreate the environment and install all the dependencies it needs. If for some reason you do need to use `pip` then the correct way to do so is through `hatch run pip`. For example, you could run `hatch run pip show plotly`. This will use the version of uv that Hatch itself uses under the hood. If you already have uv installed globally then `uv pip show plotly` would also work. diff --git a/vizro-core/docs/pages/explanation/faq.md b/vizro-core/docs/pages/explanation/faq.md index 52d08174c..98dd6f051 100644 --- a/vizro-core/docs/pages/explanation/faq.md +++ b/vizro-core/docs/pages/explanation/faq.md @@ -32,12 +32,14 @@ We do not consider frontend changes (such as changing the appearance of a compon While being in version `0.x.x`, we may introduce breaking changes in minor versions. + ## Where can I find example dashboards? For a gallery of examples showing Vizro in action, take a look at [vizro.mckinsey.com](https://vizro.mckinsey.com). The gallery links to the [Vizro HuggingFace collection](https://huggingface.co/vizro), which includes complete code accessed for each example by selecting "Files" in the top right menu. We also maintain a separate, curated page of [videos, blog posts, and examples of Vizro usage from our community](your-examples.md). + ## Why should I use Vizro? Vizro is a high-level framework built on top of Dash and Pydantic, @@ -160,18 +162,22 @@ There are a number of cases where alternatives to Vizro may be more suitable, in - where Python developers are already very comfortable leveraging other Python packages - + ## How can I report a bug? Head over to our [GitHub issues](https://github.com/mckinsey/vizro/issues) and [create a new bug report](https://github.com/mckinsey/vizro/issues/new/choose). We will try to reproduce the bug you've reported and follow up with the next steps. + ## How can I request a feature? To raise a feature request, head to our [GitHub issues](https://github.com/mckinsey/vizro/issues) and [create a new feature request](https://github.com/mckinsey/vizro/issues/new/choose). The team will then try to understand the request in more detail, explore the feasibility and prioritize it in relation to the current roadmap. We will get back to you as soon as possible with an estimate of whether and when this feature could be released. + ## I still have a question. Where can I ask it? We are happy to receive general questions around Vizro. Take a look at our [GitHub issues](https://github.com/mckinsey/vizro/issues) and [create a new issue](https://github.com/mckinsey/vizro/issues/new/choose) by clicking "General question". Several Vizro team members are active on the Plotly Community Forum. If you'd like to also ask your question there then create a topic in the [Dash Python category](https://community.plotly.com/c/python/25) and make it clear that your question concerns Vizro. + + diff --git a/vizro-core/docs/pages/explanation/your-examples.md b/vizro-core/docs/pages/explanation/your-examples.md index caccd1113..6f1da044a 100644 --- a/vizro-core/docs/pages/explanation/your-examples.md +++ b/vizro-core/docs/pages/explanation/your-examples.md @@ -23,12 +23,15 @@ If you have something you'd like us to include on the list, or spot something th ## Blog posts * [Introducing Vizro](https://quantumblack.medium.com/introducing-vizro-a-toolkit-for-creating-modular-data-visualization-applications-3a42f2bec4db). * [Creating Custom Dashboards with Vizro: A Comprehensive Guide](https://medium.com/@saffand03/creating-custom-dashboards-with-vizro-a-comprehensive-guide-73c69c6f851e). + * [I built a reusable dashboard read-the-docs traffic analytics using vizro](https://medium.com/towards-data-science/i-built-a-reusable-dashboard-for-read-the-docs-traffic-analytics-using-vizro-47dc15dc04f8). + * [Visualizing data science insights](https://medium.com/quantumblack/visualizing-data-science-insights-dfc8ad0646b6). + * [A low-code, attractive, sharable data dashboard: Illustrating my LinkedIn connections in 100 lines of Python](https://medium.com/design-bootcamp/a-low-code-attractive-sharable-data-dashboard-a60badba2a03). ## Examples on GitHub or PyCafe - + * [Personal Vizro app demos by Vizro team member `huong-li-nguyen`](https://github.com/huong-li-nguyen/vizro-app-demos). * [Proof of concept example by `viiviandias`](https://github.com/viiviandias/poc-vizro/blob/main/brasil_stocks.ipynb). * [Amazon sales analysis by `Bottleneck44`](https://github.com/Bottleneck44/Amazon-Sales-Analysis/blob/main/Amazon-analysis.ipynb). diff --git a/vizro-core/docs/pages/tutorials/explore-components.md b/vizro-core/docs/pages/tutorials/explore-components.md index a83734fc5..52a0ef3e3 100644 --- a/vizro-core/docs/pages/tutorials/explore-components.md +++ b/vizro-core/docs/pages/tutorials/explore-components.md @@ -28,6 +28,7 @@ The code below shows the steps necessary to add a box plot to the page: !!! example "First component" === "app.py" + ```{.python pycafe-link} from vizro import Vizro import vizro.models as vm @@ -113,6 +114,7 @@ The code below adds two components to the page: ) ``` === "app.py" + ```{.python pycafe-link} from vizro import Vizro import vizro.models as vm @@ -204,6 +206,7 @@ Run the code below to apply the layout to the dashboard page: layout=vm.Layout(grid=[[0, 0], [1, 2], [1, 2], [1, 2]]) ``` === "app.py" + ```{.python pycafe-link} from vizro import Vizro import vizro.models as vm @@ -276,6 +279,7 @@ are listed in the `targets` parameter, meaning that the filter is be applied to ] ``` === "app.py" + ```{.python pycafe-link} from vizro import Vizro import vizro.models as vm @@ -389,6 +393,7 @@ for parameters](../user-guides/parameters.md). ) ``` === "app.py" + ```{.python pycafe-link} from vizro import Vizro import vizro.models as vm @@ -542,6 +547,7 @@ of the subpages. Additionally, you can use the navigation panel on the left side dashboard = vm.Dashboard(pages=[home_page, first_page, second_page]) ``` === "app.py" + ```{.python pycafe-link} from vizro import Vizro diff --git a/vizro-core/docs/pages/user-guides/assets.md b/vizro-core/docs/pages/user-guides/assets.md index 045a6cd21..ae87f5527 100644 --- a/vizro-core/docs/pages/user-guides/assets.md +++ b/vizro-core/docs/pages/user-guides/assets.md @@ -44,15 +44,11 @@ If an image named `logo.` is present in the assets folder, Vizro auto You can also supply two images named `logo_dark.` and `logo_light.` to switch logos based on the theme (dark or light). -Note that both `logo_dark.` and `logo_light.` must be provided together, and they cannot be -provided if a single `logo.` is also provided for both light/dark themes. +Note that both `logo_light.` and `logo_dark.` must be supplied together, unless a single `logo.` is supplied for both light and dark themes. That is, the valid configurations are as follows: -The valid configurations are as follows: - -* Single logo: Provide only `logo.`, which is used for dark and light themes. -* Theme logos: Provide both `logo_dark.` and `logo_light.` for dark/light themes. -Do not provide `logo.`. -* No logo: No logo images provided. +* Single logo: Supply only `logo.`, which is used for dark and light themes. **Do not include light and dark theme logos**. +* Theme logos: Supply both `logo_light.` and `logo_dark.` for light/dark themes. **Do not include `logo.`**. +* No logo: No logo images supplied. ![Logo dark](../../assets/user_guides/assets/logo-dark.png) ![Logo light](../../assets/user_guides/assets/logo-light.png) diff --git a/vizro-core/docs/pages/user-guides/custom-charts.md b/vizro-core/docs/pages/user-guides/custom-charts.md index 4db31a401..cb26614c8 100644 --- a/vizro-core/docs/pages/user-guides/custom-charts.md +++ b/vizro-core/docs/pages/user-guides/custom-charts.md @@ -44,6 +44,7 @@ add a `Parameter` that enables the dashboard user to interact with the argument, !!! example "Custom `plotly.express` scatter chart with a `Parameter`" === "app.py" + ```{.python pycafe-link} import vizro.models as vm import vizro.plotly.express as px @@ -103,6 +104,7 @@ The below examples shows a more involved use-case. We create and style a waterfa !!! example "Custom `go.Figure()` waterfall chart with a `Parameter`" === "app.py" + ```{.python pycafe-link} import pandas as pd import plotly.graph_objects as go diff --git a/vizro-core/docs/pages/user-guides/custom-css.md b/vizro-core/docs/pages/user-guides/custom-css.md index 9131832a4..44e3a3621 100755 --- a/vizro-core/docs/pages/user-guides/custom-css.md +++ b/vizro-core/docs/pages/user-guides/custom-css.md @@ -218,8 +218,7 @@ Suppose you want to hide the page title on one page only. Here's how you can ach ### Overwrite CSS for selected components -To adjust CSS properties for specific components, like altering the appearance of a selected [`Card`][vizro.models.Card] rather than all Cards, -you need to provide an `id` to the component you want to style. +To adjust CSS properties for specific components, such as altering the appearance of a selected [`Card`][vizro.models.Card] rather than all Cards, you need to supply an `id` to the component you want to style. Let's say we want to change the `background-color` and `color` of a specific `Card`. diff --git a/vizro-core/docs/pages/user-guides/graph.md b/vizro-core/docs/pages/user-guides/graph.md index 973c1ab54..36c670997 100755 --- a/vizro-core/docs/pages/user-guides/graph.md +++ b/vizro-core/docs/pages/user-guides/graph.md @@ -24,6 +24,7 @@ To add a [`Graph`][vizro.models.Graph] to your page, do the following: !!! example "Graph" === "app.py" + ```{.python pycafe-link} import vizro.models as vm import vizro.plotly.express as px @@ -85,8 +86,8 @@ The [`Graph`][vizro.models.Graph] accepts a `title`, `header` and `footer` argum context to the data being displayed, or for adding a description of the data. - **title**: Displayed as an [H3 header](https://dash.plotly.com/dash-html-components/h3), useful for summarizing the main topic or insight of the component. -- **header**: Accepts Markdown text, ideal for additional descriptions, subtitles, or detailed data insights. -- **footer**: Accepts Markdown text, commonly used for citing data sources, providing information on the last update, or adding disclaimers. +- **header**: Accepts markdown text, ideal for extra descriptions, subtitles, or detailed data insights. +- **footer**: Accepts markdown text, commonly used for citing data sources, providing information on the last update, or adding disclaimers. !!! note @@ -96,6 +97,7 @@ context to the data being displayed, or for adding a description of the data. !!! example "Formatted Graph" === "app.py" + ```{.python pycafe-link} import vizro.models as vm diff --git a/vizro-core/docs/pages/user-guides/run.md b/vizro-core/docs/pages/user-guides/run.md index 2d114f9c0..29ada2935 100644 --- a/vizro-core/docs/pages/user-guides/run.md +++ b/vizro-core/docs/pages/user-guides/run.md @@ -147,7 +147,7 @@ A Vizro app wraps a Dash app, which itself wraps a Flask app. Hence to deploy a Internally, `app = Vizro()` contains a Flask app in `app.dash.server`. However, as a convenience, the Vizro `app` itself implements the [WSGI application interface](https://werkzeug.palletsprojects.com/en/3.0.x/terms/#wsgi) as a shortcut to the underlying Flask app. This means that, as in the [above example with Gunicorn](#gunicorn), the Vizro `app` object can be directly supplied to the WSGI server. -[`Vizro`][vizro.Vizro] accepts `**kwargs` that are passed through to `Dash`. This enables you to configure the underlying Dash app using the same [arguments that are available](https://dash.plotly.com/reference#dash.dash) in `Dash`. For example, in a deployment context, some of the below arguments may be useful: +[`Vizro`][vizro.Vizro] accepts `**kwargs` that are passed through to `Dash`. This enables you to configure the underlying Dash app using the same [arguments that are available](https://dash.plotly.com/reference#dash.dash) in `Dash`. For example, in a deployment context, these arguments may be useful: - `url_base_pathname`: serve your Vizro app at a specific path rather than at the domain root. For example, if you host your dashboard at http://www.example.com/my_dashboard/ then you would set `url_base_pathname="/my_dashboard/"` or an environment variable `DASH_URL_BASE_PATHNAME="/my_dashboard/"`. - `serve_locally`: set to `False` to [serve Dash component libraries from a Content Delivery Network (CDN)](https://dash.plotly.com/external-resources#serving-dash's-component-libraries-locally-or-from-a-cdn), which reduces load on the server and can improve performance. Vizro uses [jsDeliver](https://www.jsdelivr.com/) as a CDN for CSS and JavaScript sources. diff --git a/vizro-core/docs/pages/user-guides/table.md b/vizro-core/docs/pages/user-guides/table.md index 01e2dfe0e..19197c465 100755 --- a/vizro-core/docs/pages/user-guides/table.md +++ b/vizro-core/docs/pages/user-guides/table.md @@ -539,8 +539,8 @@ The [`Table`][vizro.models.Table] and the [`AgGrid`][vizro.models.AgGrid] models the data. - **title**: Displayed as an [H3 header](https://dash.plotly.com/dash-html-components/h3), useful for summarizing the main topic or insight of the component. -- **header**: Accepts Markdown text, ideal for additional descriptions, subtitles, or detailed data insights. -- **footer**: Accepts Markdown text, commonly used for citing data sources, providing information on the last update, or adding disclaimers. +- **header**: Accepts markdown text, ideal for extra descriptions, subtitles, or detailed data insights. +- **footer**: Accepts markdown text, commonly used for citing data sources, providing information on the last update, or adding disclaimers. diff --git a/vizro-core/docs/pages/user-guides/themes.md b/vizro-core/docs/pages/user-guides/themes.md index dad1319d6..6f78441d5 100644 --- a/vizro-core/docs/pages/user-guides/themes.md +++ b/vizro-core/docs/pages/user-guides/themes.md @@ -9,6 +9,7 @@ a `vizro_dark` and a `vizro_light` theme. If not specified then `theme` defaults !!! example "Change theme" === "app.py" + ```{.python pycafe-link hl_lines="18"} import vizro.models as vm import vizro.plotly.express as px diff --git a/vizro-core/docs/pages/user-guides/visual-formatting.md b/vizro-core/docs/pages/user-guides/visual-formatting.md index 252719d45..7b384f3e9 100644 --- a/vizro-core/docs/pages/user-guides/visual-formatting.md +++ b/vizro-core/docs/pages/user-guides/visual-formatting.md @@ -1,17 +1,17 @@ # How to customize the style of Vizro dashboards -Vizro has a default styling to help users with no design experience get started quickly. +Vizro has a default styling to help users with no design experience get started. There are several options if you want to customize the style: * **[Configure the `Layout`](layouts.md)**: Customize the arrangement of your components inside your Vizro dashboard. -* **[Apply a theme](themes.md)**: Choose between a dark or light theme to give your dashboard a cohesive and professional look. +* **[Apply a theme](themes.md)**: Choose between a dark or light theme. * **[Manage assets](assets.md)**: Enhance your dashboard by adding images, scripts, and stylesheets to your assets folder. * **[Customize CSS](custom-css.md)**: Incorporate custom CSS to deviate from the default styling and create a unique appearance for your Vizro dashboard. -* **[Customize your `component`](components.md)**: Modify the appearance of components like the [Graph](graph.md), the -[Table](table.md) and the [AgGrid](table.md), by passing additional arguments. Refer to the relevant user guide for +* **[Customize your `component`](components.md)**: Change the appearance of components like the [Graph](graph.md), the +[Table](table.md) and the [AgGrid](table.md), by passing extra arguments. Refer to the relevant user guide for more details. From 04b922ab338e1724a38f9ddb497e5bcb83fee6ff Mon Sep 17 00:00:00 2001 From: Maximilian Schulz <83698606+maxschulz-COL@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:56:08 +0100 Subject: [PATCH 3/3] [CI] Add VizroAI charts UI (#852) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/build-vizro-whl.yml | 16 ++++++++++++++++ tools/pycafe/create_pycafe_links.py | 11 +++++++++++ vizro-core/examples/scratch_dev/app.py | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-vizro-whl.yml b/.github/workflows/build-vizro-whl.yml index af9fb86ce..4b1b00f6b 100644 --- a/.github/workflows/build-vizro-whl.yml +++ b/.github/workflows/build-vizro-whl.yml @@ -36,3 +36,19 @@ jobs: name: pip path: vizro-core/dist/*.whl retention-days: 14 + # The below can be commented out in order to dry run the test creation of the PyCafe links + # Once satisfied, comment them again, because the actual links will be created by the pycafe-dashboards.yml workflow + # which is run from the main branch + ############### Start of PyCafe links creation ############### + # - name: Print PR Number + # run: | + # echo "Pull Request Number: ${{ github.event.workflow_run.pull_requests[0].number }}" + # - name: Create PyCafe links + # run: | + # PR_NUMBER=${{ github.event.workflow_run.pull_requests[0].number || '' }} + # if [ -n "$PR_NUMBER" ]; then + # hatch run python ../tools/pycafe/create_pycafe_links.py --github-token ${{ github.token }} --repo-name ${{ github.repository }} --pr-number $PR_NUMBER --run-id ${{ github.run_id }} --commit-sha ${{ github.sha }} + # else + # hatch run python ../tools/pycafe/create_pycafe_links.py --github-token ${{ github.token }} --repo-name ${{ github.repository }} --run-id ${{ github.run_id }} --commit-sha ${{ github.sha }} + # fi + ############### End of PyCafe links creation ############### diff --git a/tools/pycafe/create_pycafe_links.py b/tools/pycafe/create_pycafe_links.py index 68c94e798..87ac4d928 100644 --- a/tools/pycafe/create_pycafe_links.py +++ b/tools/pycafe/create_pycafe_links.py @@ -147,6 +147,17 @@ def post_comment(urls: dict[str, str]): "isort==5.13.2", "plotly==5.24.1", ], + "vizro-ai/examples/dashboard_ui/": [ + "vizro-ai>=0.3.0", + "black", + "openpyxl", + "langchain_anthropic", + "langchain_mistralai", + "greenlet # mock", + "tiktoken @ https://py.cafe/files/maartenbreddels/tiktoken-demo/tiktoken-0.7.0-cp312-cp312-pyodide_2024_0_wasm32.whl", + "https://py.cafe/files/maartenbreddels/jiter-demo/jiter-0.6.1-cp312-cp312-pyodide_2024_0_wasm32.whl", + "https://py.cafe/files/maartenbreddels/tokenizers-demo/tokenizers-0.20.2.dev0-cp312-cp312-pyodide_2024_0_wasm32.whl", + ], } urls = { directory: generate_link(directory, extra_requirements) diff --git a/vizro-core/examples/scratch_dev/app.py b/vizro-core/examples/scratch_dev/app.py index db0b4bb68..84e70e6aa 100644 --- a/vizro-core/examples/scratch_dev/app.py +++ b/vizro-core/examples/scratch_dev/app.py @@ -28,7 +28,7 @@ page = vm.Page( - title="Test New ZZZZZZZ", + title="Charts UI", components=[ vm.Graph( figure=px.bar(