last updated: 2021-01-12
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.
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")
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")
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 = fig.add_subplot(111)
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")
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))
plt.subplots_adjust(wspace=0, hspace=0)
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()
fig.subplots_adjust(left=0.07, right=0.93, top=0.92, bottom=0.1)
fig.show()
fig.savefig(svg_path + "capacitor_charging_discharging_diagrams.svg", format = "svg")