# Python coding

## Drawing with matplotlib

last updated: 2021-01-12

### Short description

For my tutorials and my webpage I need drawings. For this I like to use Inkscape, first because it is open source and second because it is performant. The Inkscape files (`.svg`) are vector graphics and are fully scalable. They can be easily embedded in a webpage with:

``````    <center><img src="svg/my_drawing.svg" alt="example drawing" width=900></center>
``````

For circuits I use KiCad, also open source. KiCad plots to svg. For formulas I use KLatexFormula, exporting to svg. But to draw mathematical functions I needed a good solution exporting to svg, and I found that `python 3` with the libraries `numpy`, `matplotlib` and sometimes `scipy` or `pandas` is a very good and cool solution. On this page I will toss some code snippets to remember them for later use.

### 6 subplots

``````    import numpy as np
import matplotlib.pyplot as plt
import scipy.signal

svg_path = "/savit/www.weigu/other_projects/python_coding/drawing_w_matplotlib/svg/"

xaxis_label = "time t / ms"
yaxis_label = "amplitude u(t) / V"
svg_size_small = (7.5,12)
svg_size_big = (20,30)

# produce data
t = np.linspace(0, 1, 1000, endpoint=True)
u1 = 5*np.sin(2 * np.pi * 5 * t)
u2 = 5*scipy.signal.square(2 * np.pi * 5 * t)
u3 = 5*scipy.signal.sawtooth(2 * np.pi * 5 * t, 0.5)
u4 = 5*scipy.signal.sawtooth(2 * np.pi * 5 * t)
u5 = -5*scipy.signal.sawtooth(2 * np.pi * 5 * t)
u6 = 5*np.ones(t.shape[0])
u6[np.where(u1<4.3)] = -5

# figure = drawing area
fig = plt.figure(figsize=(svg_size_small),tight_layout=True)

# 6 subplots, one for each curve
ax1 = fig.add_subplot(611) # 6 rows, 1 col, fig1
ax2 = fig.add_subplot(612) # 6 rows, 1 col, fig2
ax3 = fig.add_subplot(613) # 6 rows, 1 col, fig3
ax4 = fig.add_subplot(614) # 6 rows, 1 col, fig4
ax5 = fig.add_subplot(615) # 6 rows, 1 col, fig5
ax6 = fig.add_subplot(616) # 6 rows, 1 col, fig6

ax1.set_title('sine wave',fontsize = 12, fontweight = "bold",
verticalalignment = 'baseline')
ax1.grid(True, which='both')
ax1.set_xlabel(xaxis_label)
ax1.set_ylabel(yaxis_label)

ax2.set_title('square wave',fontsize = 12, fontweight = "bold",
verticalalignment = 'baseline')
ax2.grid(True, which='both')
ax2.set_xlabel(xaxis_label)
ax2.set_ylabel(yaxis_label)

ax3.set_title('triangle wave',fontsize = 12, fontweight = "bold",
verticalalignment = 'baseline')
ax3.grid(True, which='both')
ax3.set_xlabel(xaxis_label)
ax3.set_ylabel(yaxis_label)

ax4.set_title('sawtooth wave',fontsize = 12, fontweight = "bold",
verticalalignment = 'baseline')
ax4.grid(True, which='both')
ax4.set_xlabel(xaxis_label)
ax4.set_ylabel(yaxis_label)

ax5.set_title('inverted sawtooth wave',fontsize = 12, fontweight = "bold",
verticalalignment = 'baseline')
ax5.grid(True, which='both')
ax5.set_xlabel(xaxis_label)
ax5.set_ylabel(yaxis_label)

ax6.set_title(' PWM (Pulse Width Modulation) wave',fontsize = 12,
fontweight = "bold", verticalalignment = 'baseline')
ax6.grid(True, which='both')
ax6.set_xlabel(xaxis_label)
ax6.set_ylabel(yaxis_label)

l1, = ax1.plot(t, u1, 'b')
l1, = ax2.plot(t, u2, 'b')
l1, = ax3.plot(t, u3, 'b')
l1, = ax4.plot(t, u4, 'b')
l1, = ax5.plot(t, u5, 'b')
l1, = ax6.plot(t, u6, 'b')

fig.show()
fig.savefig(svg_path + "6_waveforms.svg", format = "svg") #, transparent = "True")
``````

### Fourier (FFT)

``````    import numpy as np
import matplotlib.pyplot as plt
import scipy.signal

svg_path = "/savit/www.weigu/other_projects/python_coding/drawing_w_matplotlib/svg/"

xaxis_label = "time t / ms"
yaxis_label = "amplitude u(t) / V"
xaxis_label_f = "frequency f / kHz"
yaxis_label_f = "ampl. spectrum"

svg_size_small = (7.5,12)
svg_size_big = (20,30)

n = 150
sampling_period = 5
interval = sampling_period / n

