## The problem

I would love to have production-ready plots directly from python.

## The Solution

First of all download the following dependencies

```
pip install numpy
pip install matplotlib
pip install svglib
pip install reportlab
```

You also need to have latex installed on your system. Check the complete workflow for installation here.

We are now going to go step by step into understanding the complete workflow of building a plot for your scientific work.

**Figure**: It is the complete image that you get out of matplotlib**Axes**: It is the actual plotting area as seen in the grey background in the picture below.

### Selecting the proper plot size

It is very important to understand that figures and plots are a way of communicating your ideas and findings to a bigger community. Typically most of the research documents are made for an A4 size sheet of paper. The width of an A4 size paper is 210mm, take out the 30mm right and left margin and you are left with 150mm of usable space. That is the space that you should always use while designing your figures. Thus, you only have two width options

- 150mm if you are designing for full width
- 70mm if you are designing for a two-column layout

It is inside this space constraint that you have to draw. Thus, we will begin by setting up the space inside matplotlib

```
import matplotlib.pyplot as plt
import numpy as np
mm = 1/25.4 # millimeters in inches
fig = plt.figure(figsize=(70*mm,50*mm), dpi=200) # create a figure object
fig.subplots_adjust(left=0.1, right=0.9, top=0.75, bottom=0.15)
ax = fig.add_subplot(1, 1, 1) # create an axes object in the figure
plt.close() # Closes the plot in jupyter while creating axes
```

`plt.figure`

command will set the size of the figure and with the help of `plt.subplots_adjust`

we can adjust the padding around the plot as a percentage of the width and height of the figure. The arguments `left`

, `right`

, `bottom`

and `top`

are fractional units (of the total figure dimensions).

### Tell matplotlib to use LaTeX

Now we will tell python to use latex fonts and also **set the font size to 10**. This is the font size that we use for the main content of our article. It is very important to have consistency in the font size and your figure font size should `always`

match your article font size.

```
plt.rcParams.update({
"text.usetex": True,
"font.family": "serif",
"font.size": 10,
"pdf.fonttype":42})
```

The `pdf.fonttype`

option will force python to use `TrueType`

fonts

### Plot

Now the figure is ready to plot and save as a pdf. The figure will have the correct physical dimensions and the correct font size.

```
X = np.linspace(-np.pi, np.pi, 256,endpoint=True)
C,S = np.cos(X), np.sin(X)
ax.plot(X, C, color="blue", linewidth=1.5)
ax.plot(X, S, color="red", linewidth=1.5)
```

### Export the file to pdf

If you do not wish to edit your file you can now directly export it as a pdf using

```
fig.savefig("plot.pdf", format="pdf")
```

But, if you wish to edit your file in a vector-based editing program then the file generated from the above command would result in the wrong rendering of text. To prevent this we can save the figure as SVG and then convert that to pdf. Writing to SVG will convert the text to a path and thus it will render properly in a vector-based editing program. To do that use the following code

```
fig.savefig("plot.svg", format="svg")
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPDF
drawing = svg2rlg("plot.svg")
renderPDF.drawToFile(drawing, "plot.pdf")
```

### Complete code

```
import matplotlib.pyplot as plt
import numpy as np
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPDF
plt.rcParams.update({
"text.usetex": True,
"font.family": "serif",
"font.size": 10,
"pdf.fonttype":42})
mm = 1/25.4 # millimeters in inches
fig = plt.figure(figsize=(70*mm,50*mm), dpi=200) # create a figure object
fig.subplots_adjust(left=0.1, right=0.9, top=0.75, bottom=0.15)
ax = fig.add_subplot(1, 1, 1) # create an axes object in the figure
plt.close() # Closes the plot in jupyter while creating axes
X = np.linspace(-np.pi, np.pi, 256,endpoint=True)
C,S = np.cos(X), np.sin(X)
ax.plot(X, C, color="blue", linewidth=1.5, linestyle="-", label="cosine",
zorder=-1)
ax.plot(X, S, color="red", linewidth=1.5, linestyle="-", label="sine",
zorder=-2)
ax.set_xlim(X.min()*1.1, X.max()*1.1)
ax.set_xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi],
[r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$'])
ax.set_ylim(C.min()*1.1,C.max()*1.1)
ax.set_yticks([-1, +1],
[r'$-1$', r'$+1$'])
ax.legend(loc='upper left', frameon=True)
t = 2*np.pi/3
ax.scatter([t,],[np.sin(t),], 50, color ='red')
ax.annotate(r'$\sin(\frac{2\pi}{3})=\frac{\sqrt{3}}{2}$',
xy=(t, np.sin(t)), xycoords='data',
xytext=(-50, +30), textcoords='offset points',
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=-.2"))
for label in ax.get_xticklabels() + ax.get_yticklabels():
label.set_bbox(dict(facecolor='white', edgecolor='None', alpha=0.65 ))
fig.savefig("plot.svg", format="svg")
drawing = svg2rlg("plot.svg")
renderPDF.drawToFile(drawing, "plot.pdf")
```

## References

- Text rendering with LaTeX
- Rendering math equations using TeX
- Ten Simple Rules for Better Figures
- Matplotlib tutorial for beginner
- Figure size in centimeter
- Working with Fonts in Matplotlib
- Generating PDFs from SVG input
- Matplot lib color demo
- Python Plotting With Matplotlib (Real python)
- Moving to object based plotting