Skip to content

Commit 5026b7c

Browse files
committed
update references
1 parent 0ad608a commit 5026b7c

2 files changed

Lines changed: 583 additions & 0 deletions

File tree

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"---\n",
8+
"title: Convert a NumPy array to LaTeX\n",
9+
"description: LaTeX matrices and determinants from NumPy arrays\n",
10+
"author: 'Enrique Pérez Herrero'\n",
11+
"date: '08-02-2023'\n",
12+
"editor: source\n",
13+
"image: 'theta3x3matrix.png'\n",
14+
"draft: false\n",
15+
"categories:\n",
16+
" - Python\n",
17+
" - Numpy\n",
18+
" - Latex\n",
19+
" - Determinant\n",
20+
"---\n",
21+
"\n",
22+
"\n",
23+
"![Sierra de las Nieves (Málaga)](20180104_134329.jpg)\n",
24+
"\n",
25+
"# Convert Numpy array to $LaTeX$\n",
26+
"\n",
27+
"Sometimes, when you are writing a statistics or a math article, you must go\n",
28+
"through a tedious process of typing and testing numerous lines of text until\n",
29+
"your code works. This can be especially boring when dealing with long matrices.\n",
30+
"If you want to improve your productivity, automating this process comes in very\n",
31+
"handy, and [Python](https://www.python.org/) is particularly useful for that.\n",
32+
"\n",
33+
"\n",
34+
"## Functions for matrices and determinants\n",
35+
"\n",
36+
"The functions `matrix2latex` and `det2latex` generate an indented $LaTeX$ string\n",
37+
"that can be copied or directly rendered in your math article.\n",
38+
"\n",
39+
"The `INDENT_SPACES` parameter specifies the number of spaces used for\n",
40+
"indentation.\n"
41+
],
42+
"id": "127a872b"
43+
},
44+
{
45+
"cell_type": "code",
46+
"metadata": {},
47+
"source": [
48+
"#| label: latex_functions\n",
49+
"import numpy as np\n",
50+
"\n",
51+
"INDENT_SPACES = 3\n",
52+
"\n",
53+
"def indent(num_indent=1):\n",
54+
" \"\"\"\n",
55+
" Number of spaces for indentation\n",
56+
" \"\"\"\n",
57+
" return num_indent * INDENT_SPACES * \" \"\n",
58+
"\n",
59+
"def matrix2latex(matrix):\n",
60+
" \"\"\"\n",
61+
" Convert a NumPy array to LaTeX code as a matrix\n",
62+
" \"\"\"\n",
63+
" left_latex = r\"\\left(\" + \"\\n\" + indent(1) + r\"\\begin{array}\"\n",
64+
" right_latex = indent(1) + r\"\\end{array}\" + \"\\n\" + r\"\\right)\"\n",
65+
" m_cols = matrix.shape[1]\n",
66+
" array_cols = \"{\" + \"r\" * m_cols + \"}\\n\"\n",
67+
" elements_latex = \"\"\n",
68+
" for row in matrix:\n",
69+
" elements_latex = \\\n",
70+
" elements_latex + indent(2) + \" & \".join([str(x) for x in row]) + \\\n",
71+
" r\" \\\\ \" + \"\\n\"\n",
72+
" latex = left_latex + array_cols + elements_latex + right_latex\n",
73+
" return f\"$$\\n{latex}\\n$$\"\n",
74+
"\n",
75+
"def det2latex(matrix):\n",
76+
" \"\"\"\n",
77+
" Convert a NumPy array to LaTeX code as a determinant\n",
78+
" \"\"\"\n",
79+
" left_latex = r\"\\begin{vmatrix}\" + \"\\n\"\n",
80+
" right_latex = r\"\\end{vmatrix}\"\n",
81+
" m_cols = matrix.shape[1]\n",
82+
" elements_latex = \"\"\n",
83+
" for row in matrix:\n",
84+
" elements_latex = \\\n",
85+
" elements_latex + indent(1) + \" & \".join([str(x) for x in row]) + \\\n",
86+
" r\" \\\\ \" + \"\\n\"\n",
87+
" latex = left_latex + elements_latex + right_latex\n",
88+
" return f\"$$\\n{latex}\\n$$\""
89+
],
90+
"id": "latex_functions",
91+
"execution_count": null,
92+
"outputs": []
93+
},
94+
{
95+
"cell_type": "markdown",
96+
"metadata": {},
97+
"source": [
98+
"### Output string\n",
99+
"\n",
100+
"Using the [NumPy](https://numpy.org/) function `np.eye`, we can create an\n",
101+
"identity matrix of the desired dimensions, making it a convenient tool for\n",
102+
"testing our functions.\n"
103+
],
104+
"id": "b0e17845"
105+
},
106+
{
107+
"cell_type": "code",
108+
"metadata": {},
109+
"source": [
110+
"print(matrix2latex(np.eye(3, dtype=int)))"
111+
],
112+
"id": "bf31123b",
113+
"execution_count": null,
114+
"outputs": []
115+
},
116+
{
117+
"cell_type": "markdown",
118+
"metadata": {},
119+
"source": [
120+
"## Rendering output in a document\n",
121+
"\n",
122+
"If you are working in a [Jupyter](https://jupyter.org/) notebook, you can render\n",
123+
"a $LaTeX$ string using the `Math` function from the `IPython` library, which can\n",
124+
"be imported as follows:\n"
125+
],
126+
"id": "27e76398"
127+
},
128+
{
129+
"cell_type": "code",
130+
"metadata": {},
131+
"source": [
132+
"#| eval: false\n",
133+
"from IPython.display import Math"
134+
],
135+
"id": "29c0bda7",
136+
"execution_count": null,
137+
"outputs": []
138+
},
139+
{
140+
"cell_type": "markdown",
141+
"metadata": {},
142+
"source": [
143+
"If you are writing a `Python` chunk in a `Quarto` file in\n",
144+
"[RStudio](https://posit.co/download/rstudio-desktop/), you need to include the\n",
145+
"option `#| output: asis` at the top of the code chunk. This option determines\n",
146+
"how the output is rendered in the final document.\n"
147+
],
148+
"id": "22e95356"
149+
},
150+
{
151+
"cell_type": "code",
152+
"metadata": {},
153+
"source": [
154+
"#| label: identity_det\n",
155+
"#| output: asis\n",
156+
"print(det2latex(np.eye(3, dtype=int)))"
157+
],
158+
"id": "identity_det",
159+
"execution_count": null,
160+
"outputs": []
161+
},
162+
{
163+
"cell_type": "code",
164+
"metadata": {},
165+
"source": [
166+
"#| label: identity_matrix\n",
167+
"#| output: asis\n",
168+
"# Identity 4x4 matrix\n",
169+
"identity_4 = np.eye(4, dtype=int)\n",
170+
"identity_4_latex = r\"$$I_4 = \" + f\"{matrix2latex(identity_4)}\"[2:]\n",
171+
"print(identity_4_latex)"
172+
],
173+
"id": "identity_matrix",
174+
"execution_count": null,
175+
"outputs": []
176+
},
177+
{
178+
"cell_type": "markdown",
179+
"metadata": {},
180+
"source": [
181+
"## Rendering the output to a file\n",
182+
"\n",
183+
"The $LaTeX$ string can be rendered and saved to a file using the\n",
184+
"following function, which is based on the `SymPy` library.\n"
185+
],
186+
"id": "c767ecf6"
187+
},
188+
{
189+
"cell_type": "code",
190+
"metadata": {},
191+
"source": [
192+
"#| eval: false\n",
193+
"from sympy import preview\n",
194+
"\n",
195+
"def latex2png(latex, filename, fontsize=300):\n",
196+
" \"\"\"\n",
197+
" Render LaTeX code to a PNG image\n",
198+
" \"\"\"\n",
199+
" return preview(latex,\n",
200+
" viewer='file',\n",
201+
" filename=filename,\n",
202+
" euler=False,\n",
203+
" dvioptions=['-D', f'{str(fontsize)}'])"
204+
],
205+
"id": "1d678be2",
206+
"execution_count": null,
207+
"outputs": []
208+
},
209+
{
210+
"cell_type": "markdown",
211+
"metadata": {},
212+
"source": [
213+
"## Other types of automated matrices\n",
214+
"\n",
215+
"### Matrices with numbered elements\n"
216+
],
217+
"id": "2109eb16"
218+
},
219+
{
220+
"cell_type": "code",
221+
"metadata": {},
222+
"source": [
223+
"def element_matrix(n, notation=r\"x\"):\n",
224+
" \"\"\"\n",
225+
" Matrix with elements in algebraic notation \n",
226+
" \"\"\"\n",
227+
" vec_function = \\\n",
228+
" np.vectorize(lambda i, j: notation + \"_{\" + f\"{i + 1}{j + 1}\" + \"}\")\n",
229+
" return np.fromfunction(vec_function,\n",
230+
" shape=(n, n),\n",
231+
" dtype=int)"
232+
],
233+
"id": "e113a4fb",
234+
"execution_count": null,
235+
"outputs": []
236+
},
237+
{
238+
"cell_type": "code",
239+
"metadata": {},
240+
"source": [
241+
"#| label: element_matrix_example\n",
242+
"#| output: asis\n",
243+
"print(matrix2latex(element_matrix(5, notation=r\"\\theta\")))"
244+
],
245+
"id": "element_matrix_example",
246+
"execution_count": null,
247+
"outputs": []
248+
},
249+
{
250+
"cell_type": "markdown",
251+
"metadata": {},
252+
"source": [
253+
"### Triangular matrices\n",
254+
"\n",
255+
"* _Upper Triangular Matrix_: In an upper triangular matrix, all elements below the\n",
256+
"main diagonal are zero.\n"
257+
],
258+
"id": "23a78e28"
259+
},
260+
{
261+
"cell_type": "code",
262+
"metadata": {},
263+
"source": [
264+
"def up_triangular_matrix(n):\n",
265+
" \"\"\"\n",
266+
" Upper Triangular matrix filled with ones and zeros\n",
267+
" \"\"\"\n",
268+
" return np.fromfunction(lambda i, j: 1 * np.less_equal(i , j),\n",
269+
" shape=(n, n),\n",
270+
" dtype=int)"
271+
],
272+
"id": "82e86e4b",
273+
"execution_count": null,
274+
"outputs": []
275+
},
276+
{
277+
"cell_type": "markdown",
278+
"metadata": {},
279+
"source": [
280+
"* _Lower Triangular Matrix_: In a lower triangular matrix, all elements above the main diagonal are zero.\n"
281+
],
282+
"id": "9b7fa372"
283+
},
284+
{
285+
"cell_type": "code",
286+
"metadata": {},
287+
"source": [
288+
"def lw_triangular_matrix(n):\n",
289+
" \"\"\"\n",
290+
" Lower Triangular matrix filled with ones and zeros\n",
291+
" \"\"\"\n",
292+
" return np.fromfunction(lambda i, j: 1 * np.greater_equal(i , j),\n",
293+
" shape=(n, n),\n",
294+
" dtype=int)"
295+
],
296+
"id": "bac1687e",
297+
"execution_count": null,
298+
"outputs": []
299+
},
300+
{
301+
"cell_type": "code",
302+
"metadata": {},
303+
"source": [
304+
"#| label: upper_matrix_example\n",
305+
"#| output: asis\n",
306+
"print(matrix2latex(up_triangular_matrix(5)))"
307+
],
308+
"id": "upper_matrix_example",
309+
"execution_count": null,
310+
"outputs": []
311+
}
312+
],
313+
"metadata": {
314+
"kernelspec": {
315+
"name": "shiny-test",
316+
"language": "python",
317+
"display_name": "Shiny Test",
318+
"path": "/home/eph/.local/share/jupyter/kernels/shiny-test"
319+
}
320+
},
321+
"nbformat": 4,
322+
"nbformat_minor": 5
323+
}

0 commit comments

Comments
 (0)