Can I pipe an OutputStream
object created by OpenWrite
(or similar) to a notebook instead of a file? I am aware that I can use NotebookWrite
, but I want to have all the Write
statements in my code to be redirected to file/notebook by simply switching a variable.
2 Answers
I am not sure that this is possible. The $Output
and $Messages
variables hold the output stream to where the standard output (and the message output) from the kernel goes. If you check these, you'll see that they're simply set to stdout
.
If you remove ReadProtected
from NotebookWrite
, you'll see that it is passing data to the front end instead of writing to an output stream.
All this suggest that it's not possible to redirect an output stream to an arbitrary notebook.
Instead of using output streams to switch the output "device", I'd suggest switching the output function. You could have a function write
which can be set to write = Write[outputChannel, #]&
or to write = NotebookWrite[nb, #]&
.
If you already have a lot of code using Write
then it would be inconvenient to rewrite it to use an alternative write function. But you can temporarily redefine Write
using a block:
Block[{ Write = NotebookWrite[nb, #2]& },
.... (* code called here *)
]
If you need to temporarily redefine Write
with something that itself uses Write
, then you can use the trick described here to "wrap" it with extra code.
Note: As @Heike said below, NotebookWrite[nb, Cell[BoxData[ToBoxes[#2]], "Output"]] &
is better for writing into notebooks than the simple NotebookWrite[nb, #2]&
I used above.
-
2$\begingroup$ +1 for using block, although you would probably need to define
Write = NotebookWrite[#1, Cell[BoxData[ToBoxes[#2]], "Output"]] &
or something to make it work. $\endgroup$– HeikeCommented Jan 31, 2012 at 13:42 -
$\begingroup$ I was afraid of this. Isn't the purpose of streaming/piping to provide means of saving data by easy redirection? Considering, that this bug is still not resolved, piping is really not that easy in Mathematica... $\endgroup$ Commented Jan 31, 2012 at 13:54
-
2$\begingroup$ @Istvan I agree with Szabolcs. Streams are a pretty low-level I/O tool, suitable also for reading/writing of unstructured data (e.g., not even representing valid Mathematica expressions). Notebooks are structured documents, and writing to them assumes, to my mind, higher-level I/O abstraction. If you feel a need to redirect there, it might mean that your current design is too low-level (regarding logging or whatever purpose it is you use
Write
for), so you will be better off by redesigning this part of your code to use higher-level constructs. $\endgroup$ Commented Jan 31, 2012 at 15:10 -
$\begingroup$ @IstvánZachar, I did not realize that that bug was that old. $\endgroup$– rcollyerCommented Jan 31, 2012 at 16:00
-
$\begingroup$ @István "bump" doesn't really work on a newsgroup as the old message may very well be lost in most newsreaders. Funny the moderator even let it through .. $\endgroup$– SzabolcsCommented Jan 31, 2012 at 16:03
Here's a way that allows you to actually redirect output to a notebook by using the newish DefineStreamOutputMethod
function (which dates to 9.0). It's a bit hacky by its very nature, and the version I have here creates a new notebook for output, but I think it's a reasonable place to start. There's certainly room for refinement!
DefineOutputStreamMethod["Notebook",
{
"ConstructorFunction" ->
Function[{name, isAppend, caller, opts},
With[{state = Unique["NotebookOutputStream"]},
state["notebook"] =
CreateNotebook[FilterRules[opts, Options[Notebook]]];
{True, state}]],
"CloseFunction" -> Function[state, ClearAll[state]],
"WriteFunction" -> Function[{state, bytes},
(* Since we're writing to a cell, we don't want that trailing newline. *)
With[{out = bytes /. {most___, 10} :> FromCharacterCode[{most}]},
With[{nb = state["notebook"]},
If[NotebookInformation@nb === $Failed || out === "",
{0, state},
NotebookWrite[nb, Cell[out, "Output"], After];
{Length@bytes, state}]]]]
}];
Try it out like this:
With[{stream = OpenWrite[Method -> "Notebook"]},
Block[{$Output = stream},
Do[Print[i], {i, 10}];
Close[stream]]]