5

Suppose I have a file containing the following:

ATOM     10  H5  LIG     1      -0.684   2.034   0.000  1.00  0.00
ATOM     11  C1  LIG     1       0.974   0.686   0.000  1.00  0.00
ATOM     12  H1  LIG     1       1.734   1.451   0.000  1.00  0.00
ATOM     13  C2  LIG     1       0.977  -0.683   0.000  1.00  0.00
ATOM     14  H2  LIG     1       1.743  -1.443   0.001  1.00  0.00
ATOM     15  N1  LIG     1      -0.347  -1.074   0.000  1.00  0.00
ATOM     16  H3  LIG     1      -0.675  -2.037   0.000  1.00  0.00
ATOM     17  C3  LIG     1      -1.145  -0.003   0.000  1.00  0.00
ATOM     18  H4  LIG     1      -2.226  -0.005   0.000  1.00  0.00
ATOM     19  N2  LIG     1      -0.352   1.073   0.000  1.00  0.00
ATOM     20  H5  LIG     1      -0.684   2.034   0.000  1.00  0.00

How can I add a constant decimal value to the sixth column, say 5.487, replacing the existing values? I am aware of rectangle select and calc, but neither seem to provide the ability to cleanly perform this operation in place on a column.

holocronweaver
  • 1,319
  • 10
  • 22
  • 1
    Have a look at [`evil-numbers`](https://github.com/cofi/evil-numbers) for incrementing and decrementing. It's a port of Vim functionality, but a quick glance at the source code suggests it's stand-alone and does not require `evil` to work. – Dan Jan 21 '15 at 17:49
  • Sadly, using a dedicated spreadsheet application would probably be a better choice in this case. – wdkrnls Jan 23 '15 at 14:49
  • For very large data files, I agree a spreadsheet app is necessary, but for small to medium files Emacs should be my go-to. As someone who manipulates dozens of medium-sized data files a day, streamlining this to a key binding in Emacs would be a huge time saver. – holocronweaver Jan 23 '15 at 18:47
  • @Dan `evil-numbers` is promising, but it does not seem to support rectangle regions. Created an issue on Github. – holocronweaver Jan 23 '15 at 19:05

4 Answers4

4

Using Org-mode

  1. Select the text of the table.
  2. C-c |
  3. Add at the bottom: #+TBLFM: $6=$6+5.487 and press C-c C-c while the point is either on the formula or on the table.

This gives:

| ATOM | 10 | H5 | LIG | 1 | 4.803 |  2.034 | 0.000 | 1.00 | 0.00 |
| ATOM | 11 | C1 | LIG | 1 | 6.461 |  0.686 | 0.000 | 1.00 | 0.00 |
| ATOM | 12 | H1 | LIG | 1 | 7.221 |  1.451 | 0.000 | 1.00 | 0.00 |
| ATOM | 13 | C2 | LIG | 1 | 6.464 | -0.683 | 0.000 | 1.00 | 0.00 |
| ATOM | 14 | H2 | LIG | 1 |  7.23 | -1.443 | 0.001 | 1.00 | 0.00 |
| ATOM | 15 | N1 | LIG | 1 |  5.14 | -1.074 | 0.000 | 1.00 | 0.00 |
| ATOM | 16 | H3 | LIG | 1 | 4.812 | -2.037 | 0.000 | 1.00 | 0.00 |
| ATOM | 17 | C3 | LIG | 1 | 4.342 | -0.003 | 0.000 | 1.00 | 0.00 |
| ATOM | 18 | H4 | LIG | 1 | 3.261 | -0.005 | 0.000 | 1.00 | 0.00 |
| ATOM | 19 | N2 | LIG | 1 | 5.135 |  1.073 | 0.000 | 1.00 | 0.00 |
| ATOM | 20 | H5 | LIG | 1 | 4.803 |  2.034 | 0.000 | 1.00 | 0.00 |
#+TBLFM: $6=$6+5.487

If you don't like the | / don't want to use Org-mode, just copy the result elsewhere and M-xreplace-string RET|RET RET


Way to do this with Calc

  1. Select the column you want.
  2. C-x * r inserts the column into Calc.
  3. v t transposes the vector.
  4. v u unpacks (because it was copied as a matrix with a single column).
  5. 5.487+ adds 5.487.
  6. v u unpack again.
  7. C-x r r1RET copies unpacked numbers to register 1.
  8. Place the point in front of the original column and C-x r i1RET this will insert the results you copied from Calc buffer. Then, select the original column and C-x r k.

But I agree this would be a bit too cumbersome (I actually had to look up how to insert registers since I don't usually do it). Sharing this just for the sake of diversity.

wvxvw
  • 11,222
  • 2
  • 30
  • 55
  • I tried C-| and it is undefined. What is the command for that key binding you have? – Andrii Tykhonov Jan 21 '15 at 19:49
  • @AndreyTykhonov you need to be in Org-mode to do that. For example, create a fresh buffer: `C-x b org RET` and then `M-x org-mode`. Or open some file with `.org` extension. Org tables can be used outside of Org mode, in other modes, but unless you are planning on doing this very often, setting this up may be a tad too much for this. – wvxvw Jan 21 '15 at 19:50
  • I'm in the org-mode! But `C-|` is not defined! – Andrii Tykhonov Jan 21 '15 at 20:57
  • 2
    @AndreyTykhonov It's a typo.. the binding is `C-c |`, `org-table-create-or-convert-from-region`. – Kaushal Modi Jan 21 '15 at 21:16
  • @kaushalmodi thank you! I've tried to edit the answer but it doesn't save my changes. – Andrii Tykhonov Jan 21 '15 at 22:08
  • 1
    @AndreyTykhonov oh, right, sure, it should be `C-c |`. Editing thing must be the Stackexchange karma-points. Nevermind it though, I've corrected it. – wvxvw Jan 21 '15 at 22:16
3

You can use multiple cursors to get this done.

Before you get started with the below steps, add this to your init.el, evaluate it and bind it to a key binding of your linking.

;; http://stackoverflow.com/questions/3035337/in-emacs-can-you-evaluate-an-emacs-lisp-expression-and-replace-it-with-the-resul
(defun eval-and-replace-last-math-sexp ()
  "Replace an emacs lisp expression (s-expression aka sexp) with its result"
  (interactive)
  (let ((value (eval (preceding-sexp))))
    (kill-sexp -1)
    (insert (format "%.3f" value)))) ; Change this resolution as you need

Let's bind it to C-M-= for this explanation.

Step 1 Get the cursor to column that you want to modify first.

ATOM     10  H5  LIG     1     ▮-0.684   2.034   0.000  1.00  0.00
ATOM     11  C1  LIG     1       0.974   0.686   0.000  1.00  0.00
ATOM     12  H1  LIG     1       1.734   1.451   0.000  1.00  0.00
ATOM     13  C2  LIG     1       0.977  -0.683   0.000  1.00  0.00
ATOM     14  H2  LIG     1       1.743  -1.443   0.001  1.00  0.00
ATOM     15  N1  LIG     1      -0.347  -1.074   0.000  1.00  0.00
ATOM     16  H3  LIG     1      -0.675  -2.037   0.000  1.00  0.00
ATOM     17  C3  LIG     1      -1.145  -0.003   0.000  1.00  0.00
ATOM     18  H4  LIG     1      -2.226  -0.005   0.000  1.00  0.00
ATOM     19  N2  LIG     1      -0.352   1.073   0.000  1.00  0.00
ATOM     20  H5  LIG     1      -0.684   2.034   0.000  1.00  0.00

Step 2 Create multiple cursors - Press C-> as many times required

ATOM     10  H5  LIG     1     ▮-0.684   2.034   0.000  1.00  0.00
ATOM     11  C1  LIG     1     ▯ 0.974   0.686   0.000  1.00  0.00
ATOM     12  H1  LIG     1     ▯ 1.734   1.451   0.000  1.00  0.00
ATOM     13  C2  LIG     1     ▯ 0.977  -0.683   0.000  1.00  0.00
ATOM     14  H2  LIG     1     ▯ 1.743  -1.443   0.001  1.00  0.00
ATOM     15  N1  LIG     1     ▯-0.347  -1.074   0.000  1.00  0.00
ATOM     16  H3  LIG     1     ▯-0.675  -2.037   0.000  1.00  0.00
ATOM     17  C3  LIG     1     ▯-1.145  -0.003   0.000  1.00  0.00
ATOM     18  H4  LIG     1     ▯-2.226  -0.005   0.000  1.00  0.00
ATOM     19  N2  LIG     1     ▯-0.352   1.073   0.000  1.00  0.00
ATOM     20  H5  LIG     1     ▯-0.684   2.034   0.000  1.00  0.00

Step 3 Type the math equation in elisp: (+ 5.487 M-f)

ATOM     10  H5  LIG     1     (+ 5.487 -0.684)▮   2.034   0.000  1.00  0.00
ATOM     11  C1  LIG     1     (+ 5.487  0.974)▯   0.686   0.000  1.00  0.00
ATOM     12  H1  LIG     1     (+ 5.487  1.734)▯   1.451   0.000  1.00  0.00
ATOM     13  C2  LIG     1     (+ 5.487  0.977)▯  -0.683   0.000  1.00  0.00
ATOM     14  H2  LIG     1     (+ 5.487  1.743)▯  -1.443   0.001  1.00  0.00
ATOM     15  N1  LIG     1     (+ 5.487 -0.347)▯  -1.074   0.000  1.00  0.00
ATOM     16  H3  LIG     1     (+ 5.487 -0.675)▯  -2.037   0.000  1.00  0.00
ATOM     17  C3  LIG     1     (+ 5.487 -1.145)▯  -0.003   0.000  1.00  0.00
ATOM     18  H4  LIG     1     (+ 5.487 -2.226)▯  -0.005   0.000  1.00  0.00
ATOM     19  N2  LIG     1     (+ 5.487 -0.352)▯   1.073   0.000  1.00  0.00
ATOM     20  H5  LIG     1     (+ 5.487 -0.684)▯   2.034   0.000  1.00  0.00

Step 4 Do C-M-= and hit RET to exit the multiple cursors mode. Voila!

ATOM     10  H5  LIG     1     4.803▮   2.034   0.000  1.00  0.00
ATOM     11  C1  LIG     1     6.461    0.686   0.000  1.00  0.00
ATOM     12  H1  LIG     1     7.221    1.451   0.000  1.00  0.00
ATOM     13  C2  LIG     1     6.464   -0.683   0.000  1.00  0.00
ATOM     14  H2  LIG     1     7.230   -1.443   0.001  1.00  0.00
ATOM     15  N1  LIG     1     5.140   -1.074   0.000  1.00  0.00
ATOM     16  H3  LIG     1     4.812   -2.037   0.000  1.00  0.00
ATOM     17  C3  LIG     1     4.342   -0.003   0.000  1.00  0.00
ATOM     18  H4  LIG     1     3.261   -0.005   0.000  1.00  0.00
ATOM     19  N2  LIG     1     5.135    1.073   0.000  1.00  0.00
ATOM     20  H5  LIG     1     4.803    2.034   0.000  1.00  0.00
Kaushal Modi
  • 25,203
  • 3
  • 74
  • 179
3

You can always use M-x query-replace-regexp, if you're comfortable with regexps and elisp.

Replacing:

^\(\(?:[^ ]+ +\)\{5\}\)\([ -][0-9.]+\)

With:

\1\,(format "% .3f" (+ 5.487 \#2))

Will replace the second captured group (being the 6th column) with the formatted result of the calculation.

This will break the alignment slightly if the numbers get too large, but you could tweak the pattern and formatting as necessary.

You could also use rectangle editing to copy the column in order to edit it on its own (thus simplifying the regexp by avoiding the need to match any other columns), and then replace the original rectangle with the modified one. That way the search pattern would simply be .+ (and in the replacement you would omit the \1 prefix, and use \#& instead of \#2).

phils
  • 48,657
  • 3
  • 76
  • 115
  • According to [the top answer to this question](http://stackoverflow.com/questions/11130546/search-and-replace-inside-a-rectangle-in-emacs), cua-selection-mode can do regexp on rectangle regions. If I wrap that in a function and give it a keybinding, this could be a good temporary solution! – holocronweaver Jan 23 '15 at 19:19
  • I'm familiar with that answer :) However I'm afraid the syntax used *here* (i.e. with the `\,(...)` expression in the replacement) is not a part of the regexp engine *in general*, but something specific to the interactive `[query-]replace-regexp` commands. The rectangle replacement functions referenced/implemented in that other answer, like pretty much all custom replacement commands, use a much simpler search/replace loop which does not invoke the more complicated `replace-regexp` machinery. – phils Jan 23 '15 at 22:26
  • That said, you could certainly write variants which *do* use `replace-regexp`. – phils Jan 23 '15 at 22:32
0

You can use the number package, also available from Melpa.

  • Bring the cursor to that number in row 1, col 6: -0.684▮
  • Record macro and run it as many times as possible - F3 M-x number/add RET 5.487 RET C-n M-0 F4

Voila!

Kaushal Modi
  • 25,203
  • 3
  • 74
  • 179