Python algorithm that converts array-like data into MathJaxInserting data into database by PythonPython data massagerPython script converts after effects clipboard keyframe data to nuke keyframe dataTetris-like algorithm (2D matrix)Python Script: Converts .tsv to TFRecordSort array into wave like arrayStroke Algorithm in pythonReading serial data from Arduino into Python every 100 msEffective fetching data algorithmAlgorithm that spans orthogonal vectors: Python
Will you be able to hear a supersonic aircraft flying away from you?
What are these tiny kidney bean sized things in my rotisserie chicken
Did any astronauts on a mission complain about waking up?
copying files with a string in their name from one folder to another
20 cards with no Set
Is there a benefit to leaving reviews on Expedia?
Is camera at risk of condensation in cold temperatures if never removed from bag?
What would cause vast differences in lifespans between the sexes?
Are the expansion number tokens in 5-6 players expansion different from the basic Catan?
Variable in SOSL Query
Affrication-like sound in palatal plosive [c]
What is the purpose of R1 in this circuit?
What does Darth Vader think Obi-Wan's referring to when Obi says "If you strike me down..."
How to quantify Code Quality
How to use rules — did this change between editions and how?
Christmas party and autism
Doing chemistry under water?
PyQGIS using selected layer from a combobox
Paint Exterior Door that is in Sun
Mordhau grip for bludgeoning damage?
How do people create difficult, recreational problems (e.g. like those found in competitions such as the IMO)?
Why do airline tickets have titles in addition to names?
Why would a life company agree to a 20-year guaranteed life annuity which is expected to pay out more than the principal?
Why is the Exchange French considered drawish?
Python algorithm that converts array-like data into MathJax
Inserting data into database by PythonPython data massagerPython script converts after effects clipboard keyframe data to nuke keyframe dataTetris-like algorithm (2D matrix)Python Script: Converts .tsv to TFRecordSort array into wave like arrayStroke Algorithm in pythonReading serial data from Arduino into Python every 100 msEffective fetching data algorithmAlgorithm that spans orthogonal vectors: Python
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;
$begingroup$
I frequently use MathJax, and often I need to write matrices. Since writing matrices using MathJax is very tiresome task, I decided to automate it.
Code:
import numpy as np
import pyperclip
class Conversion():
def __init__(self, matrix, n = None, m = None):
if matrix == None:
self.matrix = np.random.randint(-10,10, size = [n,m])
else:
'''If variable "matrix", for example, contains [1,2,3,4], instead of [[1,2,3,4]], functions below
will throw error, hence we need to make sure that the data type is correct.'''
if type(matrix[0]) in (str,int,float):
self.matrix = np.array([matrix,])
else:
self.matrix = np.array(matrix)
self.rows = len(self.matrix)
self.cols = len(self.matrix[0])
def single(self, choosen_brackets = ')'):
available_brackets = ' ' : 'matrix',
')' : 'pmatrix',
']' : 'bmatrix',
'' : 'Bmatrix',
'|' : 'vmatrix',
'||': 'Vmatrix' }
choosen_brackets = available_brackets[choosen_brackets]
body = '$$\begin n'.format('' + choosen_brackets + '')
for row in self.matrix:
row = [str(x) for x in row]
body += ' & '.join(row) + '\\' + 'n'
body +='end $$'.format('' + choosen_brackets + '')
print(body)
pyperclip.copy(body)
def augmented(self, choosen_brackets = '[]'):
'''We are assuming that the last column of the given matrix is a vector.'''
pos_of_the_verticar_bar = '' + 'c'*(self.cols-1) + ''
body = '$$\left [ \begin array %s n' % (pos_of_the_verticar_bar)
for row in self.matrix:
row = [str(x) for x in row]
body += ' & '.join(row) + '\\' + 'n'
body +='end array \right ]$$'
print(body)
pyperclip.copy(body)
Notes:
Since function
augmented
is quite similar tosingle
, I could've merged them into one. However, I think that keeping them separate makes the code a little bit more readable.On MSE, mathjax equations are enclosed with
$$
instead of$
"
single
" is a bad name for a function, I admit. I haven't found any better options. Feel free to offer suggestions.
What can be improved?
Written for Python 3.6.5.
python python-3.x matrix formatting latex
$endgroup$
add a comment
|
$begingroup$
I frequently use MathJax, and often I need to write matrices. Since writing matrices using MathJax is very tiresome task, I decided to automate it.
Code:
import numpy as np
import pyperclip
class Conversion():
def __init__(self, matrix, n = None, m = None):
if matrix == None:
self.matrix = np.random.randint(-10,10, size = [n,m])
else:
'''If variable "matrix", for example, contains [1,2,3,4], instead of [[1,2,3,4]], functions below
will throw error, hence we need to make sure that the data type is correct.'''
if type(matrix[0]) in (str,int,float):
self.matrix = np.array([matrix,])
else:
self.matrix = np.array(matrix)
self.rows = len(self.matrix)
self.cols = len(self.matrix[0])
def single(self, choosen_brackets = ')'):
available_brackets = ' ' : 'matrix',
')' : 'pmatrix',
']' : 'bmatrix',
'' : 'Bmatrix',
'|' : 'vmatrix',
'||': 'Vmatrix' }
choosen_brackets = available_brackets[choosen_brackets]
body = '$$\begin n'.format('' + choosen_brackets + '')
for row in self.matrix:
row = [str(x) for x in row]
body += ' & '.join(row) + '\\' + 'n'
body +='end $$'.format('' + choosen_brackets + '')
print(body)
pyperclip.copy(body)
def augmented(self, choosen_brackets = '[]'):
'''We are assuming that the last column of the given matrix is a vector.'''
pos_of_the_verticar_bar = '' + 'c'*(self.cols-1) + ''
body = '$$\left [ \begin array %s n' % (pos_of_the_verticar_bar)
for row in self.matrix:
row = [str(x) for x in row]
body += ' & '.join(row) + '\\' + 'n'
body +='end array \right ]$$'
print(body)
pyperclip.copy(body)
Notes:
Since function
augmented
is quite similar tosingle
, I could've merged them into one. However, I think that keeping them separate makes the code a little bit more readable.On MSE, mathjax equations are enclosed with
$$
instead of$
"
single
" is a bad name for a function, I admit. I haven't found any better options. Feel free to offer suggestions.
What can be improved?
Written for Python 3.6.5.
python python-3.x matrix formatting latex
$endgroup$
add a comment
|
$begingroup$
I frequently use MathJax, and often I need to write matrices. Since writing matrices using MathJax is very tiresome task, I decided to automate it.
Code:
import numpy as np
import pyperclip
class Conversion():
def __init__(self, matrix, n = None, m = None):
if matrix == None:
self.matrix = np.random.randint(-10,10, size = [n,m])
else:
'''If variable "matrix", for example, contains [1,2,3,4], instead of [[1,2,3,4]], functions below
will throw error, hence we need to make sure that the data type is correct.'''
if type(matrix[0]) in (str,int,float):
self.matrix = np.array([matrix,])
else:
self.matrix = np.array(matrix)
self.rows = len(self.matrix)
self.cols = len(self.matrix[0])
def single(self, choosen_brackets = ')'):
available_brackets = ' ' : 'matrix',
')' : 'pmatrix',
']' : 'bmatrix',
'' : 'Bmatrix',
'|' : 'vmatrix',
'||': 'Vmatrix' }
choosen_brackets = available_brackets[choosen_brackets]
body = '$$\begin n'.format('' + choosen_brackets + '')
for row in self.matrix:
row = [str(x) for x in row]
body += ' & '.join(row) + '\\' + 'n'
body +='end $$'.format('' + choosen_brackets + '')
print(body)
pyperclip.copy(body)
def augmented(self, choosen_brackets = '[]'):
'''We are assuming that the last column of the given matrix is a vector.'''
pos_of_the_verticar_bar = '' + 'c'*(self.cols-1) + ''
body = '$$\left [ \begin array %s n' % (pos_of_the_verticar_bar)
for row in self.matrix:
row = [str(x) for x in row]
body += ' & '.join(row) + '\\' + 'n'
body +='end array \right ]$$'
print(body)
pyperclip.copy(body)
Notes:
Since function
augmented
is quite similar tosingle
, I could've merged them into one. However, I think that keeping them separate makes the code a little bit more readable.On MSE, mathjax equations are enclosed with
$$
instead of$
"
single
" is a bad name for a function, I admit. I haven't found any better options. Feel free to offer suggestions.
What can be improved?
Written for Python 3.6.5.
python python-3.x matrix formatting latex
$endgroup$
I frequently use MathJax, and often I need to write matrices. Since writing matrices using MathJax is very tiresome task, I decided to automate it.
Code:
import numpy as np
import pyperclip
class Conversion():
def __init__(self, matrix, n = None, m = None):
if matrix == None:
self.matrix = np.random.randint(-10,10, size = [n,m])
else:
'''If variable "matrix", for example, contains [1,2,3,4], instead of [[1,2,3,4]], functions below
will throw error, hence we need to make sure that the data type is correct.'''
if type(matrix[0]) in (str,int,float):
self.matrix = np.array([matrix,])
else:
self.matrix = np.array(matrix)
self.rows = len(self.matrix)
self.cols = len(self.matrix[0])
def single(self, choosen_brackets = ')'):
available_brackets = ' ' : 'matrix',
')' : 'pmatrix',
']' : 'bmatrix',
'' : 'Bmatrix',
'|' : 'vmatrix',
'||': 'Vmatrix' }
choosen_brackets = available_brackets[choosen_brackets]
body = '$$\begin n'.format('' + choosen_brackets + '')
for row in self.matrix:
row = [str(x) for x in row]
body += ' & '.join(row) + '\\' + 'n'
body +='end $$'.format('' + choosen_brackets + '')
print(body)
pyperclip.copy(body)
def augmented(self, choosen_brackets = '[]'):
'''We are assuming that the last column of the given matrix is a vector.'''
pos_of_the_verticar_bar = '' + 'c'*(self.cols-1) + ''
body = '$$\left [ \begin array %s n' % (pos_of_the_verticar_bar)
for row in self.matrix:
row = [str(x) for x in row]
body += ' & '.join(row) + '\\' + 'n'
body +='end array \right ]$$'
print(body)
pyperclip.copy(body)
Notes:
Since function
augmented
is quite similar tosingle
, I could've merged them into one. However, I think that keeping them separate makes the code a little bit more readable.On MSE, mathjax equations are enclosed with
$$
instead of$
"
single
" is a bad name for a function, I admit. I haven't found any better options. Feel free to offer suggestions.
What can be improved?
Written for Python 3.6.5.
python python-3.x matrix formatting latex
python python-3.x matrix formatting latex
edited Oct 16 at 3:44
200_success
136k21 gold badges175 silver badges448 bronze badges
136k21 gold badges175 silver badges448 bronze badges
asked Oct 15 at 14:46
NelverNelver
37512 bronze badges
37512 bronze badges
add a comment
|
add a comment
|
2 Answers
2
active
oldest
votes
$begingroup$
This looks like a handy tool to have around, maybe we can make it even better.
Style
As per the official Python Style Guide (often known by his nickname PEP8), keyword-arguments of functions should have no whitespace around the =
.
Matrix size
numpy arrays have a property called .shape
which describes their number of rows and number of cols (in case of a 2D array at least). So
self.rows = len(self.matrix)
self.cols = len(self.matrix[0])
could become
self.rows, self.cols = self.matrix.shape
Since your code only works for 2D matrices, it's maybe also a good idea to check for that. The .ndim
attribute can be of help here.
Type checking
type(matrix[0]) in (str,int,float)
should instead be isinstance(matrix[0], (str, int, float))
.
Checking None
The official recommendation is to always use if sth is None:
when checking for None
.
String joining
row = [str(x) for x in row]
body += ' & '.join(row) + '\\' + 'n'
could be done in a single line:
body += ' & '.join(str(x) for x in row) + '\\' + 'n'
This means you also don't have to reassign row
to be something different than it was before.
String formatting
Since you said you're using Python 3.6, maybe have a look at f-strings for even more concise string formatting syntax. No matter if you choose to do this, maybe at least get rid of the old-style %
formatting in augmented(...)
by escaping and
using a leading
.
Function output
I find it preferable if you'd let the user decide what he wants to do with what your function returns. So instead of printing and copying the formatted matrix code, maybe just return body
and let the caller decide how to proceed from here. You could even define a "convenience" function (to_clipboard
) that basically only does pyperclip.copy(...)
, although this is likely not necessary. Another idea would be to make at least the copy
part opt-in via a "flag" bool parameter.
Class
Maybe a class is not the right tool here. A possible alternative would be to move what's done in __init__
into a "private" (read name starts with _
) helper function and get rid of the class.
Missing backslash
There seems to be a little bug in both of your functions (see how bad code duplication is ;-)): body +='end ...
is likely missing an additional .
Unused argument
If I'm not mistaken, the choosen_brackets
argument of augmented
is not used in the function.
Typo
choosen_brackets
should likely be chosen_brackets
$endgroup$
$begingroup$
Thank you for your review! May I ask why it is recommended to useis None
instead of== None
?
$endgroup$
– Nelver
Oct 16 at 2:19
$begingroup$
Strictly speaking,is
checks if both variables point to the exact same object in memory and not just that they compare equal. SinceNone
is a singleton, this is likely the more natural operation to use. But to be honest, there are probably not a lot of (other) hard facts why you should useis None
over== None
. Both variants will give you the desired result here.
$endgroup$
– AlexV
Oct 16 at 7:47
add a comment
|
$begingroup$
Python's string formatting has come a long way from the "%s"
formatting days. Nowadays classes can even determine on their own how to handle format specifiers. Therefore I would write a matrix class that can be pretty printed with different format options determining the matrix style.
class MathJaxMatrix:
brackets = '': 'matrix',
'p': 'pmatrix',
'b': 'bmatrix',
'B': 'Bmatrix',
'v': 'vmatrix',
'V': 'Vmatrix'
e_msg = "unsupported format string passed to MathJaxMatrix.__format__"
def __init__(self, m):
if m.ndim == 1:
m = m.reshape(len(m), 1)
self.m = m
self.rows, self.cols = m.shape
def __str__(self):
return "\\ n".join(" & ".join(str(x) for x in row) for row in self.m)
def __format__(self, format_spec=None):
if format_spec is None:
return str(self)
if format_spec == "a":
format_spec = 'c'
start = rf'$$left[ beginarrayformat_spec'
end = r'endarray right]$$'
else:
try:
brackets = self.brackets[format_spec]
except KeyError as e:
raise TypeError(self.e_msg) from e
start = f'$$ \beginbrackets'
end = f'endbrackets $$'
return "n".join([start, str(self), end])
Which you can use like this:
In [40]: x = np.random.rand(4, 5)
In [41]: m = MathJaxMatrix(x)
In [42]: print(m)
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
In [43]: print(f"m")
$$beginmatrix
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endmatrix $$
In [44]: print(f"m:p")
$$beginpmatrix
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endpmatrix $$
In [45]: print(f"m:a")
$$ left[ beginarrayc
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endarray right] $$
In [62]: print(f"m:e")
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
...
KeyError: 'e'
The above exception was the direct cause of the following exception:
TypeError Traceback (most recent call last)
...
TypeError: unsupported format string passed to MathJaxMatrix.__format__
Note that this removes the repeated code for getting a string representation of the actual matrix, uses np.ndarray.ndim
and np.reshape
to ensure it is a proper 2D matrix. I used the first letter of the different *matrix
options to distinguish them because }
is not allowed in format specifications.
The actual convenience function is then quite short:
def format_matrix(m, format_spec):
m = MathJaxMatrix(m)
s = f"m:format_spec"
print(s)
pyperclip.copy(s)
$endgroup$
add a comment
|
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f230758%2fpython-algorithm-that-converts-array-like-data-into-mathjax%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
This looks like a handy tool to have around, maybe we can make it even better.
Style
As per the official Python Style Guide (often known by his nickname PEP8), keyword-arguments of functions should have no whitespace around the =
.
Matrix size
numpy arrays have a property called .shape
which describes their number of rows and number of cols (in case of a 2D array at least). So
self.rows = len(self.matrix)
self.cols = len(self.matrix[0])
could become
self.rows, self.cols = self.matrix.shape
Since your code only works for 2D matrices, it's maybe also a good idea to check for that. The .ndim
attribute can be of help here.
Type checking
type(matrix[0]) in (str,int,float)
should instead be isinstance(matrix[0], (str, int, float))
.
Checking None
The official recommendation is to always use if sth is None:
when checking for None
.
String joining
row = [str(x) for x in row]
body += ' & '.join(row) + '\\' + 'n'
could be done in a single line:
body += ' & '.join(str(x) for x in row) + '\\' + 'n'
This means you also don't have to reassign row
to be something different than it was before.
String formatting
Since you said you're using Python 3.6, maybe have a look at f-strings for even more concise string formatting syntax. No matter if you choose to do this, maybe at least get rid of the old-style %
formatting in augmented(...)
by escaping and
using a leading
.
Function output
I find it preferable if you'd let the user decide what he wants to do with what your function returns. So instead of printing and copying the formatted matrix code, maybe just return body
and let the caller decide how to proceed from here. You could even define a "convenience" function (to_clipboard
) that basically only does pyperclip.copy(...)
, although this is likely not necessary. Another idea would be to make at least the copy
part opt-in via a "flag" bool parameter.
Class
Maybe a class is not the right tool here. A possible alternative would be to move what's done in __init__
into a "private" (read name starts with _
) helper function and get rid of the class.
Missing backslash
There seems to be a little bug in both of your functions (see how bad code duplication is ;-)): body +='end ...
is likely missing an additional .
Unused argument
If I'm not mistaken, the choosen_brackets
argument of augmented
is not used in the function.
Typo
choosen_brackets
should likely be chosen_brackets
$endgroup$
$begingroup$
Thank you for your review! May I ask why it is recommended to useis None
instead of== None
?
$endgroup$
– Nelver
Oct 16 at 2:19
$begingroup$
Strictly speaking,is
checks if both variables point to the exact same object in memory and not just that they compare equal. SinceNone
is a singleton, this is likely the more natural operation to use. But to be honest, there are probably not a lot of (other) hard facts why you should useis None
over== None
. Both variants will give you the desired result here.
$endgroup$
– AlexV
Oct 16 at 7:47
add a comment
|
$begingroup$
This looks like a handy tool to have around, maybe we can make it even better.
Style
As per the official Python Style Guide (often known by his nickname PEP8), keyword-arguments of functions should have no whitespace around the =
.
Matrix size
numpy arrays have a property called .shape
which describes their number of rows and number of cols (in case of a 2D array at least). So
self.rows = len(self.matrix)
self.cols = len(self.matrix[0])
could become
self.rows, self.cols = self.matrix.shape
Since your code only works for 2D matrices, it's maybe also a good idea to check for that. The .ndim
attribute can be of help here.
Type checking
type(matrix[0]) in (str,int,float)
should instead be isinstance(matrix[0], (str, int, float))
.
Checking None
The official recommendation is to always use if sth is None:
when checking for None
.
String joining
row = [str(x) for x in row]
body += ' & '.join(row) + '\\' + 'n'
could be done in a single line:
body += ' & '.join(str(x) for x in row) + '\\' + 'n'
This means you also don't have to reassign row
to be something different than it was before.
String formatting
Since you said you're using Python 3.6, maybe have a look at f-strings for even more concise string formatting syntax. No matter if you choose to do this, maybe at least get rid of the old-style %
formatting in augmented(...)
by escaping and
using a leading
.
Function output
I find it preferable if you'd let the user decide what he wants to do with what your function returns. So instead of printing and copying the formatted matrix code, maybe just return body
and let the caller decide how to proceed from here. You could even define a "convenience" function (to_clipboard
) that basically only does pyperclip.copy(...)
, although this is likely not necessary. Another idea would be to make at least the copy
part opt-in via a "flag" bool parameter.
Class
Maybe a class is not the right tool here. A possible alternative would be to move what's done in __init__
into a "private" (read name starts with _
) helper function and get rid of the class.
Missing backslash
There seems to be a little bug in both of your functions (see how bad code duplication is ;-)): body +='end ...
is likely missing an additional .
Unused argument
If I'm not mistaken, the choosen_brackets
argument of augmented
is not used in the function.
Typo
choosen_brackets
should likely be chosen_brackets
$endgroup$
$begingroup$
Thank you for your review! May I ask why it is recommended to useis None
instead of== None
?
$endgroup$
– Nelver
Oct 16 at 2:19
$begingroup$
Strictly speaking,is
checks if both variables point to the exact same object in memory and not just that they compare equal. SinceNone
is a singleton, this is likely the more natural operation to use. But to be honest, there are probably not a lot of (other) hard facts why you should useis None
over== None
. Both variants will give you the desired result here.
$endgroup$
– AlexV
Oct 16 at 7:47
add a comment
|
$begingroup$
This looks like a handy tool to have around, maybe we can make it even better.
Style
As per the official Python Style Guide (often known by his nickname PEP8), keyword-arguments of functions should have no whitespace around the =
.
Matrix size
numpy arrays have a property called .shape
which describes their number of rows and number of cols (in case of a 2D array at least). So
self.rows = len(self.matrix)
self.cols = len(self.matrix[0])
could become
self.rows, self.cols = self.matrix.shape
Since your code only works for 2D matrices, it's maybe also a good idea to check for that. The .ndim
attribute can be of help here.
Type checking
type(matrix[0]) in (str,int,float)
should instead be isinstance(matrix[0], (str, int, float))
.
Checking None
The official recommendation is to always use if sth is None:
when checking for None
.
String joining
row = [str(x) for x in row]
body += ' & '.join(row) + '\\' + 'n'
could be done in a single line:
body += ' & '.join(str(x) for x in row) + '\\' + 'n'
This means you also don't have to reassign row
to be something different than it was before.
String formatting
Since you said you're using Python 3.6, maybe have a look at f-strings for even more concise string formatting syntax. No matter if you choose to do this, maybe at least get rid of the old-style %
formatting in augmented(...)
by escaping and
using a leading
.
Function output
I find it preferable if you'd let the user decide what he wants to do with what your function returns. So instead of printing and copying the formatted matrix code, maybe just return body
and let the caller decide how to proceed from here. You could even define a "convenience" function (to_clipboard
) that basically only does pyperclip.copy(...)
, although this is likely not necessary. Another idea would be to make at least the copy
part opt-in via a "flag" bool parameter.
Class
Maybe a class is not the right tool here. A possible alternative would be to move what's done in __init__
into a "private" (read name starts with _
) helper function and get rid of the class.
Missing backslash
There seems to be a little bug in both of your functions (see how bad code duplication is ;-)): body +='end ...
is likely missing an additional .
Unused argument
If I'm not mistaken, the choosen_brackets
argument of augmented
is not used in the function.
Typo
choosen_brackets
should likely be chosen_brackets
$endgroup$
This looks like a handy tool to have around, maybe we can make it even better.
Style
As per the official Python Style Guide (often known by his nickname PEP8), keyword-arguments of functions should have no whitespace around the =
.
Matrix size
numpy arrays have a property called .shape
which describes their number of rows and number of cols (in case of a 2D array at least). So
self.rows = len(self.matrix)
self.cols = len(self.matrix[0])
could become
self.rows, self.cols = self.matrix.shape
Since your code only works for 2D matrices, it's maybe also a good idea to check for that. The .ndim
attribute can be of help here.
Type checking
type(matrix[0]) in (str,int,float)
should instead be isinstance(matrix[0], (str, int, float))
.
Checking None
The official recommendation is to always use if sth is None:
when checking for None
.
String joining
row = [str(x) for x in row]
body += ' & '.join(row) + '\\' + 'n'
could be done in a single line:
body += ' & '.join(str(x) for x in row) + '\\' + 'n'
This means you also don't have to reassign row
to be something different than it was before.
String formatting
Since you said you're using Python 3.6, maybe have a look at f-strings for even more concise string formatting syntax. No matter if you choose to do this, maybe at least get rid of the old-style %
formatting in augmented(...)
by escaping and
using a leading
.
Function output
I find it preferable if you'd let the user decide what he wants to do with what your function returns. So instead of printing and copying the formatted matrix code, maybe just return body
and let the caller decide how to proceed from here. You could even define a "convenience" function (to_clipboard
) that basically only does pyperclip.copy(...)
, although this is likely not necessary. Another idea would be to make at least the copy
part opt-in via a "flag" bool parameter.
Class
Maybe a class is not the right tool here. A possible alternative would be to move what's done in __init__
into a "private" (read name starts with _
) helper function and get rid of the class.
Missing backslash
There seems to be a little bug in both of your functions (see how bad code duplication is ;-)): body +='end ...
is likely missing an additional .
Unused argument
If I'm not mistaken, the choosen_brackets
argument of augmented
is not used in the function.
Typo
choosen_brackets
should likely be chosen_brackets
edited Oct 16 at 14:51
t2h
32 bronze badges
32 bronze badges
answered Oct 15 at 16:34
AlexVAlexV
5,1452 gold badges12 silver badges38 bronze badges
5,1452 gold badges12 silver badges38 bronze badges
$begingroup$
Thank you for your review! May I ask why it is recommended to useis None
instead of== None
?
$endgroup$
– Nelver
Oct 16 at 2:19
$begingroup$
Strictly speaking,is
checks if both variables point to the exact same object in memory and not just that they compare equal. SinceNone
is a singleton, this is likely the more natural operation to use. But to be honest, there are probably not a lot of (other) hard facts why you should useis None
over== None
. Both variants will give you the desired result here.
$endgroup$
– AlexV
Oct 16 at 7:47
add a comment
|
$begingroup$
Thank you for your review! May I ask why it is recommended to useis None
instead of== None
?
$endgroup$
– Nelver
Oct 16 at 2:19
$begingroup$
Strictly speaking,is
checks if both variables point to the exact same object in memory and not just that they compare equal. SinceNone
is a singleton, this is likely the more natural operation to use. But to be honest, there are probably not a lot of (other) hard facts why you should useis None
over== None
. Both variants will give you the desired result here.
$endgroup$
– AlexV
Oct 16 at 7:47
$begingroup$
Thank you for your review! May I ask why it is recommended to use
is None
instead of == None
?$endgroup$
– Nelver
Oct 16 at 2:19
$begingroup$
Thank you for your review! May I ask why it is recommended to use
is None
instead of == None
?$endgroup$
– Nelver
Oct 16 at 2:19
$begingroup$
Strictly speaking,
is
checks if both variables point to the exact same object in memory and not just that they compare equal. Since None
is a singleton, this is likely the more natural operation to use. But to be honest, there are probably not a lot of (other) hard facts why you should use is None
over == None
. Both variants will give you the desired result here.$endgroup$
– AlexV
Oct 16 at 7:47
$begingroup$
Strictly speaking,
is
checks if both variables point to the exact same object in memory and not just that they compare equal. Since None
is a singleton, this is likely the more natural operation to use. But to be honest, there are probably not a lot of (other) hard facts why you should use is None
over == None
. Both variants will give you the desired result here.$endgroup$
– AlexV
Oct 16 at 7:47
add a comment
|
$begingroup$
Python's string formatting has come a long way from the "%s"
formatting days. Nowadays classes can even determine on their own how to handle format specifiers. Therefore I would write a matrix class that can be pretty printed with different format options determining the matrix style.
class MathJaxMatrix:
brackets = '': 'matrix',
'p': 'pmatrix',
'b': 'bmatrix',
'B': 'Bmatrix',
'v': 'vmatrix',
'V': 'Vmatrix'
e_msg = "unsupported format string passed to MathJaxMatrix.__format__"
def __init__(self, m):
if m.ndim == 1:
m = m.reshape(len(m), 1)
self.m = m
self.rows, self.cols = m.shape
def __str__(self):
return "\\ n".join(" & ".join(str(x) for x in row) for row in self.m)
def __format__(self, format_spec=None):
if format_spec is None:
return str(self)
if format_spec == "a":
format_spec = 'c'
start = rf'$$left[ beginarrayformat_spec'
end = r'endarray right]$$'
else:
try:
brackets = self.brackets[format_spec]
except KeyError as e:
raise TypeError(self.e_msg) from e
start = f'$$ \beginbrackets'
end = f'endbrackets $$'
return "n".join([start, str(self), end])
Which you can use like this:
In [40]: x = np.random.rand(4, 5)
In [41]: m = MathJaxMatrix(x)
In [42]: print(m)
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
In [43]: print(f"m")
$$beginmatrix
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endmatrix $$
In [44]: print(f"m:p")
$$beginpmatrix
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endpmatrix $$
In [45]: print(f"m:a")
$$ left[ beginarrayc
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endarray right] $$
In [62]: print(f"m:e")
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
...
KeyError: 'e'
The above exception was the direct cause of the following exception:
TypeError Traceback (most recent call last)
...
TypeError: unsupported format string passed to MathJaxMatrix.__format__
Note that this removes the repeated code for getting a string representation of the actual matrix, uses np.ndarray.ndim
and np.reshape
to ensure it is a proper 2D matrix. I used the first letter of the different *matrix
options to distinguish them because }
is not allowed in format specifications.
The actual convenience function is then quite short:
def format_matrix(m, format_spec):
m = MathJaxMatrix(m)
s = f"m:format_spec"
print(s)
pyperclip.copy(s)
$endgroup$
add a comment
|
$begingroup$
Python's string formatting has come a long way from the "%s"
formatting days. Nowadays classes can even determine on their own how to handle format specifiers. Therefore I would write a matrix class that can be pretty printed with different format options determining the matrix style.
class MathJaxMatrix:
brackets = '': 'matrix',
'p': 'pmatrix',
'b': 'bmatrix',
'B': 'Bmatrix',
'v': 'vmatrix',
'V': 'Vmatrix'
e_msg = "unsupported format string passed to MathJaxMatrix.__format__"
def __init__(self, m):
if m.ndim == 1:
m = m.reshape(len(m), 1)
self.m = m
self.rows, self.cols = m.shape
def __str__(self):
return "\\ n".join(" & ".join(str(x) for x in row) for row in self.m)
def __format__(self, format_spec=None):
if format_spec is None:
return str(self)
if format_spec == "a":
format_spec = 'c'
start = rf'$$left[ beginarrayformat_spec'
end = r'endarray right]$$'
else:
try:
brackets = self.brackets[format_spec]
except KeyError as e:
raise TypeError(self.e_msg) from e
start = f'$$ \beginbrackets'
end = f'endbrackets $$'
return "n".join([start, str(self), end])
Which you can use like this:
In [40]: x = np.random.rand(4, 5)
In [41]: m = MathJaxMatrix(x)
In [42]: print(m)
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
In [43]: print(f"m")
$$beginmatrix
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endmatrix $$
In [44]: print(f"m:p")
$$beginpmatrix
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endpmatrix $$
In [45]: print(f"m:a")
$$ left[ beginarrayc
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endarray right] $$
In [62]: print(f"m:e")
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
...
KeyError: 'e'
The above exception was the direct cause of the following exception:
TypeError Traceback (most recent call last)
...
TypeError: unsupported format string passed to MathJaxMatrix.__format__
Note that this removes the repeated code for getting a string representation of the actual matrix, uses np.ndarray.ndim
and np.reshape
to ensure it is a proper 2D matrix. I used the first letter of the different *matrix
options to distinguish them because }
is not allowed in format specifications.
The actual convenience function is then quite short:
def format_matrix(m, format_spec):
m = MathJaxMatrix(m)
s = f"m:format_spec"
print(s)
pyperclip.copy(s)
$endgroup$
add a comment
|
$begingroup$
Python's string formatting has come a long way from the "%s"
formatting days. Nowadays classes can even determine on their own how to handle format specifiers. Therefore I would write a matrix class that can be pretty printed with different format options determining the matrix style.
class MathJaxMatrix:
brackets = '': 'matrix',
'p': 'pmatrix',
'b': 'bmatrix',
'B': 'Bmatrix',
'v': 'vmatrix',
'V': 'Vmatrix'
e_msg = "unsupported format string passed to MathJaxMatrix.__format__"
def __init__(self, m):
if m.ndim == 1:
m = m.reshape(len(m), 1)
self.m = m
self.rows, self.cols = m.shape
def __str__(self):
return "\\ n".join(" & ".join(str(x) for x in row) for row in self.m)
def __format__(self, format_spec=None):
if format_spec is None:
return str(self)
if format_spec == "a":
format_spec = 'c'
start = rf'$$left[ beginarrayformat_spec'
end = r'endarray right]$$'
else:
try:
brackets = self.brackets[format_spec]
except KeyError as e:
raise TypeError(self.e_msg) from e
start = f'$$ \beginbrackets'
end = f'endbrackets $$'
return "n".join([start, str(self), end])
Which you can use like this:
In [40]: x = np.random.rand(4, 5)
In [41]: m = MathJaxMatrix(x)
In [42]: print(m)
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
In [43]: print(f"m")
$$beginmatrix
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endmatrix $$
In [44]: print(f"m:p")
$$beginpmatrix
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endpmatrix $$
In [45]: print(f"m:a")
$$ left[ beginarrayc
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endarray right] $$
In [62]: print(f"m:e")
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
...
KeyError: 'e'
The above exception was the direct cause of the following exception:
TypeError Traceback (most recent call last)
...
TypeError: unsupported format string passed to MathJaxMatrix.__format__
Note that this removes the repeated code for getting a string representation of the actual matrix, uses np.ndarray.ndim
and np.reshape
to ensure it is a proper 2D matrix. I used the first letter of the different *matrix
options to distinguish them because }
is not allowed in format specifications.
The actual convenience function is then quite short:
def format_matrix(m, format_spec):
m = MathJaxMatrix(m)
s = f"m:format_spec"
print(s)
pyperclip.copy(s)
$endgroup$
Python's string formatting has come a long way from the "%s"
formatting days. Nowadays classes can even determine on their own how to handle format specifiers. Therefore I would write a matrix class that can be pretty printed with different format options determining the matrix style.
class MathJaxMatrix:
brackets = '': 'matrix',
'p': 'pmatrix',
'b': 'bmatrix',
'B': 'Bmatrix',
'v': 'vmatrix',
'V': 'Vmatrix'
e_msg = "unsupported format string passed to MathJaxMatrix.__format__"
def __init__(self, m):
if m.ndim == 1:
m = m.reshape(len(m), 1)
self.m = m
self.rows, self.cols = m.shape
def __str__(self):
return "\\ n".join(" & ".join(str(x) for x in row) for row in self.m)
def __format__(self, format_spec=None):
if format_spec is None:
return str(self)
if format_spec == "a":
format_spec = 'c'
start = rf'$$left[ beginarrayformat_spec'
end = r'endarray right]$$'
else:
try:
brackets = self.brackets[format_spec]
except KeyError as e:
raise TypeError(self.e_msg) from e
start = f'$$ \beginbrackets'
end = f'endbrackets $$'
return "n".join([start, str(self), end])
Which you can use like this:
In [40]: x = np.random.rand(4, 5)
In [41]: m = MathJaxMatrix(x)
In [42]: print(m)
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
In [43]: print(f"m")
$$beginmatrix
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endmatrix $$
In [44]: print(f"m:p")
$$beginpmatrix
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endpmatrix $$
In [45]: print(f"m:a")
$$ left[ beginarrayc
0.35170079706 & 0.903087473471 & 0.748996998207 & 0.741200595894 & 0.771233795397\
0.251204439922 & 0.40876741255 & 0.101668325527 & 0.738733484611 & 0.3052742949\
0.448079803976 & 0.273533142438 & 0.368031240997 & 0.34312026244 & 0.587809084934\
0.0192109217812 & 0.334069285732 & 0.644616319752 & 0.648226279564 & 0.307678962448
endarray right] $$
In [62]: print(f"m:e")
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
...
KeyError: 'e'
The above exception was the direct cause of the following exception:
TypeError Traceback (most recent call last)
...
TypeError: unsupported format string passed to MathJaxMatrix.__format__
Note that this removes the repeated code for getting a string representation of the actual matrix, uses np.ndarray.ndim
and np.reshape
to ensure it is a proper 2D matrix. I used the first letter of the different *matrix
options to distinguish them because }
is not allowed in format specifications.
The actual convenience function is then quite short:
def format_matrix(m, format_spec):
m = MathJaxMatrix(m)
s = f"m:format_spec"
print(s)
pyperclip.copy(s)
edited Oct 15 at 18:19
answered Oct 15 at 18:07
GraipherGraipher
31.8k6 gold badges50 silver badges108 bronze badges
31.8k6 gold badges50 silver badges108 bronze badges
add a comment
|
add a comment
|
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f230758%2fpython-algorithm-that-converts-array-like-data-into-mathjax%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown