How to get (not display) the section number - wolfram-mathematica

Notebook sections can be automatically numbered by inserting the automatically numbering object CounterBox["Section"] using the Insert > Automatic Numbering... menu. However this object only controls the display of the section number and I would like to get its numerical value to use in a program. Any idea how to do that?
Edit
The reason I want to use this is outlined here.

Wrap the CounterBox with a TagBox and a known tag:
Cell[BoxData[TagBox[CounterBox["Section"], "tag"]], "Text"]
Then use FrontEnd`ObjectContents to convert all DynamicBox/CounterBox/ValueBox to literals and pick out the value of that TagBox:
x = First#Cases[FrontEnd`ObjectContents[nb, True], TagBox[x_, "tag"] :> x, \[Infinity]]
If all you want to know is how many of a certain type of counters there are you can do:
x = FE`Evaluate[CurrentValue[{"MaxCounterValue", "Section"}]]

There's got to be a better way to do this, but here's something that works, if I understand what you want to do.
Create a notebook to play with:
nb = CreateDocument[{
Cell["My Title", "Title"],
Cell["My first section", "Section"],
Cell["My second section", "Section"],
Cell[TextData[{"Section ",
CounterBox["Section"]}], "Section"]}];
Select the last cell, which happens to be a Section cell.
SelectionMove[nb, After, Notebook];
SelectionMove[nb, Previous, Cell];
Count backwards.
cnt = sectionCnt = c = 0;
While[True, Print[c];
c = NotebookRead[nb];
If[c === {}, Break[]];
If[c[[2]] == "Section", sectionCnt++];
cnt++;
SelectionMove[nb, Previous, Cell]];
Now sectionCnt should hold the value that you want. You can move back to where you were easily enough:
Do[SelectionMove[nb, Next, Cell], {cnt}]

Related

Python: Printing vertically

The final code will print the distance between states. I'm trying to print the menu with the names of the states numbered and vertically. I really struggle to find my mistakes.
This code doesn't raise any error, it just prints nothing, empty.
state_data = """
LA 34.0522°N 118.2437°W
Florida 27.6648°N 81.5158°W
NY 40.7128°N 74.0060°W"""
states = []
import re
state_data1 = re.sub("[°N#°E]", "", state_data)
def process_states(string):
states_temp = string.split()
states = [(states_temp[x], float(states_temp[x + 1]), float(states_temp[x + 2])) for x in
range(0, len(states_temp), 3)]
return states
def menu():
for state_data in range(state_data1):
print(f'{state_data + 1} {name[number]}')
My first guess is, your code does not print anything without errors because you never actually execute process_airports() nor menu().
You have to call them like this at the end of your script:
something = process_airports(airport_data1)
menu()
This will now raise some errors though. So let's address them.
The menu() function will raise an error because neither name nor number are defined and because you are trying to apply the range function over a string (airport_data1) instead of an integer.
First fixing the range error: you mixed two ideas in your for-loop: iterating over the elements in your list airport_data1 and iterating over the indexes of the elements in the list.
You have to choose one (we'll see later that you can do both at once), in this example, I choose to iterate over the indexes of the list.
Then, since neither name nor number exists anywhere they will raise an error. You always need to declare variables somewhere, however, in this case they are not needed at all so let's just remove them:
def menu(data):
for i in range(len(data)):
print(f'{i + 1} {data[i]}')
processed_airports = process_airports(airport_data1)
menu(processed_airports)
Considering data is the output of process_airports()
Now for some general advices and improvements.
First, global variables.
Notice how you can access airport_data1 within the menu() function just fine, while it works this is not something recommended, it's usually better to explicitly pass variables as arguments.
Notice how in the function I proposed above, every single variable is declared in the function itself, there is no information coming from a higher scope. Again, this is not mandatory but makes the code way easier to work with and understand.
airport_data = """
Alexandroupoli 40.855869°N 25.956264°E
Athens 37.936389°N 23.947222°E
Chania 35.531667°N 24.149722°E
Chios 38.343056°N 26.140556°E
Corfu 39.601944°N 19.911667°E"""
airports = []
import re
airport_data1 = re.sub("[°N#°E]", "", airport_data)
def process_airports(string):
airports_temp = string.split()
airports = [(airports_temp[x], float(airports_temp[x + 1]), float(airports_temp[x + 2])) for x in
range(0, len(airports_temp), 3)]
return airports
def menu(data):
for i in range(len(data)):
print(f'{i + 1} {data[i]}')
# I'm adding the call to the functions for clarity
data = process_airports(airport_data1)
menu(data)
The printed menu now looks like that:
1 ('Alexandroupoli', 40.855869, 25.956264)
2 ('Athens', 37.936389, 23.947222)
3 ('Chania', 35.531667, 24.149722)
4 ('Chios', 38.343056, 26.140556)
5 ('Corfu', 39.601944, 19.911667)
Second and this is mostly fyi, but you can access both the index of a iterable and the element itself by looping over enumerate() meaning, the following function will print the exact same thing as the one with range(len(data)). This is handy if you need to work with both the element itself and it's index.
def menu(data):
for the_index, the_element in enumerate(data):
print(f'{the_index + 1} {the_element}')

Power query,Check if value in column A contains one of values in column B

I want to make,
Check if value in column A contains one of values in column B then value is comes from column B value else blank.
I wrote a function similar to below and i woke this function on add invoke custom function but i have different tables and needs lots of effort writing and updating them.
I tried many things but i have no result.
If you can help,i will be happy.Thanks much
= (Text)=>
if Text.Contains(Text.Upper(Text),"PRIME B360M-D") then"PRIME B360M-D"else
if Text.Contains(Text.Upper(Text),"PRIME B360M-K") then"PRIME B360M-K"else ""
This might work for you . Create a function named Contains as below
(string as text, list as list) =>
let Spot = List.PositionOf(List.Transform(list, (substring) => Text.Contains(string, substring)),true,1)
in if Spot<0 then null else list{Spot}
It looks for an instance where the string contains a match for an item in the List and then returns that item from the list. If there are more than one match, it returns the last one. No matches returns a null
Add custom column to your table similar to below, which uses function to check each instance of column A against the complete list of items from Column B
#"Added Custom" = Table.AddColumn(#"PreviousStep", "Custom", each Contains([A],Table.Column(#"PreviousStep","B")))
M's standard library includes List.Contains and Table.Contains. Seems appropriate to use either of them.
If I understand your code correctly, when comparing each value in column A to all values in column B, you want to make a case-insensitive, partial match (since you use Text.Upper and Text.Contains in the code in your question).
Using standard functions
Code below shows examples for how you'd use List.Contains or Table.Contains. Use whichever one you think is best for you:
let
initialTable = Table.FromColumns({{"soft cat", "doG", "fast nun", "long jOg", "big dog", "gullible fish"}, {"time", "slow", "jog", "Dog", "fish", "rambo"}}, type table [A = text, B = text]),
oneApproach = Table.AddColumn(initialTable, "usingListContains", each if List.Contains(initialTable[B], [A], (x, y) => Text.Contains(y, x, Comparer.OrdinalIgnoreCase)) then [B] else ""),
anotherApproach = Table.AddColumn(oneApproach, "usingTableContains", each if Table.Contains(initialTable, [B = [A]], {"B", (x, y) => Text.Contains(y, x, Comparer.OrdinalIgnoreCase)}) then [B] else "")
in
anotherApproach
which gives me:
Ignoring case-sensitivity, doG and big dog (in column A) partially match Dog (in column B) and therefore the output columns (usingListContains and usingTableContains aren't blank). Same for gullible fish (in column A) and fish (in column B).
I'm assuming this is the matching behaviour you're trying to achieve (in your own table).
Using a custom function
If you find the code a bit hard to follow, you could simply things by creating a custom function (see containsElseOrBlank below and give it a better name if you can):
let
initialTable = Table.FromColumns({{"soft cat", "doG", "fast nun", "long jOg", "big dog", "gullible fish"}, {"time", "slow", "jog", "Dog", "fish", "rambo"}}, type table [A = text, B = text]),
containsElseBlank = (someTable as table, columnToCheck as text, columnToLookIn as text, newColumn as text) =>
let
comparer = (x, y) => Text.Contains(y, x, Comparer.OrdinalIgnoreCase),
containsFunc = (someValue) => Table.Contains(someTable, Record.FromList({someValue}, {columnToLookIn}), {columnToLookIn, comparer}),
newColumn = Table.AddColumn(someTable, newColumn, each if containsFunc(Record.Field(_, columnToCheck)) then Record.Field(_, columnToLookIn) else "")
in newColumn,
customApproach = containsElseBlank(initialTable, "A", "B", "usingCustomFunction")
in
customApproach
which gives me:
which I think is the same as columns usingListContains and usingTableContains (in the previous image). But this approach only requires you to pass arguments to containsElseBlank in the right order (and then the function internally handles the rest).
Another approach might be to use Table.NestedJoin and then check if the result of the join is an empty table or not, but you'd also need to specify how the equality comparison should be done (assuming it lets you specify this).

Excel Mac VBA Loop Through Cells and reset some values

I currently have a worksheet that I have multiple people filling out every day. There are 4 columns that the users fill out: C, E, H, & J (all numerical values, one row per day of the month.)
The users fill in C, E, & H every day no matter what, but a lot of days there is no value to put in column J. I need the value in J to be set to 0 if the user doesn't enter anything. Of course it would be easier to just have the users enter 0, but I'm working with a complicated group of people here.
Anyway, I want to use a macro that runs automatically when the user clicks the save button (before it actually saves, of course), and have it do the following: (I am more familiar with php, so I'm just typing this out how I'm familiar - I'm sure my syntax is incorrect)
Foreach Row
If "column A" != "" {
If "column J" != "" {
//Everything is good, continue on...
} else {
CurrentRow.ColumnJ.value == 0
}//Value has been set - continue loop
}
//column A is blank, this day hasn't come yet - quit looping here
End Foreach
If anyone could help me out with this I'd appreciate it. With some research, this is what I've come up with so far, and now I'm stuck…
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim curCell As Range
'Labor Flow Sheet'.Select
For Each curCell in Range( ???? )
If curCell.Value = "" Then
???????
End If
Next curCell
End Sub
Thanks in advance!
See this link about finding the right range, and as for the question marks inside the If statement, you would want to put
curCell.Value = 0
For the question marks in your statement
For Each curCell in Range( ???? )
Solution 1:
To find the full range you're working with, you'll need to use a column that is filled out each day. You mentioned columns C, E, and H were filled out every day. Using one of those columns (let's pick C for the example here), you could find the range by using the .end method. This goes out either up down left or right from a range until it doesn't find any data. So,
Range("J1", Range("C1").End(xlDown)).Select
will select all cells from J1 (or whatever column is the last in your sheet) to the bottom-most cell containing data in column C, automatically.
Solution 2:
Manually put in the range. For example, to choose A1 to J300:
Range("A1", "J300").Select

How can i set mark for textView?

i am doing "find and repleace button" for my application. I am using gtk and ruby. And i can find that how many word, if there is. Also i want to get selection word that searched word, and i should mark them. My some code:
def search(ent, txtvu)
start = txtvu.buffer.start_iter
first, last = start.forward_search(ent.text, Gtk::TextIter::SEARCH_TEXT_ONLY, nil)
count = 0
while (first)
mark = start.buffer.create_mark(nil, first, false)
txtvu.scroll_mark_onscreen(mark)
txtvu.buffer.delete_mark(mark)
txtvu.buffer.select_range(first, last)
start.forward_char
first, last = start.forward_search(ent.text, Gtk::TextIter::SEARCH_TEXT_ONLY, nil)
start = first
count += 1
end
count says me how many words involve My code does't work. :( Why? I want to mark all searched words.
If I understand you correctly, you want to highlight all found words, not just one. In that case, select_range is not the function to call, because it will change the selection to the current word, and GtkTextView selection is single and contiguous.
Instead, create a highlight tag and apply it to all searches. For example:
# create the "highlight" tag (run this only once)
textvu.buffer.create_tag("highlight", {background => "yellow"})
# ... later, in the loop:
textvu.buffer.apply_tag("highlight", first, last)
Your matches will all appear highlighted.

help on formatting my notebook back as it was. From 'code' style to Input style

I did something silly I think.
I changed my cell style to 'code' and starting changing indentation and moving code around the way I like to, (since it is easier to do that in 'code' cell style, as the notebook interface does not get in the way). But after trying it for a while, I find other issues with this with this style.
Now I changed the style back to 'input'. But now all the code has all these extra spaces in them, and code does not look good any more as it was in the original 'input' style.
I made too many edits and manual formatting to the code.
Is there a way to tell Mathematica to 'auto-format' the code back to the default input style? i.e. remove all the extra space where needed, realign things the way they were, etc...
If I have to do this by hand, will take me forever. I could not find such as option. I tried many options there on the menues, and nothing helps.
ps. in Matlab, this is trivial to do, just select all code, then select 'smart-ident' from a menu, and it will do that.
ps. I tried emacs Mathematica mode, and they have no prety-print either.
EDIT
I tried these: Select cell, then Cell->Convert To, and selected 'InputForm' and also selected 'input Form Display'.
This seems to have removed all the extra white spaces. Which is good. Now I only need to go and just hit returns in all the right places to get it back to the original form.
At least this is much better than having to delete spaces by hand. So, disaster seems to be contained for now.
EDIT
screen shot after converting 'code' style back to 'standard form'. very hard to read.
thanks,
EDIT
To make sure what the question is, given some Mathematica code, which is 'mangled' up, and formatted by hand with manual space inserting and manual inserting of returns all over, and now if I just put it in a notebook with default style, I want it to smart-indent back to the default setting, and have all the line-wrapping, etc... as if it was originally written in the default style. i.e. pretty-print to what it would be if it was written using the 'input' code style.
here is a small function as an example that I formatted by hand. It will look not well formatted even more when I paste it here. If you copy this code to your notebook, default style, then how to auto-format it back to the default settings without doing it by hand?
If[Abs#omega <= $MachineEpsilon,
(
data = {{0, 0}};
p = ListPlot[data, Sequence#plotOptions]
),
(
driverPeriod = 2. Pi/Abs#omega;
valuesOfDriverAmplitude =
Range[aStart, aStart + aLen, aLen/aIntervals];
timeValues =
Range[initialDriverPeriod*driverPeriod,
finalDriverPeriod*driverPeriod, driverPeriod ];
data =
Table[0, {Length[valuesOfDriverAmplitude]}, {Length[timeValues ]}];
total = Length[timeValues]*Length[valuesOfDriverAmplitude];
bifurcationProgress = 0.;
count = 0.;
Do[
(
{x1, x2, x3} =
solve[q, valuesOfDriverAmplitude [[i]], omega, phase,
initialDriverPeriod*driverPeriod,
(finalDriverPeriod)*driverPeriod, x10,
x20, isDamped, 4, 4];
currentTorqueAmplitude = valuesOfDriverAmplitude[[i]];
Do[
(
data[[i, j]] = {currentTorqueAmplitude, x2[timeValues[[j]] ]};
count += 1;
bifurcationProgress = count/total;
),
{j, 1, Length[timeValues]}
]
),
{i, 1, Length[valuesOfDriverAmplitude]}
];
p = ListPlot[Flatten[data, 1], Sequence#plotOptions]
)
];
EDIT
6 PM
1) Saved the notebook as m file (mathematica package) called aclFix.m
2) then I did the following
str=Import["aclFix.m")
also tried
str=Get["aclFix.m"];
but in both cases, all what I get is the actual Manipulate on the screen showing up. And the command shown below (StringReplace etc....) does not work on it as it is not a string. I get lots of errors, such as
StringReplace::strse: String or list of strings expected at position 1 in
StringReplace[Manipulate[<<1>>,
{{aStart,0.9,},0,2,0.01,ImageSize->Tiny,ImagePadding->0,ControlPlacement->1},
{{aLen,0.2,},0.01,2,0.01,ImageSize->Tiny,ImagePadding->0,ControlPlacement->2},
<<45>>,SynchronousUpdating->False,ContinuousAction->False,<<6>>],
{(x_/;x==FromCharacterCode[32])..->,(x_/;x==<<17>>[9])..->}]. >>
may be I misunderstood the solution..
EDIT
1 AM
I exported the notebook as "m" file, Imported it back as
str = Import["aclFix.m", "Text"];
then
code=StringReplace[str, {(x_ /; x == FromCharacterCode[32]) .. ->
"", (x_ /; x == FromCharacterCode[9]) .. -> ""}]
then
Export["fix.m", code]
But it is still a string. When I import it back, it is still a string. I tried
ToExpression[code] but it did nothing. How do convert it to actual code? This is an example looking at the .m using text editor. I used the above code to test it on. May be we are getting close here?
Will look more at it.
(* Created by Wolfram Mathematica 8.0 for Students - Personal Use Only : www.wolfram.com *)
"If[Abs#omega<=$MachineEpsilon,\n(\ndata={{0,0}};\np=ListPlot[data,Sequence#p\
lotOptions]\n),\n(\ndriverPeriod=2.Pi/Abs#omega;\nvaluesOfDriverAmplitude=\nR\
ange[aStart,aStart+aLen,aLen/aIntervals];\ntimeValues=\nRange[initialDriverPe\
riod*driverPeriod,\nfinalDriverPeriod*driverPeriod,driverPeriod];\n\ndata=\nT\
able[0,{Length[valuesOfDriverAmplitude]},{Length[timeValues]}];\ntotal=Length\
[timeValues]*Length[valuesOfDriverAmplitude];\nbifurcationProgress=0.;\ncount\
=0.;\n\nDo[\n(\n{x1,x2,x3}=\nsolve[q,valuesOfDriverAmplitude[[i]],omega,phase\
,\ninitialDriverPeriod*driverPeriod,\n(finalDriverPeriod)*driverPeriod,x10,\n\
x20,isDamped,4,4];\ncurrentTorqueAmplitude=valuesOfDriverAmplitude[[i]];\nDo[\
\n(\n\ndata[[i,j]]={currentTorqueAmplitude,x2[timeValues[[j]]]};\ncount+=1;\n\
bifurcationProgress=count/total;\n),\n{j,1,Length[timeValues]}\n]\n),\n{i,1,L\
ength[valuesOfDriverAmplitude]}\n];\n\np=ListPlot[Flatten[data,1],Sequence#pl\
otOptions]\n)\n];"
It would be useful to have a sample of the code (not just visual). In the meantime, maybe this will work:
Save your code in an m-file. Then import it into the variable str, then run this
StringReplace[str,
{
(x_ /; x == FromCharacterCode[32]) .. -> "",
(x_ /; x == FromCharacterCode[9]) .. -> ""
}
]
and save the result into another m-file. What this does is to remove all series of one or more spaces or tabs. Thus, if for instance
str =
"f[
g[
u ]]"
(which contains both spaces and tabs) then running the code I gave gives
f[
g[
u]]
and you can save this back into an m-file.
If this doesn't do what you want then maybe if you provide a piece of code that is formatted the wrong way would help.
(or you could try with the interactive regexp-builder in emacs: m-x re-builder, but if you're not familiar with regexps it's probably not worth it)
How about something like
nb = EvaluationNotebook[];
NotebookFind[nb, "Code", All, CellStyle]
FrontEndExecute[{FrontEndToken[nb, "Style", "Input"]}]
FrontEndExecute[{FrontEndToken[nb, "SelectionConvert", "StandardForm"]}]
This will convert all "Code" cells to "Input" cells and convert their contents to "StandardForm".
For a list of all FrontEndTokens see belisarius' answer here.
Another option that follows from the recent comment of Rolf Mertig and Alt-Click (or Ctrl-Alt-Click in linux) on a "Code" cell to select all "Code" cells. Then use the Format menu to convert to "Input" style cells and then the Cell menu to Convert To StandardForm. (Alternatively that is Alt-Click on a "Code cell" followed by Alt-9 and then Ctrl-Shift-N)

Resources