class BubbleChart constructor: (data) -> @data = data @width = 960 @height = 600 @tooltip = MyTooltip("my_tooltip", 190) @center = {x: @width / 2, y: @height / 2} @phase_centers = { "II" : {x : 3 * @width / 8, y : 7 * @height / 16}, "III" : {x : @width / 2, y : 7 * @height / 16}, "PostMkg" : {x : 5 * @width / 8, y : 7 * @height / 16} } @yearcat_centers = { "(1985,2005]" : {x : 3 * @width / 8, y : @height / 2}, "(2005,2010]" : {x : @width / 2, y : @height / 2}, "(2010,2014]" : {x : 5 * @width / 8, y : @height / 2} } @cmpd_centers = { "GA" : {x: 9 * @width / 40, y: 24 * @height / 80}, "IFNβ-1b" : {x : 2 * @width / 5, y: 12 * @height / 40}, "IFNβ-1a" : {x : 3 * @width / 5, y: 12 * @height / 40}, "Fingolimod" : {x : 31 * @width / 40, y: 12 * @height / 40}, "Laquinimod" : {x: 9 * @width / 40, y: 17 * @height / 40}, "BG-12" : {x : 2 * @width / 5, y: 17 * @height / 40}, "Teriflunomide" : {x : 3 * @width / 5, y: 35 * @height / 80}, "Natalizumab" : {x : 31 * @width / 40, y: 69 * @height / 160}, "Alemtuzumab" : {x: 17 * @width / 80, y: 23 * @height / 40}, "Daclizumab" : {x : 2 * @width / 5, y: 45 * @height / 80}, "Rituximab" : {x : 3 * @width / 5, y: 46 * @height / 80}, "Mitoxantrone" : {x : 31 * @width / 40, y: 24 * @height / 40}, "IVIg" : {x: 15 * @width / 80, y: 114 * @height / 160}, "IFNA-2a" : {x : 2 * @width / 5, y: 28 * @height / 40}, "MMF" : {x : 3 * @width / 5, y: 28 * @height / 40}, "Other" : {x : 31 * @width / 40, y: 29 * @height / 40} } @funding_centers = { "Teva" : {x : @width / 5, y : 13 * @height / 40}, "BiogenIdec" : {x : 2 * @width / 5, y : 53 * @height / 160}, "EMDSerono" : {x : 3 * @width / 5, y : 13 * @height / 40}, "Novartis" : {x : 4 * @width / 5, y : 13 * @height / 40}, "BayerSchering" : {x : @width / 5, y : 3 * @height / 5}, "GenzymeSanofi" : {x : 2 * @width / 5, y : 3 * @height / 5}, "Roche" : {x : 3 * @width / 5, y : 3 * @height / 5}, "Other" : {x : 4 * @width / 5, y : 25 * @height / 40} } @pop_centers = { "CIS" : {x : 3 * @width / 10, y : @height / 2}, "RRMS" : {x : 9 * @width / 20, y : @height / 2}, "SPMS" : {x : 6 * @width / 10, y : @height / 2}, "PPMS" : {x : 7 * @width / 10, y : @height / 2} } @nbdoz_centers = { "1" : {x : 7 * @width / 24, y : @height / 2}, "2" : {x : 10 * @width / 24, y : @height / 2}, "3" : {x : 13 * @width / 24, y : @height / 2}, "4" : {x : 15 * @width / 24, y : @height / 2}, "5" : {x : 17 * @width / 24, y : @height / 2} } @layout_gravity = -0.01 @damper = 0.1 @vis = null @nodes = [] @force = null @circles = null @fill_color = d3.scale.ordinal() .domain(["Positive", "Negative", "No conclusion", "Ongoing", "Equivalence"]) .range(["#5e93bc", "#ca8546", "#D9D9D9", "#D9D9D9", "#D9D9D9"]) max_amount = d3.max(@data, (d) -> parseInt(d.N)) @radius_scale = d3.scale.pow().exponent(0.5).domain([0, max_amount]).range([2, 45]) this.create_nodes() this.create_vis() create_nodes: () => @data.forEach (d) => node = { id: d.Src radius: @radius_scale(parseInt(d.N)) value: d.N name: d.Name cmpd: d.Cmpd outcome: d.Outcome phase: d.Phase yearcat: d.YearCat pop: d.Pop funding: d.Funding tdur: d.Tdur cmpddetails: d.CmpdDetails funddetails: d.FundDetails nbdoz: d.NbDoz year: d.Year x: Math.random() * 900 y: Math.random() * 800 } @nodes.push node @nodes.sort (a,b) -> b.value - a.value create_vis: () => @vis = d3.select("#vis") .append("svg") .attr("width", @width) .attr("height", @height) .attr("id", "svg_vis") @circles = @vis.selectAll("circle") .data(@nodes, (d) -> d.Src) that = this @circles.enter().append("circle") .attr("r", 0) .attr("fill", (d) => @fill_color(d.outcome)) .attr("stroke-width", 2) .attr("stroke", (d) => d3.rgb(@fill_color(d.outcome)).darker()) .attr("id", (d) -> "bubble_#{d.src}") .on("mouseover", (d,i) -> that.show_details(d,i,this)) .on("mouseout", (d,i) -> that.hide_details(d,i,this)) @circles.transition().duration(2000).attr("r", (d) -> d.radius) charge: (d) -> -Math.pow(d.radius, 2.0) / 8 start: () => @force = d3.layout.force() .nodes(@nodes) .size([@width, @height]) display_outcome_all: () => @force.gravity(@layout_gravity) .charge(this.charge) .friction(0.9) .on "tick", (e) => @circles.each(this.move_towards_center(e.alpha)) .attr("cx", (d) -> d.x) .attr("cy", (d) -> d.y) @force.start() this.display_outcomes() this.display_outcomest() this.hide_phases() this.hide_yearcats() this.hide_cmpds() this.hide_cmpdst() this.hide_fundings() this.hide_pops() this.hide_nbdozs() this.hide_phasest() this.hide_yearcatst() this.hide_fundingst() this.hide_popst() this.hide_nbdozst() move_towards_center: (alpha) => (d) => d.x = d.x + (@center.x - d.x) * (@damper + 0.02) * alpha d.y = d.y + (@center.y - d.y) * (@damper + 0.02) * alpha display_outcomes: () => outcomes_x = {"Positive": @width / 2, "Negative": @width / 2, "No conclusion": @width / 2, "Equivalent": @width / 2, "Ongoing": @width / 2 } outcomes_y = {"Positive": @height / 2, "Negative": @height / 2, "No conclusion" : @height / 2, "Equivalent": @height / 2, "Ongoing": @height / 2 } outcomes_data = d3.keys(outcomes_x, outcomes_y) outcomes = @vis.selectAll(".outcomes") .data(outcomes_data) outcomes.enter() .append("circle") .attr("class", "outcomes") .attr("r", 10) .attr("cx", 50) .attr("cy", 475) .attr("fill", "#5e93bc") outcomes.enter() .append("circle") .attr("class", "outcomes") .attr("r", 10) .attr("cx", 50) .attr("cy", 525) .attr("fill", "#D9D9D9") outcomes.enter() .append("circle") .attr("class", "outcomes") .attr("r", 10) .attr("cx", 50) .attr("cy", 500) .attr("fill", "#ca8546") display_outcomest: () => outcomest_x = {@width} outcomest_y = {@height} outcomest_data = d3.keys(outcomest_x, outcomest_y) outcomest = @vis.selectAll(".outcomest") .data(outcomest_data) outcomest.enter() .append("text") .attr("class", "outcomest") .attr("id", "tout") .attr("y", 505) .attr("x", 75) .text( "Negative Outcome") outcomest.enter() .append("text") .attr("class", "outcomest") .attr("id", "tout") .attr("y", 530) .attr("x", 75) .text( "No conclusion, Ongoing, Equivalent") outcomest.enter() .append("text") .attr("class", "outcomest") .attr("id", "tout") .attr("y", 480) .attr("x", 75) .text( "Positive Outcome") outcomest.enter() .append("text") .attr("class", "outcomest") .attr("id", "tout") .attr("y", 60) .attr("x", 50) .text("106 clinical trials in MS including 44606 patients") hide_outcomest: () => outcomest = @vis.selectAll(".outcomest").remove() hide_outcomes: () => outcomes = @vis.selectAll(".outcomes").remove() display_by_phase: () => @force.gravity(@layout_gravity) .charge(this.charge) .friction(0.9) .on "tick", (e) => @circles.each(this.move_towards_phase(e.alpha)) .attr("cx", (d) -> d.x) .attr("cy", (d) -> d.y) @force.start() this.display_phases() this.display_phasest() this.hide_yearcats() this.hide_cmpds() this.hide_fundings() this.hide_pops() this.hide_outcomes() this.hide_cmpdst() this.hide_nbdozs() this.hide_outcomest() this.hide_yearcatst() this.hide_fundingst() this.hide_popst() this.hide_nbdozst() move_towards_phase: (alpha) => (d) => target = @phase_centers[d.phase] d.x = d.x + (target.x - d.x) * (@damper + 0.02) * alpha * 1.1 d.y = d.y + (target.y - d.y) * (@damper + 0.02) * alpha * 1.1 display_phases: () => phases_x = {"II": 8 * @width / 32, "(N=8612, 58 trials)": 8 * @width / 32, "III": @width / 2, "(N=26067, 32 trials)": @width / 2, "PostMkg": 24 * @width / 32, "(N=9927, 16 trials)": 24 * @width / 32 } phases_y = {"II": 2 * @height / 32, "(N=8612, 58 trials)": 3 * @height / 32, "III": 2 * @height / 32, "(N=26067, 32 trials)": 3 * @height / 32, "PostMkg" : 2 * @height / 32, "(N=9927, 16 trials)": 3 * @height / 32 } phases_data = d3.keys(phases_x, phases_y) phases = @vis.selectAll(".phases") .data(phases_data) phases.enter().append("text") .attr("class", "phases") .attr("x", (d) => phases_x[d] ) .attr("y", (d) => phases_y[d] ) .attr("text-anchor", "middle") .text((d) -> d) display_phasest: () => phasest_x = {@width} phasest_y = {@height} phasest_data = d3.keys(phasest_x, phasest_y) phasest = @vis.selectAll(".phasest") .data(phasest_data) phasest.enter() .append("text") .attr("class", "phasest") .attr("id", "tpha") .attr("y", 560) .attr("x", 0) .text( "As expected, the number of reported trials in Phase II (n=58) is larger than the one in Phase III (n=32), and their sample size is smaller.") phasest.enter() .append("text") .attr("class", "phasest") .attr("id", "tpha") .attr("y", 578) .attr("x", 0) .text( "The proportion of Phase II trials with negative outcome, 22%, is probably underestimated due to the 'publication bias'.") phasest.enter() .append("text") .attr("class", "phasest") .attr("id", "tout") .attr("y", 520) .attr("x", 65) .text( "Positive Outcome") phasest.enter() .append("circle") .attr("class", "phasest") .attr("r", 10) .attr("cx", 50) .attr("cy", 515) .attr("fill", "#5e93bc") phasest.enter() .append("text") .attr("class", "phasest") .attr("id", "tout") .attr("y", 520) .attr("x", 215) .text( "Negative Outcome") phasest.enter() .append("circle") .attr("class", "phasest") .attr("r", 10) .attr("cx", 200) .attr("cy", 515) .attr("fill", "#ca8546") phasest.enter() .append("text") .attr("class", "phasest") .attr("id", "tout") .attr("y", 520) .attr("x", 365) .text( "No conclusion, Ongoing, Equivalent") phasest.enter() .append("circle") .attr("class", "phasest") .attr("r", 10) .attr("cx", 350) .attr("cy", 515) .attr("fill", "#D9D9D9") hide_phasest: () => phasest = @vis.selectAll(".phasest").remove() hide_phases: () => phases = @vis.selectAll(".phases").remove() display_by_yearcat: () => @force.gravity(@layout_gravity) .charge(this.charge) .friction(0.9) .on "tick", (e) => @circles.each(this.move_towards_yearcat(e.alpha)) .attr("cx", (d) -> d.x) .attr("cy", (d) -> d.y) @force.start() this.display_yearcats() this.display_yearcatst() this.hide_phases() this.hide_cmpds() this.hide_cmpdst() this.hide_fundings() this.hide_pops() this.hide_outcomes() this.hide_nbdozs() this.hide_outcomest() this.hide_phasest() this.hide_fundingst() this.hide_popst() this.hide_nbdozst() move_towards_yearcat: (alpha) => (d) => target = @yearcat_centers[d.yearcat] d.x = d.x + (target.x - d.x) * (@damper + 0.02) * alpha * 1.1 d.y = d.y + (target.y - d.y) * (@damper + 0.02) * alpha * 1.1 display_yearcats: () => yearcats_x = {"(1985,2005]":5 * @width / 20, "(N=8513, 34 trials)":5 * @width / 20, "(2005,2010]": 19 * @width / 40, "(N=16710, 39 trials)": 19 * @width / 40, "(2010,2014]": 14 * @width / 20, "(N=19383, 33 trials)": 14 * @width / 20 } yearcats_y = {"(1985,2005]": 4 * @height / 32, "(N=8513, 34 trials)": 5 * @height / 32, "(2005,2010]": 4 * @height / 32, "(N=16710, 39 trials)": 5 * @height / 32, "(2010,2014]" : 4 * @height / 32,"(N=19383, 33 trials)": 5 * @height / 32 } yearcats_data = d3.keys(yearcats_x, yearcats_y) yearcats = @vis.selectAll(".yearcats") .data(yearcats_data) yearcats.enter() .append("text") .attr("class", "yearcats") .attr("x", (d) => yearcats_x[d] ) .attr("y", (d) => yearcats_y[d] ) .attr("text-anchor", "middle") .text((d) -> d) display_yearcatst: () => yearcatst_x = {@width} yearcatst_y = {@height} yearcatst_data = d3.keys(yearcatst_x, yearcatst_y) yearcatst = @vis.selectAll(".yearcatst") .data(yearcatst_data) yearcatst.enter() .append("text") .attr("class", "yearcatst") .attr("id", "tyea") .attr("y", 560) .attr("x", 0) .text( "'Year' refers to the date of publication of the clinical results.") yearcatst.enter() .append("text") .attr("class", "yearcatst") .attr("id", "tyea") .attr("y", 578) .attr("x", 0) .text( "Since the first reported trial in 1987, the number and size of clinical trials in MS have been steadily growing.") yearcatst.enter() .append("text") .attr("class", "yearcatst") .attr("id", "tout") .attr("y", 520) .attr("x", 65) .text( "Positive Outcome") yearcatst.enter() .append("circle") .attr("class", "yearcatst") .attr("r", 10) .attr("cx", 50) .attr("cy", 515) .attr("fill", "#5e93bc") yearcatst.enter() .append("text") .attr("class", "yearcatst") .attr("id", "tout") .attr("y", 520) .attr("x", 215) .text( "Negative Outcome") yearcatst.enter() .append("circle") .attr("class", "yearcatst") .attr("r", 10) .attr("cx", 200) .attr("cy", 515) .attr("fill", "#ca8546") yearcatst.enter() .append("text") .attr("class", "yearcatst") .attr("id", "tout") .attr("y", 520) .attr("x", 365) .text( "No conclusion, Ongoing, Equivalent") yearcatst.enter() .append("circle") .attr("class", "yearcatst") .attr("r", 10) .attr("cx", 350) .attr("cy", 515) .attr("fill", "#D9D9D9") hide_yearcatst: () => yearcatst = @vis.selectAll(".yearcatst").remove() hide_yearcats: () => yearcats = @vis.selectAll(".yearcats").remove() display_by_cmpd: () => @force.gravity(@layout_gravity) .charge(this.charge) .friction(0.9) .on "tick", (e) => @circles.each(this.move_towards_cmpd(e.alpha)) .attr("cx", (d) -> d.x) .attr("cy", (d) -> d.y) @force.start() this.display_cmpds() this.display_cmpdst() this.hide_yearcats() this.hide_phases() this.hide_fundings() this.hide_pops() this.hide_outcomes() this.hide_nbdozs() this.hide_outcomest() this.hide_phasest() this.hide_yearcatst() this.hide_fundingst() this.hide_popst() this.hide_nbdozst() move_towards_cmpd: (alpha) => (d) => target = @cmpd_centers[d.cmpd] d.x = d.x + (target.x - d.x) * (@damper + 0.02) * alpha * 1.1 d.y = d.y + (target.y - d.y) * (@damper + 0.02) * alpha * 1.1 display_cmpds: () => cmpds_x = {"GA (N=6318)" : @width / 8, "IFNB-1b (N=5425)" : 3 * @width / 8, "IFNB-1a (N=5130)" : 5 * @width / 8, "Fingolimod (N=5068)" : 7 * @width / 8,"Laquinimod (N=2952)" : @width / 8, "BG-12 (N=2924)" : 3 * @width / 8, "Teriflunomide (N=2878)" : 5 * @width / 8, "Natalizumab (N=2628)" : 7 * @width / 8,"Alemtuzumab (N=1755)" : @width / 8, "Daclizumab (N=854)" : 3 * @width / 8, "Rituximab (N=599)" : 24 * @width / 40, "Mitoxantrone (N=436)" : 34 * @width / 40,"IVIg (N=392)" : 9 * @width / 80, "IFNA-2a (N=147)" : 3 * @width / 8, "MMF (N=89)" : 24 * @width / 40, "Other (N=7011)" : 33 * @width / 40 } cmpds_y = {"GA (N=6318)" : 2 * @height / 40, "IFNB-1b (N=5425)" : 2 * @height / 40, "IFNB-1a (N=5130)" : 2 * @height / 40, "Fingolimod (N=5068)" : 2 * @height / 40,"Laquinimod (N=2952)" : 60 * @height / 160, "BG-12 (N=2924)" : 3 * @height / 8, "Teriflunomide (N=2878)" : 3 * @height / 8, "Natalizumab (N=2628)" : 28 * @height / 80,"Alemtuzumab (N=1755)" : 97 * @height / 160, "Daclizumab (N=854)" : 5 * @height / 8, "Rituximab (N=599)" : 99 * @height / 160, "Mitoxantrone (N=436)" : 23 * @height / 40,"IVIg (N=392)" : 63 * @height / 80, "IFNA-2a (N=147)" : 32 * @height / 40, "MMF (N=89)" : 32 * @height / 40, "Other (N=7011)" : 28 * @height / 40 } cmpds_data = d3.keys(cmpds_x, cmpds_y) cmpds = @vis.selectAll(".cmpds") .data(cmpds_data) cmpds.enter() .append("text") .attr("class", "cmpds") .attr("x", (d) => cmpds_x[d] ) .attr("y", (d) => cmpds_y[d] ) .attr("text-anchor", "middle") .text((d) -> d) display_cmpdst: () => cmpdst_x = {@width} cmpdst_y = {@height} cmpdst_data = d3.keys(cmpdst_x, cmpdst_y) cmpdst = @vis.selectAll(".cmpdst") .data(cmpdst_data) cmpdst.enter() .append("text") .attr("class", "cmpdst") .attr("id", "tout") .attr("y", 580) .attr("x", 65) .text( "Positive Outcome") cmpdst.enter() .append("circle") .attr("class", "cmpdst") .attr("r", 10) .attr("cx", 50) .attr("cy", 575) .attr("fill", "#5e93bc") cmpdst.enter() .append("text") .attr("class", "cmpdst") .attr("id", "tout") .attr("y", 580) .attr("x", 215) .text( "Negative Outcome") cmpdst.enter() .append("circle") .attr("class", "cmpdst") .attr("r", 10) .attr("cx", 200) .attr("cy", 575) .attr("fill", "#ca8546") cmpdst.enter() .append("text") .attr("class", "cmpdst") .attr("id", "tout") .attr("y", 580) .attr("x", 365) .text( "No conclusion, Ongoing, Equivalent") cmpdst.enter() .append("circle") .attr("class", "cmpdst") .attr("r", 10) .attr("cx", 350) .attr("cy", 575) .attr("fill", "#D9D9D9") hide_cmpdst: () => cmpdst = @vis.selectAll(".cmpdst").remove() hide_cmpds: () => cmpds = @vis.selectAll(".cmpds").remove() display_by_funding: () => @force.gravity(@layout_gravity) .charge(this.charge) .friction(0.9) .on "tick", (e) => @circles.each(this.move_towards_funding(e.alpha)) .attr("cx", (d) -> d.x) .attr("cy", (d) -> d.y) @force.start() this.display_fundings() this.display_fundingst() this.hide_yearcats() this.hide_phases() this.hide_cmpds() this.hide_cmpdst() this.hide_pops() this.hide_outcomes() this.hide_nbdozs() this.hide_outcomest() this.hide_phasest() this.hide_yearcatst() this.hide_popst() this.hide_nbdozst() move_towards_funding: (alpha) => (d) => target = @funding_centers[d.funding] d.x = d.x + (target.x - d.x) * (@damper + 0.02) * alpha * 1.1 d.y = d.y + (target.y - d.y) * (@damper + 0.02) * alpha * 1.1 display_fundings: () => fundings_x = {"Teva": 7 * @width / 64, "(N=9310, 16 trials)": 7 * @width / 64, "BiogenIdec": 25 * @width / 64, "(N=8535, 21 trials)": 25 * @width / 64, "EMDSerono": 41 * @width / 64, "(N=5568, 12 trials)": 41 * @width / 64, "Novartis": 57 * @width / 64, "(N=5438, 8 trials)": 57 * @width / 64, "BayerSchering": @width / 8, "(N=5334, 13 trials)": @width / 8, "GenzymeSanofi": 25 * @width / 64, "(N=4633, 8 trials)": 25 * @width / 64, "Roche": 81 * @width / 128, "(N=535, 5 trials)": 81 * @width / 128, "Other": 7 * @width / 8, "(N=5253, 23 trials)": 7 * @width / 8 } fundings_y = {"Teva": @height / 36, "(N=9310, 16 trials)": @height / 18, "BiogenIdec": @height / 36, "(N=8535, 21 trials)": @height / 18, "EMDSerono": @height / 36, "(N=5568, 12 trials)": @height / 18, "Novartis": @height / 36, "(N=5438, 8 trials)": @height / 18, "BayerSchering": 19 * @height / 36, "(N=5334, 13 trials)": 20 * @height / 36, "GenzymeSanofi": 19 * @height / 36, "(N=4633, 8 trials)": 20 * @height / 36, "Roche": 19 * @height / 36, "(N=535, 5 trials)": 20 * @height / 36, "Other": 19 * @height / 36, "(N=5253, 23 trials)": 20 * @height / 36 } fundings_data = d3.keys(fundings_x, fundings_y) fundings = @vis.selectAll(".fundings") .data(fundings_data) fundings.enter() .append("text") .attr("class", "fundings") .attr("x", (d) => fundings_x[d] ) .attr("y", (d) => fundings_y[d] ) .attr("text-anchor", "middle") .text((d) -> d) display_fundingst: () => fundingst_x = {@width} fundingst_y = {@height} fundingst_data = d3.keys(fundingst_x, fundingst_y) fundingst = @vis.selectAll(".fundingst") .data(fundingst_data) fundingst.enter() .append("text") .attr("class", "fundingst") .attr("id", "tfun") .attr("y", 560) .attr("x", 0) .text( "The most active pharmaceutical companies in MS are Teva, Biogen-Idec and EMD-Serono;") fundingst.enter() .append("text") .attr("class", "fundingst") .attr("id", "tfun") .attr("y", 578) .attr("x", 0) .text( "none of these are among the top 10 largest pharma companies in the world.") fundingst.enter() .append("text") .attr("class", "fundingst") .attr("id", "tout") .attr("y", 530) .attr("x", 65) .text( "Positive Outcome") fundingst.enter() .append("circle") .attr("class", "fundingst") .attr("r", 10) .attr("cx", 50) .attr("cy", 525) .attr("fill", "#5e93bc") fundingst.enter() .append("text") .attr("class", "fundingst") .attr("id", "tout") .attr("y", 530) .attr("x", 215) .text( "Negative Outcome") fundingst.enter() .append("circle") .attr("class", "fundingst") .attr("r", 10) .attr("cx", 200) .attr("cy", 525) .attr("fill", "#ca8546") fundingst.enter() .append("text") .attr("class", "fundingst") .attr("id", "tout") .attr("y", 530) .attr("x", 365) .text( "No conclusion, Ongoing, Equivalent") fundingst.enter() .append("circle") .attr("class", "fundingst") .attr("r", 10) .attr("cx", 350) .attr("cy", 525) .attr("fill", "#D9D9D9") hide_fundingst: () => fundingst = @vis.selectAll(".fundingst").remove() hide_fundings: () => fundings = @vis.selectAll(".fundings").remove() display_by_pop: () => @force.gravity(@layout_gravity) .charge(this.charge) .friction(0.9) .on "tick", (e) => @circles.each(this.move_towards_pop(e.alpha)) .attr("cx", (d) -> d.x) .attr("cy", (d) -> d.y) @force.start() this.display_pops() this.display_popst() this.hide_fundings() this.hide_yearcats() this.hide_phases() this.hide_cmpds() this.hide_cmpdst() this.hide_outcomes() this.hide_nbdozs() this.hide_outcomest() this.hide_phasest() this.hide_yearcatst() this.hide_fundingst() this.hide_nbdozst() move_towards_pop: (alpha) => (d) => target = @pop_centers[d.pop] d.x = d.x + (target.x - d.x) * (@damper + 0.02) * alpha * 1.1 d.y = d.y + (target.y - d.y) * (@damper + 0.02) * alpha * 1.1 display_pops: () => pops_x = {"CIS": 5 * @width / 32, "(N=1849, 4 trials)": 5 * @width / 32, "RRMS": 7 * @width / 16, "(N=37852, 93 trials)": 7 * @width / 16, "SPMS": 28 * @width / 40, "(N=2469, 4 trials)": 28 * @width / 40, "PPMS": 36 * @width / 40, "(N=2436, 5 trials)": 36 * @width / 40 } pops_y = {"CIS": 3 * @height / 32, "(N=1849, 4 trials)": 4 * @height / 32, "RRMS": 3 * @height / 32, "(N=37852, 93 trials)": 4 * @height / 32, "SPMS": 3 * @height / 32, "(N=2469, 4 trials)": 4 * @height / 32, "PPMS": 3 * @height / 32, "(N=2436, 5 trials)": 4 * @height / 32 } pops_data = d3.keys(pops_x, pops_y) pops = @vis.selectAll(".pops") .data(pops_data) pops.enter() .append("text") .attr("class", "pops") .attr("x", (d) => pops_x[d] ) .attr("y", (d) => pops_y[d] ) .attr("text-anchor", "middle") .text((d) -> d) display_popst: () => popst_x = {@width} popst_y = {@height} popst_data = d3.keys(popst_x, popst_y) popst = @vis.selectAll(".popst") .data(popst_data) popst.enter() .append("text") .attr("class", "popst") .attr("id", "tpop") .attr("y", 560) .attr("x", 0) .text( "About 85% of all initial MS diagnoses are RRMS; hence the large proportion of trials in this population.") popst.enter() .append("text") .attr("class", "popst") .attr("id", "tpop") .attr("y", 578) .attr("x", 0) .text( "Few trials have also been run in early form (CIS) or, at the opposite, in more severe forms of MS (PPMS, SPMS).") popst.enter() .append("text") .attr("class", "popst") .attr("id", "tout") .attr("y", 520) .attr("x", 65) .text( "Positive Outcome") popst.enter() .append("circle") .attr("class", "popst") .attr("r", 10) .attr("cx", 50) .attr("cy", 515) .attr("fill", "#5e93bc") popst.enter() .append("text") .attr("class", "popst") .attr("id", "tout") .attr("y", 520) .attr("x", 215) .text( "Negative Outcome") popst.enter() .append("circle") .attr("class", "popst") .attr("r", 10) .attr("cx", 200) .attr("cy", 515) .attr("fill", "#ca8546") popst.enter() .append("text") .attr("class", "popst") .attr("id", "tout") .attr("y", 520) .attr("x", 365) .text( "No conclusion, Ongoing, Equivalent") popst.enter() .append("circle") .attr("class", "popst") .attr("r", 10) .attr("cx", 350) .attr("cy", 515) .attr("fill", "#D9D9D9") hide_popst: () => popst = @vis.selectAll(".popst").remove() hide_pops: () => pops = @vis.selectAll(".pops").remove() display_by_nbdoz: () => @force.gravity(@layout_gravity) .charge(this.charge) .friction(0.9) .on "tick", (e) => @circles.each(this.move_towards_nbdoz(e.alpha)) .attr("cx", (d) -> d.x) .attr("cy", (d) -> d.y) @force.start() this.display_nbdozs() this.display_nbdozst() this.hide_yearcats() this.hide_cmpds() this.hide_cmpdst() this.hide_fundings() this.hide_pops() this.hide_outcomes() this.hide_phases() this.hide_outcomest() this.hide_phasest() this.hide_yearcatst() this.hide_fundingst() this.hide_popst() move_towards_nbdoz: (alpha) => (d) => target = @nbdoz_centers[d.nbdoz] d.x = d.x + (target.x - d.x) * (@damper + 0.02) * alpha * 1.1 d.y = d.y + (target.y - d.y) * (@damper + 0.02) * alpha * 1.1 display_nbdozs: () => nbdozs_x = {"1 Dose Level": 5 * @width / 24,"(N=16154, 52 trials)": 5 * @width / 24, "2 Dose Levels": 9 * @width / 20, "(N=25773, 45 trials)": 9 * @width / 20, "3 Dose Levels": 31 * @width / 48, "(N=1760, 5 trials)": 31 * @width / 48, "4 Dose Levels": 37 * @width / 48, "(N=622, 3 trials)": 37 * @width / 48, "5 Dose Levels": 85 * @width /96, "(N=297, 1 trial)": 85 * @width /96 } nbdozs_y = {"1 Dose Level": 4 * @height / 32, "(N=16154, 52 trials)": 5 * @height / 32, "2 Dose Levels": 4 * @height / 32, "(N=25773, 45 trials)": 5 * @height / 32, "3 Dose Levels" : 4 * @height / 32, "(N=1760, 5 trials)": 5 * @height / 32, "4 Dose Levels" : 4 * @height / 32, "(N=622, 3 trials)": 5 * @height / 32, "5 Dose Levels" : 4 * @height / 32, "(N=297, 1 trial)": 5 * @height / 32 } nbdozs_data = d3.keys(nbdozs_x, nbdozs_y) nbdozs = @vis.selectAll(".nbdozs") .data(nbdozs_data) nbdozs.enter().append("text") .attr("class", "nbdozs") .attr("x", (d) => nbdozs_x[d] ) .attr("y", (d) => nbdozs_y[d] ) .attr("text-anchor", "middle") .text((d) -> d) display_nbdozst: () => nbdozst_x = {@width} nbdozst_y = {@height} nbdozst_data = d3.keys(nbdozst_x, nbdozst_y) nbdozst = @vis.selectAll(".nbdozst") .data(nbdozst_data) nbdozst.enter() .append("text") .attr("class", "nbdozst") .attr("id", "tnbd") .attr("y", 550) .attr("x", 0) .text( "A medication is, before anything, a 'correct' dose for an active ingredient, i.e. a dose providing a relevant therapeutical benefit and limited side-effects.") nbdozst.enter() .append("text") .attr("class", "nbdozst") .attr("id", "tnbd") .attr("y", 568) .attr("x", 0) .text( "It is critical to test various dose levels (at least 3 ideally), usually in Phase II to identify such a 'correct' dose level.") nbdozst.enter() .append("text") .attr("class", "nbdozst") .attr("id", "tnbd") .attr("y", 586) .attr("x", 0) .text( "In MS, rare are the trials which have investigated more than 2 dose levels.") nbdozst.enter() .append("text") .attr("class", "nbdozst") .attr("id", "tout") .attr("y", 520) .attr("x", 65) .text( "Positive Outcome") nbdozst.enter() .append("circle") .attr("class", "nbdozst") .attr("r", 10) .attr("cx", 50) .attr("cy", 515) .attr("fill", "#5e93bc") nbdozst.enter() .append("text") .attr("class", "nbdozst") .attr("id", "tout") .attr("y", 520) .attr("x", 215) .text( "Negative Outcome") nbdozst.enter() .append("circle") .attr("class", "nbdozst") .attr("r", 10) .attr("cx", 200) .attr("cy", 515) .attr("fill", "#ca8546") nbdozst.enter() .append("text") .attr("class", "nbdozst") .attr("id", "tout") .attr("y", 520) .attr("x", 365) .text( "No conclusion, Ongoing, Equivalent") nbdozst.enter() .append("circle") .attr("class", "nbdozst") .attr("r", 10) .attr("cx", 350) .attr("cy", 515) .attr("fill", "#D9D9D9") hide_nbdozst: () => nbdozst = @vis.selectAll(".nbdozst").remove() hide_nbdozs: () => nbdozs = @vis.selectAll(".nbdozs").remove() show_details: (data, i, element) => d3.select(element).attr("stroke", "black") content = "Trial: #{data.name}
" content +="Compound: #{data.cmpddetails}
" content +="Phase: #{data.phase} (N= #{data.value})
" content +="Population: #{data.pop}
" content +="Number of Dose: #{data.nbdoz}
" content +="Trial Duration (y): #{data.tdur}
" content +="Year: #{data.year}
" content +="Funding: #{data.funddetails}
" @tooltip.showTooltip(content,d3.event) hide_details: (data, i, element) => d3.select(element).attr("stroke", (d) => d3.rgb(@fill_color(d.outcome)).darker()) @tooltip.hideTooltip() root = exports ? this $ -> chart = null render_vis = (csv) -> chart = new BubbleChart csv chart.start() root.display_all() root.display_all = () => chart.display_outcome_all() root.display_phase = () => chart.display_by_phase() root.display_yearcat = () => chart.display_by_yearcat() root.display_cmpd = () => chart.display_by_cmpd() root.display_funding = () => chart.display_by_funding() root.display_pop = () => chart.display_by_pop() root.display_nbdoz = () => chart.display_by_nbdoz() root.toggle_view = (view_type) => if view_type == 'phase' root.display_phase() else if view_type == 'yearcat' root.display_yearcat() else if view_type == 'cmpd' root.display_cmpd() else if view_type == 'funding' root.display_funding() else if view_type == 'pop' root.display_pop() else if view_type == 'nbdoz' root.display_nbdoz() else root.display_all() d3.csv "/sites/all/themes/msdf/MStrials/MStrials2014.csv", render_vis