ramnathv / rCharts

Interactive JS Charts from R
http://rcharts.io
Other
1.19k stars 654 forks source link

replicate examples given by js libraries #35

Open timelyportfolio opened 11 years ago

timelyportfolio commented 11 years ago

Another good test would be to replicate the examples provided in the libraries. I started on polycharts.

polychart.js examples in rCharts

Dow Jones (Simple Line)

require(quantmod)
require(reshape2)
require(rCharts)

DJIA <- na.omit(getSymbols("DJIA",src='FRED',auto.assign=FALSE)["2012-12-04::2013-03-10"])

xtsMelt <- function(xtsData,metric,names=NULL){
  df <- data.frame(index(xtsData),coredata(xtsData),stringsAsFactors=FALSE)
  df.melt <- melt(df,id.vars=1)
  df.melt <- data.frame(df.melt,rep(metric,NROW(df.melt)))
  #little unnecessary housekeeping
  df.melt <- df.melt[,c(1,2,4,3)]
  if(is.null(names)) {
    colnames(df.melt) <- c("date","indexname","metric","value")
  } else {colnames(df.melt) <- names}
  df.melt[,1]<- as.Date(df.melt[,1])
  return(df.melt)
}

DJIA.melt <- xtsMelt(DJIA,"price",names=c("Date","Index","Metric","Close"))
DJIA.melt[,1] <- format(DJIA.melt[,1],"%m/%d/%Y")

p1 <- rPlot(Close ~ Date, data = DJIA.melt,
            type="line",
            size=list(const=3))
p1$guides(x=list(numticks=10),y=list(min=12000,max=15000)) 
p1$set(title = "Dow Jones Daily Closing Value")
p1$show(F)

Dow Jones (Auto Updating)

Browser Shares (Multiple Lines)

browsershare <- read.csv("http://gs.statcounter.com/chart.php?statType_hidden=browser&region_hidden=ww&granularity=monthly&statType=Browser&region=Worldwide&fromMonthYear=2008-07&toMonthYear=2013-03&csv=1")
browsershare.melt <- melt(browsershare,id.vars=1)
colnames(browsershare.melt)[c(2,3)] <- c("Browser","Share")
p3 <- rPlot(Share ~ Date, color = "Browser",
            data=browsershare.melt,
            size=list(const=3),
            type="line")
p3$set(title="Browser Shares Over Time")
p3$show()

Operating Systems Shares Area

osshare <- read.csv("http://gs.statcounter.com/chart.php?statType_hidden=os&region_hidden=ww&granularity=monthly&statType=Operating%20System&region=Worldwide&fromMonthYear=2008-07&toMonthYear=2013-03&csv=1",stringsAsFactors=FALSE)
#if we wanted to sort by last value
#osshare <- osshare[,c(1,order(last(osshare[,-1]),decreasing=TRUE)+1)]
#osshare.melt <- read.csv("http://www.polychartjs.com/s/data/OSStatistics.csv")
osshare.melt <- reshape2::melt(osshare,id.vars=1)
colnames(osshare.melt)[c(2,3)] <- c("OS","Share")

p4 <- rPlot(y="Share",x="Date", color = "OS",  #could do Share ~ Date
            data=osshare.melt,
            size=list(const=3),
            opacity=list(const=0.7),
            type="area",
            height=500)
#demonstrate how we can change axis and legend titles
p4$guides(color=list(numticks=10,title="Oper System"),y=list(title="Market Share"))
p4$set(title="OS Market Shares Over Time")
p4$show()

Iris Flower Scatter Plot

data(iris)
colnames(iris) <- sapply(colnames(iris), FUN=gsub, pattern="\\.", replacement="")
p5 <- rPlot(SepalWidth ~ SepalLength, data = iris, color = "Species", type="point", height=400)
#again match polychartjs example exactly to show how we can change axis and legend titles
p5$guides(color=list(title="Category"),y=list(title="sepalWidth"),x=list(title="sepalLength"))
p5$set(title="Iris Flowers")
p5$html()
p5$show()

Bubble Chart (Animated)

LOTR Box Office Gross

