Custom label format in a Axis in Reporting Services - reporting-services

Currently I'm having trouble creating multiple format in SSRS for one Axis. The current situation is that I have a measure that could bring a maximum value of 1.2M (Currency) but an average of 500K depending the period. Originally I have the labelformat property set to 0,,M, but this doesn't bring the correct scale when the value is less than a million.
This are the current solution I have tried:
=IIF(Sum(Fields!Current_Year.Value, "CustomerSales") > Sum(Fields!Last_Year.Value, "CustomerSales"),
IIF(Sum(Fields!Current_Year.Value, "CustomerSales") < 1000000, "0,K", "0,,M"),
IIF(Sum(Fields!Last_Year.Value, "CustomerSales") < 1000000, "0,K", "0,,M"))
Public Function LabelCustomFormat(ByVal CY As Integer, ByVal LY As Integer) As String
If CY > LY Then
If(CY < 1000000) THEN
Return "0,K"
Else
Return "0,,M"
End If
Else
IF(LY < 1000000) THEN
Return "0,K"
Else
Return "0,,M"
End If
End If
End Function
Is it possible to have the different scale in one Axis of a Chart? If so, please help.

Well after trying to make a dynamic scale in the axis without success, I left the label format with the expression 0,,M and set the interval to a 1M instead of 500K.

Related

past date straight line linear regression indicator with added rate of return (price/time) of the regression

I am trying to make an indicator out of the --straight line-- linear regression pinescript drawing tool included in tradingview (not their regression channel tool or any type least squares moving average/moving regression which plots a continuous curved line). I wish to see one straight line through the chart prices defined in the custom time period input. The plot of this straight line will have acustom start time and length to define the end (or even better an end time instead f length). Next, I wish to add a rate of return feature by taking the total price move of the straight regression line from beginning to end, divided by # of time periods between the start and end date. I have tried the code seen here but I am getting a curved line, not straight. Then for the next step, I am not sure how to get the start and end price point of the regression line to divide by the total time period.
//#version=4
study("lreg ", shorttitle="run-ave", overlay=true)
timeYear = input(2022, title="Year", minval=1991, maxval=2100, type=input.integer)
timeMonth = input(1, title="Month", minval=1, maxval=12, type=input.integer)
timeDay = input(04, title="Day", minval=1, maxval=31, type=input.integer)
timeHours = input(9, title="Hours", minval=0, maxval=23, type=input.integer)
timeMinutes = input(30, title="Minutes", minval=0, maxval=59, type=input.integer)
timeSeconds = input(0, title="Seconds", minval=0, maxval=59, type=input.integer)
length = input(14)
// Initilization of variables only once
var delta = 0
// start time at 0 from a particular time interval
if(year == timeYear and month == timeMonth and dayofmonth == timeDay and hour == timeHours and minute == timeMinutes and second == timeSeconds)
delta := 0
// Count number of bars
if(year >= timeYear and month >= timeMonth and dayofmonth > timeDay)
delta += 1
plotchar(delta, title="days passed from startdate", color=color.green, char='')
// rate of change and moving average of ROC
source = input(close, "Source")
float lreg = na
float lregg = 0
if delta >= 1
lreg:= linreg(close, length, offset=0)
plot(lreg)

How to calculate values using for-end and if-else in Octave?

