Gnuplot for loop with continous variables - variables

I have a plot with many objects and labels. So I wanted to simplify the srcipt using loops. But I don't know how to adress the variables. I define the variables as followed
V1 = 10
V2 = 20
V3 = 23
...
LABEL1 = a
LABEL2 = b
...
The loop should look something like that
set for [i=1:15] label i at V(i),y_label LABEL(i)
This notation leads to errors compiling the script. Is it possiple at all to define such a loop in gnuplot? If so how can I do it?
Thanks for your help!

You can define a function which formats the label-definition as string and use a do loop to evaluate the strings:
y_label = 0
V1 = 10
V2 = 20
V3 = 23
LABEL1 = "a"
LABEL2 = "b"
LABEL3 = "c"
do for [i=1:3] {
eval(sprintf('set label %d at V%d,y_label LABEL%d', i, i, i))
}
Alternatively, you can use two string with whitespace-separated words for the iteration:
V = "10 20 23"
LABEL = "a b c"
set for [i=1:words(V)] label i at word(V, i),y_label word(LABEL, i)
Note, that gnuplot 5.0 also has some limited support to use quote marks to hold several words together as one item:
V = "10 20 25"
LABEL = "'first label' 'second label' 'third one'"
set for [i=1:words(V)] label i at word(V, i),y_label word(LABEL, i)

Related

How to calculate the number of scatterplot data points in a particular 'region' of the graph

As my questions says I'm trying to find a way to calculate the number of scatterplot data points (pink dots) in a particular 'region' of the graph or either side of the black lines/boundaries. Open to any ideas as I don't even know where to start. Thank you!!
The code:
################################
############ GES ##############
################################
p = fits.open('GES_DR17.fits')
pfeh = p[1].data['Fe_H']
pmgfe = p[1].data['Mg_Fe']
pmnfe = p[1].data['Mn_Fe']
palfe = p[1].data['Al_Fe']
#Calculate [(MgMn]
pmgmn = pmgfe - pmnfe
ax1a.scatter(palfe, pmgmn, c='thistle', marker='.',alpha=0.8,s=500,edgecolors='black',lw=0.3, vmin=-2.5, vmax=0.65)
ax1a.plot([-1,-0.07],[0.25,0.25], c='black')
ax1a.plot([-0.07,1.0],[0.25,0.25], '--', c='black')
x = np.arange(-0.15,0.4,0.01)
ax1a.plot(x,4.25*x+0.8875, 'k', c='black')
Let's call the two axes x and y. Any line in this plot can be written as
a*x + b*y + c = 0
for some value of a,b,c. But if we plug in a points with coordinates (x,y) in to the left hand side of the equation above we get positive value for all points of the one side of the line, and a negative value for the points on the other side of the line. So If you have multiple regions delimited by lines you can just check the signs. With this you can create a boolean mask for each region, and just count the number of Trues by using np.sum.
# assign the coordinates to the variables x and y as numpy arrays
x = ...
y = ...
line1 = a1*x + b1*y + c1
line2 = a2*x + b2*y + c2
mask = (line1 > 0) & (line2 < 0) # just an example, signs might vary
count = np.sum(mask)

Label a set of objects with (A->Z,AA->ZZ, AAA->ZZZ) in VBA

I have a set which has an unknown number of objects. I want to associate a label to each one of these objects. Instead of labeling each object with a number I want to label them with letters.
For example the first object would be labeled A the second B and so on.
When I get to Z, the next object would be labeled AA
AZ? then BA, BB, BC.
ZZ? then AAA, AAB, AAC and so on.
I'm working using Mapbasic (similar to VBA), but I can't seem to wrap my head around a dynamic solution. My solution assumes that there will be a max number of objects that the set may or may not exceed.
label = pos1 & pos2
Once pos2 reaches ASCII "Z" then pos1 will be "A" and pos2 will be "A". However, if there is another object after "ZZ" this will fail.
How do I overcome this static solution?
Basically what I needed was a Base 26 Counter. The function takes a parameter like "A" or "AAA" and determines the next letter in the sequence.
Function IncrementAlpha(ByVal alpha As String) As String
Dim N As Integer
Dim num As Integer
Dim str As String
Do While Len(alpha)
num = num * 26 + (Asc(alpha) - Asc("A") + 1)
alpha = Mid$(alpha, 2,1)
Loop
N = num + 1
Do While N > 0
str = Chr$(Asc("A") + (N - 1) Mod 26) & str
N = (N - 1) \ 26
Loop
IncrementAlpha = str
End Function
If we need to convert numbers to a "letter format" where:
1 = A
26 = Z
27 = AA
702 = ZZ
703 = AAA etc
...and it needs to be in Excel VBA, then we're in luck. Excel's columns are "numbered" the same way!
Function numToLetters(num As Integer) As String
numToLetters = Split(Cells(1, num).Address(, 0), "$")(0)
End Function
Pass this function a number between 1 and 16384 and it will return a string between A and XFD.
Edit:
I guess I misread; you're not using Excel. If you're using VBA you should still be able to do this will the help of an reference to an Excel Object Library.
This should get you going in terms of the logic. Haven't tested it completely, but you should be able to work from here.
Public Function GenerateLabel(ByVal Number As Long) As String
Const TOKENS As String = "ZABCDEFGHIJKLMNOPQRSTUVWXY"
Dim i As Long
Dim j As Long
Dim Prev As String
j = 1
Prev = ""
Do While Number > 0
i = (Number Mod 26) + 1
GenerateLabel = Prev & Mid(TOKENS, i, 1)
Number = Number - 26
If j > 0 Then Prev = Mid(TOKENS, j + 1, 1)
j = j + Abs(Number Mod 26 = 0)
Loop
End Function

