Alternative to NotebookLocate or NotebookFind

8

In Mathematica 8.0 and older, there are two ways to select cells based on cell tags.

NotebookLocate["CellTag"];
NotebookGet[EvaluationNotebook[]]

and

NotebookFind[EvaluationNotebook[], "CellTag", All, CellTags, AutoScroll -> False];
NotebookGet[EvaluationNotebook[]]

When executing either of these the user selection becomes modified. By manually extracting the cells from the notebook, the user selection is not modified. Therefore, you could run NotebookGet in some type of a loop or in another user interface without messing with user's interactions.

Now NotebookGet[EvaluationNotebook[]] holds the Notebook data. So how can I extract cells as if I had run one of the commands above using NotebookGet[EvaluationNotebook[]]?

EDIT: Here is a working solution http://pastebin.com/mvFPqvVY

William

Posted 2013-08-08T06:59:22.290

Reputation: 7 329

Answers

3

Pre-V9 solution

My answer here turns out to be applicable to this question, too. There I had written this function that goes traverses a notebook's expression tree down to the level of what I will call the "notebook's cells." These are the ones displayed with a cell bracket (so it does not find inline cells).

cells[nb_NotebookObject] := cells[nb, _];
cells[nb_NotebookObject, pat_] := Flatten @ cells[First @ NotebookGet[nb], pat];
cells[cellList_List, pat_] := cells[#, pat] & /@ cellList;
cells[Cell[CellGroupData[group_List, ___]], pat_] := cells[#, pat] & /@ group;
cells[c_Cell, pat_] := If[MatchQ[c, pat], c, {}];
cells[__] := {};

It was the OP, Liam, actually, who wrapped this function in an interface to search by tag, and kindly invited me to include it in this answer:

CellsByTag[notebook_, tag_] := Module[{cells},
  cells[nb_NotebookObject] := cells[nb, _];
  cells[nb_NotebookObject, pat_] := Flatten@cells[First@NotebookGet[nb], pat];
  cells[cellList_List, pat_] := cells[#, pat] & /@ cellList;
  cells[Cell[CellGroupData[group_List, ___]], pat_] := cells[#, pat] & /@ group;
  cells[c_Cell, pat_] := If[MatchQ[c, pat], c, {}];
  cells[__] := {};
  cells[notebook, _?(MemberQ[Flatten[{CellTags} /. Options[#]], tag] &)]]

Michael E2

Posted 2013-08-08T06:59:22.290

Reputation: 190 928

6

Is this what you are looking for?

V8

Cases[
      NotebookGet[EvaluationNotebook[]],
      Cell[__, CellTags -> "tag", ___]
      , \[Infinity]]

V9

NotebookRead @ First @ Cells[EvaluationNotebook[], CellTags -> "CellTag"]

Kuba

Posted 2013-08-08T06:59:22.290

Reputation: 129 207

@Liam does Cases works for you? – Kuba – 2013-08-08T07:28:12.790

Not all Cells will be in level 2 because of CellGroupings. My next reaction was to have Cases select with Infinity. Try running the following in an new notebook. http://pastebin.com/2vaixT2e

– William – 2013-08-08T16:46:03.490

@Liam You are right, this came to my mind but I forgot to check. – Kuba – 2013-08-08T16:49:15.230

I thought you did ;), but you didn't my use cases so it might have worked. Further investigation if you run the following code http://pastebin.com/BgDGa3eZ then you try running NotebookLocate["MyTag"];NotebookRead[EvaluationNotebook[]] you get 5 elements with Cases vs 2 with NotebookRead

– William – 2013-08-08T16:52:17.857

@Liam Maybe this pattern is enough Cell[__, CellTags -> "MyTag"]? Then I have 2 matching cells, this one with Cases and the one you are looking for. It seems that CellTag is at the end but I'm not sure. – Kuba – 2013-08-08T16:59:38.377

Trying running this http://pastebin.com/BgDGa3eZ then Length@Cases[NotebookGet[EvaluationNotebook[]],Cell[__, CellTags -> "MyTag", ___], \[Infinity]] or Length@Cases[NotebookGet[EvaluationNotebook[]],Cell[__, CellTags -> "MyTag", ___], \[Infinity]]

– William – 2013-08-08T17:02:20.270

let us continue this discussion in chat

– William – 2013-08-08T17:07:42.163

Surely, you want instead NotebookRead /@ Cells[EvaluationNotebook[], CellTags -> "CellTag"]. By using First, you're only getting the first of many cells, or generating an error condition when you try to get the first of zero cells. – John Fultz – 2013-08-10T04:49:44.500

The v8 solution has another problem. It fails to find cells with multiple cell tags. E.g., a cell with CellTags->{"tag", "abc"}. – John Fultz – 2013-08-10T04:52:38.233

@JohnFultz I agree about First, I assumed there is one and only one cell with such tag. This code is so short I thought is will be clear that First is for particular case and one have to implement some conditional construct to make it bulletproof. About v.8. you are right again :), I should have put some more effor to make this more general answer, I will try to do this this evening. Thank you for those remarks. – Kuba – 2013-08-10T08:25:03.773