Australian Inbound Tourism Insights

This R Markdown document provides an interactive dashboard for exploring tourism data in Australia. The insights are derived from various datasets, including visitor growth analysis, behavior analysis, and tourism hotspot identification.

Australian Inbound Tourism Roadmap

The overall layout of the Australian Inbound Tourism Dashboard consists of a yellow header with the title of the project (R shiny headed colors are limited to 6). The colour is closer to “yellow ochre” which is easy on the eyes but ensures to capture attention without fail. The Tourism Australia logo is placed on the lefthand

side to signify the project owner, the black side bar with the tabs allows easy access to the visualizations whilst maintaining a clear roadmap illustrating the story behind the topic of interest and highlighting the information available on the portal. The background is maintained as light grey or white to ensure more comfort to the end user when working with a screen for long hours. The landing page was designed to convey the main message which is the flow of the four main areas of interest in the subject of Australian Inbound Tourism. The portal provides insights of the four areas which includes Tourism growth, tourist behavior, composition and tourism hotspots. Furthermore, it provides a summary of what is provided in each of the tabs. A user can click on the three lined menu icon to open the navigation panel and select the tab of interest. Furthermore, the lower section provides the hyperlinks to the original datasets that were utilized in the development of the portal.

Alt text
Alt text

Analyzing Inbound Tourism Growth

When working with dashboards or any sort of visualizations, majority of the time people tend to want the ability to drill down to obtain more information. They require the flexibility to utilize it as a tool to answer the questions they have without it being a more general product. The trend analysis tab has been equipped with a “date range” filter so people can customize the visualization according to their needs. For example, some may want to understand tourist nationality wise growth prior covid or in another scenario they might want to understand the recovery rates based on the country of residence. Furthermore, a “chart type” filter was incorporated incase the business users have the need to understand tourism growth in terms of world regions (Such as Asians, Europeans, Africans…etc) or even the overall tourism arrival trends (Refer figure 3.2.3). In addition, a “Top countries” filter have been provided ranked by the average number of visits per year to allow the users to avoid congesting the visualizations (Refer below).

Alt text
Alt text
Alt text
Alt text

The interactive line graph consists of a tooltip to highlight the required information from the graph. The colors utilized are from the “ggplot default” color palette. The main purpose of color in this visualization was to signify its line graphs of tourist arrivals by multiple nationalities. Regardless of the quantity of the lines mapped on the graph, the colors provided were significantly distinct. This is most apparent when analyzing 10 or less nationalities at a time. On the left-hand side, a summary of the tourist arrivals by country of residence is given, along with the average visits per year and the growth rate based on the date range selected. The highlight table is colour coded with green to signify growth or red to signify a decrease. Furthermore, these key performance indicators are marked with an upward arrow to signify growth and a downward arrow for a decline. Both colour and mark visual variables are utilized to increase the distinctiveness in the visualization.

Alt text
Alt text

Analyzing Inbound Tourist Behavior

Humans are creatures of habits. Their way of life and preferences vary which defines them. But in today’s competitive environment, businesses deep dive into market segmentation and customer analytics to better cater to their target market. Similarly, the aim of the insights portal is to allow the business users to keep tabs on the average expenditure habits of tourists from different nationalities.

Understanding their expenditure preferences better will pave the way to more attractive pricing, products, and services. For this requirement we have used a scatter plot, a traditional way of establishing a relationship between two variables. This specific form of visualization was selected with the end user in mind. In today’s age nearly everyone is familiar with scatterplot. Its simplicity and wide awareness will be ideal when presenting to a busy business community. But most of all, it clearly establishes the presence or a lack of a relationship which is the type of evidence needed to convince a group of individuals. This interactive scatterplot consists of markers along with the line of best fit to emphasize the relationship present. It has a tooltip to easily provide the user with further information and it is linked to the a “country of residence” filter. When a country is selected the marker changes color from blue to orange and converts to a square shape which gets enlarged. Size, color, location and shape are utilized to differentiate it from the rest.

Alt text
Alt text

After which, a heatmap is utilized to summarize and provide insights on the average monthly visits by different nationalities along with their seasonal behavior. The interactive heatmap is colour coded using a sequential colour scheme referred to as “Heat”. “Veridis” color palette was also considered due to its robustness even with those who are colorblind, but the “heat” palette was selected for two reasons. The requirement was to have a single colour palette which gradually darkens but does not portray multiple colours when doing so. The clear convergence from cream colour to dark brown highlights seasonality quite clearly.

Alt text
Alt text

Analyzing Inbound Tourist Composition by State

Deciding on a location can be one of the most important decisions one can make whether it’s for a personal tour or for a business investment. In the tourism industry this decision can be either what are the tourist compositions within an area of interest or, if a specific target market has already decided, which areas have the highest compositions of them in order to invest in. This thought process led to realizing the need for a user to drill down both ways, one being based on nationality what are their preferred locations or based on a location to identify which nationalities are most available to cater to. Therefore, a choropleth map was used to visualize the tourist arrival density across the states which highlights their preferred destinations. A sequential color pallete from RColourBrewer known as “YlOrBr” was utilized to highlight the density in the map. It was preferred due to its clear sequential shades and the sensitivity on the eyes. Moreover, this visualization is coupled with a bar graph that summarizes the total visits in 2019 by the country of residence. These interactive visualizations are linked to two filters, one being by “Country of Residence” and the other being “By State” to enable the user to drill down if needed.

A choropleth map was preferred due to its ability to summarize large amounts of information and in turn highlight patterns or areas of interest. It provides an effective and an efficient way of visually comparing values. The bar graph was coupled together due to its simplicity and its ability to summarize the leading countries, the ones at the bottom and the ones which stand out quickly and effectively. This is referred to as composition information. Its value addition is seen when it is utilized in unison with other filters and charts.

Alt text
Alt text

Identifying Tourism Hotspots