jsondata = data.frame(
    c("The Fellowship of the Ring","The Two Towers","The Return of the King","The Hobbit"),
    c(871530000, 926047000, 1119929000, 949541000)
)
colnames(jsondata) <- c("movie","gross")
p7 <- rPlot(gross ~ movie, data = jsondata, type = "bar", color=list(const="darkgreen"))
p7$set(title = "Lord of the Rings Box Office Gross")
p7$html()
p7$show()

Histogram of Heights (Histogram)

names = c('Joe', 'Jay', 'Jen', 'Jane', 'John', 'Jone', 'Jake', 'Jule', 'Jack')
height = c(1.62, 1.63, 1.71, 1.66, 1.79, 1.58, 1.55, 1.62, 1.72) #actually error in example, 1.63)
data = data.frame(names,height)
p8 <- rPlot(x="bin(height,0.05)", y="count(names)", data=data, type="bar")
p8$guides(x=list(title="Height in Meters"), y=list(title="Density"))
p8$set(title = "Histogram of Heights")
p8$html()
p8$show()

Highest Paid Athletes (Flipped)

jsondata = data.frame(rbind(
    c('Floyd Mayweather', 85000000, 'Boxing'), 
    c('Manny Pacquaio', 62000000, 'Boxing'), 
    c('Tiger Woods', 59400000, 'Golf'), 
    c('LeBron James', 53000000, 'Basketball'), 
    c('Roger Federer', 52700000, 'Tennis'), 
    c('Kopaye Bryant', 52300000, 'Basketball'), 
    c('Phil Mickelson', 47800000, 'Golf'), 
    c('David Beckham', 46000000, 'Soccer'), 
    c('Cristiano Ronaldo', 42500000, 'Soccer'), 
    c('Peyton Manning', 42400000, 'Football'))
)
colnames(jsondata) <- c("name","pay","sport")
p9 <- rPlot(x = list(var="name", sort="pay"), y = "pay", data = jsondata, color = "sport",type = "bar" )
p9$guides(y = list(title = "Athlete Pay (in $)"), x = list(title = "Name of Athlete", numticks = 10), color = list(title = "Type of Sport"))
p9$coord(type = "cartesian", flip = "true")
p9$set(title= "Top 10 Highest Paid Athletes 2012")
p9$html()
cat(p9$render())
p9$show()

Sales Funnel (Stacking)

data = data.frame(list(
    segment=c(
        "FirstTime", "FirstTime", "FirstTime", "Return", "Return", "Return",
        "Sale", "Sale", "Sale"
    ),
    source= c(
        "Referral", "LinkedIn", "Cold Call","Referral", "LinkedIn", "Cold Call",
        "Referral", "LinkedIn", "Cold Call"
    ),
    value= c(10,15,20,5,10,18,3,5,8)
))

p10 <- rPlot(x = list(var = "segment", sort = "sum(value)", desc = "true"),
             y = "value",
             data = data,
             color = "source",
             type = "bar",
             height = 200,
             width = 720)
p10$guides(x = list(renderLine = "false", renderTick = "false", renderLabel = "true", renderGrid = "false"),
           y = list(position = "none"))
p10$coord(type = "cartesian", flip = "true")
p10$set(title = "Sales Funnel")
p10$show()

Department Salaries (Dodging)

data = list(
    names = c('Joe', 'Jay', 'Jessica', 'Mayfield', 'Candice', 'Alice'),
    department = c('Sales', 'Sales', 'IT', 'IT', 'HR', 'HR'),
    salary = c(100000, 98000, 110000, 50000, 55000, 80000)
  )
p11 <- rPlot(salary ~ department, color = 'names', data = data, type = "bar", position = "dodge")
p11$set(title = "Department Salaries")
p11$show()

Favourite Pets (Simple)

data = list(
    name=c('Lisa', 'Samson', 'Fravic', 'Zach', 'Raymond', 'Tim'),
    pet=c('cat', 'dog', 'cat', 'cat', 'dog', 'none')
)
p12 <- rPlot(y = "count(name)", x="pet", color="pet", data = data, type = "bar")
p12$coord(type="polar")
p12$guides(x = list(position = "none", padding = 0), y = list(position = "none"))
p12$show()

