title: R leaflet change colour of addCircles() in animation
body: <p>I have a Shiny app with a leaflet showing ~9,000 points on a grid (each point representing a 100 m x 100 m square). The app is animated, so that each point changes colour over time. The first version of the app used <code>addPolygons()</code> with the <code>setShapeStyle()</code> function from <a href="https://github.com/rstudio/leaflet/issues/496" rel="nofollow noreferrer">here</a> to allow the polygons to change colour over time, while accounting for area that each point accounts for. The polygon app was great but super slow, so I changed to <code>addCircleMarkers</code> instead, coupled with <code>setCircleMarkerStyle()</code> from <a href="https://github.com/rstudio/leaflet/issues/496" rel="nofollow noreferrer">the same GitHub page</a>. This is way faster and works well, BUT I have 2 problems - 1) at low zooms, my points overlap, and 2) at high zooms, my points are separated by space.</p>
  <p>Can anyway help me apply the same animation solutions offered by the change of style as <a href="https://github.com/rstudio/leaflet/issues/496" rel="nofollow noreferrer">here</a>, but applied to <code>addCircles()</code> so that I can use a set radius, or a similar solution? Ideas for making the points square, so that I don't end up with empty spaces at high zooms are also welcome.</p>
  <p>libraries and fake data:</p>
  <pre><code>library(plyr)
  library(dplyr)
  library(tidyr)
  library(lubridate)
  
  library(shiny)
  library(leaflet)
  library(viridisLite)
              
  nodes &lt;- structure(list(node = 1:9, Lon = c(-60.1760758677342, -60.1768617891598, 
  -60.1664512653477, -60.1672369749724, -60.1680228296767, -60.1688085769102, 
  -60.1695943435806, -60.170380129055, -60.1711659327049), Lat = c(43.316878317912, 
  43.317580709354, 43.309714197049,43.310416744826, 43.311119197611, 
  43.311821734546, 43.312524176034, 43.3132266121, 43.31392913277
  )), row.names = c(NA, -9L), class = &quot;data.frame&quot;) 
  
  data &lt;- nodes %&gt;%
          crossing(Date = seq(as_date(&quot;2020-01-01&quot;), as_date(&quot;2020-03-15&quot;), &quot;1 day&quot;)) %&gt;%
          mutate(Density = abs(rnorm(675, 10, 10)),
                  Exceed = ifelse(Density &gt; 20, 1, 0),
                  Layer = paste(node, &quot;Tile&quot;, sep = &quot;_&quot;))
  FirstDay &lt;- data %&gt;%
              filter(Date == min(Date))
  </code></pre>
  <p>Helper functions (based on the Github page referenced):</p>
  <pre><code>leafletjs &lt;-  tags$head(
    tags$script(HTML('
  window.LeafletWidget.methods.setStyle = function(category, layerId, style){
    var map = this;
    if (!layerId){
      return;
    } else if (!(typeof(layerId) === &quot;object&quot; &amp;&amp; layerId.length)){
      layerId = [layerId];
    }
    style = HTMLWidgets.dataframeToD3(style);
    layerId.forEach(function(d,i){
      var layer = map.layerManager.getLayer(category, d);
      if (layer){
        layer.setStyle(style[i]);
      }
    });
  };
  ')))
  
  setCircleMarkerStyle &lt;- function(map, layerId
                                   , radius = NULL
                                   , stroke = NULL
                                   , color = NULL
                                   , weight = NULL
                                   , opacity = NULL
                                   , fill = NULL
                                   , fillColor = NULL
                                   , fillOpacity = NULL
                                   , dashArray = NULL
                                   , options = NULL
                                   , data = getMapData(map)
  ){
  
    options &lt;- c(list(layerId = layerId),
                 options,
                 filterNULL(list(stroke = stroke, color = color,
                                 weight = weight, opacity = opacity,
                                 fill = fill, fillColor = fillColor,
                                 fillOpacity = fillOpacity, dashArray = dashArray
                 )))
  
    if (length(options) &lt; 2) { # no style options set
      return()
    }
    # evaluate all options
    options &lt;- evalFormula(options, data = data)
  
    # make them the same length (by building a data.frame)
    options &lt;- do.call(data.frame, c(options, list(stringsAsFactors=FALSE)))
    layerId &lt;- options[[1]]
    style &lt;- options[-1] # drop layer column
  
    #print(list(style=style))
    leaflet::invokeMethod(map, data, &quot;setStyle&quot;, &quot;marker&quot;, layerId, style);
  }
  </code></pre>
  <p>UI and server</p>
  <pre><code>ui &lt;- fluidPage(
    leafletjs,
    sidebarLayout(
      sidebarPanel(sliderInput(&quot;dateSel&quot;, &quot;Date&quot;,
                    min = min(data$Date), max = max(data$Date), 
                    value = min(data$Date), step = 1, timeFormat = &quot;%d %b %y&quot;,
                    animate = animationOptions(interval = 100, loop = FALSE))),
      mainPanel(leafletOutput(&quot;MapAnimate&quot;))))
    
  server &lt;- function(input, output, session) {   
    filteredData &lt;- reactive({
          data %&gt;% filter(Date == input$dateSel) 
                              })
                              
    output$MapAnimate &lt;- renderLeaflet({
      range &lt;- range(data$Density)
      palette &lt;- colorNumeric(palette = viridis(100), domain = range)
  
      leaflet(FirstDay) %&gt;% 
        addTiles()  %&gt;% 
        addCircleMarkers(lng = ~Lon, lat = ~Lat, layerId = ~Layer, 
                         fillColor = &quot;lightgray&quot;, fill = TRUE,
                         color = &quot;white&quot;, stroke = TRUE, 
                         fillOpacity = 1, opacity = 1, weight = 2) %&gt;%
       leaflet::addLegend(pal = palette, values = range, opacity = 0.9, position = &quot;topleft&quot;)
       })
                                                  
    observe({
      df.in &lt;- filteredData()
      range &lt;- range(data$Density)
      palette &lt;- colorNumeric(palette = viridis(100), domain = range)
       
      leafletProxy(&quot;MapAnimate&quot;, data = df.in) %&gt;%
      setCircleMarkerStyle(layerId = ~Layer, 
                          fillColor = ~palette(Density),
                          color = ~ifelse(Exceed == 1, &quot;red&quot;, &quot;white&quot;)) 
    })
          }
  
  
  shinyApp(ui = ui, server = server)  
  </code></pre>