强制 y 轴从 0 开始并仍然使用自动标记
Force y axis to start at 0 and still use automated labeling
我有一个图,其 y 最小值开始远高于 0。但我想将 0 作为 y 轴的最小值,并且仍然让 Stata 自动 创建均匀间隔y 轴标签。
这是基线:
sysuse auto2, clear
scatter turn displacement
这会产生:
这几乎是我想要的,除了y范围不是从0开始。
基于 Nick Cox (https://www.statalist.org/forums/forum/general-stata-discussion/general/1598753-force-chart-y-axis-to-start-at-0) 的回答,我将代码修改为:
scatter turn displacement, yscale(range(0 .)) ylabel(0)
这成功地将 y 轴从 0 开始,但是 0 旁边的标签消失了:
我继续删除 `ylabel(0):
scatter turn displacement, yscale(range(0 .))
这会产生相反的问题 - y 轴标签与第一个图中的标签相同。
如何让 Stata 自动生成从 0 到最大值的 y 轴标签?例如,0、10、20、30、40、50 - 但重要的是,我有很多图,需要一个自动确定精确值的解决方案,而不需要我输入 y max 等。所以它不会是选择 10, 20, ..., 50 的我,但是 Stata。
巧合的是,我一直在这个领地里做一个命令。这是一个可重现的例子。
sysuse auto, clear
summarize turn, meanonly
local max = r(max)
nicelabels 0 `max', local(yla)
* shows 0 20 40 60
scatter turn displacement, yla(`yla', ang(h))
nicelabels 0 `max', local(yla) nvals(10)
* shows 0 10 20 30 40 50 60
scatter turn displacement, yla(`yla', ang(h))
其中nicelabels
是目前这个代码。
*! 1.0.0 NJC 25 April 2022
program nicelabels
/// fudge() undocumented
version 9
gettoken first 0 : 0, parse(" ,")
capture confirm numeric variable `first'
if _rc == 0 {
// syntax varname(numeric), Local(str) [ nvals(int 5) tight Fudge(real 0) ]
syntax [if] [in] , Local(str) [ nvals(int 5) tight Fudge(real 0) ]
local varlist `first'
marksample touse
quietly count if `touse'
if r(N) == 0 exit 2000
}
else {
// syntax #1 #2 , Local(str) [ nvals(int 5) tight Fudge(real 0) ]
confirm number `first'
gettoken second 0 : 0, parse(" ,")
syntax , Local(str) [ nvals(int 5) tight Fudge(real 0) ]
if _N < 2 {
preserve
quietly set obs 2
}
tempvar varlist touse
gen double `varlist' = cond(_n == 1, `first', `second')
gen byte `touse' = _n <= 2
}
su `varlist' if `touse', meanonly
local min = r(min) - (r(max) - r(min)) * `fudge'/100
local max = r(max) + (r(max) - r(min)) * `fudge'/100
local tight = "`tight'" == "tight"
mata: nicelabels(`min', `max', `nvals', `tight')
di "`results'"
c_local `local' "`results'"
end
mata :
void nicelabels(real min, real max, real nvals, real tight) {
if (min == max) {
st_local("results", min)
exit(0)
}
real range, d, newmin, newmax
colvector nicevals
range = nicenum(max - min, 0)
d = nicenum(range / (nvals - 1), 1)
newmin = tight == 0 ? d * floor(min / d) : d * ceil(min / d)
newmax = tight == 0 ? d * ceil(max / d) : d * floor(max / d)
nvals = 1 + (newmax - newmin) / d
nicevals = newmin :+ (0 :: nvals - 1) :* d
st_local("results", invtokens(strofreal(nicevals')))
}
real nicenum(real x, real round) {
real expt, f, nf
expt = floor(log10(x))
f = x / (10^expt)
if (round) {
if (f < 1.5) nf = 1
else if (f < 3) nf = 2
else if (f < 7) nf = 5
else nf = 10
}
else {
if (f <= 1) nf = 1
else if (f <= 2) nf = 2
else if (f <= 5) nf = 5
else nf = 10
}
return(nf * 10^expt)
}
end
编辑
如果你去
sysuse auto, clear
summarize turn, meanonly
local max = r(max)
scatter turn displacement, yla(0(10)`max', ang(h))
scatter turn displacement, yla(0(20)`max', ang(h))
你会得到很好的解决方案。显然,在这种情况下,我们需要知道 10 或 20 是要使用的步长。可以使用您自己的方法以编程方式计算合适的宽度。
编辑 2022 年 5 月 10 日
现在可以从 SSC 下载经过修订和记录的 nicelabels
。
我有一个图,其 y 最小值开始远高于 0。但我想将 0 作为 y 轴的最小值,并且仍然让 Stata 自动 创建均匀间隔y 轴标签。
这是基线:
sysuse auto2, clear
scatter turn displacement
这会产生:
这几乎是我想要的,除了y范围不是从0开始。
基于 Nick Cox (https://www.statalist.org/forums/forum/general-stata-discussion/general/1598753-force-chart-y-axis-to-start-at-0) 的回答,我将代码修改为:
scatter turn displacement, yscale(range(0 .)) ylabel(0)
这成功地将 y 轴从 0 开始,但是 0 旁边的标签消失了:
我继续删除 `ylabel(0):
scatter turn displacement, yscale(range(0 .))
这会产生相反的问题 - y 轴标签与第一个图中的标签相同。
如何让 Stata 自动生成从 0 到最大值的 y 轴标签?例如,0、10、20、30、40、50 - 但重要的是,我有很多图,需要一个自动确定精确值的解决方案,而不需要我输入 y max 等。所以它不会是选择 10, 20, ..., 50 的我,但是 Stata。
巧合的是,我一直在这个领地里做一个命令。这是一个可重现的例子。
sysuse auto, clear
summarize turn, meanonly
local max = r(max)
nicelabels 0 `max', local(yla)
* shows 0 20 40 60
scatter turn displacement, yla(`yla', ang(h))
nicelabels 0 `max', local(yla) nvals(10)
* shows 0 10 20 30 40 50 60
scatter turn displacement, yla(`yla', ang(h))
其中nicelabels
是目前这个代码。
*! 1.0.0 NJC 25 April 2022
program nicelabels
/// fudge() undocumented
version 9
gettoken first 0 : 0, parse(" ,")
capture confirm numeric variable `first'
if _rc == 0 {
// syntax varname(numeric), Local(str) [ nvals(int 5) tight Fudge(real 0) ]
syntax [if] [in] , Local(str) [ nvals(int 5) tight Fudge(real 0) ]
local varlist `first'
marksample touse
quietly count if `touse'
if r(N) == 0 exit 2000
}
else {
// syntax #1 #2 , Local(str) [ nvals(int 5) tight Fudge(real 0) ]
confirm number `first'
gettoken second 0 : 0, parse(" ,")
syntax , Local(str) [ nvals(int 5) tight Fudge(real 0) ]
if _N < 2 {
preserve
quietly set obs 2
}
tempvar varlist touse
gen double `varlist' = cond(_n == 1, `first', `second')
gen byte `touse' = _n <= 2
}
su `varlist' if `touse', meanonly
local min = r(min) - (r(max) - r(min)) * `fudge'/100
local max = r(max) + (r(max) - r(min)) * `fudge'/100
local tight = "`tight'" == "tight"
mata: nicelabels(`min', `max', `nvals', `tight')
di "`results'"
c_local `local' "`results'"
end
mata :
void nicelabels(real min, real max, real nvals, real tight) {
if (min == max) {
st_local("results", min)
exit(0)
}
real range, d, newmin, newmax
colvector nicevals
range = nicenum(max - min, 0)
d = nicenum(range / (nvals - 1), 1)
newmin = tight == 0 ? d * floor(min / d) : d * ceil(min / d)
newmax = tight == 0 ? d * ceil(max / d) : d * floor(max / d)
nvals = 1 + (newmax - newmin) / d
nicevals = newmin :+ (0 :: nvals - 1) :* d
st_local("results", invtokens(strofreal(nicevals')))
}
real nicenum(real x, real round) {
real expt, f, nf
expt = floor(log10(x))
f = x / (10^expt)
if (round) {
if (f < 1.5) nf = 1
else if (f < 3) nf = 2
else if (f < 7) nf = 5
else nf = 10
}
else {
if (f <= 1) nf = 1
else if (f <= 2) nf = 2
else if (f <= 5) nf = 5
else nf = 10
}
return(nf * 10^expt)
}
end
编辑
如果你去
sysuse auto, clear
summarize turn, meanonly
local max = r(max)
scatter turn displacement, yla(0(10)`max', ang(h))
scatter turn displacement, yla(0(20)`max', ang(h))
你会得到很好的解决方案。显然,在这种情况下,我们需要知道 10 或 20 是要使用的步长。可以使用您自己的方法以编程方式计算合适的宽度。
编辑 2022 年 5 月 10 日
现在可以从 SSC 下载经过修订和记录的 nicelabels
。