The immediate stimulus for this thread is a recent question
http://www.statalist.org/forums/foru...fferent-scales
but the solution here may not be what was wanted there. In any case the focus of this thread is code I now offer and, as it were, my version of the problem.
It's like this:
* You want a graph of two or more time series, which may have very different units of measurement and/or magnitudes of values.
* tsline or xtline or a direct line versus your time variable doesn't do a very good job. That is, the command is doing what it is designed to do, but the graph is not what you want.
Here's a simple example.
What are the solutions? They include
1. Messing with the variables. One trick is to multiply (or equivalently to divide) some or all of the variables, so that their scaled values are then comparable. At its cleanest this is just a matter of scaling all variables relative to values in a base year. Otherwise you need to ensure that axis labels tell the truth. But many people hate this kind of graph in principle, or object on other grounds.
2. Separate graphs for each response variable, which you then graph combine. This is quite flexible in various ways, but scaffolding gets repeated and you have to work hard at editing the combined graph to something simpler.
3. sparkline from SSC. This was designed with the idea of showing several time series and so can seem over-Spartan for a few.
4. Whatever I've forgotten about. This isn't just a joke heading for logical completeness, as some of the point of this thread is to ask what I am overlooking.
5. It strikes me that when you have multiple time series, but they are panel or panel-like data, there is a lot of flexibility that comes with using an by() option. So, the main idea here, why not restructure the data temporarily, so that different variables become separate blocks of values in a combined response variable?
Here is some token code, which is indicative rather than definitive. There is no help file and there may not ever be one, as I don't want flak for not supporting all possible graphs. version 11 is notional; it works with 11 and may work on some earlier versions, but you'd need to try it to see (and edit that statement).
Here is a default graph. We shunt the subtitles to the left to avoid breaking the view up and down. There is a default of one column of graphs. (If you want something else, you'll have to clone and edit the code.) tsset or xtset data are required.
The Grunfeld data aren't a hard test. Key detail: What appears on the left are the variable labels, and if there aren't any, the variable names. In the Grunfeld data, there are no variable labels. If there were variable labels, they would usually be longer than the names. But as you can see horizontal layout is the default (and vertical would be unreadable in most cases, even for a few variables). Let's imagine some long variable labels:
You see the point. In turn you could reach for the wonderful Graph Editor to split the labels. Or if you have looked at the code above you will have seen a mylabels() option, although you need to think about what you type and understand compound double quotes:
Or you could just modify the code to be smarter automatically. That would probably double the code. Still, splitvallabels (Nick Winter, Ben Jann) from SSC would be a source of ideas.
http://www.statalist.org/forums/foru...fferent-scales
but the solution here may not be what was wanted there. In any case the focus of this thread is code I now offer and, as it were, my version of the problem.
It's like this:
* You want a graph of two or more time series, which may have very different units of measurement and/or magnitudes of values.
* tsline or xtline or a direct line versus your time variable doesn't do a very good job. That is, the command is doing what it is designed to do, but the graph is not what you want.
Here's a simple example.
Code:
webuse grunfeld, clear tsline invest mvalue kstock if company == 1
What are the solutions? They include
1. Messing with the variables. One trick is to multiply (or equivalently to divide) some or all of the variables, so that their scaled values are then comparable. At its cleanest this is just a matter of scaling all variables relative to values in a base year. Otherwise you need to ensure that axis labels tell the truth. But many people hate this kind of graph in principle, or object on other grounds.
2. Separate graphs for each response variable, which you then graph combine. This is quite flexible in various ways, but scaffolding gets repeated and you have to work hard at editing the combined graph to something simpler.
3. sparkline from SSC. This was designed with the idea of showing several time series and so can seem over-Spartan for a few.
Code:
* ssc inst sparkline sparkline invest mvalue kstock year if company == 1
4. Whatever I've forgotten about. This isn't just a joke heading for logical completeness, as some of the point of this thread is to ask what I am overlooking.
5. It strikes me that when you have multiple time series, but they are panel or panel-like data, there is a lot of flexibility that comes with using an by() option. So, the main idea here, why not restructure the data temporarily, so that different variables become separate blocks of values in a combined response variable?
Here is some token code, which is indicative rather than definitive. There is no help file and there may not ever be one, as I don't want flak for not supporting all possible graphs. version 11 is notional; it works with 11 and may work on some earlier versions, but you'd need to try it to see (and edit that statement).
Code:
*! 1.0.0 NJC 5sept2016 program multtsline version 11 syntax varlist(numeric) [if] [in] /// [, byopts(str asis) mylabels(str asis) *] quietly { marksample touse count if `touse' if r(N) == 0 exit 2000 tsset local panelvar `r(panelvar)' local timevar `r(timevar)' local varlist : list varlist - timevar if "`varlist'" == "" exit 102 preserve keep if `touse' drop `touse' gettoken yvar varlist : varlist local J = 0 while "`yvar'" != "" { local ++J local lbl`J' : var label `yvar' if `"`lbl`J''"' == "" local lbl`J' "`yvar'" local call `call' `yvar' `timevar' `panelvar' gettoken yvar varlist : varlist } tempname y stack `call', into(`y' `timevar' `panelvar') clear if `"`mylabels'"' != "" { tokenize `mylabels' forval j = 1/`J' { label def _stack `j' `"``j''"', add } } else forval j = 1/`J' { label def _stack `j' `"`lbl`j''"', add } label val _stack _stack } sort `panelvar' `timevar' line `y' `timevar', by(_stack, col(1) yrescale note("") `byopts') /// ytitle("") xtitle("") yla(, ang(h)) c(L) /// subtitle(, pos(9) bcolor(none) nobexpand place(e)) `options' end
Here is a default graph. We shunt the subtitles to the left to avoid breaking the view up and down. There is a default of one column of graphs. (If you want something else, you'll have to clone and edit the code.) tsset or xtset data are required.
Code:
multtsline invest mvalue kstock if company == 1
The Grunfeld data aren't a hard test. Key detail: What appears on the left are the variable labels, and if there aren't any, the variable names. In the Grunfeld data, there are no variable labels. If there were variable labels, they would usually be longer than the names. But as you can see horizontal layout is the default (and vertical would be unreadable in most cases, even for a few variables). Let's imagine some long variable labels:
Code:
label var invest "something longer" label var mvalue "would be more difficult" label var kstock "to show compactly" multtsline invest mvalue kstock if company == 1
You see the point. In turn you could reach for the wonderful Graph Editor to split the labels. Or if you have looked at the code above you will have seen a mylabels() option, although you need to think about what you type and understand compound double quotes:
Code:
multtsline invest mvalue kstock if company == 1 , mylabels(`" `" "something" "longer" "' `" "would be" "more difficult" "' `" "to show" "compactly" "' "')
Or you could just modify the code to be smarter automatically. That would probably double the code. Still, splitvallabels (Nick Winter, Ben Jann) from SSC would be a source of ideas.
Comment