I'd like to be able to mix text and computation. Something like this:
blah blah blah ...
blah blah ... The average mass is (m1 + m2 + m3)/3 = 23.4 g ... blah blah
blah blah blah ...
Where the "(m1... )/3" is the input, and the "23.4" is the output. Right now I only know how to show input in one cell, and the output in another cell below it.
Is this possible?
Update: I want to include these bits of computation in the midst of larger blocks of writing, so I'm not sure how to use a Print statement as Koantig suggested, because it seems I'd have to concatenate an entire paragraph/cell worth of strings and styles.
thanks,
Rob
I suppose that you have entered your expression in a text cell. If you highlight the expression to evaluate, in your case
(m1 + m2 + m3)/3
and hit Shift+Ctrl+Enter (on my Windows box, not sure about your box, but it's option Evaluation | Evaluate in Place if you prefer the menu), then your expression will be replaced by the result of evaluating it. I know that this is not exactly what you want, but it's the closest I have found myself. I copy the expression to the rhs of the = sign and evaluate the copy.
I expect that someone will come along soon and tell us the smart way to do this.
Maybe something like this?
m1 = 10;
m2 = 20;
m3 = 50;
f = "(m1+m2+m3)/3";
Print[f <> "= " <> ToString#N#ToExpression#f <> " g"]
The result:
(m1+m2+m3)/3= 26.6667 g
For smaller projects, I have a scratch notebook and a presentation notebook. Calculations are performed in the scratch notebook, then copied into the presentation notebook.
For larger projects, I attach the computations to the section headers, then fold the section down to just the header for presentation purposes. There's still cutting and pasting.
I have once written a notebook that parsed a pair of scratch/presentation notebooks into a final notebook where specially marked sections of the presentation notebook were replaced with results computed in the context of the scratch notebook. This was sufficiently difficult to maintain that I have never repeated the experience.
Which did you want: visible, editable expressions to be evaluated, or dead, fixed results of (past) evaluations?
Related
I’m trying to build a mogrt file for PR which will work just like the out of the box buzzwords effect in AE.
So far, I have set up some 20 text layers which are hidden and will work as text fields and I have main text layer with ‘buzzwords’ expression that feeds from text fields 1-20.
My knowledge of expressions is rather basic but I got it to work somehow by altering the first line of expression to
buzz_words = (thisComp.layer(“1”).text.sourceText +’|’+ thisComp.layer(“b”).text.sourceText+’|’)
I realise if I set this up for 20 text layers, this would be rather lengthy code, do you have any recommendations for making this a little bit less so?
Thanks in advance.
(raw code of Buzz words effect below)
buzz_words = "One|Two|Three|Four|Five|Six|Seven|Eight|Nine|Ten";
split_buzz_words_array = buzz_words.split('|');
buzz_frame_rate = effect("Buzz Frame Rate")(1);
buzz_frame = Math.floor(time * buzz_frame_rate);
buzz_index = buzz_frame % split_buzz_words_array.length;
split_buzz_words_array[buzz_index];
I have created syntax in SPSS that gives me 90 separate iterations of general linear model, each with slightly different variations fixed factors and covariates. In the output file, they are all just named as "General Linear Model." I have to then manually rename each analysis in the output, and I want to find syntax that will add a more specific name to each result that will help me identify it out of the other 89 results (e.g. "General Linear Model - Males Only: Mean by Gender w/ Weight covariate").
This is an example of one analysis from the syntax:
USE ALL.
COMPUTE filter_$=(Muscle = "BICEPS" & Subj = "S1" & SMU = 1 ).
VARIABLE LABELS filter_$ 'Muscle = "BICEPS" & Subj = "S1" & SMU = 1 (FILTER)'.
VALUE LABELS filter_$ 0 'Not Selected' 1 'Selected'.
FORMATS filter_$ (f1.0). FILTER BY filter_$.
EXECUTE.
GLM Frequency_Wk6 Frequency_Wk9
Frequency_Wk12 Frequency_Wk16
Frequency_Wk20
/WSFACTOR=Time 5 Polynomial
/METHOD=SSTYPE(3)
/PLOT=PROFILE(Time)
/EMMEANS=TABLES(Time)
/CRITERIA=ALPHA(.05)
/WSDESIGN=Time.
I am looking for syntax to add to this that will name this analysis as: "S1, SMU1 BICEPS, GLM" Not to name the whole output file, but each analysis within the output so I don't have to do it one-by-one. I have over 200 iterations at times that come out in a single output file, and renaming them individually within the output file is taking too much time.
Making an assumption that you are exporting the models to Excel (please clarify otherwise).
There is an undocumented command (OUTPUT COMMENT TEXT) that you can utilize here, though there is also a custom extension TEXT also designed to achieve the same but that would need to be explicitly downloaded via:
Utilities-->Extension Bundles-->Download And Install Extension Bundles--->TEXT
You can use OUTPUT COMMENT TEXT to assign a title/descriptive text just before the output of the GLM model (in the example below I have used FREQUENCIES as an example).
get file="C:\Program Files\IBM\SPSS\Statistics\23\Samples\English\Employee data.sav".
oms /select all /if commands=['output comment' 'frequencies'] subtypes=['comment' 'frequencies']
/destination format=xlsx outfile='C:\Temp\ExportOutput.xlsx' /tag='ExportOutput'.
output comment text="##Model##: This is a long/descriptive title to help me identify the next model that is to be run - jobcat".
freq jobcat.
output comment text="##Model##: This is a long/descriptive title to help me identify the next model that is to be run - gender".
freq gender.
output comment text="##Model##: This is a long/descriptive title to help me identify the next model that is to be run - minority".
freq minority.
omsend tag=['ExportOutput'].
You could use TITLE command here also but it is limited to only 60 characters.
You would have to change the OMS tags appropriately if using TITLE or TEXT.
Edit:
Given the OP wants to actually add a title to the left hand pane in the output viewer, a solution for this is as follows (credit to Albert-Jan Roskam for the Python code):
First save the python file "editTitles.py" to a valid Python search path (for example (for me anyway): "C:\ProgramData\IBM\SPSS\Statistics\23\extensions")
#editTitles.py
import tempfile, os, sys
import SpssClient
def _titleToPane():
"""See titleToPane(). This function does the actual job"""
outputDoc = SpssClient.GetDesignatedOutputDoc()
outputItemList = outputDoc.GetOutputItems()
textFormat = SpssClient.DocExportFormat.SpssFormatText
filename = tempfile.mktemp() + ".txt"
for index in range(outputItemList.Size()):
outputItem = outputItemList.GetItemAt(index)
if outputItem.GetDescription() == u"Page Title":
outputItem.ExportToDocument(filename, textFormat)
with open(filename) as f:
outputItem.SetDescription(f.read().rstrip())
os.remove(filename)
return outputDoc
def titleToPane(spv=None):
"""Copy the contents of the TITLE command of the designated output document
to the left output viewer pane"""
try:
outputDoc = None
SpssClient.StartClient()
if spv:
SpssClient.OpenOutputDoc(spv)
outputDoc = _titleToPane()
if spv and outputDoc:
outputDoc.SaveAs(spv)
except:
print "Error filling TITLE in Output Viewer [%s]" % sys.exc_info()[1]
finally:
SpssClient.StopClient()
Re-start SPSS Statistics and run below as a test:
get file="C:\Program Files\IBM\SPSS\Statistics\23\Samples\English\Employee data.sav".
title="##Model##: jobcat".
freq jobcat.
title="##Model##: gender".
freq gender.
title="##Model##: minority".
freq minority.
begin program.
import editTitles
editTitles.titleToPane()
end program.
The TITLE command will initially add a title to main output viewer (right hand side) but then the python code will transfer that text to the left hand pane output tree structure. As mentioned already, note TITLE is capped to 60 characters only, a warning will be triggered to highlight this also.
This editTitles.py approach is the closest you are going to get to include a descriptive title to identify each model. To replace the actual title "General Linear Model." with a custom title would require scripting knowledge and would involve a lot more code. This is a simpler alternative approach. Python integration required for this to work.
Also consider using:
SPLIT FILE SEPARATE BY <list of filter variables>.
This will automatically produce filter labels in the left hand pane.
This is easy to use for mutually exclusive filters but even if you have overlapping filters you can re-run multiple times (and have filters applied to get as close to your desired set of results).
For example:
get file="C:\Program Files\IBM\SPSS\Statistics\23\Samples\English\Employee data.sav".
sort cases by jobcat minority.
split file separate by jobcat minority.
freq educ.
split file off.
I frequently run into problems that could be solved with automating code writing, but aren't long enough to justify it as tediously entering each piece is faster.
Here is an example:
Putting lists into dictionaries and things like this. Converting A into B.
A
hotdog HD
hamburger HB
hat H
B
def symbolizeType
case self.type
when "hotdog"
return "HD"
when "hamburger"
return "HB"
when "hat"
return "H"
end
Sure I could come up with something to do this automatically, but it would only make sense if the list was 100+ items long. For a list of 10-20 items, is there a better solution than tediously typing? This is a Ruby example, but I typically run into cases like this all the time. Instead of a case statement, maybe it's a dictionary, maybe it's a list, etc.
My current solution is a python template with the streaming input and output already in place, and I just have to write the parsing and output code. This is pretty good, but is there better? I feel like this would be something VIM macro would excel at, but I'm that experienced with VIM. Can VIM do this easily?
For vim, it'd be a macro running over a list of space separated pairs of words, inserting the first 'when "' bit, the long form word 'hotdog', the ending quote, a newline and 'return "', and then the abbreviation and then final quote, then going back to the list and repeating.
Starting with a register w of:
when "
register r of:
return "
an initial list of:
hotdog HD
hamburger HB
hat H
and a starting file of:
def symbolizeType
case self.type
"newline here"
you can use the following macro at the start of the initial list:
^"ayeeeb"byeo"wp"apa"^Mrb"j
where ^M is a newline.
I do this frequently, and I use a single register and a macro, so I'll share.
Simply pick a register, record your keystrokes, and then replay your keystrokes from the register.
This is a long explanation, but the process is extremely simple and intuitive.
Here are the steps that I would take:
A. The starting text
hotdog HD
hamburger HB
hat H
B. Insert the initial, non-repetitive lines preceding the text to transform
def symbolizeType
case self.type
hotdog HD
hamburger HB
hat H
C. Transform the first line, while recording your keystrokes in a macro
This step I'll write out in detailed sub-steps.
Place the cursor on the first line to transform ("hotdog") and type qa to begin recording your keystrokes as a macro into register a.
Type ^ to move the cursor to the start of the line
Type like you normally would to transform the line to what you want, which for me comes out looking like the following macro
^i^Iwhen "^[ea"^[ldwi^M^Ireturn "^[ea"^[j
Where ^I is Tab, ^[ is Esc, and ^M is Enter.
After the line is transformed to your liking, move your cursor to the next line that you want to transform. You can see this in the macro above with the final j at the end.
This will allow you to automatically repeat the macro while it cycles through each repetitive line.
Stop recording the macro by typing q again.
You can then replay the macro from register a as many times as you like using a standard vim count prefix, in this case two consecutive times starting from the next line to transform.
2#a
This gives the following text
def symbolizeType
case self.type
when "hotdog"
return "HD"
when "hamburger"
return "HB"
when "hat"
return "H"
D. Finally, insert the ending non-repetitive text
def symbolizeType
case self.type
when "hotdog"
return "HD"
when "hamburger"
return "HB"
when "hat"
return "H"
end
Final Comments
This works very quick for any random, repetitive text, and I find it very fluent.
Simply pick a register, record your keystrokes, and then replay your keystrokes from the register.
For things like this I have a few ways of making it easier. One is to use an editor like Sublime Text that allows you to multi-edit a number of things at once, so you can throw in markup with a few keystrokes and convert that into a Hash like:
NAME_TO_CODE = {
hotdog: 'HD',
hamburger: 'HB',
hat: 'H'
}
Not really a whole lot changed there. Your function looks like:
def symbolize_type(type)
NAME_TO_CODE[type.to_sym]
end
Defining this as a data structure has the bonus of being able to manipulate it:
CODE_TO_NAME = NAME_TO_CODE.invert
Now you can do this:
def unsymbolize_type(symbol)
CODE_TO_NAME[symbol.to_s]
end
You can also get super lazy and just parse it on the fly:
NAME_TO_CODE = Hash[%w[
hotdog HD
hamburger HB
hat H
].each_slice(2).to_a]
snippets are like the built-in :abbreviate on steroids, usually with parameter insertions, mirroring, and multiple stops inside them. One of the first, very famous (and still widely used) Vim plugins is snipMate (inspired by the TextMate editor); unfortunately, it's not maintained any more; though there is a fork. A modern alternative (that requires Python though) is UltiSnips. There are more, see this list on the Vim Tips Wiki.
There are three things to evaluate: First, the features of the snippet engine itself, second, the quality and breadth of snippets provided by the author or others; third, how easy it is to add new snippets.
If you take a look at the Combinatorica package in Mathematica8 in (mathematicapath)/AddOns/LegacyPackages/DiscreteMath/Combinatorica.m you will find the definitions of functions. What I'm interested to know is how Mathematica knows how to format the usage messages. Something tells me that I'm not looking at the right file. In any case, lets try the following:
Cofactor::usage = "Cofactor[m, {i, j}] calculates the (i, j)th cofactor of matrix m."
This line is the 682 line in the file mentioned above. Now if we run it in a mathematica notebook and we use ?Cofactor we will see the exact same message. But if we get the package then the message is formatted. Here is a screenshot:
Notice how the m, i and j inside the function changed and a double arrow was added to the message. I think the arrow was added to the message because there exists documentation for it. Can someone explain this behavior?
EDIT:
This is a screenshot of my notebook file that autosaves to an m file.
As you can see, the L and M are in italic times new roman. Now I will load the package and see the usage.
So far so good. Now lets look at the Documentation center. I will look for the function LineDistance.
As you can see, it shows a weird message. In this case we only want to display the message without any styles. I still can't figure out how the Combinatorica package does this.
I followed this to make the index so that the doc center can display the summary. The summary is essentially the usage display. Let me know if I need to be more specific.
OK, here's the explanation.
Digging in the Combinatorica source reveals this:
(* get formatted Combinatorica messages, except for special cases *)
If[FileType[ToFileName[{System`Private`$MessagesDir,$Language},"Usage.m"]]===File,
Select[FindList[ToFileName[{System`Private`$MessagesDir,$Language},"Usage.m"],"Combinatorica`"],
StringMatchQ[#,StartOfString~~"Combinatorica`*"]&&
!StringMatchQ[#,"Combinatorica`"~~("EdgeColor"|"Path"|"Thin"|"Thick"|"Star"|"RandomInteger")~~__]&]//ToExpression;
]
It is loading messages from ToFileName[{System`Private`$MessagesDir,$Language},"Usage.m"], which on my machine is SystemFiles\Kernel\TextResources\English\Usage.m. This is why all usage messages are created conditionally in Combinatorica.m (only if they don't exist yet). If you look in Usage.m you'll see it has all the ugly boxes stuff that #ragfield mentioned.
I guess the simplest way to have formatted messages is to edit them in the front end in a notebook, and create an auto-save package. This way you can use all the front end's formatting tools, and won't need to deal with boxes.
I will answer on how the link in the Message is generated. Tracing Message printing shows a call to undocumented Documentation`CreateMessageLink function which returns the URL to the corresponding Documentation page if this page exists:
Trace[Information[Sin], Documentation`CreateMessageLink]
In[32]:= Documentation`CreateMessageLink["System", "Sin", "argx", "English"]
Out[32]= "paclet:ref/message/General/argx"
In some cases we can also see calls to Internal`MessageButtonHandler which further calls Documentation`CreateMessageLink:
Trace[Message[Sin::argx, 1, 1],
Internal`MessageButtonHandler | Documentation`CreateMessageLink,
TraceInternal -> True]
The way to embed style information in a String expression is to use linear syntax. For a box expression such as:
StyleBox["foo", FontSlant->Italic]
You can embed this inside of a String by adding \* to the front of it and escaping any special characters such as quotes:
"blah \*StyleBox[\"foo\", FontSlant->Italic] blah"
This should work for any box expression, no matter how complicated:
"blah \*RowBox[{SubsuperscriptBox[\"\[Integral]\",\"0\",\"1\"],RowBox[{FractionBox[\"1\",RowBox[{\"x\",\"+\",\"1\"}]],RowBox[{\"\[DifferentialD]\",\"x\"}]}]}] blah"
I am currently working on rewriting your ApplicationMaker for newer Mathematica-Versions with added functionalities and came to the exact same question here.
My answer is simple: Mathematica dont allowes you to use formated summaries for your symbols (or even build in symbols), so we have to unformate the usage-strings for the summaries. The usagestring itself can still have formatting, but one needs to have a function that removes all the formatingboxes from a string.
i have a solution that uses the UndocumentedTestFEParserPacket as described by John Fultz! in this question.
This funny named Tool parses a String Input into the real unchanged Mathematica BoxForm.
This is my example code:
str0 = Sum::usage
str1=StringJoin[ToString[StringReplace[#, "\\\"" -> "\""]]& /#
(Riffle[MathLink`CallFrontEnd[
FrontEnd`UndocumentedTestFEParserPacket[str0, True]]〚1〛
//. RowBox[{seq___}] :> seq /. BoxData -> List, " "]
/. SubscriptBox[a_, b_] :> a<>"_"<>b
/. Except[List, _Symbol][args__] :> Sequence##Riffle[{args}, " "])];
str2 = Fold[StringReplace, str1,
{((WhitespaceCharacter...)~~br:("["|"("|"=") ~~ (WhitespaceCharacter ...)) :> br,
((WhitespaceCharacter ...) ~~ br:("]"|"}"|","|".")) :> br,
(br:("{") ~~ (WhitespaceCharacter ...)) :> br,
". " ~~ Except[EndOfString] -> ". \n"}]
and this is how the Output looks like (first Output formatted fancy str0, second simple flat str2)
Code Explanation:
str0 is the formatted usagestring with all the StyleBoxes and other formatting boxes.
str1:
UndocumentedTestFEParserPacket[str0, True] gives Boxes and strips off all StyleBoxes, thats because the second argument is True.
First Replacement removes all RowBoxes. The outer BoxForm changed to a List of strings. Whitespaces are inserted between these strings the by Riffle. SubscriptBox gets a special treatment. The last line replaces every remaining FormatBox such as UnderoverscriptBox and it does that by adding Whitespaces between the arguments, and returning the arguments as a flat Sequence.
ToString[StringReplace[#, "\\\"" -> "\""]]& /#
was added to include more cases such as StringReplace::usage. This cases include string representations "" with Styles inside of a the usage-string, when "args" has to be given as strings.
str2:
In this block of code i only remove unwanted WhitespaceCharacter from the string str1 and i add linebreaks "/n" after the ".", because they got lost during the Parsing. There are 3 different cases where WhitespaceCharacter can be removed.
1 removing left-and right sided WithespaceCharacter from a character like "[".
2. and 3. removing WithespaceCharacter from left(2) or right(3) side.
Summary
Istead of summary-> mySymbol::usage, use summary -> unformatString[mySymbol::usage] with unformatString being an appropriate function that performes the unformating like descriped above.
Alternatively you can define another usage message manually like
f::usage = "fancy string with formating";
f::usage2 = "flat string without formating";
than use summary -> mySymbol::usage2
I recently dived into LaTeX, starting with the help of a WYSIWYM editor like Lix. Now I'm staring writing tex files in Sci-TE, It already has syntax higlighting and I adapted the tex.properties file to work in Windows showing a preview on Go [F5]
One pretty thing Lyx does, and it's hard to acheive with a common text editor, is to format text in 80 columns: I can write a paragraph and hit Return each time I reach near the edge column but if, after the first draft, I want to add or cut some words here and there I end up breaking the layout and having to rearrange newlines.
It would be useful to have a tool in Sci-TE so I can select a paragraph of text I added or deleted some words in and have it rearranged in 80 columns. Probably not something working on the whole document since it could probably break some intended anticipated line break.
Probably I could easily write a Python plugin for geany, I saw vim has something similar, but I'd like to know if its' possible in Sci-TE too.
I was a bit disappointed when I found no answer as I was searching for same. No helpers by Google either, so I searched for Lua examples and syntax in a hope to craft it myself. I don't know Lua so this can perhaps be made differently or efficiently but its better then nothing I hope - here is Lua function which needs to be put in SciTE start-up Lua script:
function wrap_text()
local border = 80
local t = {}
local pos = editor.SelectionStart
local sel = editor:GetSelText()
if #sel == 0 then return end
local para = {}
local function helper(line) table.insert(para, line) return "" end
helper((sel:gsub("(.-)\r?\n", helper)))
for k, v in pairs(para) do
line = ""
for token in string.gmatch(v, "[^%s]+") do
if string.len(token .. line) >= border then
t[#t + 1] = line
line = token .. " "
else
line = line .. token .. " "
end
end
t[#t + 1] = line:gsub("%s$", "")
end
editor:ReplaceSel(table.concat(t, "\n"))
editor:GotoPos(pos)
end
Usage is like any other function from start-up script, but for completness I'll paste my tool definition from SciTE properties file:
command.name.8.*=Wrap Text
command.mode.8.*=subsystem:lua,savebefore:no,groupundo
command.8.*=wrap_text
command.replace.selection.8.*=2
It does respect paragraphs, so it can be used on broader selection, not just one paragraph.
This is one way to do it in scite: first, add this to your .SciTEUser.properties (Options/Open User Options file):
# Column guide, indicates long lines (https://wiki.archlinux.org/index.php/SciTE)
# this is what they call "margin line" in gedit (at right),
# in scite, "margin" is the area on left for line numbers
edge.mode=1
edge.column=80
... and save, so you can see a line at 80 characters.
Then scale the scite window, so the text you see is wrapped at the line.
Finally, select the long line text which is to be broken into lines, and do Edit / Paragraph / Split (for me the shortcut Ctrl-K also works for that).
Unfortunately, there seems to be no "break-lines-as-you-type" facility in scite, like the "Line Breaking" facility in geany. not anymore, now there's a plugin - see this answer
Well, I was rather disappointed that there seems to be no "break-lines-as-you-type" facility in scite; and I finally managed to code a small Lua plugin/add-on/extension for that, and released it here:
lua-users wiki: Scite Line Break
Installation and usage instructions are in the script itself. Here is how SciTE may look when the extension properly installed, and toggle activated after startup:
Note that it's pretty much the same functionality as in geany - it inserts linebreaks upon typing text - but not on pressing backspace, nor upon copy/pasting.
the same but more easy, I think...
put this in the user properties:
command.name.0.*=swrap
command.0.*=fold -s $(FileNameExt) > /tmp/scite_temp ; cat /tmp/scite_temp >$(FileNameExt)
command.is.filter.0.*=1
Ciao
Pietro