Rapidly open 1,-1 data file as image - image

I'm working on a project that produces data files that are square matrices of numbers, either 1 or -1. I need to visualize this as images, and what I do now is using Matlab to open them, the matlab function imshow automatically draws those kind of matrices as monochrome black and white images.
Using matlab though is very slow and I was wondering if there was some linux program that I can fastly use from the terminal to do so, like an imagemagick oneliner or something similar.
This is an example of file
-1 1 -1 -1 1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 1 1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1
And this would be the image
The actual matrices would be of the order of 128x128.
Thank you!

It is trivial to convert your data to "PBM" format, even with a text editor,as I've done here. Change all of the " 1" to "0", "-1" to "1", and add a one-line header "P1 8 8 1" (substitute the actual width and height for "8 8"). Here's a one-line script matrix2pbm that does that:
echo P1 $2 $3 1; sed -e "s/-1/z/g; s/1/0/g; s/z/1/g" $1
Run it with
./matrix2pbm matrix.txt 8 8 > matrix.pbm
cat matrix.pbm
P1 8 8 1
1 0 1 1 0 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 0 0 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
The PBM format is one of the Netpbm image formats [http://en.wikipedia.org/wiki/Netpbm_format]
If you like, you can then use ImageMagick or some other file converter to convert the result into some other format:
convert matrix.pbm matrix.png
As emcconville commented, you can do both transformations with this one-liner:
./matrix2pbm matrix.txt 8 8 | convert pbm:- matrix.png

Related

Parse error when building my matrix, do not understand why

I'm trying to build a matrix out of linear equations but for some reason I keep getting a parse error in my matrix when previously I did not.
CoM=[K1*(abs(Q1).^r) K2*(abs(Q2).^r) -(K3*(abs(Q3).^r)) -(K4*(abs(Q4).^r)); K3*(abs(Q3).^r) -(K5*(abs(Q5).^r)) -(K6*(abs(Q6).^r) -(K7*(abs(Q7).^r) ; 1 -1 0 0 ; 1 1 -1 0 ; 1 -1 0 0 ; 1 -1 0 0 ; 1 1 -1 0];
^
error: parse error near line 1 of file '____'\WNA2loop.m
syntax error
CoM=[K1*(abs(Q1).^r) K2*(abs(Q2).^r) -(K3*(abs(Q3).^r)) -(K4*(abs(Q4).^r)); K3*(abs(Q3).^r) -(K5*(abs(Q5).^r)) -(K6*(abs(Q6).^r) -(K7*(abs(Q7).^r) ; 1 -1 0 0 ; 1 1 -1 0 ; 1 -1 0 0 ; 1 -1 0 0 ; 1 1 -1 0];
^
Right where I put the caret but when I take that small part of the matrix and run the command it
[1 -1 0 0 ; 1 1 -1 0 ; 1 -1 0 0 ; 1 -1 0 0 ; 1 1 -1 0]
ans = 1 -1 0 0
1 1 -1 0
1 -1 0 0
1 -1 0 0
1 1 -1 0
The K1 to K7 and Q1 to Q7 as well as the are just variables that get input by the user through the input function it worked before but now it just wont budge, could someone please provide assistance on this?

numeric vs alphanumeric sort on ubuntu 18.04.2

I am getting some strange behavior on sort utility on Ubuntu 18.04.2. Here's some sequence of commands issued. How can I ensure numeric sort for all the columns? column 1, 2, 3, 4 should be in order.
$ cat zz
0 0 0 0
0 1 0 0
1 0 0 0
1 1 0 0
1 1 1 0
1 1 1 1
2 2 2 2
10 10 10 10
1 1 10 1
1 1 100 1
$ cat zz | sort
0 0 0 0
0 1 0 0
1 0 0 0
10 10 10 10
1 1 0 0
1 1 1 0
1 1 100 1
1 1 10 1
1 1 1 1
2 2 2 2
$ cat zz | sort -n
0 0 0 0
0 1 0 0
1 0 0 0
1 1 0 0
1 1 1 0
1 1 100 1
1 1 10 1
1 1 1 1
2 2 2 2
10 10 10 10
$ cat zz | sort -n -k1,3
0 0 0 0
0 1 0 0
1 0 0 0
1 1 0 0
1 1 1 0
1 1 100 1
1 1 10 1
1 1 1 1
2 2 2 2
10 10 10 10
Desired output (with numeric sorting):
0 0 0 0
0 1 0 0
1 0 0 0
1 1 0 0
1 1 1 0
1 1 1 1
1 1 10 1
1 1 100 1
2 2 2 2
10 10 10 10
What options should I use in sort to get my desired output i.e. sorted in numeric order

Bash text file editing/modifying

I have a text file that I am trying to modify. I am taking the input file that has lines of the form of
(y+1/4,-x+1/2,z+3/4)
and trying to change it to
0 1 0 -1 0 0 0 0 1 1 / 4 1 / 2 3 / 4
I currently can get to this point
0 1 0 1/4 -1 0 0 1/2 0 0 1 3/4
using
#!bin/bash
filename="227.dat"
sed -i 's/(/ /g' $filename
sed -i 's/)//g' $filename
sed -i 's/,/ /g' $filename
sed -i 's/-x/-1 0 0/g' $filename
sed -i 's/x/ 1 0 0/g' $filename
sed -i 's/-y/ 0 -1 0/g' $filename
sed -i 's/y/ 0 1 0/g' $filename
sed -i 's/-z/ 0 0 -1/g' $filename
sed -i 's/z/ 0 0 1/g' $filename
sed -i '/+/! s/$/ 0 \/ 1 0 \/ 1 0 \/ 1/' $filename
while ((i++)); read -r line; do
if [[ $line == *[+]* ]]
then
sed -i 's/+/ /g' $filename
echo $i
fi
done < "$filename"
The reason for the echo $i was to see that it correctly gives the line number and I thought perhaps I could use it for commands on those specific lines. I am doing this conversion as the code we use in creating crystal structures needs the vector notation with fractions at the end, not the x,y,z notation. I already know this is not the "prettiest" or simplest solution, but I am very new to all of this and it's what I have been able to piece together so far. Any suggestions?
Here's an approach that may simplify the parsing. Read each line into an array using IFS set to all possible delimiters and characters you don't care about:
while IFS=$'\(\)+,' read -ra line; do
for i in 1 3 5; do
case "${line[$i]}" in
x) printf "%s\t%s\t%s\t" 1 0 0 ;;
y) printf "%s\t%s\t%s\t" 0 1 0 ;;
z) printf "%s\t%s\t%s\t" 0 0 1 ;;
-x) printf "%s\t%s\t%s\t" -1 0 0 ;;
-y) printf "%s\t%s\t%s\t" 0 -1 0 ;;
-z) printf "%s\t%s\t%s\t" 0 0 -1 ;;
esac
done
for i in 2 4 6; do
printf "%s\t" "${line[$i]}"
done
echo
done < "$filename"
#!/usr/bin/env bash
filename="227.dat"
re='[(]y[+]([[:digit:]/]+),-x[+]([[:digit:]/]+),z[+]([[:digit:]/]+)[)]';
while IFS= read -r line; do
if [[ $line =~ $re ]]; then
printf '\t%s' \
0 1 0 \
-1 0 0 \
0 0 1 \
"${BASH_REMATCH[1]}" \
"${BASH_REMATCH[2]}" \
"${BASH_REMATCH[3]}";
printf '\n';
else
echo "ERROR: $line does not match $re" 1>&2;
fi;
done <"$filename"
...given, your input, returns:
0 1 0 -1 0 0 0 0 1 1/4 1/2 3/4
...which as far as I can tell is correct.
A more complex approach, making unfounded extrapolations (given the lack of detail and exemplars in the question itself), might look like:
#!/usr/bin/env bash
while IFS='(),' read -a pieces; do
declare -A vars=( [x]=1 [y]=1 [z]=1 [x_sigil]='' [y_sigil]='' [z_sigil]='' )
for piece in "${pieces[#]}"; do
# 1 2 3 4
if [[ $piece =~ (-?)([xyz])([+]([[:digit:]/]+))? ]]; then
if [[ ${BASH_REMATCH[4]} ]]; then # only if there *are* digits
vars[${BASH_REMATCH[2]}]=${BASH_REMATCH[4]} # ...then store them.
fi
vars[${BASH_REMATCH[2]}_sigil]=${BASH_REMATCH[1]} # store - if applicable
fi
done
printf '\t%s' \
"0" "${vars[x_sigil]}1" 0 \
"${vars[y_sigil]}1" 0 0 \
0 0 "${vars[z_sigil]}1" \
"${vars[y]}" "${vars[x]}" "${vars[z]}"
printf '\n'
done
Given the sample inputs provided in a comment on this answer, output is:
0 1 0 1 0 0 0 0 1 1 1 1
0 1 0 1 0 0 0 0 1 1 1 1
0 1 0 1 0 0 0 0 1 1 1 1
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 1 0 -1 0 0 0 0 1 1/2 3/4 1/4
0 -1 0 1 0 0 0 0 1 1/4 1/2 3/4
0 -1 0 -1 0 0 0 0 -1 1 1 1
0 -1 0 -1 0 0 0 0 -1 1 1 1
0 -1 0 -1 0 0 0 0 -1 1 1 1
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
0 -1 0 1 0 0 0 0 -1 1/2 1/4 3/4
0 1 0 -1 0 0 0 0 -1 3/4 1/2 1/4
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
0 -1 0 -1 0 0 0 0 -1 1 1 1
0 -1 0 1 0 0 0 0 1 1/4 1/2 3/4
0 1 0 -1 0 0 0 0 1 1/2 3/4 1/4
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 1 0 1 0 0 0 0 1 1 1 1
0 1 0 -1 0 0 0 0 -1 3/4 1/2 1/4
0 -1 0 1 0 0 0 0 -1 1/2 1/4 3/4
0 -1 0 1 0 0 0 0 -1 1/2 1/4 3/4
0 -1 0 1 0 0 0 0 -1 1/2 1/4 3/4
0 -1 0 1 0 0 0 0 -1 1/2 1/4 3/4
0 -1 0 1 0 0 0 0 1 1/4 1/2 3/4

