I'm working on a QwtPlot - I have a regular time scale on X axis and a custom y scale with discrete values
The problem is that when I'm zooming the discrete Axis (it has major ticks only) with a magnifier, the ticks on the scale start repeating themselves and instead of getting
e.g. 2 ticks "0" and "1" I'm getting 4 ticks "0", "0", "1", "1" (or more, depends on the zoom). So because the divider can't divide the values, it just repeats them.
No idea what function or object to use/reimplement to make the scale stop drawing additional divisions (and btw also additional grid lines). Just stopping the magnifier from magnifying too much isn't the right answer since I want it to magnify more.
What I did to my discrete y axis (in CPlot inheriting QwtPlot) is:
QList<double> ticks;
for(int i=0; i<visualisation->getPIDs().size();i++)
{
ticks.append(i);
}
QwtScaleDiv* div=new QwtScaleDiv(0,visualisation->getPIDs().size()-1);
div->setTicks(QwtScaleDiv::MajorTick, ticks);
discreteScale=new CDiscreteScaleDraw;
discreteScale->setLUT(visualisation->getPIDs());
setAxisScaleDraw(QwtPlot::yLeft, discreteScale);
setAxisMaxMinor(QwtPlot::yLeft,0);
this->setAxisAutoScale(QwtPlot::yLeft, 0);
PS. On my time scale I have a similar problem, but this is the case of precision - when zooming in I would like to get the precision of 123,456.789 and I get 123,456.78 (and then the labels get doubled, tripled etc again). I would also like to remove the coma that QwtScaleDraw puts there so that I would get 123456.789, but the most important thing is getting rid of repeating labels.
The significance of a double is more than 6 but not endless, so without limiting the magnifier you will run sooner or later into this issue.
The double to string conversion is done using QLocale::toString() with its default parameter values ( 'g', 6 ). If you want to use different values you have to overload by implementing CDiscreteScaleDraw::label().
Concerning the ",': guess this is because of the NumberOptions of your locale. Try to change them using QLocale::setNumberOptions().
Related
I would like to automate the graph axis values for a series of plots in Stata 13.
In particular, I would like to show axis labels like 10^-1, 0, 10^1, 10^2 etc. by feeding the axis options macros.
The solution in the following blog post gives a good starting point:
Labeling logarithmic axes in Stata graphs
I could also also produce nicer labels by using "10{sup:`x'}".
However, I cannot find the solution to the following additional elements:
the range of the axis labels would run from 10^-10 up to 10^10. Moreover, my baseline is ln, so log values are 2.3, 4.6, etc. In particular, the line below which only takes integers as input:
label define expon `vallabel', replace
I would like to force the range of the axis values by graph (e.g. a particular axis runs from 10^-2 to 10^5). I understand that range() only extends axes, but does not allow to trim them.
Any ideas on either or both of the above?
This is a very straightforward output in R or Python, even standard without many additional arguments, but unfortunately not so in Stata.
Q1. You should check out niceloglabels from SSC as announced in this thread. niceloglabels together with other tricks and devices in this territory will be discussed in a column expected to appear in Stata Journal 18(1) in the first quarter of 2018.
Value labels are limited to association with integers but that does not bite here. All you need focus on is the text which is to be displayed as axis labels at designated points on either axis; such points can be specified using any numeric value within the axis range.
Your specific problem appears to be that one of your variables is a natural logarithm but you wish to label axes in terms of powers of 10. Conversion to a variable containing logarithms to base 10 is surely easy, but another program mylabels (SSC) can help here. This is a self-contained example.
* ssc inst mylabels
sysuse auto, clear
set scheme s1color
gen lnprice = ln(price)
mylabels 4000 8000 16000, myscale(ln(#)) local(yla)
gen lnweight = ln(weight)
mylabels 2 3 4, myscale(ln(1000*#)) suffix(" x 10{sup:3}") local(xla)
scatter lnprice lnweight, yla(`yla') xla(`xla') ms(Oh) ytitle(Price (USD)) xtitle(Weight (lb))
I have used different styles for the two axes just to show what is possible. On other grounds it is usually preferable to be consistent about style.
Broadly speaking, the use of niceloglabels is often simpler as it boils down to specifying xscale(log) or yscale(log) with the labels you want to see. niceloglabels also looks at a variable range or a specified minimum and maximum to suggest what labels might be used.
Q2. range() is an option with twoway function that allows extension of the x axis range. For most graph commands, the pertinent options are xscale() or yscale(), which again extend axis ranges if suitably specified. None of these options will omit data as a side-effect or reduce axis ranges as compared with what axis label options imply. If you want to omit data you need to use if or in or clone your variables and replace values you don't want to show with missing values in the clone.
FWIW, superscripts look much better to me than ^ for powers.
I have finally found a clunky but working solution.
The trick is to first generate 2 locals: one to evaluate the axis value, another to denote the axis label. Then combine both into a new local.
Somehow I need to do this separately for positive and negative values.
I'm sure this can be improved...
// define macros
forvalues i = 0(1)10 {
local a`i' = `i'*2.3
local b`i' `" "10{sup:`i'}" "'
local l`i' `a`i'' `"`b`i''"'
}
forvalues i = 1(1)10 {
local am`i' = `i'*-2.3
local bm`i' `" "10{sup:-`i'}" "'
local lm`i' `am`i'' `"`bm`i''"'
}
// graph
hist lnx, ///
xl(`lm4' `lm3' `lm2' `lm1' `l0' `l1' `l2' `l3' `l4')
I have dataset include about 100 observations, say all of them are in (x,y) format, all of y is in integer format. I need proc sgplot to make a graphic about them. The range about my y is from 1 to 150. I hope I can force the graphic to show every corresponding y value on the y-axis instead of automatically reducing the ticks to a small number in order to show them clearly. For example, if the first five value of my y is (1,3,4,6,7,....), I hope the y tick shows exactly (1,3,4,6,7,....) instead (1,5,...).
I tried
yaxis value=(1 to 150 by 1) valueshint display=all;
It does not work as maybe I have too many observations. I know the result maybe overwhelming, but I just want to see the result. Thanks.
You don't say if you're using SAS/GRAPH or ODS GRAPHICS (SGPLOT etc.), so I'll answer the latter which is what I know; the answer should be useful for both in concept.
You likely cannot get SAS to plot so much on the axis unless the axis is very large itself. This means you have two options.
Raise the size of the graphic produced a lot in terms of pixels(and then shrink that to a usable size via image physical size, or using an external tool). Not necessarily usable in all cases, but produces a very high resolution plot (which is very big size-wise). This page explains how to do that for ODS graphics (use image_dpi as a high number, and width and height in inches as a normal number), and this page explains for SAS/GRAPH. You may need to make your font small to make it work (if you're adding numbers, which I assume you are), or you may need to make an initially large plot first and then go into paint/photoshop/gimp/etc. and make it smaller.
Use annotate to create the axis marks. This is fairly easy if you know how to use annotate, as you're just writing to the location of the axis (y) and the item (x), and then a bit below that for the text. This will make it very easy to make a total garbage plot, but it will likely work ultimately.
These likely work in both SAS/GRAPH and ODS GRAPHICS, and I can't test either as you don't post any code or simulated data to test with, but I think both approaches have some merit (as does the approach of "don't do this", but you've thought that through).
I'm having problems with the y axis on a custom XYChart. The y axis is a NumberAxis, and I set the tick label formatter to a custom formatter. Auto-ranging is off. When I change the upper bound of the chart and request an axis layout, the old labels remain on the chart. With debug logging, I can see that the custom formatter methods are being invoked, and that they return the correct Strings, but the tick labels on the chart do not update. The only ones that do update are the ones that were not on the axis before. For example, if the range of the y axis was 0 to 3, and then I change the upper bound from 3 to 5, new labels with the correct values will show up at indices 4 and 5. However, the labels for 0 through 3 do not update even though the custom formatter now returns different Strings for them.
I tried taking the custom formatter out of the equation and simply changed the tick label fill to another color when I changed the upper bound of the y axis, and I saw the same behavior (labels for pre-existing indices had the old color, and labels for new indices had the new color). I hope I'm missing something obvious. Any help would be greatly appreciated. Otherwise I may need to resort to recreating the chart whenever the y axis labels need to change.
From what I have found, the tick labels themselves are basically immutable. Once a range is set, it only adds and removes ticks, but doesn't update them. What I did to overcome this is to set the upper bound to the lower bound (effectively removing all ticks), and then setting the upper bound back to the range I wanted, so it would re-create the ticks.
Is there any way to create a break in my vertical scale on the Google charts api?
I have a couple of dozen data points all about 600-2000 on the y-axis except for one value which is almost 300,000; this makes all the smaller data points nearly unreadable. I need to represent all this data and a logarithmic scale is not an option.
Simple answer: no, it is not possible.
Breaking axes is (generally) frowned upon in the visualization community and therefore isn't supported most of the time in various software.
If you want to be tricky, you can create a function to find outliers, and then move them to a second series in your data. Plot that series on the second axis, and have it with a different color. This says, "This figure is different and does not fit" which brings added attention to it, while still allowing the rest of the data to be seen in the same scale.
Personally I would just cut off the graph at an arbitrary value, set the value of that point to the maximum value, and add a tooltip saying, "Outlier: 300,000" or whatever it is. This will allow people to see the other numbers, but show that this number itself is an outlier without coloring it differently or removing it from the single series.
Either way is doable.
You need use a log scale. It's a vAxis and hAxis attribute. The supported values are:
log: Conventional logarithm scale
mirrorLog: Logarithm scale that allows 0 values
var options = {
vAxis: {
scaleType: 'mirrorLog',
}
};
var data = {};//your data
chart.draw(data, options);
If I had a product and wanted to visualize the amount of time that has passed between releases of that product, what type of graph would I use? What I'm trying to show is the average amount of time that has passed between release cycles, as well as (approximately) how far through the current release cycle we currently are.
The best I could come up with is a horizontal bar graph. Each bar would have a date associated with it that marked a particular release, and the length of the bar could indicate how much time has passed, maybe even list the exact number of days, but I could imagine that being slightly confusing, e.g. is that the amount of time that's passed before that release or after that release?
I imagine there must be a better way to visualize this.
UPDATE: I think I may have explained it poorly; let me try another approach. This buying guide does almost exactly what I want. It's compact, it lists when the releases happened, you can see roughly how long one release took compared to another (relatively), and the unfinished release is shown so you can get an idea of about how far through the average cycle you are. But one of the problems it has is that it is difficult to tell whether a particular stretch of time in between releases came before a particular date or afterwards. I was thinking about making the bars bigger and putting in the number of days too, which would only make the before/after ambiguity worse. So my question is, how can this chart be improved to be more visually intuitive? Thanks!
From your Question and your comments to the two answers prior to mine, your dataviz technique will have to
show the amount of time that has
passed between release cycles;
show both absolute and relative (i.e., time elapsed within a
release cycle as well as between them) which
is practically awkward because, as
you said, either you're forced to use
a tiny font to fit your plot on an
8.5 x 11 page, or the plot is so wide that it doesn't conveniently print
and it's too difficult for a readerto
capture in a single glance; and
show progress w/r/t the next target release
For the first item, i just used an axis scaled to time (x-axis). For the second, i used the y axis to represent intra-project time--where as, time between projects is on the x-axis. Doing this, keeps the plot size manageable. For the third item, i prefer to represent duration differently for cases like this--i.e., where there's a definite start and a definite finish. In other words, when my boss asks me how a certain project is going, i think i naturally say "50% complete" or something like that, rather than "we are four weeks into it". I think thermometer symbols can be visually intuitive here--i.e., you show progress by filling a container.
So in the plot below, i show five separate projects (versions 1 through 5); the x-axis is in weeks and shows how far apart in time are the project start dates for each. The y-axis (which i didn't show, instead relying on the color fill in the thermometer symbol to show "degree of completion of each project.
I created this plot in R (using only libraries in the base install).
Here's the code:
# synthetic data:
x = c(1, 10, 22, 40, 58) # x-axis
y = c(2, 5.5, 9, 12.4, 15.0) # y-axis
z = c(1, 0.9, 0.80, 0.67, 0.25) # % fill for thermometer symbols
# create the plot:
plot(x, y, ann=F, axes=F, type="n")
symbols(x, y, thermometers=cbind(0.5, 4, z), inches=1.2, fg=rep(3, 5),
ann=F, axes=F)
axis(side=1, at=xt, lwd.ticks=1.3, col="steelblue4", col.ticks="red")
A few comments in case you're not familiar with R. First, the plot, and axis function calls could have been omitted. The other three are purely for aesthetics:
plot was called to create a plot with no data, no labels, and no visible axis, so that i could draw my custom axis later and leave the y-axis out entirely;
axis is just for drawing a custom x-axis, with the tick marks where i wanted them.
symbols is the only call required.
The 'thermometer' argument is a matrix in which the first two columns are the symbol width and height, respectively, and the third column is the % filled ('z'); 'inches' is the actual symbol size, and 'fg' is the fill color for each symbol, i.e., 'rep(3,5) just means '3' repeated 5 times, where '3' is just a convenience symbol for the lovely green color you see below.
Maybe a Gantt Chart? For each release, you could use a row to the duration that the release was active. Also, you could include rows for development time. You would be able to visualize pretty easily a number of metrics...
Time between releases
Duration of each release
% completion of current dev cycle
Development periods compared release to release
I think I'd probably use some sort of Timeline, good examples