python を 使った シルバーストーン曲線 の 描画


### 1. シルバーストーン曲線 ビジュアライズゼーション
マクシー・シルバーストーン曲線 を pythonで ビジュアライズゼーションするコードです．
JupyterNotebook で動作確認済みです．
なお，現在入っているパラメタは超適当に置いてるので，各自で変更して使ってください．


```python:fix_cost_simulator
import pandas as pd
import numpy as np
import math
import matplotlib.pyplot as plt
%matplotlib inline

# set investigation cost
PLANT_COST = 9_999_999_999 # set plant cost [!]
LINE_COST = 99_999_999     # set line cost [!]
TOOLING_COST = 69_999_999   # set tooling cost [!]

# set how much lines a plant will have [!]
PLANNED_NUM_OF_LINE = 8

# set each condition of the capacity. (pcs/yr = pcs/day * day/mo * mo/yr) 
LINE_DAILY_CAPA = 999 # set daily line production capacity [!]
TOOLING_DAILY_CAPA = 599 # set daily tooling production capacity [!]
DAYS_PER_MONTH = 22 # set working days [!]
MONTHS_PER_YEAR = 12 # how many months in a year
LINE_CAPA = LINE_DAILY_CAPA * DAYS_PER_MONTH * MONTHS_PER_YEAR # calc line capacity per year
TOOLING_CAPA = TOOLING_DAILY_CAPA * DAYS_PER_MONTH * MONTHS_PER_YEAR # calc tooling capacity per year

# set the condition for this simulation
START_QTY = 100_000 # starting point(production number) for this simulation
PLOT_WIDTH = 1_000 # plotting width
MARGIN_RATIO = 0.9 # set safety margin (consider a risk of sales) [!]
PLANT_DEP_YEAR = 9 # set plant depreciation year [!]
LINE_DEP_YEAR = 9 # set line depreciation year [!]
TOOLING_DEP_YEAR = 2.2 # set tooling depreciation year [!]
END_QTY = PLANNED_NUM_OF_LINE * LINE_CAPA # calc the end of this simulation

# initialize number of line/tooling
line_num = math.ceil(START_QTY / LINE_CAPA) # initialize number of line
tooling_num = math.ceil(START_QTY / TOOLING_CAPA) # initialize number of tooling

plant_dep_qty =  END_QTY * PLANT_DEP_YEAR * MARGIN_RATIO # calc plant depreciation quantity

# generate data for simulation
x_range = np.arange(START_QTY, END_QTY, PLOT_WIDTH)
Y = []
p_line_capa = line_num * LINE_CAPA # calc initial line production capacity
p_tooling_capa = tooling_num * TOOLING_CAPA # calc initial tooling production capacity
for x in x_range:
    if x > p_line_capa: # if production qty is over line capa, add a new line
        line_num += 1
        p_line_capa = line_num * LINE_CAPA
    if x > p_tooling_capa: # if production qty is over tooling capa, add a new tooling
        tooling_num += 1
        p_tooling_capa = tooling_num * TOOLING_CAPA
        
    plant_alloc = PLANT_COST / plant_dep_qty # calc allocated cost of plant building cost
    line_alloc = line_num * LINE_COST / x / LINE_DEP_YEAR # calc allocated cost of line cost
    tooling_alloc = tooling_num * TOOLING_COST / x / TOOLING_DEP_YEAR # calc allocated cost of tooling cost
    all_alloc = plant_alloc + line_alloc + tooling_alloc
    if line_num > PLANNED_NUM_OF_LINE: # if line_num is over planned num of line, cause error.
        print('Error: line_num is over PLANNED_NUM_OF_LINE.')
        break
    Y.append(all_alloc)
    
# show the precondition of this simulation
precondition_dict = {}
precondition_dict['plant_building_cost [工場建屋費用]'] = f'{PLANT_COST:,}'
precondition_dict['line_building_cost [ライン敷設費用]'] = f'{LINE_COST:,}'
precondition_dict['tooling_cost [金型費用]'] = f'{TOOLING_COST:,}'
precondition_dict['max_line_num_per_a_plant [1工場あたり最大ライン敷設計画数(pcs/day)]'] = PLANNED_NUM_OF_LINE
precondition_dict['max_production_daily_capa [1日あたりライン生産能力(pcs/day)]'] = LINE_DAILY_CAPA
precondition_dict['max_tooling_daily_capa [1日あたり金型生産能力]'] = TOOLING_DAILY_CAPA
precondition_dict['plant_depreciation_year [工場建屋の償却設定年数]'] = PLANT_DEP_YEAR
precondition_dict['line_depreciation_year [ラインの償却設定年数]'] = LINE_DEP_YEAR
precondition_dict['tooling_depreciation_year [金型の償却設定年数]'] = TOOLING_DEP_YEAR
precondition_dict['max_line_num [最大ライン敷設数]'] = line_num
precondition_dict['max_tooling_num [最大金型数]'] = tooling_num
precondition_dict['plant_production_capa [工場の生産能力(pcs/yr)]'] = f'{END_QTY:,}'
df = pd.DataFrame(precondition_dict.values(), index=precondition_dict.keys(), columns=['precondition [前提条件]'])
display(df)

# set your plan
yourX = 1_000_000 # set your sales plan [!]
yourY = 999_999_999
for x, y in zip(x_range, Y):
    if x > yourX:
        yourY = y
        break
        
# show simulation result
plt.rcParams["font.size"] = 15
fig, ax = plt.subplots(1, 1, facecolor='#F5FBFF', figsize=(15,10))
ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, loc: f'{int(x):,}'))
ax.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, loc: f'{int(x):,}'))
ax.plot(x_range, Y, c='green')
ax.vlines(x=yourX, ymin=min(Y), ymax=max(Y), color='red')
ax.text(x=yourX*1.03, y=max(Y)*0.995, s=f'{yourY:,.2f} @ ( line_num:{np.ceil(yourX/LINE_CAPA):.0f}, tooling_num:{np.ceil(yourX/TOOLING_CAPA):.0f} )', color='red', fontsize=20)
fig.savefig('./data/img/FixedCostSim.png')
plt.show()

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463767/171c5a33-2d11-61f7-9db2-2f2bf3dfe78d.png)

- `Maxcy et al.［1965］silver stone` でググると，[自動車製造企業の財務戦略 -トヨタを素材として-](https://core.ac.uk/download/pdf/39330568.pdf)が引っ掛かった．興味深い．
- 1965年っていうと，当然ながら，EXCELもない時代．マクシーさんは手書きでプロットしていったのでしょう．python でこれだけ楽に描画できるのは本当に有難い．

### 2. バナナの叩き売り ビジュアライゼーション

```python:banana_sim
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