When investing in a location within this industry is of paramount importance to consider the tourist content availability within the area. Sometimes the most cost-effective place might not be the best decision due to the lack of tourist content. This will tremendously lower the interest of their target market. Tourists in general prefer areas with proper food and drink, accommodation, events, and attractions. Investing in an area where these lack might not be fruit full. This section of the insights portal is dedicated to making use of and communicating insights generated from the data maintained by the Australian Data Warehouse.

The visualizations selected to the portray this information was a proportional symbol map to high light opportunities using shape, size, location and colour to effectively differentiate between the tourist content while highlighting hotspots of opportunities. The choropleth map is linked with both a highlight table summarizing the quantity and type of tourist content available at the location and a column graph summarizing the suburbs with the most tourists. Further below, a highlight table with a google panel like view of the granular details of the tourist content listing such as the title , address, phone number etc. are displayed for end user convenience.

In order to add in user convenience three dashboard filters have been incorporated. A “Tourist Content Category” filter which can concentrate all insights within the dashboard tab to focus on the specific content type. This can be useful for both tourists and as well as for business users within the same industry. Secondly, a “State filter was incorporated to identify the tourist content listings within the state and within each suburb. This was followed by the inclusion of a “Tourist Content Quantity” filter which enables the user to filter out locations by the quantity of listings available in that area.

Alt text
Alt text
Alt text
Alt text

Step 1: Package Loading

#import required libraries
library(png)
library(ggplot2)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(shiny)
library(shinydashboard)
## 
## Attaching package: 'shinydashboard'
## The following object is masked from 'package:graphics':
## 
##     box
library(formattable)
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
library(readxl)
library(plotly)
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:formattable':
## 
##     style
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
library(data.table)
## 
## Attaching package: 'data.table'
## The following objects are masked from 'package:lubridate':
## 
##     hour, isoweek, mday, minute, month, quarter, second, wday, week,
##     yday, year
## The following objects are masked from 'package:dplyr':
## 
##     between, first, last
library(ozmaps)
library(sf)
## Linking to GEOS 3.12.1, GDAL 3.8.4, PROJ 9.3.1; sf_use_s2() is TRUE
library(leaflet)
library(RColorBrewer)
library(base)

Step 2: Data Import and Preprocessing

#### Global data preparation ############################################################################################################################
#import data sets
# For growth Analysis 
data <- read.csv("austrlia_visitor_time.csv")
# For Behavior analysis and composition Analysis 
data02 <- read_excel("Visitors_State.xlsx", sheet = "Visitors_by_state")
## New names:
## • `` -> `...3`
# For tourism hotspot identification
data03 <- read_excel("Australia_Tourist_Data_Warehouse.xlsx")

#data preprocessing
#seperating date by day,month and year
data$day <- format(as.Date(data$date, format="%m/%d/%Y"),"%d")
data$month <- format(as.Date(data$date, format="%m/%d/%Y"),"%m")
data$year <- format(as.Date(data$date, format = "%m/%d/%Y"), "%Y")
# excluding total records for world regions
data<-data%>% filter(data$variable_type != "Total")

Step 3: Prepare Geographic Data

#importing Australia states boundary lines (Excluding other territories & descending order)
sf_oz <- ozmap("states") 

sf_oz <- sf_oz %>% filter(sf_oz$NAME != "Other Territories") 
sf_oz <- sf_oz %>% arrange(desc(sf_oz$NAME))

# Join the boundary information to the data set using the state name
data02 <- data02 %>%
  left_join(sf_oz, by = c("State" = "NAME"))

# Define the user interface fo the Rshiny Dashboard (Yellow)
title <- tags$a(href='https://www.google.com',
                icon("plane"),
                'Insights Portal', target="_blank", style = "color: #8B4513;")

# change path to working directory
logo <- "C:/Users/Thinithi/Monash/Sem1_2023/FIT5147VIZUALIZATION/Assignments/Data visualization Project/Thinithi_27523306_Code/logo/Tourismlogo.png"

Step 3: User Interface Setup

