dribnet / strokes

Let's pretend d3 was written in ClojureScript.
374 stars 28 forks source link

Selection.data(function(d){...}) Not working #8

Closed beandipper closed 11 years ago

beandipper commented 11 years ago

using the usual seems to work fine

(-> selection (.data mydata (fn [d] d)))

but if passing only a function to the (.data) call, the parameter seems to not properly be recognized

(-> selection (.data (fn [d] d)))

For an example try to implement this table

function tabulate(data, columns) {
    var table = d3.select("body").append("table")
            .attr("style", "margin-left: 250px"),
        thead = table.append("thead"),
        tbody = table.append("tbody");

    // append the header row
    thead.append("tr")
        .selectAll("th")
        .data(columns)
        .enter()
        .append("th")
            .text(function(column) { return column; });

    // create a row for each object in the data
    var rows = tbody.selectAll("tr")
        .data(data)
        .enter()
        .append("tr");

    // create a cell in each row for each column
    var cells = rows.selectAll("td")
        .data(function(row) {
            return columns.map(function(column) {
                return {column: column, value: row[column]};
            });
        })
        .enter()
        .append("td")
        .attr("style", "font-family: Courier")
            .html(function(d) { return d.value; });

    return table;
}
dribnet commented 11 years ago

Thanks for the bug report. Are you sure on this one? My straight port of your first version worked fine for me:

(ns testmatrix
  (:require [strokes :refer [d3]]))

(strokes/bootstrap)

(def matrix [
  [11975  5871 8916 2868]
  [ 1951 10048 2060 6171]
  [ 8010 16145 8090 8045]
  [ 1013   990  940 6907]
])

(def tr (-> d3 (.select "body") 
  (.append "table")
  (.selectAll "tr")
  (.data matrix)
  (.enter)
  (.append "tr")))

(def td (-> tr 
  (.selectAll "td")
  (.data (fn [d] d))
  (.enter)
  (.append "td")
  (.text (fn [d] d))))

I can try the more complicated one and throw this up on a gist - can you provide me sample tabulate() parameters for data and columns? Also note that (.data identity) is slightly more idiomatic than (.data (fn [d] d)), but both work.

(for reference, the original js snippet equivalent to the cljs above is...)

var matrix = [
  [11975,  5871, 8916, 2868],
  [ 1951, 10048, 2060, 6171],
  [ 8010, 16145, 8090, 8045],
  [ 1013,   990,  940, 6907]
];

var tr = d3.select("body").append("table").selectAll("tr")
    .data(matrix)
  .enter().append("tr");

var td = tr.selectAll("td")
    .data(function(d) { return d; })
  .enter().append("td")
    .text(function(d) { return d; });
beandipper commented 11 years ago

It could be that it occurs when using a map instead of a 2D array for the data. Maybe something to do with the nested anonymous functions in conjunction with (.map ...) ? Here are the examples of the input parameters

var data = [
    {name: "Jill", age: 30},
    {name: "Bob", age: 32},
    {name: "George", age: 29},
    {name: "Sally", age: 31}
];

var columns =  ["name", "age"];

tabulate(data,columns);

And here is a jsFiddle with the example I was trying to implement for the whole implementation

dribnet commented 11 years ago

My version below seems to be working, so closing for now. But please let me know if this is still a problem for you and will reopen if need be. Also a live version posted on s.trokes.org.

(ns testmatrix
  (:require [strokes :refer [d3]]))

(strokes/bootstrap)

(defn tablulate [data]
  (let [columns (vec (keys (first data)))
        table (-> d3 (.select "body") (.append "table"))
        thead (-> table (.append "thead"))
        tbody (-> table (.append "tbody"))]

    (-> thead (.append "tr")
      (.selectAll "th")
      (.data columns)
      (.enter)
      (.append "th")
      (.text name))

    (-> tbody (.selectAll "tr")
      (.data data)
      (.enter)
      (.append "tr")
      (.selectAll "td")
      (.data (fn [row]
        (map (fn [c] {:column c :value (get row c)}) columns)))
      (.enter)
      (.append "td")
      (.html #(:value %)))

    table))

(tablulate [
  {:name "Jill"   :age 30}
  {:name "Bob"    :age 32}
  {:name "George" :age 29}
  {:name "Sally"  :age 31}
])