How to read and update the lowlimit and highlimit value of lineplot/dataplot? - dm-script

I try to write a code, that can read change the highlimit value (the highest value of Y axis) of linePlot/dataPlot. As shown as below, it is not working. It looks like that we cannot read the high limit value of a line plot by “number highlimit= imgdisp.linePlotImageDisplaySetContrastLimits(highlimit)”, how can read this value from a lineplot? Thanks
number linelen=len(headerline)
number i, nocommas=0
for(i=0; i<linelen; i++)
{
string thischar=mid(headerline, i, 1)
if(asc(thischar)==44) nocommas=nocommas+1 // found a comma
}
number xsize, ysize
getsize(array, xsize, ysize)
image dataplot=realimage("", 4, xsize,1)
showimage(dataplot)
setname(dataplot, imgname)
imagedisplay imgdisp=dataplot.imagegetimagedisplay(0)
number highlimit= imgdisp.linePlotImageDisplaySetContrastLimits(highlimit)
if( highlimit<50){imgdisp.linePlotImageDisplaySetContrastLimits( 0, 400)
imgdisp.LinePlotImageDisplaySetDoAutoSurvey( 0, 0 )}

Several things here:
1)
Generally, each "Set" command has an according "Get" command as well. So, the script command to read the current display-limits simply is
linePlotImageDisplayGetContrastLimits()
2)
Setting contrast limits only works if auto-surveying is switched off. You have to switch it off before you set the limits. (If you set the limits first, they are immediately replaced by the values from the survey, so you see no effect.)
3)
I am not sure what you really want to set/get. Do you want to get the maximum value of the data, or the display limit?
The maximum value is simply got by max( ) .
The DisplayLimits define the range on the y-axis, i.e. they set the value you can also specify in the properties of the display as below, they are independent of what values you have in the data:
Display limits set to 0 - 500. (Maximum data value = 500)
Display limits set to 0 - 1000. (Maximum data value = 500)
Display properties dialog.
Here is some example code of how to set and read the display limits:
image spec := RealImage( "", 4, 500 )
spec = 20 + random() * icol
spec.ShowImage()
number maxV = max(spec)
imageDisplay LPID = spec.ImageGetImageDisplay(0)
LPID.LinePlotImageDisplaySetDoAutoSurvey( 0, 0 ) // switch survey off
LPID.LinePlotImageDisplaySetContrastLimits( 0, maxV*2 ) // Set the display
number lowL, highL
LPID.LinePlotImageDisplayGetContrastLimits( lowL, highL )
Result( "\n Maximum value in data:" + maxV )
Result( "\n Data display range:" + lowL + " to " + highL )

Related

compare values in an table in lua

I need help. I am having an table like this:
local dict = {}
dict[1] = {achan = '7f', aseq='02'} --ACK
dict[2] = {dchan = '7f', dseq='03'} --DATA
dict[3] = {achan = '7f', aseq='03'} --ACK
dict[4] = {dchan = '7f', dseq='04'} --DATA
dict[5] = {achan = '7f', aseq='04'} --ACK
dict[6] = {dchan = '7f', dseq='02'} --DATA
Basically I am using this in an Dissector so I don't know the Index except the one I am actually "standing" at the moment.
So what I want to have is:
if the "achan" and the "dchan" is the same and the "aseq" i am standing at the moment is the same as an "dseq" value on positions from the past which are already saved into the table then it should give me back the index from the same "dseq" value from the past.
if (dict[position at the moment].achan == dict[?].dchan) and (dict[position at the moment].aseq == dict[?].dseq) then
return index
end
for example: dchan from position 6 is the same es achan from position 1 and dseq from position 6 is the same as aseq from position 1. So I want to get the position 1 back
You can use a numeric for loop with a negative step size to go back in your table, starting from the previous element. Check wether the achan and aseq fields exist, then compare them vs the dchan and dseq fields of your current entry.
function getPreviousIndex(dict, currentIndex)
for i = currentIndex - 1, 1, -1 do
if dict[i].achan and dict[currentIndex].dchan
and dict[i].achan == dict[currentIndex].dchan
and dict[i].aseq and dict[currentIndex].dseq
and dict[i].aseq == dict[currentIndex].dseq then
return i
end
end
end
This code assumes you have no gaps in your table. You should also add some error handling that makes sure you actually are at a dchan entry and that your index is in range and so on...