def make_and_plot_data(p1, p2, b):
    X = np.arange(p1, p2, 1)
    Y = []
    for x in X:
        Y.append(b)
    ax.plot(X,Y,c='green')

X0 = 0
X1 = 50  # [!]
X2 = 100 # [!]
X3 = 200 # [!]

C0 = 2000 # 購入量 X0 以上，X1 未満の売り値 [!]
C1 = 1000 # 購入量 X1 以上，X2 未満の売り値 [!]
C2 = 500 # 購入量 X2 以上，X3 未満の売り値 [!]

yourX = 120 # [!]
yourY = 500 # [!]

plt.rcParams["font.size"] = 15
fig = plt.figure(facecolor='#F5FBFF', figsize=(15,10))
ax = fig.subplots(1,1)
make_and_plot_data(X0, X1, C0)
make_and_plot_data(X1, X2, C1)
make_and_plot_data(X2, X3, C2)
ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, loc: f'{int(x):,}'))
ax.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, loc: f'{int(x):,}'))
ax.vlines(x=yourX, ymin=0, ymax=C0, color='red')
ax.text(x=yourX*1.03, y=yourY*1.1, s=f'{yourY} @ {yourX:,}', color='red', fontsize=20)
fig.savefig('./data/img/bananaCostSim.png')
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463767/140ee199-21a6-039f-1069-38c5c346b15d.png)