How to insert whitespace between characters of words in a specific field in a file

I have a file containing 100000 lines like this
1 0110100010010101
2 1000010010111001
3 1000011001111000
10 1011110000111110
123 0001000000100001
I would like to know how can I display efficiently just the second field by adding whitespaces between characters.
0 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1
1 0 0 0 0 1 0 0 1 0 1 1 1 0 0 1
1 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0
1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 0
0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1
One solution would be to get the second column with awk and then add the whitespaces using sed. But as the file is too long I would like to avoid using pipes. Then I'm wondering if I can do that by just using awk.
Thanks in advance
is this ok?
awk '{gsub(/./,"& ",$2);print $2}' yourFile
example
kent$ echo "1 0110100010010101
2 1000010010111001
3 1000011001111000"|awk '{gsub(/./,"& ",$2);print $2}'
0 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1
1 0 0 0 0 1 0 0 1 0 1 1 1 0 0 1
1 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0
update
more than 2 digits in 1st column won't work? I didn't get it:
kent$ echo "133 0110100010010101
233 1000010010111001
333 1000011001111000"|awk '{gsub(/./,"& ",$2);print $2}'
0 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1
1 0 0 0 0 1 0 0 1 0 1 1 1 0 0 1
1 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0
gsub(/./,"& ", $2)
1 /./ match any single character
2 "& " & here means the matched string, in this case, each character
3 $2 column 2
so it means, replace each character in 2nd column into the character itself + " ".
One way using only awk:
awk '{ gsub( /./, "& ", $2 ); print $2; }' infile
That yields:
0 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1
1 0 0 0 0 1 0 0 1 0 1 1 1 0 0 1
1 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0
EDIT: Kent and I gave the same implementation, so, for this answer to be a bit more useful, I will add the sed one:
sed -e 's/^[^ ]* *//; s/./& /g' infile
Just adding a sed alternative:
sed -e 's/^.* *//;s/./& /g;s/ $//' file
Three comands:
Remove the characters and spaces on the start of the line
Replace everycharacter with itself followed by a space
(Optional) Remove the trailing space at the end of the line
sed solution.
sed 's/.* //;s/\(.\)/\1 /g'
It adds an extra space at the end of each line. Add ;s/ $// to the expression to remove it.
This might work for you (GNU sed):
sed 's/^\S*\s*//;s/\B/ /g' /file

Diag Function to create a matrix

How would I go about creating the matrix
[1 2 0 0 0;
-1 1 2 0 0;
0 -1 1 2 0;
0 0 -1 1 2;
0 0 0 -1 1]
using the diag command in MatLab?
Here is one way:
> diag(ones(1,5),0)+diag(ones(1,4),1)*2+diag(ones(1,4),-1)*-1
ans =
1 2 0 0 0
-1 1 2 0 0
0 -1 1 2 0
0 0 -1 1 2
0 0 0 -1 1
>
This just creates three diagonals at 0, +1 and -1, scales them as needed, then adds them.

Resources