Skip to content

Commit adb2d4b

Browse files
authored
Merge pull request #2 from sol-eng/prep-quickstart
Prep quickstart
2 parents 58cf9c0 + 1d9c172 commit adb2d4b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+189496
-61
lines changed

.connect.yml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
default:
2+
content:
3+
- title: "Use Python with R"
4+
path: "./rmarkdown-notebook"
5+
description: "Use the reticulate package to integrate Python into an R Markdown notebook."
6+
tag:
7+
- "Demo Content|Python"
8+
url: "/python/reticulate/"
9+
image: "reticulated_python.png"
10+
- title: "Sentiment Analysis with Python"
11+
path: "./sentiment-analysis"
12+
description: "A Plumber API that uses R and Python to evaluate sentiment in text input using a pretrained spaCy model."
13+
tag:
14+
- "Demo Content|Python"
15+
url: "/python/sentiment-analysis/"
16+
image: "sentiment-analysis/spacy_logo.jpg"

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,3 @@ __pycache__
4141
.ipynb_checkpoints
4242
*.html
4343
rmarkdown-notebook/flights.csv
44-
sentiment-analysis/model/

.internal.yml

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
default:
22
content:
33
- name: "Use Python with R"
4-
path: "./reticulate"
4+
path: "./rmarkdown-notebook"
55
description: "Use the reticulate package to integrate Python into an R Markdown notebook."
66
tag:
77
- "Demo Content|Python"
8-
url: "/python/reticulate/"
8+
url: "/python/reticulate/"
9+
image: "reticulated_python.png"
10+
- name: "Sentiment Analysis with Python"
11+
path: "./sentiment-analysis"
12+
description: "A Plumber API that uses R and Python to evaluate sentiment in text input using a pretrained spaCy model."
13+
tag:
14+
- "Demo Content|Python"
15+
url: "/python/sentiment-analysis/"
16+
image: "sentiment-analysis/spacy_logo.jpg"

image-classifier/app.R

+67-51
Original file line numberDiff line numberDiff line change
@@ -3,79 +3,95 @@ library(reticulate) # Used to call Tensorflow Python script
33
library(shiny)
44
library(shinycssloaders)
55

6+
behavior <- config::get("image")
7+
stopifnot(behavior %in% c("upload", "fetch-image-url"))
8+
69
# Load source of Python image classifier script
710
source_python('image-classifier.py')
811