Favourite Pets (Animating)

p13

Volunteer Requirements (Facet)

data=data.frame(
        c( "Grade 9",  10,  'Yes'),
        c( "Grade 9",  90,  'No'),
        c( "Grade 10",  40,  'Yes'),
        c( "Grade 10",  60,  'No'),
        c( "Grade 11",  70,  'Yes'),
        c( "Grade 11",  30,  'No'),
        c( "Grade 12",  90,  'Yes'),
        c( "Grade 12",  10,  'No')
)
colnames(data) <- c("grade","percent","completed")

p14 <- rPlot(width = 720, height = 230,
             y = "percent", color = "completed", data = data)
p14$guides(x=list(position="none", padding=0),
           y=list(position="none"),
           color(scale = 'function(value) {return value === 'Yes' ? "#62bf9c" : "#DDD"'))
p14$coord(type="polar")
p14$facet(type="wrap", var=list(grade), cols=4, formatter='function(index){return index.grade}')
p14$set(title = "Percent of Students Completing Volunteer Requirement")
p14$show()

Boxplot

## Use InsectSprays Data since Polychart Example is Fake Data
data(InsectSprays)
#boxplot(count~spray, data=InsectSprays, col="lightgray")
p15 <- rPlot(width=720,
             x = "spray",
             y = "box(count)",
             data = InsectSprays,
             type = "box")
p15$guides(x=list(min=0, max=110))
p15

Iris Flower Tile Plot (Tile, Binning)

data(iris)
colnames(iris) <- sapply(colnames(iris), FUN=gsub, pattern="\\.", replacement="")
p16 <- rPlot(height = 400,
             width = 720,
             x = "bin(SepalLength, 1)",
             y = "bin(SepalWidth, 0.5)",
             color = "mean(PetalWidth)",
             data = iris,
             type = "tile")
p16$guides(color = list(scale = list(type="gradient", lower = "#EEE", upper = "#a23")))
p16$facet(type="wrap",var="Species" ) #,formatter='function(object) { return object.category }')
p16$set(title = "Iris Flowers")
p16

Population (Interactive)

If we can create this one, we know we can do almost anything

p17

Iris Flower Facetted Plot

data(iris)
colnames(iris) <- sapply(colnames(iris), FUN=gsub, pattern="\\.", replacement="")
p18 <- rPlot(width = 720,
             height = 300,
             x = "SepalLength",
             y = "SepalWidth",
             color = "Species",
             data = iris,
             type = "point")
p18$facet(type = "wrap", var = "Species")
p18$set(title = "Iris Flowers")
p18
ramnathv commented 11 years ago

I like your idea and thanks for taking the initiative. However, I would prefer to use datasets built into R (preferably base R), so that users dont get distracted by the data preparation steps. I want users to be able to take a data frame and plot it as they would, using lattice or ggplot2.

I just pushed a new version to github that includes a create_chart function that takes a .R file with an example, and converts it into an example page with the source code (simple layout). I would like you to try it and let me know how it works. Here is how it works. Assume, you save the following code to example_lotr.R

jsondata = data.frame(
    c("The Fellowship of the Ring","The Two Towers","The Return of the King","The Hobbit"),
    c(871530000, 926047000, 1119929000, 949541000)
)
colnames(jsondata) <- c("movie","gross")
p6 <- rPlot(gross ~ movie, data = jsondata, type = "bar", color=list(const="darkgreen"))
p6$set(title = "Lord of the Rings Box Office Gross")
p6

You can generate an example page using the code below. Note that just typing mychart automatically calls the show method, the default for which has not been changed to static = T.

mychart = create_chart('example_lotr.R')
mychart

Publishing your chart now is even simpler. Just do

mychart$publish('LOTR Box Office Gross')

rCharts will automatically switch to serving all assets from the CDN so that it works online. Right now the title does not show up, but it is only a matter of tweaking the layout to get it right. You can check the layouts out in inst/rChart.html and inst/rChart2.html.

Let me know how it works for you, and any feedback you have.

timelyportfolio commented 11 years ago