Lua (And SQL) Error, attempt to call a boolean value

So I'm getting this error while making an addon for Garrys mod, I've been trying for a while but can't quite figure this error out:
[ERROR] addons/ted_stockmarket/lua/autorun/server/stockmarket_init.lua:6: attempt to call a boolean value
1. loadcompany - addons/ted_stockmarket/lua/autorun/server/stockmarket_init.lua:6
2. unknown - addons/ted_stockmarket/lua/autorun/server/stockmarket_init.lua:20
3. unknown - lua/includes/modules/concommand.lua:54
Files are included in full so line numbers will be exact, doing on pastebin because I can't figure out the formatting on this right now. The code is kind of all over the place, I haven't touched this is a while and half of the stuff in the file is bound to be replaced
include("stockmarketprices.lua")
include("stockmarket_config.lua")
local function loadcompany(cmp)
if cmp != nil and sql.TableExists("stockmarket_sharedata") then sql.Query("INSERT INTO stockmarket_sharedata (Companyshort, Company, Shares, Value) VALUES ('"..cmp[2]..", "..cmp[3]..", "..cmp[4]..", "..cmp[5])"')"
end
end
local function test()
if !sql.TableExists(stockmarket_sharedata) then
print("Stock market performing initial load...")
sql.Query( "CREATE TABLE stockmarket_sharedata ( Companyshort string not null, Company string not null, Shares string not null, Value int not null, Rate decimal not null)" )
print("Stock market done loading, restart your server to apply changes.")
end
if stock1[1] == 1 then loadcompany(stock1)
print(stock1[3].." is done loading!")
end
end
hook.Add("Initialize", "First Load", test)
function sharepricechange(shortname, chance, low, high, direction)
if math.random(1, 100) <= chance then shortname.marketbump = math.random(low, high) end
end
hook.Add( "PlayerSay", "chatcommands", function( ply, text )
local text = string.lower( text )
local amount = tonumber(string.sub(text, 16))
local shares = tonumber(file.Read("stockmarket/lifeinsuranceshrs.txt"))
if string.sub(text, 1, 14) == "/buyshares ins" and amount <= shares then
file.Write("stockmarket/lifeinsuranceshrs.txt", ((tonumber(file.Read("stockmarket/lifeinsuranceshrs.txt"))) - tonumber(string.sub(text, 16))))
print("You have invested! There are now "..file.Read("stockmarket/lifeinsuranceshrs.txt").. " shares left for life insurance")
else end
if text == "/stockmarkethelp" then
ply:PrintMessage(HUD_PRINTCONSOLE, [[ /buyshares "company" "amount" - Purchase a specified amount of shares from a specified company.
/stockmarket - Prints all information about the stock market in console.]])
return("") end
end)
function ResetStockmarket(ply)
if ply:IsUserGroup("superadmin") then
local files, directories = file.Find( "*", "DATA")
print(files[1])
file.Delete("stockmarket")end
if !ply:IsUserGroup("superadmin") then ply:PrintMessage( HUD_PRINTCONSOLE, "You are not the right rank to use this command" )
end
end
concommand.Add( "stockmarket_reset", ResetStockmarket)
concommand.Add( "stockmarket_test", test)
pastebin.com/ERFfnbMc
stock1 = { -- DO NOT CHANGE THE TABLE IDENTIFIER
1, -- First line, determine whether or not you want this company to work
"FLN", -- The shortname of the company, keep 3 letters for consistency
"Flynn's Funerals", -- The name of the company
10000, -- The default amount of shares avaliable
94, -- The starting price of each share
0 -- The rate of the shares change in value, do not touch this.
}
pastebin.com/jbJseUWC

Make line chart with values and dates