912
server <- function(input, output, session) {
10-
11-
output$contents <- renderTable({
12-
# After the user uploads a file, the image will be classified and the predictions will be shown.
13+
14+
# where the image that should be classified is on disk
15+
image_path <- reactiveVal("./img/cat.jpg")
16+
17+
image_prefix <- "pytorch_image"
18+
19+
# the configurable selector for fetch-image-url vs. upload
20+
output$image_selector <- renderUI({
21+
if (behavior == "fetch-image-url") {
22+
list(
23+
textInput("file1", label = h5("Enter Image URL:"), value = ""),
24+
actionButton("fetch-image-url", "Fetch Image")
25+
)
26+
} else if (behavior == "upload") {
27+
fileInput("file_upload", label = h5("Upload an Image:"))
28+
} else {
29+
stop("Invalid configuration. Please chose 'fetch-image-url' or 'upload'")
30+
}
31+
})
32+
33+
# handle upload
34+
observe({
35+
req(input$file_upload)
36+
upload_file <- input$file_upload
37+
image_path(upload_file$datapath[[1]])
38+
})
39+
40+
# handle fetch-image-url
41+
observeEvent(input[["fetch-image-url"]], {
1342
req(input$file1)
43+
tryCatch({
44+
# Fetch image from URL
45+
temp_fetch_image_url <- fs::file_temp(image_prefix, ext = ".jpg")
46+
downloader::download(input$file1, temp_fetch_image_url)
47+
48+
image_path(temp_fetch_image_url)
49+
}, error = function(e){
50+
# usually, you would not expose this to the user
51+
# without a little sanitization
52+
showNotification(as.character(safeError(e)), type = "warning")
53+
})
54+
})
55+
56+
output$contents <- renderTable({
57+
req(image_path())
1458

1559
tryCatch(
1660
{
17-
# Download image from URL
18-
downloader::download(input$file1, "image")
19-
2061
# Call function from PyTorch Python script to classify image
21-
results <- classify_image_pytorch(image_path="image")
62+
results <- classify_image_pytorch(image_path=image_path())
2263
},
2364
error = function(e) {
24-
stop(safeError(e))
65+
# usually, you would not expose this to the user
66+
# without a little sanitization
67+
showNotification(as.character(safeError(e)), type = "warning")
2568
}
2669
)
2770
return(results)
2871
})
2972

73+
# render the image
3074
output$image1 <- renderImage({
31-
req(input$file1)
32-
tryCatch(
33-
{
34-
input$file1
35-
},
36-
error = function(e) {
37-
stop(safeError(e))
38-
}
39-
)
75+
req(image_path())
76+
77+
# Copy the image to temp space
78+
new_path <- fs::file_copy(image_path(), fs::file_temp(image_prefix, ext = ".jpg"))
4079

4180
# Return a list containing the filename
42-
if(is.null(input$file1)) {
81+
if(is.null(new_path)) {
4382
return(NULL)
4483
}
4584
else {
46-
return(list(src = "image"))
85+
return(list(src = new_path, style = htmltools::css(width = "100%")))
4786
}
4887
})
4988

50-
observe({
51-
x = input$oil_platform
52-
image_url = "https://upload.wikimedia.org/wikipedia/commons/a/a1/Oil_platform.jpeg"
53-
updateTextInput(session, "file1", value = paste(image_url))
54-
})
55-
56-
observe({
57-
x = input$truck
58-
image_url = "https://upload.wikimedia.org/wikipedia/commons/6/6c/Toyota-1984-truck.jpg"
59-
updateTextInput(session, "file1", value = paste(image_url))
60-
})
61-
62-
observe({
63-
x = input$flower
64-
image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Aster_Tataricus.JPG/612px-Aster_Tataricus.JPG"
65-
updateTextInput(session, "file1", value = paste(image_url))
66-
})
67-
68-
observe({
69-
x = input$cat
70-
image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7f/Egyptian_Mau_Bronze.jpg/611px-Egyptian_Mau_Bronze.jpg"
71-
updateTextInput(session, "file1", value = paste(image_url))
72-
})
73-
74-
observe({
75-
x = input$dog
76-
image_url = "https://upload.wikimedia.org/wikipedia/commons/e/e4/Border_Collie_600.jpg"
77-
updateTextInput(session, "file1", value = paste(image_url))
78-
})
89+
# default images
90+
observeEvent(input$oil_platform, image_path("./img/oil_platform.jpg"))
91+
observeEvent(input$truck, image_path("./img/truck.jpg"))
92+
observeEvent(input$flower, image_path("./img/flower.jpg"))
93+
observeEvent(input$cat, image_path("./img/cat.jpg"))
94+
observeEvent(input$dog, image_path("./img/dog.jpg"))
7995

8096
}
8197

@@ -84,8 +100,8 @@ ui <- fluidPage(
84100
titlePanel("Image Classifier"),
85101
sidebarLayout(
86102
sidebarPanel(
87-
textInput("file1", label = h5("Enter Image URL:"), value = ""),
88-
helpText("Your image will be downloaded and classified using Tensorflow in Python."),
103+
uiOutput("image_selector"),
104+
helpText("Your image will be classified using Tensorflow in Python."),
89105
helpText("The resulting predictions will be shown along with their confidence level."),
90106
hr(),
91107
helpText("Or, choose an example image:"),
@@ -103,7 +119,7 @@ ui <- fluidPage(
103119
mainPanel(
104120
# Output
105121
tableOutput("contents") %>% withSpinner(),
106-
imageOutput("image1") %>% withSpinner(color = "#ffffff")
122+
imageOutput("image1", height = NULL) %>% withSpinner(color = "#ffffff")
107123
)
108124
)
109125
)

image-classifier/config.yml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
default:
2+
image: "fetch-image-url"
3+
quickstart:
4+
image: "upload"

image-classifier/img/cat.jpg

85 KB
Loading

image-classifier/img/dog.jpg

96.6 KB
Loading

image-classifier/img/flower.jpg

60.3 KB
Loading

image-classifier/img/oil_platform.jpg

71.1 KB
Loading

image-classifier/img/truck.jpg

120 KB
Loading

0 commit comments

Comments
 (0)