I need to calculate variable Nfj in the following equation:
ea_M = (sf/E)*(2*Nfj)^b + ef*(2*Nfj)^c
so that it is equal to 4 different values of ea: 5.0900e-04, 4.3626e-04, 3.6358e-04, and 2.9084e-04. The results should be 4 values of Nfj which should be stored in results. I am rounding because I think that it is not possible to calculated exactly equal values of ea, without rounding the equality would always be false.
I wrote for it this code, but it does not work as expected: the script runs for a very long time without any results. How can I fix it to work correctly?
sf = 882.07;
ef = 0.59;
b = -0.102969;
c = -0.58;
E = 210000;
ea = [5.0900e-04; 4.3626e-04; 3.6358e-04; 2.9084e-04]
for pos = 1:length(ea)
for Nfj = 1e3:10:1e12
ea_M = (sf/E)*(2*Nfj)^b + ef*(2*Nfj)^c;
if round(ea_M * 10^5)/10^5 == round(ea(pos) * 10^5)/10^5;
disp(ea_M)
disp(Nfj)
results(pos) = Nfj;
end
end
end
You are trying every 10th value, from 103 to 1012: there are 1011 values here to try! This is of course a lot. You will be searching for ever, and you might skip the actual value that would make the equality true.
If you are not able to solve the equation manually, you can use a numerical solver. Let's first print the function:
sf = 882.07;
ef = 0.59;
b = -0.102969;
c = -0.58;
E = 210000;
ea_M = #(Nfj) (sf/E)*(2*Nfj).^b + ef*(2*Nfj).^c;
Nfj = logspace(3,12,1000);
plot(Nfj, ea_M(Nfj))
set(gca, 'xscale', 'log')
It looks like this function is nicely monotonic, and the four values you are looking for are in the interval of 103 to 1012 you were searching. To find where it equals one of your values, we can subtract that value and find where it equals zero. You can very quickly narrow down your search if you start at a point where the function is larger than zero, and one where it is smaller than zero. You halve the interval every time, keeping the half of the interval that contains the zero crossing. The fzero function does just this.
ea = [5.0900e-04; 4.3626e-04; 3.6358e-04; 2.9084e-04];
results = zeros(size(ea));
for pos = 1:numel(ea)
results(pos) = fzero(#(Nfj) ea_M(Nfj) - ea(pos), [1e3,1e12]);
end
results
In MATLAB, this code runs in a small fraction of a second and outputs:
results =
1.0e+10 *
0.0429
0.1849
1.0627
9.1919
and ea_M(results) - ea is approximately zero.
A few notes on the code I posted here:
ea_M is defined as an anonymous function. This makes it easier to reuse the expression, rather than writing it over and over again. I replaced ^ with .^ to allow this function to do the computation on an array of Nfj values at once, rather than only single values. This is necessary for the fzero call.
I plotted the function on a logarithmic scale, because this function calls for that. The same is not true for all functions.
I preallocated the results array, you should avoid increasing the size of an array in a loop.

Format number with variable amount of significant figures depending on size

I've got a little function that displays a formatted amount of some number value. The intention is to show a "commonsense" amount of significant figures depending on the size of the number. So for instance, 1,234 comes out as 1.2k while 12,345 comes out as 12k and 123,456 comes out as 123k.
So in other words, I want to show a single decimal when on the lower end of a given order of magnitude, but not for larger values where it would just be useless noise.
I need this function to scale all the way from 1 to a few billion. The current solution is just to branch it:
-- given `current`
local text = (
current > 9,999,999,999 and ('%dB') :format(current/1,000,000,000) or
current > 999,999,999 and ('%.1fB'):format(current/1,000,000,000) or
current > 9,999,999 and ('%dM') :format(current/1,000,000) or
current > 999,999 and ('%.1fM'):format(current/1,000,000) or
current > 9,999 and ('%dk') :format(current/1,000) or
current > 999 and ('%.1fk'):format(current/1,000) or
('%d'):format(current) -- show values < 1000 floored
)
textobject:SetText(text)
-- code formatted for readability
Which I feel is very ugly. Is there some elegant formula for rounding numbers in this fashion without just adding another (two) clauses for every factor of 1000 larger I need to support?
I didn't realize how simple this actually was until a friend gave me a solution (which checked the magnitude of the number based on its length). I converted that to use log to find the magnitude, and now have an elegant working answer:
local suf = {'k','M','B','T'}
local function clean_format(val)
if val == 0 then return '0' end -- *Edit*: Fix an error caused by attempting to get log10(0)
local m = math.min(#suf,math.floor(math.log10(val)/3)) -- find the magnitude, or use the max magnitude we 'understand'
local n = val / 1000 ^ m -- calculate the displayed value
local fmt = (m == 0 or n >= 10) and '%d%s' or '%.1f%s' -- and choose whether to apply a decimal place based on its size and magnitude
return fmt:format(n,suf[m] or '')
end
Scaling it up to support a greater factor of 1000 is as easy as putting the next entry in the suf array.
Note: for language-agnostic purposes, Lua arrays are 1-based, not zero based. The above solution would present an off-by-one error in many other languages.
Put your ranges and their suffixes inside a table.
local multipliers = {
{10^10, 'B', 10^9},
{10^9, 'B', 10^9, true},
{10^7, 'M', 10^6},
{10^6, 'M', 10^6, true},
{10^4, 'k', 10^3},
{10^3, 'k', 10^3, true},
{1, '', 1},
}
The optional true value at the 4th position of alternate variables is for the %.1f placeholder. The third index is for the divisor.
Now, iterate over this table (using ipairs) and format accordingly:
function MyFormatter( current )
for i, t in ipairs( multipliers ) do
if current >= t[1] then
local sHold = (t[4] and "%.1f" or "%d")..t[2]
return sHold:format( current/t[3] )
end
end
end

dynamic tables or arrays

I have a function that is meant to dynamically change the size of a 3D Array or table but it keeps breaking saying that it return value nil because it is out of bounds. Here is the code for it:
function resize()
temp = { }
for h=1, height do
table.insert( temp , { } )
for y=1, length do
table.insert ( temp[h], { } )
for x=1, width do
num = 16
if #blocks <= height then
if #blocks[h] <= length then
if #blocks[h][y] <= width then
num = blocks[h][y][x]
end
end
end
table.insert( temp[h][y] , num )
end
end
end
blocks = temp
end
I know it's not very well commented but the idea is that it creates a new table with the changed dimensions, and then superimpose the data of blocks over the new table and finally overwriting blocks with the new temp table.
The length width and height are changed by one either incremented or decremented but only one at a time.
I'm not sure if I explained it clearly enough, if not let me know and I'll try explain in more detail.
Thanks all,
James
I think that the bug lies in your if statements. You should sizes of blocks against h, y and x, not height and length and width.
As a side note, do not use table.insert when you can substitute it with temp[h] = {}. It's faster. Also, try to use locals for temp storage.
Your specific error (probably)
You do not test against nil values. Any non-initialized table (= array in this case) members are nil by definition. And comparing nil with a number will generate an error:
lua: attempt to compare nil with number
However, as you seem unable to provide the actual error message, this is only a guess. Do not take me wrong these are errors in your code, but there could be something else wrong that I overlooked. Anyway here are some comments along with your code to show you what happens
if #blocks <= height then -- say #blocks is 3, height is 4
if #blocks[h] <= length then -- E: in iteration 4 blocks[h] is nil
if #blocks[h][y] <= width then -- E: in it. 3,4 blocks[h][y] is nil
num = blocks[h][y][x]
end
end
end
You would have to test against nil on every level first, like
if blocks[h] and blocks[h][y] and blocks[h][y][x] and
#blocks[h]<=height and #blocks[h][y]<=height and #blocks[h][y][x]<=height
num = blocks[h][y][x]
end
General programming mistakes
blocks, length, width and height seem to be parameters for your function but are not in its header, so I suppose you set them externally before calling the function? This is certainly not good practice.
temp and num should be declared local.
Alternative
You can make the data-structure more intelligent, for example, if you put your 3D array in a flattened table and add a __call metamethod like this
function newMdArray(X, Y, Z)
local MT = { __call = function(t, x, y, z, v)
if x>X or y>Y or z>Z or x<1 or y<1 or z<1 then return nil end
local k = x + X*(y-1) + X*Y*(z-1);
if v ~= nil then t[k] = v; end
return t[k]
end };
return setmetatable({}, MT);
end
Then this is all you have to do to make a resized copy of it:
function resizeMdArray(array, X, Y, Z)
local r = newMdArray(X, Y, Z);
for x=1, X do
for y=1, Y do
for z=1, Z do
r(x, y, z, array(x, y, z) or 16);
end
end
end
return r;
end
A nice bonus is, since this data structure flattens the 3D array into a 1D array, if you only want to copy the data, you can do so by simply accessing it as a table and copying each element:
for i=1, X*Y*Z do
new[i] = old[i]
end
Of course you could do the very same with a "real" (hidden) 3-D array in the background saving you the arithmetic calculations, however then you would have to test for empty values all the time to prevent nil errors.
Well I'm not sure if this is the best way to do it, but it does work.
function resize()
temp = { } -- temp table
-- inserting all the height levels
for h=1, height do table.insert( temp , { } ) end
-- inserting all the lengths
for h=1, height do
for l=1, length do table.insert( temp[h], { } ) end
end
-- inserting all the width and defaulting them to 0
for h=1, height do
for l=1, length do
for w=1, width do table.insert( temp[h][l] , 0 ) end
end
end
-- if the canvas size is increasing
if #blocks <= height then
if #blocks[1] <= length then
if #blocks[1][1] <= width then
for h=1, #blocks do
for l=1, #blocks[1] do
for w=1, #blocks[1][1] do
-- fill in data from blocks
temp[h][l][w] = blocks[h][l][w]
end
end
end
end
end
end
--if the canvas size is decreasing
if #blocks >= height then
if #blocks[1] >= length then
if #blocks[1][1] >= width then
for h=1, #temp do
for l=1, #temp[1] do
for w=1, #temp[1][1] do
-- fill in data from blocks but not the last value
temp[h][l][w] = blocks[h][l][w]
end
end
end
end
end
end
-- overwrite blocks with the new dimensions
blocks = temp

How to compute Fourier coefficients with MATLAB

I'm trying to compute the Fourier coefficients for a waveform using MATLAB. The coefficients can be computed using the following formulas:
T is chosen to be 1 which gives omega = 2pi.
However I'm having issues performing the integrals. The functions are are triangle wave (Which can be generated using sawtooth(t,0.5) if I'm not mistaking) as well as a square wave.
I've tried with the following code (For the triangle wave):
function [ a0,am,bm ] = test( numTerms )
b_m = zeros(1,numTerms);
w=2*pi;
for i = 1:numTerms
f1 = #(t) sawtooth(t,0.5).*cos(i*w*t);
f2 = #(t) sawtooth(t,0.5).*sin(i*w*t);
am(i) = 2*quad(f1,0,1);
bm(i) = 2*quad(f2,0,1);
end
end
However it's not getting anywhere near the values I need. The b_m coefficients are given for a
triangle wave and are supposed to be 1/m^2 and -1/m^2 when m is odd alternating beginning with the positive term.
The major issue for me is that I don't quite understand how integrals work in MATLAB and I'm not sure whether or not the approach I've chosen works.
Edit:
To clairify, this is the form that I'm looking to write the function on when the coefficients have been determined:
Here's an attempt using fft:
function [ a0,am,bm ] = test( numTerms )
T=2*pi;
w=1;
t = [0:0.1:2];
f = fft(sawtooth(t,0.5));
am = real(f);
bm = imag(f);
func = num2str(f(1));
for i = 1:numTerms
func = strcat(func,'+',num2str(am(i)),'*cos(',num2str(i*w),'*t)','+',num2str(bm(i)),'*sin(',num2str(i*w),'*t)');
end
y = inline(func);
plot(t,y(t));
end
Looks to me that your problem is what sawtooth returns the mathworks documentation says that:
sawtooth(t,width) generates a modified triangle wave where width, a scalar parameter between 0 and 1, determines the point between 0 and 2π at which the maximum occurs. The function increases from -1 to 1 on the interval 0 to 2πwidth, then decreases linearly from 1 to -1 on the interval 2πwidth to 2π. Thus a parameter of 0.5 specifies a standard triangle wave, symmetric about time instant π with peak-to-peak amplitude of 1. sawtooth(t,1) is equivalent to sawtooth(t).
So I'm guessing that's part of your problem.
After you responded I looked into it some more. Looks to me like it's the quad function; not very accurate! I recast the problem like this:
function [ a0,am,bm ] = sotest( t, numTerms )
bm = zeros(1,numTerms);
am = zeros(1,numTerms);
% 2L = 1
L = 0.5;
for ii = 1:numTerms
am(ii) = (1/L)*quadl(#(x) aCos(x,ii,L),0,2*L);
bm(ii) = (1/L)*quadl(#(x) aSin(x,ii,L),0,2*L);
end
ii = 0;
a0 = (1/L)*trapz( t, t.*cos((ii*pi*t)/L) );
% now let's test it
y = ones(size(t))*(a0/2);
for ii=1:numTerms
y = y + am(ii)*cos(ii*2*pi*t);
y = y + bm(ii)*sin(ii*2*pi*t);
end
figure; plot( t, y);
end
function a = aCos(t,n,L)
a = t.*cos((n*pi*t)/L);
end
function b = aSin(t,n,L)
b = t.*sin((n*pi*t)/L);
end
And then I called it like:
[ a0,am,bm ] = sotest( t, 100 );
and I got:
Sweetness!!!
All I really changed was from quad to quadl. I figured that out by using trapz which worked great until the time vector I was using didn't have enough resolution, which led me to believe it was a numerical issue rather than something fundamental. Hope this helps!
To troubleshoot your code I would plot the functions you are using and investigate, how the quad function samples them. You might be undersampling them, so make sure your minimum step size is smaller than the period of the function by at least factor 10.
I would suggest using the FFTs that are built-in to Matlab. Not only is the FFT the most efficient method to compute a spectrum (it is n*log(n) dependent on the length n of the array, whereas the integral in n^2 dependent), it will also give you automatically the frequency points that are supported by your (equally spaced) time data. If you compute the integral yourself (might be needed if datapoints are not equally spaced), you might calculate frequency data that are not resolved (closer spacing than 1/over the spacing in time, i.e. beyond the 'Fourier limit').