In my app i use ios-charts library (swift alternative of MPAndroidChart).
All i need is to display line chart with dates and values.
Right now i use this function to display chart
func setChart(dataPoints: [String], values: [Double]) {
var dataEntries: [ChartDataEntry] = []
for i in 0..<dataPoints.count {
let dataEntry = ChartDataEntry(value: values[i], xIndex: i)
dataEntries.append(dataEntry)
}
let lineChartDataSet = LineChartDataSet(yVals: dataEntries, label: "Items count")
let lineChartData = LineChartData(xVals: dataPoints, dataSet: lineChartDataSet)
dateChartView.data = lineChartData
}
And this is my data:
xItems = ["27.05", "03.06", "17.07", "19.09", "20.09"] //String
let unitsSold = [25.0, 30.0, 45.0, 60.0, 20.0] //Double
But as you can see - xItems are dates in "dd.mm" format. As they are strings they have same paddings between each other. I want them to be more accurate with real dates. For example 19.09 and 20.09 should be very close. I know that i should match each day with some number in order to accomplish it. But i don't know what to do next - how i can adjust x labels margins?
UPDATE
After small research where i found out that many developers had asked about this feature but nothing happened - for my case i found very interesting alternative to this library in Swift - PNChart. It is easy to use, it solves my problem.
The easiest solution will be to loop through your data and add a ChartDataEntry with a value of 0 and a corresponding label for each missing date.
In response to the question in the comments here is a screenshot from one of my applications where I am filling in date gaps with 0 values:
In my case I wanted the 0 values rather than an averaged line from data point to data point as it clearly indicates there is no data on the days skipped (8/11 for instance).
From #Philipp Jahoda's comments it sounds like you could skip the 0 value entries and just index the data you have to the correct labels.
I modified the MPAndroidChart example program to skip a few data points and this is the result:
As #Philipp Jahoda mentioned in the comments the chart handles missing Entry by just connecting to the next data point. From the code below you can see that I am generating x values (labels) for the entire data set but skipping y values (data points) for index 11 - 29 which is what you want. The only thing remaining would be to handle the x labels as it sounds like you don't want 15, 20, and 25 in my example to show up.
ArrayList<String> xVals = new ArrayList<String>();
for (int i = 0; i < count; i++) {
xVals.add((i) + "");
}
ArrayList<Entry> yVals = new ArrayList<Entry>();
for (int i = 0; i < count; i++) {
if (i > 10 && i < 30) {
continue;
}
float mult = (range + 1);
float val = (float) (Math.random() * mult) + 3;// + (float)
// ((mult *
// 0.1) / 10);
yVals.add(new Entry(val, i));
}
What I did is fully feed the dates for x data even no y data for it, and just not add the data entry for the specific xIndex, then it will not draw the y value for the xIndex to achieve what you want, this is the easiest way since you just write a for loop and continue if you detect no y value there.
I don't suggest use 0 or nan, since if it is a line chart, it will connect the 0 data or bad things will happen for nan. You might want to break the lines, but again ios-charts does not support it yet (I also asked a feature for this), you need to write your own code to break the line, or you can live with connecting the 0 data or just connect to the next valid data.
The down side is it may has performance drop since many xIndex there, but I tried ~1000 and it is acceptable. I already asked for such feature a long time ago, but it took lot of time to think about it.
Here's a function I wrote based on Wingzero's answer (I pass NaNs for the entries in the values array that are empty) :
func populateLineChartView(lineChartView: LineChartView, labels: [String], values: [Float]) {
var dataEntries: [ChartDataEntry] = []
for i in 0..<labels.count {
if !values[i].isNaN {
let dataEntry = ChartDataEntry(value: Double(values[i]), xIndex: i)
dataEntries.append(dataEntry)
}
}
let lineChartDataSet = LineChartDataSet(yVals: dataEntries, label: "Label")
let lineChartData = LineChartData(xVals: labels, dataSet: lineChartDataSet)
lineChartView.data = lineChartData
}
The solution which worked for me is splitting Linedataset into 2 Linedatasets. First would hold yvals till empty space and second after emptyspace.
//create 2 LineDataSets. set1- till empty space set2 after empty space
set1 = new LineDataSet(yVals1, "DataSet 1");
set2= new LineDataSet(yVals2,"DataSet 1");
//load datasets into datasets array
ArrayList<ILineDataSet> dataSets = new ArrayList<ILineDataSet>();
dataSets.add(set1);
dataSets.add(set2);
//create a data object with the datasets
LineData data = new LineData(xVals, dataSets);
// set data
mChart.setData(data);

