Draw Cash Flow Diagrams in Python

Recently, I am studying engineering economics, and I often have to draw cash flow diagrams. Wish it was easier to draw cash flow diagrams in Python. Although I don’t know if this makes sense.

1. Draw a cash flow diagram based on the cash flow statement

Suppose you have the following cash flow statement:

project – year t

0

1

2

3

4

5

6

invest

600

income

350

350

450

450

450

450

Operating costs

200

200

250

250

250

250

It is desirable to draw a corresponding advanced flow diagram based on this cash flow statement.

code show as below:

""" Draw a Flow of Funds Diagram """

"Color Settings"
arrow_color = 'black'
axis_color = 'black'
title_color = 'black'

'Import the corresponding library'
import matplotlib.pyplot as plt
import numpy as np

' Set the plot title '
plt.title("Cash Flow Diagram", c=title_color)
plt.ylabel("Fund (ten thousand)")

' set initial variable value '
# Dispersion of chart elements
# It is convenient to adjust the chart distribution when the value changes
distance=50

# Use a second-order list to save the value of the cash flow
A = [[ -600, 0, 0, 0, 0, 0, 0 ] ,
     [ 0, 350, 350, 450, 450, 450, 450 ],
     [ 0, -200, -200, -250, -250, -250, -250 ] ]

'Draw a flow of money graph from a list'
# Distinguish between positive and negative values
# It is to make the label position of negative value lower and not affect the look and feel
for j in range(0,len(A)):
        for i in range(0,len(A[j])):
                if A[j][i] > 0:
                        plt.arrow(i, 0, 0, A[j][i]-distance, fc=arrow_color, ec=arrow_color, shape="full", head_width=0.1, head_length=distance, overhang=0.5)
                        plt.text(i + len(A)*0.01, A[j][i] + distance, str(round(A[j][i],2)))
                elif A[j][i] < 0:
                        plt.arrow(i, 0, 0, A[j][i]-distance, fc=arrow_color, ec=arrow_color, shape="full", head_width=0.1, head_length=distance, overhang=0.5)
                        plt.text(i + len(A)*0.01, A[j][i]-distance, str(round(A[j][i],2)))

' Set the characteristics of individual elements in the diagram '
# The following are actually nothing, mainly to beautify the chart

ax = plt.gca()

# Set the four coordinate axes to be invisible
ax.spines['top'].set_visible(False) # set the coordinate axis, the same below
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)

# Move the x-axis and its data labels into the chart
ax.spines['bottom'].set_position(('data',0))
plt.setp( ax.xaxis.get_majorticklabels(), ha="left" ) # right indicates that the X coordinate data labels are aligned to the right
plt.arrow(-0.1, 0, len(A[0]) + 1.2, 0, fc=axis_color, ec=axis_color, shape="full", head_width=distance*0.5, head_length=0.3, overhang=0.5 )

# hide the y coordinate
plt. yticks ([])

# Set the scale of the x-axis to 1
x_major_locator=plt.MultipleLocator(1) # Set the scale interval of the x-axis to 1 and store it in the variable
ax.xaxis.set_major_locator(x_major_locator) # Set the main scale of the x-axis to a multiple of 1

# Set the X Y range of the chart to prevent the drawing area from being too large or too small
plt.xlim(-0.1, len(A[0]) + 1.4)
plt.ylim(-15*distance, 15*distance)

'Adjust Chinese display '
plt.rcParams['font.sans-serif'] = ['SimHei'] # used to display Chinese labels normally
plt.rcParams['axes.unicode_minus'] = False # used to display the negative sign normally

'drawing'
plt. show()

Drawing effect:

2. Draw cash flow diagrams of equal amounts, equal differences, and equal ratio sequences

For the drawing of equal amount, equal difference, and proportional sequence cash flow diagrams, you can use a loop similar to the following. You can use the loop to generate a proportional sequence and add it to the first line of list A, and draw a proportional curve at the same time.

A[0].append(-30)

'Generate a sequence of ratios'
for i in range(0,7):
A[0].append(10*(1.2)**i)

# Draw a proportional curve
x = np.arange(1,8)
y = 10*(1.2**(x-1))
plt.plot(x,y, c='g', ls='--') 

Drawing effect:

3. Combining various drawing methods to draw a more complex cash flow diagram

Design a more complex matrix:

# Use a second-order list to save the value of the cash flow
A = [[ 0, 80000, 80000, 0 ] ,
     [ -100000, -30000, -30000, 0 ] ,
     [ 0, 0, 30000, 0 ] ,
     [ 0, 0, -300000, -50000 ] ,
     [ 0, 0, 0, 150000 ] ,
     [ 0, 0, 0, 240000 ]

Set arrow_color to be a list, and change the part that iterates over the matrix to arrow_color[j] to set a different color for each row of the matrix.

"Color Settings"
arrow_color = ['green','green','green','red','red','red']
axis_color = 'black'
title_color = 'black'
for j in range(0,len(A)):
        for i in range(0,len(A[j])):
                if A[j][i] > 0:
                        plt.arrow(i, 0, 0, A[j][i]-distance, fc=arrow_color[j], ec=arrow_color[j], shape="full", head_width=0.1, head_length=distance, overhang=0.5)
                        plt.text(i + len(A)*0.01, A[j][i] + distance, str(round(A[j][i],2)))
                elif A[j][i] < 0:
                        plt.arrow(i, 0, 0, A[j][i] + distance, fc=arrow_color[j], ec=arrow_color[j], shape="full", head_width=0.1, head_length=distance, overhang=0.5)
                        plt.text(i + len(A)*0.01, A[j][i]-distance, str(round(A[j][i],2)))

Add labels to label the funding rate and legend.

# add some tags
plt.text(0, 250000, r'interest rate $i_{c} = 10 %$')

'Add Legend'
line1, = plt.plot(1,1, 'g', label='old equipment cash flow')
line2, = plt.plot(2,2, 'r', label='new equipment cash flow')
plt.legend(handles=[line1, line2], loc='lower right')

Drawing effect: