{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "150de2e4-622f-4d0f-91a2-ad47dd16c53a", "metadata": {}, "outputs": [], "source": [ "# Vizro-AI setup\n", "\n", "from vizro import Vizro\n", "import vizro_ai\n", "from vizro_ai import VizroAI\n", "from dotenv import load_dotenv\n", "\n", "# Ensure the API key is in .env\n", "load_dotenv()\n", "\n", "# Choose your model\n", "\n", "vizro_ai = VizroAI(model=\"gpt-4-turbo\")\n", "\n", "import pandas as pd\n", "\n", "df = pd.read_csv('filtered_books.csv')\n", "df[\"Date Read\"] = pd.to_datetime(df['Date Read'],dayfirst=True)\n", "\n", "# Data cleanup \n", "# Specify columns to check for missing values\n", "columns_to_check = ['Title', 'Author', 'ISBN', 'My Rating', 'Average Rating', 'Number of Pages', 'Original Publication Year', 'Date Read']\n", "df_cleaned = df.dropna(subset=columns_to_check)\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "1cbbea13-28f1-47fc-9348-9e41ba178463", "metadata": {}, "outputs": [], "source": [ "# Specifiy the prompt here\n", "user_question = \"\"\"\n", "Create a dashboard with 3 pages, one for each chart. \n", "\n", "On the first page, plot a chart with the title \"Sequence of reading\" . \n", "It is a scatter chart. Use the x axis to show the date a book was read. Plot it at y=1.\n", "Add a filter so the user can adjust the range of dates by year on the x axis.\n", "\n", "On the second page, plot a chart with the title \"Pages and Book totals\" . \n", "It shows the cumulative total number of pages read by summing the Number of Pages of each book read in each year, using the Date Read data. \n", "Plot date on the x axis and the number of pages on the y axis using a scale on the left hand side of the chart.\n", "Superimpose a bar chart showing the total books read for each year, taking data from the Date Read column. \n", "Show the total books read using the right hand side of the chart which can be a different scale to the y axis shown on the left hand side. \n", "Add a filter so the user can adjust the range of dates by year on the x axis.\n", "\n", "On the third page, for each row, create a dumbbell chart to show the difference between My Rating and Average Rating for each book.\n", "Use shapes to add the horizontal lines between markers. Omit the legend. Don't show any row where My Rating is 0.\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": 3, "id": "14e9f5de-1ace-44cd-8b3a-3f1ee805fe2e", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "72dc4d9d9a6748d4b651dc76197bc8b5", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Store df info: 0%| | 0/1 [00:00 components: 0%| | 0/1 [00:00 components: 0%| | 0/1 [00:00 components: 0%| | 0/1 [00:00 controls: 0%| | 0/1 [00:00 controls: 0it [00:00, ?it/s]" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "5055cf7208594dbe8bf0db4621ffff25", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Currently Building ... [Page] controls: 0%| | 0/1 [00:00. Definition will not be included.\n", "WARNING:root:Could not extract source for . Definition will not be included.\n", "WARNING:root:Could not extract source for . Definition will not be included.\n" ] }, { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "############ Imports ##############\n", "import vizro.models as vm\n", "from vizro.models.types import capture\n", "import pandas as pd\n", "import plotly.graph_objects as go\n", "from vizro.models.types import capture\n", "\n", "\n", "####### Function definitions ######\n", "@capture(\"graph\")\n", "def sequence_reading(data_frame):\n", " fig = go.Figure()\n", " fig.add_trace(\n", " go.Scatter(\n", " x=data_frame[\"Date Read\"],\n", " y=[1] * len(data_frame),\n", " mode=\"markers\",\n", " marker=dict(size=10, color=\"blue\"),\n", " )\n", " )\n", " fig.update_layout(\n", " title=\"Sequence of reading\",\n", " xaxis_title=\"Date Read\",\n", " yaxis_title=\"Sequence\",\n", " yaxis=dict(showticklabels=False, showgrid=False),\n", " xaxis=dict(tickangle=-45),\n", " )\n", " return fig\n", "\n", "\n", "@capture(\"graph\")\n", "def pages_books_totals(data_frame):\n", " # Prepare data\n", " data_frame[\"Date Read\"] = pd.to_datetime(data_frame[\"Date Read\"])\n", " data_frame.sort_values(\"Date Read\", inplace=True)\n", " data_frame[\"Cumulative Pages\"] = data_frame[\"Number of Pages\"].cumsum()\n", "\n", " # Aggregate data by year for total books read\n", " yearly_books = data_frame.groupby(data_frame[\"Date Read\"].dt.year).size()\n", "\n", " # Create figure with secondary y-axis\n", " fig = go.Figure()\n", "\n", " # Add line for cumulative pages\n", " fig.add_trace(\n", " go.Scatter(\n", " x=data_frame[\"Date Read\"],\n", " y=data_frame[\"Cumulative Pages\"],\n", " mode=\"lines\",\n", " name=\"Cumulative Pages Read\",\n", " )\n", " )\n", "\n", " # Add bars for books read per year\n", " fig.add_trace(\n", " go.Bar(\n", " x=yearly_books.index, y=yearly_books, name=\"Books Read per Year\", yaxis=\"y2\"\n", " )\n", " )\n", "\n", " # Set up the layout\n", " fig.update_layout(\n", " title=\"Cumulative Pages Read and Books Read per Year\",\n", " xaxis_title=\"Date\",\n", " yaxis=dict(title=\"Number of Pages\"),\n", " yaxis2=dict(title=\"Total Books\", overlaying=\"y\", side=\"right\"),\n", " )\n", "\n", " return fig\n", "\n", "\n", "@capture(\"graph\")\n", "def rating_comparison(data_frame):\n", " # Filter out rows where 'My Rating' is 0\n", " df = data_frame[data_frame[\"My Rating\"] != 0]\n", "\n", " # Create a figure\n", " fig = go.Figure()\n", "\n", " # Add dumbbell traces\n", " for index, row in df.iterrows():\n", " fig.add_trace(\n", " go.Scatter(\n", " x=[row[\"My Rating\"], row[\"Average Rating\"]],\n", " y=[row[\"Title\"], row[\"Title\"]],\n", " mode=\"markers+lines\",\n", " name=row[\"Title\"],\n", " marker=dict(size=10),\n", " line=dict(width=2),\n", " )\n", " )\n", "\n", " # Update layout\n", " fig.update_layout(\n", " title=\"Comparison of My Rating vs Average Rating\",\n", " xaxis_title=\"Rating\",\n", " yaxis_title=\"Book Title\",\n", " showlegend=False,\n", " )\n", "\n", " return fig\n", "\n", "\n", "####### Data Manager Settings #####\n", "#######!!! UNCOMMENT BELOW !!!#####\n", "# from vizro.managers import data_manager\n", "# data_manager[\"book_reading_data\"] = ===> Fill in here <===\n", "\n", "\n", "########### Model code ############\n", "model = vm.Dashboard(\n", " pages=[\n", " vm.Page(\n", " components=[\n", " vm.Graph(\n", " id=\"sequence_reading\",\n", " figure=sequence_reading(data_frame=\"book_reading_data\"),\n", " )\n", " ],\n", " title=\"Sequence of Reading\",\n", " layout=vm.Layout(grid=[[0]]),\n", " controls=[\n", " vm.Filter(\n", " column=\"Year Published\",\n", " targets=[\"sequence_reading\"],\n", " selector=vm.RangeSlider(type=\"range_slider\"),\n", " )\n", " ],\n", " ),\n", " vm.Page(\n", " components=[\n", " vm.Graph(\n", " id=\"pages_books_totals\",\n", " figure=pages_books_totals(data_frame=\"book_reading_data\"),\n", " )\n", " ],\n", " title=\"Pages and Book Totals\",\n", " layout=vm.Layout(grid=[[0]]),\n", " controls=[\n", " vm.Filter(\n", " column=\"Year Published\",\n", " targets=[\"pages_books_totals\"],\n", " selector=vm.RangeSlider(type=\"range_slider\"),\n", " )\n", " ],\n", " ),\n", " vm.Page(\n", " components=[\n", " vm.Graph(\n", " id=\"rating_comparison\",\n", " figure=rating_comparison(data_frame=\"book_reading_data\"),\n", " )\n", " ],\n", " title=\"Rating Comparison\",\n", " layout=vm.Layout(grid=[[0]]),\n", " controls=[],\n", " ),\n", " ],\n", " title=\"Book Reading Analysis Dashboard\",\n", ")\n", "\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "ERROR:__main__:Exception on /_dash-update-component [POST]\n", "Traceback (most recent call last):\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/flask/app.py\", line 1473, in wsgi_app\n", " response = self.full_dispatch_request()\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/flask/app.py\", line 882, in full_dispatch_request\n", " rv = self.handle_user_exception(e)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/flask/app.py\", line 880, in full_dispatch_request\n", " rv = self.dispatch_request()\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/flask/app.py\", line 865, in dispatch_request\n", " return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/dash/dash.py\", line 1376, in dispatch\n", " ctx.run(\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/dash/_callback.py\", line 507, in add_context\n", " raise err\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/dash/_callback.py\", line 496, in add_context\n", " output_value = _invoke_callback(func, *func_args, **func_kwargs)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/dash/_callback.py\", line 43, in _invoke_callback\n", " return func(*args, **kwargs) # %% callback invoked %%\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/models/_action/_action.py\", line 181, in callback_wrapper\n", " return_value = self._action_callback_function(inputs=external, outputs=callback_outputs.get(\"external\"))\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/models/_action/_action.py\", line 110, in _action_callback_function\n", " return_value = self.function(**inputs)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/models/types.py\", line 153, in __call__\n", " return self.__function(**{**self.__bound_arguments, **kwargs})\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/actions/_on_page_load_action.py\", line 25, in _on_page_load\n", " return _get_modified_page_figures(\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/actions/_actions_utils.py\", line 278, in _get_modified_page_figures\n", " filtered_data = _apply_filters(unfiltered_data, ctds_filter, ctds_filter_interaction, target)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/actions/_actions_utils.py\", line 224, in _apply_filters\n", " filtered_data = _apply_filter_controls(data_frame=data, ctds_filter=ctds_filter, target=target)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/actions/_actions_utils.py\", line 79, in _apply_filter_controls\n", " data_frame = data_frame[_filter_function(data_frame[_filter_column], _filter_value)]\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/models/_controls/filter.py\", line 62, in _filter_between\n", " return series.between(value[0], value[1], inclusive=\"both\")\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/pandas/core/series.py\", line 5638, in between\n", " lmask = self >= left\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/pandas/core/ops/common.py\", line 76, in new_method\n", " return method(self, other)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/pandas/core/arraylike.py\", line 60, in __ge__\n", " return self._cmp_method(other, operator.ge)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/pandas/core/series.py\", line 6119, in _cmp_method\n", " res_values = ops.comparison_op(lvalues, rvalues, op)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/pandas/core/ops/array_ops.py\", line 341, in comparison_op\n", " return invalid_comparison(lvalues, rvalues, op)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/pandas/core/ops/invalid.py\", line 40, in invalid_comparison\n", " raise TypeError(f\"Invalid comparison between dtype={left.dtype} and {typ}\")\n", "TypeError: Invalid comparison between dtype=int64 and str\n", "ERROR:__main__:Exception on /_dash-update-component [POST]\n", "Traceback (most recent call last):\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/flask/app.py\", line 1473, in wsgi_app\n", " response = self.full_dispatch_request()\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/flask/app.py\", line 882, in full_dispatch_request\n", " rv = self.handle_user_exception(e)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/flask/app.py\", line 880, in full_dispatch_request\n", " rv = self.dispatch_request()\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/flask/app.py\", line 865, in dispatch_request\n", " return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/dash/dash.py\", line 1376, in dispatch\n", " ctx.run(\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/dash/_callback.py\", line 507, in add_context\n", " raise err\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/dash/_callback.py\", line 496, in add_context\n", " output_value = _invoke_callback(func, *func_args, **func_kwargs)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/dash/_callback.py\", line 43, in _invoke_callback\n", " return func(*args, **kwargs) # %% callback invoked %%\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/models/_action/_action.py\", line 181, in callback_wrapper\n", " return_value = self._action_callback_function(inputs=external, outputs=callback_outputs.get(\"external\"))\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/models/_action/_action.py\", line 110, in _action_callback_function\n", " return_value = self.function(**inputs)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/models/types.py\", line 153, in __call__\n", " return self.__function(**{**self.__bound_arguments, **kwargs})\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/actions/_on_page_load_action.py\", line 25, in _on_page_load\n", " return _get_modified_page_figures(\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/actions/_actions_utils.py\", line 278, in _get_modified_page_figures\n", " filtered_data = _apply_filters(unfiltered_data, ctds_filter, ctds_filter_interaction, target)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/actions/_actions_utils.py\", line 224, in _apply_filters\n", " filtered_data = _apply_filter_controls(data_frame=data, ctds_filter=ctds_filter, target=target)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/actions/_actions_utils.py\", line 79, in _apply_filter_controls\n", " data_frame = data_frame[_filter_function(data_frame[_filter_column], _filter_value)]\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/vizro/models/_controls/filter.py\", line 62, in _filter_between\n", " return series.between(value[0], value[1], inclusive=\"both\")\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/pandas/core/series.py\", line 5638, in between\n", " lmask = self >= left\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/pandas/core/ops/common.py\", line 76, in new_method\n", " return method(self, other)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/pandas/core/arraylike.py\", line 60, in __ge__\n", " return self._cmp_method(other, operator.ge)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/pandas/core/series.py\", line 6119, in _cmp_method\n", " res_values = ops.comparison_op(lvalues, rvalues, op)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/pandas/core/ops/array_ops.py\", line 341, in comparison_op\n", " return invalid_comparison(lvalues, rvalues, op)\n", " File \"/Users/jo_stichbury/Documents/GitHub/vizro/vizro-core/vizro/lib/python3.10/site-packages/pandas/core/ops/invalid.py\", line 40, in invalid_comparison\n", " raise TypeError(f\"Invalid comparison between dtype={left.dtype} and {typ}\")\n", "TypeError: Invalid comparison between dtype=int64 and str\n", ":9: SettingWithCopyWarning:\n", "\n", "\n", "A value is trying to be set on a copy of a slice from a DataFrame.\n", "Try using .loc[row_indexer,col_indexer] = value instead\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", "\n", ":10: SettingWithCopyWarning:\n", "\n", "\n", "A value is trying to be set on a copy of a slice from a DataFrame\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", "\n", ":11: SettingWithCopyWarning:\n", "\n", "\n", "A value is trying to be set on a copy of a slice from a DataFrame.\n", "Try using .loc[row_indexer,col_indexer] = value instead\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", "\n", ":9: SettingWithCopyWarning:\n", "\n", "\n", "A value is trying to be set on a copy of a slice from a DataFrame.\n", "Try using .loc[row_indexer,col_indexer] = value instead\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", "\n", ":10: SettingWithCopyWarning:\n", "\n", "\n", "A value is trying to be set on a copy of a slice from a DataFrame\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", "\n", ":11: SettingWithCopyWarning:\n", "\n", "\n", "A value is trying to be set on a copy of a slice from a DataFrame.\n", "Try using .loc[row_indexer,col_indexer] = value instead\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", "\n", ":9: SettingWithCopyWarning:\n", "\n", "\n", "A value is trying to be set on a copy of a slice from a DataFrame.\n", "Try using .loc[row_indexer,col_indexer] = value instead\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", "\n", ":10: SettingWithCopyWarning:\n", "\n", "\n", "A value is trying to be set on a copy of a slice from a DataFrame\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", "\n", ":11: SettingWithCopyWarning:\n", "\n", "\n", "A value is trying to be set on a copy of a slice from a DataFrame.\n", "Try using .loc[row_indexer,col_indexer] = value instead\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", "\n" ] } ], "source": [ "result = vizro_ai.dashboard([df_cleaned], user_question, return_elements=True)\n", "Vizro().build(result.dashboard).run(port=8006)\n", "print(result.code)" ] }, { "cell_type": "code", "execution_count": null, "id": "c893170d-756b-4ca8-a3a2-d3646ac8e595", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.15" } }, "nbformat": 4, "nbformat_minor": 5 }