Web Application Development with R Using Shiny · is the author of Web Application Development with...

Post on 28-Mar-2020

5 views 1 download

Transcript of Web Application Development with R Using Shiny · is the author of Web Application Development with...

WebApplicationDevelopmentwithRUsingShinyThirdEdition

Buildstunninggraphicsandinteractivedatavisualizationstodelivercutting-edgeanalytics

ChrisBeeleyShitalkumarR.Sukhdeve

BIRMINGHAM-MUMBAI

WebApplicationDevelopmentwithRUsingShinyThirdEditionCopyright©2018PacktPublishing

Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthepublisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.

Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyoftheinformationpresented.However,theinformationcontainedinthisbookissoldwithoutwarranty,eitherexpressorimplied.Neithertheauthors,norPacktPublishingoritsdealersanddistributors,willbeheldliableforanydamagescausedorallegedtohavebeencauseddirectlyorindirectlybythisbook.

PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthecompaniesandproductsmentionedinthisbookbytheappropriateuseofcapitals.However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.

AcquisitionEditor:DevanshiDoshiContentDevelopmentEditor:AishwaryaGawankarTechnicalEditor:RutujaVazeCopyEditor:SafisEditingProjectCoordinator:SheejalShahProofreader:SafisEditingIndexer:PratikShirodkarGraphics:AlishonMendonsaProductionCoordinator:ArvindkumarGupta

Firstpublished:October2013Secondpublished:January2016Thirdedition:September2018

Productionreference:1260918

PublishedbyPacktPublishingLtd.LiveryPlace35LiveryStreetBirminghamB32PB,UK.

ISBN978-1-78899-312-8

www.packtpub.com

mapt.io

Maptisanonlinedigitallibrarythatgivesyoufullaccesstoover5,000booksandvideos,aswellasindustryleadingtoolstohelpyouplanyourpersonaldevelopmentandadvanceyourcareer.Formoreinformation,pleasevisitourwebsite.

Whysubscribe?SpendlesstimelearningandmoretimecodingwithpracticaleBooksandVideosfromover4,000industryprofessionals

ImproveyourlearningwithSkillPlansbuiltespeciallyforyou

GetafreeeBookorvideoeverymonth

Maptisfullysearchable

Copyandpaste,print,andbookmarkcontent

Packt.comDidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFandePubfilesavailable?YoucanupgradetotheeBookversionatwww.packt.comandasaprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwithusatcustomercare@packtpub.comformoredetails.

Atwww.packt.com,youcanalsoreadacollectionoffreetechnicalarticles,signupforarangeoffreenewsletters,andreceiveexclusivediscountsandoffersonPacktbooksandeBooks.

Contributors

AbouttheauthorsChrisBeeleyhasbeenusingRandotheropensourcesoftwarefortenyearstobettercapture,analyze,andvisualizedatainthehealthcaresectorintheUK.HeistheauthorofWebApplicationDevelopmentwithRUsingShiny.Heworksfull-time,developingsoftwaretostore,collate,andpresentquestionnairedatausingopentechnologies(MySQL,PHP,R,andShiny),withaparticularemphasisonusingthewebandShinytoproducesimpleandattractivedatasummaries.ChrisisworkinghardtoincreasetheuseofRandShiny,bothwithinhisownorganizationandthroughouttherestofthehealthcaresector,aswelltoenablehisorganizationtobetteruseavarietyofotherdatasciencetools.ChrishasalsodeliveredtalksaboutShinyalloverthecountry.

ShitalkumarR.SukhdeveisaseniordatascientistatPTSmartfrenTelecomTbk,Jakarta,Indonesia.Onhiscareerjourney,hehasworkedwithRelianceJioasadatascientist,entrepreneur,andcorporatetrainer.Hehastrainedover1,000professionalsandstudentsandhasdeliveredover200lecturesonRandmachinelearning.ResearchanddevelopmentinAI-drivenself-optimizingnetworks,predictivemaintenance,optimalnetworkquality,anomalydetection,andcustomerexperiencemanagementfor4GLTEnetworksareallareasofinteresttoShitalkumar.HeisveryexperiencedwithR,Spark,RShiny,H2O,Python,KNIME,theHadoopecosystem,MapReduce,Hive,andconfiguringtheopensourceRShinyserverformachinelearningmodelsanddashboarddeployment.

Iwouldliketothankmyfather,Mr.RajendraSukhdeve;mother,Mrs.ManjuSukhdeve;wife,Sandika;family;andfriendsforalwaysbelievinginmeandallowingmetodevotetimetowritingthisbook.MyspecialthankstoMr.NikolaSucevic,Mr.BhupeshDaheria,andMr.PramodKolhatkarforgivingmeanopportunitytoworkwiththemandexploredatascience.ThankstoPacktPublishingandteamfortheircontinuoussupportandguidance.

AboutthereviewerAbhinavAgrawalhasmorethan13years'ITexperienceandhasworkedwithtopconsultingfirmsandUSfinancialinstitutions.Hisexpertiseliesinthebankingandfinancialservicesdomainandheisaseasonedproject/programmanagementprofessionalwithapassionfordataanalytics,machinelearning,artificialintelligence,roboticsprocessautomation,digitaltransformation,andemergingdigitalpaymentssolutions.HestartedusingRandShinyin2014todevelopweb-basedanalyticssolutionsforclients.HeworksasaprogrammanagerandisafreelanceRinstructorandRShinyconsultant.Inhissparetime,helovestomentordatasciencestudents,makedataanalytics-relatedinstructionalvideosonYouTube,andshareknowledgewiththecommunity.

PacktissearchingforauthorslikeyouIfyou'reinterestedinbecominganauthorforPackt,pleasevisitauthors.packtpub.comandapplytoday.Wehaveworkedwiththousandsofdevelopersandtechprofessionals,justlikeyou,tohelpthemsharetheirinsightwiththeglobaltechcommunity.Youcanmakeageneralapplication,applyforaspecifichottopicthatwearerecruitinganauthorfor,orsubmityourownidea.

TableofContentsTitlePage

CopyrightandCredits

WebApplicationDevelopmentwithRUsingShinyThirdEdition

www.PacktPub.com

Whysubscribe?

Packt.com

Contributors

Abouttheauthors

Aboutthereviewer

Packtissearchingforauthorslikeyou

Preface

Whothisbookisfor

Whatthisbookcovers

Togetthemostoutofthisbook

Downloadtheexamplecodefiles

Downloadthecolorimages

Conventionsused

Getintouch

Reviews

1. BeginningRandShinyInstallingR

TheRconsole

CodeeditorsandIDEs

LearningR

Gettinghelp

Loadingdata

Datatypesandstructures

Dataframes,lists,arrays,andmatrices

Variabletypes

Functions

Objects

Basegraphicsandggplot2

Barchart

Linechart

Introductiontothetidyverse

Cecin'estpasunepipe

Gapminder

AsimpleShiny-enabledlineplot

InstallingShinyandrunningtheexamples

Summary

2. ShinyFirstStepsTypesofShinyapplication

InteractiveShinydocumentsinRMarkdown

AminimalexampleofafullShinyapplication

Theui.Roftheminimalexample

AnoteonHTMLhelperfunctions

Thefinishedinterface

Theserver.Roftheminimalexample

Theprogramstructure

Anoptionalexercise

Embeddingapplicationsindocuments

Widgettypes

TheGapminderapplication

TheUI

Dataprocessing

Reactiveobjects

Outputs

Textsummary

Trendgraphs

Amapusingleaflet

Advancedlayoutfeatures

Summary

3. IntegratingShinywithHTMLRunningtheapplicationsandcode

ShinyandHTML

CustomHTMLlinksinShiny

ui.R

server.R

AminimalHTMLinterface

index.html

server.R

IncludingaShinyapponawebpage

HTMLtemplates

Inlinetemplatecode

server.R

ui.Randtemplate.html

Definingcodeintheui.Rfile

ui.R

Takeastepbackandrewind

Exercise

Debugging

Bootstrap3andShiny

Summary

4. MasteringShiny'sUIFunctionsShiny'slayoutfunctions

Simple

Complete

Doityourself

Combininglayoutfunctions

StreamliningtheUIbyhidingelements

NamingtabPanelelements

BeautifultableswithDataTable

Reactiveuserinterfaces

Thereactiveuserinterfaceexample– server.R

Thereactiveuserinterfaceexample– ui.R

Progressbars

Progressbarwithshinycssloaders

Modals

AlternativeShinydesigns

Summary

5. EasyJavaScriptandCustomJavaScriptFunctionsJavaScriptandShiny

Example1– readingandwritingtheDOM

ui.R

appendText.js

Example2 –sendingmessagesbetweenclientandserver

ui.R

server.R

dropdownDepend.js

Shinyjs

Extendshinyjs

ui.R

server.R

JavaScript

RespondingtoeventsinJavaScript

htmlwidgets

Dygraphs

rCharts

d3heatmap

threejs

Summary

6. DashboardsApplicationsinthischapter

Flexdashboards

Sidebarapplicationwithextrastyling

AddingiconstoyourUI

Usingshinythemes

Usingthegridlayout

ui.R

Fulldashboard

Notifications

Infoboxes

ui.R

GoogleChartsgauge

ResizingtheGooglechart

ui.R

Summary

7. PowerShinyAnimation

ReadingclientinformationandGETrequestsinShiny

CustominterfacesfromGETstrings

Downloadinggraphicsandreports

Downloadablereportswithknitr

Downloadinganduploadingdata

Bookmarking

Bookmarkingstate

EncodingthestateintoaURL

Single-fileapplication

Multiple-fileapplication

Bookmarkingbysavingthestatetotheserver

Interactiveplots

Interactivetables

Rowselection

Columnselection

CellSelection

Linkinginteractivewidgets

Shinygadgets

Addingapassword

Summary

8. CodePatternsinShinyApplicationsReactivityinRShiny

Acloserlookatreactivity

Controllingspecificinputwiththeisolate()function

Runningreactivefunctionsovertime(executionscheduling)

Event-handlingusingobserveEventandeventReactive

Functionsandmodules

Shinytest

Debugging

Handlingerrors(includingvalidate()andreq())

Validate

Handlingmissinginputwithreq()

ProfilingRcode

Debounceandthrottle

Summary

9. PersistentStorageandSharingShinyApplicationsSharingoverGitHub

AnintroductiontoGit

UsingGitandGitHubwithinRstudio

ProjectsinRStudio(h3)

SharingapplicationsusingGit

Sharingusing.zipand.tar

Sharingwiththeworld

Shinyapps.io

Shinyapps.iowithoutRStudio

Shinyserver

RunningShinyapponAmazonAWS

Scoping,loading,andreusingdatainShinyapplications

Temporarydatainput/output

Persistentdatastorage

DatabaseusingDplyr,DBI,andPOOL

SQLInjection

Summary

OtherBooksYouMayEnjoy

Leaveareview-letotherreadersknowwhatyouthink

PrefaceWiththisbook,youwillbeabletoharnessthegraphicalandstatisticalpowerofRandrapidlydevelopinteractiveandengaginguserinterfacesusingthesuperbShinypackage,whichmakesprogrammingforuserinteractionsimple.Risahighlyflexibleandpowerfultoolusedforanalyzingandvisualizingdata.ShinyistheperfectcompaniontoR,makingitquickandsimpletoshareanalysisandgraphicsfromRforuserstotheninteractwithandqueryovertheweb.LetShinydothehardworkwhileyouspendyourtimegeneratingcontentandstyling,ratherthanwritingcodetohandleuserinputs.Thisbookisfullofpracticalexamplesandshowsyouhowtowritecutting-edgeinteractivecontentfortheweb,rightfromaminimalexampleallthewaytofullystyledandextensibleapplications.

ThisbookincludesanintroductiontoShinyandRandtakesyouallthewaytoadvancedfunctionsinShinyaswellasusingShinyinconjunctionwithHTML,CSS,andJavaScripttoproduceattractiveandhighlyinteractiveapplicationsquicklyandeasily.ItalsoincludesadetailedlookatotherpackagesavailableforR,whichcanbeusedinconjunctionwithShinytoproducedashboards,maps,advancedD3graphics,andmuchmore.

WhothisbookisforThisbookisforanybodywhowantstoproduceinteractivedatasummariesovertheweb,whetheryouwanttosharethemwithafewcolleaguesorthewholeworld.

WhatthisbookcoversChapter1,BeginningRandShiny,runsthroughthebasicsofstatisticalgraphics,datainput,andanalysiswithR.WealsodiscussdatastructuresandprogrammingbasicsinRinordertogiveyouathoroughgroundinginRbeforewelookatShiny.

Chapter2,ShinyFirstSteps,helpsyoubuildyourfirstShinyapplication.WebeginbysimplyaddinginteractivecontenttoadocumentwritteninMarkdown;andthendelvedeeperintoShiny,buildingaveryprimitiveandminimalexample;andfinally,we'lllookatmorecomplexapplicationsandtheinputsandoutputsnecessarytobuildthem.

Chapter3,IntegratingShinywithHTML,covershowShinyworkswithexistingwebcontentinHTMLandCSS.WediscusstheShinyhelperfunctionsthatallowyoutoaddacustomHTMLtoastandardShinyapplicationandhowtobuildaminimalexampleofaShinyapplicationinyourownrawHTMLwithShinyrunninginthebackground.We'llalsogetintotheuseofHTMLtemplates,whichmakeintegratingShinywithHTMLeasy.

Chapter4,MasteringShiny'sUIFunctions,describesallthedifferentwaysthatShinyofferstohelpyouachievethelayoutandappearancethatyouwantyourapplicationtohave.Itdiscusseshowtoshowandhideelementsoftheinterface,aswellashowtomaketheinterfacereacttothestateoftheapplication.Producingattractivedatatablesisdiscussed,aswellashowtogiveyourusersmessageswithprogressbarsandmodals.

Chapter5,EasyJavaScriptandCustomJavaScriptFunctions,coversusingJavaScriptwithShiny,rightfromaddingsimpleJavaScriptrightonthepagetoenhanceaprogram'sappearanceorfunctionality,tosendingmessagestoandfromtheclient'sbrowserusingmessagestoandfromJavaScript.Theuseoftheshinyjsandhtmlwidgetspackagesisalsodiscussed,whichfurtheraddtoyourabilitytoaddcustomorcannedJavaScripttoaShinyapplication.

Chapter6,Dashboards,includesacoupleofdifferenttypesofShinydashboard,anddescribeshowtomakeattractiveShinydashboards,usingcolor,icons,anda

widerangeofinputsandoutputs,aswellashowtolaythemoutusingtheveryflexiblelayoutfunctions,whichcanbeaccessedwithaShinydashboard.

Chapter7,PowerShiny,includesmanypowerfulfeaturesofShiny,suchasanimatingplots,readingclientinformation,andGETrequestsinShiny.Wewillgothroughgraphicsandreportgenerationandhowtodownloadthemusingknitr.Downloadinganduploadingisalsoaninterestingpartofanyapplication,andwe'lltakealookatitinShinywithsomeexamples.Bookmarkingthestateoftheapplicationisanadd-ontoregeneratetheoutputontheapplication.Wewillseeademonstrationoffastapplicationdevelopmentusingwidgetsandgadgets.Attheendofthechapter,wewillseehowtoauthenticatetheapplicationusingapassword.

Chapter8,CodePatternsinShinyApplications,coversthecodingpatternsavailableinShiny.WewilldiscussreactivityinRShiny,controllingspecificinputwiththeisolate()function,runningreactivefunctionsovertime,eventhandlingusingtheobserveEventfunctionsandtheShinytestmodules,debugging,handlingerrors(includingvalidate()andreq()),profilingRcode,debounce,andthrottle.

Chapter9,PersistentStorageandSharingShinyApplications,willexplorehowtokeepyourcodeonGitHub.ThischapterwillincludeanintroductiontoGitHubandhowtointegrateGitwithRStudio.WewillalsolearnhowtoshareyourreportsandaliveapplicationwithShinyapps.io.Thischapterwillalsofocusonthedeploymentoptionsavailable,suchasShinyServerandrunningShinyinAWS.WewillgothroughsomeoftheconceptsthatarevitalfordevelopingagoodShinyapplication,suchasscoping,loading,andreusingdatainShinyapplications.We'llalsolookattemporarydatainput/output,permanentdatafunctions,databases,SQLinjection,anddatabaseswiththepoolpackage.

TogetthemostoutofthisbookNopreviousexperiencewithR,Shiny,HTML,orCSSisrequiredtousethisbook,althoughyoushouldpossesssomepreviousexperiencewithprogramminginadifferentlanguage.ThisbookcanbeusedwiththeWindows,macOS,orLinuxoperatingsystems.ItrequirestheinstallationofRaswellasseveraluser-contributedpackageswithinR.Randitsassociatedpackagesareallavailableforfree.TheRStudioIDEisrecommendedbecauseitsimplifiessomeofthetaskscoveredinthisbook,butisnotessential.Again,thissoftwareisavailablefreeofcharge.

DownloadtheexamplecodefilesYoucandownloadtheexamplecodefilesforthisbookfromyouraccountatwww.packt.com.Ifyoupurchasedthisbookelsewhere,youcanvisitwww.packt.com/supportandregistertohavethefilesemaileddirectlytoyou.

Youcandownloadthecodefilesbyfollowingthesesteps:

1. Loginorregisteratwww.packt.com.2. SelecttheSUPPORTtab.3. ClickonCodeDownloads&Errata.4. EnterthenameofthebookintheSearchboxandfollowtheonscreen

instructions.

Oncethefileisdownloaded,pleasemakesurethatyouunziporextractthefolderusingthelatestversionof:

WinRAR/7-ZipforWindowsZipeg/iZip/UnRarXforMac7-Zip/PeaZipforLinux

ThecodebundleforthebookisalsohostedonGitHubathttps://github.com/PacktPublishing/Web-Application-Development-with-R-Using-Shiny-third-edition.Incasethere'sanupdatetothecode,itwillbeupdatedontheexistingGitHubrepository.

Wealsohaveothercodebundlesfromourrichcatalogofbooksandvideosavailableathttps://github.com/PacktPublishing/.Checkthemout!

DownloadthecolorimagesWealsoprovideaPDFfilethathascolorimagesofthescreenshots/diagramsusedinthisbook.Youcandownloadithere:https://www.packtpub.com/sites/default/files/downloads/9781788993128_ColorImages.pdf.

ConventionsusedThereareanumberoftextconventionsusedthroughoutthisbook.

CodeInText:Indicatescodewordsintext,databasetablenames,foldernames,filenames,fileextensions,pathnames,dummyURLs,userinput,andTwitterhandles.Hereisanexample:"The[1]phrasetellsyouthatRreturnedoneresult;inthiscase,4."

Ablockofcodeissetasfollows:

<ul>

<li>Firstbullet</li>

<li>Secondbullet</li>

<li>Thirdbullet</li>

</ul>

Whenwewishtodrawyourattentiontoaparticularpartofacodeblock,therelevantlinesoritemsaresetinbold:

tabsetPanel(id="theTabs",

tabPanel("Summary",textOutput("summary"),

value="summary"),

tabPanel("Trend",plotOutput("trend"),

value="trend"),

tabPanel("Map",leafletOutput("map"),

p("Mapdataisfromthemostrecentyearintheselectedrange"),

value="map")

)

Anycommand-lineinputoroutputiswrittenasfollows:

>2+2

[1]4

Bold:Indicatesanewterm,animportantword,orwordsthatyouseeonscreen.Forexample,wordsinmenusordialogboxesappearinthetextlikethis.Hereisanexample:"Tosetupanewproject,gotoFile|NewProjectinRStudio."

Warningsorimportantnotesappearlikethis.

Tipsandtricksappearlikethis.

GetintouchFeedbackfromourreadersisalwayswelcome.

Generalfeedback:Ifyouhavequestionsaboutanyaspectofthisbook,mentionthebooktitleinthesubjectofyourmessageandemailusatcustomercare@packtpub.com.

Errata:Althoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdohappen.Ifyouhavefoundamistakeinthisbook,wewouldbegratefulifyouwouldreportthistous.Pleasevisitwww.packt.com/submit-errata,selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthedetails.

Piracy:IfyoucomeacrossanyillegalcopiesofourworksinanyformontheInternet,wewouldbegratefulifyouwouldprovideuswiththelocationaddressorwebsitename.Pleasecontactusatcopyright@packt.comwithalinktothematerial.

Ifyouareinterestedinbecominganauthor:Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,pleasevisitauthors.packtpub.com.

ReviewsPleaseleaveareview.Onceyouhavereadandusedthisbook,whynotleaveareviewonthesitethatyoupurchaseditfrom?Potentialreaderscanthenseeanduseyourunbiasedopiniontomakepurchasedecisions,weatPacktcanunderstandwhatyouthinkaboutourproducts,andourauthorscanseeyourfeedbackontheirbook.Thankyou!

FormoreinformationaboutPackt,pleasevisitpackt.com.

BeginningRandShinyRisfreeandopensource,andisthepre-eminenttoolforstatisticiansanddatascientists.Ithasmorethan6,000user-contributedpackages,whichhelpusersworkinginfieldsasdiverseaschemistry,biology,physics,finance,psychology,andmedicalscience.R'sextremelypowerfulandflexiblestatisticalgraphicsgreatlyhelptheseusersintheirwork.

Inrecentyears,Rhasbecomemoreandmorepopular,andthereareanincreasingnumberofpackagesforRthatmakecleaning,analyzing,andpresentingdataonthewebeasyforeverybody.TheShinypackageinparticularmakesitincrediblyeasytodeliverinteractivedatasummariesandqueriestoendusersthroughanymodernwebbrowser.You'rereadingthisbookbecauseyouwanttousethesepowerfulandflexibletoolsforyourowncontent.

Thisbookwillshowyouhow,rightfromwhenyoujuststartwithR,youcanbuildyourowninterfaceswithShinyandintegratethemwithyourownwebsites.Inthischapter,we'regoingtocoverthefollowingtopics:

DownloadingandinstallingRChoosingacode-editingenvironment/IDELookingatthepowerofRLearningabouthowRStudioandcontributedpackagescanmakewritingcode,managingprojects,andworkingwithdataeasierInstallingShinyandrunningtheexamplesHowtousesomeofShiny'sawesomeapplications,andsomeoftheelementsoftheShinyapplicationthatwewillbuildoverthecourseofthisbook

Risabigsubject,andthisisawhistle-stoptour,soifyougetalittlelostalongtheway,don'tworry.Thischapterisreallyallaboutshowingyouwhat'soutthere,andwillbothencourageyoutodelvedeeperintothebitsthatinterestyouandshowyouplacesyoucangoforhelpifyouwanttolearnmoreonaparticularsubject.

InstallingRRisavailableforWindows,MacOSX,andLinuxatcran.r-project.org.Thesourcecodeisalsoavailableatthesameaddress.ItisalsoincludedinmanyLinuxpackagemanagementsystems;Linuxusersareadvisedtocheckbeforedownloadingfromtheweb.DetailsoninstallingfromsourceorbinaryforWindows,MacOSX,andLinuxareallavailableatcran.r-project.org/doc/manuals/R-admin.html.

TheRconsoleWindowsandMacOSXuserscanruntheRapplicationtolaunchtheRconsole.LinuxandMacOSXuserscanalsoruntheRconsolestraightfromtheTerminalbytypingR.

Ineithercase,theRconsoleitselfwilllooksomethinglikethefollowingscreenshot:

RwillrespondtoyourcommandsrightfromtheTerminal.Let'shaveago.RunthefollowingcommandintheRconsole:

>2+2

[1]4

The[1]phrasetellsyouthatRreturnedoneresult,inthiscase,4.ThefollowingcommandshowsyouhowtoprintHelloworld:

>print("Helloworld!")

[1]"Helloworld!"

Thefollowingcommandshowsthemultiplesofpi:

>1:10*pi

[1]3.1415936.2831859.42477812.56637115.70796318.849556

[7]21.99114925.13274128.27433431.415927

Thisexampleillustratesvector-basedprogramminginR.The1:10phrasegeneratesthenumbers1:10asavector,andeachisthenmultipliedbypi,whichreturnsanothervector,theelementseachbeingpitimeslargerthantheoriginal.OperatingonvectorsisanimportantpartofwritingsimpleandefficientRcode.Asyoucansee,Ragainindexesthevaluesitreturnsattheconsole,withtheseventhvaluebeing21.99.

OneofthebigstrengthsofusingRisthegraphicscapability,whichisexcellent,eveninavanillainstallationofR(thesegraphicsarereferredtoasthebasegraphicsbecausetheyshipwithR).Whenaddingpackagessuchasggplot2andsomeoftheJavaScript-basedpackages,Rbecomesagraphicaltourdeforce,whetherproducingstatistical,mathematical,ortopographicalfigures,orindeedanyothertypeofgraphicaloutput.Togetaflavorofthepowerofthebasegraphics,simplytypethefollowingintheConsoleandseethetypesofplotsthatcanbemadeusingR:

>demo(graphics)

Youcanalsotypethefollowingcommand:

>demo(persp)

Therewillbemoreonggplot2andbasegraphicslaterinthechapter.

Enjoy!TherearemanymoreexamplesofRgraphicsatr-graph-gallery.com.

CodeeditorsandIDEsTheWindowsandOSXversionsofRbothcomewithbuilt-incodeeditors,whichallowcodetobeedited,saved,andsenttotheRconsole.It'shardtorecommendthatyouusethisbecauseitisratherprimitive.MostuserswouldbebestservedbyRStudio(foundatrstudio.com/),whichincludesprojectmanagementandversioncontrol(includingsupportforGit,whichiscoveredinChapter9,PersistentStorageandSharingShinyApplications),theviewingofdataandgraphics,codecompletion,packagemanagement,andmanyotherfeatures.ThefollowingisanillustrativescreenshotofanRStudiosession:

Ascanbeseen,inthetop-leftcorner,thereisthecode-editingpane(withsyntaxhighlighting).Movingclockwisefromtherewilltakeyoutotheenvironmentpane(inwhichyoucanseethedifferentobjectsthatareloadedintothesession),whichistheviewingpanecontainingvariousoptionssuchasFiles,Plots,Build,Help,andfinally,atthebottomleft,theConsole.Inthemiddle,thereisoneofthemostusefulfeaturesofRStudio,theabilitytoviewdataframes.ThisviewcanbecreatedbyclickingadataframeintheEnvironmentpanelatthetopright.

Thisfunctionalsoenablessortingandfilteringbycolumn.

However,ifyoualreadyuseanIDEforothertypesofcode,itisquitelikelythatRcanbewellintegratedintoit.ExamplesofIDEswithgoodRintegrationincludethefollowing:

EmacswiththeEmacsSpeaksStatisticspluginVimwiththeVim-RpluginEclipsewiththeStatETplugin

LearningRTherearealmostasmanyusesforRastherearepeopleusingit.Itisnotpossiblethatyourspecificneedswillbecoveredinthisbook.However,youprobablywanttouseRtoprocess,query,andvisualizedata,suchassalesfigures,satisfactionsurveys,concurrentusers,sportingresults,orwhatevertypesofdatayourorganizationprocesses.Fornow,let'sjusttakealookatthebasics.

GettinghelpTherearemanybooksandonlinematerialsthatcoverallaspectsofR.ThenameRcanmakeitdifficulttocomeupwithusefulwebsearchhits(substitutingCRANforRcansometimeshelp);nonetheless,searchingforRtutorialbringsupusefulresults.Someusefulresourcesincludethefollowing:

AnexcellentintroductiontosyntaxanddatastructuresinR(atgoo.gl/M0RQ5z)VideosonusingRfromGoogle(atgoo.gl/A3uRsh)Swirl(atswirlstats.com)Quick-R(atstatmethods.net)

AttheRconsole,thecodephrase?functionnamecanbeusedtoshowthehelpfileforafunction.Forexample,?helpbringsuphelpmaterials,andusing??helpwillbringupalistofpotentiallyrelevantfunctionsfrominstalledpackages.

SubscribingtoandaskingquestionsontheR-helpmailinglistatstat.ethz.ch/mailman/listinfo/r-helpallowsyoutocommunicatewithsomeoftheleadingfiguresintheRcommunity,aswellasmanyothertalentedenthusiasts.Readthepostingguideanddoyourresearchbeforeyouaskanyquestions,becauseit'sabusyandsometimesunforgivinglist.

TherearetwoStackExchangecommunitiesthatcanprovidefurtherhelpatstats.stackexchange.com/(forquestionsaboutstatisticsandvisualizationwithR)andstackoverflow.com/(forquestionsaboutprogrammingwithR).

TherearemanywaystolearnRandrelatedsubjectsonline;RStudiohasaveryusefullistontheirwebsiteatgoo.gl/8tX7FP.

LoadingdataThesimplestwayofloadingdataintoRisprobablyusingacomma-separatedvalue(.csv)spreadsheetfile,whichcanbedownloadedfrommanydatasourcesandloadedandsavedinallspreadsheetsoftware(suchasExcelorLibreOffice).Theread.table()commandimportsdataofthistypebyspecifyingtheseparatorasacomma,orusingread.csv(),afunctionspecificallyfor.csvfiles,asshowninthefollowingcommand:

>analyticsData=read.table("~/example.csv",sep=",")

Otherwise,youcanusethefollowingcommand:

>analyticsData=read.csv("~/example.csv")

Notethatunlikeotherlanguages,Ruses<-forassignmentaswellas=.Assignmentcanbemadetheotherwayusing->.Theresultofthisisthatycanbetoldtoholdthevalueof4inay<-4or4->yformat.Therearesomeother,moreadvancedthingsthatcanbedonewithassignmentinR,butdon'tworryaboutthemnow.Inthisbook,Iwillpreferthe=operator,sinceIusethisinmyowncode.Justbeawareofbothmethodssothatyoucanunderstandthecodeyoucomeacrossinforumsandblogposts.

Eitheroftheprecedingcodeexampleswillassignthecontentsoftheexample.csvfiletoadataframenamedanalyticsData,withthefirstrowofthespreadsheetprovidingthevariablenames.AdataframeisaspecialtypeofobjectinR,whichisdesignedtobeusefulforthestorageandanalysisofdata.

RStudiowilleventakecareofloading.csvfilesforyou,ifyouclickontheminthefileselectorpane(inthebottomrightbydefault)andselectImportdataset....Thiscanbeusefultohelpyougetstarted,butasyougetmoreconfidentit'sreallybettertodoeverythingwithcoderatherthanpointingandclicking.RStudiowill,toitsgreatcredit,showyouthecodethatmakesyourpointingandclickingwork,sotakeanoteofitanduseittoloadthedatathenexttimeyourself.

DatatypesandstructuresTherearemanydatatypesandstructuresofdatawithinR.ThefollowingtopicssummarizesomeofthemaintypesandstructuresthatyouwillusewhenbuildingShinyapplications.

Dataframes,lists,arrays,andmatricesDataframeshaveseveralimportantfeaturesthatmakethemusefulfordataanalysis:

Rectangulardatastructures,withthetypicalusebeingcases(forexample,thedaysinonemonth)listeddowntherowsandvariables(pageviews,uniquevisitors,orreferrers)listedalongthecolumnsAmixofdatatypesissupported.Atypicaldataframemightincludevariablescontainingdates,numbers(integersorfloats),andtextWithsubsettingandvariableextraction,Rprovidesalotofbuilt-infunctionalitytoselectrowsandvariableswithinadataframeManyfunctionsincludeadataargument,whichmakesitverysimpletopassdataframesintofunctionsandprocessonlythevariablesandcasesthatarerelevant,whichmakesforcleanerandsimplercode

Wecaninspectthefirstfewrowsofthedataframeusingthehead(analyticsData)command.Thefollowingscreenshotshowstheoutputofthiscommand:

Asyoucansee,therearefourvariableswithinthedataframe:onecontainsdates,twocontainintegervariables,andonecontainsanumericvariable.

Variablescanbeextractedfromdataframesverysimplyusingthe$operator,asfollows:

>analyticsData$pageViews

[1]836676940689647899934718776570651816

[13]731604627946634990994599657642894983

[25]646540756989965821

Variablescanalsobeextractedfromdataframesusing[],asshowninthefollowingcommand:

>analyticsData[,"pageViews"]

Notetheuseofacommawithnothingbeforeittoindicatethatallrowsarerequired.Ingeneral,dataframescanbeaccessedusingdataObject[x,y],withxbeingthenumber(s)orname(s)oftherowsrequiredandybeingthenumber(s)orname(s)ofthecolumnsrequired.Forexample,ifthefirst10rowswererequiredfromthepageViewscolumn,itcouldbeachievedlikethis:

>analyticsData[1:10,"pageViews"]

[1]836676940689647899934718776570

Leavingthespacebeforethecommablankreturnsallrows,andleavingthespaceafterthecommablankreturnsallvariables.Forexample,thefollowingcommandreturnsthefirstthreerowsofallvariables:

>analyticsData[1:3,]

Thefollowingscreenshotshowstheoutputofthiscommand:

Dataframesareaspecialtypeoflist.Listscanholdmanydifferenttypesofdata,includinglists.AswithmanydatatypesinR,theirelementscanbenamed,whichcanbeusefultowritecodethatiseasytounderstand.Let'smakealistoftheoptionsfordinner,withdrinkquantitiesexpressedinmilliliters.

Inthefollowingexample,pleasealsonotetheuseofthec()function,whichisusedtoproducevectorsandlistsbygivingtheirelementsseparatedbycommas.Rwillpickanappropriateclassforthereturnvalue,stringforvectorsthatcontainstrings,numericforthosethatonlycontainnumbers,logicalforBooleanvalues,andsoon:

>dinnerList<-list("Vegetables"=

c("Potatoes","Cabbage","Carrots"),

"Dessert"=c("Icecream","Applepie"),

"Drinks"=c(250,330,500)

)

Notethatcodeisindentedthroughout,althoughenteringcodedirectlyintotheconsolewillnotproduceindentations;itisdoneforreadability.

Indexingissimilartodataframes(whichare,afterall,justaspecialinstanceofalist).Theycanbeindexedbynumber,asshowninthefollowingcommand:

>dinnerList[1:2]

$Vegetables

[1]"Potatoes""Cabbage""Carrots"

$Dessert

[1]"Icecream""Applepie"

Thisreturnsalist.Returninganobjectoftheappropriateclassisachievedusing[[]]:

>dinnerList[[3]]

[1]250330500

Inthiscase,anumericvectorisreturned.Theycanalsobeindexedbyname,asshowninthefollowingcode:

>dinnerList["Drinks"]

$Drinks

[1]250330500

Notethatthisalsoreturnsalist.

Matricesandarrays,which,unlikedataframes,onlyholdonetypeofdata,alsomakeuseofsquarebracketsforindexing,withanalyticsMatrix[,3:6]returningallrowsofthethirdtosixthcolumns,analyticsMatrix[1,3]returningjustthefirstrowofthethirdcolumn,andanalyticsArray[1,2,]returningthefirstrowofthesecondcolumnacrossalloftheelementswithinthethirddimension.

VariabletypesRisadynamicallytypedlanguage,andyouarenotrequiredtodeclarethetypeofyourvariableswhenusingit.Ofcourse,itisworthknowingaboutthedifferenttypesofvariablethatyoumightreadorwriteusingR.Thedifferenttypesofvariablecanbestoredinavarietyofstructures,suchasvectors,matrices,anddataframes,althoughsomerestrictionsapplyasmentionedpreviously(forexample,matricesmustcontainonlyonevariabletype).Thefollowingbulletlistcontainsthespecificsofusingthesevariabletypes:

Declaringavariablewithatleastonestringinitwillproduceavectorofstrings(inR,thecharacterdatatype),asshowninthefollowingcode:

>c("First","Third",4,"Second")

[1]"First""Third""4""Second"

Youwillnoticethatthenumeral4isconvertedtoastring,"4".Thisisasaresultofcoercion,inwhichelementsofadatastructureareconvertedtootherdatatypesinordertofitwithinthetypesthatareallowedwithinthedatastructure.Coercionoccursautomatically,asinthiscase,orwithanexplicitcalltotheas()function—forexample,as.numeric(),oras.Date().

Declaringavariablethatcontainsonlynumberswillproduceanumericvector,asshowninthefollowingcode:

>c(15,10,20,11,0.4,-4)

[1]15.010.020.011.00.4-4.0

R,ofcourse,alsoincludesalogicaldatatype,asshowninthefollowingcode:

>c(TRUE,FALSE,TRUE,TRUE,FALSE)

[1]TRUEFALSETRUETRUEFALSE

Adatatypeexistsfordates,whichareoftenasourceofproblemsforbeginners,asshowninthefollowingcode:

>as.Date(c("2013/10/24","2012/12/05","2011/09/02"))

[1]"2013-10-24""2012-12-05""2011-09-02"

TheuseofthefactordatatypetellsRallofthepossiblevaluesofacategoricalvariable,suchasgenderorspecies,asshowninthefollowingcode:

>factor(c("Male","Female","Female","Male","Male"),

levels=c("Female","Male"))

[1]MaleFemaleFemaleMaleMale

Levels:FemaleMale

FunctionsAsyougrowinconfidencewithR,youwillwanttobeginwritingyourownfunctions.Thisisachievedverysimply,andinamannerquitesimilartomanyotherlanguages.YouwillnodoubtwanttoreadmoreaboutwritingfunctionsinRinmoredetail,butjusttogiveyouanidea,thefollowingcodeisafunctioncalledthesumMultiplyfunctionthataddstogetherxandyandmultipliestheresultbyz:

sumMultiply<-function(x,y,z){

final=(x+y)*z

return(final)

}

ThisfunctioncannowbecalledusingsumMultiply(2,3,6),whichwillreturn2plus3times6,whichgives30.

ObjectsTherearemanyspecialobjecttypeswithinRthataredesignedtomakeiteasiertoanalyzedata.FunctionsinRcanbepolymorphic—thatistosay,theycanrespondtodifferentdatatypesindifferentwaysinordertoproducetheoutputthattheuserdesires.Forexample,theplot()functioninRrespondstoawidevarietyofdatatypesandobjects,includingsingle-dimensionvectors(eachvalueofyplottedsequentially)andtwo-dimensionalmatrices(producingascatterplot),aswellasspecializedstatisticalobjects,suchasregressionmodelsandtimeseriesdata.Inthelattercase,plotsthatarespecializedforthesepurposesareproduced.

Aswiththerestofthisintroduction,don'tworryifyouhaven'twrittenfunctionsbefore,ordon'tunderstandobjectconceptsandaren'tsurewhatthisallmeans.Youcanproducegreatapplicationswithoutunderstandingallthesethings,butasyoudomoreandmorewithR,youwillstarttowanttolearnmoredetailsabouthowRworksandhowexpertsproduceRcode.Thisintroductionisdesignedtogiveyouajumping-offpointtolearnmoreabouthowtogetthebestoutofR(andShiny).

Basegraphicsandggplot2Therearelotsofuser-contributedgraphicspackagesinRthatcanproducesomewonderfulgraphics.YoumaywishtotakealookforyourselfattheCRANtaskviewatcran.r-project.org/web/views/Graphics.html.Wewillhaveaveryquicklookattwoapproaches:basegraphics,socalledbecausetheyformthedefaultgraphicalenvironmentwithinavanillainstallationofR,andggplot2,ahighlypopularuser-contributedpackageproducedbyHadleyWickham,whichisalittletrickiertomasterthanbasegraphics,butcanveryrapidlyproduceawiderangeofgraphicaldatasummaries.Wewillcovertwographsthatarefamiliartoeveryone:thebarchartandthelinechart.

BarchartUsefulwhencomparingquantitiesacrosscategories,barchartsareverysimpleinbasegraphics,particularlywhencombinedwiththetable()command.Wewillusethempgdataset,whichcomeswiththeggplot2package;itsummarizesthedifferentcharacteristicsofarangeofcars.First,let'sinstalltheggplot2package.Youcandothisstraightfromtheconsoleusingthefollowingcode:

>install.packages("ggplot2")

Alternatively,youcanusethebuilt-inpackagefunctionsinIDEssuchasRStudioorRKWard.We'llneedtoloadthepackageatthebeginningofeachsessioninwhichwewanttousethisdataset,orintheggplot2packageitself.Fromtheconsole,typethefollowingcommand:

>library(ggplot2)

Wewillusethetable()commandtocountthenumberofeachtypeofcarfeaturedinthedataset,asshowninthefollowingcode:

>table(mpg$class)

Thisreturnsatableobject(anotherspecialobjecttypewithinR)thatcontainsthecolumnsshowninthefollowingscreenshot:

Producingabarchartofthisobjectisachievedsimplyusingthefollowingcode:

>barplot(table(mpg$class),main="Basegraphics")

Thebarplotfunctiontakesavectoroffrequencies.Wheretheyarenamed,asisthecaseinourexample(thetable()commandreturningnamedfrequenciesin

tableform),namesareautomaticallyincludedonthexaxis.Thedefaultsforthisgraphareratherplain.Explore?barplotand?partolearnmoreaboutfine-tuningyourgraphics.

We'vealreadyloadedtheggplot2packageinordertousethempgdataset,butifyouhaveshutdownRinbetweenthesetwoexamples,youwillneedtoreloaditbyusingthefollowingcommand:

>library(ggplot2)

Thesamegraphisproducedinggplot2asfollows:

>ggplot(data=mpg,aes(x=class))+geom_bar()+

ggtitle("ggplot2")

Thisggplotcallshowsthethreefundamentalelementsofggplotcalls:theuseofadataframe(data=mpg);thesetupofaesthetics(aes(x=class)),whichdetermineshowvariablesaremappedontoaxes,colors,andothervisualfeatures;andtheuseof+geom_xxx().Aggplotcallsetsupthedataandaesthetics,butdoesnotplotanything.Functionssuchasgeom_bar()(therearemanyothers;see??geom)tellggplotwhattypeofgraphtoplot,aswellasinstructingittotakeoptionalarguments—forexample,geom_bar()optionallytakesapositionargument,whichdefineswhetherthebarsshouldbestacked,offset,orstretchedtoacommonheighttoshowproportionsinsteadoffrequencies.

Theseelementsarethekeytothepowerandflexibilitythatggplot2offers.Oncethedatastructureisdefined,waysofvisualizingthatdatastructurecanbeaddedandtakenawayeasily,notonlyintermsofthetypeofgraphic(bar,line,orscattergraph)butalsothescalesandcoordinatessystem(log10,polarcoordinates,andsoon)andstatisticaltransformations(smoothingdata,summarizingoverspatialcoordinates,andsoon).Theappearanceofplotscanbeeasilychangedwithpresetanduser-definedthemes,andmultipleplotscanbeaddedinlayers(thatis,addingthemtooneplot)orfacets(thatis,drawingmultipleplotswithonefunctioncall).

Thebasegraphicsandggplotversionsofthebarchartareshowninthefollowingscreenshotforthepurposesofcomparison:

LinechartLinechartsaremostoftenusedtoindicatechange,particularlyovertime.Thistime,wewillusethelongleydataset,featuringeconomicvariablesfrombetween1947and1962,asshowninthefollowingcode:

>plot(x=1947:1962,y=longley$GNP,type="l",

xlab="Year",main="Basegraphics")

Thexaxisisgivenverysimplybythe1947:1962phrase,whichenumeratesallthenumbersbetween1947and1962,andthetype="l"argumentspecifiestheplottingofthelines,asopposedtopointsorboth.

Theggplotcalllooksalotlikethebarchart,exceptwithanxandydimensionintheaestheticsthistime.Thecommandlooksasfollows:

>ggplot(longley,aes(x=1947:1962,y=GNP))+geom_line()+

xlab("Year")+ggtitle("ggplot2")

IntroductiontothetidyverseThetidyverseis,accordingtoitshomepage,"anopinionatedcollectionofRpackagesdesignedfordatascience"(seehttps://www.tidyverse.org/).Allofthepackagesareinstalledusinginstall.packages("tidyverse"),andcallinglibrary(tidyverse)loadsasubsetofthesepackages,thoseconsideredtohavethemostvalueinday-to-daydatascience.Callinglibrary(tidyverse)loadsthefollowingpackages:

ggplot2:Forplottingdplyr:Fordatawranglingtidyr:Fortidying(anduntidying!)datareadr:Betterfunctionsforreadingcomma-andtab-delimiteddataandothertypesofflatfilespurrr:Foriteratingtibble:Betterdataframesstringr:Fordealingwithstringsforcats:Betterhandlingoffactors,anRpropertyusedtodescribethecategoriesofavariable,describedbrieflyearlierinthechapter

Installingthetidyversealsoinstallsthefollowingpackages,whichthenneedtobeloadedseparatelywiththeirownlibrary()instruction:readxl,haven,jsonlite,xml2,httr,rvest,DBI,lubridate,hms,blob,rlang,magrittr,glue,andbroom.Formoredetailsonthesepackages,consultthedocumentationattidyverse.org/.

Thekeywordinthisdescriptionisopinionated.ThetidyverseisasetofRpackagesthatworkwithtidydata,eitherproducingit,orconsumingit,orboth.TidydatawasdescribedbyHadleyWickhamintheJournalofStatisticalSoftware,Vol59,Issue10(https://www.jstatsoft.org/article/view/v059i10/v59i10.pdf).Tidydataobeysthreeprinciples:

EachvariableformsacolumnEachobservationformsarowEachtypeofobservationalunitformsatable

FormanyRusers,theirfirstintroductiontotidydatawillhavebeenggplot2,

whichconsumestidydataandrequiresothertypesofdatatobemungedintothisform.Inordertoexplainwhatthismeans,wewilllookatasimpleexample.Forthepurposesofthisdiscussion,wewillignorethelastprinciple,whichismoreaboutorganizinggroupsofdatasetsratherthanindividualdatasets.

Let'shavealookatasimpleexampleofamessydataset.Intherealworld,youwillfinddatasetsthatarealotmessierthanthis,butthiswillservetoillustratetheprinciplesweareusinghere.ThefollowingarethefirstthreerowsofthemedaltableforthePyeongchangWinterOlympics,whichtookplacein2018,asanRdataframe:

medals=data.frame(country=c("Norway","Germany","Canada"),

gold=c(14,14,11),

silver=c(14,10,8),

bronze=c(11,7,10)

)

Ifweprintitattheconsole,itlookslikethefollowingscreenshot:

Thisisperhapsthemostcommonsortofmessydatayouwillcomeacross:greatasasummary,certainlyintelligibletopeoplewatchingtheWinterOlympics,butnottidy.Therearemedalsinthreedifferentcolumns.Atidydatasetwouldcontainonlyonecolumnforthemedaltallies.Let'stidyitupusingthetidyrpackage,whichisloadedwithlibrary(tidyverse),oryoucanloaditseparatelywithlibrary(tidyr).Wecantidythedataverysimplyusingthegather()function.Thegather()functiontakesadataframeasanargument,alongwithkeyandvaluecolumnnames(whichyoucansettowhatyoulike),andthecolumnnamesthatyouwishtobegathered(allothercolumnswillbeduplicatedasappropriate).Inthiscase,wewanttogathereverythingexceptthecountry,sowecanuse-variableNametoindicatethatwewishtogathereverythingexceptvariableName.Thefinalcodelookslikethefollowing:

library(tidyr)

gather(medals,key=Type,value=Medals,-country)

Thishasanicetidyoutput,asshowninthefollowingscreenshot:

Cecin'estpasunepipeNowthatwe'vecoveredtidydata,thereisonemoreconceptthatisverycommoninthetidyversethatweshoulddiscuss.Thisisthepipe(%>%)fromthemagrittrpackage.ThisissimilartotheUnixpipe,andittakestheleft-handsideofthepipeandappliestheright-handsidefunctiontoit.Takethefollowingcode:

mpg%>%summary()

Theprecedingcodeisequivalenttothefollowingcode:

summary(mpg)

Asanotherexample,lookatthefollowingcode:

gapminder%>%filter(year>1960)

Theprecedingcodeisequivalenttothefollowingcode:

filter(gapminder,year>1960)

Pipinggreatlyenhancesthereadabilityofcodethatrequiresseveralstepstoexecute.Takethefollowingcode:

x%>%f%>%g%>%h

Theprecedingcodeisequivalenttothefollowingcode:

h(g(f(x)))

Todemonstratewitharealexample,takethefollowingcode:

groupedData=gapminder%>%

filter(year>1960)%>%

group_by(continent,year)%>%

summarise(meanLife=mean(lifeExp))

Theprecedingcodeisequivalenttothefollowingcode:

summarise(

group_by(

filter(gapminder,year>1960),

continent,year),

meanLife=mean(lifeExp))

Hopefully,itshouldbeobviouswhichistheeasiertoreadofthetwo.

GapminderNowwe'velookedattidyingdata,let'shaveaquicklookatusingdplyrandggplottofilter,process,andplotsomedata.Inthissection,andthroughoutthisbook,we'regoingtobeusingtheGapminderdatathatwasmadefamousbyHansRoslingandtheGapminderfoundation.Anexcerptofthisdataisavailablefromthegapminderpackage,asassembledbyJennyBryan,anditcanbeinstalledandloadedverysimplyusinginstall.packages("gapminder");library(gapminder).Asthepackagedescriptionindicates,itincludes,foreachofthe142countriesthatareincluded,thevaluesforlifeexpectancy,GDPpercapita,andpopulation,everyfiveyears,from1952to2007.

Inordertopreparethedataforplotting,wewillmakeuseofdplyr,asshowninthefollowingcode:

groupedData=gapminder%>%

filter(year>1960)%>%

group_by(continent,year)%>%

summarise(meanLife=mean(lifeExp))

Thissingleblockofcode,allexecutedinoneline,producesadataframesuitableforplotting,anduseschainingtoenhancethesimplicityofthecode.Threeseparatedataoperations,filter(),group_by(),andsummarise(),areallused,withtheresultsfromeachbeingsenttothenextinstructionusingthe%>%operator.Thethreeinstructionscarryoutthefollowingtasks:

filter():Thisissimilartosubset().Thisoperationonlykeepsrowsthatmeetcertainrequirements—inthiscase,yearsbeyond1960.group_by():Thisallowsoperationstobecarriedoutonsubsetsofdatapoints—inthiscase,eachcontinentforeachoftheyearswithinthedataset.summarise():Thiscarriesoutsummaryfunctions,suchassumandmean,onseveraldatapoints—inthiscasethemeanlifeexpectancywithineachcontinentandavailableyear.

So,tosummarize,theprecedingcodefiltersthedatatoselectonlyyearsbeyond1960,groupsitbythecontinentandyear,andfindsthemeanlifeexpectancywithinthatcontinentoryear.Printingtheoutputfromtheprecedingcodeyieldsthefollowing:

Asyoucansee,theoutputisatibble,whichhasaniceprintmethodthatonlyprintsthefirstseveralrows.Tibblesareverysimilartodataframes,andareoftenproducedbydefaultinsteadofdataframeswithinthetidyverse.Therearesomenicedifferences,buttheyarefairlyinterchangeablewithdataframesforourpurposes,sowewillnotgetsidetrackedbythedifferenceshere.

Nowwehavementionedtibbles,youcanseethatthedataframeisanicesummaryofthemeanlifeexpectancybyyearandcontinent.

AsimpleShiny-enabledlineplotWehavealreadyseenhoweasyitistodrawlineplotsinggplot2.Let'saddsomeShinymagictoalineplotnow.ThiscanbeachievedveryeasilyindeedinRStudiobyjustnavigatingtoFile|NewFile|RMarkdown|NewShinydocumentandinstallingthedependencieswhenprompted.Onceatitlehasbeenadded,thiswillcreateanewRMarkdowndocumentwithinteractiveShinyelements.RMarkdownisanextensionofMarkdown(seedaringfireball.net/projects/markdown/),whichisitselfamarkuplanguage,suchasHTMLorLaTeX,whichisdesignedtobeeasytouseandread.RMarkdownallowsRcodechunkstoberunwithinaMarkdowndocument,whichrendersthecontentsdynamic.ThereismoreinformationaboutMarkdownandRMarkdowninChapter2,ShinyFirstSteps.ThissectiongivesaveryrapidintroductiontothetypeofresultspossibleusingShiny-enabledRMarkdowndocuments.

FormoredetailsonhowtoruninteractivedocumentsoutsideRStudio,refertogoo.gl/Ngubdo.Bydefault,anewdocumentwillhaveplaceholdercodeinitwhichyoucanruntodemonstratethefunctionality.Wewilladdthefollowing:

---

title:"Gapminder"

author:"ChrisBeeley"

output:html_document

runtime:shiny

---

```{r,echo=FALSE,message=FALSE}

library(tidyverse)

library(gapminder)

inputPanel(

checkboxInput("linear",label="Addtrendline?",value=FALSE)

)

#drawtheplot

renderPlot({

thePlot=gapminder%>%

filter(year>1960)%>%

group_by(continent,year)%>%

summarise(meanLife=mean(lifeExp))%>%

ggplot(aes(x=year,y=meanLife,

group=continent,colour=continent))+

geom_line()

if(input$linear){

thePlot=thePlot+geom_smooth(method="lm")

}

print(thePlot)

})

```

Thefirstpartbetweenthe---istheYAML,whichperformsthesetupofthedocument.InthecaseofproducingthisdocumentwithinRStudio,thiswillalreadybepopulatedforyou.

Rchunksaremarkedasshown,with```{r}tobeginand```toclose.Theechoandmessageargumentsareoptional—weusethemheretosuppressoutputoftheactualcodeandanymessagesfromRinthefinaldocument.

We'llgointomoredetailabouthowShinyinputsandoutputsaresetuplateroninthebook.Fornow,justknowthattheinputissetupwithacalltocheckboxInput(),which,asthenamesuggests,createsacheckbox.It'sgivenaname("linear")andalabeltodisplaytotheuser("Addtrendline?").Theoutput,beingaplot,iswrappedinrenderPlot().Youcanseethecheckboxvaluebeingaccessedontheif(input$linear){...}line.Shinyinputsarealwaysaccessedwithinput$andthentheirname,so,inthiscase,input$linear.Whentheboxisclicked—thatis,whenitequalsTRUE—wecanseeatrendlinebeingaddedwithgeom_smooth().We'llgointomoredetailabouthowallofthiscodeworkslaterinthebook;thisisafirstlooksothatyoucanstarttoseehowdifferenttasksarecarriedoutusingRandShiny.

You'llhaveaninteractivegraphiconceyourunthedocument(clickonRundocumentinRStudioorusetherun()commandfromthermarkdownpackage),asshowninthefollowingscreenshot:

Asyoucansee,Shinyallowsustoturnonoroffatrendlinecourtesyofgeom_smooth()fromtheggplot2package.

InstallingShinyandrunningtheexamplesShinycanbeinstalledusingstandardpackagemanagementfunctions,asdescribedpreviously(usingtheGUIorrunninginstall.packages("shiny")attheconsole).

Let'srunsomeoftheexamples,asshowninthefollowingcode:

>library(shiny)

>runExample("01_hello")

Yourwebbrowsershouldlaunchanddisplaythefollowingscreenshot(notethatIclickedontheshowbelowbuttonontheapptobetterfitthegraphiconthepage):

Thegraphshowsthefrequencyofasetofrandomnumbersdrawnfromastatisticaldistributionknownasthenormaldistribution,andthesliderallowsuserstoselectthesizeofthedraw,from0to1,000.Youwillnotethatwhenyoumovetheslider,thegraphupdatesautomatically.ThisisafundamentalfeatureofShiny,whichmakesuseofareactiveprogrammingparadigm.

Thisisatypeofprogrammingthatusesreactiveexpressions,whichkeeptrackofthevaluesonwhichtheyarebased.Thesevaluescanchange(theyareknownasreactivevalues)andupdatethemselveswheneveranyoftheirreactivevalueschange.So,inthisexample,thefunctionthatgeneratestherandomdataanddrawsthegraphisareactiveexpression,andthenumberofrandomdrawsthatitmakesisareactivevalueonwhichtheexpressiondepends.So,wheneverthenumberofdrawschanges,thefunctionre-executes.

Youcanfindmoreinformationaboutthisexample,aswellasacomprehensivetutorialforShiny,atshiny.rstudio.com/tutorial/.

Also,notethelayoutandstyleofthewebpage.ShinyisbasedbydefaultontheBootstraptheme(seegetbootstrap.com/).However,youarenotlimitedbythestylingatall,andcanbuildthewholeUIusingamixofHTML,CSS,andShinycode.

Let'slookataninterfacethatismadewithbare-bonesHTMLandShiny.Notethatinthisandallsubsequentexamples,we'regoingtoassumethatyourunlibrary(shiny)atthebeginningofeachsession.Youdon'thavetorunitbeforeeachexample,exceptatthebeginningofeachRsession.So,ifyouhaveclosedRandhavecomeback,thenrunitontheconsole.Ifyoucan'tremember,runitagaintobesure,asfollows:

library(shiny)

runExample("08_html")

Andhereitis,inallitscustomizableglory:

Now,thereareafewdifferentstatisticaldistributionstopickfromandadifferentmethodofselectingthenumberofobservations.Bynow,youshouldbelookingatthewebpageandimaginingallthepossibilitiestherearetoproduceyourowninteractivedatasummariesandstylethemjusthowyouwant,quicklyandsimply.Bytheendofthenextchapter,you'llhavemadeyourownapplicationwiththedefaultUI,andbytheendofthebook,you'llhavecompletecontroloverthestylingandbeponderingwhereelseyoucango.

TherearelotsofotherexamplesincludedwiththeShinylibrary;justtyperunExample()intheconsoletobeprovidedwithalist.

Toseesomereallypowerfulandwell-featuredShinyapplications,takealookattheshowcaseatshiny.rstudio.com/gallery/.

SummaryInthischapter,weinstalledRandexploredthedifferentoptionsforGUIsandIDEs,andlookedatsomeexamplesofthepowerofR.WesawhowRmakesiteasytomanageandreformatdataandproducebeautifulplotswithafewlinesofcode.YoualsolearnedalittleaboutthecodingconventionsanddatastructuresofR.Wesawhowtoformatadatasetandproduceaninteractiveplotinadocumentquicklyandeasily.Finally,weinstalledShiny,rantheexamplesincludedinthepackage,andwereintroducedtoacoupleofbasicconceptsinShiny.

Inthenextchapter,wewillgoontobuildourownShinyapplicationusingthedefaultUI.

ShinyFirstStepsInthepreviouschapter,welookedatR,learnedsomeofitsbasicsyntax,andsawsomeexamplesofthepowerandflexibilitythatRandShinyoffer.ThischapterintroducesthebasicsofShiny.Inthischapter,we'regoingtobuildourownapplicationtointeractivelyexploretheGapminderdatadescribedinthepreviouschapter.Wewillcoverthefollowingtopics:

ThetypesofShinyapplication—RMarkdown,single-file,two-file,ShinygadgetsInteractiveShinydocumentsinRMarkdownSingle-fileShinyapplicationsTwo-fileShinyapplicationsAminimalexampleofafullShinyapplicationWidgettypesThebasicstructureofaShinyprogramTheselectionofsimpleinputwidgets(checkboxesandcombobuttons)Theselectionofsimpleoutputtypes(renderingplotsandmaps,andreturningtext)Theselectionofsimplelayouttypes(pagewithsidebarandtabbedoutputpanel)ReactiveobjectsAbriefsummaryofmoreadvancedlayoutfeatures

TypesofShinyapplicationInthefirsteditionofthisbook,whichwasbasedonShiny0.6,wedescribedonlytwotypesofapplication.First,afairlysimpleBootstrap-themedinterfacewithinputwidgetsdowntheleftandoutput(asinglepageoratabbedoutputwindow)ontheright.Thesecondtypeconsistedofcustom-builtwebpageswiththeirownHTMLandCSSfiles.Shinyhasdevelopedquiteabitsincethen,andthereareactuallymanytypesofShinyapplicationandmanywaysofbuildingthem.Theseareasfollows:

InteractivemarkdowndocumentswithShinywidgetsembeddedShinyapplications(defaultCSS,writtenentirelyinR)Webpages(forexample,customCSS,HTML,andJavaScript)ShinygadgetsFlexdashboards

Inthischapter,wewillbeconsideringthefirsttwo:interactivedocumentsandfullapplications.Chapter3,IntegratingShinywithHTML,willcoverhowtobuildyourownwebpagescontainingShinyapplications.ShinygadgetsaretoolsforRprogrammersratherthanforendusers,andtheyallowRuserstoexploredataandgenerategraphicsandsummarieswithShinyinterfaces.TheywillbedescribedfurtherinChapter7,PowerShiny.FlexdashboardswillbelookedatinChapter6,Dashboards.

InteractiveShinydocumentsinRMarkdownAswesawinthepreviouschapter,interactivedocumentscanbemadeveryeasilyusingRMarkdowninRStudio.EvenifyouarenotusingRStudio,itisasimplematterofwritinganRMarkdownfilewithShinycodeinit.IfyoudonotuseRStudio,youwillneedanup-to-dateversionofPandoc(theversioninmanyLinuxdistributionsisnotrecentenough).FormoreoninstallingPandoconLinux,Windows,orMac,gotopandoc.org/installing.html.

RMarkdownisbasedonMarkdown,whichisamarkuplanguagedesignedtobeeasilyconvertedintoHTML,butwhichlooksmuchmorelikeanaturaldocumentinitsrawformat,asopposedtoHTMLorothermarkuplanguages(suchasLaTeX),whichhavemoreprominentandstrange-lookingtags.Forexample,theMarkdownsyntaxforabulletedlistisasfollows:

*Firstbullet

*Secondbullet

*Thirdbullet

TheHTMLequivalentisasfollows:

<ul>

<li>Firstbullet</li>

<li>Secondbullet</li>

<li>Thirdbullet</li>

</ul>

TaggingmarkupinLaTeXisevenmoreverbose.RMarkdownusesMarkdownconventions,butallowscodechunksofRtoberunwithinthedocument,andallowstextandgraphicaloutputtobegeneratedfromthosechunks.CoupledwithPandoc(theSwissArmyknifeofdocumentrendering),MarkdownandRMarkdowncanberenderedintomanyformats,includingXHTML,HTML,epub,LaTeX,.pdf,.doc,.docx,and.odt.

RMarkdownwithShinygoesonestepfurtherandallowsuserstointeractwiththedocumentonawebpage.

Let'sbuildaminimalexample.IfyouareusingRStudio,youwillbegivenaboilerplateShinyMarkdowndocumenttoworkfrom,whichmakesthingsabiteasier,butherewe'llignorethatandbuilditfromscratch.Thecodeisavailableatgoo.gl/N7Qkv8.

Let'sgothrougheachpartofthedocument.NavigatetoFile|NewFile|RMarkdown|Newdocumentandenterthefollowingcode:

#ExampleRMarkdowndocument

Thisisaninteractivedocumentwrittenin*markdown*.Asyoucanseeitiseasytoinclude:

1.Orderedlists

2.*Italics*

3.**Boldtype**

4.Linksto[Documentation](http://example.com/)

##Thisisheadingtwo

Perhapsthisintroducesthevisualisationbelow.

ThisisthedocumentpartoftheShinydocument,writteninMarkdown.Thefollowingconventionscanbenoted:

The#characterisusedforheadingsatlevel1,and##forheadingsatlevel2Numbered(ordered)listsaredesignatedwith1,2,andsoonItalicsaregivenwith*singleasterisks*andaboldformatisgivenwith**doubleasterisks**

Linksarerepresentedusingtheformatof(http://example.com/)

Nextfollowsacodechunk,beginningwith```{r}andendingwith```.Theecho=FALSEargumentisaddedtothechunktopreventtheprintingoftheRcode.Youwillusuallywanttodothis,butnotoneveryoccasion—forexample,whenproducingateachingresource:

```{r,echo=FALSE}sliderInput("sampleSize",label="Sizeofsample",min=10,max=100,value=50,step=1)renderPlot({hist(runif(input$sampleSize))})```

Straightaway,wecanseesomeofthedesignprinciplesinShinyapplications.Wecanseetheseparationofinputcode,sliderInput(),andoutputcode,renderPlot().ThesliderInput()function,asthenamesuggests,definesaninputwidgetthatallowstheusertoselectfromarangeofnumericvalues,inthiscase,between10and100,withastartingvalueof50andastepincreaseof1.TherenderPlot()functionproducesareactiveplotusingwhateverfunctionsitfindswithinitself(inthiscase,thegraphicalfunctionhist(),whichdrawsahistogram).

AswealreadycoveredinChapter1,BeginningRandShiny,reactiveoutputschangewhentheirinputschange.Therunif(n)functionproducesnrandomnumbersbetween0and1(withdefaultarguments).Aswecanseeinthiscase,nisgivenbyinput$sampleSize.InputsareaccessedverysimplyinShinyinthisformat;youcanseethatwenamedtheinputsampleSizewithinthesliderInput()function,whichplacestheselectedvaluefromthewidgetininput$sampleSize(namingitmyInputplacesthevalueininput$myInput).

Therefore,runif()generatesrandomnumbersinthequantityofinput$sampleSize,hist()plotsthemwithahistogram,andrenderPlot({})tellsShinythattheoutputwithinisreactiveandshouldbeupdatedwheneveritsinputs(inthiscase,justinput$sampleSize)change.

Thefinalresultwilllooklikethefollowingscreenshot:

That'sit!YoumadeyourfirstShinyapplication.It'sthateasy.Now,let'sconsiderbuildingfullyfledgedapplications,startingwithaminimalexampleandbuildingupfromthere.

AminimalexampleofafullShinyapplicationThefirstthingtonoteisthatShinyprogramsaretheeasiesttobuildandunderstandusingtwoscripts,whicharekeptwithinthesamefolder.Theyshouldbenamedserver.Randui.R.

Theui.RoftheminimalexampleTheui.RfileisadescriptionoftheUI,andisoftentheshortestandsimplestpartofaShinyapplication.Inthefollowingcode,notetheuseofthe#character,whichmarkslinesofcodeascommentsthatwillnotberun,butwhichareforthebenefitofthehumansproducingthecode:

fluidPage(#Line1

titlePanel("Minimalapplication"),#Line2

sidebarLayout(#Line3

sidebarPanel(#Line4

textInput(inputId="comment",#Line5

label="Saysomething?",#Line6

value=""#Line7

)),#Line8

mainPanel(#Line9

h3("Thisisyousayingit"),#Line10

textOutput("textDisplay")#Line11

)

)

)

Thefollowinglistisanexplanationofeachline:

Line1:FlexiblelayoutfunctionLine2:TitleLine3:Standardinputsonthesidebar;outputsinthemainarealayoutLine4:ThesidebarlayoutfunctionLine5:Givethenameoftheinputelement;thiswillbepassedtoserver.RLine6:ThedisplaylabelforthevariableLine7:TheinitialvalueLine9:TheoutputpanelLine10:ThetitledrawnwiththeHTMLhelperfunctionLine11:TheoutputtextwiththeID,textDisplay,asdefinedinserver.R

TorunaShinyprogramonyourlocalmachine,youjustneedtodothefollowing:

1. Makesurethatserver.Randui.Rareinthesamefolder2. MakethisfolderR'sworkingdirectory(usingthesetwd()command—for

example,setwd("~/shinyFiles/minimalExample"),orwiththeSession>Setworkingdirectorymenuoption)

3. LoadtheShinypackagewiththelibrary(shiny)command4. TyperunApp()intheconsole(or,inRstudio,clickRunappjustabovethe

codewindow)

UsingrunApp()withthenameofadirectorywithinworksjustaswell—forexample,runApp("~/shinyFiles/minimalExample").SoinsteadofsettingtheworkingdirectorytothelocationofyourapplicationandthenusingrunApp()separately,thewholethingcansimplybecarriedoutinoneinstruction,passingrunApp()inthenameofthedirectorydirectly.Justrememberthatitisadirectoryandnotafilethatyouneedtopointto.

Thefirstinstruction,fluidPage(...,tellsShinythatweareusingafluidpagelayout.ThisisaveryflexiblelayoutfunctionwhosefunctionalitywewillexplorefurtherinChapter4,MasteringShiny'sUIFunctions.Next,thetitleoftheapplicationisdefinedverysimplyusingthetitlePanel()function.Thenfollowsthemainlayoutinstruction;inthiscase,wearegoingtousethesimplestUIlayout,sidebarLayout(),whichplacesinputsontheleft(orright,optionally)andthemainoutputsectioninthemiddle.AlloftheUIelementsaredefinedwithinthesidebarLayout()function.

ThenexttwoinstructionsperformthemainUIsetup,withsidebarPanel()settinguptheapplicationcontrolsandmainPanel()settinguptheoutputarea.ThesidebarPanel()phrasewillusuallycontainalloftheinputwidgets;inthiscase,thereisonlyone:textInput().ThetextInput()widgetisasimplewidgetthatcollectstextfromatextboxthatuserscaninteractwithusingthekeyboard.Theargumentsareprettytypicalamongmostofthewidgets,andareasfollows:

inputId:Thisargumentnamesthevariable,soitcanbereferredtointheserver.Rfilelabel:Thisargumentgivesalabeltoattachtotheinput,sousersknowwhatitdoesvalue:Thisargumentgivestheinitialvaluetothewidgetwhenitissetup;allthewidgetshavesensibledefaultsforthisargument—inthiscase,itisablankstring,""

Whenyoustartout,itcanbeagoodideatospelloutthedefaultargumentsinyourcodeuntilyougetusedtowhichfunctioncontainswhicharguments.Italsomakesyourcodemorereadableandremindsyouwhatthereturnvalueofthe

functionis(forexample,value=TRUEwouldsuggestaBooleanreturn).

ThefinalfunctionismainPanel(),whichsetsuptheoutputwindow.YoucanseethatIusedoneoftheHTMLhelperfunctionstomakealittletitle,h3("...").Therearemanyofthesehelperfunctionsincluded,andtheyareincrediblyusefulforsituationswhereyoueitherdon'twanttodotoomuchstylingwithHTMLandCSSyourselfordon'tknowhow.Let'sjuststopveryquicklytolookatafewexamples.

AnoteonHTMLhelperfunctionsThereareseveralHTMLhelperfunctionsthataredesignedtogenerateHTMLtogostraightonthepage;type?pintheconsoleforthecompletelist.ThesefunctionsallowyoutomarkuptextinHTMLusingRcode—forexample,h3("Heading3")willproduce<h3>Heading3</h3>,p("Paragraph")willproduce<p>Paragraph</p>,andsoon.

TheHTMLtagsthatwillbeavailableusingthisfunctioninclude<br>,<code>,<div>,<em>,<h1>,<img>,<p>,<pre>,and<span>.Evenmoretagsareavailablethroughtheuseofthetags()function.ThereismoreonShinyandHTMLinChapter3,IntegratingShinywithHTML,andafulllistoftagsandotherhelpisavailableinthedocumentationatshiny.rstudio.com/articles/html-tags.html.

ThefinishedinterfaceTheotherelementthatgoesinmainPanel()isanareatohandlereactivetextthatisgeneratedwithintheserver.Rfile—thatis,acalltotextOutput()withthenameoftheoutputasdefinedinserver.R—inthiscase,textDisplay.

Thefinishedinterfacelookssimilartothefollowingscreenshot:

Ifyou'regettingalittlebitlost,don'tworry.Basically,Shinyisjustsettingupaframeworkofnamedinputandoutputelements;theinputelementsaredefinedinui.Randprocessedbyserver.R,whichthensendsthembacktoui.R,whichknowswheretheyallgoandwhattypesofoutputtheyare.

Theserver.RoftheminimalexampleLet'snowlookatserver.R,whereitshouldallbecomeclear.Lookatthefollowingcode:

function(input,output){#serverisdefinedhereoutput$textDisplay=renderText({#assigntooutput$textDisplay

paste0("Yousaid'",input$comment,#fromtextinput

"'.Thereare",nchar(input$comment),

"charactersinthis.")

})

}

Wedefinethereactivecomponentsoftheapplicationwithinfunction(input,output){...}.Onthewhole,twotypesofthingsgoinhere.Reactiveobjects(forexample,data)aredefined,whicharethenpassedaroundasneeded(forexample,todifferentoutputinstructions),andoutputsaredefined,suchasgraphs.Thissimpleexamplecontainsonlythelatter.We'llseeanexampleofthefirsttypeinthenextexample.

Anoutputelementisdefinednextwithoutput$textDsiplay=renderText({..}).Thisinstructiondoestwobasicthings.First,itgivestheoutputaname(textDisplay)sothatitcanbereferencedinui.R(youcanseeitinthelastpartofui.R).Second,ittellsShinythatthecontentcontainedwithinisreactive(thatis,itwillbeupdatedwhenitsinputschange)andittakestheformoftext.WewillcoveradvancedconceptsinreactiveprogrammingwithShinyinalaterchapter.TherearemanyexcellentillustrationsofreactiveprogrammingattheShinytutorialpages,availableatrstudio.github.io/shiny/tutorial/#reactivity-overview.

Theactualprocessingisverysimpleinthisexample.Inputsarereadfromui.Rbytheuseofinput$...,sotheelementnamedinui.Rascomment(goandhavealookatui.Rnowtofindit)isreferencedwithinput$comment.

Thewholecommandusespaste0()tolinkstringswithnospaces(equivalenttopaste(...,sep="")),picksupthetexttheuserinputtedwithinput$comment,andprintsit,alongwiththenumberofcharacterswithinit(nchar())andsomeexplanatorytext.

That'sit!YourfirstShinyapplicationisready.Thefullcodecanbefoundhere,h

ttps://gist.github.com/ChrisBeeley/4202605cf2e64b4f609e.Usingtheseverysimplebuildingblocks,youcanactuallymakesomereallyusefulandengagingapplications.

TheprogramstructureSincethefirsteditionofthisbook,asignificantchangehastakenplacewithregardstohowShinyapplicationsarestructured.Anewfeaturehasbeenadded,givingustheabilitytoplacethemallwithinonecodefile.Thisismostusefulwhenbuildingsmalldemonstrationsorexamplesforotherusers,whocanjustpastethewholecodefileintotheconsoleandhavetheapplicationrunautomatically.Inordertomakeuseofthisfunctionality,justcombinethecodefromserver.Randui.R,asshowninthefollowingexample:

library(shiny)

server<-function(input,output){

#contentsofserver.Rfile

}

ui<-fluidPage(#orotherlayoutfunction

#contentsofui.Rfile

)

shinyApp(ui=ui,server=server)

Thisisusefulneitherforlargeapplications,norforthepurposesofexplainingthefunctionsofparticularpartsofcodewithinthisbook,soweshallignoreitfromnowon.Justbeawarethatit'spossible;youmaywellcomeacrossitonforums,andyoumaywishtocontributesomesmallexamplesyourself.

AnoptionalexerciseIfyouwanttohaveapracticebeforewemoveon,taketheexistingcodeandmodifyitsothattheoutputisaplotofauser-definednumberofobservations,withthetextasthetitleoftheplot.Theplotcallshouldlooklikethefollowing:

hist(rnorm(XXXX),main="YYYY")

Intheprecedinglineofcode,XXXXisanumbertakenfromafunctioninui.Rthatyouwilladd(sliderInput()ornumericInput())andYYYYisthetextoutputwealreadyusedintheminimalexample.YouwillalsoneedtomakeuseofrenderPlot();type?renderPlotintheconsoleformoredetails.

Sofarinthischapter,wehavelookedataminimalexampleandlearnedaboutthebasiccommandsthatgointheserver.Randui.Rfiles.Thinkingaboutwhatwe'vedoneintermsofreactivity,theui.Rfiledefinesareactivevalue,input$comment.Theserver.Rfiledefinesareactiveexpression,renderText().Itdependsoninput$comment.

NotethatthisdependenceisdefinedautomaticallybyShiny.TherenderText()expressionusesanoutputfrominput$comment,soShinyautomaticallyconnectsthem.Wheneverinput$commentchanges,renderText()willautomaticallyrunwiththenewvalue.TheoptionalexercisegavetworeactivevaluestotherenderPlot()call,andso,whenevereitherchanges,renderPlot()willbererun.Intherestofthischapter,wewilllookatanapplicationthatusessomeslightlymoreadvancedreactivityconcepts,andbytheendofthebook,wewillhavecoveredallthecapabilitiesthatShinyoffersandwhentousethem.

EmbeddingapplicationsindocumentsTobrieflyreturntothesubjectofinteractivedocuments,itisworthnotingthatitispossibletoembedentireShinyapplicationswithininteractivedocumentsratherthanhavingtheratherstripped-downfunctionalitythatweembeddedwithinadocumentearlierinthechapter.Justincludealinktothedirectorythatholdstheapplication,likethis:

```{r,echo=FALSE}

shinyAppDir(

"~/myApps/thisApplication",

)

```

Formoreinformationaboutembedding,type?shinyAppintheconsole.

WidgettypesBeforewemoveontoamoreadvancedapplication,let'shavealookatthemainwidgetsthatyouwillmakeuseofwithinShiny.I'vebuiltaShinyapplicationthatwillshowyouwhattheyalllooklike,aswellastheiroutputsandthetypeofdatatheyreturn.Torunit,justenterthefollowingcommand:

>library(shiny)

runGist(6571951)

Thisisoneoftheseveralbuilt-infunctionsofShinythatallowyoutoruncodehostedontheinternet.DetailsaboutsharingyourowncreationsinotherwaysarediscussedinChapter9,Persistence,Storage,andSharing.Thefinishedapplicationlookslikethefollowingscreenshot:

Youcanseethefunctionnames(checkboxGroupInputandcheckboxInput)asnumberedentriesontheleft-handsideofthepanel;formoredetails,justtype?checkboxGroupInputintotheconsole.

Ifyou'recuriousaboutthecode,it'savailableatgist.github.com/ChrisBeeley/6571951.

TheGapminderapplicationNowthatwe'vegotthebasics,let'sbuildafullapplication.Beforeweproceed,notethatwewillneedtoinstallafewpackages—tidyverse,gapminder,leaflet,andggmap.EachcanbeinstalledfromCRAN(theofficialRpackagerepository)usingthecodephrasesinstall.packages("tidyverse"),install.packages("gapminder"),andsoon.Wewillnotinstallggmapthisway,though.Atthetimeofwriting,thereisabugintheCRANversion.We'llinstallthedevversioninstead,asshowninthefollowingcode:

install.packages("devtools")

library(devtools)

devtools::install_github("dkahle/ggmap")

Theapplicationisprettysimpletogetusstarted,butitillustratesseveralimportantmethodsandprinciplesinShiny.Itfeaturestabbedoutput,whichallowstheusertoselectdifferentinputsorgroups,whichareeachkeptonaseparatetab.ItfeaturesthestandardShinylayout—thesidebarlayout—withinputsattheleftandoutputsinthemainsection.Thethreetabsgiveatextualsummary,alinegraphshowinglifeexpectancyovertime,andamapwithcirclesscaledtothelifeexpectancyineachcountry.Theapplicationlookslikethefollowingscreenshot:

TheUIIfyoucan,downloadandrunthecodeanddatafromgithub.com/ChrisBeeley/gapminder(thedatagoesinthesamefolderasthecode)soyoucangetanideaofwhateverythingdoes.Ifyouwanttoruntheprogramwithoutcopyingtheactualdataandcodetoyourcomputer(copyingdataandcodeispreferablesothatyoucanplaywithit),justuseanotherfunctiontoshareandrunapplications(wewilldiscussthisinChapter5,EasyJavaScriptandCustomJavaScriptFunctions),asshowninthefollowingcode:

runGitHub("gapminder","ChrisBeeley")

AsinmanyShinyapplications,ui.Risbyfarthesimplerofthetwocodefiles,andisasfollows:

library(shiny)

library(leaflet)

fluidPage(

titlePanel("Gapminder"),

Thefirstthingthatwedoisloadtheleaflet()package.Theleaflet()packageisusedfordrawinginteractivemaps.We'lldiscussitindetaillater.Fornow,justnotethatitisnecessarytoloaditintheUIinordertoaccessaspecialoutputfunctionthatdoesn'texistwithinShiny—leafletOutput().ThewholeinterfaceiswrappedinfluidPage().Thisistrueofmost,butnotall,Shinyapplications.WewilllookindetailatthebasictypesofShinypageandsetupinChapter4,MasteringShiny'sUIFunctions.Itperformsthebasicsetupofthepage,makingitresponsiveandensuringthatitlooksgoodondifferentlysizedbrowsers.ThereismoredetailonthisfunctioninChapter4,MasteringShiny'sUIFunctions.ThetitlePanel()functionisusedtogivetheapplicationanicebigtitle.

ThenextsectionshowsthesetupofthestandardlayoutofaShinyapplication.Simplified,itlookslikethefollowingcode,withsidebarPanel()definingtheinputsontheleftandmainPanel()theinputsontheright,allwrappedinsidebarLayout():

sidebarLayout(

sidebarPanel(

#inputcontrolsinhere

),

mainPanel(

#outputshere

)

Donotethatkeepingtheinputsontheleftandtheoutputsontherightisthetypicallayout,butShinyistotallyflexible.Youcankeepsomeinputsontherightifyouwish,orevenoutputsontheleft.ThisisjusttheusualsetupthatyouwillseeinasimpleShinyapplication.

WithinsidebarPanel(),wefindtwoinputs,sliderInput()andcheckboxInput(),asshowninthefollowingcode:

sliderInput(inputId="year",

label="Yearsincluded",

min=1952,

max=2007,

value=c(1952,2007),

sep="",

step=5

),

checkboxInput("linear",label="Addtrendline?",value=FALSE)

ThesliderInput()functionallowsyourusertoselectanumber,orarange,usingaslider.Inthiscase,theywillbeselectingarange,therangeofyearsthattheyareinterestedinforthetextsummaryandthetimeseriesgraph.Wehavealreadyseenthefirsttwoarguments,andtheywillbecomeveryfamiliartoyou—inputId

givingtheinputanamesoitcanbereferredtoasinput$name(input$yearinthiscase)andlabel,whichgivesthecontrolanicefriendlylabelfortheusertoreadsotheycanunderstandtheapplication.Youcanseetheotherarguments,givingaminimum,amaximum,andaninitialvalue(inthiscase,two,todefinearange).Wecanoptionallydefinetheseparatortoseparatethethousandsinthenumbers—inthiscase,settingittonothinginordertostoptheyearsappearingas1,952,2,007,andsoon.Notetheuseofstep=5.Thisgivesthenumericgapbetweeneachnotchontheslider.IfitisleftasNULL,thenShinywillpicksomethingsensible.Weuse5herebecausetheGapminderdataissplitintofive-yearchunks.

ThecheckboxInput()functionverysimplygivesyouatickboxthatreturnsTRUEwhentickedandFALSEwhenunticked.Thisexampleincludesallthepossiblearguments,whichgivesitanameandlabelandselectstheinitialvalue.

Thisconcludestheinputs.Let'slookattheoutputpanel,asshowninthefollowingcode:

),#endofsidebarPanel()

mainPanel(

tabsetPanel(

tabPanel("Summary",textOutput("summary")),

tabPanel("Trend",plotOutput("trend")),

tabPanel("Map",leafletOutput("map"),

p("Mapdataisfromthemostrecentyearintheselectedrange;

radiusofcirclesisscaledtolifeexpectancy"))

)

)

ProbablythemostunfamiliarpartofthiscodeistheuseoftabsetPanel().Thisallowsmultipleframesofoutputtobeshownonthescreenandselectedbytheuser,asiscommoninGUIsthatsupporttabbedframes.Notethatprocessingisonlycarriedoutforthecurrentlyselectedtab;invisibletabsarenotupdatedbehindthescenes,butratherwhentheyaremadeactive.Thisisusefultoknowwheresomeoralltabsrequiresignificantdataprocessing.Thesetupisverysimple,withacalltotabsetPanel()containingseveralcallstotabPanel()inwhicheachofthetabsisdefinedwithaheadingandapieceofoutputasdefinedinserver.R.Asyoucansee,therearethreetypesofoutputgivenbythreedifferentoutputfunctions—text,shownbytextOutput();aplot,shownbyplotOutput();andamapproducedwiththeleafletpackageandshownwithleafletOutput()(moreonwhichlater).

DataprocessingAsyouwritemoreandmorecomplexprograms,it'stheserver.Rfilethatwillbecomethelargestbecausethisiswhereallthedataprocessingandoutputgoes,andisevenwheresomeofthefunctionsthathandleadvancedUIfeatureslive.Let'slookatthechunksinorderandtalkabouttheworkcarriedoutineachsection.

Thefirstchunkofcodelookslikethefollowing:

library(tidyverse)

library(gapminder)

library(leaflet)

library(ggmap)

Youcanseethepackagesthatweneedbeingloadedatthetop.Weloadthetidyverseforaccesstothingssuchasdplyrandggplot,formungingdataandplotting,respectively.Thegapminderpackageisusedtoloadasubsetofthegapminderdata.IthasbeenverykindlymungedandplacedonlineintheformofaCRANpackagebyJennyBryan.Wewilltalkmoreaboutthedatathatitmakesavailablelater.Theleafletpackage—which,aswementionedbefore,isusedfordrawingmaps—isloadednext.Finally,theggmappackageisloaded.Thiswillbeusedtoconvertcountrynamestolatitudeandlongitudeforplottingbyleaflet.

Thenextthingthatwedoismungeor,ifwealreadymungedit,loadthedata,asshowninthefollowingcode:

if(!file.exists("geocodedData.Rdata")){

mapData=gapminder%>%

mutate(country2=as.character(country))%>%

group_by(country)%>%

slice(1)%>%

mutate_geocode(country2,source="dsk")%>%

select(-country2)

mapData=left_join(gapminder,mapData)%>%

group_by(country)%>%

fill(lon)%>%

fill(lat)

save(mapData,file="geocodedData.Rdata")

}else{

load("geocodedData.Rdata")

}

I'mnotgoingtodistractfromShinybytalkingtoomuchaboutthiscode.Essentially,itcheckstoseewhetherthedataisalreadyintherelevantdirectory(whichitwillbeafteryou'verunitonce).Ifitis,itjustloadsthedata.Ifnot,itpreparesitbyproducingasmallerdatasetwithoneinstanceofeachcountryandgeocodingit(thatis,turningitintolatitudeandlongitude),thencombiningitwiththewholedataset(toputalltheyearsforeachcountrybackin),andfillingintheresultingmissinggeocodingsusingtheincrediblyusefulfill()functionofdplyr.Havingdoneallthat,itsavesthedatafornexttime(sincequeryingtheAPIforall142countriestakesquitealongtime).Don'tworrytoomuchifyoucan'tfollowthiscodeatthemoment;it'sreallytherejusttogetthedataontoyourcomputerinasimpleway.

It'sworthnotingthatdatainstructions—andindeedanyothercode—thatappearabovefunction(input,output){}areexecutedoncewhentheapplicationstartsandthenserveallinstancesoftheShinyapplication.Thismakesnodifferencewhenyou'redevelopingonalocalmachine,sincethecodewillstartfresheverytimeyourunit,butonceyoumoveyourcodetoaserver,itcanmakeabigdifference,sincethecodeisonlyrunonceforalltheusersandapplicationinstancesyouhave(untilyourestarttheShinyserver,whichmanagesconnectionstoyourapplicationsonaserver,ofcourse).Therefore,anyintensivedataorprocessingcallsarebestkeptinthissectiontoavoidyourusershavingtowaitalongtimefortheirapplicationtoload.

ReactiveobjectsTherestofthiscodeiswrappedinfunction(input,output){}.Thisisthereactivepartofyourapplication.Wewilltalkinmoredetailaboutreactiveprogramminglaterinthebook;fornow,let'sjustsaythatreactiveprogrammingisatypeofprogrammingwherewhentheinputschange,theoutputschange.

Thenextpieceofcodelookslikethis:

theData=reactive({

mapData%>%

filter(year>=input$year)

})

Thiscodedefinesareactiveobject.Upuntilnow,theserver.Rfilehasjustcontainedalistofoutputcommandsthatproducetheoutput,readytofilltheallocatedspacesinui.R.Here,we'reworkingalittledifferently.Sometimes,youwanttoprepareareactivedatasetonceandthenpassitaroundtheprogramasneeded.

Thismightbebecauseyouhavetabbedoutputwindowsthatusethesamedataset(asinthiscase),andyoudon'twanttowriteandmaintaincodethatpreparesthedataaccordingtothevaluesofreactiveinputswithinallthreefunctions.Thereareothertimeswhenyouwanttocontroltheprocessingofdatabecauseitistimeintensiveoritmightmakeanonlinequery(suchasinthecaseofaliveapplicationthatqueriesdataliveinresponsetoreactiveinputs).Thewaythatyoucantakemorecontroloverdataprocessingfromreactiveinputs,ratherthandistributingitthroughyouroutputcode,istousereactiveobjects.Areactiveobject,likeareactivefunction,changeswhenitsinputchanges.Unlikeareactivefunction,itdoesn'tdoanything,butisjustadataobject(dataframe,number,list,andsoon)thatcanbeaccessedbyotherfunctions.Crucially,whenitruns,itsoutputiscached.Thismeansthataslongasitsinputsdon'tchange,itwillnotrerunifitiscalledonagainbyadifferentpartofyourapplication.Thispreventsyourapplicationfromrunningthesamedataprocessingtasksrepeatedly.

Inthiscase,thedataprocessingisverysmall,sowe'renotreallysavinganytime

usingreactiveobjects;however,itisstillgoodpracticetousethembecause,aswejustmentioned,itmeansthatyouonlyhaveonedatafunctiontomaintainratherthanseveralscatteredbetweentheoutputs.

Let'shavealookatanexample:

theData=reactive({

mapData%>%

filter(year>=input$year[1],year<=input$year[2])

})

Thisfunction,verysimply,filtersthedatasothatitcontainsonlydatathatwasloggedbetweentheyearsselectedinsliderInput().Thefirstthingtonoteisthat,unlikepreviousexamples,wearenotmakingacall,suchasoutput$lineGraph<-renderPlot({...})oroutput$summaryText<-renderText({...}).Instead,wearemarkingwhateverisinsidethecallreactivebyenclosingitinreactive({...})andassigningit,verysimply,totheData.ThisgeneratesareactiveobjectnamedtheData.Thiscanbeaccessedbycallingthisfunction—thatis,byrunningtheData()(forthewholedataframe),ortheData()$variableName(foravariable),ortheData()[,2:10](forthesecondtothetenthvariable).NotethebracketsaftertheData.Moreinformationonreactiveobjects,whentousethem,andlotsofadviceaboutmanagingandcontrollingreactivityanddataprocessinginyourapplicationisgiveninChapter8,CodePatternsinShinyApplications.

OutputsFinally,wewilllookathowtheoutputsaredefined.Let'slookfirstatthecodethatproducesthefirsttabofoutput,whichisthetextualsummaryofthedata.

TextsummaryThetextsummaryfunctioniswrappedinrenderText().ThisletsShinyknowthatthisfunctionreturnstext,asshowninthefollowingcode:

output$summary=renderText({

paste0(input$year[2]-input$year[1],"yearsareselected.Thereare",

length(unique(theData()$country)),"countriesinthedatasetmeasuredat",

length(unique(theData()$year)),"occasions.")

})

Rememberthatthisoutputispickedupinui.RwiththetextOutput()function,whichtakesthe"summary"identifier,which,asyoucansee,isthenamegivenbytheoutput$summary=renderText({...})function.Thefunctionverysimplypastestogethersometextandsomevaluestakenfromtheapplication.

TrendgraphsThenextpartofthecodespecifiesthegraphofthetrendinlifeexpectancyusingggplot2.Let'slookateachpieceofcode:

#trend

output$trend=renderPlot({

thePlot=theData()%>%

group_by(continent,year)%>%

summarise(meanLife=mean(lifeExp))%>%

ggplot(aes(x=year,y=meanLife,group=continent,colour=continent))+

geom_line()+ggtitle("Graphtoshowlifeexpectancybycontinentovertime")

if(input$linear){

thePlot=thePlot+geom_smooth(method="lm")

}

print(thePlot)

})

Thefirstlinedefinestheoutputasareactiveplot.Thesecondinstructionuseschaineddplyrinstructions,aswesawinChapter1,BeginningRandShiny,firsttogroupthedatabycontinentandyear,andthentocalculatethemeanlifeexpectancyinthegroupsthatresult(inAfricaineachyear,inAmericaineachyear,andsoon).Thisisthensentontoaggplotinstructionforthegivenyearonthexaxis,meanlifeexpectancyontheyaxis,andthegroupings/colorsdefinedbythecontinent.NotethatbyassigningittothePlot,wedonotprintit,butmerelybegintobuilditup.

Thenextsectiontestsforthevalueofthesmoothingcheckbox,input$linear,andifitisTRUE,aregressionlineisaddedtotheplot.Therequirementtoprint()ggplotgraphicshasbeendroppedfromShiny(inthefirsteditionofthisbook,itwasnecessaryforyoutoprint()eachgraphic).Thisgraphicwillneedtobeprintedinanyenvironment,eventheconsole,becauseithasnotbeencalledwithggplot(),butmerelyassignedtothePlot.Normally,whenusingggplot()directlyinaShinysession,therewillbenoneedtoprint()theplot.

AmapusingleafletFinally,weaddamaptothelasttabusingtheleafletpackage.TheleafletpackageisanRinterfacetotheexcellentJavaScriptleafletpackage,whichcanbeusedtobuildawidevarietyofmapsfrommanydifferentsourcesandannotatethemwithdatainanumberofdifferentways.Formoredetailsontheleafletpackage,visitrstudio.github.io/leaflet/.Thecodeisrelativelysimpleandlookslikethefollowing:

output$map=renderLeaflet({#1

mapData%>%#2

filter(year==input$year[2])%>%#3

leaflet()%>%#4

addTiles()%>%#5

setView(lng=0,lat=0,zoom=2)%>%#6

addCircles(lng=~lon,lat=~lat,weight=1,#7

radius=~lifeExp*5000,#8

popup=~paste(country,lifeExp))#9

})

It'snotessentialthatyouunderstandthiscodeatthispoint,andwewillbemakinguseoftheleafletpackageintherestofthebook,butlet'slookatitlinebylinetogetanideaofhowitworks:

Line1:Thisdefinesoutput$mapascontainingaleafletmapsothatShinyknowshowtohandletheoutput.Line2:ThistellsthefunctiontousethemapDatathatwealreadyloadedrightatthetopofthefile(not,inthiscase,thereactivedatareturnedbymapData()).Line3:Thisfiltersthedatasothatonlythemostrecentdatagivenintheselectioncanbeselected.Line4:ThistellsRthatwewanttousealeaflet.Line5:Thisdrawsthebackgroundtothemap—lotsofdifferentmapsareavailable.See?addTilesformorehelponthisfunction.Line6:Thisdefineswhichbitofthemapwearelookingatandhowzoomedinweare.Thiswillfocusonlatitude0andlongitude0,withthemapzoomedmostofthewayout.Lines7to9:Theseaddtheactualdatapoints;here,youcanseethatwegivethelatitudeandlongitudeasone-sidedequations,reducetheweight(penwidth),andgivetheformulatodeterminetheradiusofthecircles(life

expectancywitha5,000scalersoitshowsattherightsize).Finally,wedefinethepopup,whichiswhatappearswhenyouclickeachcircle(inthiscase,thenameofthecountryandtheactuallifeexpectancy).

AdvancedlayoutfeaturesInthischapter,wehavecoveredthemostsimpleofthelayoutfeaturesinShinywiththehelpofthesidebarLayout(),mainPanel(),andtabsetPanel()functions.Inlaterchapters,wewillbuildlargerandmorecomplexapplications,includingdashboards,andmakeuseofmoreadvancedlayoutfeatures.Itisworthpausingherebrieflytotakeaquicklookattheothertypesoflayoutthatareavailablesothatyoucanthinkaboutthebestwaytoimplementyourownapplicationaswegothroughthenextcoupleofchapters.

ThereareessentiallytwomorebroadtypesoflayoutfunctionthatyoucanuseinShiny.ThefirstusesthelayoutfeaturesofBootstrapandallowsyoutopreciselydefinethelayoutofyourapplicationusingagridlayout.Essentially,BootstrapasksyoutodefinetheUIasaseriesofrows.Eachrowcanbefurthersubdividedintocolumnsofvaryingwidths.

Eachsetofcolumnsonarowhaswidthsthataddupto12.Inthisway,youcanquiteeasilyspecify,forexample,thefirstrowasconsistingofonecolumnofwidth12,andthenthesecondrowasconsistingoftwocolumns,oneofwidth2andoneofwidth10.Thiscreatesaheaderpanelacrossthetopofthescreen,andthenathinoneandathickonetwocolumnsbelow,whichyouarelikelytoputUIandoutputelementsin,respectively.Awholevarietyoflayoutsispossible,andnestingandoffsettingthecolumnsarebothpossible,whichmeansthatwiththerightcode,youcanbuildanygrid-basedlayoutyoucanthinkof.Wewilllookatthecodetoimplementcustomlayoutsinthiswayinmoredetailinlaterchapters.

Ifyoudon'twanttosetupyourUIinthatmuchdetail,Shinyprovideslotsofotherlayoutsthatcanbeveryeasilycalledtolayoutyourapplicationinaparticularway.ThesefunctionsincludenavbarPage(),navList(),verticalLayout(),andsplitLayout().WewilllookatallofthelayoutfunctionsinChapter4,MasteringShiny'sUIFunctions,butit'sworthnotingherethattherearelotsofdifferentwaystocontrolthelayoutofaShinyapplication.

SummaryInthischapter,wehavecoveredalotofground.We'veseenthatShinyapplicationsaregenerallymadeupoftwofiles:server.Randui.R.You'velearnedwhateachpartofthecodedoes,includingsettingupui.Rwiththepositionandtypeofinputsandoutputs,andsettingupserver.Rwiththedataprocessingfunctions,outputs,andanyreactiveobjectsthatarerequired.

Theoptionalexerciseshavegivenyouachancetoexperimentwiththecodefilesinthischapter,varyingtheoutputtypes,usingdifferentwidgets,andreviewingandadjustingtheirreturnvaluesasappropriate.You'velearnedaboutthedefaultlayoutinShiny,sidebarLayout(),aswellastheuseofmainPanel()andtabsetPanel().

You'vealsolearnedaboutreactiveobjectsandwhenyoumightusethem.There'smoreonfinelycontrollingreactivitylaterinthebook.

Inthenextchapter,you'regoingtolearnhowtointegrateShinywithyourowncontentusingHTMLandCSS.

IntegratingShinywithHTMLSo,webuiltourownapplicationtoexploretheGapminderdata.YoulearnedaboutthebasicsetupofaShinyapplicationandsawalotofthewidgets.Itwillbeimportanttorememberthisbasicstructurebecausewearegoingtocoveralotofdifferentterritoriesinthischapterand,asaconsequence,wewon'thaveasingleapplicationattheend,aswedidinthepreviouschapter,butlotsofbitsandpiecesthatyoucanusetostartbuildingyourowncontent.

Buildingoneapplicationwithallofthesedifferentconceptswouldcreateseveralpagesofcode,anditwouldbedifficulttounderstandwhichpartdoeswhat.Asyougothroughthechapter,youmightwanttorebuildtheGapminderapplication,oranotheroneofyourown(ifyouhaveone),usingeachoftheconcepts.Ifyoudothis,youwillhaveabeautifullystyledandinteractiveapplicationbytheendthatyoureallyunderstand.Or,youmightliketojustbrowsethroughandpickoutthethingsthatyouareparticularlyinterestedin;youshouldbeabletounderstandeachsectiononitsown.Let'sgetstartednow.

Inthischapter,wearegoingtocoverthefollowingareas:

AddingHTMLtonativeShinyapplicationsCustomizingShinyapplications,orwholewebpages,usingHTMLStylingyourShinyapplicationusingCSSIncorporatingShinycontentwithinanotherwebpageHTMLtemplates

RunningtheapplicationsandcodeForconvenience,Ihavegatheredtogetheralltheapplicationsinthischapter.Thelinktotheliveversions,aswellasthesourcecodeanddata,canbefoundonmywebsiteatchrisbeeley.net/website.Ifyoucan,runtheliveversionfirstandthenbrowsethecodeasyougothrougheachexample.

ShinyandHTMLItmightseemquiteintimidatingtocustomizetheHTMLinaShinyapplication,andyoumayfeelthatbygoingunderthehood,itwouldbeeasytobreaktheapplicationorruinthestyling.YoumaynotwanttobotherrewritingeverywidgetandoutputinHTMLjusttomakeoneminorchangetotheinterface.

Infact,Shinyisveryaccommodating,andyouwillfindthatitwillquitehappilyacceptamixofShinycodeandHTMLcodeproducedbyyouusingShinyhelperfunctionsandtherawHTML,alsowrittenbyyou.So,youcanstylejustonebuttonorcompletelybuildtheinterfacefromscratchandintegrateitwithsomeothercontent.I'llshowyouallofthesemethodsandgivesomehintsaboutthetypeofthingsyoumightliketodowiththem.Let'sstartsimplebyincludingsomecustomHTMLinanotherwisevanillaShinyapplication.

CustomHTMLlinksinShinyWewillnowmakealittletoyapplicationthatshowsthelifeexpectancyovertimeforthreedifferentcountries,andthatgivesalinktotheWikipediapageforeach.It'snotreallydesignedtolookgoodorbeuseful,butrathertoillustrateseveralthingsthatarepossiblewhenyouwishtoaddsmallamountsofHTMLtoanativeShinyapplication,ratherthanbuildingfromscratchorworkingwithHTMLtemplates(moreonwhichlater).

We'regoingtobuildanapplicationthatallowsyoutoselectfromacoupleofdifferentcountriesandviewthelifeexpectancyovertimeinthatcountry.AcustomHTMLbuttonshowstheWikipediapagefortheselectedcountry.

ui.RLet'stakealookattheui.Rfilefirst:

fluidPage(

tags$head(HTML("<linkhref='http://fonts.googleapis.com/css?family=Jura'

rel='stylesheet'type='text/css'>")),

h2("CustomHTML",style="font-family:'Jura';

color:green;font-size:64px;"),

sidebarLayout(

sidebarPanel(

radioButtons("country","Country",

c("Afghanistan","Bahrain","Cambodia"))

),

mainPanel(

h3("Timeseries"),

HTML("<p><em>Lifeexpectancy</em>overtime</p>"),

plotOutput("plotDisplay"),

htmlOutput("outputLink")

)

)

)

There'saquickmethodofstylingtextinlineinthisexample.First,let'sfetchafontfromGoogleFonts,whichyoucanseebysimplyusingthetags$functiontogenerateanHTML<head>andthenplacingthelinkinside,asshowninthefollowingcode:

tags$head(HTML("<link

href='http://fonts.googleapis.com/css?family=Jura'

rel='stylesheet'type='text/css'>"))

Nowthatwehavethefontavailable,it'sasimplematterofplacingitwithintheapplication.ThetitlePage()argument,whichisoftenusedatthetopofaShinyapplication,hasbeenremovedandreplacedwithh2()becauseh2()willallowyoutoinsertinlinestylingstraightintothefunction,whereastitlePage()willnot.Moreover,althoughtheacceptedargumentsaredifferent,theactualHTMLgeneratedbytitlePage()andh2()isthesame.Totestthisyourself,gototheconsoleandtypetitlePage("Test")andthentryusingh2("Test").

Inbothcases,thesamethingisreturned—<h2>Test</h2>.Thisisareallyuseful

wayoflearningmoreaboutShinyandhelpingyoutodebugmorecomplexapplicationsthatmakeuseofShinyfunctions,aswellasHTMLandCSS.Sometimes,itcanbenecessarytoruntheapplicationandtheninspecttheHTMLusingtheinspectsourcefunctionavailableinmostwebbrowsers(Chrome,Explorer,Firefox,Safari,andsoon).Runningthefunctiondirectlyintheconsoleisalotquickerandlessconfusing.Havingdonethis,it'sasimplematterofpassingstylinginformationintoh2(),asyouwouldpassinlinestylingintoafontinHTML:

style="font-family:'Jura';color:green;font-size:64px;"

AlsoincludedistheHTML()function,whichmarkstextstringsasHTML,preventingtheHTMLfromescaping,whichwouldotherwiserenderthisonthescreenverbatim.TheothernewpartofthisfileisthehtmlOutput()function.This,inasimilarwaytotheHTML()function,preventsHTMLfromescapingandallowsyoutouseyourownmarkup,butthistimefortextpassedfromserver.R.Here'sthefinalinterface:

server.RTheserver.Rinthiscaseisquitesimple.First,weloadthetidyverseandthedata(thedatawecreatedinthepreviouschapter),asshowninthefollowingcode:

library(tidyverse)

load("geocodedData.Rdata")

Then,wedefinethereactivepartoftheapplication,asshowninthefollowingcode:

function(input,output){

output$plotDisplay<-renderPlot({

gapminder%>%

filter(country==input$country)%>%

ggplot(aes(x=year,y=lifeExp))+

geom_line()

})

output$outputLink<-renderText({

link="https://en.wikipedia.org/wiki/"

paste0('<formaction="',link,input$country,'">

<inputtype="submit"value="GotoWikipedia">

</form>')

})

}

Thefirstpartofthecodeshouldholdnosurprises,beingafairlysimplelinegraphproducedusingggplot2.Youcanseethefamiliarfilter()functionbeingusedtorestricttheseriestodatafromonecountry.ThesecondpartofthecodeusesrenderText(),whichwehaveusedbeforetoshowtextwithinanoutput.TheonlydifferencehereisthatwearegoingtogenerateourownHTML.Youwillrecallfromtheui.RthatthisoutputneedstobewrappedinhtmlOutput(),nottextOutput(),topreservetheHTML(whichwouldotherwisebeautomaticallyescapedinShiny).

That'sanicegentleintroductiontostartingtomixHTMLintoyourShinyapplications.Now,let'sgototheotherextremeandlookatbuildingyourinterfaceentirelyinHTML.

AminimalHTMLinterfaceNowthatwehavedippedourtoesintoHTML,let'sbuilda(nearly)minimalexampleofaninterfaceentirelyinHTML.TouseyourownHTMLinaShinyapplication,createtheserver.Rfileasyounormallywould.Then,insteadofaui.Rfile,createafoldernamedwwwandplaceafilenamedindex.htmlinsidethisfolder.Thisiswhereyouwilldefineyourinterface.

index.htmlLet'slookateachchunkofindex.htmlinturn,asshowninthefollowingcode:

<html>

<head>

<title>HTMLminimalexample</title>

<scriptsrc="shared/jquery.js"

type="text/javascript"></script>

<scriptsrc="shared/shiny.js"type="text/javascript"></script>

<linkrel="stylesheet"type="text/css"

href="shared/shiny.css"/>

<styletype="text/css">

body{

background-color:#ecf1ef;

}

#navigation{

position:absolute;

width:300px;

}

#centerdoc{

max-width:600px;

margin-left:350px;

border-left:1pxsolid#c6ec8c;

padding-left:20px;

}

</style>

</head>

The<head>sectioncontainssomeimportantsetupcodeforShiny,loadingtheJavaScriptandjQueryscripts,whichmakeitwork,aswellasastylesheetforShiny.YouwillneedtoaddsomeCSSofyourown,unlessyouwanteveryelementoftheinterfaceandoutputtobedisplayedasabigjumbleatthebottomofthescreen,makingthewholethinglookveryugly.Forsimplicity,I'veaddedsomeverybasicCSSinthe<head>section;youcould,ofcourse,useaseparateCSSfileandaddalinktoit,justasshiny.cssisreferenced.

ThebodyoftheHTMLcontainsalltheinputandoutputelementsthatyouwanttouse,aswellasanyothercontentthatyouwantonthepage.Inthiscase,I'vemixedupaShinyinterfacewithapictureofmycatsbecausenowebpageiscompletewithoutapictureofacat!Havealookatthefollowingcode:

<body>

<h1>MinimalHTMLUI</h1>

<divid="navigation">

<p>

<label>Titleforgraph:</label><br/>

<textareaname="comment"rows="4"

cols="30">Myfirstgraph</textarea>

</p>

<divclass="attr-colshiny-input-radiogroup"id="graph">

<p>

<label>Whatsortofgraphwouldyoulike?</label><br>

<inputtype="radio"name="graph"value="1"

title="Straightline"checked>Linear<br>

<inputtype="radio"name="graph"value="2"

title="Curve">Quadratic<br>

</p>

</div>

<label>Here'sapictureofmycats</label><br/>

<imgsrc="cat.jpg"alt="Mycats"width="300"height="300">

</div>

<divid="centerdoc">

<divid="textDisplay"class="shiny-text-output"></div>

<br/>

<divid="plotDisplay"class="shiny-plot-output"

style="width:80%;height:400px"></div>

</div>

</body>

</html>

Therearethreemainelements:atitleandtwo<div>sections,onefortheinputsandonefortheoutput.TheUIisdefinedwithinthenavigation<div>,whichisleftaligned.RecreatingShinywidgetsinHTMLisprettysimple,andyoucanalsouseHTMLelementsthatarenotgiveninShiny.InsteadofreplacingthetextInput()widgetwith<inputtype="text">(whichisequivalenttoit),Ihaveinsteadused<textarea>,whichallowsmorecontroloverthesizeandshapeoftheinputarea.

TheradioButtons()widgetcanberecreatedwith<inputtype="radio">.Youcanseethatbothgetanameattribute,whichisreferencedintheserver.Rfileasinput$name(inthiscase,input$commentandinput$graph).Youwillnotethatthereisanother<div>aroundtheradiobuttondefinition,<divclass="attr-colshiny-input-radiogroup"id="graph">.ThisisanecessaryextrawhenusingShinywithHTML,asdiscussedatgoo.gl/Lrx9GB.AnotheradvantageofusingyourownHTMListhatyoucanaddtooltips;Ihaveaddedthesetotheradiobuttonsusingthetitleattribute.

Theoutputregionissetupwithtwo<div>tags:onethatisnamedtextDisplayandpicksupoutput$textDisplay,asdefinedinserver.R,andtheotherthatisnamedplotDisplayandpicksupoutput$plotDisplayfromtheserver.Rfile.Inyourowncode,youwillneedtospecifytheclass(asshowninthepreviousexample)aseithershiny-text-output(fortext),shiny-plot-output(forplots),orshiny-html-output(fortablesoranythingelsethatRwilloutputasHTML).Youwillneedtospecifythe

heightofplots(inpx,cm,andsoon),andcanoptionallyspecifythewidtheitherinabsoluteorrelative(%)terms.

Justtodemonstratethatyoucanthrowanythingintherethatyoulike,there'sapictureofmycatsunderneaththeUI.Youwill,ofcourse,havesomethingabitmoresophisticatedinmind.Addmore<div>sections,links,pictures,andwhateveryoulike.

server.RLet'stakeaquicklookattheserver.Rfile,showninthefollowingcode:

function(input,output){

output$textDisplay<-renderText({

paste0("Title:'",input$comment,

"'.Thereare",nchar(input$comment),

"charactersinthis."

)

})

output$plotDisplay<-renderPlot({

par(bg="#ecf1ef")#setthebackgroundcolor

plot(poly(1:100,as.numeric(input$graph)),type="l",

ylab="y",xlab="x")

})

}

Texthandlingisdoneasbefore.You'llnotethattherenderPlot()functionbeginsbysettingthebackgroundcolortothesameasthepageitself(par(bg="#ecf1ef");formoregraphicaloptionsinR,see?par).Youdon'thavetodothis,butthegraph'sbackgroundwillbevisibleasabigwhitesquareifyoudon't.

Theactualplotitselfusesthepoly()commandtoproduceasetofnumbersfromalinearorquadraticfunctionaccordingtotheuserinput(thatis,input$graph).Notetheuseofas.numeric()tocoercethevaluewegetfromtheradiobuttondefinitioninindex.htmlfromastringtoanumber.

ThisisacommonsourceoferrorswhenusingShinycode,andyoumustremembertokeeptrackofhowvariablesarestored,whetheraslists,strings,orothervariabletypes,andeithercoercetheminplace(asdonehere),orcoercethemallinonegousingareactivefunction.

Thelatteroptioncanbeagoodideatomakeyourcodelessfiddlyandbuggybecauseitremovestheneedtokeeptrackofvariabletypesineverysinglefunctionyouwrite.ThereismoreaboutdefiningyourownreactivefunctionsandpassingdataaroundaShinyinstanceinthenextchapter.Thetype="l"argumentreturnsalinegraph,andthexlabandylabargumentsgivelabelstothexandyaxes.

Thefollowingscreenshotshowsthefinishedarticle:

Finishedarticle

IncludingaShinyapponawebpageThesimplestwaytomixShinyandanexistingwebpageisbyusinganiframe.JustlikewiththeRMarkdowndocumentinthepreviouschapter,itallowsyoutoincorporateanentireShinyapplicationintoanexistingdocument,exceptinthiscase,thedocumentisawebpageratherthanaMarkdowndocument.Theonlyrestrictionisthatyouwillneedtohosttheapplicationsomewhereontheinternetsoyoucanpointtoit.Onceyou'vedonethat,it'sassimpleasjustpointingtotheapplication,likeso:

<iframesrc="https://chrisbeeley.net/shinyapps/shinybook3rdedition/chapter2/widgettypes/"frameborder="0"width="950"height="800"></iframe>

HTMLtemplatesThedevelopersofShinythemselvesnotedthatalthoughithasalwaysbeenpossibletoproduceentireShinyapplicationsinHTML,itisveryraretofindanyexampleswheresomebodyhasdoneso.ThisisprobablybecauseofShiny'sabilitytoproduceattractiveapplicationsusingpureRcode(anditsabilitytoincorporatesnippetsofHTML),aswellastherelativecomplexityofwritingthewholeinterfaceyourself.Tomakethingssimpler,Shiny0.13addedtheabilitytouseHTMLtemplates.UsinganHTMLtemplate,youcanveryeasilymixtogetherHTMLandShinycode.Therearetwomainwaysofdoingthis:firstlybydefiningthecodeinlinewithintheHTML,andsecondlybydefiningitwiththeui.Rfile.Inbothcases,youwillneedthreefiles—aserver.Rfile,aui.Rfile,andanotherfile,atthesamedirectorylevel(notinawww/folder),whichwillbeHTMLandwhichyoucannameanythingyoulike.Let'scallourstemplate.html.

InlinetemplatecodeLet'slookfirstattheslightlysimplermethod,whichisincludingthecodeinlinewithintheHTMLtemplate.We'lltakesomeelementsoftheGapminderapplicationinthepreviouschapterandincorporatethemintoanHTMLtemplate.Theserver.Rfileisunchanged,althoughthisversionisalittleshorterthanthepreviousonebecausewehavetakenoutsomeoftheoutputs.Forthesakeofbrevity,we'llagainloadthedatathatwegeneratedinthepreviouschapter.Ifyouwanttoseehowtogeneratethisdata,havealookbackatthepreviouschapter.

server.RToremindyouoftheserver.Rfile,andtoshowyouwhichbitswehaveretained,let'slookattheserver.Rfilefirst,showninthefollowingcode:

library(tidyverse)

library(gapminder)

load("geocodedData.Rdata")

function(input,output){

theData=reactive({

mapData%>%

filter(year>=input$year[1])

})

output$trend=renderPlot({

thePlot=theData()%>%

group_by(continent,year)%>%

summarise(meanLife=mean(lifeExp))%>%

ggplot(aes(x=year,y=meanLife,group=continent,

colour=continent))+geom_line()+

ggtitle("Graphtoshowlifeexpectancybycontinentovertime")

if(input$linear){

thePlot=thePlot+geom_smooth(method="lm")

}

print(thePlot)

})

}

Therearenosurprisesinthiscode,really;itisjustacut-downversionofthecodefromthepreviouschapter.Youcanseeareactivefunctiontobringbackthedata(theData()),andacalltorenderPlot(),whichproducesalinegraphusingggplot().

ui.Randtemplate.htmlTheui.Risincrediblysimple,andlookslikethis:

htmlTemplate("template.html")

That'sit!YouarejusttellingShinywhattheHTMLfileiscalled.Rememberthatwecalledittemplate.html.Simple.Now,therealworkisdonewiththeHTMLfile.

Let'slookattheHTMLfile'svarioussections.First,thehead:

<html>

<head>

{{headContent()}}

{{bootstrapLib()}}

</head>

Thefirstthingtonoteishowthefilewillbewritten.Essentially,itwillbeHTML,interspersedwithShinycodewrappedindoublecurlybraces.So,thisfirstsectionopensthehtmltagandtheheadtagandthenrunstwofunctions,whicharegiveninsidedoublecurlybraces.YoualwaysneedtoincludeheadContent(),whichplacestheboilerplatecodenecessarytomakethepagework,justaswesawwiththeminimalHTMLwebpagethatwelookedatearlierinthechapter.SomeShinyfunctionsrequireyoutoincludebootstrapLib(),whichloadsvariousBootstrapcomponents.It'snotreallyworthworryingaboutwhetheryouareusingthosecomponentsornot,sinceyoumightaddthemlater,orincludethematfirstandthentakethemaway,andsoon.Justincludeiteverytimeandthenyouwon'tneedtoworry.

Next,wedefinethebodyoftheapplication,asshowninthefollowingcode:

<body>

<h1>MinimalHTMLUI</h1>

<divclass="container-fluid">

<divclass="row">

<divclass="col-sm-4">

<h3>Controlpanel</h3>

{{sliderInput(inputId="year",

label="Yearsincluded",

min=1952,

max=2007,

value=c(1952,2007),

sep="",

step=5)}}

{{checkboxInput("linear",label="Addtrendline?",

value=FALSE)}}

</div>

<divclass="col-sm-8">

{{plotOutput("trend")}}

<p>Formoreinformationabout<strong>Shiny</strong>lookatthe

<ahref="http://shiny.rstudio.com/articles/">documentation.</a></p>

<hr>

<p>Ifyouwishtowritesomecodeyoumayliketousethepre()functionlikethis:</p>

<pre>checkboxInput("linear",label="Addtrendline?",value=FALSE)</pre>

</div>

</div>

</div>

</body>

</html>

Asyoucansee,theShinycodeisincludedjustasyouwouldseeitinanynormalShinyapplication(indeed,thesearethefunctionsfromChapter2,ShinyFirstSteps),butineachcase,theyarewrappedwithdoublecurlybraces.It'sassimpleasthat.Itispossibletopassvaluesintothetemplatefromtheui.R,likethis:

htmlTemplate("template.html",customStep=10)

ThisvaluecannowbeaccessedfromwithintheShinycodeinthetemplate,likeso:

{{sliderInput(inputId="year",

label="Yearsincluded",

min=1952,

max=2007,

value=c(1952,2007),

sep="",

step=customStep)}}

Definingcodeintheui.RfileTheothermethodofdefininganHTMLtemplateisverysimilar,exceptinthiscase,theShinycodeisdefinedintheui.Rfile.Theserver.Rcodeisunchanged.

ui.RLet'sfirstlookattheui.Rfile,showninthefollowingcode:

htmlTemplate(

"template.html",

slider=sliderInput(inputId="year",

label="Yearsincluded",

min=1952,

max=2007,

value=c(1952,2007),

sep="",

step=5),

checkbox=checkboxInput("linear",label="Addtrendline?",value=FALSE),

thePlot=plotOutput("trend")

)

Asyoucansee,inthiscase,wearedefiningtheinputsintheui.Rfile.ThisisjustlikepassingthevalueofcustomStepinthepreviousexample,exceptthatinthiscasewearepassingwholewidgets,notjustvalues.Thesevaluesarenowreferredtoverysimplyinthetemplate.html,likeso:

...preamble

<divclass="container-fluid">

<divclass="row">

<divclass="col-sm-4">

<h3>Controlpanel</h3>

{{slider}}

{{checkbox}}

</div>

<divclass="col-sm-8">

{{thePlot}}

<p>Formoreinformationabout<strong>Shiny</strong>lookatthe

<ahref="http://shiny.rstudio.com/articles/">documentation.</a></p>

<hr>

...restofHTML

Themethodsareverysimilar.DefininginlineismoreappropriatewhenyourShinycodeisrelativelybrief,asitwasinthisexample.IfyouhavelargeamountsofShinyUIcode,youwillprobablyprefertodefineitinui.RtoavoidclutteringyourHTMLfilewithRcode.

TakeastepbackandrewindWecoveredquitealotofmaterialinthissection,soit'sworthspendingamomentreviewingwhatwecovered.We'velookedataddingHTMLtoanapplicationthatisotherwisewritteninpureShiny.We'velookedatstylingapplicationswithCSS,aswellasbuildingentireinterfaceswithHTMLusingHTMLtemplates,orbymakingthewholethingfromscratch.

ExerciseIfyouhaven'talreadybeentempted,nowisdefinitelyagoodtimetohaveagoatbuildingyourownapplicationwithyourowndata.ThenextchaptercoversadvancedtopicsinShinyUIdesign,andthoughyouarewelcometoplowon,alittlepracticalexperiencewiththefunctionswillstandyouingoodsteadforthenextchapter.Ifyou'reinterestedinsharingyourcreationsrightaway,feelfreetojumptoChapter9,PersistentStorageandSharingShinyApplications.

HowyougoaboutbuildingyourfirstapplicationwillverymuchdependonyourpreviousexperienceandwhatyouwanttoachievewithShiny,butaswitheverythinginlife,itisbettertostartsimple.Startwiththeminimalexamplegiveninthepreviouschapterandputinsomedatathat'srelevanttoyou.Shinyapplicationscanbehardtodebug(comparedwithinteractiveRsessions,atleast),soinyourearlyforays,keepthingsverysimple.

Forexample,insteadofdrawingagraph,startwithasimplerenderText()callandjustprintthefirstfewvaluesofavariable.ThiswillatleastletyouknowthatyourdataisloadingokayandthattheserverandUIarecommunicatingproperly.AlwaysmakesurethatanycodeyouwriteinR(graphs,tables,datamanagement,andsoon)worksinaplaininteractivesessionbeforeyouputitintoaShinyapplication!

DebuggingProbablythemosthelpfulandsimpledebuggingtechniqueistousecat()toprinttotheRconsole.Therearetwomainreasonswhyyoushoulddothis:

Thefirstistoputinlittlemessagestoyourself—forexample,cat("Thisbranchofcodeexecuted").ThesecondistoprintthepropertiesofRobjectsifyouarehavingproblemsrelatingtodatastructure,size,ortype.Thecat(str(x))phraseisparticularlyuseful,andwillprintalittlesummaryofanykindofRobject,whetheritisalist,adataframe,anumericvector,oranythingelse.

TheotherusefulmethodisastandardmethodofdebugginginR,browser(),whichcanbeputanywhereinyourcode.Assoonasitisexecuted,ithaltstheapplicationandentersdebugmode(see?browser).ThereismoreondebuggingShinyapplicationsinChapter8,CodePatternsinShinyApplications.

Onceyouhavetheapplicationworking,youcanstarttoaddcustomHTMLusingShiny'sbuilt-infunctionsorrewriteui.Rintoindex.html.ThechoiceherereallydependsonhowmuchHTMLyouwanttoinclude.AlthoughintheoryyoucancreateverylargeHTMLinterfacesinShinyusing.htmlfilesreferencedbytheincludeHTML()command,youwillendupwitharatherconfusinglistofmarkupsscatteredacrossdifferentfiles.

Bootstrap3andShinySincethefirsteditionofthisbook,ShinyhasmigratedfromBootstrap2toBootstrap3.Therearenowmanyfunctions—bothwithinShinyandinitspackages(suchasshinydashboardandshinythemes,bothavailableonCRAN)—thatenhancethewayyoucanstyleyourapplicationsstraightfromShiny.Thereismoreonadvancedlayoutfunctions,Bootstrap3,andthepackagestohelpyoutostyleyourapplicationsinChapter4,MasteringShiny'sUIFunctions.

SummaryThischapterhasincorporatedquiteapileoftoolsintoyourShinytoolbox.YoulearnedhowtousecustomHTMLstraightfromaminimalui.RUIsetupandhowtobuildthewholethingfromscratchusingHTMLandCSS.

Inthenextchapter,youaregoingtolearnmoreaboutbuildingaUIwithShiny.Shinyincludesalotofdifferentlayoutfunctions,whichwillallbedescribed,andwewillalsolookatmakingnicetables,usingprogressbars,andmodals,aswellasmakingyourUIreactive.

MasteringShiny'sUIFunctionsSofarinthisbook,we'vemasteredthebasicsofShinybybuildingourownGapminderdata-explorerapplication,andwe'velookedathowtostyleandextendShinyapplicationsusingHTMLandCSS.Inthischapter,wearegoingtoextendourtoolkitbylearningaboutmoreofShiny'sUIfunctions.Theseallowyoutotakecontrolofthefinedetailsofthewayyourapplicationlooksandbehaves.

Inordertodothis,we'regoingtochangethewaytheUIworksintheGapminderapplicationtomakeitmoreintuitiveandwell-featured.ThefinishedcodeanddataforthisadvancedGapminderapplicationcanbefoundathttps://chrisbeeley.net/website/.

Inthischapter,wewillcoverthefollowingtopics:

UsingShiny'smanylayoutfunctionseffectivelyLearninghowtoshowandhidepartsoftheinterfaceChangingtheinterfacereactivelyProducingbeautifultableswiththeDataTableslibraryShowingprogressbarstousersinlong-runningfunctionsShowingmessageswithmodals

Shiny'slayoutfunctionsTherearequitealotofdifferentlayoutfunctionsinShiny,andunderstandingwhattheyalldocanhelpyoutobuildtheinterfacethatyouwanteasily.It'spossibletocombinealotofthem,too,sowe'llreviewtheformandfunctionofeach,andthenshowalargerexampleattheendthatcombinesthemtogether.TherearethreemaintypesoflayoutfunctionthatShinyoffers.ThefirstiswhatIwouldcallsimplelayoutfunctions.Theseproduceastraightforwardkindoflayout,withoutmuchinthewayofstyling,anditisthesefunctionsthatcanoftenbecombinedtogether.ThenextkindiswhatIwouldcallcomplete.Thisisalayoutfunctionthatoffersalittlestylingandissuitablefordefininganentireapplication.Itwouldthereforeoftenbeusedonitsownwithoutanyothertypeoflayoutfunction.ThelastkindIwouldcallthedo-it-yourselfanditreferstoafunctionthatdoesn'treallydomuchatall,butratherjustdefinesthespaceinwhichyouwillplaceyourwidgets.Thisfunction,ofcourse,isverysuitableforcombiningwithotherfunctionstoproducethesetupyouwant.Let'srevieweachtypeinturn.

SimpleThroughoutthesecodeexamples,we'regoingtohaveaverysimpleserver.Rfile,whichwillnotchange.Itsimplydrawsatableandnothingelse.Wewillthereforealsobreakthehabitoftherestofthisbookandusethesingleapp.Rfilestructurefortheseexamples,sincetheyaresosmall.Withthatinmind,let'slookatthefirstapplication,whichwillbeflowLayout():

server=function(input,output){

output$table=renderTable({

head(iris)

})

}

ui=flowLayout(

sliderInput("slider","Slider",min=1,max=100,value=50),

textInput("text","Text"),

tableOutput("table")

)

shinyApp(ui,server)

InflowLayout,elementsareorderedlefttoright,toptobottom.Resizingthewindowcausestheelementstoreorderthemselvessotheyfit,lefttoright,toptobottom.Downloadthecodeexampleandtryitforyourself.Throughoutthissection,it'sagoodideatodownloadtheexamplesandtrythemout.

ThenextexampleisverticalLayout().Inthisandsubsequentcodeexamples,wewillnotbotherwiththeserverandshinyApp()codesincetheywillneverchange.Wewilljustlookatthevalueforuiineachcase:

ui=verticalLayout(

sliderInput("slider","Slider",min=1,max=100,value=50),

textInput("text","Text"),

tableOutput("table")

)

Asthenamesuggests,itmerelyarrangeselementsvertically.Asmanyasyousupply.Hereitisinaction:

ThefinalsimplefunctionissplitLayout().Ittakesasmanyelementsasyougiveitandarrangesthemonthepagelefttoright.Bydefault,eachisgiventhesamewidthbutyoucanoptionallysetthewidthforeachmanually.Hereisanexample:

ui=splitLayout(

cellWidths=c("20%","20%","60%"),

sliderInput("slider","Slider",min=1,max=100,value=50),

textInput("text","Text"),

tableOutput("table")

)

Inthiscase,wehavesetthewidthstobetteraccommodatethetable(which,asyoucansee,isgiven60%ofthewidth).It'ssuperficiallysimilartoflowLayout(),inthatifyoulayoutanapplicationwithboth,theymaylooksimilaratfirst,butthetwocriticaldifferencesarethatsplitLayout()allowsyoutodefinethewidthofeachwidget,andthatifyouresizethewindow,flowLayout(truetoitsname)willflowontothenextrow,whereassplitLayout()willjustcrampeverythingup,as

showninthefollowingscreenshot:

SplitLayout

CompleteNow,wecometothecompletesetupfunctions,thosethatcanbeusedindividuallytomakeawell-styledapplication.First,ofcourse,wehavetheoldfavorite,sidebarLayout().Many,manyShinyapplicationsarewrittenusingthislayoutanditisanattractiveandfunctionalsetup,withawellpanelthathighlightsthecontrolsandalargeareaforoneormoreoutputs.We'vealreadyseenthissetup,butasaquickreviewofthebasicstructurewithoutalltheusualclutter,let'stakealookattheuicode:

ui=fluidPage(

sidebarLayout(

sidebarPanel(

sliderInput("slider","Slider",min=1,max=100,value=50),

textInput("text","Text")),

mainPanel(tableOutput("table"))

)

)

It'sworthnotingthatthislayoutrequirestheuseoffluidPage()tosetitupcorrectly.Thisfunctionisrequiredforthisandanotherlayoutfunction,whichwewillcovershortly,aswellasbeingusefulinitsownright(whichwewillalsocovershortly).

TheothertwocompletelayoutfunctionsarenavbarPOAge()andnavlistPanel().Theyworksimilarlyinthatbothprovidebuttonsforyoutopagethroughsetsofinputandoutput.Let'slookateach.Hereisthesamesetofinputandoutput,puttogetherasanavbar:

Navbar

Thisisoneoftheselectedpages,Inputs.ThetableisviewableontheTablepage,accessedbyclickingtheTablebuttononthebaratthetop.ThisisobviouslynotparticularlygoodUIdesign,it'sjustdonetoillustratehowthefunctionswork.

Thecodeisverysimpleandjustconsistsoftabpanels,likeyouwouldfindintabsetPanel():

ui=navbarPage("Navbardemo",

tabPanel("Inputs",

sliderInput("slider","Slider",

min=1,max=100,value=50),

textInput("text","Text")),

tabPanel("Table",tableOutput("table"))

)

Navlistsworkinaprettysimilarway,exceptthepagesforthebuttonsaregatheredoverontheleft,asshowninthefollowingscreenshot:

Thecodehereisverysimilar,exceptinthiscase,aswiththesidebarLayout()function,acalltofluidPage()isnecessary:

ui=fluidPage(

navlistPanel("Navlistdemo",

tabPanel("Inputs",

sliderInput("slider","Slider",

min=1,max=100,value=50),

textInput("text","Text")),

tabPanel("Table",tableOutput("table"))

)

)

DoityourselfWealreadysawfluidPage()beingusedtosetuptheenvironmentforotherlayoutfunctionstowork.ButthisfunctioncanalsobeusedtobuildaUIfromscratch,usingthefluidRow()function.UsingfluidRow()withinfluidPage()allowsyoutoimplementthestandardbootstrapgridlayout,asdescribedatw3schools.com/bootstrap/bootstrap_grid_system.asp.Essentially,theinterfaceisbuiltuprowbyrowusingthefluidRow()function.Eachrowcanbedividedintosectionsofarbitrarywidthusingthecolumn()function.Thecolumnfunctiontakesanumericargumentspecifyinghowwideitshouldbe.Thetotalofalloftheseargumentsinagivenrowshouldalwaysbe12.So,forexample,arowmightconsistofcolumnsofwidth3and9,andthefollowingrow,perhapswidthsof4,4,and4.Inthiscase,averysimpleimplementationusingfluidRow()mightlooklikethis:

ui=fluidPage(

fluidRow(

column(width=4,

sliderInput("slider","Slider",min=1,max=100,value=50),

textInput("text","Text")),

column(width=8,

tableOutput("table")

)

)

)

CombininglayoutfunctionsTofinish,let'slookathowtousedifferentlayoutfunctionstogethertoachieveasimpleandflexiblesetupforyourapplication.Therearelotsofdifferentwaysofdoingthis;thisexampleisdesignedjusttoshowyouthatyoucanuseawidevarietyoffunctionstowritequick,simplecode.Intruth,anydesigncanbemadeusingthegridsystem,givenenoughtimeandeffort,butitissometimessimplerjusttouseabuilt-infunction,asyoucansee.Inthisexample,I'veaddedacoupleofgraphstofleshouttheinterfaceabit,butwewon'tbotherlookingatthecodeforthem.They'rejustcreatedusingrenderPlot({plot(runif(10,runif(10))})andassignedtooutput$graph1andoutput$graph2.ThefinalUIcodelookslikethis:

ui=fluidPage(

fluidRow(

column(width=4,

sliderInput("slider","Slider",min=1,max=100,value=50)),

column(width=8,

tableOutput("table")

)

),

splitLayout(

plotOutput("graph1"),plotOutput("graph2")

),

verticalLayout(

textInput("text","Text"),

p("Moredetailshere"),

a(href="https://shiny.rstudio.com/tutorial/","Shinydocumentation")

)

)

Asyoucansee,youcanfreelymixtogethertheselayoutfunctionstotakeadvantageofthebenefitsofeach;fluidRow()togiveprecisecontroloverthewidthofthecolumns,splitLayout()forsimplicity,andverticalLayout()tostackthewidgetsontopofeachother.Thefinalapplicationlookslikethefollowingscreenshot:

StreamliningtheUIbyhidingelementsThisisasimplefunctionthatyouarecertainlygoingtoneedifyoubuildevenamoderatelycomplexapplication.Thoseofyouwhohavebeendoingextracreditexercisesand/orexperimentingwithyourownapplicationswillprobablyhavealreadywishedforthisor,indeed,havealreadyfoundit.

conditionalPanel()allowsyoutoshoworhideUIelementsbasedonotherselectionswithintheUI.Thefunctiontakesacondition(inJavaScript,buttheformandsyntaxwillbefamiliarfrommanylanguages)andaUIelement,anddisplaystheUIonlywhentheconditionistrue.We'regoingtoenhancetheGapminderapplicationtoshowtheoptiontoaddatrendlinetothegraphonlywhenthegraphisshown.Inordertodothis,we'regoingtohavetoknowwhichofthetabpanelsiscurrentlyselected,andinordertodothatwe'regoingtohavetogivethemaname.Let'sdothatnow.

NamingtabPanelelementsInordertoallowtestingforwhichtabiscurrentlyselected,we'regoingtohavetofirstgivethetabsofthetabbedoutputnames.Thisisdoneasfollows(withthenewcodeinbold):

tabsetPanel(id="theTabs",

tabPanel("Summary",textOutput("summary"),

value="summary"),

tabPanel("Trend",plotOutput("trend"),

value="trend"),

tabPanel("Map",leafletOutput("map"),

p("Mapdataisfromthemostrecentyearintheselectedrange"),

value="map")

)

Asyoucansee,thewholepanelisgivenanID(theTabs)andtheneachtabPanelisalsogivenaname(summary,trend,map).Theyarereferredtointheserver.Rfileverysimplyasinput$theTabs.

Finally,wecanmakeourchangestoui.RtoremovepartsoftheUIbasedontabselection:

conditionalPanel(

condition="input.theTabs=='trend'",

checkboxInput("linear",label="Addtrendline?",

value=FALSE)

),

Asyoucansee,theconditionappearsveryR/Shiny-like,exceptwiththe.operatorfamiliartoJavaScriptusersinplaceof$.ThisisaverysimplebutpowerfulwayofmakingsurethatyourUIisnotclutteredwithirrelevantmaterial.

BeautifultableswithDataTableLaterversionsofShinyaddedsupporttodrawtablesusingthewonderfulDataTablejQuerylibrary.Thiswillenableyouruserstosearchandsortthroughlargetablesveryeasily.ToseeDataTableinaction,visitthehomepageathttp://datatables.net/orruntheapplicationfeaturedinthischapter.

Thepackagecanbeinstalledusinginstall.packages("DT")andneedstobeloadedinthepreambletotheserver.Randui.Rfilewithlibrary(DT).Oncethisisdone,usingthepackageisquitestraightforward.Therearetwofunctions:oneinserver.R(renderDataTable)andoneinui.R(dataTableOutput).Theyareusedasfollows:

###server.R

output$countryTable=renderDataTable({

mapData%>%

filter(year==2007)%>%

select(-c(lon,lat))

})

###ui.R

tabPanel("Table",dataTableOutput("countryTable"),

value="table")

AnythingthatreturnsadataframeoramatrixcanbeusedwithinrenderDataTable().Outofthebox,itwillproduceattractive,searchable,pageabletables.Inthiscase,thetablelookslikethis:

InpreviousversionsofShiny,therewerenamespaceconflictsbetweenthedatatablefunctionsandthestandardfunctions,withShinydrawingastandard

tablewithsomeofthesamefunctionnamesastheDTpackage.ThesituationnowisthatShinywillproducetheseJavaScriptdatatablesoutofthebox,butwithoutenablingalloftheoptionsofthefullDTpackage(inparticular,client-sideprocessing).It'sworthwhile,then,tousetheDTpackageandloaditinserver.Randui.R.Let'scustomizethetableusingtheoptionsthatareavailablewiththeDTpackage.Thecodeisasfollows:

datatable(

mapData%>%

filter(year==2007)%>%

select(-c(lon,lat)),

colnames=c("Country","Continent","Year","Lifeexpectancy",

"Population","GPDpercapita"),

caption="Countrydetails",filter="top",

options=list(

pageLength=15,

lengthMenu=c(10,20,50))

)

Thefirstthingtonoticeisthatweneedtowrapthefunctionindatatable().TherenderDataTable()functionwillautomaticallyapplythattoanydataframeormatrixreturnedbyit,butinordertoaddoptionsweneedtoexplicitlyaddit.Youcanseethecolumnnamesbeingmadefriendlierwiththecolnamesargument,acaption,andacolumnfilterbeingaddedatthetopusingfilter='top'.Lastly,therearesomeoptionsthatareaddedfromwithinacalltooptions=list(...),inthiscasechangingthesizeofthetableandtheoptionsforrownumbersgivenforthetable(making10,20,or50rowstheoptionsavailable).Therearemany,manyoptionsavailable,soreadthedocumentationformoredetails:rstudio.github.io/DT/.

ReactiveuserinterfacesAnothertrickyouwilldefinitelywantupyoursleeveatsomepointisareactiveuserinterface.ThisenablesyoutochangeyourUI(forexample,thenumberorcontentofradiobuttons)basedonreactivefunctions.

Forexample,consideranapplicationthatIwroterelatedtosurveyresponsesacrossabroadrangeofhealthservicesindifferentareas.Theservicesarerelatedtoeachotherinquiteacomplexhierarchy,andovertime,differentareasandservicesrespond(orceasetoexist,ormerge,orchangetheirname),whichmeansthatforeachtimeperiodtheusermightbeinterestedin,therewouldbeatotallydifferentsetofareasandservices.Theonlysensiblesolutiontothisproblemistohavetheusertellyouwhichareaanddaterangetheyareinterestedinandthengivethembackthecorrectlistofservicesthathavesurveyresponseswithinthatareaanddaterange.

Theexamplewe'regoingtolookatisalittlesimplerthanthis,justtokeepfromgettingboggeddownintoomuchdetail,buttheprincipleisexactlythesameandyoushouldnotfindthisideatoodifficulttoadapttoyourownUI.Wearegoingtomakeaselector,whichallowstheusertopickoneoftheyearswithintheyearrangethattheyhaveselectedandhavethatyearplottedonthemap,insteadofbeingstuckwiththemostrecentyear.Thechoicewillbeconstrainedbythefactthatthedatawasonlyrecordedeverysevenyears.So,forexample,iftheuserselects1960to1990,theselectorboxwillcontainonlytheyears1962,1967,1972,1977,1982,and1987.

Thereactiveuserinterfaceexample–server.RWhenyouaremakingareactiveuserinterface,thebigdifferenceisthatinsteadofwritingyourUIdefinitioninyourui.Rfile,youplaceitinserver.RandwrapitinrenderUI().Then,allyoudoispointtoitfromyourui.Rfile.

Let'stakealookattherelevantbitoftheserver.Rfile:

output$yearSelectorUI=renderUI({

selectedYears=unique(mapData$year)

selectInput("yearSelector","Selectyear",

selectedYears)

})

Thefirstlinetakesthereactivedatasetthatcontainsonlythedatabetweenthedatesselectedbytheuserandgivesalltheuniquevaluesoftheyearwithinit.Thesecondlineisawidgettypethatwehavenotusedyetthatgeneratesacombobox.Theusualidandlabelargumentsaregiven,followedbythevaluesthatthecomboboxcantake.Thisistakenfromthevariabledefinedinthefirstline.Theoutputitself,thatis,thebitdefinedasoutput$something=renderUI({...}),canbegivenanynameyoulike.ItwillsimplybecalledbywhateverthatnameisinuiOutputwithinui.R,asweshallseeinamoment.Notethattheactualinputthatwearecreating,thatis,thethingthatwillbecalledbyinput$something,hasthenamegivenintheselectInput()function.So,inthiscasetheinputwillbecalledinput$yearSelectorandnotinput$yearSelectorUI.Toavoidconfusion,IhaveadoptedanamingconventionformyuseofrenderUI,whereIgivetheoutput$thesamenameasselectInput(),orwhicheverotherfunctionitis,butwithUIattheend.ThishelpsmenottomixthemupandmeansIcanalwaysremembertheotherifIknowthefirstone.Let'slookatthecorrespondingentryintheui.Rnow.

Thereactiveuserinterfaceexample–ui.RTheui.Rfilemerelyneedstopointtothereactivedefinition,asshowninthefollowinglineofcode(justaddittothelistofwidgetswithinsidebarPanel()):

uiOutput("yearSelectorUI")

Youcannowpointtothevalueofthewidgetintheusualway,asinput$yearSelector.

TherearemoreadvancedthingsyoucandowithareactiveUIusingtheinsertUI()andremoveUI()functions,whichallowyoutoinsertarbitrarycontrolsorsetsofcontrolsandremovecontrols,respectively.Althoughtheyarequitesimpletoactuallyproduce,makinguseofthemisquitetrickybecauseoftheneedtokeeptrackofthenamesgiventoeachinput,aswellaswhichhavebeenaddedandremovedsofar.Asaconsequence,wewillnotlookatanexampleinthisbook;seethedocumentationforasimpleexampleandyoumaywishtobearinmindthatitispossibleshouldyoueverneeditinalargeapplication.

ProgressbarsItisquitecommoninShinyapplications,andinanalyticsgenerally,tohavecomputationsordata-fetchesthattakealongtime.Sometimes,itwillbenecessaryfortheusertowaitforsometimebeforetheiroutputisreturned.Incasessuchasthis,itisagoodpracticetodotwothings:toinformtheuserthattheserverisprocessingtherequestandhasnotsimplycrashedorotherwisefailed,andtogivetheusersomeideaofhowmuchtimehaselapsedsincetheyrequestedtheoutputandhowmuchtimetheyhaveremainingtowait.

ThisisachievedverysimplyinShinyusingthewithProgress()function.Thisfunctiondefaultstomeasuringprogressonascalefrom0to1andproducesaloadingbaratthetopoftheapplicationwiththeinformationfromthemessageanddetailargumentsoftheloadingfunction.

YoucanseeinthefollowingcodethatthewithProgressfunctionisusedtowrapafunction(inthiscase,thefunctionthatdrawsthemap),withmessageanddetailargumentsdescribingwhathashappenedandaninitialvalueof0(value=0,thatis,noprogressyet):

withProgress(message='Pleasewait',

detail='Drawingmap...',value=0,{

...functioncode...

})

Asthecodeissteppedthrough,thevalueofprogresscansteadilybeincreasedfrom0to1(forexample,inafor()loop)usingthefollowing:

incProgress(1/3)

Thethirdtimethisiscalled,thevalueofprogresswillbe1,whichindicatesthatthefunctionhascompleted(althoughothervaluesofprogresscanbeselectedwherenecessary;see?withProgess()).Tosummarize,thefinishedcodelooksasfollows:

withProgress(message='Pleasewait',

detail='Drawingmap...',value=0,{

...functioncode...

incProgress(1/3)

...functioncode...

incProgress(1/3)

...functioncode...

incProgress(1/3)

...functioncode...

})

It'sassimpleasthat.Again,takealookattheapplicationtoseeitinaction.Ifyouneedtogiveyourusermoredetailedinformationabouthowfartheyarethroughtheprocessing,theincProgress()functionalsotakesmessageanddetailarguments,whichmeansyoucanchangetheinformationbeinggivenbywithProgress()asyoustepthroughthefunction.Forexample,youmaywishtowriteincProgress(1/3,detail="Summarizingdata"),perhapsincProgress(1/3,message="Generatinggraph"),andsoon.

ProgressbarwithshinycssloadersTheshinycssloaderspackagemakesiteveneasiertoallowyourusertoseethatanoutputisloading.ItisavailableonCRANandsocanbeinstalledwiththis:

install.packages(“shinycssloaders”)

Outputsincludinggraphsandtableswillnowshowananimatedbusyiconwhiletheyload.ThecodeisassimpleaswrappinganoutputinwithSpinner(),orevenjustpipingittowithSpinner():

withSpinner(plotOutput(“myplot”))

Or,youcanusethefollowing:

plotOutput(“myplot”)%>%

withSpinner()

ModalsModalsareaUIelementfromBootstrapandarepop-upmessagesthatcantellyourusermoreaboutwhattheapplicationisdoing.Theycanbeusefultogiveauserwarnings,ortoallowtheusertorequestmoreinformationaboutanoutputiftheywishtoknowmore.Youcanwriteamodalverysimply,usingtwofunctionsintheserver.Rfile.ThemodalDialogfunctionproducesthemodal,andtheshowModalfunctionshowsit.Youcanusethemtogetherjustlikethis:

showModal(modalDialog(

title="Warning",

"Thisisawarning"

))

Thiswillgiveusasimpledialogwithatitleandamainsection:

Butwecandomoreinterestingthingsthanthiswithmodaldialogs.Therearetwowaysthatwecanexpandtheirfunctionality.First,becausethemodalDialog()functionwillacceptanyShinyUIelements,notjusttext,youcanaddHTMLelementssuchashorizontalrule,withhr(),andeveninputandoutput.Andsecond,youcangeneratethemodaldialogusingthemodalDialog()functionelsewhere,andmerelypasstheoutputtoshowModal().Theapplicationdoesn'treallydoanythingsensible,butit'sjustforillustration.We'regoingtohaveabuttonthatlaunchesamodaldialog.Themodaldialogwillcontainanactionbuttonandaninstructionnottopressit.Iftheuserdoespressit,afunctionelsewheredecideswhetherwe'realldoomedortheygotawaywithitthistime.Let'shavealookatthecode.We'llstartveryquicklywiththeonelinethatweaddtotheui.Rfiletoshowthebuttonthatmakesthemodaldialog:

actionButton("showModal","Launchloyaltytest")

Thisisthefirsttimethatwe'veseenanactionbutton.ActionbuttonsaresimplyHTMLcontrolsthatstartoffwithavalueof0andincrementby1eachtimethey'repressed.Onedoesn'tnormallyusethisvalue,althoughsometimesitcanbeusefultoknowhowmanytimesthebuttonwaspressed.Instead,theactionbuttonisusedbecausereactivefunctionscanformdependenciesonit,meaningtheywillrunwhenthebuttonispressed.Includingacalltoanactionbutton(byjustwritinginput$showModalononelineofthecode)willcauseanyreactivefunction,whetheritbeanoutputorotherwise,torerunwhenthebuttonispressed.Thereisalsoaspecialfunction,observeEvent({}),thatreactstoeventssuchasbuttonpushes,whichwe'regoingtousenow.ForadetaileddescriptionofhowtouseobserveEvent({})anditscousin,observe({}),seeChapter8,CodePatternsinShinyApplications.Fornow,it'senoughtoknowthatobserveEvent(input$showModal,{...})willruneverytimesomeonepushestheshowmodalbutton.

Havingsetupthebuttontolaunchit,let'sproducethefirstmodal:

observeEvent(input$showModal,{

showModal(modalDialog(

title="Loyaltytest",

actionButton("dontPress","Don'tpressthis")

))

})

Asyoucansee,straightawaywe'vemadethingsmoreinterestingbyincludingaShinyfunctioninsidethemodalratherthanjustsometext.Now,we'regoingtosetupanothermodalifsomeonepressestheactionbuttoninthefirst:

observeEvent(input$dontPress,{

showModal(testOutcome(sample(c(TRUE,FALSE),1)))

})

YoucanseetheshowModal()functionthatacceptsamodaldialogobjectandtheobserveEvent()function,againreactingtoabuttonpush.Butthistime,we'regeneratingthemodalwithafunction,testOutcome().Youcanseealsothatwe'repassingavaluetotestOutcome(),eitherTRUEorFALSE,chosenrandomly.Thisletsthefunctionknowwhethertheuserhasdoomedusallorgotawaywithitthistime.Let'slookatthefunction:

testOutcome=function(chance){

modalDialog(title="Outcome",

ifelse(chance,"You'vedoomedusall!",

"Yougotawaywithitthistime!"))

}

Asyoucansee,thefunctionisverysimpleandcreatesamodaldialogthatdecides,basedonthevaluefedtoit,whetherwe'realldoomed.Hopefully,thatshouldgiveyouagoodgroundinginhowwecanusefunctionstocreatemodals.Ifyou'recomfortablewiththis,exploretheexamplesinthedocumentation;theyuseadvancedconceptsinShiny,suchasreactivevalues(coveredinChapter8,CodePatternsinShinyApplications).

AlternativeShinydesignsAtthetimeofwriting,thereisquiteanexcitingnewdevelopmentintheworldofShinyUI,whichisthatdevelopersarestartingtoprovideShinyinterfacestoUIframeworksotherthanBootstrap.Thefirstexampleofthis,whichwillhopefullyleadtomanymore,isanimplementationoftheMaterialdesignframeworkforShiny.MaterialdesignistheveryflatdesigncreatedbyGooglein2014andfamiliartoanyuseroftheAndroidoperatingsystem.Hereisanexample:

TheShinypackageitselfisbasedontheopensourceimplementationofMaterialdesign,MaterializeCSS(materializecss.com/),andiscalledshinymaterial.ItisavailableonCRAN(cran.r-project.org/web/packages/shinymaterial/index.html).ThepackageitselffeaturesdifferentfunctionsfromvanillaShiny,material_radio_button()andmaterial_modal(),forexample,buttheprinciplesarethesameandanyShinydevelopershouldfinditeasytousethedifferentfunctionstogiveatotallydifferentfeeltotheirapplication.

SummaryInthischapter,welookedatdifferentwaystomakeyourapplicationgood-lookingandeasytouse.Welookedattherangeoflayoutfunctionsandhowbesttousethem,andwelookedatmakinginputthatshows,hides,andchangesitscontentsinresponsetothestateoftheapplication.Wealsolookedatmakingandcustomizingdatatables,andshowingprogressbarsandmessagestoyouruser,aswellasatotallynewwaythatShinyapplicationscanlookbasedontheMaterialdesignframeworkfromGoogle.

ThenextchapterisallaboutusingJavaScript,allthewayfromusingJavaScriptfromRcodewiththeshinyjspackagetoproducingacomplexapplicationthatusesJavaScripttopassmessagesbackandforthbetweentheShinyserverandtheclient.

EasyJavaScriptandCustomJavaScriptFunctionsWithShiny,JavaScript,andjQuery,youcanbuildprettymuchanythingyoucanthinkof;moreover,ShinyandjQuerywilldoalotoftheheavylifting,whichmeansthatfairlyminimalamountsofcodewillberequired.Inthischapter,wewillcover:

UsingJavaScripttoreadandwritetotheDOMUsingJavaScripttosendmessagesbetweenclientandserverEasyJavaScriptwiththeshinyjspackageUsingyourownJavaScriptwithextendShinyjsListeningforeventswithJavaScriptUsingJavaScriptlibrarieswithhtmlwidgets

JavaScriptandShinyTheconnectionbetweenJavaScriptandShinyisanotherreasontorecommendRStudioasanIDEbecauseitperformsbeautifulsyntaxhighlightingonJavaScriptstraightoutofthebox(although,clearly,othertexteditorsandIDEsmaydothisorbeeasilyconfiguredtodoso).

Beforeweproceed,it'sworthreviewingthedifferencebetweenserverandclient-sidecodeandwhatthey'reusedfor.JavaScriptgainedpopularityasaclient-sidelanguage,whichranonwebbrowsersandaddedinteractivitytowebsitesthatwouldotherwisebestaticHTMLandCSSfiles,whichweredownloadedfromservers.

Ithasfoundincreasinguseontheserverside(forexample,withNode.js),butwearegoingtouseitontheclientsideandsowillnotconsiderthisanyfurther.So,inthiscase,JavaScriptisrunningontheclientside.Theserversideinthiscase,ofcourse,isR,andspecificallythecommandsaretobefoundintheserver.Rfile.ShinyandJavaScript(and,byextension,jQuery)can,asserverandclientrespectively,passthingsbackandforthbetweenthemselvesasyouwish.

Also,it'sworthnotingthattherearetwowaysforShinyandJavaScripttointeractwitheachother.

Thefirstisperhapsthesimplestandwillbeconsideredfirst.BecauseShinyandJavaScriptcanbothreadandwritetothewebpage(thatis,totheDocumentObjectModel(DOM),itisquitesimpleforthemtointeractwitheachotheronthewebpage.TheDOMisawayoforganizingobjectsinHTML,XHTML,andXMLdocuments,inwhichelementsarereferencedwithinatreestructure.

Adetaileddiscussioniswelloutsidethescopeofthisbook;sufficetosaythatifyouaregoingtouseJavaScriptwithShinyorHTML,youwillneedtolearnabouttheDOMandhowtogetandsetattributeswithinit.

ThesecondwayinwhichShinyandJavaScriptcaninteractiswhenit'seasierorbettertosendmessagesdirectlybetweentheserverandclient.Althoughintheory,youcouldusethe<inputtype="hidden">tagofHTMLandpassmessageson

theDOMwithoutshowingthemtotheuser,itwilloftenbeeasiertocutoutthemiddlemanandsendtheinformationdirectly,particularlywhenthemessageiscomplicated(alargeJSONobject,forinstance).

Wewilllookatsendingmessagesdirectlyafterthefirstexample.

First,asawarm-up,wewilllookatusingJavaScripttoreadtheDOMgeneratedbyShinyandperformsomeclient-sideprocessing,beforewritingthechangesbacktotheDOM.

Example1–readingandwritingtheDOMInthisexample,we'regoingtofindoutsomethingaboutthestateoftheapplicationfromtheDOM,grabitwithJavaScript,andwriteitbacktotheDOM.We'lllookatui.RtoputtogetherthepageandthenlookattheJavaScript.Theserver.Rfileisunchanged,sowewillnotdiscussithere.

ui.RWe'regoingtousetheGapminderapplicationwe'vebeenlookingatthroughoutthebook,butaddalittleJavaScriptmagic.We'regoingtoaddabuttonthat,whenclicked,writesthecurrentlyselectedyearsonthesummarytexttab.Let'stakealookatwhatwe'readdingtotheui.Rfile,overinthesidebarPanel()function:

tags$input(type="button",

id="append",

value="Addcurrentinputvalues",

onClick="buttonClick()"),

includeHTML("appendText.js")

Asyoucansee,weusethetags$xxx()functionthatwesawinChapter3,IntegratingShinywithHTML,inordertogenerateabuttonthatwillrunaJavaScriptactionwhenit'sclicked.ItgeneratesthefollowingHTML:

<inputtype="button"id="append"value="Addcurrentinputvalues"

onclick="buttonClick()">

Theotherfunction,whichwealsosawinChapter3,IntegratingShinywithHTML,istheincludeHTML()function.AsdescribedinChapter3,IntegratingShinywithHTML,thisfunctionallowsyoutoincludeHTMLfromafileratherthanclutteringupyourui.Rwithit.JustlikeHTML(),itpreventsShinyfromescapinganyHTMLwithinit,whichisthedefaultbehavior.Inthiscase,wearelinkingtoaJavaScriptfilecalledappendText.js.Now,wejustneedtoaddanelementtowhichtheJavaScriptcanwrite,inmainPanel():

tabPanel("Summary",textOutput("summary"),p(id="selection","Values"))

WenowhaveaparagraphelementwithanIDofselectiontowhichwecanwrite.server.Risunchanged,andsonowlet'slookattheJavaScript.

appendText.jsTheJavaScriptisverysimpleandlookslikethis:

<scripttype="text/javascript">

functionbuttonClick(){

varelem=document.getElementById('selection');

elem.innerHTML=document.getElementById('year').value;

}

</script>

YoucanseethatwegrabtheelementwiththeIDofselectionandwritethevalueoftheyeartoit.Youwill,Iamsure,wishtoproducesomethingalittlemoresophisticatedthanthis!Nowwehavethebasics,thesecondexampleisabitmorecomplex.Inthisexample,wewillbepassingmessagesdirectlybetweenserver(R)andclient(JavaScript).

Example2–sendingmessagesbetweenclientandserverInthisexample,wearegoingtousetheDOMandmessagestopassinformationbetweentheclientandserver.Theuserwillbeabletoselectanumberusingaslider.Theserverreadsthisinputandthenpicksarandomnumberbetween1andtheuser-suppliednumber.ThisnumberiswrittenbacktothescreenaswellasbeingsentinamessagetoJavaScript.

JavaScriptreceivesthisnumberandproducesadrop-downselectorthatallowstheusertoselectavaluebetween1andtherandomnumberthattheserverpicked.Everytimetheuserselectsadifferentvaluefromthisdropdown,JavaScriptwilldeciderandomlywhetheritthinksthatShinyrules!orwhether,infact,JavaScriptrules!.Thisissentasamessagetotheserver,whichpicksitupandwritesittothescreen.Clearly,thisisnotofmuchuseasarealapplication,butitshoulddemonstratetoyoutheprinciplesofsendingandreceivingmessagesandreadingandwritingtotheDOM.

Itisdefinitelyworthhavingalookattheapplicationlive.Aswithalltheapplications,itcanberunstraightfrommywebsite(chrisbeeley.net/website)wherethesourcecodecanalsobedownloaded.Hereistheapplicationinaction:

Asyoucanseeinthepreviousscreenshot,theuserhaspicked7,theserverhaspicked6outoftherangeofnumbersfrom1to7,JavaScripthasbuiltadrop-downmenuusingthatnumberofoptions,andhasalsodecidedinthiscasethatJavaScriptrules.DonotethatthisapplicationcouldquiteeasilybewritteninpureShiny,and,likemanyexamplesinthisbook,isprovidedforillustrationonly.Itisworthkeepingitsimple,soyoucaneasilyseehoweverythingfitstogetherwithoutworryingaboutunderstandingeverythingJavaScriptisdoing.

Inthiscase,theui.Randserver.Rfilesarebothprettysimpleandshouldbefairlyself-explanatory.MostofthecodeisintheJavaScriptfile.Let'squicklylookattheui.Randserver.Rfilesfirst.

ui.RThecoderunsasfollows:

fluidPage(

#flexiblelayoutfunction

h4(HTML("Thinkofanumber:</br>DoesShinyor</br>JavaScript

rule?")),

sidebarLayout(

sidebarPanel(

#sidebarconfiguration

sliderInput("pickNumber","Pickanumber",

min=1,max=10,value=5),

tags$div(id="output")#tags$XXforholdingdropdown

),

mainPanel(

includeHTML("dropdownDepend.js"),#includeJSfile

textOutput("randomNumber"),

hr(),

textOutput("theMessage")

)

)

)

Theuseofh4(HTML("XXX"))allowsustoshrinkthetitlealittleandaddsomeHTMLlinebreaks(avoidingHTMLescapingwiththeHTMLfunctionasbefore).tags$div(...)producesa<div>elementinwhichtoplacethedrop-downmenu,whichJavaScriptwillbuild.ThemainPanel()calljustcontainsareferencetotheJavaScriptfilethatwillrunonthepage,aplacetoputtherandomnumbertheserverwillpick,ahorizontalline,andamessagefromJavaScriptregardingwhetherJavaScriptorShinyrules.

server.RTheserver.Rfilerunsasfollows:

function(input,output,session){

output$randomNumber=renderText({

theNumber=sample(1:input$pickNumber,1)

session$sendCustomMessage(type='sendMessage',

message=theNumber)

return(theNumber)

})

output$theMessage=renderText({

return(input$JsMessage)

})

}

Thefirstthingtonotehereistheuseoffunction(input,output,session){...}insteadofthefunction(input,output){...}thatweareusedtoseeing.TheadditionofasessionargumentaddsaconsiderableamountoffunctionalitytoShinyapplications.Inthiscase,itallowsustosendmessagestoJavaScript.Thereismoreonthefunctionalityofthesessionargumentinthenextchapter,Chapter6,Dashboards.

Thefirstfunctionherecarriesouttwotasks.First,ittakesthenumberthattheuserselectedonthesliderandpicksarandomnumberbetween1andthatnumber.ItsendsthatnumberstraighttoJavaScriptusingthesession$sendCustomMessagefunction(whichthesessionargumentwementionedpreviouslyenables).ThesendCustomMessage()functionisdefinedwithinShiny;itisplacedaftersession$inordertotieittothesessiondefinedintheshinyServer(function(input,output,session){...})function.Finally,itreturnsthenumbertoShiny,justlikeinastandardapplication,readytobeplacedintheoutputslot,whichui.Rsetsup.

ThesecondfunctionreceivestheJavaScriptmessage.It'sveryeasytoaccess,theShinyfunctionwithinJavaScriptwritesittothestandardinput$xxxvariablename,whichweareusedtoseeingthroughoutthebook.Asisnowplain,alotoftheworkinthisapplicationisbeingdonewithintheJavaScriptfile.Let'stakealook.

dropdownDepend.jsThereisquitealotofcodeinthissectiondoingquitealotofdifferentthings,sowe'llstepthrougheachchunkinturn:

<scripttype="text/javascript">

//Shinyfunctiontoreceivemessages

Shiny.addCustomMessageHandler("sendMessage",

function(message){

//callthisbeforemodifyingtheDOM

Shiny.unbindAll();

Thefirstpartcarriesouttwofunctions;Shiny.addCustomMessageHandler("sendMessage",function(message){...})registersthemessage-handlerwithShiny.The"sendMessage"namewasdefinedintheserver.Rfunctioninthesession$sendCustomMessage(type='sendMessage',message=theNumber)call.Thisisthefirststepinreceivingandprocessingmessagesfromtheserver.

ThesecondpartbeginstheprocessofreadingandwritingtotheDOM.WheneveryouaregoingtomodifytheDOMinJavaScript,youshouldcallShiny.unbindAll()firstandthenShiny.bindAll()attheend;wewillcomeacrossthelatterfunctionlaterinthissection:

/*deletethedropdownifitalready

existswhichitwillthesecond

timethisfunctioniscalled*/

//getthedropdownandassigntoelement

varelement=document.getElementById('mySelect');

//ifitalreadyexistsdeleteit

if(element!==null){

element.parentNode.removeChild(element);

}

Inthissection,wechecktoseewhetherthedropdownhasalreadybeendrawn(whichitwillbethesecondtimethisfunctioniscalled),andifithas,wedeleteitinordertoredrawitwiththenewnumberofoptions:

//Createemptyarraytostoretheoptions

vartheNumbers=[];

//addascendingnumbersuptothe

//valueofthemessage

for(vari=1;i<=message;i++){

theNumbers.push(i);

}

//grabthedivreadytowritetoit

vartheDiv=document.getElementById("output");

Now,wecreateanarrayandfillitwiththenumbersfrom1tothevalueofmessage,whichistherandomnumberthattheserverpickedandpassedtothisfunction:

//createanewdropdown

varselectList=document.createElement("select");

//giveitanameandwriteittothediv

selectList.setAttribute("id","mySelect");

theDiv.appendChild(selectList);

//addtheoptions

for(varn=0;n<theNumbers.length;n++){

varoption=document.createElement("option");

option.setAttribute("value",theNumbers[n]);

option.text=theNumbers[n];

selectList.appendChild(option);

}

Next,wecreatethedrop-downlistandaddtheoptionstoitusingthearrayofnumberscreatedimmediatelybefore:

//addanonchangefunctiontocallshinyRules

//everytimethisinputchanges

selectList.onchange=shinyRules;

//addclasstostylenicelyinBootstrap

selectList.className+="form-control";

//callthiswhenyou'vefinishedmodifyingtheDOM

Shiny.bindAll();

}

);

Finally,weaddononchangepropertytothedropdownsothatitwillcalltheshinyRules()functioneverytimeitischanged,addtheform-controlclasstorenderthedropdownnicelyinBootstrap,andcalltheShiny.bindAll()functionnecessarywhenwehavefinishedwritingtheDOM:

shinyRules=function(){

//definetextarrayandpickrandomelement

vartextArray=['JavaScriptRules!','ShinyRules!'];

varrandomNumber=Math.floor(Math.random()*textArray.length);

//wheneverthisinputchangessendamessagetotheserver

Shiny.onInputChange("JsMessage",textArray[randomNumber]);

}

</script>

ThislastpieceofcodedefinestheshinyRules()function,which,asintheprecedingcode,willbecalledeachtimethedropdownischanged.Itsetsupatextarray,picksarandomelementfromit,andthenusestheShiny.onInputChange(...)functiontosendthiselementtotheserver.Asyoucansee,thefunctiontakestwoargumentsinthiscase:"JsMessage"andtextArray[randomNumber].

Thefirstoftheseargumentsgivesthemessageaname,soitcanbepickedupbytheserver.Rfile.Thisisthepartoftheserver.Rfilethatwesawbeforethatreadsinput$JsMessage,sotheinputisaccessedusingthestandardShinynotationofinput$xxxthatweareusedtoseeing.Ifyougobacktolookattheserver.Rfile,youcanseeacalltorenderText()thatreturnsinput$JsMessage,readytobewrittenstraighttotheoutputpaneloftheinterface.

ShinyjsWe'vealreadyseenthataslongasyouknowJavaScript,usingJavaScriptisprettyeasyinShiny.Theshinyjspackage,availableonCRAN,actuallymakesiteasytouseextrabitsofJavaScriptinyourapplicationbywritingpureRcode.Installitwithinstall.packages("shinyjs")andlet'stakealook.

ShinyjsgivesyouaccesstoquiteafewnicelittleJavaScripttricks,soseethedocumentationformore,butwe'regoingtohavealookatafewwiththehelpoftheGapminderapplication.Thefirstistheabilitytodisableandenablecontrols.Thiscanbeusefultohelpyourusersunderstandhowanapplicationworks.Forexample,inthegapminderapplication,theyearcontroldoesnotdoanythingwhenthemaptabisselected,sincethedatausedisalwaysthemostrecentdataanyway.Wecanhidethecontrol,aswesawinthepreviouschapter,Chapter4,MasteringShiny'sUIFunctions,butsometimeswemayprefertograyoutanddisablethecontrol.

Inordertouseshinyjs,weneedtocalllibrary(shinyjs)inboththeserver.Randui.Rfiles.WealsoneedtoadduseShinyjs()anywherewithinfluidPage()inui.R.Withthisdone,enablinganddisablingcontrolsisverysimpleusingtheenable()anddisable()functionsfromShinyjs.WehavenamedthetabPaneltheTabsandthemaptabmapandthereforewecantestwhetherinput$theTabsisequalto"map".Now,it'sverysimpletoturnthecontrolonoroff:

observe({

if(input$theTabs=="map"){

disable("year")

}else{

enable("year")

}

})

Anothersimpletrickischangingtheformattingoftextortables.WecandothisverysimplyusingthetoggleClass()function,whichaddsandtakesawayaCSSclassto/fromadiv.Allweneedtodoiswrapthetextoutputfromthegapminderui.Rindiv,andgiveitamemorableid("theText"):

div(id="theText",textOutput("summary"))

DefinetheCSSintheheadoftheHTMLusingtags$head():

fluidPage(

tags$head(

tags$style(HTML(".redText{

color:red;

}"

))

),

...)

Addabutton:

checkboxInput("redText","Redtext?")

Andnow,applytothenameddiv("theText")thenamedclass("redText")whenthenamedbutton(input$redText)ispressed:

observe({

toggleClass("theText","redText",input$redText)

})

Wecanalsoallowtheusertoresetsomeorallofthecontrols.Thiscanbeusefuliftheycannotrememberthedefaultsandtheywishtorestoredefaultvaluesforthecontrolswithoutrestartingtheapplication.Thisfunctionrequiresonlyadiv.Wewillplaceadivaroundtheyearslidertoallowtheusertorestoretheirdefaultseasily:

div(id="yearPanel",

sliderInput("year",

"Yearsincluded",

min=1952,

max=2007,

value=c(1952,2007),

sep=""

)

),

Now,wejustneedanactionbuttonfortheusertopress:

actionButton("reset","Resetyear")

Now,weuseobserveEvent()tolistenforthebuttonpush,andreset()toresetthevalueofthenameddiv:

observeEvent(input$reset,{

reset("yearPanel")

})

Thelastexamplewe'regoingtoshowusestheoneventfunction,whichwillrunanypieceofRcodeinresponsetoanevent.Itwillrespondtothefollowingevents:click,dblclick,hover,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,keydown,keypress,andkeyup.We'regoingtolistenforthehoverevent,whichreferstowhenthemousepointerisabovesomething.Inordertodoso,wemerelyspecifythetypeofevent,theIDofthecontrol,andthentheRfunctionwewishtorun:

onevent("hover","year",

html("controlList",

input$year,add=FALSE))

Thisfunctionlistensforahoverovertheyearcontrol,andthenexecutesthegivenfunction.ThefunctionlooksforanelementwithanIDof"controlList",andaddsthevalueoftheinputyear.Theadd=FALSEargumentisgivensothepreviousentryisoverwritteneachtime.WeaddtheelementtothetabPanelgraph:

tabPanel("Trend",value="graph",plotOutput("trend"),

p(id="controlList")),

Now,theapplicationhasalittlereadoutofthecurrentlyselectedyearsunderneaththegraph,whichupdatestothenewvaluewheneveryouhoverovertheyearcontrol:

Gapminder

ExtendshinyjsTheshinyjspackagecandomuchmorethanjustgiveyouaccesstocannedJavaScript,usefulthoughthatis.UsingtheextendShinyjs()function,youcanveryeasilyreadRinputandsendittoJavaScript.ItissimplertouseiftheV8packageisinstalled.Ifyoucannotinstallthispackage,thereisaworkaround;consultthedocumentation.

We'regoingtoimprovetheapplicationthatwejustproduced(itwillstillbejustasuseless,ofcourse!)byallowingtheusertochangethesizeandthecolorofthetext.Thefinishedapplicationlooksasfollows:

Finishedapplication

ui.RLet'sstartwiththethingstoaddtotheui.R.Onceagain,weaddaplaceforthetexttolivetothegraphtab:

tabPanel("Trend",plotOutput("trend"),

h3("Userselectionhistory"),

p(id="selection",""))

Then,weaddabuttontoaddthetextandsomecontrolstothesidebar:

actionButton("buttonClick","Addinputs"),

selectInput("color","Textcolour",

c("Red"="red",

"Blue"="blue",

"Black"="black")),

selectInput("size","Textsize",

c("Extremelysmall"="xx-small",

"Verysmall"="x-small",

"Small"="small",

"Medium"="medium",

"Large"="large",

"Extralarge"="x-large",

"Supersize"="xx-large"))

ThelastadditionisareferencetotheJavaScriptfilethatwillmakeeverythinghappen.WeaddthiswiththeextendShinyjs()function.PutitunderneathuseShinyjs(),soyoudon'tloseit:

useShinyjs(),

extendShinyjs(script="appendText.js")

Let'slooknowattheserver.Rcode.

server.RThecodehereisprettysimple:

observeEvent(input$buttonClick,{

js$buttonClick(input$color,input$size)

})

We'veseentheobserveEvent()functionbefore;itsimplylistensfortheinput$buttonClickactionbutton.Thejs()functionisdoingallthework;itsendsitsargumentstotheshinyjs.buttonClickfunctionwithintheJavaScriptfile(whichwewilllookatnext).Ingeneral,js$foosendsitsargumentstoshinyjs.foointhedefinedJavaScript.

JavaScriptLastly,let'slookattheJavaScript.Aspreviouslymentioned,shinyjs.buttonClickisafunctionthatcanaccesstheargumentsofjs$buttonClick().Withthatinmind,let'slookatthecode:

shinyjs.buttonClick=function(params){

//boilerplatecode

vardefaultParams={

color:"black",

size:"medium"

};

params=shinyjs.getParams(params,defaultParams);

//restofcode

varelem=document.getElementById('selection');

elem.innerHTML=document.getElementById('year').value;

elem.style.color=params.color;

elem.style.fontSize=params.size;

}

Notethatitisnotnecessarytoincludethe<scripttype="text/javascript">...</script>scripttagaroundtheJavaScriptinthisfile.Thefirstpartisboilerplatecode,andit'sdesignedtohandletheuseofnamedandunnamedlistswithintheRargumentsofthefunctioncall.BothareacceptedbyextendShinyjs(),sothiscodeensuresthattheyplaynicelyasJavaScript.Italsoallowsyoutoadddefaultvalues.YoucanseetheparametersfromRbeingreadintotheparamsvariablewiththeshinyjs.getParamsfunction.

Therestofthecodeisverysimple,merelygrabbingtheselectionelement,addingtexttoit,andchangingthecolorandsizeusingparams.colorandparams.size,bothbroughtthroughfromRandplacedasnamedelementswithinparams.Youwillrecalltheinput$colorandinput$sizevaluesbeingpassedasargumentswithinthejs$buttonClick()function.

Andthat'sitforshinyjs.Averysimple,powerfulwayofusingeithercannedJavaScriptorincorporatingyourownJavaScriptandreadingRinputveryeasily.

RespondingtoeventsinJavaScriptYoucanlistenforallkindsofeventsinShinyapplications,eitherfromthewindoworfromindividualelements,andrunJavaScriptcodewhentheyoccur.Forexample,youcanlistenforwhenShinymakestheinitialconnectionwiththeclient,andyoucanlistenforwhenShinyisbusyoridle.Youcanlistenforwhenaninputchanges,oranoutputrecalculates.Forafulllist,seethedocumentationatshiny.rstudio.com/articles/js-events.html.Asanexample,we'regoingtomakeaverysimpleprogramthattakesalongtimetodrawagraphandgivesyoualittlealertboxwhenitisfinished.Theprogramissosimplethatwewillusethesingle-fileapp.Rformat.Here,itisreproducedinitsentirety:

ui<-fluidPage(

titlePanel("JavaScriptEvents"),

sidebarLayout(

sidebarPanel(

actionButton("redraw","Redrawplot")

),

mainPanel(

plotOutput("testPlot"),

includeHTML("events.js")

)))

server<-function(input,output){

output$testPlot<-renderPlot({

input$redraw

Sys.sleep(5)

plot(1:10)

})

}

shinyApp(ui=ui,server=server)

Weconstructanactionbuttontorefreshthegraph,setupaverysimpleplot,andestablishadependencybetweentheplotandtheactionbuttonsoitrefresheswhentheactionbuttonispressed.TheJavaScriptfileisaddedusingtheincludeHTML()function,aswesawearlierinthechapter.

TheJavaScriptitselfisverysimple:

<scripttype="text/javascript">

$(document).on('shiny:idle',function(event){

alert('Finished!');

});

</script>

Youcanseethatthefunctionlistensforshiny:idle(whichistriggeredwhenShinyhasfinishedwhatitisdoing)anddisplaysanalerttotheuser.Ifwewished,wecouldjustlistenforthatspecificgraphbeingredrawn;thisisachievedsimplyasfollows:

$('#testPlot').on('shiny:recalculated',function(event){

alert("Finished");

});

YoucanaccessawholerangeofJavaScriptplottinglibrariesstraightfromR,andthereforefromShiny,usingthehtmlWidgetspackage.Let'shavealookatsomeofthethingsthatareavailable.

htmlwidgetsThehtmlwidgetspackageallowspackagedeveloperstoveryeasilyproducebindingsbetweenJavaScriptvisualizationlibrariesandR.IfyouwishtomakeuseofthehtmlwidgetspackagetoproduceabindingtoyourownfavoriteJavaScriptlibrary,itisarelativelysimpleprocess,thedetailsofwhichcanbefoundathtmlwidgets.org/develop_intro.html.Wewillnotlookattheprocessofproducingyourownbindingsbecausemanypopularlibrariesareavailable,andthereareplentyinthischapterthatdemonstratetheuseofexistinglibraries.Moreover,itrequirescompetencewithJavaScript,whichisnotassumedinthisbook.SufficetosaythatthehtmlwidgetspackagemakesiteasytouseJavaScriptvisualizationlibrariesfromR,includingRMarkdowndocumentsandShinyapplications.

We'vealreadyseenleafletinthisbook.Thispackagemakesuseofthehtmlwidgetspackage.Inthischapter,wewillhavealookatsomeotherusefulpackagesthatmakeuseofhtmlwidgets.Forthesakeofspace,wewilllookonlyatthefunctionalityandsomeexampleapplications,ratherthangoingthroughallofthecode.Theapplicationpicturedistheoneusedinthepreviouseditionofthisbookandallthecodeforthischaptercanbefoundatchrisbeeley.net/website/shinybookV2.html.

Wewilllookatthefollowing:

dygraphsrChartsd3heatmapthreejs

DygraphsThedygraphslibraryinJavaScript(http://dygraphs.com/)isdesignedtoshowtimeseriesandtrenddata.Itsupportszoom,pan,andmouseover,andevensupportsmobiledevicesbyofferingpinchtozoom.ThedygraphsRpackageprovidesahandyinterfacetomanyofthefunctionsofthedygraphslibrary.Itcanbeinstalledusinginstall.packages("dygraphs").

Formoreinformationaboutthedygraphspackage,seethefollowinglink,http://rstudio.github.io/dygraphs/.

Let'stakealookatanexamplegraph:

GoogleAnalytics

Thereareacoupleofthingsyouneedtomakeanoteofonthisgraph.First,youcanseethemouseovereffectatthetop-rightofthegraph,wherethedateandvaluesofNHSusersandOtherarelisted.Second,thisgraphhasbeensmoothed

usingarollingaverage.Thenumberofpointstobeaveragedisspecifiedinthewidgetontheleft-handsideofthepage(Selectrollperiod)andisgivenbydefaultinthesmallsquareboxatthebottom-leftofthegraph.Third,thegrayboxatthebottomwiththeselectoroneithersidecanbeusedtoselectdaterangesonthegraph.ThiscanbeusefulinaShinyapplicationasawayofkeepingthedaterangeofallthedataconstantsbutallowingtheusertozoominonthegraphastheychoose.Asyoucansee,thetextunderneaththegraphmakesthisdistinctionclear,reportingthenumberofdaysinthewholedataset(933)aswellasthenumberselectedonthegraphitself(578).Makingagraphuser-friendlyandinteractiveisextremelyeasyusingthedygraphspackage.

rChartsThesupportinrChartsfordifferentJavaScriptlibrariesisverybroad,andtherearemanypossibilitiesforproducingbeautiful,interactivegraphics.Here,wewilltakealookatjustoneandperusethedocumentationatramnathv.github.io/rCharts/toseethedifferentlibrariesandgraphssupportedbythepackage.

TherChartspackageisnotavailableonCRANbutcanbeinstalledveryeasilyusingthefollowingcode:

install.packages("devtools")require(devtools)install_github("ramnathv/rCharts")

Let'snowtakealookatoneofthemanyplotoutputspossiblewiththispackage:

Plotoutputs

Thisplotisaclusteredbarchartoftheselectedinput(Averagesession/Users/Sessions),showingthenumbersoneachdayandinfivedifferentcountries.ThankstothemagicofD3,theplotisinteractiveoutofthebox.Itsupportsmouseover,asshowninthescreenshot,withJapan'sresultsforWednesdayhighlighted.TheplotcanbechangedfromGroupedtoStacked(thatis,differentdaysgroupedhorizontallyorvertically),andthedaysoftheweekcanbehiddenandshownbyclickingonthematthetopinthelegendofthegraph.

d3heatmapThed3heatmappackageusesvanillaD3andproducesinteractiveheatmaps.Itcanbeinstalledusinginstall.packages("d3heatmap").

Formoreinformationaboutthed3heatmappackage,seethefollowinglink,http://htmlwidgets.org/showcase_d3heatmap.html.

Hereisanexample:

Heatmap

Mouseovergivestheindividualvalueswithintheheatmap.

threejsThethreejspackage,asdiscussedatthebeginningofthechapter,canbeusedtoproduce3Dscatterplotsorplotsonglobemappings(includingEarthandcelestialbodies).Itcanbeinstalledusinginstall.packages("threejs").Inordertoproducetheglobeoutputthatisshowninthescreenshot,itisnecessarytoalsoinstallmapsusinginstall.packages("maps").Anexampleisshownhere:

Globe

Thevisualizationiscompletelyinteractiveandcanbespunwithamousedrag.

SummaryInthischapter,weusedJavaScripttoreadandwritetheDOM,andsendmessagesbackandforthwiththeserver.Weexploredhowtogetthemostoutoftheshinyjspackage,aswellashowtolistenforeventswithJavaScript.Lastly,wetalkedaboutthehtmlwidgetspackage,andshowedsomeexamplesofsomeofthegraphicsyoucanproduceusinghtmlwidgets-enabledRpackages.

Inthenextchapter,wewilllookathowtobuilddashboardsinShiny.

DashboardsThischapterisallaboutlayingoutyourShinyapplications.InChapter4,MasteringShiny'sUIFunctions,wealreadylookedatdoingitbyhand,usingHTMLorCSS,andwealreadysawhowtolayoutapplicationsusingtheBootstrapgridsystem.Shiny(anditsassociatedpackages)includesloadsoffunctionsthatallowyoutolayoutyourapplicationsbeautifullyandsimply.Thischaptertakesthecodeandapplicationsyouhavealreadyseenandchangesthemfromtheveryplain,vanilla-lookinglayoutthatthedefaultstylingreturnstoslick,customizablelayouts,culminatinginafull-featureddashboard.

Inthischapter,wewilldothefollowing:

MakeadashboardveryeasilyusingtheflexdashboardtemplateAddiconstoapplicationsFurtherexploreShinyusingtheBootstrapgridsystemtolayoutapplicationsBuildadashboardtohelpyourusersaccessalltheinformationtheyneedfromwithinthesameintuitiveinterface

ApplicationsinthischapterInordertobetterunderstandthelayoutfunctionsinparticular,we'renotgoingtoaddanyfunctionalityinthischapter.We'llstartoffwiththevanillaGapminderapplicationwehavebeenusingthroughoutandwe'llapplydifferenttypesoflayouttoit,soyoucanseehowtheywork.Asweprogress,wewilladdoneortwoextrafeatures.However,wewillmainlyfocusonlookingatthesameapplicationbutwithdifferenttypesoflayoutfunctionsappliedtoit.

Itishighlyrecommendedthatyoudownloadandrunallthecodeinthischapter,soyoucangetabettersenseofhowtheapplicationswork,aswellasseeingtheserver.Rcodeineachcase,whichwon'tberepeatedforeachapplication.Ifyou'renotinfrontofacomputerwhilereadingthissection,hopefullythereareenoughscreenshotsandexplanatorymaterialtokeepyougoinguntilyoucanseetheapplicationsinactionforyourself.

FlexdashboardsFlexdashboardsareasimpleRMarkdowntemplateandmakelayingoutdashboards(withorwithoutinteractivityfromShiny)verysimple.Formoreinformationaboutflexdashboards,gotormarkdown.rstudio.com/flexdashboard/.CreatingaflexdashboardinRStudioisincrediblyeasy.First,installthepackagewithinstall.packages("flexdashboard").Then,justselectfromFile|NewFile|RMarkdown...|FromTemplate|FlexDashboard|OK:

AswithmostRStudiodocuments,itcomesprefilledwiththeboilerplatecodetomakethestructureofadashboard.Youcanseethestructurestraightawayifyoulike,byclickingKnitinRStudio(orbycallingrmarkdown::render("yourFileName.Rmd")).

Theboilerplatedashboardlookslikethis:

Let'smakeaverysimplestaticdashboardfirsttolearnmoreaboutit,andthenwe'lllookatsomemoreadvancedlayoutfeaturesandaddsomeinteractiveShinyelements.Hereisthefinisheddashboard:

I'veusedthedefaultlayoutthatisreturnedwhenyouselectaflexdashboardtemplate,whichisstructuredverysimplylikethis,bymodifyingtheheadings:

Column{data-width=650}

-----------------------------------------------------------------------

###Lifeexpectancyovertime

```{r}

*Code*

```

Column{data-width=350}

-----------------------------------------------------------------------

###Lifeexpectancy

```{r}

*Code*

```

###GDPpercapita

```{r}

*Code*

```

Asyoucansee,thedashboardislaidoutincolumns,withthewidthdefinedin{}bracketsateachcolumndefinition.Chunksaredefinedasyou'dexpectinanyRMarkdowndocument,with###asaheadingand```{r}...```wrappingthecode.Flexdashboardwillneatlyarrangetheoutputforyouincolumns.

Simple!Now,let'slookatdoingsomethingabitdifferentwiththelayout,and

we'lladdsomeShinyatthesametime.ToturnaflexdashboardintoaShinydashboard,justaddruntime:shinytotheoptionsatthetop(thispartofthedocumentiscalledtheYAMLheader).Whilewe'rehere,let'salsolayouttheapplicationwithrows,ratherthancolumns.Simplychangeorientation:columnstoorientation:rows.

So,nowyourheadershouldlooklikethefollowing:

---

title:"Shinygapminder"

runtime:shiny

output:

flexdashboard::flex_dashboard:

orientation:rows

vertical_layout:fill

---

Let'snowdefineacolumnwithasidebarandplaceourcontrolsinitasnormal,asfollows:

```{rsetup,include=FALSE}

library(flexdashboard)

library(leaflet)

```

Column{.sidebar}

-----------------------------------------------------------------------

```{r}

sliderInput("year",

"Yearsincluded",

min=1952,

max=2007,

value=c(1952,2007),

sep="",

step=5

)

checkboxInput("linear",label="Addtrendline?",value=FALSE)

```

Andnow,wecanaccessthosevaluesasnormalintheoutput.Oneoftheoutputvaluesisdefinedasnormal,exceptasarowratherthanacolumn:

Row

-----------------------------------------------------------------------

###Lifeexpectancyovertime

```{r}

renderPlot({

thePlot=mapData%>%

filter(year>=input$year[1],year<=input$year[2])%>%

group_by(continent,year)%>%

summarise(meanLife=mean(lifeExp))%>%

ggplot(aes(x=year,y=meanLife,group=continent,colour=continent))+

geom_line()

if(input$linear){

thePlot=thePlot+geom_smooth(method="lm")

}

print(thePlot)

})

```

Notethat,inthiscase,wecan'tdefineareactiveobjecttofiltertheyearvalues,aswedidbefore,sowefilterbydatewithineachoutputitem(whichisbadcodingpracticeinanormalShinyapplication,ofcourse).We'llputtheotheroutputitemsinatabset,asfollows:

Row{.tabset}

-----------------------------------------------------------------------

###Lifeexpectancy

```{r}

renderLeaflet({

mapData%>%

filter(year==input$year[2])%>%

leaflet()%>%

addTiles()%>%

setView(lng=0,lat=0,zoom=2)%>%

addCircles(lng=~lon,lat=~lat,weight=1,

radius=~lifeExp*5000,

popup=~paste(country,lifeExp))

})

```

###GDPpercapita

```{r}

renderLeaflet({

mapData%>%

filter(year==input$year[2])%>%

leaflet()%>%

addTiles()%>%

setView(lng=0,lat=0,zoom=2)%>%

addCircles(lng=~lon,lat=~lat,weight=1,

radius=~log(gdpPercap)*25000,

popup=~paste(country,gdpPercap))

})

```

Andthat'sit.Prettysimple.Thefinishedarticlelookslikethis:

It'saprettysmart-lookingdashboard,consideringhowsimpleitistocode.Therearelotsmoreoptionsforflexdashboards,includingtheuseofShinymodules(coveredinChapter8,CodePatternsinShinyApplications)aswellasdifferentmethodsoflayingoutflexdashboards.Visitthelinkgivenpreviouslyformoreinformation.Fortherestofthischapter,wewillbelookingatfullShinyapplications.

SidebarapplicationwithextrastylingAsawarmup,we'llsticktoasimplelayoutwithasidebarfornow.Asweprogressthroughthischapter,we'llchangethelayoutandmakeitmorelikeamoderndashboard.Becausewe'renotdoingtoomuchinthewayoffeaturesorlayoutinthisfirstapplication,we'lladdafewvisualbellsandwhistles.SomeofthemwillbedroppedinlaterversionsoftheapplicationjusttostopthecodeandUIfrombecomingtoocluttered,butyoucanofcoursewriteanapplicationyourselfwithalloftheUIelementsinifyouwishto.Allofthecodeanddatafortheapplicationsinthischapterisavailableatchrisbeeley.net/website/.

AddingiconstoyourUIAswegothroughthevariousUIelementslater,we'regoingtosprinkleafewiconsthroughout,justtogivethepageabitmorevisualinterest.Iconscancomefromtwoiconlibraries,locatedatfontawesome.io/icons/andgetbootstrap.com/components/#glyphicons.Theycanbeaddedsimplyusingtheicon()commandwiththenameoftherequiredicongivenasastring.

Forexample,icon("user")willbydefaultreturniconsfromtheFontAwesomelibrary,andtousetheglyphicons,simplyaddlib="glyphicon"asfollows:

icon=icon("user",lib="glyphicon")

TheycanbeaddeddirectlytoyourUIoronbuttons(includingthebuttonsatthetopoftabpanels).Fromthefullcodeofthisapplication,youcanseethatwehavereplacedtheboringhorizontalrule,whichseparatedourinputwidgets,withaspinningLinuxpenguin(because,woo!Linux!)usingclass="fa-spin".TheclassargumentcomesfromtheuseofCSSclassestovarythecharacteristicsofFontAwesomeicons.Theexamplesaregivenatfontawesome.github.io/Font-Awesome/examples/.YoucanalterthesizeofFontAwesomeiconswithclass="fa-lg"(onethirdlarger),class="fa-2x"(twiceaslarge),class="fa-3x",anduptoclass="fa-5x".Puttingthemtogether,wegetthefollowing:

icon("linux",class="fa-spinfa-3x")

Now,let'slookatstylingyourapplicationveryeasilyusingshinythemes.

UsingshinythemesLet'sgivethewholeapplicationalickofpaintusingtheshinythemespackage.Ifyouhaven'talreadydoneso,installitwithinstall.packages("shinythemes").Thedocumentation(includingalistoftheavailablethemes)canbefoundatrstudio.github.io/shinythemes/.LoadthepackageandpassathemeintofluidPage():

library(shinythemes)

fluidPage(

theme=shinytheme("darkly"),

...restofUI...

Ifyouwanttochooseyourthemeinteractively,insteadaddthemeSelector()toyourUIdefinition,andalittleinteractivechooserwillappearonyourapp.Onceyou'rehappywithit,usethepreviouscodeformattomakethatthedefaultchoiceinyourapp:

library(shinythemes)

fluidPage(

themeSelector(),

...restofUI...

Enjoyyournewthemeandconsultthedocumentationfortheotheravailablethemesandtheappearanceofeach.

Andhere'sthefinishedapplication,showingthespinningpenguinandtheuserandcalendaricons,aswellasthethemechooserandoneofthethemes:

UsingthegridlayoutInthenextversionoftheapplication,we'regoingtousethefluidRow()functiontoapplyacustomlayouttotheUI.ThisfunctionallowsyoutoimplementthestandardBootstrapgridlayout,aswesawinChapter4,MasteringShiny'sUIFunctions.

Thewidthofthescreenisgivenas12units,andyoucanpassthecolumn()functionsofarbitrarysizeintoafluidRow()instructiontodefineagroupofwidthsaddingupto12.Inthissimpleexample,wewillhavethreecolumnsinthefirstrowandthenoneinthesecondrow.Thefinishedapplicationlookslikethis:

ui.RLet'slookattheui.Rfilenecessarytoachievethis.Theserver.Rfileremainsthesameasinthepreviousexample.We'lltakebreaksaswestepthroughthecodetounderstandwhat'shappening.We'lldefinethetitlealittledifferentlyhere,justtomakethingsabitdifferent.Theactualtitleitselfgoesintheh2()HMTLhelperfunction,andweusestandardinlinemarkuptoselectthefont,color,andsize,asshown.ThetitleisgivenasanargumenttothefluidPage()function;thisgivesthebrowserwindowitstitle(it'sautomaticallysetbytitlePanel(),butwe'renotusingthathere):

fluidPage(

title="Gapminder",

h2("Gapminderexplorer",

style="font-family:'Impact';color:purple;font-size:32px;"),

Now,weaddinarowofUIelementsusingthefluidRow()functionanddefinetwoequalcolumnswithinthisrow.NoticetheuseofwellPanel()aroundsliderInput().Thisplacestheinputinsideapanelandgivesitabetter,moredefinedappearancenexttotheotherUIelements,aswellasfillingthehorizontalwidthofthecolumn:

fluidRow(

column(6,

wellPanel(

sliderInput("year",

"Yearsincluded",

min=1952,

max=2007,

value=c(1952,2007),

sep="",

step=5

))

),

column(6,

p("Mapdataisfromthemostrecentyearintheselectedrange",

style="text-align:center;"))

Next,weaddahorizontalruletobreakthescreenupabitandthetwooutputitems,boththemselvesplacedwithinfluidRow():

hr(),

fluidRow(

column(6,plotOutput("trend")),

column(6,leafletOutput("map"))

),

Andaddonemorefluidrow,toplaceacheckboxwhereyoucanchooseifyouwantatrendlineandthetextualsummary,bothplacedheresotheyareunderneaththerelevantgraph:

fluidRow(

column(6,

checkboxInput("linear",label="Addtrendline?",

value=FALSE),

textOutput("summary")

)

)

FulldashboardThiswillbethemostfull-featuredapplicationinthischapterandhasthelongestserver.Rfile.

Ideally,downloadtheapplicationcodeavailableatchrisbeeley.net/website/andrunitonyourmachine,orvisitahostedversion,alsoonthesite.Thereisquiteabitofnewfunctionalityinthisapplication,soit'sagoodideatoexploreitnow.

Ifyoucan'tdothis,therefollowsabriefoutlineofthenewfunctionalityintheapplication:

Notificationsinthetop-rightoftheinterfaceLargefriendlyicons(informationboxes)forkeyfigureswithicons(calendar,person,piechart,Shinyversion,andsoon)Agauge

Thefinisheddashboardlookslikethis:

We'llstartbylookingatthecodeforeachoftheseadditionsandthenmoveontolookathowthewholeUIisputtogetherusingtheshinydashboardpackage.

NotificationsTheabilitytocreatenotificationsispartofalargeramountoffunctionalitywithinshinydashboard,whichallowsyoutocreatemessages,tasks,andnotificationsintheheaderofyourdashboard.Formoredetails,visitrstudio.github.io/shinydashboard/structure.html.

Inthisexample,we'lljustaddnotifications.Thecodeisverysimilartotheothertwotypesofcontent.StaticnotificationscanbeproducedwiththenotificationItem()functionasfollows(withtheoptionalstatusandcolorargumentsnotusedhere):

notificationItem(text="3userstoday",icon("users"))

Inordertoproducecontentdynamically,weneedtodoabitmorework.Ontheserver.Rside,thecodeisasfollows.Itallowsthenotificationcontenttoberendereddynamicallyandcalledintheui.RfilewithdropdownMenuOutput("notifications"):

output$notifications<-renderMenu({

countries=length(unique(theData()$country))

continents=length(unique(theData()$continent))

notifData=data.frame("number"=c(countries,continents),

"text"=c("countries","continents"),

"icon"=c("flag","globe"))

notifs<-apply(notifData,1,function(row){

notificationItem(text=paste0(row[["number"]],row[["text"]]),

icon=icon(row[["icon"]]))

})

dropdownMenu(type="notifications",.list=notifs)

})

Thevaluesneedfirsttobeplacedwithinadataframe,asshown.Thedynamicelementisgivenbycountriesandcontinents,definedasthenumberofcountriesandcontinents,respectively.Textdescribingwhatthevaluerepresentsandaniconarealsoaddedtothedataframe.Thefinalnotifsvalueisproducedusingafunctionthat'sgivenasanexampleinthehelpfiles,asyoucanseeititerateovertherowsofthedataframeandchangethenotificationsintothecorrectvalue.Asyoucansee,thedataframethatweproducedisprocessedrow-wisewiththe

appropriatevaluesfortextandiconbeingproduced(text="142countries",icon="flag",andtext="5continents",icon="globe").Finally,theyaregiventodropdownMenu()astheargumentto.list.Noticethatwealsodefinethetypeastype="notifications".

Havingdoneallthis,theactualnotificationsarepassedintotheheaderintheui.Rfilequitesimply,likethis:

header<-dashboardHeader(title="Gapminder",

dropdownMenuOutput("notifications"))

Thislooksalittledifferenttotheusualstructurethatwehaveencountered,whichisbecause,unlikestandardShinyinterfaces,Shinydashboardsareconstructedfromthreeseparatesections:dashboardHeader(),dashboardSidebar(),anddashboardBody().WewilllookindetailattheconstructionofaShinydashboardinthesectiononui.Rlater.

InfoboxesWehavealreadyseenhowtouseiconsearlierinthischapter,butshinydashboardmakesanicefeatureofitbyexpandingandcoloringiconstodrawattentiontokeypiecesofinformation.Aninfoboxcanbedrawnstaticallyasfollows:

infoBox(width=3,"Shinyversion","1.1.0",

icon=icon("desktop"))

Asyoucansee,thewidthcanbeset(usingthe12spanrulefromthestandardBootstrapfunctionswesawearlierinthischapter)withatitle(Shinyversion)andvalue(1.1.0)(althoughyoumayoftenwishtopassanumber).ThisfunctionisplacedwithindashboardBody()intheui.Rfile.Formoreinformationontheargumentsofthisfunction,type?infoBoxintotheconsole.

Althoughyoumaysometimeswishtohardcodeinfoboxesinthisway(toshowversionnumbersofanapplication,asinthiscase),inthemajorityofcases,youaregoingtoproducethiscontentdynamically.Inthiscase,youwillasalwaysneedtodosomepreparationonserver.Rfirst.Hereisthecodeforthefirstinfobox:

output$infoYears<-renderInfoBox({

infoBox(

"Years",input$year[2]-input$year[1],

icon=icon("calendar",lib="font-awesome"),

color="blue",

fill=ifelse(input$year[2]<2007,

TRUE,FALSE)

)

})

Thefirsticonisthenumberofdayswithinthespecifiedrange.Thefirstargumentgivestheiconatitle,Years,andthesecondgivesitavalue(thenumberofyears,calculatedbysubtractingthefirstyearfromthesecond).Youcanalsoselectthecoloroftheboxandwhethertheright-handportion(whichcontainsthetext,asopposedtotheicon)isfilled(asolidcolor)ornot.

Asyoucansee,herewearedecidingthefillofthevalueportionoftheicondynamically.Whenthelargestyearintherangeislowerthan2007,theiconwillbefilled.Ifitisn't,itwon't.See?ifelseforhelpwithifelse().

Theotherdynamicinfoboxesaresetupinthesameway,asfollows:

output$infoLifeExp<-renderInfoBox({

infoLifeExp=theData()%>%

filter(year==2007)%>%

group_by(continent)%>%

filter(continent==input$continent)%>%

pull(lifeExp)%>%

mean()%>%

round(0)

infoBox(

"LifeExp.(2007)",infoLifeExp,

icon=icon("user"),

color="purple",

fill=ifelse(infoLifeExp>60,

TRUE,FALSE)

)

})

output$infoGdpPercap<-renderInfoBox({

infoGDP=theData()%>%

filter(year==2007)%>%

group_by(continent)%>%

filter(continent==input$continent)%>%

pull(gdpPercap)%>%

mean()%>%

round(0)

infoBox("GDPpercapita",

infoGDP,

icon=icon("usd"),

color="green",

fill=ifelse(infoGDP>5000,

TRUE,FALSE)

)

})

ui.RTheui.Rfiletodisplaydynamicinfoboxesissimilartothefunctionwealreadysawtodisplaystaticinfoboxes,exceptnowthefunctionisinfoBoxOutput().Puttingallfourinfoboxestogether,wenowgetthefollowing:

fluidRow(

infoBoxOutput(width=3,"infoYears"),

infoBoxOutput(width=3,"infoLifeExp"),

infoBoxOutput(width=3,"infoGdpPercap"),

infoBox(width=3,"Shinyversion","1.1.0",

icon=icon("desktop")))

Aselsewhere,ineachcaseinfoBoxOutput()isgivenastring(infoYears),whichreferstothenameofthecorrespondingoutputelement(output$infoYears).

GoogleChartsgaugeThegaugewithGDPpercapitaisfromtheexcellentGoogleChartsAPI.Moreinformationonthiscanbefoundatdevelopers.google.com/chart/.Fortunatelyforus,thereisanRpackagetointerfacewithGoogleCharts,sothereisnoneedtogetourhandsdirtywithadifferentAPI.ThepackageisonCRANandcanbeinstalledwithinstall.packages("googleVis").

Installandloaditnow.Thecodeisasfollows:

output$gauge=renderGvis({

infoGDP=theData()%>%

filter(year==2007)%>%

group_by(continent)%>%

filter(continent==input$continent)%>%

pull(gdpPercap)%>%

mean()%>%

round(0)

df=data.frame(Label="GDP",Value=infoGDP)

gvisGauge(df,

options=list(min=0,max=50000,

greenFrom=5000,greenTo=50000,

yellowFrom=5000,yellowTo=25000,

redFrom=0,redTo=5000))

})

Adataframeisproduced,withthefirstcolumnbeingthelabelforthegauge,andthesecondthevalueofthegauge.Ifyourequiremorethanonegauge,simplyincludemultiplerows.Inthiscase,wewilljustuseonerow.Thegaugeisdrawnverysimplybypassingthedataframeandalistofoptions,whicharefairlyself-explanatory,givingtheminimumandmaximumforthegauge,aswellasthelimitswherethegaugeisgreen,yellow,andred,ifdesired.Thegaugeisdrawnverysimplyinui.RusinghtmlOutput("gauge").

ResizingtheGooglechartSofar,sosimple.However,thereisaproblem!Googlevisualizationcharts,unlikenativeRvisualizations,arenotautomaticallyresizedwhenthebrowserwindowchanges.We'regoingtofixthisproblemverysimply,usingsomevaluesthatwecanextractfromthesessionargumentoffunction(input,output,session){...}.Shinymakeslotsofthingsavailableinthisvariable,andoneofthemostusefuloftheseissession$clientData.Thistellsyoulotsofthingsaboutyouruser'sbrowser,suchasthepixelratio,aswellastheheightandwidthofindividualoutputelementswithintheapplication.Formoreontheusesofthesessionargument,seeshiny.rstudio.com/reference/shiny/1.0.2/session.html.Inourcase,allweneedtodoisestablishadependencyonsomethingwithinthisclientdata,whichwillchangewheneverthebrowserwindowresizes.

Inthiscase,output_trend_widthisperfect.Thisisthewidthofthelineplotshowinglifeexpectancyovertime.Thesevariablesarenamed,forexample,output$clientData$output_nameOfOutput_width.Whenthebrowserisresized,thispropertywillchange.We'renotreallyworriedaboutheightbecausethereisn'tanythingtobumpagainstthegaugebelowit,onlytotheleftandright.Thecodetodrawthegaugethereforebecomesasfollows:

output$gauge<-renderGvis({

#dependenceonsizeofplotstodetectaresize

session$clientData$output_trend_width

[...asbefore...]

})

Changingthewidthofthebrowserwindowwillnowredrawthegauge,whichwillmakeittherightsizeagain.

ui.RHavingexaminedallthenewelements,wecanhavealookathowShinydashboardsareputtogether.Aswasbrieflymentionedpreviously,Shinydashboardsarecomposedofthreepieces;dashboardHeader(),dashboardSidebar(),anddashboardBody().Theycanbeputtogetherlikethis:

dashboardPage(

dashboardHeader([...]),

dashboardSidebar([...]),

dashboardBody([...])

)

Or,theycanbeputtogetherlikethis:

#producecomponents

header<-dashboardHeader([...])

sidebar<-dashboardSidebar([...])

body<-dashboardBody([...])

#assemble

dashboardPage(header,sidebar,body)

Personally,Ihaveastrongpreferenceforthelatterformat,sinceitseemstometomakethecodesimplerandeasiertoread(nottomentionwithlessindentation),butyoumayprefertheotherway.

Wealreadysawtheheaderpartoftheapplicationpreviously;thisisreproducedinthefollowingcodeforconvenience.Notealsothat,unlikeinmanyShinyapplications,itisnecessarytoloadseveralpackagesintheui.Rfilebecausetherearespecialfunctionswithinthosepackages,whichgetcalledwiththefile(forexample,dashboardHeader(),leafletOutput(),andothers).Thetopoftheui.Rfilethereforelooksasfollows:

library(shinydashboard)

library(leaflet)

header=dashboardHeader(title="Gapminder",

dropdownMenuOutput("notifications"))

Thesidebarcancontaininputwidgets,asistypicalinShinyapplications,butalsobuttonstoselectdifferenttabsofthedashboard,eachofwhichcanbesetuptohavedifferentoutputelementsonit.Inthiscase,wehavetwotabs:themainonecontainsthegraphsandiconswehavespentmostofthissectiondiscussing,

andthemaptabcontainingtheinteractiveleafletmap.

Thecodeisasfollows:

sidebar<-dashboardSidebar(

sidebarMenu(

menuItem("Dashboard",tabName="dashboard",

icon=icon("dashboard")),

menuItem("Map",icon=icon("globe"),tabName="map",

badgeLabel="beta",badgeColor="red"),

Thefirsttwoitemsaretabbuttonsthatwillallowustopresentdifferentsetsofoutputelementstousers.Eachisgivenatitle(DashboardandMap),aname(dashboardandmaps),andanicon(dashboardandglobe).Theseconditemcangiveusersextrainformationaboutthetab—inthisexample,showingthattheoutputelementsonthattabarestillinbeta,usingthebadgeLabelandbadgeColorarguments,givingaredbetainthiscase.

Therestofthesidebarsetupisfamiliarfrompreviousincarnationsofthisapplication,asfollows:

menuItem("Map",icon=icon("globe"),tabName="map",

badgeLabel="beta",badgeColor="red"),

sliderInput("year",

"Yearsincluded",

min=1952,

max=2007,

value=c(1952,2007),

sep="",

step=5

),

selectInput("continent","Selectcontinent",

choices=c("Africa","Americas","Asia",

"Europe","Oceania"))

I'veaddeda"continent"selector,whichtheinfoboxesandgaugerespondto,showingtheaveragelifeexpectancyandGDPpercapitafortheselectedcontinent.Finally,dashboardBodyissetupusingatabItems(tabItem(),tabItem())structure:

body=dashboardBody(

tabItems(

tabItem(tabName="dashboard",

fluidRow(

infoBoxOutput(width=3,"infoYears"),

infoBoxOutput(width=3,"infoLifeExp"),

infoBoxOutput(width=3,"infoGdpPercap"),

infoBox(width=3,"Shinyversion","1.1.0",

icon=icon("desktop"))),

fluidRow(

box(width=10,plotOutput("trend"),

checkboxInput("linear",

label="Addtrendline?",

value=FALSE)),

box(width=2,htmlOutput("gauge"))

)

),

tabItem(tabName="map",

box(width=12,leafletOutput("map"),

p("Mapdataisfromthemostrecentyearintheselectedrange"))

)

)

)

Eachtabitemwillbepassedintohere;inthiscase,wehavetwo,aswesawinthepreviouscode-dashboardandmap.Nowyoucanputanythingyoulikeinit.Inthiscase,wehaveafluidrowwithfourinfoboxesofwidthof3(thetotalwidthbeing12,ofcourse).Thefirstthreearethedynamicinfoboxesthatwesetupintheserver.Rfile,andthethirdisastaticversion.Thecodeforthestaticversion,too,isfeaturedearlierinthissection.Wefinishthetabitemwithanotherfluidrow.Notetheuseofthebox()functionthatdrawswhiteboxesaroundtheelementsofadashboard.

Wefinishwiththefinaltab,map,which,ascanbeseen,containsjustoneboxwiththemapinandacommentaboutthedatainthemap.

SummaryInthischapter,weexploredmanydifferentwaysoflayingoutthesameapplications.WelookedatbothstaticandShiny-basedinteractiveflexdashboards.Startingwiththestandardsidebarlayout,welookedataddingiconsandusingtheshinythemespackagetoquicklystyleavanillaapplication.Weexploredthefunctionalityoftheshinydashboardpackage,whichallowsyoutoproducetabbedoutputsections;addintasks,notifications,andmessagesforyourusers;showlargefriendlyiconswithkeyinformationon;andprovideanattractiveandprofessional-lookingdefaultappearance.

Thekeytomakingthemostofthematerialinthischapter,aswellasofShinygenerally,istorememberthatyoucancombinethetoolsthatShinygivesyouinalotofdifferentways,dependingonyourneedsandyourskillset.There'snothingtostopyoufromusingtheshinydashboardpackagewithsomehighlycustomizedHTMLinoneofthetabsifyouneedtoverypreciselybuildaparticularkindofinterface.Somedevelopers,whohavemoreexperiencewithJavaScriptthanwithR,mayprefertoworkwiththeGoogleChartsAPIinJavaScriptanduseShinyasjustadataworkhorse,servingdataorstatisticsstraighttotheJavaScriptfunction.Thinkaboutwhatyouneed,andtherewillusuallybeacoupleofwaystoachieveit.Thesolutionyoupickwillbebasedpartlyonproducinganapplicationthatissimple,clean,andeasytomaintainanddebug.

Inthenextchapter,wearegoingtolookatgettingthemostoutofShinybyusingcustomURLstrings,producinginteractiveplots,addingpasswords,downloadinganduploadingdata,andmore.

PowerShinyInthischapter,wearegoingtolearnmanypowerfulfeaturesofShiny.Wewillstartwithanimatingplots.Afterthat,wewilldiscusshowtoreadclientinformationandgetrequestsinShiny.Nowadays,tellingastoryaboutthedataininteractiveandreportingwaysisindemand.So,wewillgothroughgraphicsandreport-generation,andhowtodownloadthemusingknitr.Downloadinganduploadingisalsoaninterestingpartofanyapplication,whichwewillseeusingsomeexamples.Bookmarkingthestateoftheappisanadd-ontoregeneratetheoutputontheapp.Wewillseeademonstrationofthefastdevelopmentofappsusingwidgetsandgadgets.Attheendofthechapter,wewilllookathowtoauthenticatetheappusingapassword.

Inthischapter,wewillcoverthefollowingtopics:

AnimationReadingclientinformationandGETrequestsinShinyCustominterfacesfromGETstringsDownloadinggraphicsandreportsDownloadablereportswithknitrDownloadinganduploadingdataBookmarkingInteractiveplotsInteractingwithtablesLinkinginteractivewidgetsShinygadgetsAddingapassword

AnimationAnimationissurprisinglyeasy.ThesliderInput()function,whichprovidesanHTMLwidgetthatallowsustoselectanumberalongaline,hasanoptionalanimationfunctionthatwillincrementavariablebyasetamounteverytimeaspecifiedunitoftimeelapses.Thisallowsyoutoveryeasilyproduceagraphicthatisanimated.

Inthefollowingexample,wearegoingtolookatthemonthlygraphandplotalineartrendlinethroughthefirst20%ofthedata(0-20%ofthedata).Then,wearegoingtoincrementthepercentagevaluethatselectstheportionofthedataby5%andplotalinearthroughthatportionofdata(5-25%ofthedata).Then,incrementby10-30%andplotanotherline,andsoon.

Thesliderinputissetupasfollows,withanID,label,minimumvalue,maximumvalue,initialvalue,stepbetweenvalues,andtheanimationoptions,givingthedelayinmillisecondsandwhethertheanimationshouldloop:

sliderInput("animation","Trendovertime",

min=0,max=80,value=0,step=5,

animate=animationOptions(interval=1000,

loop=TRUE))

Havingsetthisup,theanimatedgraphcodeisprettysimple,lookingverymuchlikethemonthlygraphdataexceptwiththelinearsmoothbasedonasubsetofthedatainsteadofthewholedataset.Thegraphissetupasbeforeandthenasubsetofthedataisproducedonwhichthelinearsmoothcanbebased:

groupByDate<-group_by(passData(),YearMonth,networkDomain)%>%

summarise(meanSession=mean(sessionDuration,na.rm=TRUE),

users=sum(users),

newUsers=sum(newUsers),sessions=sum(sessions))

groupByDate$Date<-as.Date(paste0(groupByDate$YearMonth,"01"),

format="%Y%m%d")

smoothData<-groupByDate[groupByDate$Date%in%

quantile(groupByDate$Date,

input$animation/100,

type=1):quantile(groupByDate$Date,

(input$animation+20)/100,

type=1),]

Wewon'tgettoodistractedbythiscode,butessentially,itteststoseewhichofthewholedaterangefallsinarangedefinedbypercentagequantilesbasedonthesliderInput()values.Takealookat?quantileformoreinformation.

Finally,thelinearsmoothisdrawnwithanextradataargumenttotellggplot2tobasethelineonlyonthesmallersmoothDataobjectandnotthewholerange:

ggplot(groupByDate,aes_string(x="Date",

y=input$outputRequired,

group="networkDomain",

colour="networkDomain"))+geom_line()+

geom_smooth(data=smoothData,

method="lm",colour="black")

Notbadforafewlinesofcode.Wehavebothggplot2andShinytothankforhoweasythisis.

ReadingclientinformationandGETrequestsinShinyShinyincludessomeveryusefulfunctionalitythatallowsyoutoreadinformationfromaclient'swebbrowser,suchasinformationfromtheURL(includingGETsearchrequests)andthesizeofplotsinpixels.

Allyouneedtodo,asbefore,isrunshinyServer()withasessionargument.Thiscauses,amongotherthings,anobjecttobecreatedthatholdsinformationaboutaclient'ssession,namedsession$clientData.

Theexactcontentofthisobjectwilldependonwhatisopenonthescreen.Thefollowingobjectswillalwaysexist:

url_hostname#hostname,e.g.localhostorchrisbeeley.net

url_pathname=#path,e.g./or/shiny

url_port=#portnumber(8100forlocalhost,canoptionally

#changewhenhosting,seechapter5)

url_protocol=#highlylikelytobehttp:

url_search=#thetextafterthe"?"intheURL.Inthe

following

#examplethiswillread"?person=NHS&smooth=yes".

Differentoutputtypeswillyielddifferentinformation.Plotswillgivethefollowinginformation,amongotherreturnvalues:

output_myplot_height=#inpixels

output_myplot_width=#inpixels

Therearemanyapplicationstowhichthisinformationcanbeput,suchasgivingdifferentUIsordefaultsettingstousersfromdifferentdomains,orconfiguringgraphsandotheroutputbasedontheirsize(forexample,foruserswhoareusingmobiledevicesor32"monitors).We'regoingtolookatperhapsthemostobviousandpowerfuluseofclientdata:thesearchstring.

CustominterfacesfromGETstringsInthisexample,we'regoingtoproduceURLsthatallowShinytoconfigureitselfwhentheuserlandsonthepagetosavethemfromhavingtosetuptheirpreferenceseachtime.Wewillmakeuseoftwovariables:onespecifiesthatauserisonlyinterestedindatafromtheNHSnetworkdomainandtheotherspecifiesthattheuserwantsasmoothinglinepresentontheirtrendgraph.Userswhorequestasmoothinglinewillalsobetakenstraighttothetrendlinetab.

AswellastheworkwiththeGETquery,theonlyextrabitwewillneedhereisafunctiontochangetheselectedpanelfromtabsetPanel().Thisisdone,unsurprisingly,usingupdateTabsetPanel().

CateringtothesedifferentneedsisveryeasilydonebycreatingURLsthatencodethepreferencesandgivingthemtothedifferentusers.Tosimplifythecode,wewillpretendthat,iftheyarepassedatall,thecorrectnumberofsearchtermsisalwayspassedinthecorrectorder.ThisisareasonableassumptionifyouwritetheURLsyourself.Inareal-worldexample,theURLsaremostlikelygoingtobegeneratedprogrammaticallyfromaUI.Correctlyparsingthemisnottoochallenging,butitisnotreallythefocusofthediscussionhere.ThefollowingarethetwoURLswewillgiveout:

feedbacksite.nhs.uk/shiny?person=NHS&smooth=yesfeedbacksite.nhs.uk/shiny?person=other&smooth=no

Asinthepreviousexample,thecodeiswrappedinobserve(),andthefirstportionofthecodereturnsthesearchtermsfromtheURLasanamedlist:

observe({

searchString<-parseQueryString(session$clientData$url_search)

...

Havingdonethis,wecanthencheckthatsearchStringexists(incaseotheruserslandfromthedefaultURL)and,ifitdoes,wecanchangethesettingsaccordingly.TheupdateTabsetPanel()commandusesalotoftheconceptswealreadysawwhenwereadthetabthatwasselected.Thefunctiontakesasessionargument,aninputIdargument(thenameofthepanel),andaselectedargument

(thenameofthetab):

#updateinputsaccordingtoquerystring

if(length(searchString)>0){#ifthesearchStringexists

#dealwithfirstquerywhichindicatestheaudience

if(searchString[[1]]=="nhs"){#forNHSusersdothefollowing

updateCheckboxGroupInput(session,"domainShow",

choices=list("NHSusers"="nhs.uk",

"Other"="Other"),selected=c("nhs.uk"))

}

#dotheywantasmooth?

if(searchString[[2]]=="yes"){

updateTabsetPanel(session,"theTabs",selected="trend")

updateCheckboxInput(session,inputId="smooth",

value=TRUE)

}

}

})

Thisisclearlyaverypowerfulwaytomaketheexperiencebetterforyouruserscompletelytransparently.Youmaywishtospendabitoftimesettingupawebinterfaceinwhateverlanguageyoulike(PHP,JavaScript,andsoon)andcorrectlyparsingtheURLsthatyougeneratewithinShiny.Ifyouneedtohandlevaryinglengthsandnamesoflists,youwillneedafewextracommands:

names(theList):Givesyouthenameofeachreturnvaluelength(unlist(theList)):Tellsyouhowlongthelistis

DownloadinggraphicsandreportsTheoptiontodownloadgraphicsandreportscanbeaddedeasilyusingdownloadHandler().Essentially,downloadHandler()hastwoargumentsthatbothcontainfunctions:onetodefinethepathtowhichthedownloadshouldgo,andonethatdefineswhatistobedownloaded.

Thefirstthingweneedtodoistakeanyfunctionsthatareusedeitherinthedownloadgraphicrequestorthereportandmakethemreactivefunctions,whichcanbecalledfromanywhereratherthaninstructionstodrawagraphwithinacalltorenderPlot().Theeffectofthis,ofcourse,isthatweonlyhaveonefunctiontowriteandmaintainratherthanoneinsidethedownloadgraphicfunction,oneinsidethedownloadreportfunction,andsoon.Thisisachievedverysimply:

trendGraph<-reactive({

...restoffunctionthatwasinsiderenderPlot

})

Thegraphcannoweasilybeprintedwithinthetrendtab:

output$trend<-renderPlot({

trendGraph()

})

We'llgothroughthefollowingcodefromserver.Rstepbystep:

output$downloadData.trend<-downloadHandler(

filename<-function(){

paste("Trend_plot",Sys.Date(),".png",sep="")

},

Thisisthefilenamefunction,andasyoucansee,itproducesfilenameTrend_plot_XX_.pngwhereXXisthecurrentdate:

content<-function(file){

png(file,width=980,height=400,

units="px",pointsize=12,

bg="white",res=NA)

trend.plot<-trendGraph()

print(trend.plot)

dev.off()

},

Thisisthecontentfunction,andasyoucansee,itopensapngdevice(?png),calls

areactivefunctionnamedmyTrend(),whichdrawsthegraph,printstothedevice,andcloseswithacalltodev.off().YoucansetupthetrendGraph()functionsimply;inthiscase,itisjustlikethefunctionthatdrawsthegraphitself,exceptinsteadofbeingwrappedinrenderPlot()toindicatethatitisaShinyoutputitisjustdefinedasareactivefunction.

Finally,thefollowingisgiventotellShinywhattypeoffiletoexpect:

contentType='image/png')

Addingthedownloadbuttontotheui.Rfileissimple;thedownloadButton()functiontakesthenameofthedownloadhandlerasdefinedinserver.Randalabelforthebutton:

tabPanel("Trend",plotOutput("trend"),

downloadButton("downloadData.trend","Downloadgraphic")

Asyoucansee,Ihaveaddedthebuttonunderneaththegraph,sousersknowwhattheyaredownloading.

DownloadablereportswithknitrThissamefunctioncanveryeasilyallowyouruserstoproducecustomreportsinHTML,pdf,orMSWordreadytobedownloadedtotheirmachines,usingtheknitrpackage(http://yihui.name/knitr/).knitrisauser-contributedpackagethatallowsreportstobegenerateddynamicallyfromamixtureofastaticreportformatsinterleavedwiththeoutputfromofR.

So,forexample,titlesandtextcanbefixed,buteachtimethereportisrun,adifferentoutputwillbeproducedwithinthedocumentdependingonthestateofthedatawhentheoutputisgenerated.knitrcanbeusedwiththeRMarkdownformat.HereisthesimpleRMarkdowndocumentwithintheGoogleAnalyticsapplication:

#Summaryreport

##Textsummary

Thisreportsummarisesdatabetween`rstrftime(input$dateRange[1],

format="%d%B%Y")`and`rstrftime(input$dateRange[2],

format="%d%B%Y")`.

##Trendgraph

```{rfig.width=7,fig.height=6,echo=FALSE}

trendGraph()

```

Ascanbeseen,thedocumentisamixofstaticheadingsandtext,inlineRoutput(givenas`r"print("somthing")`),andgraphicaloutput.ThetrendGraph()function,ofcourse,isthesametrendGraph()functionthatwesawinthedownloadgraphicscode.

Thecodetodownloadthereportisasfollows(withtheRMarkdowndocumentinthesamefolderasserver.RandnamedReport.Rmd):

output$downloadDoc<-

downloadHandler(filename="Report.html",

content=function(file){

knit2html("Report.Rmd",envir=environment())

#copydocumentto'file'

file.copy("Report.html",file,

overwrite=TRUE)

}

)

Addingabuttontodownloadthegraphisthesameasforthedownloadinggraphfunction;thefollowingshouldbeplacedinui.RwithinthesidebarPanel()function:

downloadButton("downloadDoc","Downloadreport")

DownloadinganduploadingdataDownloadingdataisdoneinasimilarfashion,whichlookslikethefollowingdownloadHandler()call:

output$downloadData<-downloadHandler(

filename=function(){

"myData.csv"

}

content=function(file){

write.csv(passData(),file)

}

)

UploadingdataisachievedusingthefileInput()function.Inthefollowingexample,wewillassumethattheuserwishestouploadacomma-separatedspreadsheet(.csv)file.Thebuttonisaddedtoui.Rinthefollowingmanner:

fileInput("uploadFile","UploadyourownCSVfile")

Thisbuttonallowsausertoselecttheirown.csvfile,anditalsomakesavarietyofobjectsbasedontheID(inthiscase,input$uploadFile$)availablefromserver.R.Themostusefulisinput$uploadFile$datapath,whichisapathtothefileitselfandcanbeturnedintoadataframeusingread.csv():

userData<-read.csv(input$uploadFile$datapath)

Thereareotherbitsofinformationaboutthefileavailable.Takealookat?fileInputformoredetails.

BookmarkingInternetusersarefamiliarwiththetermbookmarking.Ifwearesurfingasiteandthinkit'ssomethingimportantthatwe'dliketovisitagain,weusuallybookmarkit.HowaboutthebookmarkingaShinyapp?AstheShinyapphasdatarepresentationandinput/outputinteractions,savingthisstateusingbookmarkingandthenreproducingitwillrequiresomecodingexpertise.

Inthissection,wearegoingtofocusonhowtobookmarkthestateofaShinyapp.WewillseecodingmodificationsinthebasicstructureoftheShinyappneededtoincorporatethebookmarkingfeature.Wewillexplorebookmarkingastate,andsomeexceptionalcasesandhowtodealwiththem.

BookmarkingstateThestateofanapplicationcanbedefinedasthestateofinputandoutputatagiventime.InShinyapps,thestateoftheinputandoutputcanbetheinputintheinputboxandtheoutputintheoutputboxoragraphataparticulartime.Here,ouraimistosaveastateatagiventimeandrestoreit.AsofnowwehavelearnedaboutthestructureofShinyapps.Shinyappscanbeasinglefile(UIandServerfiletogether)ormultiplefiles(UI,Severorglobalfilesseparately).Andtherecanbeappswheretheflowofinputandoutputcanbestraightforwardornotstraightforward.Astraightforwardcontrolflowofanappcanbeconsideredastheappthathasadeterministicoutputforaninputandvice-versa.Inthissection,wewilllearntoprogramthebookmarkingfeaturesforthestateofappswithastraightforwardcontrolflow.

Themethodsofbookmarkingcanbeclassifiedintotwocategories:

BookmarkingbyEncodingthestateintoaURLBookmarkingbysavingthestatetotheserver

Inboththemethods,thebasicconceptistopreservethestateoftheapplicationataparticulartime.Thedifferenceliesinhowtosavethestate.Let'sdiscussboththemethodsindetail.

EncodingthestateintoaURLInthismethodofbookmarkingthestate,thestateoftheappisembeddedintoaURL.Aswehavediscussed,thestateoftheapplicationmeanstheinputandoutputvaluesataparticulartime.So,theinputandoutputvaluesareembeddedintheappforatimeinstance.TheinputandoutputvaluescanbeseenintheURLitself.AswearefamiliarwiththecodingofShinyapps,thedifferenceswithbookmarkingarethattheUIhastobereturnedasavalueofafunctionwithasingleargumentandenableBookmarking()hastobecalled.WhenwediscussedthedifferentstylesofcodingaShinyappinsinglefileormultiplefiles,welearnedweneedtounderstandhowtoimplementtherequirements-implementingUIwithasingleargumentfunctionandusingenableBookmarking().

Single-fileapplicationSingle-fileappshaveUIandservercodeinthesamefile.Forsuchacodingstyle,theappskeletoncanbegivenasfollows:

ui<-function(request){#UIcode}

server<-function(input,output,session){#ServerCode}

shinyApp(ui,server,enableBookmarking="url")

WecanseethattheUIcodeisreturnedasafunctionratherthanfluidpageoranyotherUIelement.Andinthelastlineofcode,theenableBookmarkingargumentissetto"url".TherestofthecodeissimilartoShinyapps.Let'sdevelopanappwiththeprecedingskeletonthatfindsthesquareofanumber.StartingwithUI,thereisatextInput()boxforgettingtheinput,verbatimTextOutput()forshowingoutput,andbookmarkButton()forbookmarking:

ui<-function(request){

fluidPage(

textInput("inptxt","EnterNumber"),

verbatimTextOutput("outsquare"),

bookmarkButton())

}

Intheservercode,wehavetocalculatethesquareoftheinputtednumberandsenditfordisplay.WecanseeinthefollowingcodethatrenderText()isfirstconvertingtheinputtedtextintoanumberandthencalculatingthesquare:

server<-function(input,output,session){

output$outsquare<-renderText({

(as.numeric(input$inptxt)*as.numeric(input$inptxt))

})}

Inthelast,wehavetocallshinyApp()inwhichwearepassingtheenableBookmarkingargumentas"url":

shinyApp(ui,server,enableBookmarking="url")

Let'shavealookatoutputofthecode:

Wecanseethatintheapp,theinputis2andtheoutputvalueis4.ThebookmarkwindowshowsthelinkedURLwithsomevaluesthatareencodingtheinput/output,http://127.0.0.1:4255/?_inputs_&inptxt=%222%22.

SinglefileShinyapplicationscanalsobereturnedbyafunction.Let'srecreatethesquareapplicationusingfunction:

App<-function(){

ui<-function(request){

fluidPage(

textInput("inptxt","EnterNumber"),

verbatimTextOutput("outsquare"),

bookmarkButton()

)

}

server<-function(input,output,session){

output$outsquare<-renderText({

(as.numeric(input$inptxt)*as.numeric(input$inptxt))

})

}

shinyApp(ui,server,enableBookmarking="url")

}

Toruntheapp,copythecodeintoanRScriptfile,selectallcode,andrunit.Afterthat,wecanexecutethecodeusingApp()inconsoleorRScript.enableBookmark()canalsobesetatthebeginningoftheappcode.

Now,wearereadytodevelopourapplicationformultiplefiles.

Multiple-fileapplicationInShinyapplicationswhereUIandservercodesarekeptinseparatefiles,enableBookmarking()hastobekeptintheglobal.rfile.Therestofthethingsarethesame.Forredevelopingthesquared-numberappinamultiple-filepattern,wehavetocopytheUIcodeandpasteitintotheui.rfileandservercodeintheserver.rfilewithenableBookmarking(store="url")intheglobal.rfile.Wewillgetthesameoutputaswegotinthesingle-fileimplementation.

BookmarkingbysavingthestatetotheserverInthismethod,theonlymodificationintermsofcodingistochangetheenableBookmarkingargumenttotheserver.Let'srecreatethesquare-calculationapplicationusingsavingstatetotheserver:

ui<-function(request){

fluidPage(

textInput("inptxt","EnterNumber"),

verbatimTextOutput("outsquare"),

bookmarkButton()

)

}

server<-function(input,output,session){

output$outsquare<-renderText({

(as.numeric(input$inptxt)*as.numeric(input$inptxt))

})

}

shinyApp(ui,server,enableBookmarking="server")#savingtotheserver

Howdoesitmakeadifferenceinprocessing?SavingstatetotheservermethodsavesthestateoftheapplicationontheserverinsteadofembeddingthestatesintoaURL.Shinyprovidestwoversionsofservers.OneistheopensourceShinyserver,andtheotherisShinyserverpro.InShinyserver,thestateoftheapplicationissavedinthe/var/lib/shiny-server/bookmarkssubdirectory.RStudioConnectalsostoresthebookmarkstatein/var/lib/rstudio_connect/bookmarks.WeusuallyexperimentwithourapplicationsondesktopversionsofRstudio.Insuchcases,thestateissavedintheshiny_bookmarks/subdirectory.

Theadvantageofusingsavingstateintheserveristhatfilescanalsobebookmarked,whichisnotpossiblewithbookmarkingwithencoding.LargefilesarenotsupportedbybookmarkingwithaURL.Tosavestateontheserver,thehostingenvironmentmustbesupported.

Asofnowwehavediscussedbookmarkingstatefortheappshavingstraightforwardflow.Butifappsdon'thavestraightforwardflows,weneedtotakesomeextrameasurestodealwithsuchsituations.Inasimilarway,ifappshaverandom-numbergenerationandusethattogenerateoutput,thenthesemethodologieswon'twork.

Forsuchapplicationswithcomplexstate,useofcallbackfunctionsisneeded.ShinyhasprovidedonBookmark(),andonRestore()toachievecallbackfunctions.Thesecallbackfunctionstakeoneargument,namedstate.Wecanusestate$valuetosaveandretrievevaluestobebookmarked.

Let'sdevelopanapplicationthatgeneratesarandomnumberandaddsittotheinputtednumber.HereistheUIcodeforgettingtheinputnumberusingtextInput().IthasoneactionButton()fortriggeringtheeventoftheaddition,andbookmarkButton()forbookmarking:

ui<-function(request){

fluidPage(

sidebarPanel(

textInput("txt","Number"),

actionButton("add","Add"),

bookmarkButton()

),

mainPanel(

h4("SumofRandomNumberandInputedNumber:",textOutput("result"))

)

)

}

Intheservercode,wecanseethattheresultvariableisinitiatedtozeroandarandom-numbergenerator,runif(),hasbeenused.onBookmark()isusedtosavetheresultvalueinthestate$valuesobject.AndonRestore()isusingthesamestateobjecttorestorethebookmarkedvalue:

server<-function(input,output,session){

vals<-reactiveValues(result=0)

#Savevaluesinstate$valuesforbookmark

onBookmark(function(state){

state$values$currentresult<-vals$result

})

#Readvaluesfromstate$valueswhenwerestore

onRestore(function(state){

vals$result<-state$values$currentresult

})

#Excludetheaddbuttonfrombookmarking

setBookmarkExclude("add")

observeEvent(input$add,{

vals$result<-vals$result+floor(runif(1))+as.numeric(input$txt)

})

output$result<-renderText({

vals$result

})

}

shinyApp(ui,server,enableBookmarking="url")

So,wehavelearnedhowtobookmarktheShinyappstateinasimple,straightforwardflowaswellasincomplexstates.WealsolearnedinwhichconditionsencodingwithaURListobeusedandwhenasaveontheservercanbeadvantageous.

InteractiveplotsToexplorecomplexpatternsindata,simplyputtingdataintoastaticgraphisn'tparticularlyuseful.Inthebigdataera,interactiveplotsdemandalotoftime.Rhascomeupwithveryelegantinteractiveoptions:

clickdouble-clickhoverbrushzoomin/outselectionofarea

plotOutput(),likefunction,providesoptionstoenablethesepropertiestomakeplotsmoreinteractive.Let'sexploreplotOutput()anduseitinourapp.HereisthesyntaxforplotOutput():

plotOutput(outputID,width,height,click=NULL,dbclick=NULL,hover=NULL,hoverDelay=NULL,hoverDelayType=NULL,brush=NULL,clickId=NULL,inline=FALSE)

Let'sdevelopanapplicationthatexplorestheirisdatasetandusessomeinteractivefeaturesofplotting:

library(shiny)

shinyApp(

#---------------Uistart--------------------------------

ui=basicPage(fluidRow(

column(width=4,

plotOutput("plot",height=300,

click="plot_click",

hover=hoverOpts(id="plot_hover",delayType="throttle"),

brush=brushOpts(id="plot_brush")

),

h4("Clickedpoints"),

tableOutput("plot_clickedpoints")

),

column(width=4,verbatimTextOutput("plot_hoverinfo")

)

)),

server=function(input,output,session){

output$plot<-renderPlot({

plot(iris$Sepal.Length,iris$Sepal.Width)

})

output$plot_clickedpoints<-renderTable({

#Forbasegraphics,weneedtospecifycolumns,thoughforggplot2,

#it'susuallynotnecessary.

res<-nearPoints(iris,input$plot_click,"Sepal.Length","Sepal.Width")

if(nrow(res)==0)

return()

res

})

output$plot_hoverinfo<-renderPrint({

cat("Hover(throttled):\n")

str(input$plot_hover)

})

}

)

Inthiscode,wecanseethatplotOutput()hastheclickandhoverproperties.Theclickpropertyspecifiesthatitwilldetectaclickeventontheplot.hoverwilldetectthepointer'sposition.

Inthefollowingoutput,thepositionofpointeriscapturedanddetailsaredisplayedinthehoverwindowanddataforthepointisinthetable:

ggplotandplotly,likeRlibraries,arefullofverygoodinteractiveplottingfunctions.ThesefunctionsuseD3.jstoproduceinteractiveplotsandgraphs.Aswehavealreadydiscussedggplot2,wewillnotelaborateonithere.

plotlyisalsoveryeasytouse.Ifplotlyisnotinstalledonyoursystem,youcaninstallitusinginstall.package("plotly").Let'slookatanexamplewithplotly:

library(plotly)

plot_ly(iris,x=iris$Sepal.Length,y=iris$Sepal.Width,text=paste("iris$Sepal.Width:",iris$Sepal.Width),

mode="markers",color=iris$Sepal.Width,size=iris$Sepal.Width)

Inthefirstlineofcode,theplotlylibraryisinvokedwhichfacilitatestheuseofplot_ly().Inplot_ly(),thefirstargumentisthenameofthedataset,thesecondisthexaxis,andthethirdistheyaxis.Theoutputcanbeseeninthefollowingscreenshot;bydefault,itsupportshoverandclickevents:

InteractivetablesIntheprecedingexampleapplication,wesawhowtomakeourplotinteractive.Nowit'stimetomaketablesinteractive.Interactiveplotsmeanwecanhavefreedominselectingrows/columns/cellsandshortingcolumns.

DTisapackagewithDTlibrarythathelpsustomaketablesmoreinteractive.Let'sseeasmallclient-sideexampleofDataTableswithShiny:

library(shiny)

library(DT)

shinyApp(

ui=fluidPage(DTOutput('tbl')),

server=function(input,output){

output$tbl=renderDT(

iris,options=list(lengthChange=FALSE)

)

})

Intheprecedingcode,DTOutput()isforoutputtingthetableonUI,andontheserversidewehaveusedrenderDT()tosendthedataintotheUIfromtheirisdataset.Theoutputcanbeseenhere:

Wecanseeintheprecedingscreenshotthatwecanselectrowsusingamousepointer.Inthisway,interactivefunctionalitycanbeaddedtotables.

DTsupportsbothserver-sideandclient-sideprocessing;thedefaultisserver-side,butclient-sidecanbesetbycallingDT::renderDT()withaserver=FALSEargument.Ifthedatasetisrelativelysmall,useserver=FALSE,otherwiseitwillbetooslowtorenderthetableinthewebbrowser,andthetablewillnotbeveryresponsive,foralargedataset.Examplecode:

DT::renderDataTable(iris,server=FALSE)

Formoredetailshttps://rstudio.github.io/DT/linkcanbefollowed.

RowselectionRowselectionisthedefaultindatatable(...,).Wecantoggletheselectionbyclickingontherow.Itcanalsobedisabledbysettingthedatatable(...,selection='none')property.The'selection'modecanalsobesetto'single'or'multiple'.Bydefault,themultipleselectionmodeisset.

ColumnselectionTochangethedefaultmoderowselectiontocolumn,weneedtosetthetargetascolumnindatatableasdatatable(...,selection=list(target='column')).Toselectrowandcolumnsimultaneously,thetargetcanbesetas"row+column".

CellSelectionToenablecellselection,thevalueoftargetmustbesettocell.

LinkinginteractivewidgetsShinyhasanumberofwidgetsthatcanbelinkedinourapplications.Forreferringtothewidgetgallerygotohttps://shiny.rstudio.com/gallery/widget-gallery.html.Here,youcanfindwidgetswithsampleoutputandaseecodebutton.Havealookatasnapshotofthesite:

Forbetterunderstanding,wewillbuildanapplicationwithaShinydashboardandintegratewidgetsintoourapp.Let'sdevelopourappstepbystep:

1. Developabasicdashboard.2. CopythecodeintoanRScriptfile.3. Iftheshinydashboardpackageisnotinstalled,installit.4. Executethecodebyclickingontherunappbutton:

##app.R##

library(shiny)

library(shinydashboard)

ui<-dashboardPage(

dashboardHeader(),

dashboardSidebar(),

dashboardBody()

)

server<-function(input,output){}

shinyApp(ui,server)

Hereistheoutput:

Now,let'sintegratethewidgetintoourbasicdashboard:

1. Gotohttps://shiny.rstudio.com/gallery/widget-gallery.html.2. Let'sintegratetheFileinputwidgetintoourapp.SoclickonFileinputto

seethecode.3. CopythecodefromtheUIfileandpasteitintothedashboardbody()dashboard

UIfiles:

dashboardBody(

fileInput("file",label=h3("Fileinput")),

hr(),

fluidRow(column(4,

verbatimTextOutput("value")))

)

4. CopythecodefortheserverfileoftheFileinputwidgetandpasteintheservercodeofourdashboard:

server<-function(input,output){

output$value<-renderPrint({

str(input$file)

})

}

5. Ourfile-uploadmanagerappisready.Thecompletecodecanbeseenhere:

##app.R##

library(shiny)

library(shinydashboard)

ui<-dashboardPage(

dashboardHeader(),

dashboardSidebar(),

dashboardBody(fileInput("file",label=h3("Fileinput")),

hr(),

fluidRow(column(4,verbatimTextOutput("value"))))

)

server<-function(input,output){

output$value<-renderPrint({

str(input$file)

})

}

shinyApp(ui,server)

Hereistheoutput:

Fromtheprecedingscreenshot,wecanseethattheFileinputwidgethasbeenintegratedintoourapplication,andafterclickingontheBrowse...button,anyfilecanbeuploaded.

ShinygadgetsSofar,wehaveseenhowtopresentdatawithShinyappsfortheenduser.Nowit'stimetodevelopgadgetsforRcoders.ThemaindifferencebetweenShinyappsandShinygadgetsisthatappsaredeployedonservers,suchasshinyapps.iooradeployableserver,butgadgetsaretobecalledfromthecodefromRScript.Atthesametime,ShinygadgetscanberegisteredwithRStudioasadd-ins.

Shinygadgetshavebeendevelopedtomakerepeatabletaskseasilydoable,suchasimportingdataintherightformats,cleaningdata,manipulating,orvisualization.Nowlet'sseehowtowriteShinygadgets:

library(shiny)

library(miniUI)

newGadget<-function(inputVal1,inputVal2){

ui<-miniPage(

gadgetTitleBar("NewGadget"),#titleofGadget

miniContentPanel(

#layout,inputs,outputs

)

)

server<-function(input,output,session){

#Definereactiveexpressions,outputs,etc.

#WhentheDonebuttonisclicked,returnavalue

observeEvent(input$done,{

returnValue<-...

stopApp(returnValue)

})

}

runGadget(ui,server)

}

Fromthegadgetsskeleton,wecanseethatitissimilartoShinyapps.ThepackagingoftheUIandserverlogicisdonedifferentlyingadgets.Shinyappsaregenerallykeptintheapp'sdirectorywiththeserverandUIfiles,butShinygadgetsaredefinedinsidearegularfunction.

Aswecanseefromtheskeleton,westillhavetheUIandserverconstruct,butthey'reallwrappedinaregularfunction.Andhencethefunction'sinputValue1andinputValue2argumentscanbeaccessedlocally,andreturnvaluesfromtheserver

constructcanbethereturnvalueofthegadget.

Againinskeleton,UIhasminiPageinsteadoffluidpage,andminiContentPanelinplaceofsidelayout.Thisisbecausethegadget'soutputwillopeninaseparateRStudioViewerpaneinsteadofawebpage.TheMiniUIconstructisusedtomakeoptimaluseofavailablespace.

Let'sdevelopaShinygadgettoplotthedatapassedasanargument,detecttheclickevent,andshowthedata:

library(shiny)

library(miniUI)

library(ggplot2)

click_gadget<-function(data,xvar,yvar){

ui<-miniPage(

gadgetTitleBar("Dragtoselectpoints"),

miniContentPanel(

plotOutput("plot",height="100%",click="plot_click")

)

)

server<-function(input,output,session){

#Rendertheplot

output$plot<-renderPlot({

#Plotthedatawithx/yvarsindicatedbythecaller.

ggplot(data,aes_string(xvar,yvar))+geom_point()

})

#HandletheDonebuttonbeingpressed.

observeEvent(input$done,{

#Returnthebrushedpoints.See?shiny::brushedPoints.

stopApp(clickOpts(data,input$plot_click))

})

}

runGadget(ui,server)

}

Toexecutethiscode,firstselectalltheprecedingcodeinRScriptandexecuteit,thenrunclick_gadget(iris,"Sepal.Length","Sepal.Width").Here,theirisdatasethasbeenused,butitcanbechangedtoanydataset:

Atthesametime,iftheplotisclickedandtheDonebuttonispressed,wecanseethedataoftheinputteddataset.

AddingapasswordSofar,wehavelearnedhowtodevelopaShinyapplication.Sincetheapplicationisexposingsomuchdatatotheoutsideworld,itneedstobeprotectedbyunauthorizedmeans.Forthat,wecanprovidepasswordauthentication.Shinyprovidesacontrolforachievingthistask,calledpasswordInput(https://shiny.rstudio.com/reference/shiny/latest/passwordInput.html):

passwordInput(inputId,label,value="",width=NULL,placeholder=NULL)

Let'sseeanexamplewithpasswordInput:

ui<-fluidPage(

passwordInput("password","Password:"),

actionButton("go","Go"),

verbatimTextOutput("value")

)

server<-function(input,output){

output$value<-renderText({

req(input$go)

isolate(input$password)

})

}

Hereistheoutput:

Intheprecedingapplication,theUIsectionhaspasswordInput(),whichconvertstheenteredtextintodotsandtheinputtedvalueisstoredinapasswordvariablethatcanfurtherbeusedinreactiveprocesses.ThecodecanbecopiedandpastedintoRScriptandexecutedasasimpleShinyapplication.

SummaryInthischapter,welearnedaboutRShiny'sadvancedfeatures.Animation,graphics,reportdevelopment,andusingknitrarewonderfulprofessional-levelpresentationfeatures;usingthese,anybodycansharetheirresultsandtellthestoryaboutthedatainhand.WealsodiscussedanddemonstratedthefeatureofbookmarkingtheShinyapp'sstatewithdifferentlevelsofcomplexity.Interactiveplotsandtablesarenewwaystoplaywithdataandfindingnewwaysofdynamicpresentation.Widgetsarelikecookbooksandcanbeusedtospeeduptheapp-developmentprocess.WecannowalsocodeforRusersanddevelopersbydevelopinggadgets.Addingapasswordtoourappcangiveusextracontrolonrestrictingthedataaccessedbyendusers.Inthischapter,westudiedmostofthelatestadvancedfeaturesofpresentation,codesharing,andauthentication.

CodePatternsinShinyApplicationsAsyourShinyapplicationsbecomelargerandmorecomplex,itisimportanttowriteclear,readable,andmaintainablecode.Insomecases,itisalsonecessarytomodularizeyourcode.ThischaptercoversvariousaspectsofwritinganddebuggingShinyapplications,functions,andmodules.WewillalsolookatfeaturesthatrelatetothecontrolofreactivitywithinyourapplicationandhowtospeedupShinyapplications.

Inthischapter,wewillcoverthefollowingtopics:

ReactivityinRShinyControllingspecificinputwiththeisolate()functionRunningreactivefunctionsovertimeEventhandlingusingobserveEventFunctionsandModulesShinytestDebuggingHandlingerrors(includingvalidate()andreq())ProfilingRcodeDebounceandthrottle

ReactivityinRShinyRShinyusesareactiveprogrammingcodingpattern,whichmakesapplicationsresponsive.Inreactiveprogramming,therearebasicallythreeelements:

ReactiveSourceReactiveEndpointReactiveConductor

ThecombinationoftheseelementsiswhatmakesaShinyappmoreresponsive.Let'shavealookinmoredetailathowtheywork:

ReactiveSource:ThereactivesourceistheinputobjectingtheShinyapp.IttakestheinputfromtheuserandkeepsitintheInputobject.TheInputobjectisassociatedwithanyUIelement,withwhichtheuserinteractsandprovidesinput.Itcanbeaninputbox,anactionbutton,aninteractivetableorplot,oranyotherUIcomponent.Forexample,ifwetakeinputfromatextboxnamedtxtboxintheUIcode,wecansaythatinput$txtboxisthereactivesource.

ReactiveEndpoint:ThereactiveendpointistheoutputobjectinaShinyapp.ItacceptsavalueandputsthatintheoutputcomponentsoftheUI.TheoutputcomponentscanbeanyUIelementthatisusedtodisplaythedatainanyformat.Theoutputobjectisoutput.Forexample,ifwewanttoputthedataintoaplotnamedhist_plotintheUIfile,thenoutput$hist_plotwillbethereactiveendpoint.

Asimpleapplicationcancontainonlythesetwoelements:thesourceandtheendpoint.Let'stakealookatanexampleofanapplicationthatusuallyappearswheneverwestartanewShinyapplication:

library(shiny)

#DefineUIforapplicationthatdrawsahistogram

ui<-fluidPage(

#Applicationtitle

titlePanel("OldFaithfulGeyserData"),

#Sidebarwithasliderinputfornumberofbins

sidebarLayout(

sidebarPanel(

sliderInput("bins",

"Numberofbins:",

min=1,

max=50,

value=30)

),

#Showaplotofthegenerateddistribution

mainPanel(

plotOutput("distPlot")

)

)

)

#Defineserverlogicrequiredtodrawahistogram

server<-function(input,output){

output$distPlot<-renderPlot({

#generatebinsbasedoninput$binsfromui.R

x<-faithful[,2]

bins<-seq(min(x),max(x),length.out=input$bins+1)

#drawthehistogramwiththespecifiednumberofbins

hist(x,breaks=bins,col='darkgray',border='white')

})

}

#Runtheapplication

shinyApp(ui=ui,server=server)

Yougetthefollowingoutput:

IntheUIsectionoftheprecedingcode,sliderInputistheinputcomponentnamedbins.Intheservercodesection,input$binsisthereactivesource.Similarly,plotOutput("distPlot")istheoutputcomponentontheUI.Asthevalueofinput$binschanges,thisplotalsochanges.Thisishowreactivityworks.Intheserver

section,output$distPlotisthereactiveendpoint.Thisisrepresentedhere:

However,withmorecomplexapps,thereactivesourceandendpointscanformdifferentcombinations.Imaginethatagraphistobebuiltusingtwoinputvalues.Inthiscase,theflowdiagramwouldbeasfollows:

ReactiveConductor:Sofar,wehaveseenthatthesourceisdirectlyconnectedtotheendpoint.Theremaybesituationswherethereisamiddleelementbetweenthesetwo.Thismiddleelementiscalledareactiveconductor.

Reactiveconductorsareusuallyusedtoencapsulateslowoperationsorcatchdata.FromShiny'sofficialwebsite,https://shiny.rstudio.com/articles/reactivity-overview.htmltocalculateanumberandinverseofitintheFibonaccisequenceforthe

nthelementofasingleapplication,whichcanbeverytime-consuming.Thissituationisshowninthecode:

#CalculatenthnumberinFibonaccisequence

fib<-function(n)ifelse(n<3,1,fib(n-1)+fib(n-2))

server<-function(input,output){

output$nthValue<-renderText({fib(as.numeric(input$n))})

output$nthValueInv<-renderText({1/fib(as.numeric(input$n))})

}

Theflowdiagramwouldbeasfollows:

Insuchsituations,amiddlelayertocatchtheresultscanbeaddedtoreducethetimetakenbythisprocess.Thatiscalledareactiveconductor.Theprecedingcodecanbemodifiedusingareactiveconductor,asfollows:

fib<-function(n)ifelse(n<3,1,fib(n-1)+fib(n-2))

server<-function(input,output){

currentFib<-reactive({fib(as.numeric(input$n))})

output$nthValue<-renderText({currentFib()})

output$nthValueInv<-renderText({1/currentFib()})

}

Nowtheflowdiagramwilllookasfollows:

Upuntilnow,wehavediscussedthreeelements:thereactivesource,thereactiveconductor,andthereactiveendpoints.Thesearethegeneraltermsusedtodescribereactiveprogrammingelements.InRShiny,thereactivesourceisknownasthereactivevalue,thereactiveendpointistheobserver,andthereactiveconductoristhereactiveexpression.Therearetwofundamentaldifferencesbetweentheobserverandreactiveconductor'sfunctionality.Thefirstisthattheobserverrespondstoeventflushingbutreactiveexpressionsdon't.Thesecondisthatreactiveexpressionscanreturnvaluesbuttheobservercan't.

AcloserlookatreactivitySofar,wehavediscussedreactiveprogrammingandhowShinyimplementsitsfeatures.We'llnowtakeacloserlookathowthisworks.RShinyusesapullmechanisminsteadofapushmechanism.Thismeanswhenevertheoutputsensesthatthereisachangeininput,itpullsthenewvaluesfromtheinput.Inpushmechanisms,outputvaluesarepushedforeveryinputchange.Pullmechanismsarealsoknownaslazy-evaluationmechanisms.Thissimplymeansthattheyarenotlikeinputtooutputelectricitytransfers,butmorelikepigeon-carriermethods.

Shinyimplementsreactivitywithtwospecialobjectclasses:

Reactivevalues,which,aswehaveseen,canbeprintedasinput$valueObserver,whichcanbeprintedasoutput$output_val

Wheneveranobserverusesareactivevalue,itcreatesareactivecontextwiththevalue.Thecontextcanbeanyexpressionthatisrunifthereisanychangeinthevalue.Here,theexpressionreferstocallback.Ifmultipleobserversareusingthesamevalue,thatsinglevaluecanholdmultiplecontexts:

Fromtheprecedingdiagram,seehowcontextworksbylookingatthebasiccommunicationbetweenreactivevaluesandobservers.Supposethattheinputvaluechangesto60,sowegetinput$=60.Inthiscase,acontextwithanewvaluewillbecreated.Theobserversensesthatnewvalueandaskstheserverforcallback.Theserverfindsthecontextwiththenewvalueandflushesittotheobserver:

Inagraphicalrepresentation,thereactivesourcecanonlybeaparentandthesourceendcanonlybeachild,whereasaconductorcanbeaparentandachild.

Controllingspecificinputwiththeisolate()functionTheremaybesituationswhentheobserverorconductorwantstoreadthevalueofanexpressionbutavoiddependency.Supposewewanttoimportsomedataorperformsomecalculations,butonlyafterabuttonhasbeenclicked.

Let'stakealookatthisexample:

library(shiny)

#DefineUIforapplicationthatdrawsahistogram

ui<-fluidPage(

#Applicationtitle

titlePanel("OldFaithfulGeyserData"),

#Sidebarwithasliderinputfornumberofbins

sidebarLayout(

sidebarPanel(

sliderInput("bins",

"Numberofbins:",

min=1,

max=50,

value=30)

),

#Showaplotofthegenerateddistribution

mainPanel(

actionButton("goButton","Go!"),

plotOutput("distPlot")

)

)

)

#Defineserverlogicrequiredtodrawahistogram

Intheserverfile,wecanseethatoutput$distPlotisdependentoninput$goButton.Wheneverthebuttonisclicked,theplotgetsexecuted.However,whenwewrapinput$binsinisolate(),thistellsShinythattheobserverorreactiveexpressionshouldnotbedependentonanyreactiveobject:

server<-function(input,output){

output$distPlot<-renderPlot({

#generatebinsbasedoninput$binsfromui.R

x<-faithful[,2]

#bins<-seq(min(x),max(x),length.out=input$bins+1)

#Takeadependencyoninput$goButton

input$goButton

dist<-isolate(bins<-seq(min(x),max(x),length.out=input$bins+1))

hist(dist,breaks=bins,col='darkgray',border='white')

#drawthehistogramwiththespecifiednumberofbins

#hist(x,breaks=bins,col='darkgray',border='white')

})

}

#Runtheapplication

shinyApp(ui=ui,server=server)

Theflowgraphlooksasfollows:

Inthecode,wecanpreventtheplotbeingshownthefirsttimewithouttheclickbuttonbeingpressedbyapplyingconditionstoit.Inisolate(),notonlyreactivebutalsoreactiveexpressionscanbeincluded.Itisalsopossibletoincludemultiplestatementsinanisolateblock.

Runningreactivefunctionsovertime(executionscheduling)ThecoreoftheShinyapplicationisthereactiveengine,whichtellsShinywhentoexecuteeachcomponent.Wearenowfamiliarwiththereactiveflowofvariouscomponents.Reactiveobservershaveaflagthatindicateswhethertheyhavebeeninvalidated.Wheneverthevaluesoftheinputobjectchange,allofthedescendantsinthatgraphareinvalidated.Suchinvalidatedobserversarealsocalleddirtyorclean.Alongwiththis,thearrowsintheflowdiagramthathavebeenfollowedareremoved.

Let'sdiscussanexampleofasinglereactivesourceandendpoint:

server<-function(input,output){

output$Plot_output<-renderPlot({

hist(rnorm(input$User_input))

})

}

Theflowdiagramisasfollows:

Assoonastheinputvalueschange,allthedescendantsareinvalidatedandaflusheventistriggered:

Thisisrepresentedinthefollowingdiagram,inwhichtheoutputobjectisshownindarkgrey.Whenthishappens,alltheinvalidatedobserversarere-executed.Iftheoutputobjectre-executes,itaccessesthereactivevalue.Thismakestheoutputobjectdependentontheinput:

Fromtheprecedinggraph,wecanseethatoutput$Plot_outisrequestingforinput.Onceitgetsinput,theinvalidatingflagisclearedandtheoutputisplacedontheUI:

Event-handlingusingobserveEventandeventReactiveSofar,wehavelookedathowreactivityworksinShinyapplications.Wehavelearnedhowtouseobserve()andisolate().Wewillnowlookinmoredetailatevent-handling.Aneventcanbedefinedasareactivevalueoranexpressionthattriggersothercalculations.Forexample,sometimeswewantsomeactionstohappenonlyaftertheactionbuttonisclicked.

Wehavealreadylearnedtohandleeventsusingobserve()andisolate().Therearetwomoremethods:

observeEvent

eventReactive

Thesetwoprovidestraightforwardwaysofhandlingevents:

observeEvent:Ifwewanttoperformanactioninresponsetoanevent,observeEventisuseful.Thesyntaxisasfollows:

observeEvent(eventExpr,handlerExpr,event.env=parent.frame(),

event.quoted=FALSE,handler.env=parent.frame(),

handler.quoted=FALSE,label=NULL,suspended=FALSE,priority=

0,

domain=getDefaultReactiveDomain(),autoDestroy=TRUE,

ignoreNULL=TRUE,ignoreInit=FALSE,once=FALSE)

Thefirstargumentistheeventtoberespondedtoandthesecondisthefunctiontobecalledwhentheeventoccurs.TherestoftheparametersareoptionalandanexplanationcanbeseeninnextsectionofeventReactive.

eventReactive:eventReactiveisusedtocalculateavaluethatonlygetsupdatedwhenaresponsetoaneventisneeded.Thesyntaxisgivenhere:

eventReactive(eventExpr,valueExpr,event.env=parent.frame(),

event.quoted=FALSE,value.env=parent.frame(),value.quoted=

FALSE,

label=NULL,domain=getDefaultReactiveDomain(),ignoreNULL=

TRUE,

ignoreInit=FALSE)

Here,thefirstargumentistheeventtobedetectedandthesecondisthevalueexpression.Therestoftheargumentsareexplainedhere:

event.env:Theparentenvironmentfortheeventexpression.Bydefault,theparentenvironmentisthecallingenvironment.event.quoted:AlogicalexpressiontotellwhethereventExpisquoted.handler.envandhandler.quoted:Thesameasevent.envandevent.quoted,withrespecttothehandler.Thelabelisthenamegiventotheobserverorthereactive.Suspended:Alogicalexpressionforidentifyingwhethertheobserverissuspended.Priority:Avaluethatidentifiesthepriorityoftheobserver.autoDestroy:Anotherlogicalexpression.Ifitistrue,theobserverwillbedestroyedafterthedomainhasended.ignoreNULL:Alogicalparameteraswell.Ifitistrue,theactionistobetriggeredforthevalueisNULL.ignoreInit:Falsebydefault.IfitisTRUE,andobserveEventisfirstcreatedorinitialized,handlerExpr(secondargument)isignored.valueExpr:AnexpressionthatreturnsthevalueofeventReactive.value.envis:TheparentenvironmentforvalueExpr.value.quoted:CheckswhethervalueExprisquotedornot.

library(shiny):

shinyApp(

ui=fluidPage(

column(4,

numericInput("x","Value",1),

actionButton("button","Show")

),

column(8,tableOutput("table"))

),

Intheprecedingcode,thereisoneinputboxandanactionbuttonontheUI.Thefollowingisthecodeoftheserversection.Here,wecanseethatobserveEventishandlingtheevent,showingtheinputvalues,andeventReactiveiscalculatingtheheadrowsfromtheirisdatasetswithagivenvalueofx:

server=function(input,output){

observeEvent(input$button,{

cat("Showing",input$x,"rows\n")

})

df<-eventReactive(input$button,{

head(iris,input$x)

})

output$table<-renderTable({

df()

})

}

)

Youwillgetthefollowingoutput:

FunctionsandmodulesWehavenowgonethroughagoodnumberofShinyapplicationsthatarefocusedondifferenttopics.Imaginethatwenowhavetodevelopafully-fledgedenterpriseapplicationwithvariousfunctionalitiesasaShinyapplication.Astheapplicationgrows,sowillthenumberoflinesofcodeanditscomplexity.Insituationssuchasthese,applicationscanbecomeunmanageable.Wemayalsoberewritingthesamekindofcoderepeatedly,therebyincreasingthedevelopmenttime.Additionally,variablesneedtobescoped,whichlimitsthereusabilityofnames.Toeliminatetheseobstacles,wecanusemodularization.

Modularizationisnothingbuttheuseofseparatingmodulesaccordingtotheirfunctionality.Modulescanbedefinedasasetofinstructionsthatarewrittentoaccomplishatask.Rprogrammingisdevelopedaroundmodules.Werepeatedlycallfunctionsforalmostanytaskwewanttoperform.Thismeansthatwedon'thavetowritemorecode,asisrequiredinprogramminglanguagessuchasC,C++,orJava.WecanusethisprogrammingparadigmwithShinyaswell.

Sofar,wehavecodedUIandserverfunctionsintheShinyapplication,withanumberofcomponentsandinputandoutputelements.Wewillnowtrytomodifytheseinasimplercodingpatternwithmodules.

Wecanorganizethecodeintotwosections,basedontwofunctions:

ForcreatingUIelementsForloadingserverlogic

Wealsohavetosticktosomenamingconventionssothatthecodecanbeidentifiedeasily.TheUImodulescanbesuffixedwithInput,Output,orUI.Beforegoingintotoomuchdetail,let'sstartbyobservingthesimpleapplicationcodethatisavailablewheneverwestarttheShinyapplication,RStudio.Thisisgivenhere:

#

#ThisisaShinywebapplication.Youcanruntheapplicationbyclicking

#the'RunApp'buttonabove.

#

#FindoutmoreaboutbuildingapplicationswithShinyhere:

#

#http://shiny.rstudio.com/

#

library(shiny)

#DefineUIforapplicationthatdrawsahistogram

ui<-fluidPage(

#Applicationtitle

titlePanel("OldFaithfulGeyserData"),

#Sidebarwithasliderinputfornumberofbins

sidebarLayout(

sidebarPanel(

sliderInput("bins",

"Numberofbins:",

min=1,

max=50,

value=30)

),

#Showaplotofthegenerateddistribution

mainPanel(

plotOutput("distPlot")

)

)

)

#Defineserverlogicrequiredtodrawahistogram

server<-function(input,output){

output$distPlot<-renderPlot({

#generatebinsbasedoninput$binsfromui.R

x<-faithful[,2]

bins<-seq(min(x),max(x),length.out=input$bins+1)

#drawthehistogramwiththespecifiednumberofbins

hist(x,breaks=bins,col='darkgray',border='white')

})

}

#Runtheapplication

shinyApp(ui=ui,server=server)

WecanseethatthiscodefromRStudioissimplywrittenwithoutmodularization.Let'sdiscussindetailhowwecanmodularizetheUIandServercodeofthisapplication:

UICodemodularization:Intheprecedingcode,oneoftheelementsoftheUIsectionissliderInput.Atthemoment,thereisonlyonesliderInputbox,buttheremightbemore,meaningwewouldhavetowritethesamecodeagainandagainifwedidn'tusemodularization.Let'sdevelopamoduleforthis.FortheUImodule,weneedtogiveanametothefunction,suchasSliderbarInput.WealsoneedtogiveanIDtoeachinputelementthatweareusing.Inthefunctionargument,therefore,wewilladdoneIDparameter,whichwillbeusedtocreateanamespaceusingNS().Rightnow,

weonlyhaveoneinputelement,butinthefuturewemaywanttoaddmultipleelements.WewillusetagList().TheUImodulewillnowlookasfollows:

SliderbarInput<-function(id){

ns<-NS(id)

tagList(

sliderInput(ns("bins"),

"Numberofbins:",

min=1,

max=50,

value=30)

)

}

WehavenowseparatedtheinputcodefromtheUIcode.WehavetocallthiscodefrominsidetheUIwheneverwewanttoputinasliderbar.Inthefollowingcode,wecanseethatSliderbarInput("Simplesliderbar")hasbeencalled.Thiswillcalltotheprecedingcode."Simplesliderbar"istheIDgiventosliderInput:

ui<-fluidPage(

#Applicationtitle

titlePanel("OldFaithfulGeyserData"),

#Sidebarwithasliderinputfornumberofbins

sidebarLayout(

sidebarPanel(

SliderbarInput("Simplesliderbar")#calltofunction

),

#Showaplotofthegenerateddistribution

mainPanel(

plotOutput("distPlot")

)

)

)

ServerCodemodularization:Intheserversectionoftheoriginalcode,wearedevelopingacalculationtorenderaplot.Wewilldevelopamoduletoperformthistask.Ourfirsttaskistogiveanametothefunction,suchasSliderbar.Intheservermodule,thefunctionhastohavethreearguments:Input,Output,andSession.Therestcanbetheinputparameterstheuserwantstoadd.Afterthat,wewillwriteallthecalculationcodeinthisfunction.Ournewmodulewilllookasfollows:

Sliderbar<-function(input,output,session){

#generatebinsbasedoninput$binsfromui.R

x<-faithful[,2]

bins<-seq(min(x),max(x),length.out=input$bins+1)

#drawthehistogramwiththespecifiednumberofbins

hist(x,breaks=bins,col='darkgray',border='white')

}

WenowhavetocalltheprecedingcodefromtheusingcallModule()servercode.Here,wewillpassthefunctiontobecalledandthelabelorIDoftheinputelement.Theservercodewilllookasfollows:

server<-function(input,output){

output$distPlot<-renderPlot({

callModule(Sliderbar,"Simplesliderbar")

#SimplesliderbariscomingfromUI

})

}

Bydoingthis,wehaverecreatedtheapplication.However,wehavetodecidewherewecandefineourmodules.Oneoptionistokeepourmodulesinthepreambleofasinglefileapplicationorinafilethatissourcedinthepreambleofasinglefile.Anotheroptionistoputthemodulesinaglobal.rfile,orafilethatissourcedintheglobalfile.Alternatively,wecanwrapamoduleinapackagethatisloadedbytheapplication.

Theadvantageofusingmodularizationisthatitmakesthecodereusable.

ShinytestLet'ssaythattheShinyapplicationwehavedevelopedrunswellonourmachineforsomeinput,butforothersitdoesnotgivethedesiredoutputoritgetsstucksomewhereandthrowserrors.Inthesoftwaredevelopmentprocess,testingisoneofthemostimportanttasks.AShinyapplicationmightstopworkingduetoanyofthefollowingreasons:

TheversionofShinyandtheversionofthepackagesmaydifferAmodificationintheapplicationcodeleadstothewronginputforanyotherreactivecodeThedataformatmayhavechanged

Theremaybecountlessreasonsthatcauseustocomeacrosserrorsandcausetheapplicationtostopworking.Doingtestingmanuallycanbetime-consumingandinefficientbecauseyouhavetoconsiderawiderangeofusecases.Forthisreason,Shinyhastheshinytestpackageforautomatictesting.Itcanbeinstalledasfollows(https://www.rdocumentation.org/packages/devtools/versions/1.13.6/topics/install_github):

library(devtools)

install_github("rstudio/shinytest")

Tocarryoutatest,followthesesteps:

1. RunrecordTest()tolaunchtheappinatestrecorder(https://rstudio.github.io/shinytest/reference/recordTest.html):

library(shinytest)

#Launchthetargetapp(replacewiththecorrectpath)

recordTest("path/to/app")

Inthetestrecorder,wecanfindalistofrecordedevents.Theseeventsareinteractionsmadebytheuser.Wecanalsotakesnapshotsofthestateoftheappbyclickingontakesnapontheright-handsidewindowoftherecorder.

2. Quitthetestrecorderandfindthetestscriptinthe.Rfileinthetest/

subdirectory.Thisholdscodelikethefollowing:

app<-ShinyDriver$new("..")

app$snapshotInit("mytest")

app$snapshot()

app$setInputs(checkGroup=c("1","2"))

app$setInputs(checkGroup=c("1","2","3"))

app$setInputs(action="click")

app$snapshot()

Here,wetrythepossibleusecaseinputandfiguringerrors.Foramorein-depthunderstandingoftheworkingsoftheshinytestpackage,refertohttps://rstudio.github.io/shinytest/articles/shinytest.html.

DebuggingDebuggingaShinyappisnotthesameasdebuggingcodeinotherprogramminglanguages,suchasC,C++,orJava,wherethecontrolflowlookslinear.BecauseRShinyisreactive,itrunsonawebserveraswellasaShinyframework.Thatmakesithardertodebug.

Ifwegetanerrororanundesirableoutput,wecanapplybreakpointsatthesuspectedlineofcode.Thiscanbedonebyclickingontheleftsideofthecodewherethelinenumberisgiven,whichmakesareddotappear:

Afterrunningthecode,Shinywillstopexecutionatthebreakpointandwecanstepintothecodeandtakealookatthecurrentvariablevalues.SettingabreakpointispossiblewithRStudio.

Sometimes,applyingabreakpointdoesn'twork,sowehavetochangetheinputandobservetheoutput.Wecanthenapplyabreakpointagaintotrytodiagnosetheproblem.Wecanenabletheshowcasemodeandseewhichpartofthecodeisexecuting:

shiny::runApp(display.mode="showcase")

Toexaminethereactive,wecanenableshiny.reclogandobservethereactivelogs:

options(shiny.reactlog=TRUE)

Thiswillgiveusanideaabouthowthereactivesareworking.Formoredetaileddebugging,wecanapplyaprintstatementinsuspectedplacestounderstandtheflowoftheapplicationandthebehaviorofthecode.Inordertotracetheleveloftheclientorserverarchitecture,weneedtosettheshiny.tracemodetoon.ThiswillprovideatraceoftheappintheJSONfile.

Thebrowser()statementcanalsobeusedfordebugging.Itactsasbreakpointandcanbeaddedanywhereinthecode.

Debuggingwiththeprecedingmethodologiesissufficienttorunanapplication,buttherearemanyothermethods,whichareoutsidethescopeofthisbook.Afterdebugging,thenextstepistohandletheerrorsthataredetected.

Handlingerrors(includingvalidate()andreq())Areyougettinganerrormessageinredonyourscreen?Areyouoryouruserabletounderstandthatmessage?Theanswerstosuchquestionscanbevalidationerrorsusingvalidate()andreq().

ValidateThisisdesignedtoleadtheuserthroughtheUIoftheShinyapp.Imaginethatwehaveasituationwhereweneedtoplotagraphbasedonsomevaluesofalistboxanditthrowsuparedmessage.Thislooksstressfultotheuser.Weneedtoprovideaprecautionarymessagetomakesurethereaderentersavalidinput.validateisawayofcheckingtheinputandprovidingamessage,usingneed.Inthefollowingcode,wecanseethatvalidateischeckingforaphonenumber.Iftheinputisanemptystring,itwillgiveamessage:

server<-function(input,output){

Phon_Number<-reactive({

validate(

need(input$PN!="","ProvidePhonenumber")

)

get(input$data,'package:datasets')

})

Handlingmissinginputwithreq()Sometimes,wemightseeanerrorwhenourgraphneedstobeupdateddynamicallybecausethedataisunavailablewhiletheapplicationisloading.Itisalsopossiblethatthedataisnotavailableforacertaininputandtheelementtriestorendertheoutput.Inthissituation,wewouldseeanerrormessage.

Tohandlethis,wecanusereq().req()istheshortformofrequire.Thisisusefulforcheckingpreconditions.Wheneverweneedtowriteareactiveelement,wecanencloseitinreq().Thiswillmakesurethattheoutputishalteduntilthevaluesareavailable.

ProfilingRcodeInthebigdataera,wherewemighthavepetabytesofdata,maintainingtheperformanceofapplicationsiscrucial.Theapplicationperformancemightgodownbecauseofdata-loadingoperationsorcalculations.Todetectsuchoperations,wehaveapackagecalledprofvis.Thistellsushowmuchtimealineofcodetakestoexecute.Installthepackageasfollows:

install.packages("profvis")

RStudiohasprovidedsupportfortheprofvispackage.Let'stakealookathowtouseit:

library(profvis)

profvis({

plot(iris$Sepal.Length,iris$Sepal.Width)

plot(cars$speed,cars$dist)

})

profvisenclosesthecodetobeanalyzed.Inthefollowingscreenshot,wecanseetheoutput.Foreachlineofcode,wecanseethememoryusagewiththetimetaken:

DebounceandthrottleDebounceandthrottleareusedtoslowdownareactiveexpression.Forexample,supposeweareusingtheinvalidationcheckforareactiveexpressionanderrorindicationsarepromptedunnecessarily.Wecanusedebounceandthrottletomakeexpressionssuchastheseslowdownandwaitforintermediateexpressionstocompletetheircalculations.Thesyntaxesofbothoftheseareasfollows:

debounce(r,millis,priority=100,domain=getDefaultReactiveDomain())

throttle(r,millis,priority=100,domain=getDefaultReactiveDomain())

Here,risthereactiveexpressionthatinvalidatestoooften.millisisthetimewindowusedbydebounce/throttle,andprioritysetstheobserver'spriority.Forexample,ifwewanttoadddebouncetoanexpression,wecandoitasfollows:

plot_iris<-plot(iris$Sepal.Length,iris$Sepal.Width))%>%debounce(1000)

Formoredetailvisitehttps://shiny.rstudio.com/reference/shiny/1.0.0/debounce.html.Letshaveanexample

##OnlyrunexamplesininteractiveRsessions

if(interactive()){

options(device.ask.default=FALSE)

library(shiny)

library(magrittr)

ui<-fluidPage(

plotOutput("plot",click=clickOpts("hover")),

helpText("Quicklyclickontheplotabove,whilewatchingtheresulttablebelow:"),

tableOutput("result")

)

server<-function(input,output,session){

hover<-reactive({

if(is.null(input$hover))

list(x=NA,y=NA)

else

input$hover

})

hover_d<-hover%>%debounce(1000)

hover_t<-hover%>%throttle(1000)

output$plot<-renderPlot({

plot(iris)

})

output$result<-renderTable({

data.frame(

mode=c("raw","throttle","debounce"),

x=c(hover()$x,hover_t()$x,hover_d()$x),

y=c(hover()$y,hover_t()$y,hover_d()$y)

)

})

}

shinyApp(ui,server)

}

Youwillgetthefollowingoutput:

Resulttable

SummaryInthischapter,welearnedaboutthereactivityofRShiny.Welearnedindetailhowreactivesource,endpoint,andconductorwork,andhowtocontrolspecificinputwithisolate().Wehavealsoscheduledthereactiveoffunctions.Afterthat,weusedobserveEventandeventReactiveforevent-handling,andlearnedhowtomakeourcodemoremodular.Afterdevelopingourapplication,wecarriedouttestingusingShinytest,debugging,anderror-handling.Ontopofallthis,wediscussedhowtoimprovetheperformanceofourShinycodeusingprofiling.

PersistentStorageandSharingShinyApplicationsHavingmadeallofthosewonderfullyintuitiveandpowerfulapplications,youarequitenaturallygoingtowanttoshowthemoff.YoumaywishtosharethemwithcolleaguesormembersoftheworldwideRcommunity.Youmaywishtosharethemwithindividualsinyourdepartmentorfieldwho,whilenotRusers,canhandlealittlebitofefforttogetanapplicationworking.Oryoumaywishtosharethemtransparentlyandfreelywiththewholeworldbyhostingthemonaserver.Shinyoffersquitealotofapproachestosharingapplications,andyou'llbegladtohearthateventhemostcomplexshouldnotbetootaxing,withtherighthardwareandOSonyourserver.

Inthischapter,wewilltakealookatthefollowing:

SharingoverGitHubAnintroductiontoGitusingGitandGitHubwithinRStudioSharingapplicationsusingGitSharingusing.zipand.tarShinyapps.io

ShinyServerRunningShinyinAWSandGoogleCloudScoping,loading,andreusingdatainShinyapplicationsTemporarydatainput/outputPermanentdatafunctionsDatabasesSQLinjectionDatabaseswiththepoolpackage

ThereareafewwaysofsharingwithRusersrunningtheShinypackagewithinRsummarizedinthefollowingsections.

SharingoverGitHubByfar,theeasiestwaytoshareyourcreationswithfellowRusersisoverGitHub(github.com).Ofcourse,otherRuserscanalsousealltheothermethodsinthischapter,butthisisprobablythemostfrictionlessmethod(shortofhostingtheapplication)forbothyouandtheenduser.

AnintroductiontoGitYouwillnodoubthaveheardofGit(git-scm.com—theversion-controlsystemthathascollaborativesharingfeaturesatGitHub),evenifyouhaveneverusedit.Gitisaversion-controlsystemthatcanbeusedlocallyonyourcomputer,orinordertogetthebestoutofit,theversion-controlrepositoryonyourcomputercanbesyncedonlineatGitHub.HostingofopensourcecodeatGitHubisfree,andtherearepaidoptionsforclosedsourcecode.Ifyouhaven'talreadyusedaversioncontrol,thisisanexcellentreasontostart.Itisalittleintimidatingfornewcomers,butovertime,theresourcesandtutorialsonthesitehaveimprovedandperhapsonedayofhead-scratchingawaitsyou.TrustmethatonedayIwillbepaidbackhundredfold.TheProGitbookcanbedownloadedforfreefromtheGitsiteatgit-scm.com/book/en/v2.Thereisalsoawonderfulinteractivetutorial(try.github.io)ontheGitsite.Asadie-hardLinuxenthusiast,itpainsmetoadmitit,butIactuallyfoundlearningonWindowseasierbecausetheyprovideawonderfulGUItogetyoustarted(alsoonOSX).ThisdoesnotmeanthatyouneedtouseWindowsorshouldsticktoWindows;IhappilydroppedtheGUIandwenttotheterminalinLinuxonceI'dfoundmyfeetabit.

It'salsoworthnotingthattherearesomegreatGUIsforLinuxaswell,soyoucancheckyourpackage-managementsystem.Ididn'tfindanythatsupportedbeginnerssowellastheofficialWindowsorOSXversions,though.GithasalistofGUIsatgit-scm.com/downloads/guis.NotethatsomeofthesesupportGitHubandotherssupportGititself.ThelistincludestheWindows,OSX,andLinuxGUIs.

Finally,RStudioitselfactuallysupportsGitandGitHub,andonceyou'veinstalledGitandsetupyouraccount,youcanprettymuchrunthewholeshowfromwithinRStudioitself.

UsingGitandGitHubwithinRstudioToinstallGit,simplygototheURLmentionedearlieranddownloadthe.exefileforWindows,oronUbuntu,runthefollowingcommand:

sudoapt-getinstallgit

ForotherflavorsofLinux,checkthepackage-managementsystem.HavinginstalledGit,younowneedtosetupanewprojectwithinRStudio.Aversion-controlwithGit(orSVN,adifferentversion-controlsystem,whichwewillnotconsiderhere)isonlypossiblewhenweuseaprojectwithinRStudio.

ProjectsinRStudio(h3)UsingprojectsinRStudioisagoodwaytoorganizeyourwork.EachprojecthasitsownworkingdirectorywithaseparateRsession,workspace,consoleinputhistory,andopeneditortabs(amongotherthings).Eachtimeaprojectisopened,eachofthesewillbesettothevaluecurrentlyassociatedwiththeproject,ineffectlaunchinganewRsession,loadingthedataandconsolehistorysincethelasttimetheprojectwasused(iftheyareselectedasthedefaultbehaviororindividuallyforthisproject),settingtheworkingdirectorytotheoneassociatedwiththeproject,andsoon.Thisallowsyoutoswitchinandoutofdifferentprojectseitherasyouworkorwhenyoupickupworkthenextday.Tosetupanewproject,gotoFile|NewProjectinRStudio.SelecteitherNewDirectoryifthisisacompletelynewsetofcodeandfilesthatyouwanttocreateanewfolderfor,orExistingDirectoryifyouhavealreadystartedandjustwanttopointtheprojecttoadirectorythatyouhavealreadycreated.Onceyouhaveaprojectsetup,gotoTools|Versioncontrol|ProjectSetup....Thefollowingmenuwillappear:

MakesurethattheGit/SVNtabontheleft-handsideofthepageisselectedandusetheversion-controlsystemcontrolontheright-handsideofthepagetoselectGit/SVN,ifyouprefer,butthiswillonlyappearifyouhaveinstalledit,andthiswillnotbecoveredinthischapter.YoumayneedtoreopentheprojectatthispointbygoingtoFile|Recentprojects.Youwillneedtoconfiguretheremoteconnectionbetweenyourlocal.gitrepositoryandtheGitHubaccountyourself.GotoyourGitHubaccount,andgotoRepositories|New.Giveitanameanddescription,andselectCreaterepository.Havingdonethis,someinstructionswillappearonthescreenthatwillhelpyoutosetupaconnectionbetweenthisremoterepositoryandthelocalversiononyourmachine.Atthetimeofwriting,thesimplestwayofdoingthisisthethirdboxdown.Keeptheseinstructionsasyouwillneedthemlater,butfornow,weneedtoconfigureRStudioalittlefurther.GototheTools|Globaloptions,andselecttheGit/SVNtab.Thefollowingmenuwillappear:

CheckwhethertheGitexecutableissetupcorrectlyinthefirstline.IfyoualreadyhaveanSSHRSAkey,itshouldbedisplayedinthebottomline.Ifnot,clickonCreateRSAKey,andyouwillbeguidedtocreateone.IfyouhavenotpreviouslypairedyourRSAkeywithyourGitHubaccount(whichyouwouldnothavedoneifthisisyourfirstexperiencewithGitHub),clickonViewpublickeyabovethethirdline,andthencopytheresultingtextintoyourGitHubaccountbygoingtoyouraccountsettings.Thiscanbeachievedbyclickingon

youruserportraitatthetop-rightcorneroftheGitHubwebpage.Next,clickonSettings,andthenclickontheleft-handsideofthescreenandselectSSHkeys,andfinally,clickonAddSSHkey,pasteyourkey,andclickonAddkey.Havingdonethis,youwillneedtocommityourcodetoGit,thatis,tothelocalcopyonyourmachine.ThisisveryeasyinRStudio.SelecttheGittabintheEnvironmentpaneinRStudio(bydefault,it'sthetop-righttabonthescreen),asshowninthefollowingscreenshot:

Selecttheelementsthatyouwanttocommitbyclickingontheboxestothefarleftofthescreenshot.ThiswillbeanythingthatyouwanttocommittoGitforyourfirstsubmissionandanythingthathaschangedforsubsequentsubmissions.ClickonCommitinthemenubar,whichisvisibleinthescreenshot.Youwillbepromptedtoreviewthechangesinanewwindowaswellasinstructedtowriteacommitmessageinthetop-rightcornerofthiswindow.Youcannotcommitwithoutamessage.Foryourfirstcommit,youmightliketowriteFirstcommitofbetaversion,andthenforsubsequentcommits,youmightmakecommentssuchasFixedjQuerybugandAddeddashboardelements,dependingonthechangesyouhavemade.Finally,topushtoGitHubforthefirsttime,selectMore|ShellintheGittab.Thiswillopenaterminalwindow.RemembertheterminalcommandsthattheGitHubwebpagegaveuswhenwesetupthenewrepositoryandthetwo-linerItoldyoutokeeptrackof?Thisiswhereweneedthem.Linebyline,copy

thetwo-linerfromthewebpage.ThiswillsetuptheconnectionbetweenRStudioandGitHub.Fromnowon,youcanpushyourcode(thatis,uploadittoGitHub)bycommittingandclickingonthePushbuttonintheGittabmenubar.ThisisaverybriefintroductiontoGit,GitHub,andRStudio,andisdesignedtogetyoustarted.Thereismuchmoretolearnabouthowtousethesetoolsefficiently,andyouareadvisedtotakealookattheonlinedocumentationforallthreeinordertolearnhowtomakethisprocessevensimplerandmorepowerful.

SharingapplicationsusingGitWeneedtoconsultthewebsitesmentionedearlierformoredetailsofeachofthesesteps.Onceyou'vesetyourGitversioncontrolandpairedwithanonlinerepositoryatGitHub,youcanveryeasilyshareyourcreationswithanyonerunningtheRandShinypackageusingtherunGitHub()command,whichtakesthenameoftherepositoryandtheusernameasmandatoryarguments:

runGitHub("GoogleAnalytics2ndEdition","ChrisBeeley")

Codeanddataarebothautomaticallydownloadedandrun.IfyouareusingRStudioandwanttolaunchyourownexternalbrowser,asopposedtousingtheonethatisbuilt-in,youneedtoaddlaunch.browser=TRUE.Ifyoudon'twantorneedversioncontrol,anddon'tneeddatatobeincludedinthedownload,asimpleroptionistouseGist,whichisalsohostedatGitHubatgist.github.com.UsingGistissimplyamatterofvisitingtheURL,settingupanaccount,pastingyourcodeintoit,andgivingtheserver.Randui.Rfilesthecorrectfilenames.YouwillthenhaveaURL,usingwhichyoucanshowyourcodetoothers.RunningthiscodefromtheShinypackageisjustamatterofusingrunGist()withtheURLorevenusingtheuniquenumericidentifierfromtheURL.

library(shiny):

runGist("https://gist.github.com/ChrisBeeley/a2f1d88dfedcd2e1cb59")

runGist("a2f1d88dfedcd2e1cb59")

Sharingusing.zipand.tarProbablythenextmostfrictionlessmethodofdistributingaShinyapplicationtoRusersisbyhostingeithera.zipor.tarfileofyourapplication,eitherovertheweborFTP.Youwillneedsomewheretohostthefile,andthenuserscanruntheapplicationusingrunUrl(),asfollows:

runUrl("http://www.myserver/shinyapps/myshinyapp.zip")

NotethatthisURLisnotreal.Youneedtoreplaceitwiththeaddressofyourownfile.

Ofcourse,youcandistributea.zipfileanywayyoulike—yourusersneedtoonlyunzipandthenuserunApp()fromwithinthedirectory,justasyoudowhentestingtheapplication.YoucanemailthefileanddistributeitonaUSBdriveforanymethodthatyouchoose.Thedisadvantagesofthismethodarethatyourusershavetounzipthefilethemselves(althoughthisisunlikelytoconfusemanyRusers),andanychangesmadetotheapplicationwillalsoneedtobedistributedmanually.

SharingwiththeworldInmostcases,anyseriousworkthatyoudowithShinywillatsomepointneedtobesharedwithanonR-user,whetherit'sanontechnicalcolleagueinyourdepartmentorthewholeoftheinternet.Inthiscase,abitmoreofthelegworkfallstoyou,butyoushouldstillbepleasantlysurprisedabouthowsimpletheprocessis.Therearetwooptionshere:setupyourownserverorgetapaidaccountwithRStudiotodoitforyou.

Shinyapps.ioShinyapps.ioisRStudio'spaidhostingforShinyapplications.Atthetimeofwriting,thereisatieredpricingstructure,dependingonthenumberofapplicationsyouwishtodeploy,whetheryouneedtheauthenticationofusers,thenumberofhoursyourapplicationswillrunpermonth,andsoon.Youcansetupafreeaccountthat,atthetimeofwriting,allowsfiveapplicationsand25hoursofapplicationruntimeamonth.Thisiswelcome;however,itisonlysuitableforverysmall-scaleuse;asingletweetofyourapplicationonthe#rstatshashtagislikelytobringenoughtraffictoyoursitetouseallofthe25hoursinaveryshorttime.Indeed,Ihavebeenlinkedtomanyshinyapps.ioapplications,whichindicatethattheaccounthasexceededtheallocatedhoursthismonthand,therefore,doesnotwork.

Bewarned:ifyouwanttheworldtoseeyourapplication,youeitherneedtogetapaidaccountorrunyourownserver(whichisexplainedlater).Usingthisservicedoes,ofcourse,entailcopyingyourcodeand/ordatatoathirdparty,soifthisisaproblemforyou,youwillneedtotakealookathostingyourselfonaserver.

IfyouareusingRStudio,itisveryeasytogetanapplicationonshinyapps.WheneveryouhaveaShinyapplication(thatis,aserver.Rorui.Rfile)open,youwillfindalittlePublishiconintheupper-rightcorneroftheeditor,asshowninthefollowingscreenshot:

Youwillbepromptedtoinstallvariousthings,dependingonyourOSandtheconfigurationofyourRinstallation.OnLinux,youwillprobablysaveyourselfabitofconfigurationifyouinstallthedevelopmentversionofR(r-base-devonUbuntu,availablethroughtheRmetapackageonFedora;forotherdistributionsoroperatingsystems,refertotherelevantdocumentation).

Foralloperatingsystems,youwillbepromptedtoinstallvariousRpackages.UsersofLinuxmayhaveproblemsconfiguringsomeofthesepackages;youmayneedtoinstalllibcurl-devandopenssl-dev(ortheirequivalentforyourdistro).InWindows,inmyexperience,thewholeoperation,rightfromthevanillainstallationofR,iscompletelyseamlessandeverythingwillbeinstalledandconfiguredcorrectly.

Then,youwillbepromptedtogotoyourshinyapps.ioaccountandlogin,whereyoucanauthenticateRStudio.YoucannowpublishitstraightfromRStudio:

1. Pressthebuttonhighlightedintheprecedingscreenshot,selectthefilestobeuploaded(forexample,thecodeanddatafiles),andclickonPublish

2. Itwilllaunchabrowserforyou,soyoucanseetheapplicationforyourselfandcopythelinkthatneedstobeshared

3. Ifyouforgetthelink,justlogintoshinyapps.io—thelinkisavailablefromyourlistofapplicationsinthemenu

Shinyapps.iowithoutRStudioIt'snotnecessarytouseRStudiotouseshinyapps.io,it'sjustabiteasier.Youneedtofollowthesesteps:

1. Ifyou'rehappierinanotherIDE,youjustneedtoensurethatyouhavethelatestversionofdevtoolsinstalled:

install.packages('devtools')

2. Installshinyapps:

install_github('rstudio/shinyapps')

3. Loadshinyapps:

library(shinyapps)

4. Logintoyourshinyapps.ioaccount,copytheauthorizetokencommandfromthetokensmenu(tokenmarkedwithXshere),andrunitinyourRsession(notethatthisonlyhastobedoneonceoneachcomputer):

shinyapps::setAccountInfo(name='chrisbeeley',

token='XXXXXXXXXXXXXXXXXXXXXXXX',

secret='XXXXXXXXXXXXXXXXXXXX')

5. Setyourworkingdirectorytothefolderthatholdsyourapplication:

setwd("~/myShinyApp")

6. Deploy:

deployApp()

MoredetailsareavailableonRStudio'spagesatshiny.rstudio.com/articles/shinyapps.html.

ShinyserverIfyouwanttohosttheapplicationsyourself,ShinyServerisavailableforLinux.Again,therearepaidandfreeoptions.ShinyServeristotallyfreeandopensource,whichisagreatcredittoRstudio.Thepaidversionhasanumberofbenefits.Themainonesaretheprovisionofsupportandextrafeatures,particularlyauthentication(LDAP/PAM/GoogleaccountsandrunningoverSSLtoencryptdatatoandfromtheserver).ItalsoallowsyoutousemultipleRprocessestoserveoneapplication,supportsmultipleversionsofRonthesameserver,andprovidesanadmindashboardthathelpsserveradministratorstomonitorserverload,concurrentconnections,andsoon.

BinariesareavailableforUbuntu,RedHat,CentOS,andSUSEEnterprise;forotherdistributions,itispossibletobuildfromthesource.Thefreeversionis,inmyexperience,stableandwell-featured.Installationdetailscanbefoundatrstudio.com/products/shiny/download-server/.

Followtheinstructionsmentionedpreviouslytoinstall,andusingthedefaultconfiguration,youshouldbeabletonavigatetoatestShinyapplicationbygoingtochrisbeeley.net:3838/shiny/01_hello/inawebbrowser(replacethedomainwithyourownURL).InorderforShinyServertowork,youneedtoopentherelevantport(inthiscase,thedefaultconfiguration,3838)onyourfirewall.Bydefault,applicationsarerunfromfileslocatedwithin/srv/shiny-server.Youcanincludedirectorieswithinthisfoldertoorganizeyourapplications.Theadministrator'sguide,whichislinkedtoandfromthedownloadpage,includesdetailsofhowtoconfigureShinyServer.

YoumaywishtochangetheportthroughwhichShinyservercommunicates(again,openingthisportonyourfirewall),changethelocationofapplicationfiles,oraddseverallocationstoapplicationfiles,orsomethingelseentirely.Thecompletedetailsareavailableinthedocumentation.InstallationonUbuntuisembarrassinglyeasy;evenwithmylimitedknowledgeofrunningLinuxservers,Ihaditupandrunningonmypersonalserverinlessthananhour.It'srunquitehappilyeversince.Mileagewithotherdistributionswillvary,althoughjudgingfromforumandblogposts,peoplehavesuccessfullyrunitonavarietyofdistributions.Dependingonwhatyouaredoingwithyourapplication,onething

tobecarefulofisdirectoryownershipandpermissions.

Forexample,oneofmyapplicationsproducesPDFfilesfordownload.ThisrequiresmakingShinytheownerofthedirectorywithintheapplicationfolder,whichhousesthetemporaryfilesthatareproducedfordownloadandmakingthedirectorywritable.Inacorporateenvironment,youmayalsofindthattheportShinyusesisblockedbythefirewall—changingtoadifferentportissimplyamatterofeditingtheconfigurationfileasdetailedontheShinyserverwebpagegivenpreviously.IfyouareinacorporateenvironmentrunningWindows,it'sworthnotingthattheopenversionrunsfineonanUbuntuservervirtualizedonWindows,inmyexperience.Icouldn'tspeakforthepaidversion,andI'msureRStudiowouldbehappytoadviseyouifyouwerethinkingaboutpayingforalicense.

RunningShinyapponAmazonAWSWehavethoroughlydiscussedhowtodevelopShinyapps.Nowit'stimetodiscussdeployingtheShinyapponAmazonAWS.Thedeploymentoftheapplicationisnecessarytomakeitavailableforusers.TodeployitonAmazonAWS,wehavetofollowthesesteps:

1. RegisterwithAmazonAWSandoptforEC2.Amazonprovidesafreesubscriptionforwhichtheuserhastoprovidecreditcarddetails.Suchschemesaresubjecttochangeaspercompanypolicy.

2. Logintoyouraccount,gotoAWSservice,andthentocomputeandfindEC2.ClickonEC2andadashboardwillappear.ClickonLaunchInstanceanditwilldiverttochooseAmazonMachineImage(AMI).SupposewehavechosentheUbuntuserver.Nowit'stimetochoosetheinstancetype,whichcanbet2.small,t2.micro,t2.large,andmore.Clickonthelaunchbuttonandanotherwindowwillcomeforreviewlaunch.Reviewandclickonlaunch.

WecanalsoconfiguresecuritybyConfigureSecurityGroup.InthisSSHrowcanbechangetoMYIP.Clickonaddrule,andaddacustomTCPrule.Underportrange,changeitto3838,whichistheportforShinyserver.

Afterthis,clickonreviewandlaunchandyouwillgetadialogueboxforgeneratingaprivatekey.Here,wehavetogiveanametothekeyandclicktodownloadthekeypair.Afterthat,wewillgetthe.pemfile.Saveitsecurely.ClickonlaunchandgettheEC2instancerunningsuccessfully.CopytheIPaddressavailableundertheDNS(IPv4).

3. AccesstheEC2thatwecreated.Downloadputty,andconvertthe.pemfileintoppk.ClickonPuttygen,thenFiletab,andloadtheprivatekey.Navigateto.pemandimportit.Savetheprivatekeywithanametoyourdesiredlocation.Afterdoingallthis,wehaveour.ppkfile.Openputty,andinthehostnamebox,entertheIPaddressoftheEC2instance.NavigatetoAuthfor

authenticationandimporttheppkkeythatwecreated.ClickonOpenandenteryourcredentials.

4. DownloadWinSCP,typetheEC2IP,andclickonadvance.UnderSSHAuthentication,entertheprivatekeyandclickonOk.EnternameasIPaddressandusernameandpassword.ClickYesinthedialogueboxthatappears.

5. Gototheroot.Gotothepromptandtypesudo-i,thenwewillgetthe#symbol.Runthefollowingcommands:

sudoapt-getupdate

sudoapt-getinstallr-base

sudoapt-getinstallr-base-dev

sudosu - -c"R-e\"install.packages('shiny',repos='http://cran.rstudio.com/')\""

ToinstallShinyserver,runthefollowingcommand:

wgethttps://download3.rstudio.org/ubuntu-12.04/x86_64/shiny-

server-1.4.4.807-amd64.deb

sudodpkg-ishiny-server-1.4.4.807-amd64.deb

6. Wecanseethefoldershiny-serverinthe/srv/shiny-server/path.Executethefollowingcommands:

sudochmod777/srv/shiny-server

sudomkdir/srv/shiny-server/Myapp_components

Intheprecedingcommand,theMyapp_componentsfolderiscreatedtosavethevariousshinyappcomponents,suchasserver.Randui.R.

7. AswehavealreadyinstalledandconfiguredwinSCPandcreatedtheMyapp_componentsfolder,wearereadytosendthecomponentstotheEC2instance.Configuretheshiny-server.conffile,whichislocatedin/etc/shiny-server/.Executethefollowingcommand:

sudochmod777/etc/shiny-server

Nowwecancopyconfigfileontothelocalsystem,editit,andsaveitback.

8. GototheAmazonconsoleandfindtherunningEC2instance.CopythepublicDNS,ec2-34-215-115-68.us-west-2.compute.amazonaws.com,appenditwith

3838/Myapp_components,andpastethisinyourbrowser'sURLbar.PressEnterandyourappshouldstartrunning.

Scoping,loading,andreusingdatainShinyapplicationsAlthoughloadingandreusingdatainShinyapplicationsiscoveredinthischapter,becauseitislikelythatthesefeatureswouldbeusedinashinyapps.io-hostedapplication,muchofitalsoappliestolocally-runShinyapplications.Ifyouuseshinyapps.io,itwillexpectyourapplicationtobeportable,thatis,toavoiddependenceonwritingpermanentchangestothelocalfilesystem.Thisisbecausetheapplicationmightbemovedtoanotherserverforload-balancingpurposes,renderingchangestothepreviouslocalfilesysteminaccessible.Youcanwritetemporaryfileswhileauserisconnectedtotheapplication(forexample,iftheuseruploadstheirowndata,thiscanbesavedtemporarily),butanychangesmadewillbelostwhentheuserexits.

DependingontheenvironmentinwhichyouarerunningandthetaskyouarecarryingoutwithyourShinyapplication,itisusuallyagoodpracticeinmostcasestomakeallShinyapplicationsportable.Bymakingtheapplicationportable,youcannotonlyseamlesslyswitchtoshinyapps.io(evenifitisjusttoshareabetaversionwithcolleaguesusingafreeaccount),butitalsomeansthattheapplicationisportableacrossothercontexts;forexample,ifyoudistributeitviaa.zipfile,changeyourcomputer,ormigratetheserveronwhichyourunShinyServer.Itisimportant,therefore,tounderstandthescopingofdatawithinShinyapplicationsaswellasthemeansofgettingdatainandout,bothtemporarilyandpermanently.

Temporarydatainput/outputTherearethreelevelsofscopingwithinthetemporary,portablepartofaShinyapplication:

Thelowestlevelisdatathatisread-onlywithineachindividualinstanceofaShinyapplication.Thislevelisquiteusefulifauserwantsafreshcopyofdataeachtimetheyvisittheapplication(ifdataneedstobeevenfresherthanthis,itcanbeplacedinareactivefunction).AnydataloadedaftertheshinyServer()functionwillbescopedlikethis.Notethatthisdataisonlyavailablefromtheserver.Rfileandnotfromtheui.Rfile,whichisloadedfirst.Thenextlevelupisdatathatisavailabletoallinstancesoftheapplication(again,justwithinserver.R).Thiscanbeusefulifthereisaverylargedatasetthatneedstobeloadedorthatneedssignificantprocessing;thiscanthenbedonethefirsttimetheapplicationspinsup,sousersdonothavetowaitforit.AnydataloadedbeforetheshinyServer()functionwillbescopedinthisway.Lastly,itispossibletomakedataavailabletoui.Randserver.Racrossallfunctionsbyloadingitinafilecalledglobal.R.Itisn'tveryoftenthatyouwouldwanttodothis;Ineverhave,butyoumayfinditusefulifyouwishtoconfigureyourUIusingdatabutdon'twantorneedtheextracodeandprocessingtimeadynamicUIwouldnecessitate.

RememberthatitisveryeasytogetdatainandoutofShinysessions(thatis,temporarily)usingthefileInput()anddownloadHandler()functions.

PersistentdatastorageIndatascienceproductdevelopment,oneofthemostimportantstepsistobringdatafromvarioussourcesandkeepitonstoragesystems.Mostly,data-storagemanagementfordatascienceprojectsisdonewithadatawarehouse.Nowadays,varioustechnologieshavebeendevelopedtostoreandprocessvarioustypesofdata,whichcanbestructured,semi-structured,orunstructured.UsingHadoop,HDFS,Hive,MongoDB,SQLite,orMySQL-liketoolsandtechnologiesarecoupleduptodevelopanecosystemtomakeforeasyavailabilityandfastprocessingofdata.

Innormalsoftware,thedatasourcesareusuallyRDBMSandmeanttodealwithonlinetransactionalrequirements.Butindatascienceprojects,thescenariosarequitedifferent.Here,generallyhistoricaldataisusedtopresentgraphsorgeneratereports.AndsinceShinyisalsoconsideredatooltopresentdata,itislesslikelytoexpectthatitsappswillacceptdatafromusersallthetime.Butthiscasealsoneedstobeconsidered.Inthissection,wewilldiscussthepersistentdata-storageoptionsavailablewithshinyappsandinwhatsituationstheyaregoingtobeused.

Asofnow,whateverShinyappswehavedevelopedareusinginbuiltdata.Suchdataiskeptlocallywheretheappresides.Forverysmalldata,thistechniquecanworkforsometime.Butasthedatagrows,theappwillbeunmanageable.Insuchscenarios,weneedtolookforotheroptionsthatcanhandlethegrowingdemandofdata.Today'sworldhassurpassedthebigdatalimits.So,whataretheoptionsavailable?

Let'sdiscusssomeofthepersistentdata-storageoptionsavailable:

Localfilesystem:Thisisaveryeasywaytostoredatawheretheappresides.Ifwehaveconfiguredtheshinyserverin-houseforthedeploymentoftheapp,wecantakesomememorytosavethedataacceptedfromuserorgeneratedduringtheexecution.Withthismethod,datacanbesavedandaccessedveryfast.Supposewewanttosavedataintoadataframeandkeepaddingdataintothistable.Wecanfollowsomeeasystepsand

developourapp:

1. WithanewRscriptfile,createadataframe:

NewDF<-data.frame("Sn","Name","Age")

Aftertheexecutionoftheprecedingcode,NewDFdataframewillbereadytouse.

NowifwewanttoadddatatothisNewDF,wehavetowritethefollowingsimplecode:

#insertdatainfirstrow.

NewDF[1,]<-c(1,"Rahul",25)

#insertdatainsecondrow

NewDF[2,]<-c(2,"Sumit",26)

2. IntheNewDF[1,]code,thefirstpartofthesubscripthastherownumberandthesecondcolumnnumber.NewDF[1,]isreferringtothefirstrowandallthecolumns.Similarly,NewDF[2,]referstothesecondrowandallthecolumns.Inthisway,datacanbeadded,modified,anddeletedwiththehelpoftheshinyapp.Andatthesametime,dataisresidingonapersistentstorage.Thisisoneofthemostimportantmethods,becausewhicheverecosystemisfollowedfordata-warehousing,somepartofthedatahastobekeptonShinylocalstorageforprocessing.

Dropbox:Dropboxisaverypopularstoragesystemavailableremotely.Itsupportsavarietyoffileformats.rdrop2isapackagetoaccessDropboxfromR.Itprovidesfunctionsforlistingfiles,copying,moving,anddeleting.ToaccessDropbox,wehavetofirstcreateanaccount.Thebasicsubscriptionisfreeandprovides2GBspaceforuse.Pleasevisithttps://www.dropbox.com/individualforabasicsubscription.TousedatafromDropbox,weneedtogothroughtheauthenticationprocessfirst:

library(rdrop2)

drop_auth()

Afterexecutingtheprecedingcode,itwilllaunchthebrowserandaskforyourDropboxaccountdetails.Wehavetologintoouraccount.Oncethisprocessisdone,closethebrowserandcompletetheauthenticationfromR.Thecredentialscanbeautomatically

cachedandusedinfuture.Wecanalsosavethetokenusingthefollowingcode:

token<-drop_auth()

saveRDS(token,file="token.rds")

Wecanalsoretrieveouraccountinformationusingthedrop_acc()%>%data.frame()command.MostofthecommandstoaccessDropboxfromRstartwithdrop_likedrop_acc().Fordirectory-listing,drop_dir()canbeused.IfyouwanttouploadafiletoDropbox,wecanusethefollowingcode:

write.csv(newFile,"newfile.csv")

drop_upload("newfile.csv")

Inasimilarway,drop_create(),drop_download(),drop_delete(),drop_move(),anddrop_copy()canalsobeused.AllthesediscussedfunctionscanbeusedwithRShinyapps.

AmazonAWSS3:Apopularplatformforfilehosting.Itkeepsfilesinbuckets.aws.s3isthepackageprovidedwithRtoaccessAWSS3.Theaws.s3packageisnotavailableonCRAN.Thefollowingcodecanbeuseforinstallation:

#lateststableversion

install.packages("aws.s3",repos=c("cloudyr"=

"http://cloudyr.github.io/drat"))

#onwindowsyoumayneed:

install.packages("aws.s3",repos=c("cloudyr"=

"http://cloudyr.github.io/drat"),INSTALL_opts="--no-multiarch")

Tousethispackage,weneedtocreateanaccountwithAmazonAWSforS3.Afreeaccountcanalsobecreatedwithlimitedaccessforoneyear.Oncewegetregistered,wecangeneratekeypairsontheIAMManagementwindowwiththeheadingaccesskey.Youcanalsovisithttps://github.com/cloudyr/aws.signature/formoredetaileddescriptionsofthecredentials.ItcanalsobedonethroughRusingthefollowingcode:

Sys.setenv("AWS_ACCESS_KEY_ID"="mykey",

"AWS_SECRET_ACCESS_KEY"="mysecretkey",

"AWS_DEFAULT_REGION"="us-east-1",

"AWS_SESSION_TOKEN"="mytoken")

Aftersettingcredentials,wecanaccessbucketsusingthefollowingcode:

"library("aws.s3")

bucketlist()

Wecanalsoaccesspublicly-listedbuckets:

bucketlist()get_bucket(bucket='1000genomes')

TogetalistofalltheobjectsintheprivateS3bucket,thefollowingcodeisuseful:

#specifykeys

get_bucket(

bucket='my_bucket',

key=YOUR_AWS_ACCESS_KEY,

secret=YOUR_AWS_SECRET_ACCESS_KEY

)

#specifykeysasenvironmentvariables

Sys.setenv("AWS_ACCESS_KEY_ID"="mykey",

"AWS_SECRET_ACCESS_KEY"="mysecretkey")

get_bucket("my_bucket")

Theaws.s3packagehasmanyfunctions.Someofthemareasfollows:

bucketlist():Providesadataframeofusers'buckets.get_bucket():Providesalistanddataframe,respectively,ofobjectsinagivenbucket.get_bucket_df():Providesalistanddataframe,respectively,ofobjectsinagivenbucket.object_exists():Providesalogicaloutputforwhetheranobjectexists.s3read_using():ProvidesagenericinterfaceforreadingfromS3objectsusingauser-definedfunction.get_object():ReturnsarawvectorrepresentationofanS3object.s3connection():ProvidesabinaryreadableconnectiontostreamanS3objectintoR.SQLite:Alightweightdatabaseengineavailablepublicly.Itsupportsstructureddata-management.Wecancreatetablesandperformupdate,deletion,andinsertionoperationsonit.Italsosupportstransactionmanagement.

ToembedSQLiteintoR,theRSQLitepackageneedstobeinstalled.ItisavailableonCRAN:

install.packages("RSQLite")

AconnectiontoSQLitecanbecreatedusingthefollowingcommand:

library(DBI)

con<-dbConnect(RSQLite::SQLite(),":memory:")

dbListTables(con)

Usingtheprecedingconnectionobject,con,wecanwritethedatasetinSQLite,asshowninthefollowingsnippet:

dbWriteTable(con,"iris",iris)

dbListTables(con)

Tofetchthecolumnsofthetable:

dbListFields(con,"iris")

Andtofetchtheentiretable:

dbReadTable(con,"iris")

Afterusingoftheconnection,wemustcloseitusingdbDisconnect(con):

MySQL:MySQLisaverypopularRDBMSdatabase-managementtoolavailablepublicly.ItissimilartoSQLitebutmorepowerful.Itcanbehostedlocallyorremotely.WecanusetheRMySQLpackagetointeractwithMySQLandR.ThepackagecanbedownloadedfromCRAN:

install.packages("RMySQL")

ToinstallintheLinuxplatformorOSX,youneedtheMariaDBConnector.RMySQLactsasaninterfacebetweenRandMySQL:

library(RMySQL)

library(DBI)

con<-dbConnect(RMySQL::MySQL(),group="my-db")

Inthefollowingcode,dbConnect()isthefunctiontoestablishaconnectionwiththeMySQLdatabasefromR.TheconobjectcannowbeusedtoperformvariousoperationsonDatabase.Let'sseesomeofthem:

dbListTables(con)

Theprecedingcodeliststhetablesinthedatabase.TowriteatablefromRintoMySQL,usethefollowingcode:

dbWriteTable(con,"iris",iris)

dbListTables(con)

Wecanalsofetchtheentiretablefromthedatabaseasfollows:

#Youcanfetchallresults:

res<-dbSendQuery(con,"SELECT*FROMiris")

dbFetch(res)

Todisconnecttheconnection,usethefollowingcode.

dbDisconnect(con)

GoogleSheets:Googlesheetsisalsoagoodoptionforstoringdata.Itispersistentandaccessiblefromanywhere.Googlesheetscanbeaccessedusingatitle,key,orURL.Datacanbeeasilyextractedoredited.Wecancreate,delete,rename,copy,anduploadGooglesheets.Wecanalsouploadlocally-generatedspreadsheetsintoGooglesheetsandviceversa.

TouseGooglesheetsfromR,wecanusethegooglesheetspackage.Itisdevelopedtobeusedwiththe%>%pipeoperator.Itusesthedplyrpackageinternally.ItcanbedownloadedfromCRAN:

install.packages("googlesheets")

Withthispackage,ademosheetforpracticeisavailable,namedGapminder.Let'susesomecodetoplaywiththissheet:

gs_gap()%>%

gs_copy(to="Gapminder")

Thiscodeisforthecopyingofthesheet.Toviewthesheetinthebrowser:

gap%>%gs_browse()

gap%>%gs_browse(ws="Europe")

Toreadallthedataintheworksheet,wecanusethefollowingcode:

africa<-gs_read(gap)

glimpse(africa)

Africa

Wecanalsotargetspecificcells:

gap%>%gs_read(ws=2,range="A1:D8")

Wecanalsocreatenewspreadsheets:

giris_ss<-gs_new("iris",input=head(iris,3),trim=TRUE)

WecanexploremoreaboutgooglesheetsandRathttps://github.com/jennybc/googlesheets#install-googlesheets.

DatabaseusingDplyr,DBI,andPOOLInthissection,wewilllearntousethedplyrpackagetoaccessdatafromdatabasesources.WewillalsoseehowtohookuptoanexternaldatabaseusingtheDBIpackage.ThePoolpackageisalsoanimportanttopictomanageconnectionsandpreventleakstomanageperformance.

dplyr:Apopulardata-manipulationpackageforinternalandexternaldatabases.ItinternallyworksasSQL.Itprovidesavarietyoffunctionsfordatamanipulation:

filter()

select()

arrange()

rename()

distinct()

mutate()

transmute()

summarise()

sample_n()

sample_frac()

Let'sseeanexampleusingsomeofthesefunctionswiththeirisdataset:

library(dplyr)

iris%>%filter(Sepal.Length>4&Sepal.Length<5)

Intheprecedingcode,thefilterfunctionhasbeenusedtofiltertherowsoftheirisdataset,whichhasvaluesbetween4and5.Wecanalsoselectonlycertaincolumns,usingselect():

iris%>%select(Sepal.Length)

Forselectingdistinctvalues,wecanusedistinct():

iris%>%distinct()

Wecanalsousethesefunctionsincombination.Thecodeshownhereisfirstfilteringthedataandthenapplyingselect():

iris%>%filter(Sepal.Length>4&Sepal.Length<5)%>%select(Sepal.Length)

Inthisway,wecangetrideofusingRandSQLseparatelyusingdplyr.

DBI:AcommoninterfacebetweenRandDBMS.Italsoprovidesavarietyoffunctionsforsupportingthefollowingfunctions:

ConnectinganddisconnectingtotheDBMSCreatingstatementsandexecutingintheDBMSExtractingresultsfromstatementsException-handlingTransactionmanagement

dbGetQuery()isaconvenientwayofexecutingquerieswithaconnectionobject.Ittakestwoargumentsimportantlyconnectiontodatabaseandquery:

dbGetQuery(conn,"SELECT*FROMCityLIMIT5;")

Pool:WiththeDBIpackage,therearesomeproblemswithconnection-managementandperformance.Wehavetocreateanddestroyconnectionsasandwhennecessary.Otherwise,therewillbeanaccumulationofleakedconnections.Thisleakedconnectionholdsresourcesthatmusthavebeenfreed.Becauseofthisapp,theperformancegoesdown.Fordealingwithsuchproblems,poolpackageisavailable.Itprovidesanextralayerofabstractionwhileestablishingaconnection.Usingthispackage,wecancreateanobjectwithareferencetothedatabase.Thisobjectiscalledpool.Thismakesusavoiddirectlyfetchingthedatabase.Also,thispoolobjectcanholdanumberofconnectionstothedatabase.Wheneverwearequeryingthedatabase,weareactuallyqueryingtothepoolthatholdstherunningandwaitingconnections.

Thepoolcanprovideuswithidleconnectionsthatwerepreviouslyfetchedorwithanewone.Oncetheconnectionisended,thegarbage-collectionprocessmakesfreeallresourcesheldbytheconnection.So,inthecontextoftheShinyapp,wedon'thavetoworryaboutendingtheconnection.

ThepoolpackageisavailableonGitHubandcanbedownloadedasfollows:

devtools::install_github("rstudio/pool")

Let'sseetheskeletonofaShinyappwithpool:

library(shiny)

library(DBI)

library(pool)

pool<-dbPool(

drv=RMySQL::MySQL(),

dbname="Database_Name",

host="Host_link",

username="username",

password="password"

)

ui<-fluidPage(

#--------Uistuff----------------------

)

server<-function(input,output,session){

#----ServerStuff-------------------

}

shinyApp(ui,server)

WithsqlInterpolate(),wecancreateaquerythatcanbetheinputtodbGetQuery().InsqlInterpolate,wecanseethreeparametersinthefunction:pool,sql,andid.poolistheobjectandsqlistheSQLquery.IDcanbeanyinput.dbGetQuery()willhavetwoparameters.Thepoolobjectandqueryarecreatedusinginterpolate:

query<-sqlInterpolate(pool,sql,id=input$ID)

dbGetQuery(pool,query)

Thisappskeletonisforasingle-fileapp.Foramulti-fileapp,itcanbeputonthetopoftheserveranduifileorinaglobalfile.

SQLInjectionSQLInjectionisakindofattackdonebyaddingSQLquirestotheURLoftheapplication.SuchqueriesexecuteontheDBMSwithouthavinglegitimateaccesstoit.Suchattacksarepossibleiftherearesomebranchesintothecode.Let'sseesomecodetounderstanditbetter:

dbGetQuery(conn,paste0("SELECT*FROMCityLIMIT",input$nrows,";"))

Aswecanseeintheprecedingcode,input$nrowshasbeenputdirectlyintothequery.Ifanattackergotaccesstothisinput$nrows,theycouldinjectanySQLstatementintoit.Inthiscase,thesolutioncanbetopreventanattackerfrompassingvectors.So,thecodecanbemodifiedasfollows:

dbGetQuery(conn,paste0("SELECT*FROMCityLIMIT",as.integer(input$nrows)[1],";"))

Theinputisconvertedintoanintegerfirst.So,ifanattackerputssomeSQLintoit,itwillgetconvertedintoanintegerandloseitsmeaning.Thisisaneasyexample.Let'sdiscussamorecomplexsituation:

query<-paste0("SELECT*FROMCityWHEREID='",input$ID,"';")

Inthiscode,ifanattackergetsaccesstoinput$IDandmanagestomodifythevalue,theycangetthedataofasinglecity.Forexample,input$IDchangedto5meansthatthedataofthecitywithID=5willbeinvoked.Butiftheyaretryingtogetinformationofallthecities,theycantryOR1=1ORandcangetdataofallthecity.Suchinputmakestheconditionalwaystrue.ThesolutiontothisattackistousesqlInterpolate().ItcanbeusedtointerpolatethevaluesintoaSQLstring,whichpreventsaSQLinjectionattack:

sql<-"SELECT*FROMCityWHEREID=?id;"

query<-sqlInterpolate(conn,sql,id=input$ID)

Intheprecedingcode,ifwechangetheinputto'OR1=1OR',itwillbeconvertedintoSELECT*FROMCityWHEREID='''OR1=1OR''',whereithasaddedextra('').ThiswillgiveblanktableoutputandpreventsSQLinjection.Instead,ifweuseinput$ID=6,itwillchangethequerytoSELECT*FROMCityWHEREID='6',whichisavalidID.SotheoutputwillbethedataofthecitywithID=6.

Thisprocessofcheckingandconvertinguserinputintosafevaluesiscalledsanitization.WemustalwaystakecaretosanitizetheuserinputtopreventSQLinjectionattacks.

SummaryInthischapter,welearnedaboutseveralmethodstoshareyourShinyapplicationswiththeworld.ThisprocessisveryeasywithfellowusersofR,andalittleharderwiththewholeinternet;howeveryoudoit,I'msureyou'llagreethatitwasrelativelypainlessandworththeeffort.WediscussedhowtouseGitandGitHub(andGist),andhowtousethemtoshareyourcodeandapplicationswithotherRusers.WealsolookedatdistributingShinyapplicationsmanuallyoroverFTPtoRusersusingthe.zipand.tarfiles.Wecoveredhostingsolutionstoshareyourapplicationwiththewholeinternet,includingShinyapps,ShinyServer,andAmazonAWS.Wewentthroughthepersistentdata-storageoptionsandhowtousethedplyr,DBI,andPoolpackages.WealsosawhowtopreventSQLinjectionattacks.

OtherBooksYouMayEnjoyIfyouenjoyedthisbook,youmaybeinterestedintheseotherbooksbyPackt:

RDataVisualizationRecipesVitorBianchiLanzetta

ISBN:9781788398312

GettoknowvariousdatavisualizationlibrariesavailableinRtorepresentdataGenerateelegantcodestocraftgraphicsusingggplot2,ggvisandplotlyAddelements,text,animation,andcolorstoyourplottomakesenseofdataDeepenyourknowledgebyaddingbar-charts,scatterplots,andtimeseriesplotsusingggplot2BuildinteractivedashboardsusingShiny.ColorspecificmapregionsbasedonthevaluesofavariableinyourdataframeCreatehigh-qualityjournal-publishablescatterplotsCreateanddesignvariousthree-dimensionalandmultivariateplots

DataAnalysiswithR-SecondEditionTonyFischetti

ISBN:9781788393720

GainathoroughunderstandingofstatisticalreasoningandsamplingtheoryEmployhypothesistestingtodrawinferencesfromyourdataLearnBayesianmethodsforestimatingparametersTrainregression,classification,andtimeseriesmodelsHandlemissingdatagracefullyusingmultipleimputationIdentifyandmanageproblematicdatapointsLearnhowtoscaleyouranalysestolargerdatawithRcpp,data.table,dplyr,andparallelizationPutbestpracticesintoeffecttomakeyourjobeasierandfacilitatereproducibility

Leaveareview-letotherreadersknowwhatyouthinkPleaseshareyourthoughtsonthisbookwithothersbyleavingareviewonthesitethatyouboughtitfrom.IfyoupurchasedthebookfromAmazon,pleaseleaveusanhonestreviewonthisbook'sAmazonpage.Thisisvitalsothatotherpotentialreaderscanseeanduseyourunbiasedopiniontomakepurchasingdecisions,wecanunderstandwhatourcustomersthinkaboutourproducts,andourauthorscanseeyourfeedbackonthetitlethattheyhaveworkedwithPackttocreate.Itwillonlytakeafewminutesofyourtime,butisvaluabletootherpotentialcustomers,ourauthors,andPackt.Thankyou!