{"id":4968,"date":"2025-02-05T23:15:00","date_gmt":"2025-02-05T14:15:00","guid":{"rendered":"https:\/\/secondlife.lol\/?p=4968"},"modified":"2025-02-05T23:21:55","modified_gmt":"2025-02-05T14:21:55","slug":"python-survey-app-shiny-for-python-guide","status":"publish","type":"post","link":"https:\/\/secondlife.lol\/en\/python-survey-app-shiny-for-python-guide\/","title":{"rendered":"Creating Python Surveys: A Beginner's Guide to Shiny for Python"},"content":{"rendered":"<p>Hello, fellow Python enthusiasts! Today we have a really exciting topic for you. If you're like me, you've probably thought to yourself, \"I wonder if I could create a survey myself?\" In today's post, we'll make that dream a reality!<\/p>\n\n\n\n<p>We'll be using a powerful tool called 'Shiny for Python', and as we dive into the ins and outs of using it, we'll create our own awesome survey app. If you're a beginner, don't worry, this post is for you!<\/p>\n\n\n\n<p>So, let's take a trip into the magical world of Python together. Let's get started by creating a Python survey that will let your creativity run wild!<\/p>\n\n\n<style>.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-content-wrap{padding-top:var(--global-kb-spacing-sm, 1.5rem);padding-right:var(--global-kb-spacing-sm, 1.5rem);padding-bottom:var(--global-kb-spacing-sm, 1.5rem);padding-left:var(--global-kb-spacing-sm, 1.5rem);border-top:3px solid var(--global-palette2, #2B6CB0);border-right:3px solid var(--global-palette2, #2B6CB0);border-bottom:3px solid var(--global-palette2, #2B6CB0);border-left:3px solid var(--global-palette2, #2B6CB0);border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;box-shadow:0px 0px 14px 0px rgba(0, 0, 0, 0.2);}.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-contents-title-wrap{padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;}.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-contents-title-wrap{color:var(--global-palette2, #2B6CB0);}.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-contents-title{color:var(--global-palette2, #2B6CB0);font-size:28px;font-weight:regular;font-style:normal;}.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-content-wrap .kb-table-of-content-list{color:var(--global-palette1, #3182CE);line-height:2em;font-weight:regular;font-style:normal;margin-top:var(--global-kb-spacing-sm, 1.5rem);margin-right:0px;margin-bottom:0px;margin-left:0px;}.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-content-wrap .kb-table-of-content-list .kb-table-of-contents__entry:hover{color:var(--global-palette6, #718096);}@media all and (max-width: 1024px){.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-content-wrap{border-top:3px solid var(--global-palette2, #2B6CB0);border-right:3px solid var(--global-palette2, #2B6CB0);border-bottom:3px solid var(--global-palette2, #2B6CB0);border-left:3px solid var(--global-palette2, #2B6CB0);}}@media all and (max-width: 1024px){.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-contents-title{font-size:28px;}}@media all and (max-width: 767px){.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-content-wrap{border-top:3px solid var(--global-palette2, #2B6CB0);border-right:3px solid var(--global-palette2, #2B6CB0);border-bottom:3px solid var(--global-palette2, #2B6CB0);border-left:3px solid var(--global-palette2, #2B6CB0);}.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-contents-title{font-size:28px;}}<\/style>\n\n\n<h2 class=\"wp-block-heading\">1. Shiny for Python: New Horizons for Surveys<\/h2>\n\n\n\n<p><a href=\"https:\/\/shiny.posit.co\/py\/\" target=\"_blank\" rel=\"noopener\">Shiny for Python<\/a>is a framework that is rapidly gaining popularity among data scientists and developers. Why? Because it allows you to create interactive web applications without the need for complex web technologies. <\/p>\n\n\n\n<p>Especially when building a survey app, Shiny for Python is a great way to go from data collection to analysis in one step.<\/p>\n\n\n<style>.wp-block-kadence-column.kb-section-dir-horizontal > .kt-inside-inner-col > .kt-info-box4968_d8b3f1-06 .kt-blocks-info-box-link-wrap{max-width:unset;}.kt-info-box4968_d8b3f1-06 .kt-blocks-info-box-link-wrap{border-top:5px solid var(--global-palette7, #eeeeee);border-right:5px solid var(--global-palette7, #eeeeee);border-bottom:5px solid var(--global-palette7, #eeeeee);border-left:5px solid var(--global-palette7, #eeeeee);border-top-left-radius:30px;border-top-right-radius:30px;border-bottom-right-radius:30px;border-bottom-left-radius:30px;background:#ffffff;padding-top:var(--global-kb-spacing-xs, 1rem);padding-right:var(--global-kb-spacing-xs, 1rem);padding-bottom:var(--global-kb-spacing-xs, 1rem);padding-left:var(--global-kb-spacing-xs, 1rem);}.kt-info-box4968_d8b3f1-06 .kadence-info-box-icon-container .kt-info-svg-icon, .kt-info-box4968_d8b3f1-06 .kt-info-svg-icon-flip, .kt-info-box4968_d8b3f1-06 .kt-blocks-info-box-number{font-size:50px;}.kt-info-box4968_d8b3f1-06 .kt-blocks-info-box-media{border-radius:200px;overflow:hidden;border-top-width:0px;border-right-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:20px;padding-right:20px;padding-bottom:20px;padding-left:20px;margin-top:0px;margin-right:20px;margin-bottom:0px;margin-left:0px;}.kt-info-box4968_d8b3f1-06 .kt-blocks-info-box-media .kadence-info-box-image-intrisic img{border-radius:200px;}.kt-info-box4968_d8b3f1-06 .kt-infobox-textcontent h3.kt-blocks-info-box-title{padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;margin-top:5px;margin-right:0px;margin-bottom:10px;margin-left:0px;}.kt-info-box4968_d8b3f1-06 .kt-blocks-info-box-learnmore{background:transparent;border-width:0px 0px 0px 0px;padding-top:4px;padding-right:8px;padding-bottom:4px;padding-left:8px;margin-top:10px;margin-right:0px;margin-bottom:10px;margin-left:0px;}@media all and (max-width: 1024px){.kt-info-box4968_d8b3f1-06 .kt-blocks-info-box-link-wrap{border-top:5px solid var(--global-palette7, #eeeeee);border-right:5px solid var(--global-palette7, #eeeeee);border-bottom:5px solid var(--global-palette7, #eeeeee);border-left:5px solid var(--global-palette7, #eeeeee);}}@media all and (max-width: 767px){.kt-info-box4968_d8b3f1-06 .kt-blocks-info-box-link-wrap{border-top:5px solid var(--global-palette7, #eeeeee);border-right:5px solid var(--global-palette7, #eeeeee);border-bottom:5px solid var(--global-palette7, #eeeeee);border-left:5px solid var(--global-palette7, #eeeeee);}}<\/style>\n<div class=\"wp-block-kadence-infobox kt-info-box4968_d8b3f1-06\"><span class=\"kt-blocks-info-box-link-wrap info-box-link kt-blocks-info-box-media-align-left kt-info-halign-left\"><div class=\"kt-blocks-info-box-media-container\"><div class=\"kt-blocks-info-box-media kt-info-media-animate-none\"><div class=\"kadence-info-box-icon-container kt-info-icon-animate-none\"><div class=\"kadence-info-box-icon-inner-container\"><span class=\"kb-svg-icon-wrap kb-svg-icon-fe_alertCircle kt-info-svg-icon\"><svg viewbox=\"0 0 24 24\"  fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"  aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"10\"\/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"\/><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"16\"\/><\/svg><\/span><\/div><\/div><\/div><\/div><div class=\"kt-infobox-textcontent\"><h3 class=\"kt-blocks-info-box-title\">Shiny for Python<\/h3><p class=\"kt-blocks-info-box-text\">Shiny for Python is a framework that enables you to develop responsive web applications in Python. It brings the popular Shiny package from the R language to the Python environment, enabling data scientists to create interactive data visualization apps without the need for complex web development knowledge. <br>Shiny for Python consists of a UI and a server part, which can dynamically calculate and display results based on user input. It also provides the ability to run apps directly in the browser without a server via Shinylive.<\/p><\/div><\/span><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">2. Before you begin: What to bring checklist<\/h2>\n\n\n\n<p>Before you start building your Python survey app, you'll need a few things. Let's check them out together.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Python 3.8 or later. (You can check this version using the <a href=\"https:\/\/secondlife.lol\/en\/how-to-check-python-version\/\" data-type=\"post\" data-id=\"2437\">Click here<\/a>)<\/li>\n\n\n\n<li>Your favorite code editor (e.g., VS Code, PyCharm)<\/li>\n\n\n\n<li>Basic knowledge of terminal usage<\/li>\n\n\n\n<li>Passion and curiosity (most important!)<\/li>\n<\/ol>\n\n\n\n<p>Okay, now that we're all set up, let's get excited!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Install Shiny for Python<\/h2>\n\n\n\n<p>First, you need to install Shiny for Python. Open a terminal and type the following command<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pip install shiny<\/code><\/pre>\n\n\n\n<p>Running the above command will simply install Shiny for Python, the first step in creating a Python survey. Cool, right? (Below, I'm running a reinstall with it already installed, so you can see I'm already satisfied).<\/p>\n\n\n<style>.kb-image4968_bb3ba5-89 .kb-image-has-overlay:after{opacity:0.3;border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;}.kb-image4968_bb3ba5-89 img.kb-img, .kb-image4968_bb3ba5-89 .kb-img img{border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;box-shadow:0px 0px 14px 0px rgba(0, 0, 0, 0.2);}<\/style>\n<div class=\"wp-block-kadence-image kb-image4968_bb3ba5-89\"><figure class=\"aligncenter size-full\"><img decoding=\"async\" width=\"995\" height=\"497\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-15.jpg\" alt=\"Shiny for Python \uc124\uce58\ud558\uae30\" class=\"kb-img wp-image-4971\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-15.jpg 995w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-15-300x150.jpg 300w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-15-600x300.jpg 600w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-15-768x384.jpg 768w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-15-18x9.jpg 18w\" sizes=\"(max-width: 995px) 100vw, 995px\" \/><figcaption>(Shiny for Python installation terminal image)<\/figcaption><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">4. Create your first Shiny app<\/h2>\n\n\n\n<p>Let's dive into creating a Python survey. First, let's start with the most basic of Shiny apps, which you may recognize as the <a href=\"https:\/\/secondlife.lol\/en\/python-virtual-environment-batch-file-creation\/\" data-type=\"post\" data-id=\"4655\">Virtual Environments<\/a>to run the code below.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>#survey_app\n\nfrom shiny import App, ui\n\nDefine the # UI\napp_ui = ui.page_fluid(\n    ui.h1(\"My First Shiny App\"),\n    ui.p(\"Welcome to the world of Shiny for Python!\")\n)\n\n# Empty server function (you can add logic later)\ndef server(input, output, session):\n    pass\n\nCreate a # Shiny app object\napp = App(app_ui, server)<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Code commentary<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>(I saved the code above with the name survey_app).<\/li>\n\n\n\n<li><code>from shiny import App, ui<\/code>: Fetch the necessary classes and modules from the Shiny library.<\/li>\n\n\n\n<li><code>app_ui = ui.page_fluid(...)<\/code>Defines the user interface (UI) of the application.\n<ul class=\"wp-block-list\">\n<li><code>ui.h1(...)<\/code>: Add a large heading (H1 tag) to the page.<\/li>\n\n\n\n<li><code>ui.p(...)<\/code>Add a : paragraph (p tag) to display the welcome message.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><code>def server(input, output, session):<\/code>Defines a server function. This is currently an empty function, but you can add your application's logic here in the future<a href=\"https:\/\/blog.zarathu.com\/posts\/2022-08-26-shinyforpython\/\" target=\"_blank\" rel=\"noreferrer noopener\">1<\/a>.<\/li>\n\n\n\n<li><code>app = App(app_ui, server)<\/code>: Combines UI and server functions to create a Shiny application object.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>shiny run survey_app.py<\/code><\/pre>\n\n\n\n<p>If you type the above command into the terminal and press Enter, you should get the following response: 127.0.0.1:8000, which, when clicked while holding down the Ctrl key, generates a really simple web page. Fascinating, isn't it? <\/p>\n\n\n<style>.kb-image4968_0730d0-0a .kb-image-has-overlay:after{opacity:0.3;border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;}.kb-image4968_0730d0-0a img.kb-img, .kb-image4968_0730d0-0a .kb-img img{border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;box-shadow:0px 0px 14px 0px rgba(0, 0, 0, 0.2);}<\/style>\n<div class=\"wp-block-kadence-image kb-image4968_0730d0-0a\"><figure class=\"aligncenter size-full\"><img decoding=\"async\" width=\"1200\" height=\"640\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-16.jpg\" alt=\"\ucf54\ub4dc\ucc3d\uacfc \ud130\ubbf8\ub110 \uc774\ubbf8\uc9c0\" class=\"kb-img wp-image-4972\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-16.jpg 1200w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-16-300x160.jpg 300w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-16-600x320.jpg 600w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-16-768x410.jpg 768w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-16-18x10.jpg 18w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><figcaption>(Image of PyCharm code window and terminal window)<\/figcaption><\/figure><\/div>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><\/blockquote>\n\n\n<style>.kb-image4968_320c8b-0d .kb-image-has-overlay:after{opacity:0.3;border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;}.kb-image4968_320c8b-0d img.kb-img, .kb-image4968_320c8b-0d .kb-img img{border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;box-shadow:0px 0px 14px 0px rgba(0, 0, 0, 0.2);}<\/style>\n<div class=\"wp-block-kadence-image kb-image4968_320c8b-0d\"><figure class=\"aligncenter size-full\"><img decoding=\"async\" width=\"1200\" height=\"638\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-17.jpg\" alt=\"\uc0dd\uc131\ub41c \uc6f9\ud398\uc774\uc9c0 \uc774\ubbf8\uc9c0\" class=\"kb-img wp-image-4973\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-17.jpg 1200w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-17-300x160.jpg 300w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-17-600x319.jpg 600w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-17-768x408.jpg 768w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-17-18x10.jpg 18w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><figcaption>(Web page image generated by running a shiny app)<\/figcaption><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">5. Create a survey form<\/h2>\n\n\n\n<p>Now let's get down to business and create a survey form. We'll create a simple form that asks for your name, age, and favorite programming language.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>from shiny import App, ui, reactive\n\nDefine the # UI\napp_ui = ui.page_fluid(\n    ui.h1(\"Python Programmer Survey\"), # title (h1 tag)\n    ui.input_text(\"name\", \"Enter your name\"), # Text input field (name)\n    ui.input_numeric(\"age\", \"Enter your age\", value=20), # Numeric input field (default 20)\n    ui.input_select(\n        \"fav_lang\",\n        \"What is your favorite programming language?\", # select input field\n        choices=[\"Python\", \"JavaScript\", \"Java\", \"C++\", \"Other\"]\n    ),\n    ui.input_action_button(\"submit\", \"Submit\"), # button (Submit)\n    ui.output_text_verbatim(\"result\") # output field (result)\n)\n\nDefine the # server logic\ndef server(input, output, session):\n    @reactive.Effect\n    @reactive.event(input.submit) # Execute on button click\n    def submit_survey():\n        # Combines the input data into a string and outputs it\n        result = f\"Name: {input.name()}, Age: {input.age()}, Favorite Language: {input.fav_lang()}\"\n        output.result.set(result) # Display the result in the UI\n\nRun the # Shiny app\napp = App(app_ui, server)<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Code commentary<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>UI configuration (<code>app_ui<\/code>)<\/strong>\n<ul class=\"wp-block-list\">\n<li><code>ui.h1(...)<\/code> : Displays the title of the survey.<\/li>\n\n\n\n<li><code>ui.input_text(...)<\/code> : Provide a text field for the user to enter a name.<\/li>\n\n\n\n<li><code>ui.input_numeric(...)<\/code> : Provides a numeric field for you to enter your age. The default value is 20.<\/li>\n\n\n\n<li><code>ui.input_select(...)<\/code> Create a drop-down menu so users can select their favorite programming language.<\/li>\n\n\n\n<li><code>ui.input_action_button(...)<\/code> : Add a Submit Survey button.<\/li>\n\n\n\n<li><code>ui.output_text_verbatim(...)<\/code> : Creates a space to output the result of the user's input as text.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Server logic (<code>server<\/code> function)<\/strong>\n<ul class=\"wp-block-list\">\n<li><code>@reactive.Effect<\/code> : Specifies it as a responsive function.<\/li>\n\n\n\n<li><code>@reactive.event(input.submit)<\/code> Click the : button (<code>submit<\/code>) It only runs when the event occurs.<\/li>\n\n\n\n<li><code>result = f\"Name: {input.name()}, Age: {input.age()}, Favorite Language: {input.fav_lang()}\"<\/code><br>\u2192 Take the data entered by the user and generate a string.<\/li>\n\n\n\n<li><code>output.result.set(result)<\/code><br>\u2192 Save the result to the <code>output_text_verbatim(\"result\")<\/code> area of the page.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Run the Shiny app (<code>app = App(app_ui, server)<\/code>)<\/strong>\n<ul class=\"wp-block-list\">\n<li><code>App(app_ui, server)<\/code>to connect the UI to the server.<\/li>\n\n\n\n<li><code>app.run()<\/code>opens the app in a web browser.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>This will result in a basic Python survey form like the one below. Isn't that pretty cool?<\/p>\n\n\n<style>.kb-image4968_74dbbb-6b .kb-image-has-overlay:after{opacity:0.3;border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;}.kb-image4968_74dbbb-6b img.kb-img, .kb-image4968_74dbbb-6b .kb-img img{border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;box-shadow:0px 0px 14px 0px rgba(0, 0, 0, 0.2);}<\/style>\n<div class=\"wp-block-kadence-image kb-image4968_74dbbb-6b\"><figure class=\"aligncenter size-full\"><img decoding=\"async\" width=\"1200\" height=\"638\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-18.jpg\" alt=\"\ud30c\uc774\uc36c \uc124\ubb38\uc870\uc0ac \ud3fc \uc6f9\ud398\uc774\uc9c0\" class=\"kb-img wp-image-4974\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-18.jpg 1200w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-18-300x160.jpg 300w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-18-600x319.jpg 600w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-18-768x408.jpg 768w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-18-18x10.jpg 18w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">6. Save the data<\/h2>\n\n\n\n<p>Collecting and storing data is key to surveys. Let's add the ability to store survey respondents' data in a CSV file.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>from shiny import App, ui, reactive\nimport pandas as pd # Install those packages with pip install pandas if needed\nfrom pathlib import Path\n\nDefine the # UI\napp_ui = ui.page_fluid(\n    ui.h1(\"Python Programmer Survey\"), # title (h1 tag)\n    ui.input_text(\"name\", \"Enter your name\"), # Text input field (name)\n    ui.input_numeric(\"age\", \"Enter your age\", value=20), # Numeric input field (default 20)\n    ui.input_select(\n        \"fav_lang\",\n        \"What is your favorite programming language?\", # select input field\n        choices=[\"Python\", \"JavaScript\", \"Java\", \"C++\", \"Other\"]\n    ),\n    ui.input_action_button(\"submit\", \"Submit\"), # button (Submit)\n    ui.output_text_verbatim(\"result\") # output field (result)\n)\n\nDefine the # server logic\ndef server(input, output, session):\n    @reactive.Effect\n    @reactive.event(input.submit) # Execute on button click\n    def submit_survey():\n        # Store the data entered by the user in the form of a dictionary\n        data = {\n            \"name\": [input.name()],\n            \"age\": [input.age()],\n            \"favorite_language\": [input.fav_lang()]\n        }\n        \n        Convert the # data into a Pandas DataFrame\n        df = pd.DataFrame(data)\n\n        Check if the # CSV file exists and save it\n        file_path = \"survey_results.csv\"\n        if not Path(file_path).exists():\n            df.to_csv(file_path, index=False) # Include headers on first save\n        else:\n            df.to_csv(file_path, mode=\"a\", header=False, index=False) # Save additional to existing file\n\n        Output the # result message to the UI\n        output.result.set(\"Your response has been recorded. Thank you!\")\n\n# Run the Shiny app\napp = App(app_ui, server)<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Code commentary<\/h3>\n\n\n\n<p>1. <strong>Saving data to a CSV file<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The user's input data is stored in a dictionary (<code>dict<\/code>) format.<\/li>\n\n\n\n<li><code>pandas.DataFrame<\/code>to convert it to a dataframe.<\/li>\n\n\n\n<li>Save the response data to the <code>\"survey_results.csv\"<\/code> Save to a file.\n<ul class=\"wp-block-list\">\n<li>If it doesn't exist, create a new file and click Save with header.<\/li>\n\n\n\n<li>If the file already exists, save the new response data in Append mode (excluding headers).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>2. <strong>Responsive event handling<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>@reactive.event(input.submit)<\/code>using the <code>Submit<\/code> Set to run only when the button is pressed.<\/li>\n<\/ul>\n\n\n\n<p>3. <strong>Display the resulting message<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>After saving the data <code>\"Your response has been recorded. Thank you!\"<\/code> Outputs the message to the UI.<\/li>\n<\/ul>\n\n\n\n<p>In the Python survey form, we entered Trump, age 20, and Python, and when we hit the submit button, the survey responses are now saved in a CSV file (survey_result). If you click on this file, you'll see the data you entered as shown below!<\/p>\n\n\n<style>.kb-image4968_771ae8-31 .kb-image-has-overlay:after{opacity:0.3;border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;}.kb-image4968_771ae8-31 img.kb-img, .kb-image4968_771ae8-31 .kb-img img{border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;box-shadow:0px 0px 14px 0px rgba(0, 0, 0, 0.2);}<\/style>\n<div class=\"wp-block-kadence-image kb-image4968_771ae8-31\"><figure class=\"aligncenter size-full\"><img decoding=\"async\" width=\"1200\" height=\"750\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3.png\" alt=\"CSV\ud30c\uc77c\ub85c \ub370\uc774\ud130 \uc800\uc7a5\ud558\uae30\" class=\"kb-img wp-image-4978\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3.png 1200w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-300x188.png 300w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-600x375.png 600w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-768x480.png 768w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-3-18x12.png 18w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n\n<p>Congratulations, you've done an amazing job creating a Python survey and taking your first steps into data analysis.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. Visualize survey results<\/h2>\n\n\n\n<p>Now that we've collected our data, let's visualize the results. Let's create a simple chart using Shiny for Python and matplotlib.<\/p>\n\n\n\n<pre id=\"language-python\" class=\"wp-block-code language-python\"><code>from shiny import App, ui, reactive, render\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom pathlib import Path\n\nDefine the # UI\napp_ui = ui.page_fluid(\n    ui.h1(\"Python Programmer Survey\"), # title\n    ui.input_text(\"name\", \"Enter your name\"), # name input field\n    ui.input_numeric(\"age\", \"Enter your age\", value=20), # Age input field\n    ui.input_select(\n        \"fav_lang\",\n        \"What is your favorite programming language?\", # Select favorite programming language\n        choices=[\"Python\", \"JavaScript\", \"Java\", \"C++\", \"Other\"]\n    ),\n    ui.input_action_button(\"submit\", \"Submit\"), # Submit button\n    ui.output_text_verbatim(\"result\"), # Result output\n    ui.output_plot(\"age_histogram\") # Age distribution histogram output\n)\n\nDefine the # server logic\ndef server(input, output, session):\n    @reactive.Effect\n    @reactive.event(input.submit) # Execute on button click\n    def submit_survey():\n        # Save user input data as a dictionary\n        data = {\n            \"name\": [input.name()],\n            \"age\": [input.age()],\n            \"favorite_language\": [input.fav_lang()]\n        }\n        \n        Convert the # data to a DataFrame\n        df = pd.DataFrame(data)\n\n        Set the # file path\n        file_path = \"survey_results.csv\"\n\n        If # CSV file does not exist, create it including headers, if it does, append it (Append)\n        if not Path(file_path).exists():\n            df.to_csv(file_path, index=False)\n        else:\n            df.to_csv(file_path, mode=\"a\", header=False, index=False)\n\n        Output the # save complete message\n        output.result.set(\"Your response has been recorded. Thank you!\")\n\n    @output\n    @render.plot\n    def age_histogram():\n        Load # survey data\n        file_path = \"survey_results.csv\"\n        if not Path(file_path).exists():\n            return # Do not plot graph if no data exists\n\n        df = pd.read_csv(file_path)\n\n        Create a histogram of the # age distribution\n        fig, ax = plt.subplots(figsize=(10, 6)) # Create a new figure\n        ax.hist(df['age'], bins=10, edgecolor='black', alpha=0.7) # Histogram\n        ax.set_title('Age Distribution')\n        ax.set_xlabel('Age')\n        ax.set_ylabel('Response Count')\n\n        return fig # return `fig` instead of `plt.gcf()` return fig\n\n# Run the Shiny app\napp = App(app_ui, server)<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Code commentary<\/h3>\n\n\n\n<p>1. <strong>Age distribution histogram (<code>age_histogram<\/code> Add)<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>ui.output_plot(\"age_histogram\")<\/code>to make room for the graph in the UI.<\/li>\n\n\n\n<li><code>@output @render.plot<\/code> Decorator to use the <code>age_histogram()<\/code> Define a function.<\/li>\n\n\n\n<li><code>survey_results.csv<\/code>by fetching data from <code>matplotlib<\/code>to generate a histogram.<\/li>\n\n\n\n<li>Age (<code>age<\/code>) Visualize the number of responses based on the field.<\/li>\n<\/ul>\n\n\n\n<p>2. <strong>Handling exceptions when no data is available<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>if not Path(file_path).exists(): return<\/code> Add a condition to suppress the graph if there is no survey data.<\/li>\n<\/ul>\n\n\n\n<p>3. <strong>UI updates<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>ui.output_plot(\"age_histogram\")<\/code>to visualize the age distribution of respondents in real-time.<\/li>\n<\/ul>\n\n\n\n<p>This creates a histogram that shows the age distribution of the respondents at a glance. Doesn't it make the data come alive? (Right now, I only have four random inputs, so I'm not getting a good histogram).<\/p>\n\n\n<style>.kb-image4968_90cdea-dd .kb-image-has-overlay:after{opacity:0.3;border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;}.kb-image4968_90cdea-dd img.kb-img, .kb-image4968_90cdea-dd .kb-img img{border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;box-shadow:0px 0px 14px 0px rgba(0, 0, 0, 0.2);}<\/style>\n<div class=\"wp-block-kadence-image kb-image4968_90cdea-dd\"><figure class=\"aligncenter size-full\"><img decoding=\"async\" width=\"1200\" height=\"676\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-4-1.jpg\" alt=\"\ud30c\uc774\uc36c \uc124\ubb38\uc870\uc0ac \ub9cc\ub4e4\uae30\" class=\"kb-img wp-image-4979\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-4-1.jpg 1200w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-4-1-300x169.jpg 300w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-4-1-600x338.jpg 600w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-4-1-768x433.jpg 768w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/image-4-1-18x10.jpg 18w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><figcaption>(Image of the live viewable histogram implementation webpage)<\/figcaption><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">8. Wrapping up: The endless possibilities of Shiny for Python<\/h2>\n\n\n\n<p>So far, we've used Shiny for Python to create a simple Python survey app, and that's just the beginning! With Shiny for Python, you can create more complex and interactive apps, such as the one below.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Dashboards that update in real time<\/li>\n\n\n\n<li>Predictive apps with machine learning models<\/li>\n\n\n\n<li>Large-scale data visualization tools<\/li>\n<\/ul>\n\n\n\n<p>Your imagination is the limit!<\/p>\n\n\n\n<p>How did you like creating a Python survey? As you've been learning how to use Shiny for Python, you've noticed how fascinating it is to be able to go from data collection to analysis to visualization all in one go. Now you have the basics to create your own survey app.<\/p>\n\n\n\n<p>If you want to go deeper, <a href=\"https:\/\/shiny.posit.co\/py\/docs\/overview.html\" target=\"_blank\" rel=\"noopener\">Shiny for Python<\/a>And remember, the best way to learn is to build it yourself. Create your own unique survey app!<\/p>\n\n\n\n<p>Now it's your turn. What cool apps would you like to build with Python and Shiny for Python? Share your ideas in the comments. Let's have fun growing together!<\/p>\n\n\n<style>.kb-image4457_249bea-0c.kb-image-is-ratio-size, .kb-image4457_249bea-0c .kb-image-is-ratio-size{max-width:300px;width:100%;}.wp-block-kadence-column > .kt-inside-inner-col > .kb-image4457_249bea-0c.kb-image-is-ratio-size, .wp-block-kadence-column > .kt-inside-inner-col > .kb-image4457_249bea-0c .kb-image-is-ratio-size{align-self:unset;}.kb-image4457_249bea-0c figure{max-width:300px;}.kb-image4457_249bea-0c .image-is-svg, .kb-image4457_249bea-0c .image-is-svg img{width:100%;}.kb-image4457_249bea-0c .kb-image-has-overlay:after{opacity:0.3;}<\/style>\n<div class=\"wp-block-kadence-image kb-image4457_249bea-0c\"><figure class=\"aligncenter size-medium\"><img decoding=\"async\" width=\"300\" height=\"300\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/01\/teri-coding-300x300.webp\" alt=\"\ud14c\ub9ac \uc774\ubaa8\ud2f0\ucf58\" class=\"kb-img wp-image-4456\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/01\/teri-coding-300x300.webp 300w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/01\/teri-coding-600x600.webp 600w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/01\/teri-coding-150x150.webp 150w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/01\/teri-coding-768x768.webp 768w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/01\/teri-coding-12x12.webp 12w, https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/01\/teri-coding.webp 1024w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><figcaption><strong>(Happy coding!)<\/strong><\/figcaption><\/figure><\/div>","protected":false},"excerpt":{"rendered":"<p>\uc548\ub155\ud558\uc138\uc694, \ud30c\uc774\uc36c \uc5f4\uc815 \ub118\uce58\ub294 \uc5ec\ub7ec\ubd84! \uc624\ub298\uc740 \uc815\ub9d0 \ud765\ubbf8\uc9c4\uc9c4\ud55c \uc8fc\uc81c\ub85c \ucc3e\uc544\uc654\uc2b5\ub2c8\ub2e4&#8230;.<\/p>","protected":false},"author":3,"featured_media":4981,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"categories":[3],"tags":[874,177,875,876,33],"class_list":["post-4968","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-python-coding","tag-shiny-for-python","tag-177","tag-875","tag-876","tag-33"],"taxonomy_info":{"category":[{"value":3,"label":"\ud30c\uc774\uc36c(Python)"}],"post_tag":[{"value":874,"label":"Shiny for Python"},{"value":177,"label":"\ub370\uc774\ud130 \ubd84\uc11d"},{"value":875,"label":"\uc124\ubb38\uc870\uc0ac"},{"value":876,"label":"\uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158"},{"value":33,"label":"\ud30c\uc774\uc36c"}]},"featured_image_src_large":["https:\/\/secondlife.lol\/wp-content\/uploads\/2025\/02\/\ud30c\uc774\uc36c-\uc124\ubb38\uc870\uc0ac-\ub9cc\ub4e4\uae30-\ud3ec\uc2a4\ud2b8-\uc378\ub124\uc77c-600x600.jpg",600,600,true],"author_info":{"display_name":"TERE","author_link":"https:\/\/secondlife.lol\/en\/author\/tere\/"},"comment_info":0,"category_info":[{"term_id":3,"name":"\ud30c\uc774\uc36c(Python)","slug":"python-coding","term_group":0,"term_taxonomy_id":3,"taxonomy":"category","description":"","parent":20,"count":116,"filter":"raw","cat_ID":3,"category_count":116,"category_description":"","cat_name":"\ud30c\uc774\uc36c(Python)","category_nicename":"python-coding","category_parent":20}],"tag_info":[{"term_id":874,"name":"Shiny for Python","slug":"shiny-for-python","term_group":0,"term_taxonomy_id":874,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":177,"name":"\ub370\uc774\ud130 \ubd84\uc11d","slug":"%eb%8d%b0%ec%9d%b4%ed%84%b0-%eb%b6%84%ec%84%9d","term_group":0,"term_taxonomy_id":177,"taxonomy":"post_tag","description":"","parent":0,"count":36,"filter":"raw"},{"term_id":875,"name":"\uc124\ubb38\uc870\uc0ac","slug":"%ec%84%a4%eb%ac%b8%ec%a1%b0%ec%82%ac","term_group":0,"term_taxonomy_id":875,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":876,"name":"\uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158","slug":"%ec%9b%b9-%ec%95%a0%ed%94%8c%eb%a6%ac%ec%bc%80%ec%9d%b4%ec%85%98","term_group":0,"term_taxonomy_id":876,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":33,"name":"\ud30c\uc774\uc36c","slug":"%ed%8c%8c%ec%9d%b4%ec%8d%ac","term_group":0,"term_taxonomy_id":33,"taxonomy":"post_tag","description":"","parent":0,"count":30,"filter":"raw"}],"_links":{"self":[{"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/posts\/4968","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/comments?post=4968"}],"version-history":[{"count":6,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/posts\/4968\/revisions"}],"predecessor-version":[{"id":4980,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/posts\/4968\/revisions\/4980"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/media\/4981"}],"wp:attachment":[{"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/media?parent=4968"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/categories?post=4968"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/tags?post=4968"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}