From fea62709c1f885aafe7a80b43470287dc452d1a0 Mon Sep 17 00:00:00 2001 From: Quarto GHA Workflow Runner Date: Sat, 3 Feb 2024 16:19:04 +0000 Subject: [PATCH] Built site for gh-pages --- .nojekyll | 2 +- chapters/sec1/1-3-data-access.html | 4 +-- search.json | 2 +- sitemap.xml | 54 +++++++++++++++--------------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/.nojekyll b/.nojekyll index d8e50392..f7ef5bbc 100644 --- a/.nojekyll +++ b/.nojekyll @@ -1 +1 @@ -954ae025 \ No newline at end of file +0a2287b1 \ No newline at end of file diff --git a/chapters/sec1/1-3-data-access.html b/chapters/sec1/1-3-data-access.html index 7178435f..a031ffa9 100644 --- a/chapters/sec1/1-3-data-access.html +++ b/chapters/sec1/1-3-data-access.html @@ -773,7 +773,7 @@

Step 3: Build a s def vals(): d = { "bill_length_mm" : input.bill_length(), - "sex_Male" : input.sex() == "Male", + "sex_male" : input.sex() == "Male", "species_Gentoo" : input.species() == "Gentoo", "species_Chinstrap" : input.species() == "Chinstrap" @@ -862,7 +862,7 @@

Step 3: Build a s pred <- eventReactive( input$predict, httr2::request(api_url) |> - httr2::req_body_json(vals()) |> + httr2::req_body_json(list(vals())) |> httr2::req_perform() |> httr2::resp_body_json(), ignoreInit = TRUE diff --git a/search.json b/search.json index 4f9233e7..3da0062d 100644 --- a/search.json +++ b/search.json @@ -256,7 +256,7 @@ "href": "chapters/sec1/1-3-data-access.html#lab-use-a-database-and-an-api", "title": "3  Databases and Data APIs", "section": "Lab: Use a database and an API", - "text": "Lab: Use a database and an API\nIn this lab, we will build the data and the presentation layers for our penguin mass model exploration. We’re going to create an app to explore the model, which will look like this:\n\nLet’s start by moving the data into an actual data layer.\n\nStep 1: Put the data in DuckDB\nLet’s start by moving the data into a DuckDB database and use it from there for the modeling and EDA scripts.\nTo start, let’s load the data.\nHere’s what that looks like in R:\ncon <- DBI::dbConnect(duckdb::duckdb(), dbdir = \"my-db.duckdb\")\nDBI::dbWriteTable(con, \"penguins\", palmerpenguins::penguins)\nDBI::dbDisconnect(con)\nOr equivalently, in Python:\nimport duckdb\nfrom palmerpenguins import penguins\n\ncon = duckdb.connect('my-db.duckdb')\ndf = penguins.load_penguins()\ncon.execute('CREATE TABLE penguins AS SELECT * FROM df')\ncon.close()\nNow that the data is loaded, let’s adjust our scripts to use the database.\nIn R, we will replace our data loading with connecting to the database. Leaving out all the parts that don’t change, it looks like\n\n\neda.qmd\n\ncon <- DBI::dbConnect(\n duckdb::duckdb(), \n dbdir = \"my-db.duckdb\"\n )\ndf <- dplyr::tbl(con, \"penguins\")\n\nWe also need to call to DBI::dbDisconnect(con) at the end of the script.\nWe don’t have to change anything because we wrote our data processing code in {dplyr}. Under the hood, {dplyr} can switch seamlessly to a database backend, which is really cool.\n\n\neda.qmd\n\ndf %>%\n group_by(species, sex) %>%\n summarise(\n across(\n ends_with(\"mm\") | ends_with(\"g\"),\n \\(x) mean(x, na.rm = TRUE)\n )\n ) %>%\n dplyr::collect() %>%\n knitr::kable()\n\nIt’s unnecessary, but I’ve added a call to dplyr::collect() in line 31. It will be implied if I don’t put it there manually, but it helps make it obvious that all the work before there has been pushed off to the database. It doesn’t matter for this small dataset, but it could benefit a larger dataset.\nIn Python, we’re just going to load the entire dataset into memory for modeling, so the line loading the dataset changes to\n\n\nmodel.qmd\n\ncon = duckdb.connect('my-db.duckdb')\ndf = con.execute(\"SELECT * FROM penguins\").fetchdf().dropna()\ncon.close()\n\nNow let’s switch to figuring out the connection we’ll need to our processing layer in the presentation layer.\n\n\nStep 2: Call the model API from code\nBefore you start, ensure the API is running on your machine from the last lab.\n\n\n\n\n\n\nNote\n\n\n\nI’m assuming it’s running on port 8080 in this lab. If you’ve put it somewhere else, change the 8080 in the code below to match the port on your machine.\n\n\nIf you want to call the model in code, you can use any http request library. In R you should use httr2 and in Python you should use requests.\nHere’s what it looks like to call the API in Python\nimport requests\n\nreq_data = {\n \"bill_length_mm\": 0,\n \"species_Chinstrap\": False,\n \"species_Gentoo\": False,\n \"sex_male\": False\n}\nreq = requests.post('http://127.0.0.1:8080/predict', json = [req_data])\nres = req.json().get('predict')[0]\nor equivalently in R\nreq <- httr2::request(\"http://127.0.0.1:8080/predict\") |>\n httr2::req_body_json(\n list(\n \"bill_length_mm\" = 0,\n \"species_Chinstrap\" = FALSE,\n \"species_Gentoo\" = FALSE,\n \"sex_male\" = FALSE\n )\n ) |>\n httr2::req_perform()\nres <- httr2::resp_body_json(r)$predict[[1]]\nNote that there’s no translation necessary to send the request. The {requests} and{httr2} packages automatically know what to do with the Python dictionary and the R list.\nGetting the result back takes more work to find the right spot in the JSON returned. This is quite common.\n\n\n\n\n\n\nNote\n\n\n\nThe {vetiver} package also includes the ability to auto-query a {vetiver} API. I’m not using it here to expose the details of calling an API.\n\n\nLet’s take this API-calling code and build the presentation layer around it.\n\n\nStep 3: Build a shiny app\nWe will use the {shiny} R and Python package for creating interactive web apps using just Python code. If you don’t know much about {shiny}, you can unthinkingly follow the examples here or spend time with the Mastering Shiny book to learn to use it yourself.\nEither way, an app that looks like the picture above would look like this in Python\n\n\napp.py\n\nfrom shiny import App, render, ui, reactive\nimport requests\n\napi_url = 'http://127.0.0.1:8080/predict'\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"Penguin Mass Predictor\"), \n ui.layout_sidebar(\n ui.panel_sidebar(\n [ui.input_slider(\"bill_length\", \"Bill Length (mm)\", 30, 60, 45, step = 0.1),\n ui.input_select(\"sex\", \"Sex\", [\"Male\", \"Female\"]),\n ui.input_select(\"species\", \"Species\", [\"Adelie\", \"Chinstrap\", \"Gentoo\"]),\n ui.input_action_button(\"predict\", \"Predict\")]\n ),\n ui.panel_main(\n ui.h2(\"Penguin Parameters\"),\n ui.output_text_verbatim(\"vals_out\"),\n ui.h2(\"Predicted Penguin Mass (g)\"), \n ui.output_text(\"pred_out\")\n )\n ) \n)\n\ndef server(input, output, session):\n @reactive.Calc\n def vals():\n d = {\n \"bill_length_mm\" : input.bill_length(),\n \"sex_Male\" : input.sex() == \"Male\",\n \"species_Gentoo\" : input.species() == \"Gentoo\", \n \"species_Chinstrap\" : input.species() == \"Chinstrap\"\n\n }\n return d\n \n @reactive.Calc\n @reactive.event(input.predict)\n def pred():\n r = requests.post(api_url, json = [vals()])\n return r.json().get('predict')[0]\n\n @output\n @render.text\n def vals_out():\n return f\"{vals()}\"\n\n @output\n @render.text\n def pred_out():\n return f\"{round(pred())}\"\n\napp = App(app_ui, server)\n\nAnd like this in R\n\n\napp.R\n\nlibrary(shiny)\n\napi_url <- \"http://127.0.0.1:8080/predict\"\n\nui <- fluidPage(\n titlePanel(\"Penguin Mass Predictor\"),\n\n # Model input values\n sidebarLayout(\n sidebarPanel(\n sliderInput(\n \"bill_length\",\n \"Bill Length (mm)\",\n min = 30,\n max = 60,\n value = 45,\n step = 0.1\n ),\n selectInput(\n \"sex\",\n \"Sex\",\n c(\"Male\", \"Female\")\n ),\n selectInput(\n \"species\",\n \"Species\",\n c(\"Adelie\", \"Chinstrap\", \"Gentoo\")\n ),\n # Get model predictions\n actionButton(\n \"predict\",\n \"Predict\"\n )\n ),\n\n mainPanel(\n h2(\"Penguin Parameters\"),\n verbatimTextOutput(\"vals\"),\n h2(\"Predicted Penguin Mass (g)\"),\n textOutput(\"pred\")\n )\n )\n)\n\nserver <- function(input, output) {\n # Input params\n vals <- reactive(\n list(\n bill_length_mm = input$bill_length,\n species_Chinstrap = input$species == \"Chinstrap\",\n species_Gentoo = input$species == \"Gentoo\",\n sex_male = input$sex == \"Male\"\n )\n )\n\n # Fetch prediction from API\n pred <- eventReactive(\n input$predict,\n httr2::request(api_url) |>\n httr2::req_body_json(vals()) |>\n httr2::req_perform() |>\n httr2::resp_body_json(),\n ignoreInit = TRUE\n )\n\n # Render to UI\n output$pred <- renderText(pred()$predict[[1]])\n output$vals <- renderPrint(vals())\n}\n\n# Run the application\nshinyApp(ui = ui, server = server)\n\nOver the next few chapters, we will implement more architectural best practices for the app and eventually go to deployment." + "text": "Lab: Use a database and an API\nIn this lab, we will build the data and the presentation layers for our penguin mass model exploration. We’re going to create an app to explore the model, which will look like this:\n\nLet’s start by moving the data into an actual data layer.\n\nStep 1: Put the data in DuckDB\nLet’s start by moving the data into a DuckDB database and use it from there for the modeling and EDA scripts.\nTo start, let’s load the data.\nHere’s what that looks like in R:\ncon <- DBI::dbConnect(duckdb::duckdb(), dbdir = \"my-db.duckdb\")\nDBI::dbWriteTable(con, \"penguins\", palmerpenguins::penguins)\nDBI::dbDisconnect(con)\nOr equivalently, in Python:\nimport duckdb\nfrom palmerpenguins import penguins\n\ncon = duckdb.connect('my-db.duckdb')\ndf = penguins.load_penguins()\ncon.execute('CREATE TABLE penguins AS SELECT * FROM df')\ncon.close()\nNow that the data is loaded, let’s adjust our scripts to use the database.\nIn R, we will replace our data loading with connecting to the database. Leaving out all the parts that don’t change, it looks like\n\n\neda.qmd\n\ncon <- DBI::dbConnect(\n duckdb::duckdb(), \n dbdir = \"my-db.duckdb\"\n )\ndf <- dplyr::tbl(con, \"penguins\")\n\nWe also need to call to DBI::dbDisconnect(con) at the end of the script.\nWe don’t have to change anything because we wrote our data processing code in {dplyr}. Under the hood, {dplyr} can switch seamlessly to a database backend, which is really cool.\n\n\neda.qmd\n\ndf %>%\n group_by(species, sex) %>%\n summarise(\n across(\n ends_with(\"mm\") | ends_with(\"g\"),\n \\(x) mean(x, na.rm = TRUE)\n )\n ) %>%\n dplyr::collect() %>%\n knitr::kable()\n\nIt’s unnecessary, but I’ve added a call to dplyr::collect() in line 31. It will be implied if I don’t put it there manually, but it helps make it obvious that all the work before there has been pushed off to the database. It doesn’t matter for this small dataset, but it could benefit a larger dataset.\nIn Python, we’re just going to load the entire dataset into memory for modeling, so the line loading the dataset changes to\n\n\nmodel.qmd\n\ncon = duckdb.connect('my-db.duckdb')\ndf = con.execute(\"SELECT * FROM penguins\").fetchdf().dropna()\ncon.close()\n\nNow let’s switch to figuring out the connection we’ll need to our processing layer in the presentation layer.\n\n\nStep 2: Call the model API from code\nBefore you start, ensure the API is running on your machine from the last lab.\n\n\n\n\n\n\nNote\n\n\n\nI’m assuming it’s running on port 8080 in this lab. If you’ve put it somewhere else, change the 8080 in the code below to match the port on your machine.\n\n\nIf you want to call the model in code, you can use any http request library. In R you should use httr2 and in Python you should use requests.\nHere’s what it looks like to call the API in Python\nimport requests\n\nreq_data = {\n \"bill_length_mm\": 0,\n \"species_Chinstrap\": False,\n \"species_Gentoo\": False,\n \"sex_male\": False\n}\nreq = requests.post('http://127.0.0.1:8080/predict', json = [req_data])\nres = req.json().get('predict')[0]\nor equivalently in R\nreq <- httr2::request(\"http://127.0.0.1:8080/predict\") |>\n httr2::req_body_json(\n list(\n \"bill_length_mm\" = 0,\n \"species_Chinstrap\" = FALSE,\n \"species_Gentoo\" = FALSE,\n \"sex_male\" = FALSE\n )\n ) |>\n httr2::req_perform()\nres <- httr2::resp_body_json(r)$predict[[1]]\nNote that there’s no translation necessary to send the request. The {requests} and{httr2} packages automatically know what to do with the Python dictionary and the R list.\nGetting the result back takes more work to find the right spot in the JSON returned. This is quite common.\n\n\n\n\n\n\nNote\n\n\n\nThe {vetiver} package also includes the ability to auto-query a {vetiver} API. I’m not using it here to expose the details of calling an API.\n\n\nLet’s take this API-calling code and build the presentation layer around it.\n\n\nStep 3: Build a shiny app\nWe will use the {shiny} R and Python package for creating interactive web apps using just Python code. If you don’t know much about {shiny}, you can unthinkingly follow the examples here or spend time with the Mastering Shiny book to learn to use it yourself.\nEither way, an app that looks like the picture above would look like this in Python\n\n\napp.py\n\nfrom shiny import App, render, ui, reactive\nimport requests\n\napi_url = 'http://127.0.0.1:8080/predict'\n\napp_ui = ui.page_fluid(\n ui.panel_title(\"Penguin Mass Predictor\"), \n ui.layout_sidebar(\n ui.panel_sidebar(\n [ui.input_slider(\"bill_length\", \"Bill Length (mm)\", 30, 60, 45, step = 0.1),\n ui.input_select(\"sex\", \"Sex\", [\"Male\", \"Female\"]),\n ui.input_select(\"species\", \"Species\", [\"Adelie\", \"Chinstrap\", \"Gentoo\"]),\n ui.input_action_button(\"predict\", \"Predict\")]\n ),\n ui.panel_main(\n ui.h2(\"Penguin Parameters\"),\n ui.output_text_verbatim(\"vals_out\"),\n ui.h2(\"Predicted Penguin Mass (g)\"), \n ui.output_text(\"pred_out\")\n )\n ) \n)\n\ndef server(input, output, session):\n @reactive.Calc\n def vals():\n d = {\n \"bill_length_mm\" : input.bill_length(),\n \"sex_male\" : input.sex() == \"Male\",\n \"species_Gentoo\" : input.species() == \"Gentoo\", \n \"species_Chinstrap\" : input.species() == \"Chinstrap\"\n\n }\n return d\n \n @reactive.Calc\n @reactive.event(input.predict)\n def pred():\n r = requests.post(api_url, json = [vals()])\n return r.json().get('predict')[0]\n\n @output\n @render.text\n def vals_out():\n return f\"{vals()}\"\n\n @output\n @render.text\n def pred_out():\n return f\"{round(pred())}\"\n\napp = App(app_ui, server)\n\nAnd like this in R\n\n\napp.R\n\nlibrary(shiny)\n\napi_url <- \"http://127.0.0.1:8080/predict\"\n\nui <- fluidPage(\n titlePanel(\"Penguin Mass Predictor\"),\n\n # Model input values\n sidebarLayout(\n sidebarPanel(\n sliderInput(\n \"bill_length\",\n \"Bill Length (mm)\",\n min = 30,\n max = 60,\n value = 45,\n step = 0.1\n ),\n selectInput(\n \"sex\",\n \"Sex\",\n c(\"Male\", \"Female\")\n ),\n selectInput(\n \"species\",\n \"Species\",\n c(\"Adelie\", \"Chinstrap\", \"Gentoo\")\n ),\n # Get model predictions\n actionButton(\n \"predict\",\n \"Predict\"\n )\n ),\n\n mainPanel(\n h2(\"Penguin Parameters\"),\n verbatimTextOutput(\"vals\"),\n h2(\"Predicted Penguin Mass (g)\"),\n textOutput(\"pred\")\n )\n )\n)\n\nserver <- function(input, output) {\n # Input params\n vals <- reactive(\n list(\n bill_length_mm = input$bill_length,\n species_Chinstrap = input$species == \"Chinstrap\",\n species_Gentoo = input$species == \"Gentoo\",\n sex_male = input$sex == \"Male\"\n )\n )\n\n # Fetch prediction from API\n pred <- eventReactive(\n input$predict,\n httr2::request(api_url) |>\n httr2::req_body_json(list(vals())) |>\n httr2::req_perform() |>\n httr2::resp_body_json(),\n ignoreInit = TRUE\n )\n\n # Render to UI\n output$pred <- renderText(pred()$predict[[1]])\n output$vals <- renderPrint(vals())\n}\n\n# Run the application\nshinyApp(ui = ui, server = server)\n\nOver the next few chapters, we will implement more architectural best practices for the app and eventually go to deployment." }, { "objectID": "chapters/sec1/1-3-data-access.html#footnotes", diff --git a/sitemap.xml b/sitemap.xml index 2772e873..6e800324 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -2,110 +2,110 @@ https://do4ds.com/index.html - 2024-02-03T16:18:24.982Z + 2024-02-03T16:19:03.883Z https://do4ds.com/chapters/intro.html - 2024-02-03T16:18:24.990Z + 2024-02-03T16:19:03.891Z https://do4ds.com/chapters/sec1/1-0-sec-intro.html - 2024-02-03T16:18:24.998Z + 2024-02-03T16:19:03.895Z https://do4ds.com/chapters/sec1/1-1-env-as-code.html - 2024-02-03T16:18:25.014Z + 2024-02-03T16:19:03.911Z https://do4ds.com/chapters/sec1/1-2-proj-arch.html - 2024-02-03T16:18:25.022Z + 2024-02-03T16:19:03.923Z https://do4ds.com/chapters/sec1/1-3-data-access.html - 2024-02-03T16:18:25.050Z + 2024-02-03T16:19:03.951Z https://do4ds.com/chapters/sec1/1-4-monitor-log.html - 2024-02-03T16:18:25.066Z + 2024-02-03T16:19:03.963Z https://do4ds.com/chapters/sec1/1-5-deployments.html - 2024-02-03T16:18:25.082Z + 2024-02-03T16:19:03.979Z https://do4ds.com/chapters/sec1/1-6-docker.html - 2024-02-03T16:18:25.094Z + 2024-02-03T16:19:03.991Z https://do4ds.com/chapters/sec2/2-0-sec-intro.html - 2024-02-03T16:18:25.098Z + 2024-02-03T16:19:03.999Z https://do4ds.com/chapters/sec2/2-1-cloud.html - 2024-02-03T16:18:25.110Z + 2024-02-03T16:19:04.015Z https://do4ds.com/chapters/sec2/2-2-cmd-line.html - 2024-02-03T16:18:25.126Z + 2024-02-03T16:19:04.023Z https://do4ds.com/chapters/sec2/2-3-linux.html - 2024-02-03T16:18:25.142Z + 2024-02-03T16:19:04.043Z https://do4ds.com/chapters/sec2/2-4-app-admin.html - 2024-02-03T16:18:25.158Z + 2024-02-03T16:19:04.055Z https://do4ds.com/chapters/sec2/2-5-scale.html - 2024-02-03T16:18:25.170Z + 2024-02-03T16:19:04.067Z https://do4ds.com/chapters/sec2/2-6-networking.html - 2024-02-03T16:18:25.190Z + 2024-02-03T16:19:04.095Z https://do4ds.com/chapters/sec2/2-7-dns.html - 2024-02-03T16:18:25.222Z + 2024-02-03T16:19:04.119Z https://do4ds.com/chapters/sec2/2-8-ssl.html - 2024-02-03T16:18:25.230Z + 2024-02-03T16:19:04.127Z https://do4ds.com/chapters/sec3/3-0-sec-intro.html - 2024-02-03T16:18:25.238Z + 2024-02-03T16:19:04.135Z https://do4ds.com/chapters/sec3/3-1-ent-networks.html - 2024-02-03T16:18:25.246Z + 2024-02-03T16:19:04.139Z https://do4ds.com/chapters/sec3/3-2-auth.html - 2024-02-03T16:18:25.250Z + 2024-02-03T16:19:04.147Z https://do4ds.com/chapters/sec3/3-3-ent-scale.html - 2024-02-03T16:18:25.258Z + 2024-02-03T16:19:04.159Z https://do4ds.com/chapters/sec3/3-4-ent-pm.html - 2024-02-03T16:18:25.270Z + 2024-02-03T16:19:04.163Z https://do4ds.com/chapters/append/auth.html - 2024-02-03T16:18:25.278Z + 2024-02-03T16:19:04.171Z https://do4ds.com/chapters/append/lb.html - 2024-02-03T16:18:25.282Z + 2024-02-03T16:19:04.179Z https://do4ds.com/chapters/append/lab-map.html - 2024-02-03T16:18:25.290Z + 2024-02-03T16:19:04.191Z https://do4ds.com/chapters/append/cheatsheets.html - 2024-02-03T16:18:25.314Z + 2024-02-03T16:19:04.211Z