Introducing Shiny for Python - R Shiny Now Available in Python
Shiny has been an R-exclusive framework from day one. Well, not anymore. At the recent <a href="https://shiny.rstudio.com/py/">RStudio Conference</a>, RStudio's CTO Joe Cheng announced Shiny for Python. Finally bringing the widely popular web framework to Python. As of August 2022, you really shouldn't use Shiny for Python for mission-critical apps in production. The whole library is still in its very early stages, and a lot is expected to change in the future. Nevertheless, there's no better time to prepare for the future and maybe (just maybe) even say <i>adios</i> to Dash and Streamlit. <blockquote>Did you know RStudio is rebranding to Posit? <a href="https://appsilon.com/posit-rstudio-rebrands/" target="_blank" rel="noopener">Learn why in our latest blog post</a>.</blockquote> Table of contents: <ul><li><a href="#introduction">What is Shiny and Shiny for Python (Py Shiny)?</a></li><li><a href="#install">How to Install and Configure Shiny in Python Ecosystem</a></li><li><a href="#dashboard">Make Your First Shiny Dashboard in Python</a></li><li><a href="#summary">Summary of Shiny for Python (Py Shiny)</a></li></ul> <hr /> <h2 id="introduction">What is Shiny and Shiny for Python (Py Shiny)?</h2> In case you're new to the topic, Shiny is a package that makes it easy to build interactive web applications and dashboards. It was previously limited to R programming language, but RStudio PBC (Posit PBC), the creators of Shiny, announced Shiny for Python. The R/Python packages are available to download on CRAN/PyPi, so getting started boils down to a single shell command. Shiny applications can be deployed as standalone web pages or embedded into R Markdown documents (R only). Overall, the deployment procedure is simple and can be done for free to an extent. <blockquote>Deployment sounds like a nightmare? <a href="https://appsilon.com/how-to-share-r-shiny-apps/" target="_blank" rel="noopener">Here are 3 simplified ways to share Shiny apps</a>.</blockquote> You can also extend Shiny apps with CSS themes, HTML widgets, and JavaScript actions, in case you ever run into the limitations of the core package itself. Long story short, there's nothing you can't do in Shiny. That claim has more weight on the R side of the story as of now, but Python support will only get better with time. Up next, let's see how to <b>install</b> the library. <h2 id="install">How to Install and Configure Shiny in Python Ecosystem</h2> Installing Shiny in Python is as simple as installing any other Python package since it's available on <a href="https://pypi.org/project/shiny/" target="_blank" rel="noopener">PyPi</a>. Run the following command from the shell: <pre><code class="language-shell">pip install shiny</code></pre> In addition, you should also install the following packages if you want to follow along with the code: <ul><li><code>numpy</code>: Fast and efficient math in Python</li><li><code>pandas</code>: Python library for handling data</li><li><code>matplotlib</code>: A standard visualization library</li><li><code>pandas_datareader</code>: Needed to fetch stock prices from the web (only for this article)</li><li><code>jinja2</code>: Needed to render Pandas DataFrames in Shiny apps (only for this article)</li></ul> Run the following command to install them all: <pre><code class="language-shell">pip install numpy pandas matplotlib pandas_datareader jinja2</code></pre> Once that's out of the way, you can use a shell command to set up a directory structure for the Shiny application. For example, the one below will create a folder <code>demo_app</code> with <code>app.py</code> inside it: <pre><code class="language-shell">shiny create demo_app</code></pre> <img class="alignnone size-full wp-image-14998" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d39cbc9849746c7450cb_d26ba428_1.webp" alt="Image 1 - Contents of the demo_app directory" width="2136" height="1140" /> Finally, you can run <code>app.py</code> with the following command: <pre><code class="language-shell">shiny run --reload demo_app/app.py</code></pre> <img class="size-full wp-image-15000" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d39db9bf482cf5d01d73_ab30378e_2.webp" alt="Image 2 - Running a Shiny for Python application" width="2136" height="1140" /> Image 2 - Running a Shiny for Python application It will run the Shiny app locally on port 8000. Once opened in the browser, it looks like this: <img class="size-full wp-image-15002" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d39d876df5e188dc663b_bec6d87d_3.webp" alt="Image 3 - The default Shiny for Python application" width="2340" height="1858" /> Image 3 - The default Shiny for Python application The app doesn't look bad and shows you how easy it is to get started with Shiny in Python. The underlying source code can be found in <code>app.py</code>. Here's what it contains: <pre><code class="language-python">from shiny import App, render, ui <br>app_ui = ui.page_fluid( ui.h2("Hello Shiny!"), ui.input_slider("n", "N", 0, 100, 20), ui.output_text_verbatim("txt"), ) <br> def server(input, output, session): @output @render.text def txt(): return f"n*2 is {input.n() * 2}" <br> app = App(app_ui, server)</code></pre> If you have any experience in R Shiny, this Python script will look familiar. Sure, Python doesn't use <code>$</code> to access methods and properties, and also uses function decorators for rendering. It's a different syntax you'll have to get used to, but it shouldn't feel like a whole new framework. Next, we'll code a Shiny dashboard from scratch to get familiar with the library. <h2 id="dashboard">Make Your First Shiny Dashboard in Python</h2> We're going to make a simple stock monitoring app. It will allow you to select a stock and inspect its 30-day performance, both visually and through a table. The table will show more metrics, such as open and close price, volume, and so on. The chart will show only the adjusted close price per day. The data is fetched from Yahoo Finance through the <code>pandas_datareader</code> library. It will automatically download single stock data based on a selected stock name, and rerender the table and chart as soon as you make any change. We've also decided to include a bit of custom CSS, so you can see how easy it is to tweak the visuals. Here's the full code snippet for <code>app.py</code>: <pre><code class="language-python">import matplotlib.pyplot as plt from datetime import datetime, timedelta from shiny import App, render, ui, reactive from pandas_datareader import data as pdr plt.rcParams["axes.spines.top"] = False plt.rcParams["axes.spines.right"] = False <br> # Configuration time_end = datetime.now() time_start = datetime.now() - timedelta(days=30) tickers = {"AAPL": "Apple", "MSFT": "Microsoft", "GOOG": "Google", "AMZN": "Amazon"} <br># App UI - One input to select a ticker and two outputs for chart and table app_ui = ui.page_fluid( # Adjust the styles to center everything ui.tags.style("#container {display: flex; flex-direction: column; align-items: center;}"), # Main container div ui.tags.div( ui.h2("Historical Stock Prices"), ui.input_select(id="ticker", label="Ticker:", choices=tickers), ui.output_plot("viz"), ui.output_table("table_data"), id="container") ) <br> # Server logic def server(input, output, session): # Store data as a result of reactive calculation @reactive.Calc def data(): df = pdr.get_data_yahoo(input.ticker(), time_start, time_end) return df.reset_index() <br> # Chart logic @output @render.plot def viz(): fig, ax = plt.subplots() ax.plot(data()["Date"], data()["Adj Close"]) ax.scatter(data()["Date"], data()["Adj Close"]) ax.set_title(f"{input.ticker()} historical prices") return fig <br> # Table logic @output @render.table def table_data(): return data() <br> # Connect everything app = App(app_ui, server)</code></pre> Once launched, here's what the dashboard looks like: <img class="size-full wp-image-15004" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b2abeb3ef1e72dc4f63481_4.gif" alt="Image 4 - Stock monitoring Shiny dashboard" width="1774" height="1046" /> Image 4 - Stock monitoring Shiny dashboard The app is relatively simple but shows you how to work with UI elements and render tables and charts. You can see how we stored fetched stock data as a reactive expression and used it when rendering both UI elements. That is a preferred way over fetching the data twice. You now know how to make basic Shiny apps in Python, so let's wrap things up next. <hr /> <h2 id="summary">Summary of Shiny for Python (Py Shiny)</h2> Bringing Shiny to Python is definitely a good step forward for the web framework and RStudio (Posit). The library is still in alpha, so a lot is expected to change in the future. You may find some things buggy, so we don't advise using it in production environments at the moment. It will get better and more feature-rich with time, so stay tuned to our blog for updates. P.S. - With Shiny for Python you can also run applications entirely in the browser using an experimental mode: <a href="https://shiny.rstudio.com/py/docs/shinylive.html" target="_blank" rel="noopener">Shinylive</a>. We'll explore this topic in future posts so be sure to subscribe to our <a href="https://appsilon.com/shiny-weekly-announcement/" target="_blank" rel="noopener">Shiny Weekly newsletter</a>. <i>What are your thoughts on Shiny for Python? Is it something you've been waiting for or you're happy to stick with R?</i> Please let us know in the comment section below. Also, feel free to continue the discussion on Twitter - <a href="https://twitter.com/appsilon" target="_blank" rel="noopener">@appsilon</a>. We'd love to hear your thoughts. <blockquote>Want to use R and Python together? <a href="https://appsilon.com/use-r-and-python-together/" target="_blank" rel="noopener">Here are 2 packages you must try</a>.</blockquote>