{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Inspired and based on:\n", "- https://shiny.rstudio.com/gallery/movie-explorer.html\n", "- https://demo.bokeh.org/movies\n", "- https://github.com/bokeh/bokeh/tree/master/examples/app/movies" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "parameters" ] }, "outputs": [], "source": [ "flex_title = \"Movie explorer\"\n", "flex_source_code = \"https://github.com/danielfrg/jupyter-flex/blob/master/examples/movie-explorer.ipynb\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "meta" ] }, "outputs": [], "source": [ "import sqlite3 as sql\n", "from os.path import dirname, join\n", "\n", "import numpy as np\n", "import pandas.io.sql as psql\n", "\n", "import plotly.graph_objects as go\n", "from bokeh.sampledata.movies_data import movie_path\n", "\n", "import ipywidgets as widgets\n", "from IPython.display import display" ] }, { "cell_type": "markdown", "metadata": { "tags": [ "sidebar" ] }, "source": [ "# Sidebar" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "axis_map = {\n", " \"Tomato Meter\": \"Meter\",\n", " \"Numeric Rating\": \"numericRating\",\n", " \"Number of Reviews\": \"Reviews\",\n", " \"Box Office (dollars)\": \"BoxOffice\",\n", " \"Length (minutes)\": \"Runtime\",\n", " \"Year\": \"Year\",\n", "}" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "genres = \"\"\"\n", "All\n", "Action\n", "Adventure\n", "Animation\n", "Biography\n", "Comedy\n", "Crime\n", "Documentary\n", "Drama\n", "Family\n", "Fantasy\n", "History\n", "Horror\n", "Music\n", "Musical\n", "Mystery\n", "Romance\n", "Sci-Fi\n", "Short\n", "Sport\n", "Thriller\n", "War\n", "Western\n", "\"\"\"" ] }, { "cell_type": "markdown", "metadata": { "tags": [ "size=700" ] }, "source": [ "### Filter" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "inputs" ] }, "outputs": [], "source": [ "components = []\n", "\n", "reviews_label = widgets.HTML(value=\"Minimum number of reviews on Rotten Tomatoes:\")\n", "reviews = widgets.IntSlider(value=80, min=10, max=300, step=1)\n", "components.extend([reviews_label, reviews])\n", "\n", "released_year_label = widgets.HTML(value=\"Year released:\")\n", "released_year = widgets.IntRangeSlider(value=[1970, 2014], min=1940, max=2014, step=1)\n", "components.extend([released_year_label, released_year])\n", "\n", "oscars_label = widgets.HTML(value=\"Minimum number of Oscar wins (all categories):\")\n", "oscars = widgets.IntSlider(value=0, min=0, max=4, step=1)\n", "components.extend([oscars_label, oscars])\n", "\n", "boxoffice_label = widgets.HTML(value=\"Dollars at Box Office (millions):\")\n", "boxoffice = widgets.IntSlider(value=0, min=0, max=800, step=1)\n", "components.extend([boxoffice_label, boxoffice])\n", "\n", "genre_label = widgets.HTML(value=\"Genre (a movie can have multiple genres):\")\n", "genre = widgets.Dropdown(options=genres.split(\"\\n\"), value=\"All\")\n", "components.extend([genre_label, genre])\n", "\n", "director_label = widgets.HTML(value=\"Director name contains (e.g., Miyazaki):\")\n", "director = widgets.Text()\n", "components.extend([director_label, director])\n", "\n", "cast_label = widgets.HTML(value=\"Cast names contains (e.g. Tom Hanks):\")\n", "cast = widgets.Text()\n", "components.extend([cast_label, cast])\n", "\n", "all_widgets = widgets.VBox(components)\n", "all_widgets" ] }, { "cell_type": "markdown", "metadata": { "tags": [ "size=300" ] }, "source": [ "### Variables" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "inputs" ] }, "outputs": [], "source": [ "components = []\n", "\n", "x_axis_label = widgets.HTML(value=\"X-axis variable:\")\n", "x_axis = widgets.Dropdown(options=list(axis_map.items()), value=\"Meter\")\n", "components.extend([x_axis_label, x_axis])\n", "\n", "y_axis_label = widgets.HTML(value=\"Y-axis variable:\")\n", "y_axis = widgets.Dropdown(options=list(axis_map.items()), value=\"Reviews\")\n", "components.extend([y_axis_label, y_axis])\n", "\n", "note = \"Note: The Tomato Meter is the proportion of positive reviews (as judged by the Rotten Tomatoes staff), and the Numeric rating is a normalized 1-10 score of those reviews which have star ratings (for example, 3 out of 4 stars).\"\n", "note_label = widgets.HTML(value=note)\n", "components.append(note_label)\n", "\n", "all_widgets = widgets.VBox(components)\n", "all_widgets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Movies" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Column" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "conn = sql.connect(movie_path)\n", "\n", "query = \"\"\"\n", "SELECT omdb.ID,\n", " imdbID,\n", " Title,\n", " Year,\n", " omdb.Rating as mpaaRating,\n", " Runtime,\n", " Genre,\n", " Released,\n", " Director,\n", " Writer,\n", " omdb.Cast,\n", " imdbRating,\n", " imdbVotes,\n", " Language,\n", " Country,\n", " Oscars,\n", " tomatoes.Rating as numericRating,\n", " Meter,\n", " Reviews,\n", " Fresh,\n", " Rotten,\n", " userMeter,\n", " userRating,\n", " userReviews,\n", " BoxOffice,\n", " Production\n", "FROM omdb, tomatoes\n", "WHERE omdb.ID = tomatoes.ID AND Reviews >= 10\n", "\"\"\"\n", "\n", "movies = psql.read_sql(query, conn)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "movies[\"color\"] = np.where(movies[\"Oscars\"] > 0, \"orange\", \"grey\")\n", "movies[\"alpha\"] = np.where(movies[\"Oscars\"] > 0, 0.9, 0.25)\n", "movies.fillna(0, inplace=True) # just replace missing values with zero\n", "movies[\"revenue\"] = movies.BoxOffice.apply(lambda x: '{:,d}'.format(int(x)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fig = go.FigureWidget()\n", "plot = go.Scatter(x=[], y=[], mode=\"markers\", text=[], hoverinfo=\"text\", marker=dict(color=[], opacity=[], size=7))\n", "fig.add_trace(plot)\n", "\n", "margin = go.layout.Margin(l=20, r=20, b=20, t=30)\n", "fig = fig.update_layout(margin=margin)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def select_movies():\n", " selected = movies[\n", " (movies.Reviews >= reviews.value) &\n", " (movies.BoxOffice >= (boxoffice.value * 1e6)) &\n", " (movies.Year >= released_year.value[0]) &\n", " (movies.Year <= released_year.value[1]) &\n", " (movies.Oscars >= oscars.value)\n", " ]\n", " if (genre.value != \"All\"):\n", " selected = selected[selected.Genre.str.contains(genre.value)==True]\n", " if (director.value != \"\"):\n", " selected = selected[selected.Director.str.contains(director.value)==True]\n", " if (cast.value != \"\"):\n", " selected = selected[selected.Cast.str.contains(cast.value)==True]\n", " return selected\n", "\n", "\n", "def on_value_change(change):\n", " df = select_movies()\n", " x_name = x_axis.value\n", " y_name = y_axis.value\n", "\n", " fig.data[0]['x'] = df[x_name]\n", " fig.data[0]['y'] = df[y_name]\n", " fig.data[0]['marker']['color'] = df[\"color\"]\n", " fig.data[0]['marker']['opacity'] = df[\"alpha\"]\n", " fig.data[0]['text'] = df[\"Title\"] + \"
\" + df[\"Year\"].astype(str) + \"
\" + df[\"BoxOffice\"].astype(str)\n", " \n", " fig.update_xaxes(title_text=x_axis.label)\n", " fig.update_yaxes(title_text=y_axis.label)\n", " fig.update_layout(title=\"%d movies selected\" % len(df))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "controls = [reviews, boxoffice, released_year, oscars, genre, director, cast, x_axis, y_axis]\n", "for control in controls:\n", " control.observe(on_value_change, names=\"value\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "chart" ] }, "outputs": [], "source": [ "on_value_change(None)\n", "fig" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "celltoolbar": "Tags", "kernelspec": { "display_name": "Python 3", "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.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }