identify yAxis tick interval - highcharts

I am using highcharts to display total income per quarter (in thousands of pounds) for a variety of departments.
Sometimes the income for the department is quite small. in this case, the y axis values contains 2 decimal places
Sometimes the income is larger and the y axis values contain 1 decimal place
And occasionally, the value are very large and the y axis values do not contain any decimal places
Fiddle to demonstrate different formatting
The problem I have is that the current formatting of the y axis looks wrong.
I need to set the number of decimal places on the y axis values based on the tick interval: -
small values (i.e. 0.25, 0.5, 0.75, 1 etc) need to be formatted to 2 decimal places.
larger values (i.e. 0.5, 1, 1.5, 2 etc) need to be formatted to 1 decimal place.
very large values (i.e. 80, 90, 100, 110 etc) need no decimal places.
The actual values can be up to 3 decimal places (e.g. 0.306, 0.518 (small) 1.429, 1.806 (larger) 102.429, 160.806(very large))
My code builds up a script string and then uses ScriptManager.RegisterStartupScript to run the script.
I have tried to set the number of decimal places based on the values
Dim yAxisValue as Double= 0
Dim numberOfDP as Integer = 0
...
While reader.Read
If yAxisValue < reader.Item("YAxisValues").ToString Then
yAxisValue = reader.Item("YAxisValues").ToString
If Val(yAxisValue) < 1 Then
numberOfDP = 2
ElseIf Val(yAxisValue) < 10 Then
numberOfDP = 1
End If
End If
End While
MyScript = MyScript & "yAxis: {" & vbCrLf
MyScript = MyScript & "labels: {" & vbCrLf
MyScript = MyScript & "style: {color: 'black'," & vbCrLf
MyScript = MyScript & "'fontSize': '11pt'}," & vbCrLf
MyScript = MyScript & "format: '{value:. & numberOfDP & f}'" & vbCrLf
MyScript = MyScript & "}" & vbCrLf
MyScript = MyScript & "}" & vbCrLf
But I would rather base the formatting on the actual tick interval.
Is there any way I can do this?

I am not sure about ScriptManager.RegisterStartupScript, but in Highcharts you can set yAxis.labels.formatter and determine there how many decimals should be displayed, for example:
function formatter () {
var dec = this.axis.tickInterval > 1 ? 0 : (this.axis.tickInterval > 0.1 ? 1 : 2);
return this.value.toFixed(dec);
}
Now just use in yAxis options that:
yAxis: {
labels: {
formatter: formatter
}
},
And live demo for you: https://jsfiddle.net/4y8n33ob/

Related

Creating Bitmask for keyboard modifiers + ASCII Code

I would like to encode three keyboard modifiers (CTRL, ALT, SHIFT) + the ASCII code of the pressed key into a single value. This falls naturally into the category of bitmasks.
One way I could do this is that the sender encodes each key as the following:
CTRL: 1000
ALT: 10000
SHIFT: 100000
KeyCode: 1-255
For example, if I were to click all modifiers + the last key in the ascii table, I would get:
100000 + 10000 + 1000 + 255 = 111255. The receiver side it would then be possible to do substraction and check if the number goes below 0 as such:
has_shift = X - 100000 < 0
has_alt = X - 10000 < 0
has_ctrl = X - 1000 < 0
if has_shift
X -= 100000
if has_alt
X -= 10000
if has_ctrl
X -= 1000
keyCode = X (the remainder)
Surely enough, I find this horrible and would assume that this could be done in a far better using bit-shift or something in that ballpark. How could this possibly be done better?
Instead add 256, 512, and 1024 respectively for ctrl, alt, shift. Then use the and operator in whatever language you're using (missing from question tags) to extract the modifiers and code. In C and many languages, that operator is &. So X & 1024 is not zero if shift was pressed. X & 255 is the character code.

line break in a Function in Mathjax

very basic question about line break. I'm a newbie at mathjax but understand latex well. I'm using mathjax to make a quiz.
I tried to use \\ in mathjax but it doesn't show the line break: I'd the question to say:
If a + 10 = 2,
then what is the value of a
{
op1: 0,
question: function() {
op1 = Math.ceil(Math.random() * 5) + 1;
return `If $ a + ${op1} = 2 \\ $, then what is the value of $a$`;
},
answer: function() {
return op1 * op2;
}
}
thanks
Since \ is a special character in javascript string literals, you need to double them if you want an actual \ in your string. So you would need to use \\\\ to get \\ in the resulting string. Your \\ would just add \, which (together with the following space) will be the \ control sequence, which will just add a space at the end of the expression.

Need DXL code to arrange attribute lines into table (converting DOORS data to LaTeX source)

I have a DXL script which parses all data in DOORS columns into a LaTeX -compatible text source file. What I can't figure out is how to re-order some data into a tabular - compatible format. The attributes in question are DXL links to a reference DOORS module, so there is one line (separated by a line-feed) per link in each cell. Currently I loop thru all columns for each object (row), with the code snippet (part of the full script)
for col in doorsModule do {
var_name = title( col )
if( ! main( col ) && search( regexp "Absolute Number", var_name, 0 ) == false )
{
// oss is my output stream variable
if ( length(text(col, obj) ) > 0 )
{
oss << "\\textbf{";
oss << var_name; // still the column title here
oss << "}\t"
var_name = text( col, obj );
oss << var_name;
oss << "\n\n";
c++;
}
}
}
Examples of the contents of a cell, where I have separately parsed the Column Name to bold and collected it prior to collecting the cell contents. All four lines are the contents of a single cell.
\textbf{LinkedItemName}
DISTANCE
MinSpeed
MaxSpeed
Time
\textbf{Unit}
m
km/h
km/h
minutes
\textbf{Driver1}
100
30
80
20
\textbf{Driver2}
50
20
60
10
\textbf{Driver3}
60
30
60
30
What I want to do is re-arrange the data so that I can write the source code for a table, to wit:
\textbf{LinkedItemName} & \textbf{Unit} & \textbf{Driver1} & \textbf{Driver2} & \textbf{Driver3} \\
DISTANCE & m & 100 & 50 & 60 \\
MinSpeed & km/h & 30 & 20 & 30 \\
MaxSpeed & km/h & 80 & 60 & 60 \\
Time & minutes & 20 & 10 & 30 \\
I know in advance the exact Attribute names I'm "collecting." I can't figure out how to manipulate the data returned from each cell (regex or otherwise) to create my desired final output. I'm guessing some regex code (in DXL) might be able to assign the contents of each line within a cell to a series of variables, but don't quite see how.
Combination of regex and string assembly seems to work. Here's a sample bit of code (some of which is straight from the DOORS DXL Reference Manual)
int idx = 0
Array thewords = create(1,1)
Array thelen = create(1,1)
Regexp getaline = regexp2 ".*"
// matches any character except newline
string txt1 = "line 1\nline two\nline three\n"
// 3 line string
while (!null txt1 && getaline txt1) {
int ilen = length(txt1[match 0])
print "ilen is " ilen "\n"
put(thelen, ilen, idx, 0)
putString(thewords,txt1[match 0],0,idx)
idx ++
// match 0 is whole of match
txt1 = txt1[end 0 + 2:] // move past newline
}
int jj
// initialize to simplify adding the "&"
int lenone = (int get(thelen,0,0) )
string foo = (string get(thewords, 0, 0,lenone ) )
int lenout
for (jj = 1; jj < idx; jj++) {
lenout = (int get(thelen,jj,0) )
foo = foo "&" (string get(thewords, 0, jj,lenout ) )
}
foo = foo "\\\\"
// foo is now "line 1&line two&line three\\ " (without quotes) as LaTeX wants

How do I fill up a number's decimal places with zeroes?

Assume the following numbers:
local a = 2
local b = 3.1
local c = 1.43
local d = 1.0582
My goal is to round these numbers to two decimal places. The result should be this, respectively:
a = 2.00
b = 3.10
c = 1.43
d = 1.06 or 1.05
Obviously I understand that any number with trailing decimal zeroes will get rounded. 2.00 will be 2. But I need the numbers as strings, and to make it visually more appealing, I would need these two decimal places.
Here's a function I use to round to two decimal places:
function round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end
This works fine for test cases c and d, but will produce wrong results with a and b: it won't fill up with zeroes. I understand it is because the rounding function takes the numbers and calculates them - therefore the excess zeroes get cut off.
But that is exactly not my goal - not cutting them off.
I've tried string manipulation, by checking if and where a . is in a number, but that didn't work at all, for any case. My method:
local zei
if i < 100 then
if tostring(i):find("%.") == nil then
zei = round(i, 2) .. ".00" --No decimal point found, append .00
else
zei = round(i, 2) --Found decimal point, round to 2
end
if tostring(i):find("%.")+2 == tostring(i):len() then
zei = round(i, 2) .. "0" --Found point, but only one trailing number, append 0
end
else
zei = round(i, 0) --Number is over 100, no decimal points needed
end
The above 100 case is just for aesthetics and not relevant here. Where zei is the displayed string, and i is one of the test case numbers.
Summary
How would I round a number to two decimal places, but append trailing zeroes, even if they were excess, e.g. 2.30? I understand I need strings for this.
Contradicting question: Strip off excess zeroes
You don't round numbers. You create string representations of those numbers. That would be done by string.format, with an appropriate format. Like this:
string.format("%.2f", a);

How to generate random lines of text of a given length from a dictionary of words (bin-packing problem)?

I need to generate three lines of text (essentially jibberish) that are each 60 characters long, including a hard return at the end of each line. The lines are generated from a dictionary of words of various lengths (typically 1-8 characters). No word may be used more than once, and words must be separated by spaces. I think this is essentially a bin-packing problem.
The approach I've taken so far is to create a hashMap of the words, grouped by their lengths. I then choose a random length, pull a word of that length from the map, and append it to the end of the line I'm currently generating, accounting for spaces or a hard return. It works about half the time, but the other half of the time I'm getting stuck in an infinite loop and my program crashes.
One problem I'm running into is this: as I add random words to the lines, groups of words of a given length may become depleted. This is because there are not necessarily the same number of words of each length in the dictionary, e.g., there may only be one word with a length of 1. So, I might need a word of a given length, but there are no longer any words of that length available.
Below is a summary of what I have so far. I'm working in ActionScript, but would appreciate insight into this problem in any language. Many thanks in advance.
dictionary // map of words with word lengths as keys and arrays of corresponding words as values
lengths // array of word lengths, sorted numerically
min = lengths[0] // minimum word length
max = lengths[lengths.length - 1] // maximum word length
line = ""
while ( line.length < 60 ) {
len = lengths[round( rand() * ( lengths.length - 1 ) )]
if ( dictionary[len] != null && dictionary[len].length > 0 ) {
diff = 60 - line.length // number of characters needed to complete the line
if ( line.length + len + 1 == 60 ) {
// this word will complete the line exactly
line += dictionary[len].splice(0, 1) + "\n"
}
else if ( min + max + 2 >= diff ) {
// find the two word lengths that will complete the line
// ==> this is where I'm having trouble
}
else if ( line.length + len + 1 < 60 - max ) {
// this word will fit safely, so just add it
line += dictionary[len].splice(0, 1) + " "
}
if ( dictionary[len].length == 0 ) {
// delete any empty arrays and update min and max lengths accordingly
dictionary[len] = null
delete dictionary[len]
i = lengths.indexOf( len )
if ( i >= 0 ) {
// words of this length have been depleted, so
// update lengths array to ensure that next random
// length is valid
lengths.splice( i, 1 )
}
if ( lengths.indexOf( min ) == -1 ) {
// update the min
min = lengths[0]
}
if ( lengths.indexOf( max ) == -1 ) {
// update the max
max = lengths[lengths.length - 1]
}
}
}
}
You should think of an n-letter word as being n+1 letters, because each word has either a space or return after it.
Since all your words are at least 2 characters long, you don't ever want to get to a point where you have 59 characters filled in. If you get to 57, you need to pick something that is 2 letters plus the return. If you get to 58, you need a 1-letter word plus the return.
Are you trying to optimize for time? Can you have the same word multiple times? Multiple times in one line? Does it matter if your words are not uniformly distributed, e.g. a lot of lines contain "a" or "I" because those are the only one-letter words in English?
Here's the basic idea. For each line, start choosing word lengths, and keep track of the word lengths and total character count so far. As you get toward the end of the line, choose word lengths less than the number of characters you have left. (e.g. if you have 5 characters left, choose words in the range of 2-5 characters, counting the space.) If you get to 57 characters, pick a 3-letter word (counting return). If you get to 58 characters, pick a 2-letter word (counting return.)
If you want, you can shuffle the word lengths at this point, so all your lines don't end with short words. Then for each word length, pick a word of that length and plug it in.
dictionnary = Group your words by lengths (like you already do)
total_length = 0
phrase = ""
while (total_length < 60){
random_length = generate_random_number(1,8)
if (total_length + random_length > 60)
{
random_length = 60 - total_length // possibly - 1 if you cound \n and -2 if you
// append a blank anyway at the end
}
phrase += dictionnary.get_random_word_of_length(random_length) + " "
total_length += random_length + 1
}

Resources