R Shiny Gantt Chart: How to Modernize Planning Management in Pharma

By:
Dario Radečić
July 4, 2023

We live in a constantly and rapidly evolving environment, which means that <strong>effective planning management</strong> is crucial for companies. This is particularly true in the <strong>pharmaceutical sector</strong>, which involves stringent regulations, research and development timelines, and intricate <strong>supply chains</strong>. Traditional planning methods often fall short in providing a <strong>comprehensive overview</strong> and <strong>real-time insights</strong> into complex projects. This is where <strong>Gantt charts, combined with the power of R Shiny</strong>, come into play. They offer a way to modernize and optimize planning management, and in this article, we will demonstrate precisely how. By the end of the article, you will have a complete R Shiny application with options to add or remove tasks from a Gantt chart. But first, <b>what is a Gantt chart?</b> That's what we'll answer in the following section. <blockquote>Want to create automated data quality reports in R and R Shiny? <a href="https://appsilon.com/automated-r-data-quality-reporting/" target="_blank" rel="noopener">Try data.validator by Appsilon - you'll never look back</a>.</blockquote> Table of contents: <ul><li><a href="#what-is-gantt-chart">What is a Gantt Chart and How it Affects Planning Management?</a></li><li><a href="#gantt-chart-in-r">Gantt Chart in R - How to Create a Gantt Chart with ggplot2</a></li><li><a href="#r-shiny-gantt">R Shiny Gantt Chart - How to Build a Planning Management App</a></li><li><a href="#summary">Summing up R Shiny Gantt Chart</a></li></ul> <hr /> <h2 id="what-is-gantt-chart">What Is a Gantt Chart and How Is It Used in Planning Management?</h2> A Gantt chart is an excellent tool in planning management as it visually represents project schedules, tasks, and timelines. It provides a comprehensive overview of a project's progress and helps project managers and stakeholders effectively allocate resources, track milestones, and manage dependencies. By displaying tasks and their interrelationships in a timeline format, Gantt charts enable teams with a quick overview to plan, monitor, and control projects more efficiently. Here's one example of a Gantt chart, specifically tied to the film production industry: <img class="size-full wp-image-19062" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7aef081d951505be79036_b2fc58be_1-3.webp" alt="Image 1 - Gantt chart example (source: wikimedia.org)" width="1920" height="1080" /> Image 1 - Gantt chart example (source: <a href="https://upload.wikimedia.org/wikipedia/commons/8/89/Gantt_Chart_Template_for_Film_Production.png" target="_blank" rel="noopener">wikimedia.org</a>) As you can see, a Gantt chart consists of horizontal bars that represent individual tasks or activities within a project. These bars are plotted along a horizontal axis, which allows stakeholders to understand the sequential order and duration of tasks. The length of each bar corresponds to the duration of the task, while the position along the timeline indicates the start and end dates Each bar represents a single task, and multiple tasks can be happening at the same time. In the above example, you can see how the Pre-Production task consists of 5 different tasks and some of them have an overlap in the time frame. To be more precise, the "Researching interview partners" task begins at the end of the "Write shooting script" task. <h3>Gantt Charts for Project Management Use</h3> This article will focus on a <b>Gantt chart application in the pharmaceutical industry</b>. It's a good example, but it's not limited to any specific industry. The tutorial below is a good introduction to Gantt charts for project managers and stakeholders to visualize the various stages of drug development, identify dependencies between tasks, and ensure that all activities are executed in a timely manner. For instance, in the pharmaceutical sector, Gantt charts can be beneficial for managing clinical trials. These trials involve multiple stages, such as patient recruitment, protocol development, data collection, analysis, and reporting. By utilizing a Gantt chart, project managers can identify potential bottlenecks, allocate resources effectively, and track the progress of each stage. This ensures that trials are conducted efficiently, adhering to strict timelines and regulatory requirements. That's about enough for the introduction to Gantt charts and the theory, so next we'll dive deep into practical use cases. First, you'll learn how to visualize Gantt charts with R's <code>ggplot2</code> package. <h2 id="gantt-chart-in-r">Gantt Charts in R - How to Create a Gantt Chart with ggplot2</h2> Now that you understand the importance of Gantt charts in planning management, let's explore how to create a Gantt chart using the popular R package - <code>ggplot2</code>. For starters, we'll import the R packages and create some dummy data. Each task for the Gantt chart will have a name, start date, and end date. For example, we'll make a dummy project in the pharmaceutical industry with 5 tasks: Research, Clinical Trials, Regulatory Approval, Manufacturing, and Marketing: <pre><code class="language-r">library(tidyverse) library(ggplot2) <br> # Individual tasks formatted as a data.frame tasks &lt;- data.frame(  Task = c("Research", "Clinical Trials", "Regulatory Approval", "Manufacturing", "Marketing"),  StartDate = as.Date(c("2023-05-01", "2023-07-01", "2024-01-01", "2024-03-01", "2024-06-01")),  EndDate = as.Date(c("2023-06-30", "2023-12-31", "2024-06-30", "2024-12-31", "2025-06-30")) ) <br>tasks</code></pre> Here's what the resulting <code>data.frame</code> looks like: <img class="size-full wp-image-19064" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7aef17b9576a4ae8c1a6a_f0878509_2-3.webp" alt="Image 2 - Dummy tasks for a pharmaceutical industry project" width="479" height="183" /> Image 2 - Dummy tasks for a pharmaceutical industry project We can now create a basic Gantt chart using <code>ggplot2</code>. We'll use the <code>geom_segment()</code> function to draw horizontal bars for each task based on their start and end dates. Here's the code: <pre><code class="language-r">ggplot(tasks, aes(x = StartDate, xend = EndDate, y = fct_rev(fct_inorder(Task)), yend = Task)) +  geom_segment()</code></pre> And we get a Gantt chart back, but the visuals leave a lot to be desired: <img class="size-full wp-image-19066" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7aef10f03f2fe35162682_ff17a418_3-3.webp" alt="Image 3 - A basic Gantt chart with ggplot2" width="1530" height="1082" /> Image 3 - A basic Gantt chart with ggplot2 Now to enhance the visuals, we'll add colors to individual tasks using the <code>color</code> parameter within <code>geom_segment()</code>. We'll also increase the line width by altering the <code>linewidth</code> parameter. The <code>colors</code> vector holds hexadecimal values for a monochromatic blue color palette: <pre><code class="language-r">colors &lt;- c("#deecfb", "#bedaf7", "#7ab3ef", "#368ce7", "#1666ba")   ggplot(tasks, aes(x = StartDate, xend = EndDate, y = fct_rev(fct_inorder(Task)), yend = Task)) +  geom_segment(linewidth = 35, color = colors)</code></pre> The resulting Gantt chart is much more visually appealing now: <img class="size-full wp-image-19068" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b29ff7abc39ede3f2cc16e_4-3.webp" alt="Image 4 - Adding colors to individual tasks" width="1530" height="1088" /> Image 4 - Adding colors to individual tasks But we can take the whole thing to the next level. The following code snippet shows you how to add titles, labels, and adjust the overall theme. In short, it makes the Gantt chart much more presentable: <pre><code class="language-r">ggplot(tasks, aes(x = StartDate, xend = EndDate, y = fct_rev(fct_inorder(Task)), yend = Task)) +  geom_segment(linewidth = 35, color = colors) +  labs(    title = "Pharma Company Gantt Chart",    x = "Duration",    y = "Task"  ) +  theme_bw() +  theme(legend.position = "none") +  theme(    plot.title = element_text(size = 20),    axis.text.x = element_text(size = 12),    axis.text.y = element_text(size = 12, angle = 45)  )</code></pre> Here's what you'll see in the visualizations panel: <img class="size-full wp-image-19070" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b29ff826ca1c8b1fa85962_5-3.webp" alt="Image 5 - Finalizing the visuals of a Gantt chart" width="1525" height="1082" /> Image 5 - Finalizing the visuals of a Gantt chart The Gantt chart is looking great now but isn't interactive in any way. We'll change that in the next section, where we'll create an R Shiny application around it. <h2 id="r-shiny-gantt">R Shiny Gantt Chart - How to Build a Planning Management App</h2> This section will take you from a static chart to a fully-working R Shiny application that allows you to add and remove elements from Gantt charts through interactive controls. It will take some work to make everything work, so follow the code section by section. We'll place comments in the code only for those sections that have changed from the previous one. That's how you'll recognize where to add, delete, or change the code. Let's start with a basic example of a R Shiny application with input controls and output sections for tables and charts. <h3>Building a Basic R Shiny App for Planning Management</h3> We'll start simple and build an R Shiny application with input controls and the output contains and display only static data. You won't be able to add or remove tasks in this section, but understanding this one is mandatory before implementing more advanced features. This is what you'll need regarding library imports, so stick them to the top of your R script: <pre><code class="language-r">library(tidyverse) library(ggplot2) library(DT) library(shiny)</code></pre> Now let's write the UI. We'll have a simple page with a sidebar and a main content section. The sidebar will have input elements for task name, start date, end date, and an action button that adds the task to the list. Again, we won't implement the logic for adding the task to the list in this section. The main panel of the app will have a task table view which will render a <code>DT</code> table with a list of tasks. Below the table, we'll also have a chart view that will show our Gantt chart. <blockquote>Don't know how to display table data in R? <a href="https://appsilon.com/top-r-packages-for-table-data/" target="_blank" rel="noopener">Here are top packages for visualizing table data in R and R Shiny</a>.</blockquote> Here's the entire code snippet for the Shiny app UI: <pre><code class="language-r"># Shiny app UI ui &lt;- fluidPage(  sidebarLayout(    sidebarPanel(      tags$h3("R Shiny Task Scheduling"),      tags$hr(), <br>      # Controls for task name, start &amp; end date      textInput(inputId = "inTaskName", label = "Task:", placeholder = "e.g., Marketing"),      dateInput(inputId = "inStartDate", value = Sys.Date(), min = Sys.Date(), label = "Start Date:"),      dateInput(inputId = "inEndDate", value = Sys.Date() + 10, min = Sys.Date() + 1, label = "End Date:"), <br>      # Button that adds the task      actionButton(inputId = "btn", label = "Add Task")    ),    mainPanel(      # Table output      tags$h3("Task Table View"),      tags$hr(),      DTOutput(outputId = "tableTasks"), <br>      # Chart output      tags$h3("Task Chart View"),      tags$hr(),      plotOutput(outputId = "plotTasks")    )  ) )</code></pre> And now onto the server logic. We'll make an initial <code>data.frame</code> of tasks as a <b>reactive value</b> and then display it both as a table and as a Gantt chart. The code for the table is new, so make sure you understand it. On the contrary, the code for the Gantt chart is almost identical to the one from the previous section: <pre><code class="language-r">server &lt;- function(input, output) {  df &lt;- reactiveValues(    data = data.frame(      Task = c("Research", "Clinical Trials", "Regulatory Approval"),      StartDate = as.Date(c("2023-05-01", "2023-07-01", "2024-01-01")),      EndDate = as.Date(c("2023-06-30", "2023-12-31", "2024-06-30"))    )  ) <br>  # Table output  output$tableTasks &lt;- renderDT({    datatable(      data = df$data,      colnames = c("Task", "Start Date", "End Date"),      filter = "top"    )  }) <br>  # Chart output  output$plotTasks &lt;- renderPlot({    ggplot(df$data, aes(x = StartDate, xend = EndDate, y = fct_rev(fct_inorder(Task)), yend = Task)) +      geom_segment(linewidth = 10, color = "#0198f9") +      labs(        title = "Pharma Company Gantt Chart",        x = "Duration",        y = "Task"      ) +      theme_bw() +      theme(legend.position = "none") +      theme(        plot.title = element_text(size = 20),        axis.text.x = element_text(size = 12),        axis.text.y = element_text(size = 12, angle = 45)      )  }) } <br> shinyApp(ui = ui, server = server)</code></pre> We now have both the UI and server code, which means we can run the R Shiny app. Here's what it looks like: <img class="size-full wp-image-19072" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b29ff9300ce9856e5114c1_6-3.webp" alt="Image 6 - Basic R Shiny app for planning management" width="1910" height="1163" /> Image 6 - Basic R Shiny app for planning management The UI controls are there and both the table and the chart display correctly. The only problem is - <b>The input controls don't work</b>. You'll learn how to enable adding tasks in the following section. <h3>How to Add Tasks to a Gantt Chart in Shiny</h3> You don't have to tweak a thing in the Shiny app UI to enable adding tasks to a task <code>data.frame</code>. Everything happens in the <code>server()</code> function. Here's a brief overview of the code changes we have to make: <ul><li><b>Attach a reactive observer to the action button</b><ul><li>Fetch the current values from the input elements (task name, start date, end date)</li><li>Check if current values are not <code>null</code></li><li>If not <code>null</code>, make a new <code>data.frame</code> that matches the structure of the existing one</li><li>Use the <code>rbind()</code> function to concatenate two <code>data.frame</code> objects. This will append the new task to the end of the existing ones</li><li>Sort the <code>data.frame</code> by <code>StartDate</code> to preserve the ordering</li></ul> </li> </ul> And that's it! It's just one task with multiple steps, and all the code changes happen in <code>server()</code> below the initial data declaration. Here's the code snippet for the entire R Shiny app: <pre><code class="language-r">library(tidyverse) library(ggplot2) library(DT) library(shiny) <br>ui &lt;- fluidPage(  sidebarLayout(    sidebarPanel(      tags$h3("R Shiny Task Scheduling"),      tags$hr(),      textInput(inputId = "inTaskName", label = "Task:", placeholder = "e.g., Marketing"),      dateInput(inputId = "inStartDate", value = Sys.Date(), min = Sys.Date(), label = "Start Date:"),      dateInput(inputId = "inEndDate", value = Sys.Date() + 10, min = Sys.Date() + 1, label = "End Date:"),      actionButton(inputId = "btn", label = "Add Task")    ),    mainPanel(      tags$h3("Task Table View"),      tags$hr(),      DTOutput(outputId = "tableTasks"),      tags$h3("Task Chart View"),      tags$hr(),      plotOutput(outputId = "plotTasks")    )  ) ) <br> server &lt;- function(input, output) {  df &lt;- reactiveValues(    data = data.frame(      Task = c("Research", "Clinical Trials", "Regulatory Approval"),      StartDate = as.Date(c("2023-05-01", "2023-07-01", "2024-01-01")),      EndDate = as.Date(c("2023-06-30", "2023-12-31", "2024-06-30"))    )  ) <br>  # ADD TASK  observeEvent(input$btn, {    task_name &lt;- input$inTaskName    task_start_date &lt;- input$inStartDate    task_end_date &lt;- input$inEndDate <br>    # Check if not null    if (!is.null(task_name) &amp;&amp; !is.null(task_start_date) &amp;&amp; !is.null(task_end_date)) {      # Make a new row      new_row &lt;- data.frame(Task = task_name, StartDate = task_start_date, EndDate = task_end_date, stringsAsFactors = FALSE)      # Add row to the existing dataframe      df$data &lt;- rbind(df$data, new_row)      # Sort the dataframe by StartDate      df$data &lt;- df$data[order(df$data$StartDate), ]    }  }) <br>  output$tableTasks &lt;- renderDT({    datatable(      data = df$data,      colnames = c("Task", "Start Date", "End Date"),      filter = "top"    )  }) <br>  output$plotTasks &lt;- renderPlot({    ggplot(df$data, aes(x = StartDate, xend = EndDate, y = fct_rev(fct_inorder(Task)), yend = Task)) +      geom_segment(linewidth = 10, color = "#0198f9") +      labs(        title = "Pharma Company Gantt Chart",        x = "Duration",        y = "Task"      ) +      theme_bw() +      theme(legend.position = "none") +      theme(        plot.title = element_text(size = 20),        axis.text.x = element_text(size = 12),        axis.text.y = element_text(size = 12, angle = 45)      )  }) } <br> shinyApp(ui = ui, server = server)</code></pre> You can now launch the app and experiment with task addition: <img class="size-full wp-image-19074" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7aef55d4d39bf0cf17790_f3592319_7.gif" alt="Image 7 - Adding tasks to the Gantt chart in R Shiny" width="1904" height="1126" /> Image 7 - Adding tasks to the Gantt chart in R Shiny You can further improve this solution by adding start date and end date checks. For example, the end date can't be lower than the start date, and we currently don't implement this check. Consider this as a homework assignment. Up next, let's see how to delete a task from the task list. <h3>How to Delete Tasks from an R Shiny Gantt Chart</h3> Deleting a task will be much more challenging than adding it. There are just much more moving parts - we need an additional button for each table row, and we need to keep track of the row number. Let's follow the same convention and declare a list of code changes we have to implement: <ul><li><b>Add an ID column and a Remove button to the table</b><ul><li>Add an ID column based on the <code>row_number()</code> function. Make sure the column is added as the first column of the <code>data.frame</code></li><li>Add a Remove button to each row by monitoring the current ID value</li></ul> </li> <li><b>Change task addition logic to accommodate new columns</b> <ul><li>Calculate the new row ID - The largest from the <code>data.frame</code> plus one</li><li>Add a Remove button for the given ID</li></ul> </li> <li><b>Attach a reactive observer to the Remove button</b> <ul><li>Use the <code>-</code> notation to remove a row at a given index location (ID)</li><li>Reorder the <code>data.frame</code> by start date</li></ul> </li> </ul> It's a lot of code changes, so don't sweat it if you can't figure everything out. Just copy our code snippet from below: <pre><code class="language-r">library(tidyverse) library(ggplot2) library(DT) library(shiny) library(glue) <br> ui &lt;- fluidPage(  sidebarLayout(    sidebarPanel(      tags$h3("R Shiny Task Scheduling"),      tags$hr(),      textInput(inputId = "inTaskName", label = "Task:", placeholder = "e.g., Marketing"),      dateInput(inputId = "inStartDate", value = Sys.Date(), min = Sys.Date(), label = "Start Date:"),      dateInput(inputId = "inEndDate", value = Sys.Date() + 10, min = Sys.Date() + 1, label = "End Date:"),      actionButton(inputId = "btn", label = "Add Task")    ),    mainPanel(      tags$h3("Task Table View"),      tags$hr(),      DTOutput(outputId = "tableTasks"),      tags$h3("Task Chart View"),      tags$hr(),      plotOutput(outputId = "plotTasks")    )  ) ) <br> server &lt;- function(input, output) {  df &lt;- reactiveValues(    data = data.frame(      Task = c("Research", "Clinical Trials", "Regulatory Approval"),      StartDate = as.Date(c("2023-05-01", "2023-07-01", "2024-01-01")),      EndDate = as.Date(c("2023-06-30", "2023-12-31", "2024-06-30"))    ) %&gt;%      # Add an ID column - used later to remove row with certain ID      mutate(ID = row_number(), .before = Task) %&gt;%      # Add a column with a custom Remove button      mutate(        Remove = glue('&lt;button id="custom_btn" onclick="Shiny.onInputChange(\'button_id\', \'{ID}\')"&gt;Remove&lt;/button&gt;')      )  ) <br>  observeEvent(input$btn, {    task_name &lt;- input$inTaskName    task_start_date &lt;- input$inStartDate    task_end_date &lt;- input$inEndDate <br>    if (!is.null(task_name) &amp;&amp; !is.null(task_start_date) &amp;&amp; !is.null(task_end_date)) {      # We also need a new row ID      new_id &lt;- max(df$data$ID) + 1      new_row &lt;- data.frame(        # Row ID        ID = new_id,        Task = task_name,        StartDate = task_start_date,        EndDate = task_end_date,        # Remove button        Remove = glue('&lt;button id="custom_btn" onclick="Shiny.onInputChange(\'button_id\', \'{new_id}\')"&gt;Remove&lt;/button&gt;'),        stringsAsFactors = FALSE      )      df$data &lt;- rbind(df$data, new_row)      df$data &lt;- df$data[order(df$data$ID), ]    }  }) <br>  # REMOVE A TASK  observeEvent(input$button_id, {    # Remove a row from the data.frame    df$data &lt;- df$data[-c(as.integer(input$button_id)), ]    # Sort the dataframe by StartDate    df$data &lt;- df$data[order(df$data$StartDate), ]  }) <br>  output$tableTasks &lt;- renderDT({    datatable(data = df$data, escape = FALSE)  }) <br>  output$plotTasks &lt;- renderPlot({    ggplot(df$data, aes(x = StartDate, xend = EndDate, y = fct_rev(fct_inorder(Task)), yend = Task)) +      geom_segment(linewidth = 10, color = "#0198f9") +      labs(        title = "Pharma Company Gantt Chart",        x = "Duration",        y = "Task"      ) +      theme_bw() +      theme(legend.position = "none") +      theme(        plot.title = element_text(size = 20),        axis.text.x = element_text(size = 12),        axis.text.y = element_text(size = 12, angle = 45)      )  }) } <br> shinyApp(ui = ui, server = server)</code></pre> Our R Shiny application for planning management is almost done. Here's what it looks like: <img class="size-full wp-image-19076" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b29ffa08a4ff6bc89afac3_8.gif" alt="Image 8 - Removing tasks from a Gantt chart in R Shiny" width="1902" height="1206" /> Image 8 - Removing tasks from a Gantt chart in R Shiny Finally, let's address the general app styles. <h3>Styling an R Shiny Gantt Planning Management Application with CSS</h3> Functionallity-wise, our app is ready to ship. But it looks terrible. In this section, we'll show you how to style it with a couple of lines of CSS code. To start, create a <code>www</code> folder right where your <code>app.R</code> script file is saved, and then create a <code>main.css</code> file inside it. Paste the following contents: <pre><code class="language-css">@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&amp;display=swap'); <br>* {  margin: 0;  padding: 0;  box-sizing: border-box; } <br>body {  font-family: 'Poppins', sans-serif;  background-color: #f2f2f2; } <br>h1, h2, h3, h4, h5, h6 {  font-weight: 700; } <br>.sidebar {  height: 100%;  background-color: #ffffff;  margin: 1.5rem 0;  border-radius: 1rem; } <br>.card {  background-color: #ffffff;  padding: 1rem 2rem;  border-radius: 1rem;  border: 1px solid #d3d3d3;  margin: 1.5rem 0; }</code></pre> This set of CSS stylings will apply the <i>Poppins</i> font to the entire application, and take care of the background colors and general margins. It's not a lot, but just enough to make the application stand out. We're not done yet. The next step is to add the <code>main.css</code> to our Shiny app. To do so, <b>add a link</b> to the <code>main.css</code> file inside the Shiny app UI. While there, we'll also surround the main panel elements into two distinct <code>div</code>'s, so we can better style them with CSS. Here's the entire code snippet: <pre><code class="language-r">library(tidyverse) library(ggplot2) library(DT) library(shiny) library(glue) <br> ui &lt;- fluidPage(  # Link to CSS file  tags$head(    tags$link(rel = "stylesheet", type = "text/css", href = "main.css")  ),  sidebarLayout(    sidebarPanel(      class = "sidebar",      tags$h3("R Shiny Task Scheduling"),      tags$hr(),      textInput(inputId = "inTaskName", label = "Task:", placeholder = "e.g., Marketing"),      dateInput(inputId = "inStartDate", value = Sys.Date(), min = Sys.Date(), label = "Start Date:"),      dateInput(inputId = "inEndDate", value = Sys.Date() + 10, min = Sys.Date() + 1, label = "End Date:"),      actionButton(inputId = "btn", label = "Add Task")    ),    mainPanel(      # Surround the elements with a DIV element that has a class name of "card"      tags$div(        class = "card",        tags$h3("Task Table View"),        tags$hr(),        DTOutput(outputId = "tableTasks")      ),      # Surround the elements with a DIV element that has a class name of "card"      tags$div(        class = "card",        tags$h3("Task Chart View"),        tags$hr(),        plotOutput(outputId = "plotTasks")      )    )  ) ) <br> server &lt;- function(input, output) {  df &lt;- reactiveValues(    data = data.frame(      Task = c("Research", "Clinical Trials", "Regulatory Approval"),      StartDate = as.Date(c("2023-05-01", "2023-07-01", "2024-01-01")),      EndDate = as.Date(c("2023-06-30", "2023-12-31", "2024-06-30"))    ) %&gt;%      mutate(ID = row_number(), .before = Task) %&gt;%      mutate(        Remove = glue('&lt;button id="custom_btn" onclick="Shiny.onInputChange(\'button_id\', \'{ID}\')"&gt;Remove&lt;/button&gt;')      )  ) <br>  observeEvent(input$btn, {    task_name &lt;- input$inTaskName    task_start_date &lt;- input$inStartDate    task_end_date &lt;- input$inEndDate <br>    if (!is.null(task_name) &amp;&amp; !is.null(task_start_date) &amp;&amp; !is.null(task_end_date)) {      new_id &lt;- max(df$data$ID) + 1      new_row &lt;- data.frame(        ID = new_id,        Task = task_name,        StartDate = task_start_date,        EndDate = task_end_date,        Remove = glue('&lt;button id="custom_btn" onclick="Shiny.onInputChange(\'button_id\', \'{new_id}\')"&gt;Remove&lt;/button&gt;'),        stringsAsFactors = FALSE      )      df$data &lt;- rbind(df$data, new_row)      df$data &lt;- df$data[order(df$data$ID), ]    }  }) <br>  observeEvent(input$button_id, {    output$text &lt;- renderText(glue("Row number {input$button_id} is selected recently"))    df$data &lt;- df$data[-c(as.integer(input$button_id)), ]    df$data &lt;- df$data[order(df$data$StartDate), ]  }) <br>  output$tableTasks &lt;- renderDT({    datatable(data = df$data, escape = FALSE)  }) <br>  output$plotTasks &lt;- renderPlot({    ggplot(df$data, aes(x = StartDate, xend = EndDate, y = fct_rev(fct_inorder(Task)), yend = Task)) +      geom_segment(linewidth = 10, color = "#0198f9") +      labs(        title = "Pharma Company Gantt Chart",        x = "Duration",        y = "Task"      ) +      theme_bw() +      theme(legend.position = "none") +      theme(        plot.title = element_text(size = 20),        axis.text.x = element_text(size = 12),        axis.text.y = element_text(size = 12, angle = 45)      )  }) } <br> shinyApp(ui = ui, server = server) </code></pre> Our application is now complete: <img class="size-full wp-image-19078" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b29ffadb018b429f9a236e_9.gif" alt="Image 9 - Completed R Shiny application for planning management" width="1902" height="1246" /> Image 9 - Completed R Shiny application for planning management Simple, yet effective. Let's make a short recap next. <hr /> <h2 id="summary">Summing up R Shiny Gantt Charts</h2> In this article, we have explored the power of R Shiny and Gantt charts in revolutionizing planning management, specifically in the context of the pharmaceutical industry. We started by understanding the importance of planning management and how Gantt charts serve as a valuable tool for visualizing project timelines and tasks. You've learned how to make Gantt charts in R with <code>ggplot2</code> and how to make an entire application around them with R Shiny. A lot for a single read. Through the use of R Shiny, teams can create powerful planning management apps tailored to their specific needs. These apps provide a comprehensive overview of projects, facilitate collaboration, and enable data-driven decision-making. Stakeholders can gain insights, identify bottlenecks, allocate resources effectively, and make timely adjustments to ensure project success. <blockquote>If your company needs a custom-tailored R Shiny application, <a href="https://appsilon.com/#contact">make sure to reach out to Appsilon</a>.</blockquote>

Have questions or insights?

Engage with experts, share ideas and take your data journey to the next level!

Is Your Software GxP Compliant?

Download a checklist designed for clinical managers in data departments to make sure that software meets requirements for FDA and EMA submissions.
Explore Possibilities

Share Your Data Goals with Us

From advanced analytics to platform development and pharma consulting, we craft solutions tailored to your needs.

Talk to our Experts
r
shiny
tutorials
shiny dashboards