# create dashboard page
ui <- dashboardPage(
  # add header
  dashboardHeader(title = title, titleWidth = 230),
  #dashboard skin colour yellow
  skin="yellow",
  #Add side bar
  dashboardSidebar(
    sidebarMenu(
      #Add tourism Australia logo
      imageOutput("logopic", height = 100),
      #Add tabs to structure the vizualiations
      menuItem("Inbound Tourism Road Map", tabName = "page", icon = icon("home")),
      menuItem("Tourism Growth", tabName = "panel1", icon = icon("th")),
      menuItem("Tourism Behavior", tabName = "panel2", icon = icon("th")),
      menuItem("Tourism Composition", tabName = "panel3", icon = icon("th")),
      menuItem("Tourism Hotspots", tabName = "subpanels", icon = icon("list"),
               menuSubItem("Tourism Hotspots", tabName = "panel4a")
      )
    )
  ),
  #Add dashboard body
  dashboardBody(
    #Edit Tabs
    tabItems(
      
      #home page road map view
      tabItem(tabName = "page",
              #center the title and make it bold
              tags$div(style = "margin-left: 90px;",h2("Australian Inbound Tourism")),
              tags$div(style = "margin-left: 90px;",p("Insights Portal Roadmap")),
              style = "text-align: center;",
              
              # infoBox for Growth
              fluidRow(
                infoBox(
                  HTML("<b>Growth</b>"), uiOutput("progress"), icon = icon("signal"), color = "maroon",
                  column(width = 4,align="center"),
                  subtitle = HTML("<li>Identify growth patterns</li>
                                   <li>Forecast future trends</li>"),
                ),
                
                # infoBox for behavior
                infoBox(
                  HTML("<b>Behavior</b>"), uiOutput("progress2"), icon = icon("code-compare"), color = "orange",
                  column(width = 4,align="center"),
                  subtitle = HTML("<li>Expenditure Habits</li>
                                   <li>Seasonal Behavior</li>"),
                ),
                
                # infoBox for composition
                infoBox(
                  HTML("<b>Composition</b>"), uiOutput("progress3"), icon = icon("earth-americas"), color = "aqua",
                  column(width = 4,align="center"),
                  subtitle = HTML("<li>By State</li>
                                   <li>By Nationality</li>"),
                ),
                
                # infoBox for hotspots
                infoBox(
                  HTML("<b>Hotspots</b>"), uiOutput("progress4"), icon = icon("camera-retro"), color = "light-blue",
                  column(width = 4,align="center"),
                  subtitle = HTML("<li>By tourist content type</li>
                                   <li>By state</li>"),
                )
              ),
              # Add paddings for space
              p(" "),
              #title for data sources
              tags$div(style = "margin-left: 90px;",p(tags$b("Data Sources"))),
              p(" "),
              fluidRow(
                # infoBoxes with links to click on to access data sources
                infoBox("Australian Bureau of Statistics",
                        tags$a(href = "https://www.abs.gov.au/statistics/industry/tourism-and-transport/overseas-arrivals-and-departures-australia/dec-2022/340105.xlsx ",
                               "Short-term visitors Arrivals by country of residence 1991-2022", style = "font-size: 10px;"),
                        tags$a(href = "https://www.abs.gov.au/statistics/industry/tourism-and-transport/overseas-arrivals-and-departures-australia/dec-2022/3401011.xlsx ",
                               "Short-term visitor arrivals by state 1991-2022", style = "font-size: 10px;"),
                        icon = icon("database"), fill=TRUE,color = "black",
                        width = 4
                        ),
                infoBox("Tourism Research Australia",
                        tags$a(href = "https://www.tra.gov.au/ArticleDocuments/185/InternationalVisitorSurvey(IVS)EarlyReleaseSummaryJune2020.xlsx.aspx ",
                               "International visitors across Australian States and Territories", style = "font-size: 10px;"),
                        tags$a(href = "https://www.tra.gov.au/ArticleDocuments/185/IVS_TOURISM_RESULTS_YE_MAR_2020.xlsx.aspx",
                               "International visitors average nights spent and expenditure", style = "font-size: 10px;"),
                        icon = icon("database"), fill=TRUE,color = "black",
                        width = 4
                ),
                infoBox("Web Scraped Data",
                        tags$a(href = "https://atdw.com.au/our-listings/?pge=1",
                               "Australian Tourist Data Warehouse", style = "font-size: 10px;"),
                        tags$a(href = "https://www.state.gov/countries-and-areas-list/",
                               "Countries and world regions", style = "font-size: 10px;"),
                        icon = icon("database"), fill=TRUE,color = "black",
                        width = 4
                )
              )
      ),
      #customise growth tab
      tabItem(tabName = "panel1",
              h2("Australian Inbound Tourism Growth"),
              p("Analyze changes in Tourist arrivals"),
              style = "text-align: center;",
              fluidRow(
                #Add TopN selector
                column(width = 3,
                       sliderInput("topselector", h3("Top Countries (By Avg Visits Per Year)", style = "font-size: 12px;"),
                                   min = 1, max = 100, value = c(1,100), width = "200px")
                ),
                #Add data selection
                column(width = 3,
                       dateRangeInput("dates", label = h3("Base Date | Reference Date", style = "font-size: 12px;"),
                                      format = "yyyy",
                                      startview = "year",
                                      start = "1994-01-01",
                                      end = "2022-01-01")
                ),
                #Add country of residence selection
                column(width = 2,
                       tags$style(".selectize-dropdown-content .choices { font-size: 12px; }"),
                       selectInput("residence", label = h3("Country Of Residence", style = "font-size: 12px;"),
                                   choices =  c("Select All", unique(data$countries)), selected = "Select All")
                ),
                #Add chart type selection
                column(width = 2,
                       tags$style(".selectize-dropdown-content .choices { font-size: 12px; }"),
                       selectInput("charttype", label = h3("Graph Type", style = "font-size: 12px;"),
                                   choices = c("By Country", "By World Region","Overall"), selected = "By Country")
                ),
                #Add trend colour selection
                column(width = 2,
                       tags$style(".selectize-dropdown-content .choices { font-size: 12px; }"),
                       selectInput("trendcolour", label = h3("Trend Colour", style = "font-size: 12px;"),
                                   choices = c("Increasing", "Decreasing","All"), selected = "All")
                ),
                # Add narrative box
                infoBox(
                        HTML(" "),
                        icon = icon("circle-info"), color = "yellow",fill=FALSE,
                        width = 12,
                        subtitle = HTML("Prior Covid impact, nearly 3Mn of the yearly visitors were from New Zealand,UK, Japan, United states, China and Singapore (Refer the highlight table). The Chinese tourists, on the other hand, seem<br>
                                        to portray the highest growth across the years.When looking at the trend of tourist arrivals prior to the lock down, all nationalities seem to have experienced growth from 1994 to 2018 except<br>
                                        for Japan which had experienced a drop of 42%. When looking at the past 10 years, inflow of tourists from all countries have increased except for Japan, Ireland, South Africa, Israel and Netherlands.<br>
                                        When considering world regions,Asian tourist visits seemed to have increased drastically from 2011 onwards. In terms of covid recovery, China, India, Vietnam, Philippines and Sri Lanka are few of the
                                        countries which had recovered to 2008 rates."),
                ),
                #include the line graph and highlight table output
                column(width = 12,
                       splitLayout(cellWidths = c("40%", "60%"),
                                   formattableOutput("highlight_table"),
                                   style = "overflow-y: scroll ; max-height: 380px",
                                   plotlyOutput("trendPlot", height = "380px"))
                
              )
              )
              #
      ),
      #customise Behavior tab
      tabItem(tabName = "panel2",
              h2("Australian Inbound Tourist Behavior"),
              p("Analyze Tourist behavior by nationality"),
              style = "text-align: center;",
              fluidRow(
                #Add country of residence selection
                column(width = 2,
                       tags$style(".selectize-dropdown-content .choices { font-size: 12px; }"),
                       selectInput("residence2", label = h3("Country Of Residence", style = "font-size: 12px;"),
                                   choices =  c("Select All", unique(data02$residence)), selected = "Select All")
                )
              ),
              fluidRow(
              #Add narrative
              infoBox(
                HTML(" "),
                icon = icon("circle-info"), color = "yellow",fill=FALSE,
                width = 12,
                subtitle = HTML("The behavior of tourists from different nationalities are highlighlted below. Some tend to stay for a shorter period and may prefer to spend a lot more during their stay while others may prefer<br>
                                 to stay a longer period and spend much less per night. The scatterplot shows the strong correlation between the two variables, since the p-value is significantly less than 0.05 it can be concluded<br>
                                 that the correlation is statistically significant and that the average nights stayed is inversely proportional to the average night expenditure"),
              )),
              fluidRow(
              #Add scatter plot output
              plotlyOutput("scatter_Plot",height = "400px")),
              p(" "),
              p(" "),
              fluidRow(
                #Add Narrative
                infoBox(
                  HTML(" "),
                  icon = icon("circle-info"), color = "yellow",fill=FALSE,
                  width = 12,
                  subtitle = HTML("At A glance we can see that the average number of tourists visits from all nationalities peak in the month of December. In addition, January and February visits seems to be higher in comparison<br>
                                  to the other months. Most importantly, the heatmap below highlights the peak months of visitors by their country of residence along with an average estimate of the number of visitors."),
                )),
              tags$div(style = "margin-left: 90px; font-size: 16px;",p(" ")),
              fluidRow(
              #Add heatmap output
              plotlyOutput("heatmap_Plot",height = "700px"))
      ),
      #customize composition tab
      tabItem(tabName = "panel3",
              h2("Australian Inbound Tourist Composition"),
              p("Analyze Tourist composition by State"),
              style = "text-align: center;",
              fluidRow(
                #Add country of residence selection
                column(width = 2,
                       tags$style(".selectize-dropdown-content .choices { font-size: 12px; }"),
                       selectInput("residence3", label = h3("Country Of Residence", style = "font-size: 12px;"),
                               choices =  c("Select All", unique(data02$residence)), selected = "Select All")
               ),
               #Add state selection
               column(width = 2,
                      tags$style(".selectize-dropdown-content .choices { font-size: 12px; }"),
                      selectInput("state", label = h3("State", style = "font-size: 12px;"),
                      choices =  c("Select All", unique(data02$State)), selected = "Select All")
              ),
              #Add narrative
                infoBox(
                  HTML(" "),
                  icon = icon("circle-info"), color = "yellow",fill=FALSE,
                  width = 12,
                  subtitle = HTML("Few observations were made when analyzing the tourist visits to each state during the year 2019. New south Wales had significant tourist visits with the main contribution is from tourists<br>
                                  from China, US, New Zealand and UK. Victoria seems to have a significantly high Chinese tourist visits while the second highest is from New Zealand tourists. In addition, Victoria seems to<br>
                                  be having the highest Asian tourists (178,000). Northern Australia, on the other hand, has mostly tourists from Japan (40,000 visits) followed by US tourists (39,000 visits). Western Australia<br>
                                  have more Singaporeans (104,000 visits) and Malaysians (99,000 visits)."
                  )
              )
              ),
              #Add two outputs horizontally
              column(width = 12,
                     p(tags$b("Tourist visits 2019")),
                     tags$div(style = "text-align: left;color: brown",p(tags$b("Colour Scale:Higher Number of visits ~ Darker the colour"))),
                     splitLayout(cellWidths = c("70%", "30%"),
                                 leafletOutput("map1",height = "400px"),
                                 plotlyOutput("bar_Plot",height = "400px"))
                     
              )
      ),
      #Customize Hotspots tab
      tabItem(tabName = "panel4a",
              h2("Australian Tourist Content Hotspots"),
              p("Identify Opportunity Areas"),
              style = "text-align: center;",
              fluidRow(
                #Add tourism content type selector
                column(width = 2,
                       tags$style(".selectize-dropdown-content .choices { font-size: 12px; }"),
                       selectInput("tourismcontent", label = h3("Tourism Content Category", style = "font-size: 12px;"),
                                   choices =  c("Select All","Accommodation","Food and Drink"
                                                ,"Attraction","Event"), selected = "Select All")
                ),
                #Add suburb selector
                column(width = 2,
                       tags$style(".selectize-dropdown-content .choices { font-size: 12px; }"),
                       selectInput("tourismcontent2", label = h3("Select Suburb", style = "font-size: 12px;"),
                                   choices =  c("Select All",data03$Suburb), selected = "Select All")
                ),
                
                #Add state selector
                column(width = 2,
                       tags$style(".selectize-dropdown-content .choices { font-size: 12px; }"),
                       selectInput("state2", label = h3("Select State", style = "font-size: 12px;"),
                                   choices =  c("Select All",data03$State), selected = "Select All")
                ),
                #Add quantity filter
                column(width = 3,
                       sliderInput("topselector2", h3("Tourist Content Quantity)", style = "font-size: 12px;"),
                                   min = 1, max = 230, value = c(1,230), width = "200px")
                ),
                #Add a narrative
                infoBox(
                  HTML(" "),
                  icon = icon("circle-info"), color = "yellow",fill=FALSE,
                  width = 12,
                  subtitle = HTML("Australian data warehouse is a digital content data base thats objective is to create a platform for businesses in the tourism industries to raise awareness. It has over 11 categories of<br>
                                  listings but initially we took listings from 4 main categories which are food & drink, accommodation, attractions, and events. Over 21,000 tourism content listings have been obtained and<br>
                                  visualized to identify hotspots which can be useful for both tourists and investors in the tourism industry. "
                  )
                )
              ),
              #Add a split screen layout
              fluidRow(
              p(tags$b("Tourism Content Lisitngs Australia")),
              column(width = 12,
                     splitLayout(cellWidths = c("80%", "20%"),
                                 #print tourism content map
                                 leafletOutput("map2",height = "400px"),
                                 #print listing summary
                                 formattableOutput("highlight_table2"),height = "400px")
                     
              )
              ),
              p(" "),
              #display bar plot
              fluidRow(
              plotlyOutput("bar_Plot2",height = "250px")
              ),
              p(" "),
              p(tags$b("Listing Details")),
              #display listing detail table
              fluidRow(
                formattableOutput("highlight_table3",height = "500px")
              )
              
      )
    )
  
  )
)
## Warning: The select input "tourismcontent2" contains a large number of options;
## consider using server-side selectize for massively improved performance. See
## the Details section of the ?selectizeInput help topic.
## Warning: The select input "state2" contains a large number of options; consider
## using server-side selectize for massively improved performance. See the Details
## section of the ?selectizeInput help topic.

Step 3: Server Setup

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

  
  # Render the image ###############################################################################################################
  output$logopic <- renderImage({
    
    list(src = logo,
         contentType = "image/png",
         width = "100%",
         height = 100)
  }, deleteFile = FALSE)
  
  #add line graph #################################################################################################################
  output$trendPlot <- renderPlotly({
    
    #seperating date day,month and year
data$day <- format(as.Date(data$date, format="%m/%d/%Y"),"%d")
data$month <- format(as.Date(data$date, format="%m/%d/%Y"),"%m")
data$year <- format(as.Date(data$date, format = "%m/%d/%Y"), "%Y")

#filteration
data<-data%>% filter(data$variable_type != "Total")

    # filter countries 
    filtered_countries <- if (input$residence == "Select All") {
      data$countries
    } else {
      input$residence
    }
    
    #filter graph type
    filtered_chartype <- if (input$charttype == "By Country") {
      'countries'
    } else if (input$charttype == "By World Region") {
      'Region'
    } else { 
      'variable_type'
    }
    
    #Filter data set based on date range 
    plot1 <- data %>%
      filter(countries %in% filtered_countries & year >= format(as.Date(input$dates[1], format = "%Y-%m-%d"), "%Y") &
               year <= format(as.Date(input$dates[2], format = "%Y-%m-%d"), "%Y"))
    
    #summarize data
    summary_data0 <- plot1 %>%
      group_by(countries, year) %>%
      summarise(total_records = sum(records), n = n()) %>%
      group_by(countries) %>%
      summarise(average_records = round(mean(total_records)))
    
    #rank the trend
    filtered_trend0 <- summary_data0 %>%
      mutate(rank_trend = rank(desc(average_records), na.last = "keep"))
    
    #filter rank based on selector
    filtered_summary0 <- filtered_trend0 %>% filter(rank_trend >= input$topselector[1] & rank_trend <= input$topselector[2])
    
    #filter relevant countries
    plot2 <- plot1 %>% filter( countries %in% filtered_summary0$countries)
  
    #plot with ggplot and save
    p <- ggplot(plot2) +
      stat_summary(aes(x = year, y = records, group = .data[[filtered_chartype]], color = .data[[filtered_chartype]]),
                   fun = sum, geom = "line", linewidth = 0.9) +
      labs(title = "Short-Term Visitor Arrival Across Time 1992-2022",
           x = "Year of Arrival",
           y = "Number of Visitors Arrived (Thousands)") +
      theme(legend.position = "bottom", axis.text.x = element_text(angle = 45, hjust = 1))+
      scale_y_continuous(labels = function(x) format(x / 1000, scientific = FALSE))
    
    #convert ggplot to plotly
    ggplotly(p) %>% layout(showlegend = FALSE)
     
  })
  
  #add highlight table ############################################################################################################
  output$highlight_table <- renderFormattable({
    
    # filter countries
    filtered_countries <- if (input$residence == "Select All") {
      data$countries
    } else {
      input$residence
    }
    
    #date filteration
    #set start date
    start_date = as.Date(input$dates[1])
    #set end date
    end_date = as.Date(input$dates[2])
    #include 3 year prior start date
    start_date0 = start_date %m-% years(3)  
    #include 3 year prior end date
    end_date0 = end_date %m-% years(3)
    
    # Filter data based on selections
    plot1 <- data %>%
      filter(countries %in% filtered_countries & year >= format(as.Date(input$dates[1], format = "%Y-%m-%d"), "%Y") &
               year <= format(as.Date(input$dates[2], format = "%Y-%m-%d"), "%Y"))
    
    #filter data for selected start period
    filtered_data <- plot1 %>%
      filter(year >= format(as.Date(start_date0, format = "%Y-%m-%d"), "%Y") &
               year <= format(as.Date(start_date, format = "%Y-%m-%d"), "%Y")) 
    #filter data for selected end period
    filtered_data0 <- plot1 %>%
      filter(year >= format(as.Date(end_date0, format = "%Y-%m-%d"), "%Y") &
               year <= format(as.Date(end_date, format = "%Y-%m-%d"), "%Y")) 
    
    #Data pre-processing
    summary_data <- plot1 %>%
      group_by(countries, year) %>%
      summarise(total_records = sum(records), n = n()) %>%
      group_by(countries) %>%
      summarise(average_records = round(mean(total_records)))
    
    summary_data0 <- filtered_data %>%
      group_by(countries, year) %>%
      summarise(total_records = sum(records), n = n()) %>%
      group_by(countries) %>%
      summarise(average_records_start = round(mean(total_records)), n = n())
    
    summary_data1 <- filtered_data0 %>%
      group_by(countries, year) %>%
      summarise(total_records = sum(records), n = n()) %>%
      group_by(countries) %>%
      summarise(average_records_end = round(mean(total_records)), n = n())
    
    #combine the processed data
    summary_df <- cbind(summary_data,summary_data0$average_records_start,summary_data1$average_records_end,
                        percent(((summary_data1$average_records_end-summary_data0$average_records_start)/summary_data0$average_records_start)),
                        round(percent(((summary_data1$average_records_end-summary_data0$average_records_start)/summary_data0$average_records_start)),3))
    #order in descending order
    summary_df <- summary_df %>% arrange(desc(average_records))
    colnames(summary_df)<-c("countries","average_records","avg_start","avg_end","Trend","Trend_num")
    
    # Format all numeric columns as integers with commas
    summary_df <- summary_df %>%
      mutate_all(~ format(.x, big.mark = ",", scientific = FALSE))
    
    # filter by trend colour selection
    filtered_trend <- if (input$trendcolour == "Increasing") {
      summary_df_final <- summary_df %>% filter(summary_df$Trend > 0)
    } else if (input$trendcolour == "Decreasing") {
      summary_df_final <- summary_df %>% filter(summary_df$Trend < 0)
    } else {
      summary_df_final <- summary_df
    }
    
    #ranking the trend
    filtered_trend <- filtered_trend %>%
      mutate(rank_trend = rank(desc(Trend_num), na.last = "keep"))

    #filter the data base topn selection and rank
    filtered_summary <- filtered_trend %>% filter(rank_trend >= input$topselector[1] & rank_trend <= input$topselector[2])
    colnames(filtered_summary)<-c("countries","average_visits_per_year","avg_start","avg_end","Trend","Trend_num","rank_trend")
    
    #Set colours for KPIs
    customGreen0 = "#DeF7E9"
    customGreen = "#71CA97"
    customRed = "#ff7f7f"
    
    #format colours
    improvement_formatter <- formatter("span", 
                                       style = x ~ formattable::style(font.weight = "bold", 
                                                                      color = ifelse(x > 0, customGreen, ifelse(x < 0, customRed, "black"))), 
                                       x ~ icontext(ifelse(x>0, "arrow-up", "arrow-down"), x)
    )
    
    #Create highlight table
    formattable(filtered_summary[, c(1, 2, 5)],
                align =c("l","c","c","c","c", "r"), 
                list(
                  `countries` = formatter("span", style = ~ formattable::style(color = "grey",font.weight = "bold")),
                  `Trend` = improvement_formatter ))
  })
  
  #add scatterplot ##################################################################################################################
  output$scatter_Plot <- renderPlotly({
    
    # filteration
    higlight_country <- if (input$residence2 != 'Select All') {
      input$residence2
    } else {
      'none'
    }
    
    #summarize expenditure
    summary_exp <- data02 %>%
      group_by(residence) %>%
      summarise(average_nights_stayed = max(Est_Avg_Nights),
                average_expense_per_night = max(Exp_Avg_Night_Exp))
    
    #Create a scatter plot using plotly
    scatter_plot <- plot_ly(data = summary_exp, x = summary_exp$average_expense_per_night ,
                            y = summary_exp$average_nights_stayed, type = "scatter",mode = "markers",name="Nationalities",
                            marker = list(symbol = ~ifelse(residence == higlight_country ,"square" , "cross"), size = ~ifelse(residence == higlight_country , 16, 10),
                                          color = ~ifelse(residence == higlight_country , "orange", "blue")),
                            text = ~paste("Country:", residence,"<br>",
                                          "Avg Night Exp:", average_expense_per_night, "<br>",
                                          "Avg Nights Stayed:", average_nights_stayed, "<br>")
    ) %>%
      layout(title = "Average Expense per Night vs. Average Nights Stayed",
             xaxis = list(title = "Average Expense per Night"),
             yaxis = list(title = "Average Nights Stayed") ) 
    
    
    #Line of Best fit
    fit <- lm(average_nights_stayed ~ average_expense_per_night, data = summary_exp)
    
    # Pvalue function obtained from a reference
    p_value_function <- function (modelobject) {
      if (class(modelobject) != "lm") stop("Not an object of class 'lm' ")
      f <- summary(modelobject)$fstatistic
      p <- pf(f[1],f[2],f[3],lower.tail=F)
      attributes(p) <- NULL
      return(p)
    }
    
    #derive pvalue
    pvalue<- p_value_function(fit)
    
    #add scatter plot and best fit line 
    scatter_plot %>% add_lines(x = ~average_expense_per_night, y = fitted(fit),mode = 'lines', name = 'Line of Best Fit', line = list(color = 'grey'), 
                               marker = list(color = 'transparent', size = 0),line = list(color = 'transparent')) %>% 
      add_annotations(x = max(summary_exp$average_expense_per_night), y = max(fitted(fit)),
                      text = paste("p-value:", format(pvalue, digits = 4)),
                      showarrow = FALSE, font = list(size = 15))
    
  })
  
  
  #add heatmap #######################################################################################################################
  output$heatmap_Plot <- renderPlotly({
    
    #summarize data
    summary_hm <- data %>%
      group_by(countries, month) %>%
      summarise(average_records = round(mean(records)))
    
    # Normalize records within each country
    summary_hm$normalized_records <- ave(summary_hm$average_records, summary_hm$countries, FUN = function(x) (x - min(x)) / (max(x) - min(x)))
    
    #create a list of month names
    month_names <- c("January", "February", "March", "April", "May", "June",
                     "July", "August", "September", "October", "November", "December")
    
    #plot a heatmap using month names and visit normalized data
    plot_ly(data = summary_hm,
            x = ~month_names[as.integer(summary_hm$month)], y = ~summary_hm$countries,
            z = ~normalized_records, 
            type = "heatmap", 
            colorscale = "Heat",
            text = ~paste("Month: ", month_names[as.integer(summary_hm$month)], "<br>",
                          "Country: ", summary_hm$countries, "<br>",
                          "Normalized visit count: ", round(summary_hm$normalized_records,2), "<br>",
                          "Avg Visits: ", format(summary_hm$average_records, big.mark = ",", scientific = FALSE)),
            hoverinfo = "text",
            showscale = TRUE) %>% 
      layout(xaxis = list(categoryorder = "array", categoryarray = month_names[as.integer(summary_hm$month)]))%>%
      layout(xaxis = list(title = "Month of visit"),
             yaxis = list(title = "Country of Residence"),
             title = "Average Monthly Visits By Country Of Residence")
  })
  
  
  
  #add barplot ######################################################################################################################
  output$bar_Plot <- renderPlotly({
    
    #filter country
    higlight_country_bar <- if (input$residence3 != 'Select All') {
      input$residence3
    } else {
      data02$residence
    }
    
    #filter state 
    higlight_state_bar <- if (input$state != 'Select All') {
      input$state
    } else {
      data02$State
    }
    
    #data preprocessing
    summary_visitors0 <- data02 %>%
      group_by(State,residence) %>%
      summarise(sum_visitors_2019 = sum(Visitors_2019),
                average_nights_stayed = max(Est_Avg_Nights),
                average_expense_per_night = max(Exp_Avg_Night_Exp))%>% 
    filter( residence %in% higlight_country_bar & State %in% higlight_state_bar)
    
    summary_visitors1 <- summary_visitors0  %>%
      group_by(residence) %>%
      summarise(visitors_country_2019 = sum(sum_visitors_2019))
    
    summary_visitors1 <- summary_visitors1 %>% 
      arrange(desc(visitors_country_2019))
    
    #filter data based on selections
    summary_visitors1$residence_factor <- factor(summary_visitors1$residence, levels = unique(summary_visitors1$residence))
    
    #create a country of residence column and convert into a factor to order the graph
    summary_visitors1$residence_factor <- factor(summary_visitors1$residence_factor, levels = rev(levels(summary_visitors1$residence_factor)))
    
    #plot bar graph of 2019 visits
    plot_ly(x = summary_visitors1$visitors_country_2019, y = summary_visitors1$residence_factor, marker = list(pattern = list(shape = "x", color = "darkblue", size=3),text = summary_visitors1$visitors_country_2019),
            type = "bar", orientation = "h" )  %>%
      layout(xaxis = list(title = "Visitors 2019"),
             yaxis = list(title = "Country of Residence"),
             title = "Visitor Statistics",
             showlegend = FALSE) %>% 
      add_annotations(x = summary_visitors1$visitors_country_2019, y = summary_visitors1$residence_factor,
                      text = format(summary_visitors1$visitors_country_2019, big.mark = ",", scientific = FALSE),
                      showarrow = FALSE, font = list(size = 8), xshift = 20) 
    })
  
  #composition map ##############################################################################################################
  output$map1<-renderLeaflet({
    
    #filter based on country
    higlight_country3 <- if (input$residence3 != 'Select All') {
      input$residence3
    } else {
      data02$residence
    }
    
    #filter state 
    higlight_state1 <- if (input$state != 'Select All') {
      input$state
    } else {
      data02$State
    }
    
    ##data preprocessing
    summary_map <- data02 %>%
      filter(data02$residence %in% higlight_country3)%>%
      group_by(State,Longitude,Latitude,geometry) %>%
      summarise(sum_visitors_2019 = sum(Visitors_2019)) 
    summary_map <- summary_map %>% arrange(desc(summary_map$State))
    
    # Create a color palette for the map
    mypalette <- colorQuantile(palette = "YlOrBr", domain = summary_map$sum_visitors_2019, n = 4)
    
    # Tooltip text and include commas for large numbers
    mytext <- paste(
      "<strong>State:</strong> ", summary_map$State, "<br/>",
      "<strong>Visitors 2019:</strong> ", format(summary_map$sum_visitors_2019, big.mark = ",", scientific = FALSE), sep="") %>%
      lapply(htmltools::HTML)
    
    #create a chloropleth map
    leaflet(summary_map) %>%
      addTiles() %>%
      setView(lng = 133, lat = -25, zoom = 4) %>%
      addPolygons(
        data = sf_oz, fillColor = ~mypalette(summary_map$sum_visitors_2019), color = "black",weight = 1,opacity = 1,
        fillOpacity = 0.4,smoothFactor = 0.5,label = mytext,labelOptions = labelOptions( 
          style = list("font-weight" = "normal", padding = "3px 8px"), textsize = "13px", direction = "auto"))
    })
  
  
  #proportional symbol map ###########################################################################################################
  output$map2<-renderLeaflet({
    
    # Calculate the count of categories at each location
    count_data0 <- data03 %>%
      filter(!is.na(category)) %>%
      group_by(State,Suburb,category,Lon, Lat) %>%
      summarize(count_id = n())
    
    #highlight_content
    higlight_tourismcontent <- if (input$tourismcontent != 'Select All') {
      input$tourismcontent
    } else {
      count_data0$category
    }
    
    higlight_tourismcontent2 <- if (input$tourismcontent2 != 'Select All') {
      input$tourismcontent2
    } else {
      count_data0$Suburb
    }
    
    
    #filter data
    count_data <- count_data0 %>% filter(category %in% higlight_tourismcontent & count_id >= input$topselector2[1] & count_id <= input$topselector2[2]
                                         & Suburb %in% higlight_tourismcontent2 )
    
    #sort dataset
    count_data <- count_data %>% arrange(desc(count_id))
    
    #feed category the colour palatte
    palt<-colorFactor(palette ="Dark2",
                      levels = unique(count_data$category))
    
    #scales the size of markers based on the largest mark
    scaled<- count_data$count_id / max(count_data$count_id) * 10
    
    #create a map with content listings
    leaflet(count_data) %>% 
      addProviderTiles("CartoDB.Positron") %>%
      setView(lng = 133, lat = -25, zoom = 4) %>%
      addCircleMarkers(~ count_data$Lon, ~count_data$Lat, popup = ~as.character(paste(count_data$category, ": ", count_data$count_id, "<br>","Suburb: ", count_data$Suburb, "<br>",
                                "State: ", count_data$State)),radius=scaled,color=~palt(count_data$category),
                                  fillColor= ~palt(count_data$category),fillOpacity =1)%>% addLegend(pal = palt,values=count_data$category,title="Tourist Content",position="topright")
    
  })
    
  
  #tourist content by suburb ########################################################################################################
  output$bar_Plot2 <- renderPlotly({
    
    #filter category
    higlight_tourismcontent3 <- if (input$tourismcontent != 'Select All') {
      input$tourismcontent
    } else {
      data03$category
    }
    
    #filter suburb
    higlight_tourismcontent4 <- if (input$tourismcontent2 != 'Select All') {
      input$tourismcontent2
    } else {
      data03$Suburb
    }
    
    #filter state
    higlight_tourismcontent10 <- if (input$state2 != 'Select All') {
      input$state2
    } else {
      data03$State
    }
  
  #data summarizing
  count_data01_raw <- data03 %>% filter( category %in% higlight_tourismcontent3 & Suburb %in% higlight_tourismcontent4
                                         & State %in% higlight_tourismcontent10)%>%
    group_by(Suburb) %>%
    summarize(count_id = n())
  
  #ranking the trend
  count_data01_raw  <- count_data01_raw %>%
    mutate(rank_trend = rank(desc(count_id), na.last = "keep"))
  
  #filter by rank
  count_data01 <- count_data01_raw %>% arrange(desc(count_id)) %>% filter(rank_trend <= 15 )
  
  #convert suburb to a factor to order the output
  count_data01$suburb_factor <- factor(count_data01$Suburb, levels = unique(count_data01$Suburb))
  
  #create column chart
  plot_ly(data = count_data01,x = count_data01$suburb_factor, y = count_data01$count_id, marker = list(pattern = list(shape = "x", color = "darkblue", size=3),text = count_data01$count_id),
          type = "bar" )  %>%
    layout(xaxis = list(title = "Suburb"),
           yaxis = list(title = "Number of Tourist Content"),
           title = "Visitor Statistics",
           showlegend = FALSE) %>% 
    add_annotations(x = count_data01$suburb_factor, y = count_data01$count_id,
                    text = count_data01$count_id,
                    showarrow = FALSE, font = list(size = 12), xshift = 0, yshift=10)

  })
  
  #add highlight table ###############################################################################################################
  output$highlight_table2 <- renderFormattable({
    
    #category
    higlight_tourismcontent5 <- if (input$tourismcontent != 'Select All') {
      input$tourismcontent
    } else {
      data03$category
    }
    
    #filter suburb
    higlight_tourismcontent6 <- if (input$tourismcontent2 != 'Select All') {
      input$tourismcontent2
    } else {
      data03$Suburb
    }
    
    #filter state
    higlight_tourismcontent11 <- if (input$state2 != 'Select All') {
      input$state2
    } else {
      data03$State
    }
    
    #data preprocessing
    information <- data03 %>%
      filter( category %in% higlight_tourismcontent5 & Suburb %in% higlight_tourismcontent6 & State %in% higlight_tourismcontent11)%>%
      group_by(category) %>%
      summarize(count = format(n(), big.mark = ",", scientific = FALSE)) %>%
      filter(!is.na(category)) %>%
      mutate(records = category)
    information <- information %>% arrange(desc(count))
    
    # Set colours
    color0 <- "purple"
    color1 <- "#E7298A"
    color2 <- "#1B9E77"
    color3 <- "#D95F02"
    
    # Format colors and icons
    improvement_formatter1 <- formatter("span", 
                                       style = x ~ formattable::style(font.weight = "bold", 
                                                                      color = ifelse(x == 'Accommodation', color0,
                                                                                     ifelse(x == 'Food and Drink', color3,
                                                                                            ifelse(x == 'Attraction', color1, color2)))),
                                       x ~ icontext(ifelse(x == 'Accommodation', "bed",
                                                           ifelse(x == 'Food and Drink', "glass",
                                                                  ifelse(x == 'Attraction', "camera", "calendar"))), x)
    )
    
    # Apply formatting to the table
    formattable(information[,1:2],
                align = c("l", "c", "c", "c", "c", "c", "r"),
                list(
                  `countries` = formatter("span", style = ~ formattable::style(color = "grey", font.weight = "bold")),
                  `category` = improvement_formatter1
                )
    )
    
  })
  
  #highlight table 3
  output$highlight_table3 <- renderFormattable({
    
    #filter category
    higlight_tourismcontent7 <- if (input$tourismcontent != 'Select All') {
      input$tourismcontent
    } else {
      data03$category
    }
    
    #filter suburb
    higlight_tourismcontent8 <- if (input$tourismcontent2 != 'Select All') {
      input$tourismcontent2
    } else {
      data03$Suburb
    }
    
    #filter state
    higlight_tourismcontent12 <- if (input$state2 != 'Select All') {
      input$state2
    } else {
      data03$State
    }
    
    #data preprocessing
    information <- data03 %>%
      filter( category %in% higlight_tourismcontent7 & Suburb %in% higlight_tourismcontent8
              & State %in% higlight_tourismcontent12)%>%
      select(title, category, Suburb, Email_text, address, contact_no) %>%
      mutate(records = '.',
             row_number = row_number()) %>%
      filter(row_number <= 20)
    
    # Set colours
    color0 <- "purple"
    color1 <- "#E7298A"
    color2 <- "#1B9E77"
    color3 <- "#D95F02"
    
    # Format colors and icons
    improvement_formatter1 <- formatter("span", 
                                       style = x ~ formattable::style(font.weight = "bold", 
                                                                      color = ifelse(x == 'Accommodation', color0,
                                                                                     ifelse(x == 'Food and Drink', color3,
                                                                                            ifelse(x == 'Attraction', color1, color2)))),
                                       x ~ icontext(ifelse(x == 'Accommodation', "bed",
                                                           ifelse(x == 'Food and Drink', "glass",
                                                                  ifelse(x == 'Attraction', "camera", "calendar"))), x)
    )
    
    # Apply formatting to the table
    formattable(information[,1:6],
                align = c("l", "c", "c", "c", "c", "c", "r"),
                list(
                  `countries` = formatter("span", style = ~ formattable::style(color = "grey", font.weight = "bold")),
                  `category` = improvement_formatter1
                )
    )
    
  })
    
    
}
Shiny applications not supported in static R Markdown documents