Great, I will experiment with the new functionality. It should be very helpful for automatically publishing examples. I am excited.

polycharts examples

Since I was already so deep in replicating the polycharts demo examples, I went ahead and completed for all of them with the exception of the interactive and pies ( did but don't work due to #3 ) and updated the issue above. Unfortunately, I think users will at some point almost always be confronted with translating r to js data. I wish I had a fairly complete and robust set of examples that I could learn from when I started this quest. These present a small set. Thanks for all that you have done to hide the difficult translation.

I am most interested in recreating the ggplot2 and lattice examples as we discussed in #31 . For R users, I think this would be incredibly beneficial, and for you, I think the tests will be very instructive.

ramnathv commented 11 years ago

Wow. That is terrific. Here is what I would recommend that you do. Maintain each example you create in a standalone R file. Make sure that it is truly standalone, in the sense that a user should be able to open a fresh R session and just source the file to view the chart.

Once I finalize the layouts, it should be easy to run create_chart to convert them into full fledged example pages. I plan to add disqus comments as well as social sharing snippets. I might go a little slow on this, because I want to nail the layout right before showing it to users.

Thanks again for all your hard work.

timelyportfolio commented 11 years ago

I will do as suggested with the standalone examples and follow the same process going forward.

now, I really want to focus on NVD3 and Rickshaw, since the license is more open. polycharts grammar is just irresistible given my love of lattice.

ramnathv commented 11 years ago

Great. I have some NVD3 examples too, which I will add to the mix in a bit. Rickshaw implementation is not complete. Moreover, legends and axes are more complicated in Rickshaw since it treats everything as a separate entity. MorrisJS on the other hand is really simple, and the spec structure is not nested, which means that any spec on their API page, can be set using the addParams or set method! MorrisJS code is also super clean, written in coffeescript and hence actually extensible.

Did you try create_chart and the publish method? Let me know. I might refactor these methods outside of rCharts so that more packages can use it (e.g. clickme).

ramnathv commented 11 years ago

This discussion on shiny google-groups seems very relevant. I think I am going to accelerate the sharing of examples.

I think focusing on Polychart and NVD3 would be a prudent choice, since these two libraries seem to have the best interactive capabilities. I can ask Thomas to focus on more examples with Highchart.

timelyportfolio commented 11 years ago

Just got of a lunch meeting and starting to experiment again.

I have started two new issues

  1. create_chart and $show(T) error #38
  2. discussion of rCharts and clickme integration #39
timelyportfolio commented 11 years ago

@ramnathv I hope this is close to what you expected https://github.com/timelyportfolio/rCharts_polycharts_standalone/.

ramnathv commented 11 years ago

I glanced through it and it looks good. I will go over in more detail and add my comments.

Meanwhile, I just cooked up a runExample function similar to runGitHub in Shiny. It seems to work fine for me. Can you test it? If it works well, I can roll it back into rCharts, so that instructions on your README.md can be simpler.

runExample <- function(repo, username, filename, ref = 'master'){
  require(downloader)
  tf <- tempfile(pattern = '*.R')
  url <- sprintf('https://raw.github.com/%s/%s/%s/%s',
    username, repo, ref, filename)
  download(url, tf)
  mychart = rCharts::create_chart(tf)
  return(mychart)
}

runExample(
  username = 'timelyportfolio', 
  repo     = 'rCharts_polycharts_standalone', 
  filename = 'area_osshare.R'
)
timelyportfolio commented 11 years ago

Just shut down my computer before I saw this. Code looks like it will work. I will test in the morning.

Kent

On Apr 23, 2013, at 9:23 PM, Ramnath Vaidyanathan notifications@github.com wrote:

I glanced through it and it looks good. I will go over in more detail and add my comments.

Meanwhile, I just cooked up a runExample function similar to runGitHub in Shiny. It seems to work fine for me. Can you test it? If it works well, I can roll it back into rCharts, so that instructions on your README.md can be simpler.

runExample <- function(repo, username, filename, ref = 'master'){ require(downloader) tf <- tempfile(pattern = '*.R') url <- sprintf('https://raw.github.com/%s/%s/%s/%s', username, repo, ref, filename) download(url, tf) mychart = rCharts::create_chart(tf) return(mychart) }

runExample( username = 'timelyportfolio', repo = 'rCharts_polycharts_standalone', filename = 'area_osshare.R' ) — Reply to this email directly or view it on GitHub.

timelyportfolio commented 11 years ago

on my windows 7, I needed

tf <- tempfile(pattern = '.R')

instead of *.R

ramnathv commented 11 years ago

Great. I will make the change. But it works if you make that change right?

timelyportfolio commented 11 years ago

Yes it works with that change.

Kent

On Apr 24, 2013, at 10:55 AM, Ramnath Vaidyanathan notifications@github.com wrote:

Great. I will make the change. But it works if you make that change right?

— Reply to this email directly or view it on GitHub.

timelyportfolio commented 11 years ago

I reformatted the repo using formatR.

ramnathv commented 11 years ago

I coded up a quick set of functions to create a gallery from a directory containing example files. It is still preliminary, but it would be nice if you could test it. Update your version of rCharts and source the functions below into your workspace and run make_example_pages(".", cdn = T) from your example directory. The resulting pages should look like this. I plan to make a few enhancements to the page, which requires the example files to include custom metadata as comment. I will post more on this. Finally, I want to integrate social sharing buttons as well as disqus comments so that users can initiate a discussion.

Screen Shot 2013-04-24 at 2 34 36 PM

make_example_pages <- function(exDir, htmlDir = 'gallery'){
  rFiles = dir(exDir, pattern = ".R")
  sidebar = get_sidebar(exDir)
  if (!file.exists(htmlDir)) dir.create(htmlDir)
  invisible(lapply(rFiles, make_example_page, sidebar, htmlDir))
}

get_sidebar <- function(exDir){
  rFiles = dir(exDir, pattern = "*.R")
  menu = lapply(rFiles, function(rFile){
    filename = tools:::file_path_sans_ext(basename(rFile))
    c(title = filename, href = sprintf("%s.html", filename))
  })
  list(menu = menu)
}

make_example_page <- function(rFile, sidebar, htmlDir){
  myexample = rCharts::create_chart(rFile)
  filename = tools:::file_path_sans_ext(basename(rFile))

  active = which(lapply(sidebar$menu, '[[', 'title') == filename)
  sidebar$menu[[active]] = c(sidebar$menu[[active]], class = 'active')
  myexample$field('tObj', sidebar)

  htmlFile = sprintf('%s/%s.html', htmlDir, filename)
  myexample$save(destfile = htmlFile, cdn = T)
}
timelyportfolio commented 11 years ago

more I play with the others, the more I realize how nice polycharts is. of course, it is the only one with a paid license and the least interactivity.

ramnathv commented 11 years ago

Yes. But it is not terribly expensive, as you can see here http://polychart.com/js/license. The developers have obviously put in a lot of thought, and Polycharts is probably the closes to delivering the reusable chart experience. NVD3 is slick, but the documentation is non-existent and the only way to figure things out is to dig into the source code.

I am close to implementing faceting in NVD3. So, once that happens, I believe we can replicate some of Polychart's functionality in NVD3.

timelyportfolio commented 11 years ago

I have no problems with the price, but I know some won't use it even if it is only $1. Think I'll have a go at Morris now.

timelyportfolio commented 11 years ago

just realized I never tried your functions above. I just ran on all the lattice conversions. Works great http://timelyportfolio.github.io/rCharts_lattice_book/polycharts_versions/gallery/figure1_01.html.

  1. Might be nice to add a scroll on the sidebar but not necessary.
  2. Also, data gets pretty massive since there is no reuse. Not sure if possible to fix though except if data comes from file rather than embedded in html.

You can also see in the repo where I grab the lattice code from the site. Unfortunately, it is not as well structured as it first seemed.

ramnathv commented 11 years ago

I took a quick look and it seems great. The sidebar could use some tweaking. I am thinking a collapsible sidebar by chapter

timelyportfolio commented 11 years ago

What would also be very nice is to add the ability to specify a .rmd or .md as a parameter to add to the beginning.