2
$\begingroup$

I have to do some visualizations about vaccines. I downloaded data on reported cases of vaccine-preventable diseases (for example, measles, tetanus, etc.) here. These data are absolute values. I downloaded the population from here for each country and multiplied the value by 1000 in order to have the real population value.

Then, to calculate the rate of cases I used the formula:

(number of reported cases/population)*100   -->   data domain [0, 100]%

Since it was a very small value, I multiplied this result by 1000:

((number of reported cases/population)*100)*1000   -->   data domain [0, 1000]%, right?

Now I have to represent this data using the bubble on a map (for example a chart like that) and I thought of something like that. The scale I use is a sqrt scale, the data domain is [0, 1000] while the range of the circle radius is [0, 1700] (my choice). The circle is actually constructed with a radius that is related to the data. If valCas is the rate of death caused by measles in France in 2015, the radius is calculated in this way (I'm using D3.js):

var circleScale = d3.scaleSqrt() 
    .domain([0, 1000]) // domain of cas data
    .range([0, 1700]); // range of circle radius

function fromValueToRadius(valCas) {
    var area = circleScale(valCas);
    return Math.sqrt(area / Math.PI);
}

The legend, however, how do I build it? I don't mean I want code but I need help in theory. Aesthetically it should be like this:

enter image description here

To do this I should use a code like this:

var legendSize1 = ?;
var legendSize2 = ?;
var legendSize3 = ?;

svg.append('circle')
    .attr('r', fromValueToRadius(legendSize1))
    .attr('cx', 0)
    .attr('cy', (0 - fromValueToRadius(legendSize1)));
svg.append('circle')
    .attr('r', fromValueToRadius(legendSize2))
    .attr('cx', 0)
    .attr('cy', (0 - fromValueToRadius(legendSize2)));
svg.append('circle')
    .attr('r', fromValueToRadius(legendSize3))
    .attr('cx', 0)
    .attr('cy', (0 - fromValueToRadius(legendSize3)));

But what is the value of legendSize1, legendSize2 and legendSize3? I know it's a simple problem but I don't understand what to do, if what I've done is correct and makes sense or not. Is it better for me not to change the population value (do not multiply it by 1000)? Is it better that I don't multiply the rate by 1000?


EDIT

This is what I understand:

  1. I download data on the population and I don't multiply them

    ie: Germany, 2012, population = 81066,228

  2. I download data on reported cases and I don't multiply them

    ie: Germany, 2012, measles = 166

  3. I compute prevalence as:

    ie: prevalence = (166/81066,228)*1000 = 0.002047

  4. To create circleScale, I need to kwon data domain. What is it?

    var circleScale = d3.scaleSqrt() 
        .domain([0, ?]) // domain of cas data
        .range([0, 1650]); // range of circle radius
    
  5. This function is correct so I don't modify it:

    function fromValueToRadius(valCas) {
        var area = circleScale(valCas);
        return Math.sqrt(area / Math.PI);
    }
    
  6. Code for legend will become:

    // for bubble size
    var legendSize1 = 10/100000;
    var legendSize2 = 50/100000;
    var legendSize3 = 100/100000;
    
    svg.append('circle')
     .attr('r', fromValueToRadius(legendSize1))
     .attr('cx', 0)
     .attr('cy', (0 - fromValueToRadius(legendSize1)));
    svg.append('circle')
     .attr('r', fromValueToRadius(legendSize2))
     .attr('cx', 0)
     .attr('cy', (0 - fromValueToRadius(legendSize2)));
    svg.append('circle')
     .attr('r', fromValueToRadius(legendSize3))
     .attr('cx', 0)
     .attr('cy', (0 - fromValueToRadius(legendSize3)));
    

So:

enter image description here

$\endgroup$

1 Answer 1

1
$\begingroup$

When you multiply by $100$, your domain is indeed $[0\%,100\%]$. When you multiply by $100$ and again by $1000$, you should not talk about percentages; that is now cases per $100,\!000$. Its domain is $[0, 100,\!000]$, certainly not $[0\%,1000\%]$.

It doesn't make sense to label the legend with $10\%$, $50\%$ and $100\%$ because you rarely see that many infections. Express it e.g. in cases per $100,\!000$ people.

[Prevalence] is arrived at by comparing the number of people found to have the condition with the total number of people studied, and is usually expressed as a fraction, as a percentage, or as the number of cases per 10,000 or 100,000 people.

https://en.wikipedia.org/wiki/Prevalence

Your fromValueToRadius function turns prevalences (the ratio of cases to total population) into radii so that the area and not the radius of the circle is proportional to the prevalence. This is good, this is how you should do it. Making the radius proportional to the value is, unfortunately, a frequent source of misleading visualisation.

Then your variables legendSize1, legendSize2, legendSize3 must be typical prevalences (e.g. cases per $100,\!000$ people) because they get transformed by the fromValueToRadius function. Use e.g. legendSize1 = 10/100000, legendSize2 = 50/100000 and legendSize3 = 100/100000. Make sure they are the same as in the label for that legend, e.g. write "$10$ in $100,\!000$" in the first label etc.; currently the labels are percentages which would be incorrect. A more subtle problem is that the areas of the three discs in your plot are not $10:50:100$, the middle one is certainly not $5$ times greater than the small one. (Just compare it to the County Bubbles figure that you linked.)

I recommend you don't multiply your data by either $100$ or $100,\!000$, instead, introduce a scaling constant for the plotting and multiply all the computed radii (both in the legend and in the figure) with that constant to scale the circles by the same factor. So that it's a modifier of the plotting, not of your data. Try out different values until you're satisfied.

I don't see what programming language you're using. I don't know whether circleScale is your own function or it is supplied by the programming environment. It makes it harder to verify what you're doing but these instructions should already help you achieve your goal.

Response to EDIT:

Germany, 2012, population = 81066,228

Avoid using a comma as a decimal point, use a point. (There are some natural languages whose spelling rules require a comma but I have never seen a computer programming language do that. In programming, it will cause unexpected problems because the interpreter thinks you have two distinct numbers: 81066 and 228.) Delete the decimal point or (if you have many countries) leave the decimal point where it is and multiply the number by $1000$ to get actual population number: Germany, 2012, population = 81066228 or Germany, 2012, population = 81066.228*1000.

Compute prevalence e.g. in units of persons in $100,\!000$ as prevalence = 100000 * 166/81066228. In this case, the data domain is [0, 100000], and legendSize1 = 10, legendSize2 = 50 and legendSize3 = 100. (The other sensible option would be to compute in ratio of cases to population size. That would change everything, e.g. domain to [0, 1], legendSize1 = 10/100000, etc.)

The necessary documentation for d3.js is here. Forget what I wrote about introducing a scaling constant. One option is to play with the value in the range in circleScale (which is now set to 1650) until you get circles of the required size. Be careful: in point 4. of your EDIT, range is what will become range of area = circleScale(valCas) in point 5. This is the range of the area, not of the radius as it is said in your point 4: .range([0, 1650]); // range of circle radius. The comment after // is incorrect.

If you want exactly a "size $1650$" circle (this is now area!) for the prevalence of "$100$ cases in $100,\!000$", then I recommend you set .domain([0, 100000]) and .range([0, 1650000]). The meaning of this domain and range is that

  • $0$ case in $100,\!000$ is mapped to area $0$,
  • $100\!,000$ cases in $100,\!000$ is mapped to area $1650*1000$,
  • and everything in between is treated accordingly, so $100$ cases in $100,\!000$ is $1000$th that much, and it should be mapped to $1650$.

I hope this works.

Be careful: your labels in the figure are now reversed, currently the largest circle has the smallest number!

$\endgroup$
2
  • $\begingroup$ Thank you! I didn't know prevalence before. The code is D3.js. I don't kwow if it's all clear to me. I'll explain what I would do, based on your answer. I edit my main message $\endgroup$
    – oipo
    May 9, 2018 at 10:46
  • $\begingroup$ I updated my answer. It's confusing me as well, not only you. You have to decide how to represent prevalence: cases per 100,000 people (which I worked out in my answer) or "cases per person" (that is, simply cases per population size, in which case you get very small numbers), and stick to it. $\endgroup$ May 9, 2018 at 13:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.