Announcement

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

  • Creating and re-colouring spaghetti plot using xtline

    Hello,

    I am trying to generate a spaghetti plot using the "xtline" command, which has worked, however, I am trying to re-colour the lines by group. The code below works to create the plot:

    -- xtline NfL , i(ID_visit) t(sample_delay1) overlay legend(off) aspectratio(1) xlabel(5 "0d" 6 "3d" 12 "0d" 13 "3d") ylabel(0(10)70) yscale(range(0 70)) --

    However, all of the lines come out as different colours. I have found this option code "plot#opts()" where the # is the plot line, so, for example, I could add -- plot5opts(lcolor(green)) -- which would change plot 5 line to green.

    The problem I am having is that this would be very long for every plot line, and I haven't been able to find which plot corresponds to which subject data point.

    I am also trying to make the x-axis so the 4 points are distributed equally along the bottom but haven't be able to do that yet.

    Would anyone be able to help with this problem to make it more efficient?

    Thank you,
    Annabelle


  • #2
    This example may help.

    Code:
    webuse grunfeld
    
    line invest year, c(L) ysc(log) yla(1000 100 10 1)
    The last two options are specifically for that variable, but the technique is more general. If you have lots of missing values, you may need more trickery.

    Comment


    • #3
      Originally posted by Annabelle Coleman View Post

      The problem I am having is that this would be very long for every plot line, and I haven't been able to find which plot corresponds to which subject data point.
      If you have a variable that defines groups, -levelsof- may help. The lines correspond to levels of your panel identifier, so first line is the minimum value and the last line is the maximum value. See how this is done below:

      Code:
      webuse grunfeld, clear
      keep if company<6
      gen group= cond(company<3, 1, 2)
      
      *START HERE: SPECIFY GROUP COLORS
      levelsof company if group==1, local(blue)
      levelsof company if group==2, local(red)
      
      *LOCAL COLOR OPTIONS
      local opts
      local colors blue red
      foreach color of local colors{
          foreach level in ``color''{
              local opts "`opts' plot`level'opts(color(`color')) "
          }
      }
      
      *GRAPH
      set scheme s1mono
      xtline invest, overlay `opts' leg(off)
      Click image for larger version

Name:	Graph.png
Views:	1
Size:	47.7 KB
ID:	1713089





      ADDED IN EDIT: I should add that if the identifier does not start at 1 and is not consecutive, generate one using the group function of egen. However, things may get complicated if some levels of the identifier are not used. I have not experimented on how xtline behaves in such cases, so you should look into this if implementing the proposed solution.
      Last edited by Andrew Musau; 10 May 2023, 05:32.

      Comment


      • #4
        Hello Andrew,

        Thank you for your response. This code makes sense, I noticed that if the identifier does not start at 1 and is not consecutive, I had to generate a new group function however this led to complications.

        This is the code I used:
        Code:
        gen Order2 = _n
        levelsof Order2 if disease_grp==0, local(blue)
        levelsof Order2 if disease_grp==1, local(red)
        levelsof Order2 if disease_grp==2, local(green)                                        
        
        local opts
        local colors blue red green
        foreach color of local colors{
            foreach level in ``color''{
               local opts "`opts' plot`level'opts(color(`color')) "
            }
        }
        
        di `opts'
        set scheme s1mono
        xtline NfL , i(ID_visit) t(sample_delay1) overlay legend(off) `opts' aspectratio(1) xlabel(5 "0d" 6 "3d" 12 "0d" 13 "3d") ylabel(0(10)70) yscale(range(0 70)) ytitle("NfL pg/mL") xtitle("3-day delay")
        But when I would use
        Code:
        di `opts'
        , it wouldn't give the right numbers for the group.

        Do you think there are any other options to try? It just gives a black and white graph from the set scheme code.

        Comment


        • #5
          I am thinking that this will be complicated with multiple missing levels. I would switch to twoway with multiple -if- restrictions.

          Comment


          • #6
            Seriously, don't mix red and green together. Many people struggle to distinguish them, exemplifying a condition known informally as colo[u]r blindness. (There are other challenges under that heading.)

            There are many palettes that work well for most people with colour vision. See e.g. https://www.statalist.org/forums/for...ailable-on-ssc and its references for more discussion.

            You also have scope to use different line patterns.

            Comment


            • #7
              A front and back plot strategy could work here. The idea is (1) each group shown prominently in turn, at the front as it were (2) the other groups shown as backdrop.

              The broad idea was written up in https://journals.sagepub.com/doi/pdf...6867X211025838 but as yet fabplot can't cope with this extension.

              Code:
              webuse grunfeld, clear
              
              * manifestly you need a variable defining groups, in this example 3
              gen group = mod(company, 3)
              
              * of these options
              * c(L) legend(off) are likely to be needed
              * ysc(log) yla(1000 100 10 1) are specific to the example
              local opts         c(L) legend(off)                   ysc(log) yla(1000 100 10 1)
              
              sort company year
              
              levelsof group, local(levels)
              
              * write your titles here: more titles needed with more groups
              local text1 "text for 1"
              local text2 "text for 2"
              local text3 "text for 3"
              
              * optional
              local colours orange blue black
              
              local Gall
              
              local graph = 1
              
              foreach g of local levels {
                  
                  local colour : word `graph' of `colours'
              
                  line invest year if group != `g', `opts' lc(gs12) lw(medium) || line invest year if group == `g', `opts' lw(medthick) lc(`colour') name(G`graph', replace) title("`text`graph''")
                  
                  local Gall `Gall' G`graph'
                  
                  local ++graph
                  
              }
                  
              graph combine `Gall'
              Click image for larger version

Name:	fabplot_sortof.png
Views:	1
Size:	79.5 KB
ID:	1713792

              Last edited by Nick Cox; 16 May 2023, 05:52.

              Comment


              • #8
                I have tried both of these methods but neither have seemed to work. I have attached an image of how I would like the spaghetti plot to look where each group is coloured separately (manually done on Illustrator), compared to how it comes out on STATA with multiple colours for each individual person using xtline code.

                Code:
                foreach obj in B2b {
                    
                    foreach analyte of varlist NfL GFAP Tau {
                    cd .. 
                        cd "3. Graphs"
                            cd "`obj'" 
                                cd `analyte'
                                
                                
                        foreach col_type in Venepuncture Fingerprick  {
                            preserve
                            drop if Objective!="`obj'" | ///
                            `analyte'==. | ///
                            CollectionType!="`col_type'"
                            
                        capture ///
                        xtline `analyte' , i(ID_visit) t(sample_delay1)  ///
                            overlay legend(off) aspectratio(1) ///
                            xlabel("``obj'xlab`col_type''", valuelabel) ///
                            ylabel(``obj'`analyte'ylab') ///
                            yscale(range(``obj'`analyte'y')) xscale(lwidth(thick)) yscale(lwidth(thick)) ///
                            ``obj'xaxis`col_type'' ///     
                            gr_edit .plotregion1.style.editstyle boxstyle(linestyle(color(none))) editcopy
                        //    name(`obj'_`analyte'_`col_type', replace)
                                graph save "`analyte'_`obj'_`col_type'_Spag_plot.gph" , replace
                                graph export "`analyte'_`obj'_`col_type'_Spag_plot.png" , replace
                                graph export "`analyte'_`obj'_`col_type'_Spag_plot.eps" , replace
                            
                            restore
                        }
                                
                                cd ..
                            cd ..
                        cd ..
                    cd "2. dta files"
                    
                    }
                }
                I have tried the twoway line command code:

                Code:
                preserve
                drop if Objective!="B2a" | ///
                NfL==. | ///
                CollectionType!="Venepuncture"
                
                
                twoway (line Order NfL if disease_grp==0, c(L) lcolor("`INF_grey'")) ///
                        (line Order NfL if disease_grp==1, c(L) lcolor("`INF_gold'")) ///
                        (line Order NfL if disease_grp==2, c(L) lcolor("`INF_Red'")),  ///
                        legend(off) ytitle("`s_type1'") xtitle("`s_type2'") /// 
                            aspectratio(1) xscale(lwidth(thick)) yscale(lwidth(thick)) /// 
                            name(practice_Spag,replace) 
                            gr_edit .plotregion1.style.editstyle boxstyle(linestyle(color(none))) editcopy
                But this gives a different type of line graph which is not how I am aiming for it to look.

                I hope visually seeing the graphs can help you understand what I am looking to do and if there are any other solutions that others can think of.

                To give you an idea of the data that I am using, ID visit is a string variable to identify the participant, sample_delay is either 0-days or 3-days, analyte (e.g., NfL) is a continuous variable.

                Best,
                Annabelle
                Attached Files

                Comment


                • #9
                  The example in #3:

                  Code:
                  webuse grunfeld, clear
                  keep if company<6
                  gen group= cond(company<3, 1, 2)
                  
                  *START HERE: SPECIFY GROUP COLORS
                  levelsof company if group==1, local(blue)
                  levelsof company if group==2, local(red)
                  
                  local plots
                  local colors blue red
                  foreach color of local colors{
                      foreach level in ``color''{
                          local plots "`plots' (line invest year if company==`level', lc(`color'))"
                      }
                  }
                  
                  set scheme s1mono
                  tw `plots', leg(off) xtitle("")
                  Res.:

                  Click image for larger version

Name:	Graph.png
Views:	1
Size:	47.7 KB
ID:	1713926



                  Last edited by Andrew Musau; 17 May 2023, 05:56.

                  Comment


                  • #10
                    There is no data example here. If as medical data your data are confidential or sensitive we respect that but the answer to that problem is already given in the FAQ Advice, just give fake data with the same structure. (Speaking for myself I am fairly fluent with Stata graphics but it's still hard for me to read a chunk of graphics code without being able to run it on relevant data.)

                    In principle the graphs you want are akin to those shown by Andrew Musau in #3.

                    The graph you show last doesn't have time as the x-axis variable.

                    I think you're missing a subtlety here.

                    xtline is special in that the time variable is not given (must not be given!) in the syntax but taken from an xtset (or tsset) declaration.

                    If you use instead line you're stepping outside that xtset (or tsset) framework and the variables you need must all be specified explicitly. The last variable named is the x axis variable.

                    There is a lot of code in ,#8 that distracts from the question, but I guess that your answer should start from something more like

                    Code:
                    twoway (line NFL time_delay if disease_grp==0, c(L) lcolor("`INF_grey'")) ///        
                    (line NFL time_delay if disease_grp==1, c(L) lcolor("`INF_gold'")) ///        
                    (line NFL time_delay if disease_grp==2, c(L) lcolor("`INF_Red'")),  ///        
                    legend(off) ytitle("`s_type1'") xtitle("`s_type2'") ///              
                    aspectratio(1) xscale(lwidth(thick)) yscale(lwidth(thick)) ///              
                    name(practice_Spag,replace)
                    Last edited by Nick Cox; 17 May 2023, 06:05.

                    Comment


                    • #11
                      Hi all - this twoway line command has worked! Thank you both for your help.

                      Comment

                      Working...
                      X