Wedge startAngle

17 views
Skip to first unread message

FRANCOIS MERCIER

unread,
May 22, 2011, 11:16:25 AM5/22/11
to prot...@googlegroups.com
Hello,

I'm trying to display frequencies in the form of a "donut plot", using pv.wedge.
Let's assume I have a sample of 36 pairs of shoes, for which I want to study the "type" (boots, sneakers, ...), and within each "type" I want to know the "material" used to make the shoes (leather, rubber, ...).
I want to display the frequency of "types" in a first donut or ring, and I want to display the frequency of "material" within each "type" in a second ring, surrounding the first one.

As you will notice, when using the code below, I managed to obtain the "type" and "material" aligned for the 1st wedge of the inner ring, but it's getting messy for the 2nd wedge of the inner ring.

Any help on how to fix this would be much apreciated. 

Thanks a lot,
Best regards
Francois

/*****************************************************************************/

var fill1=pv.colors("gold", "olivedrab", "darkseagreen", "lightseagreen")
var offset=(1/6)*Math.PI

new pv.Panel()
    .width(600)
    .height(600)

   .add(pv.Wedge)
    .data(pv.normalize([12.02, 12.01, 9, 3]))
    .left(300)
    .top(300)
    .innerRadius(135)
    .outerRadius(195)
    .angle(function(d) d*2*Math.PI)
    .fillStyle(fill1)
    .strokeStyle("white")
    .lineWidth(4)

   .add(pv.Wedge)
    .data(pv.normalize([7, 4, 1]))
    .left(300)
    .top(300)
    .innerRadius(215)
    .outerRadius(275)
    .angle(function(d) d*(2/3)*Math.PI)
    .fillStyle(function (d) pv.rgb(255, 215, 0, .1+d))
    .strokeStyle("white")
    .lineWidth(4)

   .add(pv.Wedge)
    data(pv.normalize([6, 5, 1]))
    .left(300)
    .top(300)
    .innerRadius(215)
    .outerRadius(275)
    .startAngle(function() offset+this.index) 
    .angle(function(d) d*(1/2)*Math.PI)
    .fillStyle(function (d) pv.rgb(107, 142, 35, .1+d))
    .strokeStyle("white")
    .lineWidth(4)

   .root.render();


/*****************************************************************************/

Feris Thia

unread,
May 23, 2011, 8:32:08 AM5/23/11
to prot...@googlegroups.com
Hi Francois,

Try this code.. hope it helps a bit. I've made same changes in bolded lines :)



    var fill1=pv.colors("gold", "olivedrab", "darkseagreen", "lightseagreen");
    var offset=(1/6)*Math.PI;

    var data2 = pv.normalize([6, 5, 1]);

   
    new pv.Panel()
        .width(600)
        .height(600)

       .add(pv.Wedge)
        .data(pv.normalize([12.02, 12.01, 9, 3]))
        .left(300)
        .top(300)
        .innerRadius(135)
        .outerRadius(195)
        .angle(function(d) d*2*Math.PI)
        .fillStyle(fill1)
        .strokeStyle("white")
        .lineWidth(4)

       .add(pv.Wedge)
        .data(pv.normalize([7, 4, 1]))
        .left(300)
        .top(300)
        .innerRadius(215)
        .outerRadius(275)
        .angle(function(d) d*(2/3)*Math.PI)
        .fillStyle(function (d) pv.rgb(255, 215, 0, .1+d))
        .strokeStyle("white")
        .lineWidth(4)
        .add(pv.Wedge)
        .data(data2)
        .left(300)
        .top(300)
        .innerRadius(215)
        .outerRadius(275)
        .startAngle(function() {return (offset + ((this.index>0) ? (data2[this.index-1]*1/2*Math.PI) : 0))})
        .angle(function(d) d*(1/2)*Math.PI)
        .fillStyle(function (d) pv.rgb(107, 142, 35, .1+d))
        .strokeStyle("white")
        .lineWidth(4)
        .visible(true)
       .root.render();

Regards,

Feris

jas...@hotmail.com

unread,
May 23, 2011, 11:53:28 AM5/23/11
to protovis
I think our 2nd angle function of:

.angle(function(d) d*(2/3)*Math.PI)

is in error. The 1/3 as in 1/3 d*2*Math.PI should be the normalized
wedge size

12.02/(12.02 + 12.01 +9 + 3) for the first.

