Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Color of pie slices

    Click image for larger version

Name:	3panels.png
Views:	1
Size:	46.1 KB
ID:	1424936
    Dear All,

    I am looking for the way to colorize the slices in a pie chart in a specific way. Consider the following example:

    Code:
    clear all
    
    input v
    101
    101
    101
    102
    101
    102
    103
    104
    103
    102
    103
    end
    
    tabulate v
    graph pie , over(v) plabel(_all name, color(yellow)) legend(rows(1)) ///
      pie(1, color(64 0 0)) pie(2, color(128 0 0)) ///
      pie(3, color(192 0 0)) pie(4, color(255 0 0)) ///
      name(g1) title("All")
    
    replace v=101 if v==102
    tabulate v
    
    // this is NOT the result that I want:
    graph pie , over(v) plabel(_all name, color(yellow)) legend(rows(1)) ///
      pie(1, color(64 0 0)) pie(2, color(128 0 0)) ///
      pie(3, color(192 0 0)) pie(4, color(255 0 0)) ///
      name(g2) title("Bad")
      
    // this is the result that I want:
    graph pie , over(v) plabel(_all name, color(yellow)) legend(rows(1)) ///
      pie(1, color(64 0 0))                        ///
      pie(2, color(192 0 0)) pie(3, color(255 0 0)) ///
      name(g3) title("Good")
      
    graph combine g1 g2 g3, rows(1) scale(0.5)

    I want the specific colors to apply by the type of item (104 to be colored bright-red), while its actual index depends whether the other items are present in the data.

    Ideally I would like to find a magic function sectorNumberByValue() with an argument of the domain (numeric or string) of over(), returning the sector number from the value to which that sector corresponds. Then I could do:

    Code:
    graph pie , over(v) plabel(_all name, color(yellow)) legend(rows(1)) ///
      pie(sectorNumberByValue(101), color(64 0 0)) pie(sectorNumberByValue(102), color(128 0 0)) ///
      pie(sectorNumberByValue(103), color(192 0 0)) pie(sectorNumberByValue(104), color(255 0 0)) ///
      name(g2) title("Bad")
    What I would like to avoid is simulation of the behavior of the pie chart command to try to replicate it's decisions when graphing my data, identifying the order of sectors, etc.
    Is there a simpler way?

    Thank you, Sergiy Radyakin
    Last edited by Sergiy Radyakin; 08 Jan 2018, 14:56. Reason: Added image

  • #2
    This isn't really a solution, but perhaps it's a direction you have not thought of which when pursued will lead to a solution.
    Code:
    clear all
    
    input v c
    101 1
    101 1
    101 1
    102 1
    101 1
    102 1
    103 1
    104 1
    103 1
    102 1
    103 1
    101 0
    102 0
    103 0
    104 0
    end
    
    replace v=101 if v==102 & c==1 
    
    // this is the result that I want:
    graph pie if c==1, over(v) plabel(_all name, color(yellow)) legend(rows(1)) ///
      pie(1, color(64 0 0))                        ///
      pie(2, color(192 0 0)) pie(3, color(255 0 0)) ///
      name(g3) title("Good")
    
    generate o = v-100 
    
    graph pie c, over(v) sort(o) plabel(_all name, color(yellow)) legend(rows(1)) ///
      pie(1, color(64 0 0)) pie(2, color(128 0 0)) ///
      pie(3, color(192 0 0)) pie(4, color(255 0 0)) ///
      name(g4) title("Better than Bad, though not quite Good")

    Comment


    • #3
      I'm not confident that I fully understand what the desired code should work like; even if I did, my solution would involve using -levelsof-, which might count as "replicating graph pie's decision". Sorry, if that's not convenient enough. Could you clarify a little on what you want to achieve?

      Anyways, here's my take on the issue:
      Code:
      clear all
      
      input v
      101
      101
      101
      102
      101
      102
      103
      104
      103
      102
      103
      end
      
      tabulate v
      
      // four levels:
      quietly : levelsof v , local(varlevels)
      graph pie , over(v) plabel(_all name, color(yellow)) legend(rows(1)) ///
        pie(`: list posof "101" in varlevels', color(64 0 0)) pie(`: list posof "102" in varlevels', color(128 0 0)) ///
        pie(`: list posof "103" in varlevels', color(192 0 0)) pie(`: list posof "104" in varlevels', color(255 0 0)) ///
        name(g11) title("version with four levels") nodraw
      
      replace v=101 if v==102
      tabulate v
      
      // three levels:
      quietly : levelsof v , local(varlevels)
      graph pie , over(v) plabel(_all name, color(yellow)) legend(rows(1)) ///
        pie(`: list posof "101" in varlevels', color(64 0 0)) ///
        pie(`: list posof "103" in varlevels', color(192 0 0)) pie(`: list posof "104" in varlevels', color(255 0 0)) ///
        name(g12) title("version with three levels") nodraw
      
      graph combine g11 g12, rows(1) scale(0.5)
      In order to make this work as (supposedly) desired by Sergiy, the assumption that -levelsof- sorts in the same way as -graph pie- has to hold, of course.
      Click image for larger version

Name:	2panels.png
Views:	1
Size:	84.4 KB
ID:	1424989



      Regards
      Bela
      Last edited by Daniel Bela; 09 Jan 2018, 03:08. Reason: added image

      Comment


      • #4
        Thank you very much, William and Daniel.

        Daniel's solution is, probably, closest by the spirit of it to my desired behavior (my hypothetical function sectorNumberByValue() has materialized in his solution as the position in the list).

        But at the same time there are still two issues:
        1. the critical piece is missing. Daniel wrote:
        the assumption that -levelsof- sorts in the same way as -graph pie- has to hold, of course
        Can this be confirmed somehow?
        1. assuming i have coded
          Code:
          pie(`: list posof "104" in varlevels', color(255 0 0))
          if value 104 does not occur in the data, the list position is 0 (zero) and Stata stops with an error. Apparently it doesn't want to ignore the specification of attributes of non-existing pie slices. This means that I can't write the full colorization code in the do-file, but rather need to dynamically build it probing each level from levelsof against my lookup table and pulling out an appropriate color attribute.
        William's solution seems to be working well, but it:
        1. distorts the data (as I understand I always have to add a block of records mentioning each level I want to have in the legend at least once). This should be fine for my use, since I know the universe where 101,102, ...,104 are coming from, but may not be suitable if 88 or 99 may also occur unexpectedly (in that case I would expect Stata to assign a new color code on it's own from the active palette).
        2. uses sorting (I assume sorting by {v} or by {v-100} doesn't matter and I can omit generation of additional o variable) to impose a particular order. Since sort() in this case is an option of graph pie, it has to obey (this is good), but it makes it vulnerable to changes in the implementation of pie , say, if one day it is modified by developers to ignore the slices with zero contributions.
        With this I think this thread can be closed as resolved. Still if anyone discovers a more streamlined solution, please don't hesitate to append.

        Thank you, Sergiy

        Comment

        Working...
        X