For a certain online course, I made a quick interactive map using leaflet in Rmarkdown and published it to Rpubs. The data is about world cities and their population.
I was trying to make colour gradient based on the population size of a city. For example red for Tokyo and green for a city with lesser population (~=1-2). Below is the code I used to generate the published map here:
---
title: "Global population concentration"
author: "Piyush Verma"
date: "December 28, 2017"
output: html_document
---
```{r setup, echo=FALSE}
knitr::opts_chunk$set(fig.width=12, fig.height=8)
```
```{r, message=FALSE,warning=FALSE,results='hide', echo=FALSE}
set.seed(2017-12-27)
library("data.table")
cities<-fread("./worldcities.csv")
cities<-cities[cities$pop>0,]
```
```{r, message=FALSE,warning=FALSE, echo=FALSE, width = 40, height = 30}
library("leaflet")
pal <- colorNumeric(palette = "Red",domain = cities$pop)
cities2<-cbind(cities,col=pal(cities$pop))
my_map <- cities2 %>% leaflet() %>% addTiles() %>% addCircles(weight = 1, radius = sqrt(cities$pop) * 110) %>% setView(lat = 51.4826, lng = 0.0077, zoom = 2)
my_map
```
I downloaded the data from here:
I tried using help from here but ended up producing error Error in polygonData/default(data): Dont know how to get path data from object of class numeric
Any help would be a great help for the future.
Thank you.
Change your code to
pal <- colorNumeric(palette = c("green", "red"), domain = cities$pop)
my_map <- cities2 %>% leaflet() %>% addTiles() %>%
addCircles(weight = 1, radius = sqrt(cities$pop) * 110, color = ~pal(cities$pop)) %>%
setView(lat = 51.4826, lng = 0.0077, zoom = 2)
and it works. Needs some fine-tuning though. colorQuantile might be better suited.
Related
I am building a small app to summarize some data. my results table has the value of a number of categories that sum to a given total. Now I would like users to be able to input different categories and get the sum of the statistics of those categories OR show them the total of all categories (so selecting all the categories gives the same as just selecting the total). To make the app look a bit cleaner I would like to simply use a single selectizeInput. However, that would mean that if the user selects the category total they should not be able to select any of the other 3 categories and if any of the 3 categories is selected total should be deselected. Otherwise, if the user selects all inputs including the total the sum sum to 2*Total (in my example 20 instead of 10).
Small example (based on https://shiny.rstudio.com/articles/selectize.html)
df <- data.frame(x = c("Total", "A", "B", "C"),
sum_res = c(10, 5, 3, 2))
library(shiny)
ui <- fluidPage(title = 'Selectize examples',
sidebarLayout(
sidebarPanel(
selectizeInput(
'e2',
'2. Multi-select',
multiple = TRUE,
selected = "Total",
choices = df$x
)
),
mainPanel(
helpText('Output of the examples in the left:'),
verbatimTextOutput('ex_out'),
verbatimTextOutput('sum')
)
))
server <- function(input, output) {
output$ex_out <- renderPrint({
str(list(input$e2))
})
output$sum <- renderPrint({
df %>%
filter(x %in% input$e2) %>%
summarise(sum = sum(sum_res))
})
}
shinyApp(ui, server)
This is somewhat related, but not exactly the same as Selectizeinput inputs be mutually exclusive R Shiny.
Ideally this solution would be in the custom javascript within the selectizeInput(), but could also be serverside.
One way to do it is to ignore other selections when Total is selected. Try this
df <- data.frame(x = c("A", "B", "C"),
sum_res = c(5, 3, 2))
library(shiny)
ui <- fluidPage(title = 'Selectize examples',
sidebarLayout(
sidebarPanel(
selectizeInput(
'e2',
'2. Multi-select',
multiple = TRUE,
selected = "Total",
choices = c("Total",unique(df$x))
)
),
mainPanel(
helpText('Output of the examples in the left:'),
verbatimTextOutput('ex_out'),
verbatimTextOutput('sum')
)
))
server <- function(input, output) {
output$ex_out <- renderPrint({
str(list(input$e2))
})
output$sum <- renderPrint({
if ("Total" %in% input$e2 | length(input$e2)==3) df1 <- df
else df1 <- df %>% filter(x %in% input$e2)
df1 %>% summarise(sum = sum(sum_res))
})
}
shinyApp(ui, server)
I'm trying to scrape a table from the web (here https://www.cryptoslam.io/nba-top-shot/marketplace).
I have been researching how to do this and seem to have gotten closest using library rvest and the html_table() function. In fact I was able to download the "FIFA World Cup Record" table from here https://en.wikipedia.org/wiki/Brazil_national_football_team using the code
webpage_url <- "https://en.wikipedia.org/wiki/Brazil_national_football_team"
webpage <- xml2::read_html(webpage_url)
tbls <- html_nodes(webpage, "table")
head(tbls)
tbls_ls <- webpage %>%
html_nodes("table") %>%
.[[6]] %>%
html_table(fill = TRUE)
Note that I have the libraries library(xml2), library(rvest) loaded. I then am using essentially the same code here:
webpage_url <- "https://www.cryptoslam.io/nba-top-shot/marketplace"
webpage <- xml2::read_html(webpage_url)
tbls <- html_nodes(webpage, "table")
head(tbls)
tbls_ls <- webpage %>%
html_nodes("table") %>%
.[[1]] %>%
html_table(fill = TRUE)
but getting the error
Error in matrix(NA_character_, nrow = n, ncol = maxp) :
invalid 'ncol' value (too large or NA)
In addition: Warning messages:
1: In max(p) : no non-missing arguments to max; returning -Inf
2: In matrix(NA_character_, nrow = n, ncol = maxp) :
NAs introduced by coercion to integer range
I have not been able to find any discussion of this error anywhere else. One thing that is different between the two tables is the existence of a thead tag in the second one which won't work. I have quite limited knowledge of html so I may be missing some other important differences between the table implementations.
One approach is with RSelenium:
library(RSelenium)
library(rvest) #requires xml2, no need to load separately
driver <- rsDriver(browser="chrome", port=4234L, chromever ="87.0.4280.87")
client <- driver[["client"]]
client$navigate(webpage_url)
source <- client$getPageSource()[[1]]
read_html(source) %>%
html_nodes("table") %>%
html_table() %>%
`[[`(1) -> result
head(result)
Listed Rank Crypto Set Team Play Category SN# Current Price Owner
1 NA 5 minutes ago 10324 2020-21 Bradley Beal Base Set Washington Wizards Handles 10691 (10.00 USD) P1BenEe
2 NA 5 minutes ago 1096 2019-20 Kelly Olynyk The Finals Miami Heat Layup 360 (180.00 USD) Top_Shot3point
3 NA 5 minutes ago 3138 2019-20 Alex Caruso Base Set Los Angeles Lakers Block 679 67.00 USD CaptainThunder
4 NA 5 minutes ago 3586 2020-21 Kelly Oubre Jr. Base Set Golden State Warriors Dunk 3583 5.00 USD dddd9999
5 NA 5 minutes ago 3318 2020-21 Bismack Biyombo Base Set Charlotte Hornets Layup 3315 7.00 USD ectoasty
6 NA 5 minutes ago 4940 2020-21 DeMarcus Cousins Base Set Houston Rockets 3 Pointer 4937 (3.00 USD) StoneColdBroke
That data comes from an API post request returning json. You can issue that request then parse json, returned as list from content, into whatever your desired format is
library(httr)
headers = c(
'user-agent'= 'Mozilla/5.0',
'content-type'= 'application/json',
'referer'= 'https://www.cryptoslam.io/',
'accept-language'= 'en-GB,en-US;q=0.9,en;q=0.8'
)
data = '{"draw":1,"columns":[{"data":null,"name":"","searchable":true,"orderable":false,"search":{"value":"","regex":false}},{"data":null,"name":"TimeStamp","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":null,"name":"","searchable":true,"orderable":false,"search":{"value":"","regex":false}},{"data":null,"name":"Tokens.0.Rank","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":null,"name":"Tokens.Attributes.Name","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":null,"name":"Tokens.Attributes.Set","searchable":true,"orderable":false,"search":{"value":"","regex":false}},{"data":null,"name":"Tokens.Attributes.Team","searchable":true,"orderable":false,"search":{"value":"","regex":false}},{"data":null,"name":"Tokens.Attributes.PlayCategory","searchable":true,"orderable":false,"search":{"value":"","regex":false}},{"data":null,"name":"Tokens.Attributes.SerialNumber","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":null,"name":"CurrentPrice","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":null,"name":"EndingPriceGwei","searchable":true,"orderable":true,"search":{"value":"","regex":false}},{"data":null,"name":"","searchable":true,"orderable":false,"search":{"value":"","regex":false}},{"data":null,"name":"","searchable":true,"orderable":false,"search":{"value":"","regex":false}}],"order":[{"column":1,"dir":"desc"}],"start":0,"length":50,"search":{"value":"","regex":false},"startdate":"","enddate":"","marketplace":"","attributesQuery":{}}'
r <- httr::POST(url = 'https://api2.cryptoslam.io/api/marketplace/NBA Top Shot/search', httr::add_headers(.headers=headers), body = data) %>% content()
I am in the circuit board manufacturing industry, and we measure the temperature at a variety of locations on our circuit boards in an effort to identify if certain components are exceeding their required temperatures.
I have some exposure to .js visualization libraries, RStudio and Shiny. I would like to implement this application into an existing R or ShinyDashboard that I am developing.
What I would like to accomplish is to have a 2d or 3d image of my circuit board, and a heatmap that takes the maximum temperature and shows it on that image. My data sets have columns of temperatures over time for up to 20 different locations.
I know this is a crude description, but I was wondering if anyone has any initial suggestions to accomplish this?
Update1
This is the result of running the first code:
Update2
Here is the sample dataset that I would like to base this heatmap off of.
https://docs.google.com/spreadsheets/d/11I19uQyND7YehKrYd-NPiib4bQSHmHmWENFvausigvU/edit?usp=sharing
You could use ggplot for something like this, for example:
library(grid)
library(ggplot2)
# Download image
library(jpeg)
download.file("http://www.expresspcb.com/wp-content/uploads/2015/06/PhotoProductionPCB_TL_800.jpg","pcb.jpg")
img <- readJPEG("/home/oskar/pcb.jpg")
## Load image, use this if you can't download image
#library(png)
#img <- readPNG(system.file("img", "Rlogo.png", package="png"))
g <- rasterGrob(img, interpolate=TRUE,width=1,height=1)
coords <- data.frame("x"=c(0,1),"y"=c(0,1))
# Simulate data
df <- data.frame("x.pos" = c(runif(200),runif(20,min=0.5,max=0.8)),
"y.pos" = c(runif(200),runif(20,min=0.5,max=0.8)),
"heat" = c(runif(200),runif(20,min=0.7,max=1)))
# Show overlay of image and heatmap
ggplot(data=df,aes(x=x.pos,y=y.pos,fill=heat)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
stat_density2d( alpha=0.2,aes(fill = ..level..), geom="polygon" ) +
scale_fill_gradientn(colours = rev( rainbow(3) )) +
scale_x_continuous(expand=c(0,0)) +
scale_y_continuous(expand=c(0,0))
# Show where max temperature is
dat.max = df[which.max(df$heat),]
ggplot(data=coords,aes(x=x,y=y)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_point(data=dat.max,aes(x=x.pos,y=y.pos), shape=21,size=5,color="black",fill="red") +
geom_text(data=dat.max,aes(x=x.pos,y=y.pos,label=round(heat,3)),vjust=-1,color="red",size=10)
The ggplot image part is from here
You can also bin the data manually and overlay it on the image like this (run this part after the script above):
# bin data manually
# Manually set number of rows and columns in the matrix containing sums of heat for each square in grid
nrows <- 30
ncols <- 30
# Define image coordinate ranges
x.range <- c(0,1) # x-coord range
y.range <- c(0,1) # x-coord range
# Create matrix and set all entries to 0
heat.density.dat <- matrix(nrow=nrows,ncol=ncols)
heat.density.dat[is.na(heat.density.dat)] <- 0
# Subdivide the coordinate ranges to n+1 values so that i-1,i gives a segments start and stop coordinates
x.seg <- seq(from=min(x.range),to=max(x.range),length.out=ncols+1)
y.seg <- seq(from=min(y.range),to=max(y.range),length.out=nrows+1)
# List to hold found values
a <- list()
cnt <- 1
for( ri in 2:(nrows+1)){
for ( ci in 2:(ncols+1)){
# Get current segments, for example x.vals = [0.2, 0.3]
x.vals <- x.seg [c(ri-1,ri)]
y.vals <- y.seg [c(ci-1,ci)]
# Find which of the entries in the data.frame that has x or y coordinates in the current grid
x.inds <- which( ((df$x.pos >= min(x.vals)) & (df$x.pos <= max(x.vals)))==T )
y.inds <- which( ((df$y.pos >= min(y.vals)) & (df$y.pos <= max(y.vals)))==T )
# Find which entries has both x and y in current grid
inds <- which( x.inds %in% y.inds )
# If there's any such coordinates
if (length(inds) > 0){
# Append to list
a[[cnt]] <- data.frame("x.start"=min(x.vals), "x.stop"=max(x.vals),
"y.start"=min(y.vals), "y.stop"=max(y.vals),
"acc.heat"=sum(df$heat[inds],na.rm = T) )
# Increment counter variable
cnt <- cnt + 1
}
}
}
# Construct data.frame from list
heat.dens.df <- do.call(rbind,a)
# Plot again
ggplot(data=heat.dens.df,aes(x=x.start,y=y.start)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_rect(data=heat.dens.df, aes(xmin=x.start, xmax=x.stop, ymin=y.start, ymax=y.stop, fill=acc.heat), alpha=0.5) +
scale_fill_gradientn(colours = rev( rainbow(3) )) +
scale_x_continuous(expand=c(0,0)) +
scale_y_continuous(expand=c(0,0))
Coordinate conversion from your data to my format can be done like:
sensor.data <- read.csv("~/Sample_Dataset.csv - Sample_Dataset.csv.csv")
# Create position -> coord conversion
pos.names <- names(sensor.data)[ grep("*Pos",names(sensor.data)) ] # Get column names with "Pos" in them
mock.coords <<- list()
lapply(pos.names, function(name){
# Create mocup coords between 0-1
mock.coords[[name]] <<- data.frame("x"=runif(1),"y"=runif(1))
})
# Change format of your data matrix
df.l <- list()
cnt <- 1
for (i in 1:nrow(sensor.data)){
for (j in 1:length(pos.names)){
name <- pos.names[j]
curr.coords <- mock.coords[[name]]
df.l[[cnt]] <- data.frame("x.pos"=curr.coords$x,
"y.pos"=curr.coords$x,
"heat" =sensor.data[i,j])
cnt <- cnt + 1
}
}
# Create matrix
df <- do.call(rbind, df.l)
Trying to use one of the javascript addons for leaflet - specifically the heatmap functionality - https://github.com/Leaflet/Leaflet.heat
Thing is - I want to incorporate this into Shiny, but leaflet for R doesn't seem to have this addon included by default, so I would have to somehow include this JS manually. The closest I got to figuring out how to do this is through a post on rCharts that showed this:
server.R.
HeatMap$addAssets(jshead = c("http://leaflet.github.io/Leaflet.heat/dist/leaflet-heat.js"))
HeatMap$setTemplate(afterScript = sprintf("<script>
var addressPoints = %s
var heat = L.heatLayer(addressPoints).addTo(map)
</script>",
rjson::toJSON(dt)))
(taken from: https://github.com/ramnathv/rCharts/issues/498 )
But being not too familiar with JS, and new to leaflet it's still not quite clear how it can be incorporated from beginning to end - i.e. taking this JS from github and ending up with a heatmap created using leaflet on the dataset 'quakes'.
My server side code is something like the following:
library(leaflet)
output$mymap <- renderLeaflet({
leaflet() %>%
addProviderTiles("OpenMapSurfer.Roads",
options = providerTileOptions(noWrap = TRUE))
%>% addMarkers(clusterOptions = markerClusterOptions(), data = quakes))
Where instead of clusterOptions I would like to add a heatmap of the magnitude of the earthquakes (the dataset 'quakes' is included in R so you can see it for yourself).
Any help on figuring this out would be very much appreciated! :)
The setTemplate(afterscript...) bit doesn't work in shiny. Instead you need to use tags$() and render the heatmap output separately to the map.
Here is a basic app that uses heatmaps (inspired by this SO answer )
server.R
library(shiny)
library(rCharts)
dat <- data.frame(Offence = c("Assault","Assault","Assault","Weapon","Assault","Burglary"),
Date = c("2015-10-02","2015-10-03","2015-10-04","2015-04-12","2015-06-30","2015-09-04"),
Longitude = c(-122.3809, -122.3269, -122.3342, -122.2984, -122.3044, -122.2754),
Latitude = c(47.66796,47.63436,47.57665,47.71930,47.60616,47.55392),
intensity = c(10,20,30,40,50,30000))
shinyServer(function(input, output, session) {
output$baseMap <- renderMap({
baseMap <- Leaflet$new()
baseMap$setView(c(47.5982623,-122.3415519) ,12)
baseMap$tileLayer(provider="Esri.WorldStreetMap")
baseMap
})
output$heatMap <- renderUI({
## here I'm creating the JSON through 'paste0()'.
## you can also use jsonlite::toJSON or RJSONIO::toJSON
j <- paste0("[",dat[,"Latitude"], ",", dat[,"Longitude"], ",", dat[,"intensity"], "]", collapse=",")
j <- paste0("[",j,"]")
j
tags$body(tags$script(HTML(sprintf("
var addressPoints = %s
var heat = L.heatLayer(addressPoints).addTo(map)"
, j
))))
})
})
ui.R
library(shiny)
library(rCharts)
shinyUI(fluidPage(
mainPanel(
headerPanel("title"),
chartOutput("baseMap", "leaflet"),
tags$style('.leaflet {height: 500px;}'),
tags$head(tags$script(src="http://leaflet.github.io/Leaflet.heat/dist/leaflet-heat.js")),
uiOutput('heatMap')
)
))
Edit - Using Google Maps
There is also a way to do this in the development version of googleway. For this you'll need a valid Google API key, and currently it only works in a browser
## devtools::install_github("googleway")
library(googleway)
library(magrittr)
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
actionButton(inputId = "traffic", label = "traffic"),
box(width = 10,
height = 600,
google_mapOutput("myMap")
)
)
)
server <- function(input, output){
map_key <- "your_valid_api_key"
## https://developers.google.com/maps/documentation/javascript/get-api-key
## set up some data-------
pl <- "~s|dF}{~rZnNoExBq#|#SfAIjA#~Et#fBBp#Iv#QxCoArNqGfA_#dB]`KgAfVkC|Gu#rAYf#Q|#i#p#m#n#{#^u#`#kAR_ALiADuACiAIeAOy#_#qA{#uB{#sB]gAUmAOaB?oCTkKr#kZZiN?s#Cq#EQDOLILFn#A\\CpI_A|AQjB[BGPOX#LHz#CpAKT?v#KpHu#vD]LGt#Ix#I\\QBGLOVCPJd#Dj#GnFq#`PaBp#KfBQzA[zAq#nAaAx#aA~ByDp#yAXe#VSVO#EVWPCRDJLBF#Hd#TrDj#rK`ADEJGJ#JFBFrSxBJOPCNHHPdBLnCb#bBb#lAf#zA~#lAbApAzAt#nAxA|C~BhHrAxD~AtEb#|#xAtBpBlBzCbB`AZhIhBrFpA|AZl#HRDLENGXORe#DKJSf#wD`#cDt#}INq#ZuEt#mHfBsN~BkS`CmR\\eDnAiKzAcM`CePNmAhAsGXmArAgFtDsM|DaOh#sC^kCf#kDb#uDl#kI\\sHn#yM?gDEoAOsA[}BUiBUsC#qCNuBViBrCcPp#oGHW|#oPBuDI_DKqAy#wD{Ja^}#oFY_CWoDIqBGqEBsENqE`C{^JuA\\aDj#oDn#cDxAcFz#yBtC{Fp#eAn#_An#s#t#}#j#g#bCaBtCsA`GiAzBm#`C}#jBmA~CiC~DcDjCwAfAa#bBe#nBa#pCYlCArDBlCHhCGnC_#~A]vBk#hAa#lF_CnMaGbDeArD}#vB[zEe#jFS`GFfBFxBJzO\\zZfAfCJdEPbDNvDRnEHvD?tEE~BQhC[zAYnCu#bA]dBm#bIkDtBy#bAYhB[rDYxJ[nB#vAHfBLbCf#|C~#vAp#nCdB|A`A`CzApAr#|Al#rBl#bBZbUbCZBzBDvBEtAMnF_AvB[vBOlCAlBFnBXbDr#~Bv#z#`#bBfAdD~BtB`Bv#f#nAn#x#ZZJ~A\\dBTdADtBEbAGnEg#dFi#`DYdDQdF?|DNfCV`BTlCl#dNvD`HnBdLvClAZn#DzB^hCRd#?fA?|#Ih#O`#Ud#a#h#w#\\u#Pm#Lw#HoBq#qK]eLUcIE{DC{AD}Fn#eSLeCJs#RwFRkDf#sCj#aE`AsFhAuGh#gDt#wEp#}En#_FPeBRkDByBCgBEgAS}B{#oEsA}Dy#eCi#yBGq#?s#Ds#V}#Rg#r#u#ZOj#Ml#Az#PrA^fBb#j#HV#f#e#`B}AbB_B]Ie#KeASiO}CmH_B{L}Bk#QTqBTgCAm#g#kCSaAs#V{CdAmDrAuAh#{#Ra#H{#D{Af#wBt#gAb#]ReBl#"
df_line <- decode_pl(pl)
set.seed(123)
df_line$weight <- runif(nrow(df_line), min = 1, max = 100)
## ------------
## plot the map
output$myMap <- renderGoogle_map({
google_map(key = map_key, data = df_line, search_box = F) %>%
add_heatmap(weight = "weight") %>%
add_traffic()
})
}
shinyApp(ui, server)
Consider the plot, pulled from the rCharts/NVD3 examples page
p6 <- nPlot(uempmed ~ date, data = economics, type = 'lineChart')
p6
I tried to get my y-axis to display percentages, so I tried the following code (following R: interactive plots (tooltips): rCharts dimple plot: formatting axis) but it returns a blank page
p6 <- nPlot(uempmed ~ date, data = economics, type = 'lineChart')
p6$yAxis(outputFormat = "%")
p6
I did some research and got the following to work:
p6 <- nPlot(uempmed ~ date, data = economics, type = 'lineChart')
p6$yAxis(tickFormat = "#! function(d) {return d*100 + '%' } !#")
p6
Now, I know about 0 javascript and want to stay in R as much as possible, at least in the short term. Could someone let me know
Why the first approach doesn't work, and
Whether the second approach is the best way to go about it
Since the answer to 1 is in the comment by #jdharrison, I thought I would quickly answer #2 with a complete code sample with comments demonstrating the different ways to achieve the same thing.
#turn off rstudio viewer
#since we will be making lots of charts
#we'll turn it back on at end
oldviewer = options("viewer")
options(viewer=NULL)
data(economics, package = "ggplot2")
#if we know we would like percent
#and R is our friend but javascript is not
#we could do some transformation in R
economics$uempmed <- economics$uempmed/100
p6 <- nPlot(uempmed ~ date, data = economics, type = 'lineChart')
p6
#then we could use d3.format just like the dimple example
#except dimple assumes the d3.format part so we just need "%"
#see https://github.com/PMSI-AlignAlytics/dimple/wiki/dimple.axis#tickFormat
#for more on d3.format
#see https://github.com/mbostock/d3/wiki/Formatting#d3_format
p6$yAxis( tickFormat = "#!d3.format('%')!#" )
p6
#however your method works fine also
p6$yAxis(tickFormat = "#! function(d) {return d*100 + '%' } !#")
p6
#but let's say we did not do the above transform
#dividing by 100
#here is how we could do it in javascript
data(economics, package = "ggplot2")
p6 <- nPlot(uempmed ~ date, data = economics, type = 'lineChart')
p6$yAxis(tickFormat = "#! function(d) {
//will change to .2% to show how to get two decimal
return d3.format('.2%')(d/100)
} !#")
p6
#turn rstudio viewer back on
options(viewer = oldviewer)