{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import altair as alt\n", "import panel as pn\n", "\n", "from vega_datasets import data\n", "\n", "\n", "pn.extension(\"vega\", sizing_mode=\"stretch_width\", template=\"fast\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Styling Vega and Altair for Panel\n", "\n", "In this example we will show how to style Vega and Altair charts with Panel supporting the `default` and the `dark` theme.\n", "\n", "![VegaAltairStyle.gif](https://assets.holoviews.org/panel/thumbnails/gallery/styles/matplotlib-styles.gif)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Get or set the theme\n", "\n", "When we use the Fast templates the theme will be available from the query args" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def get_theme():\n", " return pn.state.session_args.get(\"theme\", [b'default'])[0].decode()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "theme=get_theme()\n", "theme" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Select a nice accent color\n", "\n", "Below we create some functionality to *cycle through* a list of nice accent colors." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "nice_accent_colors = [\n", " (\"#00A170\", \"white\"), # Mint\n", " (\"#DAA520\", \"white\"), # Golden Rod\n", " (\"#F08080\", \"white\"), # Light Coral\n", " (\"#4099da\", \"white\"), # Summery Sky\n", " (\"#2F4F4F\", \"white\"), # Dark Slate Grey\n", " (\"#A01346\", \"white\"), # Fast\n", "]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def get_nice_accent_color():\n", " \"\"\"Returns the 'next' nice accent color\"\"\"\n", " if not \"color_index\" in pn.state.cache:\n", " pn.state.cache[\"color_index\"]=0\n", " elif pn.state.cache[\"color_index\"]==len(nice_accent_colors)-1:\n", " pn.state.cache[\"color_index\"]=0\n", " else:\n", " pn.state.cache[\"color_index\"]+=1\n", " return nice_accent_colors[pn.state.cache[\"color_index\"]]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "accent_color, color = get_nice_accent_color()\n", "pn.pane.Markdown(f\"# Color: {accent_color}\", background=accent_color, height=70, margin=0, style={\"color\": color, \"padding\": \"10px\"})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Vega and Vega-lite\n", "\n", "You can configure the style of `vega` and `vega-lite` via the `config` key. Please note that only `vega-lite` supports responsive behaviour by setting `width` and `height` to `container`. `vega` requires the `width` and `height` to be integers.\n", "\n", "See [Vega Themes](https://github.com/vega/vega-themes/) and the [Vega Themes Explorer App](https://vega.github.io/vega-themes) for more examples." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def get_vega_plot(theme=\"default\", accent_color=\"blue\"):\n", " vegalite = {\n", " \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.json\",\n", " \"description\": \"A simple bar chart with rounded corners at the end of the bar.\",\n", " \"width\": \"container\",\n", " \"height\": \"container\",\n", " \"data\": {\n", " \"values\": [\n", " {\"a\": \"A\", \"b\": 28},\n", " {\"a\": \"B\", \"b\": 55},\n", " {\"a\": \"C\", \"b\": 43},\n", " {\"a\": \"D\", \"b\": 91},\n", " {\"a\": \"E\", \"b\": 81},\n", " {\"a\": \"F\", \"b\": 53},\n", " {\"a\": \"G\", \"b\": 19},\n", " {\"a\": \"H\", \"b\": 87},\n", " {\"a\": \"I\", \"b\": 52}\n", " ]\n", " },\n", " \"mark\": {\"type\": \"bar\", \"cornerRadiusEnd\": 4, \"tooltip\": True},\n", " \"encoding\": {\n", " \"x\": {\"field\": \"a\", \"type\": \"ordinal\"},\n", " \"y\": {\"field\": \"b\", \"type\": \"quantitative\"},\n", " \"color\": {\"value\": accent_color},\n", " }\n", " }\n", "\n", " if theme == \"dark\":\n", " vegalite[\"config\"] = {\n", " \"background\": \"#333\",\n", " \"title\": {\"color\": \"#fff\"},\n", " \"style\": {\"guide-label\": {\"fill\": \"#fff\"}, \"guide-title\": {\"fill\": \"#fff\"}},\n", " \"axis\": {\"domainColor\": \"#fff\", \"gridColor\": \"#888\", \"tickColor\": \"#fff\"},\n", " }\n", " return vegalite" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "vega_plot = get_vega_plot(theme=theme, accent_color=accent_color)\n", "vega_pane = pn.pane.Vega(vega_plot, height=500, sizing_mode=\"stretch_both\", name=\"VEGA\")\n", "vega_pane" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Altair\n", "\n", "You can select the theme of Altair plots using [`altair.themes.enable`](https://altair-viz.github.io/user_guide/configuration.html#altair-themes) and the color using the `configure_mark` method.\n", "\n", "For more details see the \n", "\n", "- [Altair Customization Guide](https://altair-viz.github.io/user_guide/customization.html#customizing-visualizations)\n", "- [Altair Themes Guide](https://altair-viz.github.io/user_guide/configuration.html#altair-themes)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def get_altair_plot(theme=\"default\", accent_color=\"blue\"):\n", " if theme == \"dark\":\n", " alt.themes.enable(\"dark\")\n", " else:\n", " alt.themes.enable(\"default\")\n", " return (\n", " alt.Chart(data.cars())\n", " .mark_circle(size=200)\n", " .encode(\n", " x='Horsepower:Q',\n", " y='Miles_per_Gallon:Q',\n", " tooltip=[\"Name\", \"Origin\", \"Horsepower\", \"Miles_per_Gallon\"],\n", " )\n", " .configure_mark(\n", " color=accent_color\n", " )\n", " .properties(\n", " height=\"container\",\n", " width=\"container\",\n", " )\n", " .interactive()\n", " )" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "altair_plot = get_altair_plot(theme=theme, accent_color=accent_color)\n", "altair_pane = pn.pane.Vega(altair_plot, height=500, sizing_mode=\"stretch_both\", name=\"ALTAIR\")\n", "altair_pane" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Layout and style the data app\n", "\n", "Note how we mark this component `.servable()` so that it shows up in our data app." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pn.Tabs(vega_pane, altair_pane).servable(title=\"Panel - Vega/ Altair with custom styling\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pn.state.template.param.update(accent_base_color=accent_color, header_background=accent_color)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can serve the app via `panel serve VegaAltairStyle.ipynb` and find it at http://localhost:5006/VegaAltairStyle. You should add the `--autoreload` flag while developing for *hot reloading*." ] } ], "metadata": { "language_info": { "name": "python", "pygments_lexer": "ipython3" } }, "nbformat": 4, "nbformat_minor": 5 }