Excel ActiveX textbox - count characters or change case

Two days of continual failure. I am using a barcode system which has a barcode scanner which scans a barcode of alpha-numeric text and places it into an ActiveX textbox. It enters the text one letter at a time, and upon the completion of the entire barcode, it matches up to a Case selection, which then deletes the text in the box to get ready for the next scan.
The issue I happen to be facing is inside of the textbox. For whatever reason, the text goes into the textbox and occasionally ~ (1 time in one hour or 0 times in 8 hours) it will not complete the case. The exact text inside of the textbox which matches one of the cases is not counted and stays inside the box. At this point, any future scans are appended to the end of the text inside of the box.
Below is a sample of the variables, a case, and one of the events occuring based on case selection.
Variables
Private Sub TextBox1_Change()
Dim ws As Worksheet, v, n, t, b, c, e, f, h, j, k, i1, i2, i3, i4
Set ws = Worksheets("Sheet1")
v = TextBox1.Value
n = 0
t = 0
b = 0
c = 0
e = 0
f = 0
h = 0
j = 0
k = 0
i1 = 0
i2 = 0
i3 = 0
i4 = 0
Case
Select Case v
Case "2 in x 16 ft R -1": n = 9
t = 1
b = 10
c = 1
e = 11
f = 6
g = "2 in x 16 ft"
h = 40
j = 0.296
k = 1
Stuff that is done based on case type
'n = Sets the column reference for waste - not used?
't = Sets the cutting station column to be used (1,2,3) for the sq yards, row, and column of last scanned item for each station
'b = Sets the row reference for adding cut rolls waste + regular row reference for cut rolls
'c = Sets the column reference for adding cut rolls waste + regular column refernce for cut rolls
'e = Sets the column reference for taking 1 master roll out
'f = Sets the row reference for taking 1 master roll out
'g = name of the item being used for the time stamp
'h = Number of rolls coming out of the master roll
'j = The amount of Sq yards in the cut roll (to be used for waste)
'k = Case Selection
'i1 = Count for Cutting Station 1 timestamp, row reference
'i2 = Count for Cutting Station 2 timestamp, row reference
'i3 = Count for Cutting Station 3 timestamp, row reference
'i4 = Count for Cutting Station 1 timestamp, row reference - not used in this worksheet
If k = 1 And t = 1 Then
'Cutter 1 items
ws.Cells(1, t) = b
ws.Cells(2, t) = c
ws.Cells(3, t) = j
ws.Cells(4, t) = b
ws.Cells(5, t) = c
ws.Cells(6, t) = f
ws.Cells(7, t) = h
ws.Cells(b, c) = ws.Cells(b, c) + h
' adding different number based on case
ws.Cells(f, e) = ws.Cells(f, e) - 1
' always subtracts 1 from certain range based on case
i1 = ws.Cells(1, 30)
Cells(i1, 19).Value = Format(Now, "mm/dd/yyyy AM/PM h:mm:ss")
Cells(i1, 20).Value = g
TextBox1.Activate
TextBox1.Value = ""
Remember the text enters in one character at a time until the entire barcodes information is passed into the ActiveX textbox.
I can set a max length, but upon the max length it stays in the textbox. If I set the textbox to "", the next character in the barcode starts again and the append issue continues.
Is there a way to not have the case selection start upon the entry of each single character? Is there a way to have the textbox delete the extra information. If you set it to delete something which does not match a case, then it will delete anything entered since it puts one character in at a time.
Best regards,
Ford