# produce data
t = np.linspace(0, 1, 1000, endpoint=True)
u1 = 5*np.sin(2 * np.pi * 5 * t)
tf = np.arange(0, sampling_period, interval)
f = np.arange(n / 2) / (n * interval)
u1f = 5*np.sin(2 * np.pi * 1 * tf)
u1ff = np.fft.fft(u1f)
u1fft = abs(u1ff[range(int(n / 2))] / n )

u2 = 5*scipy.signal.square(2 * np.pi * 5 * t)
u2f = 5*scipy.signal.square(2 * np.pi * 1 * tf)
u2ff = np.fft.fft(u2f)
u2fft = abs(u2ff[range(int(n / 2))] / n )

u3 = 5*scipy.signal.sawtooth(2 * np.pi * 5 * t)
u3f = 5*scipy.signal.sawtooth(2 * np.pi * 1 * tf)
u3ff = np.fft.fft(u3f)
u3fft = abs(u3ff[range(int(n / 2))] / n )

# figure = drawing area
fig = plt.figure(figsize=(svg_size_small),tight_layout=True)
# 6 subplots, one for each curve
ax1 = fig.add_subplot(611) # 6 rows, 1 col, fig1
ax2 = fig.add_subplot(612) # 6 rows, 1 col, fig2
ax3 = fig.add_subplot(613) # 6 rows, 1 col, fig3
ax4 = fig.add_subplot(614) # 6 rows, 1 col, fig4
ax5 = fig.add_subplot(615) # 6 rows, 1 col, fig5
ax6 = fig.add_subplot(616) # 6 rows, 1 col, fig6

ax1.set_title('sine wave',fontsize = 12, fontweight = "bold",
verticalalignment = 'baseline')
ax1.grid(True, which='both')
ax1.set_xlabel(xaxis_label)
ax1.set_ylabel(yaxis_label)

ax2.set_title('spectrum of sine wave',fontsize = 12, fontweight = "bold",
verticalalignment = 'baseline')
ax2.grid(True, which='both')
ax2.set_xlabel(xaxis_label_f)
ax2.set_ylabel(yaxis_label_f)

ax3.set_title('square wave',fontsize = 12, fontweight = "bold",
verticalalignment = 'baseline')
ax3.grid(True, which='both')
ax3.set_xlabel(xaxis_label)
ax3.set_ylabel(yaxis_label)

ax4.set_title('spectrum of square wave',fontsize = 12, fontweight = "bold",
verticalalignment = 'baseline')
ax4.grid(True, which='both')
ax4.set_xlabel(xaxis_label_f)
ax4.set_ylabel(yaxis_label_f)

ax5.set_title('sawtooth wave',fontsize = 12, fontweight = "bold",
verticalalignment = 'baseline')
ax5.grid(True, which='both')
ax5.set_xlabel(xaxis_label)
ax5.set_ylabel(yaxis_label)

ax6.set_title('spectrum of sawtooth wave',fontsize = 12,
fontweight = "bold", verticalalignment = 'baseline')
ax6.grid(True, which='both')
ax6.set_xlabel(xaxis_label_f)
ax6.set_ylabel(yaxis_label_f)

l1, = ax1.plot(t, u1, 'b')
l1, = ax2.plot(f, u1fft, 'b')
l1, = ax3.plot(t, u2, 'b')
l1, = ax4.plot(f, u2fft, 'b')
l1, = ax5.plot(t, u3, 'b')
l1, = ax6.plot(f, u3fft, 'b')

fig.show()
fig.savefig(svg_path + "spectrum_x_3.svg", format = "svg") #, transparent = "True")
``````

### Logarithmic scale

``````    import matplotlib.pyplot as plt
import numpy as np
# EDIT
R1 = 22
C1 = 2.2E-6  # fg= 3288
R2 = 14.15
C2 = 2.2E-6
R3 = 11.2
C3 = 2.2E-6
svg_path = "/savit/www.weigu/other_projects/python_coding/drawing_w_matplotlib/svg/"
# END EDIT
# create equally spaced log(f) values array f
flog = np.linspace(1.0, 6.0, 100)
f = 10.0 ** flog
# calculate F (complex) and absolute value Fabs
RC1 = R1*C1
RC2 = R2*C2
RC3 = R3*C3
jomega = 1j*2*np.pi*f
F1 = 1 / (1 + jomega*RC1)
F1abs = abs(F1)
F2 = (1 / (1 + jomega*RC2)) ** 2
F2abs = abs(F2)
F3 = (1 / (1 + jomega*RC3)) ** 3
F3abs = abs(F3)

