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