epplus: How do I get a row's height after setting column's wraptext style to true?

After I set a column's WrapText=true, I want to see what the new height of the row will be (i.e. if the text wraps, for how many lines). It appears that the Height property of a row is not updated.
ExcelPackage pkg = new ExcelPackage();
ExcelWorksheet sheet = pkg.Workbook.Worksheets.Add("Test");
// height is 15.0
double heightBefore = sheet.Row(1).Height;
sheet.Cells[1, 1].Value = "Now is the time for all good men to come to the aid of their country";
ExcelColumn col = sheet.Column(1);
// this will resize the width to 60
col.AutoFit();
if (col.Width > 50)
{
col.Width = 50;
// this is just a style property, and doesn't actually execute any recalculations
col.Style.WrapText = true;
}
// so this is still 15.0. How do I get it to compute what the size will be?
double heightAfter = sheet.Row(1).Height;
// open the xls, and the height is 30.0
pkg.SaveAs(new System.IO.FileInfo("text.xlsx"));
In fact, a search for the Height property (or the underlying field _height) shows that it is only set by the property setter, and does not ever seem to be set based on anything else (like content in the row).
Any ideas on how I can get a refreshed Height for a row?
Thanks
The general pattern I've noticed with EPPlus is that it generates the framework of the document with the minimum amount of information necessary. Then, when you open the file, Excel fills out the remaining XML structure, which is why you always have to save the file after opening an EPPlus generated document.
For your question, I'm assuming that Excel is updating the row heights after you open the Excel file so EPPlus would not have the updated row height information. I'm not absolutely certain that the library doesn't support this, but like you I was unable to find a way to get the updated values.
One workaround however could be to just calculate what the value would be since you know your text length and column width:
ExcelPackage pkg = new ExcelPackage();
ExcelWorksheet sheet = pkg.Workbook.Worksheets.Add("Test");
// height is 15.0
double heightBefore = sheet.Row(1).Height;
var someText = "Now is the time for all good men to come to the aid of their country. Typewriters were once ground-breaking machines.";
sheet.Cells[1, 1].Value = someText;
ExcelColumn col = sheet.Column(1);
ExcelRow row = sheet.Row(1);
// this will resize the width to 60
col.AutoFit();
if (col.Width > 50)
{
col.Width = 50;
// this is just a style property, and doesn't actually execute any recalculations
col.Style.WrapText = true;
}
// calculate the approximate row height and set the value;
var lineCount = GetLineCount(someText, (int)col.Width);
row.Height = heightBefore * lineCount;
// open the xls, and the height is 45.0
pkg.SaveAs(new System.IO.FileInfo("text.xlsx"));
Here's the method to calculate the number of lines:
private int GetLineCount(String text, int columnWidth)
{
var lineCount = 1;
var textPosition = 0;
while (textPosition <= text.Length)
{
textPosition = Math.Min(textPosition + columnWidth, text.Length);
if (textPosition == text.Length)
break;
if (text[textPosition - 1] == ' ' || text[textPosition] == ' ')
{
lineCount++;
textPosition++;
}
else
{
textPosition = text.LastIndexOf(' ', textPosition) + 1;
var nextSpaceIndex = text.IndexOf(' ', textPosition);
if (nextSpaceIndex - textPosition >= columnWidth)
{
lineCount += (nextSpaceIndex - textPosition) / columnWidth;
textPosition = textPosition + columnWidth;
}
else
lineCount++;
}
}
return lineCount;
}
One thing to keep in mind is that Excel has a max row height of 409.5 so you'll want to make sure your column width is not so narrow that you'll reach this limit.
Also, another thing I noticed is that the column widths that you manually set with EPPlus don't actually set the columns to the expected value. For example, if you set your column width to 50, you'll notice that the actual column width is set to 49.29 so you may want to factor that in as well.

Role on dynamic google chart (interval)

How can I use this: https://developers.google.com/chart/interactive/docs/roles if I populate the graph dynamically?
This is part of my code:
...
data.addRows(dates.length);
for (i = 0; i < dates.length; i++){
if (i!=0){
data.setValue( i, 0, new Date(dates[i]) );
temp = graph[dates[i]];
var j = 0;
if (temp){
for (j = 0; j < groups.length; j++){
if ( groups[j] in temp){
var volume = parseFloat(temp[groups[j]]);
console.log(i + ' ' + j + ' ' + volume);
data.setValue( i, j+1, volume )
}
}
}
}else{
data.setValue( i, 0, new Date(dates[i]) );
var j = 0;
for (j = 0; j < groups.length; j++){
data.setValue( 0, j+1, 0 )
}
}
}
...
After I set the value with 'data.setValue', how can I set also the role? (I need for the interval value) Something like 'data.setRole' would be wonderful!! :-)
You can create the DataTable without any roles, and then create a DataView that assigns roles to the columns in the view. The documentation shows how to do this here:
DataView.setColumns Method
When creating a view, you can explicitly set the role of a column.
This is useful when creating a new calculated column. See
DataView.setColumns() for more information.
The DataView.setColumns() help file explains how to do this as follows:
setColumns(columnIndexes)
columnIndexes - An array of numbers and/or objects (can be mixed):
Numbers specify the index of the source data column to include in the view. The data is brought through unmodified. If you
need to explicitly define a role or additional column properties,
specify an object with a sourceColumn property.
Objects specify a calculated column. A calculated column creates a
value on the fly for each row and adds it to the view. The object
must have the following properties:
calc [function] - A function that will be called for each row in the column to calculate a value for that cell. The function
signature is func(dataTable, row), where dataTable is the source
DataTable, and row is the index of the source data row. The
function should return a single value of the type specified by
type.
type [string] - The JavaScript type of the value that the calc function returns.
label [Optional, string] - An optional label to assign to this generated column. If not specified, the view column will have no
label.
id [Optional, string] - An optional ID to assign to this generated column.
sourceColumn - [Optional, number] The source column to use as a value; if specified, do not specify the calc or the type property.
This is similar to passing in a number instead of an object, but
enables you to specify a role and properties for the new column.
properties [Optional, object] - An object containing any arbitrary properties to assign to this column. If not specified, the view
column will have no properties.
role [Optional, string] - A role to assign to this column. If not specified, the existing role will not be imported.
So if your interval column is column #3, for instance, you would say:
dataView.setColumns([0, 1, {sourceColumn: 2, role: 'interval'}]);
The above sets columns 0, and 1 as-is, without a role, while column 2 is assigned as an interval column.
EDIT
Responding to the comments, the intervals are in the data set. Here is an example:
function drawVisualization() {
// Create and populate the data table.
var data = google.visualization.arrayToDataTable([
['Year', 'Austria', 'Interval A', 'Interval B'],
['2003', 100, 95, 125],
['2004', 110, 96, 150],
['2005', 120, 97, 175],
['2006', 130, 98, 200],
['2007', 140, 99, 225],
['2008', 150, 100, 250]
]);
// Create Data View using columns 2 & 3 as intervals
var dataView = new google.visualization.DataView(data);
dataView.setColumns([0, 1, {sourceColumn: 2, role: 'interval'}, {sourceColumn: 3, role: 'interval'}]);
// Create and draw the visualization.
new google.visualization.LineChart(document.getElementById('visualization')).
draw(dataView,
{width:600, height:400,
hAxis: {title: "Year"}}
);
}
You include the interval values in the original data table as columns. You then use a dataview to change those columns to 'interval' role columns. Then you draw the dataview. This will provide error bars (interval columns) as expected.