12.01/(12.02 + 12.01 +9 + 3) for the 2nd

9/(12.02 + 12.01 +9 + 3) ... etc.

How to do this is the issue now.


On May 22, 11:16 am, FRANCOIS MERCIER <francois.merc...@me.com> wrote:
> Hello,
>
> I'm trying to display frequencies in the form of a "donut plot", using pv.wedge.
> Let's assume I have a sample of 36 pairs of shoes, for which I want to study the "type" (boots, sneakers, ...), and within each "type" I want to know the "material" used to make the shoes (leather, rubber, ...).
> I want to display the frequency of "types" in a first donut or ring, and I want to display the frequency of "material" within each "type" in a second ring, surrounding the first one.
>
> As you will notice, when using the code below, I managed to obtain the "type" and "material" aligned for the 1st wedge of the inner ring, but it's getting messy for the 2nd wedge of the inner ring.
>
> Any help on how to fix this would be much apreciated. 
>
> Thanks a lot,
> Best regards
> Francois
>
> /**************************************************************************­***/
>
> var fill1=pv.colors("gold", "olivedrab", "darkseagreen", "lightseagreen")
> var offset=(1/6)*Math.PI
>
> new pv.Panel()
>     .width(600)
>     .height(600)
>
>    .add(pv.Wedge)
>     .data(pv.normalize([12.02, 12.01, 9, 3]))
>     .left(300)
>     .top(300)
>     .innerRadius(135)
>     .outerRadius(195)
>     .angle(function(d) d*2*Math.PI)
>     .fillStyle(fill1)
>     .strokeStyle("white")
>     .lineWidth(4)
>
>    .add(pv.Wedge)
>     .data(pvnormalize([7, 4, 1]))
>     .left(300)
>     .top(300)
>     innerRadius(215)
>     .outerRadius(275)
>     .angle(function(d) d*(2/3)*Math.PI)
>     .fillStyle(function (d) pv.rgb(255, 215, 0, .1+d))
>     .strokeStyle("white")
>     .lineWidth(4)
>
>    .add(pv.Wedge)
>     .data(pv.normalize([6, 5, 1]))
>     .left(300)
>     .top(300)
>     .innerRadius(215)
>     .outerRadius(275)
>     .startAngle(function() offset+this.index) 
>     .angle(function(d) d*(1/2)*Math.PI)
>     .fillStyle(function (d) pv.rgb(107, 142, 35, .1+d))
>     .strokeStyle("white")
>     .lineWidth(4)
>
>    .root.render();
>
> /**************************************************************************­***/

Francois Mercier

unread,
May 23, 2011, 9:49:11 PM5/23/11
to prot...@googlegroups.com
Hi Feris, and Jas0501,

Thanks a lot for having taken the time to look at this.
Unfortunately, none of these work as I would have expected.

Dear Feris:
I think I see where you are heading at, but after having struggled for quite some time with various combinations of startAngle, offset and angle, I came to the conclusion that startAngle() and angle() are conflicting with each other, ie. they can be used simultaneously, at least for the problem at stake.

In theory (at least, as I understand it), we could use only angle(), and the 'pseudo' code would probably look like

  .angle(offset + function (d) d*(2/3)*Math.PI )

but this doesn't work.

So, I stopped fighting, and wrote (hard-coded) each wedge, the one after the other. Not pretty from a programming standpoint, but at least I have a result. Here below is the end product:

Best regards and thank you again,
F

/*=======================================================================*/

var fill1=pv.colors("gold", "olivedrab", "darkseagreen", "lightseagreen")
var offset=(1/6)*Math.PI

var data1=pv.normalize([12.02, 12.01, 9, 3]);
var data2=pv.normalize([1, 4, 7]);
var data3=pv.normalize([6, 5, 1]);