How to convert text lines to variables?

Check out this list. I need each one turned into a variable and set equal to 0. Example:
;1-Methyoxy-2-Propanol would be:
$OneMethoxyTwoPropanol = 0
;and 1,2-BUTADIENE would be:
$OneTwoButadiene = 0
Assigning them to a variable wouldn't be a problem, but there are 1500 of them.
If i had to do this work i'll make it this way :
I'll change the case of each word :
Regex to change to sentence case
Make a "SearchAndReplace" :
1 -> One
2 -> Two
...
{underscore} -> ''
{space} -> ''
...
Then in a soft like SublimeText i'll add a $ in front of each line and a = 0 at the end. With the help of the Ctrl+Shift+L
Maybe you could use a regex to help you in the "SearchAndReplace" thing.
Something like this?
Local $sFilePath = #DesktopDir & "\test.ini"
Local $aArray = IniReadSection($sFilePath, "Variables")
Local $aVariablesArray[UBound($aArray)][2]
For $i = 1 To $aArray[0][0]
$aVariablesArray[$i][0] = $aArray[$i][0]
$aVariablesArray[$i][1] = $aArray[$i][1]
Next
For $i = 1 To UBound($aVariablesArray) -1
MsgBox(0, "", "Variable: " & $aVariablesArray[$i][0] & #CRLF & "Value: " & $aVariablesArray[$i][1])
Next
Your ini file should look like this
[Variables]
firstvariable=0
secondvariable=0
etc...=0
To create an ini file just open notepad, write down the file and then save it as .ini.
You can use RegEx to rename each file according to your needs.
The array created is a 2d array. It is needed to store the variable's name and value.
stringreplace and assign will do the job. If the amount of number to word replacements becomes too large you may consider storing those rather than nesting replace functions.
$sStr = "1-Methyoxy-2-Propanol" & #LF & "1,2-BUTADIENE"
$sStr = stringreplace(stringreplace(stringreplace(stringreplace($sStr , "," , "-") , "1-" , "One") , "2-" , "Two") , "-" , "")
$aStr = stringsplit($sStr , #LF , 2)
For $i = 0 to ubound($aStr) - 1
Assign($aStr[$i] , 0)
Next
msgbox(0, '' , Eval("OneMethyoxyTwoPropanol") & #LF & Eval("OneTwoBUTADIENE"))
I simply need to turn them into a variable and set them equal to 0.
As per Documentation - Intro - Arrays:
An Array is a variable containing a series of data elements. Each element in this variable can be accessed by an index number which relates to the position of the element within the Array - in AutoIt the first element of an Array is always element [0]. Arrays elements are stored in a defined order and can be sorted.
Removes lines containing list names (; List I etc.) and empty (or less than three character-) lines (as per $g_sRegexFilter). Stores remaining lines to 2D array-elements. Example:
#include <StringConstants.au3>
#include <FileConstants.au3>
#include <Array.au3>
Global Enum $ITEM_NAME, _
$ITEM_VALUE
Global Const $g_sFilePath = 'C:\list.txt'
Global Const $g_sFileNewline = #CRLF
Global Const $g_sRegexFilter = '(?m)^(.{0,2}\v)|(;.*\v)$'
Global Const $g_sItemHeader = 'name|value'
Global $g_sFileText = ''
Global $g_aFileItems
$g_sFileText = _TextFromFile($g_sFilePath)
$g_sFileText = StringRegExpReplace($g_sFileText, $g_sRegexFilter, '')
$g_aFileItems = StringSplit($g_sFileText, $g_sFileNewline, $STR_ENTIRESPLIT + $STR_NOCOUNT)
_ArrayColInsert($g_aFileItems, $ITEM_VALUE)
For $i1 = 0 To UBound($g_aFileItems) - 1
$g_aFileItems[$i1][$ITEM_VALUE] = 0
Next
_ArrayDisplay($g_aFileItems, '$g_aFileItems', '', 0, Default, $g_sItemHeader)
Func _TextFromFile(Const $sFile)
Local $hFile = FileOpen($sFile, $FO_READ + $FO_UTF8_NOBOM)
Local Const $sData = FileRead($hFile)
FileClose($hFile)
Return $sData
EndFunc
Returns:
1-Methoxy-2-Propanol | 0
1,2-BUTADIENE | 0
2-Diethyl aminoethanol | 0
2-ETHYL HEXANOL | 0
2-ETHYL HEXYL ACRYLATE | 0
2-Ethyl hexyl lights | 0
2-Ethyl phenol | 0
2-Ethylsuccionitrile | 0
2-Methyl piperidine | 0
2-Methyl-2-Butene nitrile | 0
2-Methyl-2-Pentenal | 0
2-Methyl-3-Butene nitrile | 0
2-Methylglutaronitrile | 0
...
As:
$g_aFileItems[ x ][$ITEM_NAME]
$g_aFileItems[ x ][$ITEM_VALUE]
Add additional columns using _ArrayColInsert().
... as there are 1500 of them.
Consider using SQLite. Related.
I am using Notepad++, so I'm not sure if this would work with any other IDEs/Notepads. I'm going to be using 1-Methoxy-2-Propanol for my following example.
I learned not to start variables with numbers, so I needed to replace them with words. 1-Methoxy-2-Propanol contains a 1 and a 2, we need to change these to One and Two.
Starting product:
1-Methoxy-2-Propanol
Press Ctrl + F and move to the replace tab. In the "Find what:" box, type 1. In the "Replace with:" box, type One, then press "replace all" (not just "replace"). Do this for numbers zero (0) through nine (9). Now, your product will look like this:
One-Methoxy-Two-Propanol
Next we need to get rid of the dashes. In the Replace tab, inside of the "Find what:" box, type - and in the "Replace With:" box, backspace completely so there is nothing there, then press "Replace All". Now, your product will look like this:
OneMethoxyTwoPropanol
There are other products that include comas and parenthesis, so simply find and replace these like above.
We need to add $ to the beginning of each word. Press Ctrl + F again and go to the Replace tab. In the "Find what:" box, type ^ which symbolizes the start of a new line. In the "Replace with:" box, type $ and press "Replace All". This will make your product look like:
$OneMethoxyTwoPropanol
We need to set all of these variables zero! Go back to the replace tab. In the "Find what:" box type \r. In the "Replace with:" box, type = 0. Note the space before the equal sign. Press "Replace All". Your product will look like this:
$OneMethoxyTwoPropanol = 0
Your file should have started like this:
1-Methoxy-2-Propanol
1,2-BUTADIENE
2-Diethyl aminoethanol
2-ETHYL HEXANOL
2-ETHYL HEXYL ACRYLATE
2-Ethyl hexyl lights
2-Ethyl phenol
2-Ethylsuccionitrile
2-Methyl piperidine
2-Methyl-2-Butene nitrile
2-Methyl-2-Pentenal
2-Methyl-3-Butene nitrile
2-Methylglutaronitrile
2-Pentene nitrile
2,4,7,9-Tetramethyl-5-decyne-4
And ended up like this:
$OneMethoxyTwoPropanol = 0
$OneTwoBUTADIENE = 0
$TwoDiethylaminoethanol = 0
$TwoETHYLHEXANOL = 0
$TwoETHYLHEXYLACRYLATE = 0
$TwoEthylhexyllights = 0
$TwoEthylphenol = 0
$TwoEthylsuccionitrile = 0
$TwoMethylpiperidine = 0
$TwoMethylTwoButenenitrile = 0
$TwoMethylTwoPentenal = 0
$TwoMethylThreeButenenitrile = 0
$TwoMethylglutaronitrile = 0
$TwoPentenenitrile = 0
$TwoFourSevenNineTetramethylFivedecyneFour = 0

Looping through a specified array?

I am trying to match the row height of specific rows from one sheet to another, This works if I just remove all lines with rowlist and do For i = 1 to 200, but this takes too long. I only want to match a few row heights and not go through all between 1 and 200. My code is below:
Dim y As Double
Dim i As Long
Dim rowlist() As Variant
rowlist = Array(3, 5, 23, 30)
For i = LBound(rowlist) To UBound(rowlist)
y = Worksheets("Development").Rows(i).RowHeight
Worksheets("Final").Rows(i).RowHeight = y
Next i
When you're setting and using y, use .Rows(rowlist(i)) rather than .Rows(i).
i simply stores the index of the array, not the value, i.e.
i = 0 ; rowlist(i) =3
i = 1 ; rowlist(i)= 5
i = 2 ; rowlist(i)= 23
i = 3 ; rowlist(i)= 30
So you're correct in looping from LBound(rowlist) to UBound(rowlist), you just need to make sure that you're using the values stored in the array within that loop.