fig = plt.figure()
ax.plot(f, F1abs)
ax.plot(f, F2abs)
ax.plot(f, F3abs)
ax.hlines(y=0.7071, xmin=0, xmax=1000000, linewidth=1, color='red')
ax.vlines(x=3288, ymin=-0, ymax=1, linewidth=1, color='red')
ax.margins(x=0)  # remove inner margins
ax.text(10, 0.71, "0.7071", fontsize=10, color="red")
ax.text(3100, -0.1, "fc", fontsize=10, color="red")
ax.grid(True, which = "both", linestyle = "-")
ax.set_xscale ("log")
ax.set_xlabel("f/Hz")
ax.set_ylabel("Uout/Uin")
ax.set_title("RC low-pass frequency response 1, 2 and 3 order")
fig.show()
fig.savefig(svg_path + "rc_low_pass_frequency_response_1-3_order.svg", format = "svg")
``````

### 2 plots side by side

``````    import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as ticker

# EDIT
R1 = 10000
C1 = 100E-6
U = 5
svg_path = "/savit/www.weigu/other_projects/python_coding/drawing_w_matplotlib/svg/"
# END EDIT

RC1 = R1*C1
t1 = np.linspace(0, 7, num=100)
t2 = np.linspace(7, 14, num=100)
u_c_c = 5*(1-np.exp(-t1/RC1))
i_c_c = 5*(np.exp(-t1/RC1))
u_c_d = 5*(np.exp(-t2+7/RC1))
i_c_d = -5*(np.exp(-t2+7/RC1))
tauline_c =5*t1
tauline_d =-5*(t2-7)+5

fig, (ax1,ax2) = plt.subplots(1, 2, dpi=300, figsize=(10,4))
ax1.plot(t1, u_c_c, color = 'blue')
ax1.plot(t1, i_c_c, color = 'red')
ax1.plot(t1, tauline_c, color = 'green',linewidth=0.7)
ax1.hlines(y=5, xmin=0, xmax=7, linewidth=0.7, color='black')
ax1.hlines(y=0, xmin=0, xmax=7, linewidth=1, color='black')
ax1.hlines(y=-5, xmin=0, xmax=7, linewidth=0.7, color='black')
ax1.hlines(y=3.15, xmin=0, xmax=2, linewidth=0.7, color='cyan')
ax1.text(1.35, 3.25, "63%", fontsize=10, color="cyan")
ax1.text(0.8, 5.05, "τ", fontsize=10, color="green")
ax1.text(1.85, 5.05, "2τ", fontsize=10, color="green")
ax1.text(2.85, 5.05, "3τ", fontsize=10, color="green")
ax1.text(3.85, 5.05, "4τ", fontsize=10, color="green")
ax1.text(4.85, 5.05, "5τ", fontsize=10, color="green")

ax2.plot(t2, u_c_d, color = 'blue')
ax2.plot(t2, i_c_d, color = 'red')

ax2.hlines(y=5, xmin=7, xmax=14, linewidth=0.7, color='black')
ax2.hlines(y=0, xmin=7, xmax=14, linewidth=1, color='black')
ax2.hlines(y=-5, xmin=7, xmax=14, linewidth=0.7, color='black')
ax2.text(8.1, 2.05, "37%", fontsize=10, color="cyan")
ax2.plot(t2, tauline_d, color = 'green', linewidth=0.7)
ax2.hlines(y=1.85, xmin=7, xmax=9, linewidth=0.7, color='cyan')
ax2.text(8, 5.05, "τ", fontsize=10, color="green")
ax2.text(8.85, 5.05, "2τ", fontsize=10, color="green")
ax2.text(9.85, 5.05, "3τ", fontsize=10, color="green")
ax2.text(10.85, 5.05, "4τ", fontsize=10, color="green")
ax2.text(11.85, 5.05, "5τ", fontsize=10, color="green")

ax1.margins(x=0)  # remove inner margins
ax2.margins(x=0)
ax1.grid(True, which = "both", linestyle = "-")
ax2.grid(True, which = "both", linestyle = "-")

ax1.set_ylim(-5.5,5.5)
ax2.set_ylim(-5.5,5.5)
ax1.set_yticks(np.arange(-5, 6, step=1)) # more ticks
ax2.set_yticks(np.arange(-5, 6, step=1))

ax1.set_ylabel("Uout/V", color="blue")
ax1.set_title("Charging a capacitor with 5V (τ=1ms)")
ax2.set_xlabel("t/ms")
ax2.set_title("Discharging a capacitor (R=10kΩ, C=100nF)")

ax3 = ax2.twinx()
ax3.set_ylim(-5.5,5.5)
ax3.set_yticks(np.arange(-5, 6, step=1)) # more ticks
ax3.set_ylabel("I/mA", color="red")

scale_y = 10  # Change only ax3 divide values by 10
ticks_y = ticker.FuncFormatter(lambda x, pos: '{0:g}'.format(x/scale_y))
ax3.yaxis.set_major_formatter(ticks_y)

ax2.label_outer()