new pv.Panel()
    .width(600)
    .height(600)
    .left(300)
    .top(300)

   .add(pv.Wedge)
    .data(data1)
    .innerRadius(135)
    .outerRadius(195)
    .angle(function(d) d*2*Math.PI)
    .fillStyle(fill1)
    .strokeStyle("white")
    .lineWidth(4)

   .add(pv.Wedge)
    .data(data2)
    .innerRadius(215)
    .outerRadius(275)
    .angle(function(d) d*(2/3)*Math.PI)
    .fillStyle(function (d) pv.rgb(255, 215, 0, .1+d))
    .strokeStyle("white")
    .lineWidth(4)

   .add(pv.Wedge)
    .startAngle(offset
    .endAngle((1/2)*Math.PI
    .fillStyle(pv.rgb(107, 142, 35, .3))
    .strokeStyle("white")
    .lineWidth(4)

   .add(pv.Wedge)
    .startAngle((1/2)*Math.PI
    .endAngle((7/9)*Math.PI
    .fillStyle(pv.rgb(107, 142, 35, .2))
    .strokeStyle("white")
    .lineWidth(4)

   .add(pv.Wedge)
    .startAngle((7/9)*Math.PI
    .endAngle((5/6)*Math.PI
    .fillStyle(pv.rgb(107, 142, 35, .1))
    .strokeStyle("white")
    .lineWidth(4)

   .add(pv.Wedge)
    .innerRadius(295)
    .outerRadius(297)
    .startAngle((-2/9)*Math.PI
    .endAngle((1/2)*Math.PI
    .fillStyle("black")
    .strokeStyle("black")

   .root.render();

/*=======================================================================*/




--
You received this message because you are subscribed to the Google Groups "protovis" group.
To post to this group, send email to prot...@googlegroups.com.
To unsubscribe from this group, send email to protovis+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/protovis?hl=en.

Feris Thia

unread,
May 24, 2011, 11:23:38 AM5/24/11
to prot...@googlegroups.com
Hi Francois,

I still think I can try a better solution for you - and can be done programmatically. Check the following code and screenshot. Is it solve your problem ?



================
var datacompound = [
//Layer 1
[12.02, 12.01, 9, 3], 
//Layer 2
[
[1, 4, 7],
[6, 5, 1],
[2, 3],
[4, 4, 4]
]
];
//Preprocessed Raw Data
var c = pv.Scale.linear(0, 0.2, 0.4, 0.6, 0.8, 1).range("gold", "olivedrab", "violet", "#21004F", "darkseagreen", "lightseagreen");
datacompound[0] = pv.normalize(datacompound[0]);
for(i=0; i<datacompound[1].length; i++)
{
datacompound[1][i] = pv.normalize(datacompound[1][i]);
for(j=0;j<datacompound[1][i].length;j++)
datacompound[1][i][j] = datacompound[0][i]*datacompound[1][i][j];
}
datacompound[1] = pv.blend(datacompound[1]);

var sum1 = 0, sum2 = 0, offset1 = 0, offset2 = 0;
var startAngle = 0*Math.PI/180;
//Panel
vis = new pv.Panel()
.width(600)
.height(600)
.left(300)
.top(300)
//First Layer
.add(pv.Wedge)
.data(datacompound[0])
.innerRadius(135)
.outerRadius(195)
.startAngle(function() {if(this.index>0) offset1+=datacompound[0][this.index-1]*2*Math.PI; else offset1=startAngle; return offset1;})
.angle(function(d) d*2*Math.PI)
.fillStyle(function(d) {if(this.index>0) sum1+=datacompound[0][this.index-1]; else sum1=0; return c(sum1);})
.strokeStyle("white")
.lineWidth(4)
//Second Layer
.add(pv.Wedge)
.data(datacompound[1])
.innerRadius(200)
.outerRadius(275)
.startAngle(function() {if(this.index>0) offset1+=datacompound[1][this.index-1]*2*Math.PI; else offset1=startAngle; return offset1;})
.angle(function(d) d*2*Math.PI)
.fillStyle(function(d) {if(this.index>0) sum1+=datacompound[1][this.index-1]; else sum1=0; return c(sum1);})
.strokeStyle("white")
.lineWidth(4)

.root.render();
================

Regards,

Feris

Francois Mercier

unread,
May 24, 2011, 9:46:22 PM5/24/11
to prot...@googlegroups.com
Hi Feris,

Waou ! Looks like you nailed it down :-))

Now, it's going to take me 3 days (minimum) before I understand your code ;-)
As I'm not (yet) literate in JavaScript, it seems that I will learn a lot from this example.

Thank you so much for your help .... much apreciated,
Best regards

Francois


Feris Thia

unread,
May 24, 2011, 11:42:09 PM5/24/11
to prot...@googlegroups.com
Hi Francois,

Good that it helps. Look forward if you have any further question on the code.

Regards,

Feris
Reply all
Reply to author
Forward
0 new messages