### A Pluto.jl notebook ### # v0.19.9 #> [frontmatter] #> author_url = "https://github.com/JuliaPluto" #> image = "https://user-images.githubusercontent.com/6933510/174067690-50c8128d-748b-4f50-8a76-2ce18166642b.png" #> order = "3" #> tags = ["basic", "interactivity", "classic"] #> author_name = "Pluto.jl" #> description = "Slider, buttons, dropdowns and more from PlutoUI.jl!" #> license = "Unlicense" using Markdown using InteractiveUtils # This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). macro bind(def, element) quote local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end local el = $(esc(element)) global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) el end end # ╔═╡ 071d9ca5-9b42-4583-ad96-a48f93453a0e using PlutoUI # ╔═╡ bc532cd2-c75b-11ea-313f-8b5e771c9227 md"""# PlutoUI.jl The [Interactivity sample notebook](./sample/Interactivity.jl) explains how Pluto notebooks can use **`@bind`** to add _interactivity_ to your notebook. It's a simple concept - it uses the same reactivity that you have when editing code, except now you use sliders and buttons, instead of editing code. However, code like ```julia @bind x html"" ``` is hard to memorize, so `PlutoUI` makes it more _Julian_: ```julia @bind x Slider(5:15) ``` """ # ╔═╡ 3eff9592-cc63-11ea-2b61-4170d1a7656a # ╔═╡ 051f31fc-cc63-11ea-1e2c-0704285ea6a9 md""" #### To use it in other notebooks Simply import the `PlutoUI` package, and Pluto's built-in package manager takes care of the rest! """ # ╔═╡ fddb794c-c75c-11ea-1f55-eb9c178424cd md""" # Basics """ # ╔═╡ b819e9a8-c760-11ea-11ee-dd01da663b5c md"## Slider" # ╔═╡ 34ebf81e-c760-11ea-05bb-376173e7ed10 @bind x Slider(5:15) # ╔═╡ a4488984-c760-11ea-2930-871f6b400ef5 x # ╔═╡ 1048d1e0-cc50-11ea-1bf3-d76cae42740a # ╔═╡ a709fd2e-c760-11ea-05c5-7bf673990de1 md"The first argument is a `Vector` or range. You can set the _default value_ using a keyword argument:" # ╔═╡ d3811ac2-c760-11ea-0811-131d9f1d3910 @bind y Slider(20:0.1:30, default=25) # ╔═╡ dfe10b6c-c760-11ea-2f77-79cc4cfa8dc4 y # ╔═╡ 06962cde-cc4f-11ea-0d96-69a8cb7eeda2 # ╔═╡ 6605d010-d0d1-4cc8-a34d-3158b8572b5d md""" ## Scrubbable `Scrubbable` makes a number interactive, you can **click and drag** its value left or right. Try it in the text below: """ # ╔═╡ 756e2c82-6e2f-4d7b-a1ed-5de97be04269 md""" _If Alice has $(@bind a Scrubbable(20)) apples, and she gives $(@bind b Scrubbable(3)) apples to Bob..._ """ # ╔═╡ c07c5a9e-61f9-4247-86e7-7c3f9956d0ff md""" _...then Alice has **$(a - b)** apples left._ """ # ╔═╡ c3fea1b2-fc11-4c19-9c01-a8e03fda2817 md""" Use the Live Docs to learn more about `Scrubbable`! """ # ╔═╡ 221c308e-3cbe-4689-aa67-8970957f8cb0 # ╔═╡ e49623ac-c760-11ea-3689-c15f2e2f6081 md"## NumberField A `NumberField` can be used just like a `Slider`, it just looks different:" # ╔═╡ 314cb85a-c761-11ea-1cba-b73f84a52be8 @bind x_different NumberField(0:100, default=20) # ╔═╡ 104b55ce-cc4f-11ea-1273-092a1717e399 # ╔═╡ 4513b730-c761-11ea-1460-2dca56081fcf md"## CheckBox" # ╔═╡ 4f8e4e1e-c761-11ea-1787-419cab59bb12 @bind z CheckBox() # ╔═╡ b787ead6-c761-11ea-3b17-41c0a5434f9b z # ╔═╡ 177e6bf0-cc50-11ea-0de2-e77544f5c615 # ╔═╡ b08c347e-c761-11ea-1b61-7b69631d078b md"Default value:" # ╔═╡ b53c8ffa-c761-11ea-38d1-2d4ad96a7bee @bind having_fun CheckBox(default=true) # ╔═╡ adcf4e68-c761-11ea-00bb-c3b15c6dedc0 having_fun # ╔═╡ 1a562ad4-cc50-11ea-2485-cdec6e1a78dc # ╔═╡ 5d420570-c764-11ea-396b-cf0db01d34aa having_fun ? md"🎈🎈" : md"☕" # ╔═╡ 09393bf2-cc4f-11ea-1e48-cfbedab8e6b4 # ╔═╡ cd1b5872-c761-11ea-2179-57a3cb34d235 md"## TextField" # ╔═╡ d9e85ed0-c761-11ea-30bf-83ce272526e0 @bind s TextField() # ╔═╡ e4c262d6-c761-11ea-36b2-055419bfc981 s # ╔═╡ 0934bc0c-cc50-11ea-0da8-0d6b2f275399 # ╔═╡ e690337c-c761-11ea-08be-ade40a464eb4 md"With a default value:" # ╔═╡ f1f83980-c761-11ea-1e34-97c0ffca3f67 @bind sentence TextField(default="te dansen omdat men leeft") # ╔═╡ f985c8de-c761-11ea-126c-1fd79d547b79 sentence # ╔═╡ 1cbfd28e-cc50-11ea-2c90-a7807e4979ef # ╔═╡ 0136af80-c762-11ea-2f1a-9dccff334a11 md"You can also create a **multi-line** text box!" # ╔═╡ 0e6f0508-c762-11ea-0352-09bd694a9b35 @bind poem TextField((30, 3), "Je opent en sluit je armen,\nMaar houdt niets vast.\nHet is net zwemmen") # (poem by: Sanne de Kroon) # ╔═╡ 3dcd7002-c765-11ea-323d-a1fb49409011 split(poem, "\n") # ╔═╡ 0aa3c85e-cc4f-11ea-2fba-4bdd513d9217 # ╔═╡ 5833f7f4-c763-11ea-0b95-9b21a40192a9 md"## Select" # ╔═╡ 690cf3ac-c763-11ea-10f0-b3e28c380be9 @bind vegetable Select(["potato", "carrot"]) # ╔═╡ 705662e2-c763-11ea-2f6d-cdaffc1fc73a vegetable # ╔═╡ 1feebd8f-667a-42fd-965d-5e3167ff7c7a @bind favourite_function Select([sin, cos, tan, sqrt]) # ╔═╡ 9128d2c1-364c-4446-baaa-6d0593edda47 favourite_function(2) # ╔═╡ 3930f0d8-cc50-11ea-3de6-d91ac5c6cd9f # ╔═╡ 787a2c88-c763-11ea-0a32-bb91ca60113d md"Instead of an array of values, you can also give an array of **pairs**, where the first item is the bound value, and the second item is displayed. " # ╔═╡ ac8c4dee-c763-11ea-1b2d-c590a2d50d7e @bind fruit Select(["apple" => "🍎", "melon" => "🍉"]) # ╔═╡ dcda9ad2-c763-11ea-3ec6-093b823ba66d fruit # ╔═╡ 0c3ab1f8-cc4f-11ea-0cfb-8f076d2c9836 # ╔═╡ 62c6f866-f0fe-11ea-0961-319f28d040d4 md""" ## MultiSelect This widget allows the user to select multiple element by holding `Ctrl` / `Cmd` while clicking a more items. """ # ╔═╡ a01c8096-f0fe-11ea-3e78-ad8551e84fa1 @bind vegetable_basket MultiSelect(["potato", "carrot", "boerenkool"]) # ╔═╡ a20e30f2-f0fe-11ea-0ca7-c5195c9eb24a vegetable_basket # ╔═╡ c819ef3e-f0fe-11ea-1213-9df7597e4e89 md"Just like `Select`, you can also give an array of pairs." # ╔═╡ b104ba6d-0293-4378-9652-f628f1d08d97 md""" ## MultiCheckBox This widget allows the user to select multiple elements using checkboxes. """ # ╔═╡ 16f2218d-f1bc-4b34-a355-53acfa77fbf5 @bind fruit_basket MultiCheckBox(["apple", "blueberry", "mango"]) # ╔═╡ 2c7811cb-d9ea-470c-8cb7-2b3803489f3f fruit_basket # ╔═╡ 78be41d1-7dda-4bec-b75f-fbcf8b7594a7 md""" You can use `MultiSelect` and `MultiCheckBox` with any vector of objects, not just strings: """ # ╔═╡ 90d84f1b-042c-444e-8bac-fe358b6d68a1 @bind my_functions MultiCheckBox([sin, cos, tan]) # ╔═╡ b97cfb04-0c39-4709-9419-9294e677a872 [f(π) for f in my_functions] # ╔═╡ 283d1177-c605-4652-905b-9a70354cf878 md"Just like `Select`, you can also give an array of pairs. See the Live Docs for `MultiCheckBox` for all the customization options!" # ╔═╡ 0b1ce22e-c764-11ea-3d60-e799d58aee30 md"## Button" # ╔═╡ 6d9108a8-c765-11ea-0a38-09a1364998b1 @bind clicked Button("Hello world") # ╔═╡ 7a14e496-c765-11ea-20a1-6fb960009251 clicked # ╔═╡ 3eff932a-cc50-11ea-366e-812d3854dd4c # ╔═╡ 7e10fb52-c765-11ea-2a71-0fc347d09885 md""" ### Button as reactive trigger In the example above, _any cell that references `clicked` will re-evaluate_ when you click the button. This means that you can a button as a **reactive trigger**, by referencing its value in another cell. """ # ╔═╡ b91764e8-c765-11ea-27a2-4ba5777fbd89 @bind go Button("Recompute") # ╔═╡ bb356b12-c765-11ea-2c36-697f4314bb93 let go md"I am $(rand(1:15)) years old!" end # ╔═╡ 9276da28-cc4f-11ea-17b3-65eec41a181e # ╔═╡ 92def54a-cc4f-11ea-12c5-652f2bb46413 md"## FilePicker" # ╔═╡ 9920e56c-cc4f-11ea-2d5e-f5371c79f048 @bind important_document FilePicker() # ╔═╡ 44591b34-cc50-11ea-2005-2f7075e6f2db important_document # ╔═╡ 4fda3072-cc50-11ea-2804-197b6391b269 md"The file picker is useful if you want to show off your notebook on a dataset or image **uploaded by the reader**. It will work anywhere - you don't access files using their path. The caveat is that large files might take a long time to get processed: everything needs to pass through the browser. If you are using large datasets, a better option is to use `Select` to let the reader pick a filename. You can then read the file using `Base.read(filename, type)`" # ╔═╡ 3e5dd7d2-c760-11ea-1dca-6d8720b3558d md"# Extras" # ╔═╡ f31668c6-c768-11ea-1501-5f41afa7c83b md"## Clock" # ╔═╡ 417390ba-c760-11ea-27df-5908858ae88c @bind t Clock() # ╔═╡ 49e7cd06-c760-11ea-3f5d-2741d94278a6 t # ╔═╡ 31a2f3c4-cc51-11ea-3652-bd814517a4b5 # ╔═╡ 67709812-c760-11ea-2bda-9756ead35749 md"You can set the interval (`5.0` seconds), and disable the UI (`true`):" # ╔═╡ 4c2b45a0-c760-11ea-2b64-3fefc820cd5b @bind t_slow Clock(5.0, true) # ╔═╡ 5be148cc-c760-11ea-0819-a7bb403d27ff t_slow # ╔═╡ 347e3d06-cc51-11ea-012c-43e824eaffa2 # ╔═╡ 343d7118-cc51-11ea-387a-fb22d8c73506 md"You can use a `Clock` to drive an animation! Or use it to repeat the same command at an interval: just like with `Button`, you can reference a bound (reactive) variable without actually using it!" # ╔═╡ 32e41ac2-cc51-11ea-3358-bbead9c68123 # ╔═╡ f74f434a-c768-11ea-079c-fb707e6ba17b md"## DownloadButton" # ╔═╡ ea00721c-cc4b-11ea-1e82-0b3dbe6a7f1e md""" The download button is not an **input** element that you can `@bind` to, it's an **output** that you can use to get processed data from your notebook easily. The second argument is the _output filename_. """ # ╔═╡ fc12280c-c768-11ea-3ebc-ebcd6b3459c1 DownloadButton(poem, "poem.txt") # ╔═╡ 067cbcde-cc4c-11ea-3eed-972dc6d7bb3b DownloadButton([0x01, 0x02, 0x03], "secret_data.bin") # ╔═╡ 7da30d97-b28a-4eb9-a2ef-fad599b549d1 md""" # High-level inputs """ # ╔═╡ 170089cd-f366-4c0a-b58d-fe6e36049db7 md""" ## Confirm Normally, when you move a [`Slider`](@ref) or type in a [`TextField`](@ref), all intermediate values are sent back to `@bind`. By wrapping an input element in `confirm`, you get a button to manually **control when the value is sent**, intermediate updates are hidden from Pluto. """ # ╔═╡ b29215cb-8e7e-4382-822c-cdaa4c473ba1 @bind distance confirm(Slider(1:100)) # ╔═╡ 00f9f608-85bd-4932-b585-39f74dcf53b4 distance # ╔═╡ 48a9ffbd-cac7-4c4e-85e5-c3d0693e5550 md""" `confirm` can be wrapper around any input element to create a new one, including inputs from other packages, or inputs that you have made yourself! """ # ╔═╡ 5c85ee41-da68-4f5f-b45e-e1de7996747d # ╔═╡ 8c51343f-cb35-4ff9-9fd8-642ffab57e22 md""" ## Combine This next high-level component is a bit tricky, but very powerful! Using `combine`, you can create a single input out of multiple existing ones! In the example below, we create a new input, `wind_speed_input`. Notice that the list of wind directions is *dynamic*: if you add a new direction, a 5th slider will appear! """ # ╔═╡ 621f2e82-5ab4-4ab9-a0ff-fb1cc1b41295 import PlutoUI: combine # ╔═╡ a4837897-caae-447a-8db9-7775e7a4d0c8 # ╔═╡ d278189e-6a5b-428a-8c81-ce3d206b042c function wind_speed_input(directions::Vector) return combine() do Child inputs = [ md""" $(name): $( Child(name, Slider(1:100)) )""" for name in directions ] md""" #### Wind speeds $(inputs) """ end end # ╔═╡ f5c421cc-dbdb-459a-9bb4-d648507a87d2 @bind speeds wind_speed_input(["North", "East", "South", "West"]) # ╔═╡ a4eac824-ba87-473a-b39a-783c4de3f933 speeds # ╔═╡ f9052ed8-84cc-4cca-abb2-9363aafc6040 speeds.North # ╔═╡ 4ca9c749-08ee-467f-af2c-9b2f13199d72 md""" Use the Live Docs to learn more about `combine` and to see additional examples. > 🙋 `combine` is very useful in combination with [HypertextLiteral.jl](https://github.com/MechanicalRabbit/HypertextLiteral.jl), which you can learn using our JavaScript sample notebook. """ # ╔═╡ ad8e9b30-c75d-11ea-1fd0-0b53592135bf md"""# Loading resources Notebooks use data from different places. For example, you use [`Base.read`](https://docs.julialang.org/en/v1/base/io-network/#:~:text=read(filename%3A%3AAbstractString%2C%20String)) to access local data (files) inside your Julia code, and [`Downloads.jl`](https://github.com/JuliaLang/Downloads.jl) for remote data (interwebs). `PlutoUI` helps you communicate with the person reading the notebook! - To get **remote media** (URL) inside your **Markdown text**, use `PlutoUI.Resource`. - To get **local media** (file) inside your **Markdown text**, use `PlutoUI.LocalResource`. (With _media_, we mean **images**, video and audio.) > We **strongly recommend** that you use _remote_ media inside Pluto notebooks! > > If your notebook uses local images, then those images **will not show** when someone else opens your notebook, unless they have the same images on their computer, at the exact same location. _More on this later._ """ # ╔═╡ 87d088d0-cc54-11ea-02c6-bd673b95b9d3 md"""## Resource If you just want to show **images inside Markdown**, you can use the built-in syntax (without `PlutoUI`): ``` md"Here is a _dog_: " ``` `PlutoUI.Resource` has some extra features: - specify **image dimensions** and spacing - support for videos - support for audio""" # ╔═╡ 6a7e7e54-c75e-11ea-2ea7-ed3da37e9e96 dog_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Welsh_Springer_Spaniel.jpg/640px-Welsh_Springer_Spaniel.jpg" # ╔═╡ 3c68b25c-c761-11ea-226a-4f46579a6732 Resource(dog_url, :width => x * x_different) # ╔═╡ 9ac7921c-c75e-11ea-30f5-c35e6ee370cb t_rex_url = "https://upload.wikimedia.org/wikipedia/commons/transcoded/6/62/Meow.ogg/Meow.ogg.mp3" # ╔═╡ a8c57442-c75e-11ea-1913-7d82cbd2c69c flower_url = "https://upload.wikimedia.org/wikipedia/commons/4/41/Sunflower_Flower_Opening_Time_Lapse.ogv" # ╔═╡ cb37b916-c75b-11ea-0c83-6ba759536075 md"""Hello I am a dog $(Resource(dog_url))""" # ╔═╡ 16ea31fc-c75e-11ea-0f2d-dd790a56b2dc md"""And I sound like this: $(Resource(t_rex_url))""" # ╔═╡ 1dfd8cc6-c75e-11ea-3c04-a96734779c97 md"""This is my flower friend $(Resource(flower_url, :width => 200))""" # ╔═╡ 2fda30ea-c75e-11ea-2ff5-7f2dcf4f9b66 md"### Attributes You can pass additional _HTML attributes_ to `Resource`, these will be added to the element. For example:" # ╔═╡ 525ceea0-c75e-11ea-2766-f72418fd784e md""" $(Resource(dog_url, :width => 20)) $(Resource(dog_url, :width => 50)) $(Resource(dog_url, :width => 100)) $(Resource(dog_url, :width => 100, :style => "filter: grayscale(100%); border: 3px solid black;")) """ # ╔═╡ 382d41d8-c75e-11ea-2ae3-2ffe96e04b5a Resource(flower_url, :width => 200, :autoplay => "", :loop => "") # ╔═╡ 958ab19c-cc56-11ea-162e-d3664e66ff66 md"### YouTube, Vimeo, etc. If you use `Resource` for video, the URL has to point to a _video file_ (like `.mp4` or `.mov`). Popular video sites don't give you that link, instead, you can use their **embed codes**. You can find these inside the video player, by right clicking or using the menu buttons. You then use that inside an HTML block: ``` html\"\"\" ~ paste embed code here ~ \"\"\" ``` You might need to change the `width` to `100%` to make it fit." # ╔═╡ 8477619c-cc57-11ea-0618-1778c502d28f html"""
""" # ╔═╡ f743076c-cc57-11ea-1a8e-8799d9db985a # ╔═╡ c65d28a2-c75d-11ea-2e13-7332f93d9c5e md"## LocalResource _(not recommended)_ The examples above use `Resource` to make media from a URL available inside Markdown. To use **local files**, simply **replace `Resource` with `LocalResource`**, and use a _file path_ instead of a URL." # ╔═╡ c16dff74-cc5d-11ea-380c-aff1639b5551 # ╔═╡ dada2154-c75d-11ea-2312-b9156a9a531e html"I really hope that this works" # ╔═╡ f809110c-cc55-11ea-1551-e138c28d5d82 md"""Hello I am a dog $(LocalResource("C:\\Users\\fons\\Pictures\\hannes.jpg"))""" # ╔═╡ 1c930364-cc58-11ea-36c8-0ddf7c4700cd md""" $(html"OOPS"), it didn't! $(html"