python便利なコマンド使い方、備忘録チートメモ、pythonにはswitch case文はない

配列の要素数はlen(array)で数える

メソッドはdefを先頭に付ける。def funcname():。メソッドを外部ファイルにしたいときは、ファイル名:testfunc.pyだったらimport testfunc(ファイル名、拡張子を除く)とする。

if文でelse ifは pythonではelif(勝手にエリフと読んでる)。一致条件はイコール2つ== if :elif:
elseは同じ。中括弧は使わない。

pythonには、switch case文はない

1行コメントは先頭に#
コメントの複数行はシングルクォーテーション3つかダブルクォーテーション3つで囲む。”’ commnet ”’

改行(折返し)は行末にバックスラッシュ\を付けて改行できる(マックの場合はOptionキーと¥キー、Winの場合はAltキーと¥キー)

文字の結合はプラス+。’abc’+’def’ >>abcdef

print(‘Max:’,max(df))#配列dfに複数の数値が入ってるとしてmax()で最大値が取れる。最小値はmin()

c,mod=divmod(a,b) 商cと余りmodが同時に取得できる

ループ、途中の3から5の数字を使って計算したいときrangeを使う。
for i in range(3,6):で、rangeを使うと3,4,5のように途中から取得できる但し、6は出力されないので注意。ここでは5までが対象になる。6を対象にしたかったら1加算してrange(3,7)のようにする

ディレクトリのTXTファイル一覧を取得 import glob, files=glob.glob(path+’*.txt’)、pathにはディレクトリのパスを入れること。

Int moji=5(int型)を文字にしたいstr(moji)で文字5になる

インクリメントi++、デクリメントi–は存在しない。i+=1,i-=1とする

文字列の挿入は、文字列の2番めの文字(1の後ろ)にabc文字を挿入したい。
tmpstr=’0123456′
hoge=tmpstr[:2]+’abc’+tmpstr[2:]
print(hoge)#01abc23456
[:0][0:]だとabc0123456になる

正規表現はimport re 、re.compile,searchがある。#findで正規表現ができない(と思う)

置換はsub

年月日の取得例
from datetime import datetime
end = datetime.now()
start = datetime(end.year, end.month, end.day)
print(‘start:’,start.strftime(“%Y/%m/%d”))
print(‘today:’,end.strftime(“%Y/%m/%d”))
–月をまたいでもOKな記載は以下
from datetime import datetime,timedelta
end = datetime.now()
#start = datetime(end.year, end.month, end.day-8)#こっちだと月マタギでエラーになる。
start = end – timedelta(days=7)

pass で何もしない。!=を使いたくないときやとりあえずコードを書いて実行したいときに使える
if i==10:
pass
else:
a=20

Blender2.91、Pythonで日経平均株価のローソク足を3Dにしてみた

内容

2020年12月〜2021年1月のある期間の日経平均株価チャートを自動作成
約1、2週間分程度の株価

3Dローソク足(株に興味のない人はつまらないかも、、、)
BlenderのPythonを使うとこんなこともできるということを実践しただけの紹介動画

>>作成したローソク足の3D オブジェクトの紹介、BlenderのPython実行

ユーチューブ動画

参考サイト

https://qiita.com/kjunichi/items/a36fdc9db3876e068249
https://qiita.com/hibit/items/1ac97c71d5adc5b45f85

ブログに記載したインストール内容はこちら
https://pikucha.sakura.ne.jp/blog/2020/12/27/mac%e7%89%88blender%e3%81%aepython%e3%81%abpip%e3%80%81pandas_datareader%e3%82%a4%e3%83%b3%e3%82%b9%e3%83%88%e3%83%bc%e3%83%ab%e3%81%97%e3%81%9f%e3%83%a1%e3%83%a2/

#日経平均株価 とは
「東京証券取引所第一部に上場する約2,000銘柄の株式のうち225銘柄を対象」原則「225銘柄の株価の合計 ÷ 225」となる。修正等ある。
https://ja.m.wikipedia.org/wiki/%E6%97%A5%E7%B5%8C%E5%B9%B3%E5%9D%87%E6%A0%AA%E4%BE%A1

#ローソク足とは、
https://ja.wikipedia.org/wiki/%E3%83%AD%E3%83%BC%E3%82%BD%E3%82%AF%E8%B6%B3%E3%83%81%E3%83%A3%E3%83%BC%E3%83%88

「単位期間中に初めに付いた値段を始値(はじめね)、最後に付いた値段を終値(おわりね)、最も高い値段を高値(たかね)、最も安い値段を安値(やすね)」の値をもとにローソクの形状のように表現したもの
ローソク足は江戸時代に出羽国の本間宗久が発案

日経平均株価のデータを取得して、BlenderのPythonを使いローソク足の3D オブジェクトを作成した。

環境:MacOS BigSur

#Blender2.91
Blender用pythonモジュール: #pandas_datareader
準備:Pythonモジュールをインストールする必要がある。
Mac版BlenderのPythonにPip、pandas_datareaderインストールしておく。
・PythonはMacOS BigSur用とBlender用とが存在する。つまり保存場所が異なる。
よってBlenderで使いたいモジュールが必要なときは、個別でインストールが必要。
つまり、MacOSでpandas_datareaderをインストールしても、BlenderのPythonでは
使えない。

目的

:Blender2.91、Pythonスクリプトで日経平均株価データを米ヤフーファイナンスからネット上で取得して、ローソク足として3D(円柱)オブジェクトを作成する。
チャートデータは数日〜1週間程度のデータ

注意事項:

Pythonの文法の説明はほとんどしません。
BlenderのPythonの仕様について投稿者は、よく理解しておらず試行錯誤で作成し、推奨ではないコードの記述や間違いがあります。よって質問等があっても正しく答えられる知識がないため回答できない場合があります。
ご承知おきください。(他の人の回答を期待します。)

・Pythonスクリプトコードの概略説明

米ヤフーファイナンスから日経平均株価のデータを取得
始値、終値、高値、安値データを取得
始値より終値が大きければ陽線(赤)
小さければ陰線(青)とする
始値、終値からローソク本体の大きさ位置を決める
高値、安値からローソクのひげの大きさ位置を決める
直近の日のローソク足だけ横を向いた円錐を配置
直近のローソク足の始値終値を記載
直近の日付を記載
目盛りを配置

^読み方:キャロット

オブジェクトの原点がオブジェクトの中心に配置されていて、オブジェクトの移動やリサイズをする場合は問題は発生しないが、オブジェクトの頂点がオブジェクトの原点(中心点)より離れた位置に配置されていると、
Resizeしたときに、ポイントの縮尺が変わり、想定した位置に配置されない(バグではなく、操作や理解の問題)。
よって、リサイズして、ポイントを移動させたいときは、
オブジェクト自体を移動させてから、リサイズや個別頂点ポイントを移動させたほうが良いと思う。

 

・補足説明

Blenderターミナル起動(print出力を確認するためにターミナルが必要)
/Applications/Blender.app/Contents/MacOS/Blender

Blender2.91のpython場所 –MacOSpythonと異なる場所にある(バージョンが変わる毎にディレクトリが変わる。2.91の部分)
/Applications/Blender.app/Contents/Resources/2.91/python

 

Pythonコード

2021/01/04時点の分、Blenderで実行する。できれば、ターミナルからBlenderを起動してから、Scriptingで使用

修正履歴:2021/01/06、始値終値が重ならないように位置を調整

import os
import bpy
import math
import copy
import time
import pandas_datareader.data as data
from datetime import datetime,timedelta

#blender 2.91 
#Mac Big Sur
#ターミナル起動
#/Applications/Blender.app/Contents/MacOS/Blender

#GLOBAL
# count
# xmove
# bairitsu
#修正履歴
#2021/01/06:始値、終値の位置が重ならないように調整

#https://bluebirdofoz.hatenablog.com/entry/2018/04/25/231414
# オブジェクトの原点変更
# オブジェクトの原点を指定位置に移動する
# 引数   arg_objectname:指定オブジェクト名
# 戻り値
def set_origin_cursor(arg_objectname='Default',arg_location=(0,0,0)):
  # 他のオブジェクトの寸法を適用しないよう全てのオブジェクトを走査する
  for ob in bpy.context.scene.objects:
    # 非選択状態に設定する
    #ob.select=False#2.7
    ob.select_set(False) #2.9
  # 指定オブジェクトを取得する
  selectob = bpy.data.objects[arg_objectname]
  # 変更オブジェクトをアクティブに変更する
  #bpy.context.scene.objects.active = selectob#2.7
  bpy.context.view_layer.objects.active=selectob#2.9
  # 変更オブジェクトを選択状態にする  
  #selectob.select=True #2.7
  selectob.select_set(True) #2.9
  # 3Dカーソルの元の位置を記録しておく(参照型のコピー)
  #cursorpos = copy.copy(bpy.context.scene.cursor_location)
  # 3Dカーソルの位置を指定位置に移動する
  #bpy.context.scene.cursor_location = arg_location#2.7
  bpy.context.scene.cursor.location=arg_location#2.9
  # オブジェクトの原点を3Dカーソル位置に移動する
  bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
  # 3Dカーソルの位置を元に戻す
  #bpy.context.scene.cursor_location = cursorpos #2.7
  #bpy.context.scene.cursor.location=cursorpos#2.9 not use
  bpy.context.scene.cursor.location=(0.0,0.0,0.0)
  return

def fcandle(candleType,kopen,kclose,bairitsu,xmove,mat1,mat2):
    #count is Global
    global count
    #global xmove
    #global bairitsu
    
    if bairitsu=='' or bairitsu==0:
        print('def fcandle(),bairitsu not defined,use 0.001')
        bairitsu=0.001
    if count=='':
        print('def fcandle(),count is Global, not defined, Please check, so use 1')
        count=1
                  
    candle=candleType
    #1.円柱location:図形の中心座標 radius:円の半径 depth:高さ rotation:立体の回転角(rad)
    bpy.ops.mesh.primitive_cylinder_add(location=(0, 0, 0), radius=0.022, depth=3, rotation=(0, 0, 0))
    if candle=='yousen':
        bpy.context.object.data.materials.append(mat1) # 材質(赤)指定
    else:#insen 
        bpy.context.object.data.materials.append(mat2) # 材質(青)指定
    bpy.ops.transform.translate(value=(xmove,0,0))
    #location=bpy.context.object.location
    
    for obj in bpy.context.selected_objects:
        if obj.name=='Cylinder':
            tmpcount=count+1
            obj.name = "candle"+str(tmpcount)
    
    #bpy.ops.object.shade_smooth()
    
    new_bar = bpy.context.object
    for vert in new_bar.data.vertices:
        if candle=='yousen':
            if vert.co[2] > 0:#Zjiku ni up
                vert.co[2] = kclose*bairitsu#close
            else:
                vert.co[2] = kopen*bairitsu
        elif candle=='insen':
            if vert.co[2] > 0:
                vert.co[2] = kopen*bairitsu
            else:
                vert.co[2] = kclose*bairitsu
    clocation=(xmove,0,(kopen+kclose)*bairitsu/2) 
    set_origin_cursor(obj.name,clocation)
    location=bpy.context.object.location
    
    return  location#candle             
#end def

def fcandle_hige(candleType,khigh,klow,bairitsu,candleLocation,mat1,mat2):
    global count
    #global xmove
    #global bairitsu    
    #count,bairitsu is Global
    #if bairistu=='' or bairitsu==0:
    #    print('def fcandle_hige(),bairitsu not defined, so use 0.001')
    #    bairitsu=0.001
    if count=='':
        print('def fcandle_hige(),count is Global, not defined, Please check, so use 1')
        count=1
        
    candle=candleType
    bpy.ops.mesh.primitive_cylinder_add(location=(0, 0, 0), radius=0.022/7, depth=3, rotation=(0, 0, 0))
    if candle=='yousen':
        bpy.context.object.data.materials.append(mat1) # 材質(赤)指定
    else:#insen 
        bpy.context.object.data.materials.append(mat2) # 材質(青)指定
    bpy.ops.transform.translate(value=(candleLocation[0],candleLocation[1],0))#hige location is same candle location
    
    for obj in bpy.context.selected_objects:
        if obj.name=='Cylinder':
            tmpcount=count+1
            obj.name = "hige"+str(tmpcount)
    
    #xmove+=0.048
    #bpy.ops.object.shade_smooth()
    
    new_bar = bpy.context.object
    for vert in new_bar.data.vertices:
            if vert.co[2] > 0:#Zjiku ni up
                vert.co[2] = khigh*bairitsu#close
            else:
                vert.co[2] = klow*bairitsu
    set_origin_cursor(obj.name,candleLocation)
    
#end def
# テキストオブジェクトの追加
def add_text(text, t_color,location):
# 角度設定時に利用
  ROT_QUATER = math.pi / 2
  bpy.ops.object.text_add()
  ob = bpy.context.object
  ob.data.body = text
  ob.data.extrude = 0.05
  ob.data.bevel_depth = 0.002
  
  bpy.ops.font.open(filepath="/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc")
  bpy.data.fonts["HiraginoSans-W6"].name = "HiraginoSans-W6"
  fnt = bpy.data.fonts.load('/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc')
  ob.data.font = fnt 
  
  ob.rotation_euler[0] = ROT_QUATER
  # 3Dカーソルの位置を0,0,0
  bpy.context.scene.cursor.location=(0.0,0.0,0.0)
  #3Dカーソルを原点を変更してから、translateする必要がある。
  bpy.ops.transform.translate(value=location)#26500*0.001,(1.8,0.1/3,26.5)
  bpy.ops.transform.resize(value=(0.2,0.1,0.2)) # 図形を変形
  
  #ob.rotation_euler[2] = ROT_QUATER
  ob.data.align_x = 'CENTER'
  ob.data.align_y = 'CENTER'
  mat = bpy.data.materials.new('color_txt')
  mat.diffuse_color = t_color#(0.8, 0.8, 0.8, 1.0)
  # マテリアルスロットを追加する
  bpy.ops.object.material_slot_add()
  # 作成したマテリアルスロットに新規マテリアルを設定する
  bpy.context.object.active_material = mat
  #ob.active_material.diffuse_color = (1,0,0)
  #bpy.context.object.active_material.diffuse_color = (1,0,0)
  #mat.diffuse_color = (1.0,0.0,0.0)
  
  #mat.diffuse_color = (1,0,0)#t_color #error , I do not yet 2020/05/15 
  #ob.data.materials.append(mat)
  #ob.active_material.diffuse_color = t_color # error

#convert to mesh

  #s = bpy.context.scene.objects.active
  #s.name = "text_name"
  bpy.ops.object.convert(target='MESH')# work
  for obj in bpy.context.selected_objects:
     if obj.name=='Text':
         obj.name=text

  return ob
#end def

def add_textKai(text, t_color,location,size):
# 角度設定時に利用
  ROT_QUATER = math.pi / 2
  bpy.ops.object.text_add()
  ob = bpy.context.object
  ob.data.body = text
  ob.data.extrude = 0.05
  ob.data.bevel_depth = 0.002
  
  bpy.ops.font.open(filepath="/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc")
  bpy.data.fonts["HiraginoSans-W6"].name = "HiraginoSans-W6"
  fnt = bpy.data.fonts.load('/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc')
  ob.data.font = fnt 
  
  ob.rotation_euler[0] = ROT_QUATER
  # 3Dカーソルの位置を0,0,0
  bpy.context.scene.cursor.location=(0.0,0.0,0.0)
  #3Dカーソルを原点を変更してから、translateする必要がある。
  bpy.ops.transform.translate(value=location)#26500*0.001,(1.8,0.1/3,26.5)
  bpy.ops.transform.resize(value=size) # 図形を変形(0.2,0.1,0.2)
  
  #ob.rotation_euler[2] = ROT_QUATER
  ob.data.align_x = 'CENTER'
  ob.data.align_y = 'CENTER'
  mat = bpy.data.materials.new('color_txt')
  mat.diffuse_color = t_color#(0.8, 0.8, 0.8, 1.0)
  # マテリアルスロットを追加する
  bpy.ops.object.material_slot_add()
  # 作成したマテリアルスロットに新規マテリアルを設定する
  bpy.context.object.active_material = mat
  #ob.active_material.diffuse_color = (1,0,0)
  #bpy.context.object.active_material.diffuse_color = (1,0,0)
  #mat.diffuse_color = (1.0,0.0,0.0)
  #mat.diffuse_color = (1,0,0)#t_color #error , I do not yet 2020/05/15 
  #ob.data.materials.append(mat)
  #ob.active_material.diffuse_color = t_color # error
#convert to mesh
  #s = bpy.context.scene.objects.active
  #s.name = "text_name"
  bpy.ops.object.convert(target='MESH')# work
  for obj in bpy.context.selected_objects:
     if obj.name=='Text':
         obj.name=text  
  return ob
#end def

#2020/12/29
#print('Max:',max(df['High']))#最大値が取れる
#高値の最大値maxと安値の最小値minを取得して
#500円ごとのバー基準株価線(26500,27000,27500)を自動で作成したい。
def makeBarMaxtoMin(highobj,lowobj):
    #print('Max:',max(highobj))#df['High']
    #print('Min:',min(lowobj))#df['Low']
    #bairitsu is Global
    global count
    global xmove
    global bairitsu    
    #if bairistu=='' or bairitsu==0:
    #    print('def makeBarMaxtoMin(),bairitsu not defined,use 0.001')
     #   bairitsu=0.001    
    #every 500yen
    priceRange=500
    #highPriceNumはバーの本数を取得する
    highPriceNum,highmod=divmod(max(highobj),priceRange)#26200/priceRange
    lowPriceNum,lowmod=divmod(min(lowobj),priceRange)
    #高値については、余りが出たら、1を追加する
    #print('highmod:',highmod)
    if highmod!=0:
        highPriceNum=highPriceNum+1
        #Rangeで範囲を指定してしようする場合1加算では足りないので、rangeで更に1を加算する
        #print('after highPriceNum:',highPriceNum)

    for i in range(math.floor(lowPriceNum),math.floor(highPriceNum+1)):
        #range()が出力するのは、(highPriceNum-1)なので1を加算してhighPriceNum分までを計算させる
        print('barPrice:',i*priceRange)
        #i*priceRangeの位置でBarオブジェクトを作成する。
        # 3Dカーソルの位置を0,0,0
        bpy.context.scene.cursor.location=(0.0,0.0,0.0) 
        color=(0.8,0.5,0.8,0.8)
        add_text(str(i*priceRange), color,(1.8,0.1/3, (i*priceRange)*bairitsu+0.045))#0.045 is ajustment
        
        bpy.context.scene.cursor.location=(0.0,0.0,0.0)
        # 平板作成 26500bar1
        bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size=2.0)
        bpy.ops.transform.translate(value=(0.0,0.1/2,(i*priceRange)*bairitsu))#26500*0.001
        bpy.ops.transform.resize(value=(2.0,0.06/6,0.01/6)) # 図形を変形
        bpy.context.object.data.materials.append(mat3) # 材質
        for obj in bpy.context.selected_objects:
            if obj.name=='Cube':
                obj.name='bar_'+str(i*priceRange) 
#end def
######################################################################
#main
######################################################################
count=0#count is Global
xmove=0.8#1# move distancs
bairitsu=0.001# size Global

#Stock date
n=maenohi=5
end = datetime.now()
#start = end - timedelta(days=maenohi)#end.day-7 changes
#start = datetime(end.year, end.month, end.day-7)
##土日があると表示させるローソク足の数が少ないので、数が満たされるまでループするためSleepを入れた
#大量のデータはCSVで取得してからローソク足にしたほうが良さそう
x=0
while x<=(maenohi):
    start = end - timedelta(days=n)
    df=data.DataReader('^N225','yahoo',start,end)#3990.T,#^N225
    date=df.index# 日付
    time.sleep(3)
    print('len(date):',len(date))
    print('3秒待ち')
    x=len(date)
    n=n+1
print(df.head(5))
if len(date)==0:
    print('ERROR Can not get any Price data, Check internet or yahoo finance com.')
    sys.exit()

# 既存要素削除
for item in bpy.data.meshes:
    bpy.data.meshes.remove(item)

for item in bpy.data.materials:
    bpy.data.materials.remove(item)
        
#bpy.ops.outliner.item_rename()
#2.立方体 location:図形の中心座標 size:立方体の一辺の長さ rotation:立体の回転角(rad)
#bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size=1.0, rotation=(0, 0, 0))

# 2.材質の定義(赤色)
mat1 = bpy.data.materials.new('Red')
mat1.diffuse_color = (1.0, 0.0, 0.0, 1.0)

# 3.材質の定義(青色)
mat2 = bpy.data.materials.new('blue')
mat2.diffuse_color = (0.0, 0.0, 1.0, 1.0)

mat3 = bpy.data.materials.new('gray')
mat3.diffuse_color = (0.8, 0.8, 0.8, 0.5)

mat5 = bpy.data.materials.new('yellow')
mat5.diffuse_color = (1.0, 0.9, 0.1, 1.0)

# 平板作成 27000bar
#bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size=2.0)
#Resizeして、ポイント移動をするとポイントの縮尺が変わり、想定した位置に移動しない(推測)。
#これはオブジェクトの原点とScaleの考え方の違いかもしれない。
#よって、リサイズして、ポイントを移動させたいときは、
#リサイズをする前にオブジェクト自体を移動させてから、ポイントを移動させたほうが良いと思う。
#bpy.ops.transform.translate(value=(0.0,0.1/2,27))#27000*0.001
#bpy.ops.transform.resize(value=(2.0,0.06/6,0.01/6)) # 図形を変形
#bpy.context.object.data.materials.append(mat3) # 材質

# 平板作成 26500bar1
#bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size=2.0)
#bpy.ops.transform.translate(value=(0.0,0.1/2,bar1*bairitsu))#26500*0.001
#bpy.ops.transform.resize(value=(2.0,0.06/6,0.01/6)) # 図形を変形
#bpy.context.object.data.materials.append(mat3) # 材質

# 3Dカーソルの位置を0,0,0
#bpy.context.scene.cursor_location =(0.0,0.0,0.0)
bpy.context.scene.cursor.location=(0.0,0.0,0.0)

#26500txt
#color=(0.8,0.5,0.8,0.8)
#add_text('26500', color,(1.8,0.1/3,bar1*bairitsu+0.045))#0.045 is ajustment
#27000txt
#add_text('27000', color,(1.8,0.1/3,bar2*bairitsu+0.045))


#date=df.indexをカウントして、それぞれを取得する。ちょっとスマートではないが、、
for fdate in date:
    khigh=df['High'][count]
    klow=df['Low'][count]
    kopen=df['Open'][count]
    kclose=df['Adj Close'][count]
    #ここに日付ごとの処理を入れる。
    #
    if kopen-kclose<0:
        candle='yousen'#color Red
        #print('陽線')
    else:
        candle='insen'#color Blue
        #print('陰線')
    #objを生成する。
    #始値、終値でZ軸の高さを設定する。
    print( fdate.strftime("%Y/%m/%d") )#2020-12-22 00:00:00となるので、時刻を除く2020-12-22
    #Candle_Main####################################################
    candleLocation=fcandle(candle,kopen,kclose,bairitsu,xmove,mat1,mat2)
    xmove+=0.048
    
    #Candle_hige####################################################
    fcandle_hige(candle,khigh,klow,bairitsu,candleLocation,mat1,mat2)
    #count is Global      
    count+=1

#最後のローソクのobjの横に矢印を与える
#この場合、ローソクの原点を移動させて、ローソクの中心に移動させる必要がある
candleCount=0
for obj in bpy.data.objects:
    if 'candle' in obj.name:
        #print(obj.name)
        candleCount+=1
candleName='candle'+str(candleCount)

#Arrow
bpy.ops.mesh.primitive_cone_add(radius1=1, radius2=0, depth=2, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(0.05, 0.05, 0.05))
#図形を回転(Y軸周りに90°)
bpy.ops.transform.rotate(value=-3.1415/2 ,orient_axis='Y')
bpy.context.object.data.materials.append(mat5) 
bpy.ops.transform.translate(value=(bpy.data.objects[candleName].location[0]+0.08,bpy.data.objects[candleName].location[1],bpy.data.objects[candleName].location[2]))#


bpy.context.scene.cursor.location=(0.0,0.0,0.0)
#open,close
color=(1.0,1.0,1.0,1.0)
#str,color,location,size
lastOpen=df['Open'][len(date)-1]#始値
lastClose=df['Close'][len(date)-1]#終値
roundOpen='O:'+str(round(lastOpen,2))#画面に表示させる直近の始値文字
roundClose='C:'+str(round(lastClose,2))#画面に表示させる直近の終値文字

add_textKai(roundOpen, color,(xmove+0.1,0,lastOpen*bairitsu),(0.06,0.05,0.06))
add_textKai(roundClose, color,(xmove+0.1,0,lastClose*bairitsu),(0.06,0.05,0.06))

#end.strftime("%Y/%m/%d") or date[len(date)-1].strftime("%Y/%m/%d")today
color=(0.0,1.0,0.0,1.0)
coneLocation=bpy.data.objects['Cone'].location
tyokkinDay=date[len(date)-1].strftime("%Y/%m/%d")
if len(date)>0:
    add_textKai(tyokkinDay,color, (coneLocation[0]+0.16,coneLocation[1],coneLocation[2]),(0.06,0.05,0.06))
#print('last day:',date[len(date)-1])

#始値、終値、直近の日付の調整。オブジェクトが重なってしまう金額が近いときに離す処理
if candle=='yousen':#Openが下側でCloseが上側にあるはず
    #bpy.data.objects[roundOpen].dimensions[1]#Z方向の幅サイズではなくてY軸、理由はローカルで回転させたから
    #bpy.data.objects[roundClose].dimensions[1]
    #bpy.data.objects[tyokkinDay].dimensions[1]
    #始値、終値、直近の日付のlocationを取得する。Z方向ではなくてY軸の幅の半分を上下に加減算して重なりを調べる
    #bpy.data.objects[roundOpen].location[2]
    #bpy.data.objects[roundClose].location[2]
    #bpy.data.objects[tyokkinDay].location[2]
    #roundCloseを調整する.roundCloseの下側位置が、直近日付の上側位置以下になっているときに、直近日付の上の方にroundCloseを上へ移動させる
    
    #location is [2]:Z, dimensions is [1]:Y
    if bpy.data.objects[roundClose].location[2]-bpy.data.objects[roundClose].dimensions[1]/2 <= bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]/2:
        #直近日付の位置に、プラスへ移動
        bpy.data.objects[roundClose].location[2]=bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]*1.5
    #roundOpenを調整する。roundOpenの「上側」位置が、直近日付の「下側」以上になっているときに、直近日付の「下の方」にroundOpenを下へ移動させる
    if bpy.data.objects[roundOpen].location[2]+bpy.data.objects[roundOpen].dimensions[1]/2 >=bpy.data.objects[tyokkinDay].location[2]-bpy.data.objects[tyokkinDay].dimensions[1]/2:
            #「マイナス」へ移動
        bpy.data.objects[roundOpen].location[2]=bpy.data.objects[tyokkinDay].location[1]-bpy.data.objects[tyokkinDay].dimensions[1]*1.5
else:#insen Openが上側でCloseが下側にあるはず.Yousenとは逆
    #roundOpen
    print('insen')
    if bpy.data.objects[roundOpen].location[2]-bpy.data.objects[roundOpen].dimensions[1]/2<=bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]/2:
        bpy.data.objects[roundOpen].location[2]=bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]*1.5
        print('Open')
    #roundClose
    if bpy.data.objects[roundClose].location[2]+bpy.data.objects[roundClose].dimensions[1]/2>=bpy.data.objects[tyokkinDay].location[2]-bpy.data.objects[tyokkinDay].dimensions[1]/2:
        bpy.data.objects[roundClose].location[2]=bpy.data.objects[tyokkinDay].location[2]-bpy.data.objects[tyokkinDay].dimensions[1]*1.5
        print('Close')

    

#2020/12/29
#print('Max:',max(df['High']))#最大値が取れる
#高値の最大値maxと安値の最小値minを取得して
#500円ごとのバー基準株価線(26500,27000,27500)を自動で作成したい。
makeBarMaxtoMin(df['High'],df['Low'])

#camera move, near Cone obj
camera_obj = bpy.data.objects['Camera']
print(camera_obj.location)
camera_obj.location=(coneLocation[0]+0.16,coneLocation[1]-3.0,coneLocation[2])

print('done.')

''' Result



'''

 

別コード、株価を記載したCSVファイルを読み込んで立体ローソク足にした

米ヤフーファイナンスに接続して当日にデータを取得すると、前日データが欠落するし、データが公開されるまで時間がかかる(20分)ので
CSVで当日データを記載したファイルを読み込んだほうが早いと思ってCSV読み取りでローソク足を立体化するPythonコードを書いた。日経平均株価データのクラスオブジェクト、カプセルデータとして扱う。CSVの場合は、数字が文字列扱いになるので、floatにするなどの型変換が必要だった。
なお、このコードには、別ファイルのBlendファイルからオブジェクト(猫)を読み込むコードを記載してある。
ファイルパスはフルパス。

import os
import bpy
import math
import copy
import time
import pandas_datareader.data as data
from datetime import datetime,timedelta

#blender 2.91 
#Mac Big Sur
#ターミナル起動
#/Applications/Blender.app/Contents/MacOS/Blender

#GLOBAL
# count
# xmove
# bairitsu

#日経平均株価データのクラスオブジェクト、カプセルデータ
class nikkeiClass:
    def __init__(self, cindex, chigh,clow,copen,cclose,cadjclose):
        self.index = cindex
        self.high = chigh
        self.low = clow
        self.open = copen
        self.close = cclose
        self.adjclose = cadjclose

#https://bluebirdofoz.hatenablog.com/entry/2018/04/25/231414
# オブジェクトの原点変更
# オブジェクトの原点を指定位置に移動する
# 引数   arg_objectname:指定オブジェクト名
# 戻り値
def set_origin_cursor(arg_objectname='Default',arg_location=(0,0,0)):
  # 他のオブジェクトの寸法を適用しないよう全てのオブジェクトを走査する
  for ob in bpy.context.scene.objects:
    # 非選択状態に設定する
    #ob.select=False#2.7
    ob.select_set(False) #2.9
  # 指定オブジェクトを取得する
  selectob = bpy.data.objects[arg_objectname]
  # 変更オブジェクトをアクティブに変更する
  #bpy.context.scene.objects.active = selectob#2.7
  bpy.context.view_layer.objects.active=selectob#2.9
  # 変更オブジェクトを選択状態にする  
  #selectob.select=True #2.7
  selectob.select_set(True) #2.9
  # 3Dカーソルの元の位置を記録しておく(参照型のコピー)
  #cursorpos = copy.copy(bpy.context.scene.cursor_location)
  # 3Dカーソルの位置を指定位置に移動する
  #bpy.context.scene.cursor_location = arg_location#2.7
  bpy.context.scene.cursor.location=arg_location#2.9
  # オブジェクトの原点を3Dカーソル位置に移動する
  bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
  # 3Dカーソルの位置を元に戻す
  #bpy.context.scene.cursor_location = cursorpos #2.7
  #bpy.context.scene.cursor.location=cursorpos#2.9 not use
  bpy.context.scene.cursor.location=(0.0,0.0,0.0)
  return

def fcandle(candleType,kopen,kclose,bairitsu,xmove,mat1,mat2):
    #count is Global
    global count
    #global xmove
    #global bairitsu
    
    if bairitsu=='' or bairitsu==0:
        print('def fcandle(),bairitsu not defined,use 0.001')
        bairitsu=0.001
    if count=='':
        print('def fcandle(),count is Global, not defined, Please check, so use 1')
        count=1
                  
    candle=candleType
    #1.円柱location:図形の中心座標 radius:円の半径 depth:高さ rotation:立体の回転角(rad)
    bpy.ops.mesh.primitive_cylinder_add(location=(0, 0, 0), radius=0.022, depth=3, rotation=(0, 0, 0))
    if candle=='yousen':
        bpy.context.object.data.materials.append(mat1) # 材質(赤)指定
    else:#insen 
        bpy.context.object.data.materials.append(mat2) # 材質(青)指定
    bpy.ops.transform.translate(value=(xmove,0,0))
    #location=bpy.context.object.location
    
    for obj in bpy.context.selected_objects:
        if obj.name=='Cylinder':
            tmpcount=count+1
            obj.name = "candle"+str(tmpcount)
    
    #bpy.ops.object.shade_smooth()
    
    new_bar = bpy.context.object
    for vert in new_bar.data.vertices:
        if candle=='yousen':
            if vert.co[2] > 0:#Zjiku ni up
                vert.co[2] = kclose*bairitsu#close
            else:
                vert.co[2] = kopen*bairitsu
        elif candle=='insen':
            if vert.co[2] > 0:
                vert.co[2] = kopen*bairitsu
            else:
                vert.co[2] = kclose*bairitsu
    clocation=(xmove,0,(kopen+kclose)*bairitsu/2) 
    set_origin_cursor(obj.name,clocation)
    location=bpy.context.object.location
    
    return  location#candle             
#end def

def fcandle_hige(candleType,khigh,klow,bairitsu,candleLocation,mat1,mat2):
    global count
    #global xmove
    #global bairitsu    
    #count,bairitsu is Global
    #if bairistu=='' or bairitsu==0:
    #    print('def fcandle_hige(),bairitsu not defined, so use 0.001')
    #    bairitsu=0.001
    if count=='':
        print('def fcandle_hige(),count is Global, not defined, Please check, so use 1')
        count=1
        
    candle=candleType
    bpy.ops.mesh.primitive_cylinder_add(location=(0, 0, 0), radius=0.022/7, depth=3, rotation=(0, 0, 0))
    if candle=='yousen':
        bpy.context.object.data.materials.append(mat1) # 材質(赤)指定
    else:#insen 
        bpy.context.object.data.materials.append(mat2) # 材質(青)指定
    bpy.ops.transform.translate(value=(candleLocation[0],candleLocation[1],0))#hige location is same candle location
    
    for obj in bpy.context.selected_objects:
        if obj.name=='Cylinder':
            tmpcount=count+1
            obj.name = "hige"+str(tmpcount)
    
    #xmove+=0.048
    #bpy.ops.object.shade_smooth()
    
    new_bar = bpy.context.object
    for vert in new_bar.data.vertices:
            if vert.co[2] > 0:#Zjiku ni up
                vert.co[2] = khigh*bairitsu#close
            else:
                vert.co[2] = klow*bairitsu
    set_origin_cursor(obj.name,candleLocation)
    
#end def
# テキストオブジェクトの追加
def add_text(text, t_color,location):
# 角度設定時に利用
  ROT_QUATER = math.pi / 2
  bpy.ops.object.text_add()
  ob = bpy.context.object
  ob.data.body = text
  ob.data.extrude = 0.05
  ob.data.bevel_depth = 0.002
  
  bpy.ops.font.open(filepath="/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc")
  bpy.data.fonts["HiraginoSans-W6"].name = "HiraginoSans-W6"
  fnt = bpy.data.fonts.load('/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc')
  ob.data.font = fnt 
  
  ob.rotation_euler[0] = ROT_QUATER
  # 3Dカーソルの位置を0,0,0
  bpy.context.scene.cursor.location=(0.0,0.0,0.0)
  #3Dカーソルを原点を変更してから、translateする必要がある。
  bpy.ops.transform.translate(value=location)#26500*0.001,(1.8,0.1/3,26.5)
  bpy.ops.transform.resize(value=(0.2,0.1,0.2)) # 図形を変形
  
  #ob.rotation_euler[2] = ROT_QUATER
  ob.data.align_x = 'CENTER'
  ob.data.align_y = 'CENTER'
  mat = bpy.data.materials.new('color_txt')
  mat.diffuse_color = t_color#(0.8, 0.8, 0.8, 1.0)
  # マテリアルスロットを追加する
  bpy.ops.object.material_slot_add()
  # 作成したマテリアルスロットに新規マテリアルを設定する
  bpy.context.object.active_material = mat
  #ob.active_material.diffuse_color = (1,0,0)
  #bpy.context.object.active_material.diffuse_color = (1,0,0)
  #mat.diffuse_color = (1.0,0.0,0.0)
  
  #mat.diffuse_color = (1,0,0)#t_color #error , I do not yet 2020/05/15 
  #ob.data.materials.append(mat)
  #ob.active_material.diffuse_color = t_color # error

#convert to mesh

  #s = bpy.context.scene.objects.active
  #s.name = "text_name"
  bpy.ops.object.convert(target='MESH')# work
  for obj in bpy.context.selected_objects:
     if obj.name=='Text':
         obj.name=text

  return ob
#end def

def add_textKai(text, t_color,location,size):
# 角度設定時に利用
  ROT_QUATER = math.pi / 2
  bpy.ops.object.text_add()
  ob = bpy.context.object
  ob.data.body = text
  ob.data.extrude = 0.05
  ob.data.bevel_depth = 0.002
  
  bpy.ops.font.open(filepath="/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc")
  bpy.data.fonts["HiraginoSans-W6"].name = "HiraginoSans-W6"
  fnt = bpy.data.fonts.load('/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc')
  ob.data.font = fnt 
  
  ob.rotation_euler[0] = ROT_QUATER
  # 3Dカーソルの位置を0,0,0
  bpy.context.scene.cursor.location=(0.0,0.0,0.0)
  #3Dカーソルを原点を変更してから、translateする必要がある。
  bpy.ops.transform.translate(value=location)#26500*0.001,(1.8,0.1/3,26.5)
  bpy.ops.transform.resize(value=size) # 図形を変形(0.2,0.1,0.2)
  
  #ob.rotation_euler[2] = ROT_QUATER
  ob.data.align_x = 'CENTER'
  ob.data.align_y = 'CENTER'
  mat = bpy.data.materials.new('color_txt')
  mat.diffuse_color = t_color#(0.8, 0.8, 0.8, 1.0)
  # マテリアルスロットを追加する
  bpy.ops.object.material_slot_add()
  # 作成したマテリアルスロットに新規マテリアルを設定する
  bpy.context.object.active_material = mat
  #ob.active_material.diffuse_color = (1,0,0)
  #bpy.context.object.active_material.diffuse_color = (1,0,0)
  #mat.diffuse_color = (1.0,0.0,0.0)
  #mat.diffuse_color = (1,0,0)#t_color #error , I do not yet 2020/05/15 
  #ob.data.materials.append(mat)
  #ob.active_material.diffuse_color = t_color # error
#convert to mesh
  #s = bpy.context.scene.objects.active
  #s.name = "text_name"
  bpy.ops.object.convert(target='MESH')# work
  for obj in bpy.context.selected_objects:
     if obj.name=='Text':
         obj.name=text  
  return ob
#end def

#2020/12/29
#print('Max:',max(df['High']))#最大値が取れる
#高値の最大値maxと安値の最小値minを取得して
#500円ごとのバー基準株価線(26500,27000,27500)を自動で作成したい。
def makeBarMaxtoMin(highobj,lowobj):
    #print('Max:',max(highobj))#df['High']
    #print('Min:',min(lowobj))#df['Low']
    #bairitsu is Global
    global count
    global xmove
    global bairitsu    
    #if bairistu=='' or bairitsu==0:
    #    print('def makeBarMaxtoMin(),bairitsu not defined,use 0.001')
     #   bairitsu=0.001    
    #every 500yen
    priceRange=500
    #highPriceNumはバーの本数を取得する
    highPriceNum,highmod=divmod(max(highobj),priceRange)#26200/priceRange
    lowPriceNum,lowmod=divmod(min(lowobj),priceRange)
    #高値については、余りが出たら、1を追加する
    #print('highmod:',highmod)
    if highmod!=0:
        highPriceNum=highPriceNum+1
        #Rangeで範囲を指定してしようする場合1加算では足りないので、rangeで更に1を加算する
        #print('after highPriceNum:',highPriceNum)

    for i in range(math.floor(lowPriceNum),math.floor(highPriceNum+1)):
        #range()が出力するのは、(highPriceNum-1)なので1を加算してhighPriceNum分までを計算させる
        print('barPrice:',i*priceRange)
        #i*priceRangeの位置でBarオブジェクトを作成する。
        # 3Dカーソルの位置を0,0,0
        bpy.context.scene.cursor.location=(0.0,0.0,0.0) 
        color=(0.8,0.5,0.8,0.8)
        add_text(str(i*priceRange), color,(1.8,0.1/3, (i*priceRange)*bairitsu+0.045))#0.045 is ajustment
        
        bpy.context.scene.cursor.location=(0.0,0.0,0.0)
        # 平板作成 26500bar1
        bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size=2.0)
        bpy.ops.transform.translate(value=(0.0,0.1/2,(i*priceRange)*bairitsu))#26500*0.001
        bpy.ops.transform.resize(value=(2.0,0.06/6,0.01/6)) # 図形を変形
        bpy.context.object.data.materials.append(mat3) # 材質
        for obj in bpy.context.selected_objects:
            if obj.name=='Cube':
                obj.name='bar_'+str(i*priceRange) 
#end def
######################################################################
#main
######################################################################
count=0#count is Global
xmove=0.8#1# move distancs
bairitsu=0.001# size Global

print('this Code for reading CSV.')
print('>>>>>CSV出力>>>>>')
#ここからCSV出力用
checkLineCount=0
df=[]

#CSVを読み込む
ifile='/Users/toshiromaseda/Documents/blender/script/2021年1月14日日経.csv'
try:#ファイルが存在しないときのエラー処理try
    with open(ifile,'tr') as fin:
        for iline in fin:
            try:
                tmp=iline.strip().split(",")#stripしてからsplit()だと理解している。
                if 'High' in tmp[0]:
                    continue
                if len(tmp) < 6:#全部で6列存在する。
                    print('ERROR 列の数があっていません。少ないようです。行数:',checkLineCount)
                    break
                print('iline[]:',tmp[0])
                #ここから処理を入れていけばよい
                df.append(nikkeiClass(tmp[0],tmp[1],tmp[2],tmp[3],tmp[4],tmp[5]))
                checkLineCount+=1
            except:
                print ('error')
except FileNotFoundError as e: # FileNotFoundErrorは例外クラス名
    print("ファイルが見つかりません。パス、ファイル名を確認してください", e)
    ifile.close()
    sys._exit()#ファイルがなければ終了

#Stock date
n=maenohi=5
end = datetime.now()
start = end - timedelta(days=n)
#start = end - timedelta(days=maenohi)#end.day-7 changes
#start = datetime(end.year, end.month, end.day-7)
##土日があると表示させるローソク足の数が少ないので、数が満たされるまでループするためSleepを入れた
#大量のデータはCSVで取得してからローソク足にしたほうが良さそう

'''
x=0
while x<=(maenohi):
    start = end - timedelta(days=n)
    df=data.DataReader('^N225','yahoo',start,end)#3990.T,#^N225
    date=df.index# 日付
    time.sleep(3)
    print('len(date):',len(date))
    print('3秒待ち')
    x=len(date)
    n=n+1
print(df.head(8))
if len(date)==0:
    print('ERROR Can not get any Price data, Check internet or yahoo finance com.')
    sys.exit()
'''

# 既存要素削除
for item in bpy.data.meshes:
    bpy.data.meshes.remove(item)

for item in bpy.data.materials:
    bpy.data.materials.remove(item)
        
#bpy.ops.outliner.item_rename()
#2.立方体 location:図形の中心座標 size:立方体の一辺の長さ rotation:立体の回転角(rad)
#bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size=1.0, rotation=(0, 0, 0))

# 2.材質の定義(赤色)
mat1 = bpy.data.materials.new('Red')
mat1.diffuse_color = (1.0, 0.0, 0.0, 1.0)

# 3.材質の定義(青色)
mat2 = bpy.data.materials.new('blue')
mat2.diffuse_color = (0.0, 0.0, 1.0, 1.0)

mat3 = bpy.data.materials.new('gray')
mat3.diffuse_color = (0.8, 0.8, 0.8, 0.5)

mat5 = bpy.data.materials.new('yellow')
mat5.diffuse_color = (1.0, 0.9, 0.1, 1.0)

# 3Dカーソルの位置を0,0,0
#bpy.context.scene.cursor_location =(0.0,0.0,0.0)
bpy.context.scene.cursor.location=(0.0,0.0,0.0)

#date=df.indexをカウントして、それぞれを取得する。ちょっとスマートではないが、、
for fdate in df:
    khigh=float(fdate.high)
    klow=float(fdate.low)
    kopen=float(fdate.open)
    kclose=float(fdate.adjclose)
    #ここに日付ごとの処理を入れる。
    #
    if kopen-kclose<0:
        candle='yousen'#color Red
        #print('陽線')
    else:
        candle='insen'#color Blue
        #print('陰線')
    #objを生成する。
    #始値、終値でZ軸の高さを設定する。
    #print( fdate.strftime("%Y/%m/%d") )#2020-12-22 00:00:00となるので、時刻を除く2020-12-22
    #Candle_Main####################################################
    candleLocation=fcandle(candle,kopen,kclose,bairitsu,xmove,mat1,mat2)
    xmove+=0.048
    
    #Candle_hige####################################################
    fcandle_hige(candle,khigh,klow,bairitsu,candleLocation,mat1,mat2)
    #count is Global      
    count+=1

#最後のローソクのobjの横に矢印を与える
#この場合、ローソクの原点を移動させて、ローソクの中心に移動させる必要がある
candleCount=0
for obj in bpy.data.objects:
    if 'candle' in obj.name:
        #print(obj.name)
        candleCount+=1
candleName='candle'+str(candleCount)

#Arrow
bpy.ops.mesh.primitive_cone_add(radius1=1, radius2=0, depth=2, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(0.05, 0.05, 0.05))
#図形を回転(Y軸周りに90°)
bpy.ops.transform.rotate(value=-3.1415/2 ,orient_axis='Y')
bpy.context.object.data.materials.append(mat5) 
bpy.ops.transform.translate(value=(bpy.data.objects[candleName].location[0]+0.08,bpy.data.objects[candleName].location[1],bpy.data.objects[candleName].location[2]))#


bpy.context.scene.cursor.location=(0.0,0.0,0.0)
#open,close
color=(1.0,1.0,1.0,1.0)
#str,color,location,size
lastOpen=float(df[len(df)-1].open)#始値
lastClose=float(df[len(df)-1].close)#終値
roundOpen='O:'+str(round(lastOpen,2))#画面に表示させる直近の始値文字
roundClose='C:'+str(round(lastClose,2))#画面に表示させる直近の終値文字

add_textKai(roundOpen, color,(xmove+0.1,0,lastOpen*bairitsu),(0.06,0.05,0.06))
add_textKai(roundClose, color,(xmove+0.1,0,lastClose*bairitsu),(0.06,0.05,0.06))

#end.strftime("%Y/%m/%d") or date[len(date)-1].strftime("%Y/%m/%d")today
color=(0.0,1.0,0.0,1.0)
coneLocation=bpy.data.objects['Cone'].location
#tyokkinDay=date[len(date)-1].strftime("%Y/%m/%d")
tyokkinDay=df[len(df)-1].index

if len(df)>0:
    add_textKai(tyokkinDay,color, (coneLocation[0]+0.16,coneLocation[1],coneLocation[2]),(0.06,0.05,0.06))
#print('last day:',date[len(date)-1])

#始値、終値、直近の日付の調整。オブジェクトが重なってしまう金額が近いときに離す処理
if candle=='yousen':#Openが下側でCloseが上側にあるはず
    #bpy.data.objects[roundOpen].dimensions[1]#Z方向の幅サイズではなくてY軸、理由はローカルで回転させたから
    #bpy.data.objects[roundClose].dimensions[1]
    #bpy.data.objects[tyokkinDay].dimensions[1]
    #始値、終値、直近の日付のlocationを取得する。Z方向ではなくてY軸の幅の半分を上下に加減算して重なりを調べる
    #bpy.data.objects[roundOpen].location[2]
    #bpy.data.objects[roundClose].location[2]
    #bpy.data.objects[tyokkinDay].location[2]
    #roundCloseを調整する.roundCloseの下側位置が、直近日付の上側位置以下になっているときに、直近日付の上の方にroundCloseを上へ移動させる
    
    #location is [2]:Z, dimensions is [1]:Y
    if bpy.data.objects[roundClose].location[2]-bpy.data.objects[roundClose].dimensions[1]/2 <= bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]/2:
        #直近日付の位置に、プラスへ移動
        bpy.data.objects[roundClose].location[2]=bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]*1.5
    #roundOpenを調整する。roundOpenの「上側」位置が、直近日付の「下側」以上になっているときに、直近日付の「下の方」にroundOpenを下へ移動させる
    if bpy.data.objects[roundOpen].location[2]+bpy.data.objects[roundOpen].dimensions[1]/2 >=bpy.data.objects[tyokkinDay].location[2]-bpy.data.objects[tyokkinDay].dimensions[1]/2:
            #「マイナス」へ移動
        bpy.data.objects[roundOpen].location[2]=bpy.data.objects[tyokkinDay].location[1]-bpy.data.objects[tyokkinDay].dimensions[1]*1.5
else:#insen Openが上側でCloseが下側にあるはず.Yousenとは逆
    #roundOpen
    print('insen')
    if bpy.data.objects[roundOpen].location[2]-bpy.data.objects[roundOpen].dimensions[1]/2<=bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]/2:
        bpy.data.objects[roundOpen].location[2]=bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]*1.5
        print('Open')
    #roundClose
    if bpy.data.objects[roundClose].location[2]+bpy.data.objects[roundClose].dimensions[1]/2>=bpy.data.objects[tyokkinDay].location[2]-bpy.data.objects[tyokkinDay].dimensions[1]/2:
        bpy.data.objects[roundClose].location[2]=bpy.data.objects[tyokkinDay].location[2]-bpy.data.objects[tyokkinDay].dimensions[1]*1.5
        print('Close')

    

#2020/12/29
#print('Max:',max(df['High']))#最大値が取れる
#高値の最大値maxと安値の最小値minを取得して
#500円ごとのバー基準株価線(26500,27000,27500)を自動で作成したい。
#面倒だけど、別途高値、安値の配列オブジェクトを作って、メソッドに渡す
dfHigh=[]
dfLow=[]
for m in df:
    dfHigh.append(float(m.high))
    dfLow.append(float(m.low))

makeBarMaxtoMin(dfHigh,dfLow)

#camera move, near Cone obj
camera_obj = bpy.data.objects['Camera']
print(camera_obj.location)
camera_obj.location=(coneLocation[0]+0.16,coneLocation[1]-3.0,coneLocation[2])

#Neko呼び出し
file_path = '/Users/toshiromaseda/Documents/blender/model/テスト、研究モデル/Neko/Neko_simple_001.blend'
inner_path = 'Object'
object_name = 'Neko'
 
bpy.ops.wm.append(
    filepath=os.path.join(file_path, inner_path, object_name),
    directory=os.path.join(file_path, inner_path),
    filename=object_name
    )

bpy.context.scene.cursor.location=(0.0,0.0,0.0)
# 指定オブジェクトを取得する
#arg_objectname='Neko'
selectob = bpy.data.objects[object_name]
selectob.select_set(True) #2.9
selectob.location=(coneLocation[0],coneLocation[1]-0.1,coneLocation[2])
bpy.ops.transform.resize(value=(0.07,0.07,0.07)) # 図形を変形

print('done.')

''' Result



'''

 

python,株データ取得pandas_datareader 米ヤフーファイナンスからデータ欠落する時間帯があるメモ

#Blenderにpandas_datareaderインストール済

python,株データ取得のためのコード、Anaconda、JupyterLabで実行
#日経平均株価のデータを取得したときに、前日分が欠落することがあった。今日の分は取得できたのに、、、
#過去1週間のデータを取得とするはずだったが一部の日付データが取得できず。
#start: 2020/12/22
#today: 2020/12/29
#df=data.DataReader(‘^N225′,’yahoo’,start,end)
#しかし、午前中は 12/29当日データは取得できたけど、前日12/28分は取得できず。
#AM9-11ごろ x
#AM11:07分頃
#AM11:30 x
#11時53分 今度は28日が取得できて、今日の分が取得できず
#12:07 正常に取得できた。28日と今日の29日

結論:たぶん午前中は欠落するデータがあるかもしれない。午後12:05になると当日の日経平均株価が正常に取得できるようだ。正常に取得できないときは、日付が今日の分29日はあっても前日の28日がない。ちなみに25日分はあった

start: 2020/12/21
today: 2020/12/29
2020/12/21
2020/12/22
2020/12/23
2020/12/24
2020/12/25
2020/12/28>>午前中はこの日のデータが取得できず
2020/12/29>>午前中でも取得できた
                    High           Low          Open         Close  Volume  \
Date                                                                         
2020-12-21  26905.669922  26533.630859  26834.099609  26714.419922   60700   
2020-12-22  26639.990234  26361.660156  26559.330078  26436.390625   58600   
2020-12-23  26585.210938  26414.740234  26580.429688  26524.789062   56000   
2020-12-24  26764.529297  26605.259766  26635.109375  26668.349609   47900   
2020-12-25  26716.609375  26638.279297  26708.099609  26656.609375   33400   
2020-12-28  26854.029297  26664.599609  26691.289062  26854.029297   50700   
2020-12-29  27298.220703  26921.140625  26936.380859  27292.369141       0   

               Adj Close  
Date                      
2020-12-21  26714.419922  
2020-12-22  26436.390625  
2020-12-23  26524.789062  
2020-12-24  26668.349609  
2020-12-25  26656.609375  
2020-12-28  26854.029297  
2020-12-29  27292.369141

 

Mac版BlenderのPythonにPip、pandas_datareaderインストールしたメモ

・PythonはMacOS BigSur用とBlender用とが存在する。

つまり保存場所が異なる。
よってBlenderで使いたいモジュールが必要なときは、個別でインストールが必要。
つまり、MacOSでpandas_datareaderをインストールしても、BlenderのPythonでは
使えない。これは、Blenderが使用するPythonのバージョンがOS側と異なるとエラーになる
かもしれないので、個別にPythonをインストールする必要があるためだと推測した。

環境:MacOS BigSur

Blender:2.91

参考URL
https://qiita.com/kjunichi/items/a36fdc9db3876e068249
https://qiita.com/hibit/items/1ac97c71d5adc5b45f85

さらに、Blenderのバージョンアップ毎にインストールが必要かもしれない。
以下、メモとして記載した。バージョンアップ毎にフォルダが変わるし、MacOSが変わる毎に
ディレクトリが変わるかもしれない。

MacのBlenderをターミナルから起動

/Applications/Blender.app/Contents/MacOS/Blender

Blenderのpython場所

–MacOSのpythonと異なる場所にある(バージョンが変わる毎にディレクトリが変わる。2.91の部分)BlenderのPythonのディレクトリ
/Applications/Blender.app/Contents/Resources/2.91/python

・バージョンアップ毎にインストールが必要かもしれないので、記載しておく。

python向けにpipをインストール(バージョンが変わる毎に作業が必要かも)

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py /Applications/blender.app/Contents/Resources/2.91/python/bin/python3.7m get-pip.py

>>curl: (3) URL using bad/illegal format or missing URL
curl: (6) Could not resolve host: get-pip.py
変なエラーがでている気がするが、ダウンロードはできてた
でもpipフォルダーができてないので、正しければ
bin/pipフォルダができるはずが、pipフォルダがない状態
このcurlは失敗。
次に続く、

・python/binフォルダに、pipフォルダが作成されなかったときは、以下のコマンドを実行する

get-pip.pyを実行、ターミナルで実行する

/Applications/blender.app/Contents/Resources/2.91/python/bin/python3.7m /Applications/Blender.app/Contents/Resources/2.91/python/bin/get-pip.py

成功した↓
(base) ToshironoiMac:bin toshiromaseda$ pwd
/Applications/Blender.app/Contents/Resources/2.91/python/bin
(base) ToshironoiMac:bin toshiromaseda$ ls
get-pip.py pip pip3 pip3.7 python3.7m wheel

binフォルダ内に、pip,pip3,pip3.7ができた。こんなにフォルダいらんのに、、、

よくわかっていないがpipフォルダにインストールする。
pandas_datareaderインストール、ターミナルで実行する

/Applications/Blender.app/Contents/Resources/2.91/python/bin/pip install pandas_datareader

pandasインストール>>不要みたいだ。実行したけど成功と表示されない。すでにインストールされてるよ的なメッセージだったと思う。から次回は実行しなくてもよいはず。

/Applications/Blender.app/Contents/Resources/2.91/python/bin/pip install pandas

ここまでインストールは終わり。
BlenderのScriptingに記載して実行してエラーがでなければ読み込みOK。
–ここから
import pandas_datareader.data as data
from datetime import datetime

print(‘done.’)
print(‘success’)
–ここまで

これで、BlenderのPythonからグラフを株価チャートを作成できたりする。

Blender_python

blender 2.91 回転しないと思ったら

右上のOptionsのLocationsのチェックを外せばよい。

Rキーを押したり、Sキーを押してマウスを動かしてもオブジェクトが回転、拡大しない。291のバグかと思ったら、Optionsのチェックが入っていた。バージョンが上がったりすると、設定が変わって色々とチェックを入れたりするので

Blenderをインストールしてその直後に変なところを触ってしまうようだ。

Blender

Blender Pythonファイルを開いて 実行手順メモ

Pythonファイルを読み込んで(開く)実行するだけの手順メモ
数ヶ月使っていないと手順を忘れやすいから困る

参考
Blenderのコンソールからファイル名を指定する方法あるらしい。↓まだ試していない。
https://www.it-swarm-ja.tech/ja/python/blender%E3%81%A7python%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92%E5%AE%9F%E8%A1%8C/1068290152/

備忘録
Pythonファイルに記載したスクリプトを実行してBlenderでオブジェクトを作成する手順

忘れていたのでメモ

1.Pythonファイルを作成済とする。
2.Blenderを起動して、Scripting画面にする。
3.右側にTextエリアがあるのでファイルを開く(Pythonファイルを作成済とする)
4.実行(右向きの三角アイコン)ボタンをクリックする
5.オブジェクトが作成される。

Pythonファイル

pythonでTXTからCSV変換してMysqlへのインサート処理

#pythonメソッドは外部ファイルpy
#2020/12/21
#CSVをMysqlにインサート
#Test_Table_StockOption
#TXTからCSVに変換してCSVファイルを読み込んでMysqlのテーブルに登録を一括して行えるようにする。DB,テーブルは作成済とする。スタンドアローンでの利用

環境:MacOS BigSur、Python3、Mysql、JupiterLab Anaconda

#実行用

# MySQLdbのインポート
import MySQLdb
import os
import re
import sys
import datetime
import glob#ファイル一覧
import shutil#move

import methodMysql#個人用メソッド pyファイル
#本文は下にある。メソッドを先に記載しないと呼び出しでエラーになる。


#本文
########入力内容########################################################################
ifile='2020年12月23日AM7時39分.txt'#CSVはTXTから作成されるのでCSV名は不要
useTable='Table_StockOption'#Mysqlへ登録するテーブル、テスト用、通常用がある
useDate='2020/12/23'#オプション取り込みの日付
useMonth=1#月限 12月の作業はたいてい翌月である1月
########入力内容

#TXTをCSVに出力してからMysqlへ登録する。DB,テーブルは事前に用意されたものとする
###本文 ここでoutMojiMKIII()メソッドを使用している
path='/Users/toshiromaseda/Documents/2020年株関連/kabu_python/'
os.chdir(path)#ディレクトリ変更
print(os.getcwd())#ディレクトリ確認

csvfile='c_'+ifile.split('.')[0]+'.csv'

methodMysql.checkFile(ifile)#check 取り込み済みのファイルかどうかを調べる

try:
    ofile=open(csvfile,'tw') 
except FileNotFoundError as e: # FileNotFoundErrorは例外クラス名
   print("ファイルが見つかりません", e)
   #print("強制終了")
   sys.exit()#ファイルがなければ終了
except Exception as e: # Exceptionは、それ以外の例外が発生した場合
   print(e)

try:#ファイルが存在しないときのエラー処理try
    with open(ifile,'tr') as fin:
        for iline in fin:
            #ilineに、”コール”、”出来高”の文字がある行は無視するようにする
            #countで探すか 1行目、2行目は不要なのでDBにインサートしないための処理
            if iline.count('コール')>=1 or iline.count('出来高')>=1:
                continue#以下は実行されない
            try:
                ofile.write(methodMysql.outMojiMKIII(iline)+'\n')#MKIII改良版2020/12/18
                #次はMysqlに直接インサートするバージョンを作業する
            except Exception:
                print("do not")
        ofile.close()
except FileNotFoundError as e: # FileNotFoundErrorは例外クラス名
    print("ファイルが見つかりません。パス、ファイル名を確認してください", e)
    ofile.close()
    print("強制終了")
    sys.exit()#ファイルがなければ終了
except Exception as e: # Exceptionは、それ以外の例外が発生した場合
   print(e)

#CSVからMysqlへ CSVファイルがないと実行できない。重複チェックなし
#csvToMysql(difileはCSVファイル名,dtablename、doptionDate日付、dmonth月限)
#テスト用テーブルTest_Table_StockOption
methodMysql.csvToMysql(csvfile,useTable,useDate,useMonth)

#Testが終わったら試す。 単独実行可能 但し、ファイルの移動先チェックがないので、他で移動がないことをチェックする必要あり
methodMysql.fileMove(ifile,'./option_python_execute')
methodMysql.fileMove(csvfile,'./option_python_execute')

#表、グラフを出力する 単独実行可能
methodMysql.selectMysql('Table_StockOption')

print("終わりました。")

メソッド 外部ファイルにしたmethodMysql.py これをimport methodMysql として読み込む

#pythonUseMysql2.ipynbで使用
# MySQLdbのインポート
import MySQLdb
import os
import re
import sys
import datetime
import glob#ファイル一覧
import shutil#move

#株探の先物オプション記事について、特定文字列について空白をカンマに置換処理するためのメソッド
#def latterHalf(text):数字を後ろから探す
#def outMojiMKIII(text):空白をカンマに置換処理
#def csvToMysql(difile,dtablename,doptionDate,dmonth):
#def checkFile(filename):fileが存在するかチェック。パスは固定
#def fileMove(file,path):file移動
#def selectMysql(tablename):select 



#メソッドを別ファイルにした。
#文字列の後ろ側の数字を後ろから探し、抜けていた場合0を埋める
def latterHalf(text):
    textout=text
    pattern=re.compile('[0-9]+')#findで正規表現ができない
    i=0
    checkArray=[]#タプルを入れる配列
    while i>=0:#数字を探す
      m=pattern.search(textout, i)
      if m:
        #print(m.start())
        #print(m.end())
        #これをタプル配列に入れて、N,N-1で差が大きいときに0を入れる
        #print(m.span())
        checkArray.append(m.span())
        i = m.end()#m.start() + 1#m.end()
      else:
        break
    n=len(checkArray)
    if n>=2:#nは最低2こ必要 最後と最後の1こ前の
        #print("[n-1][0]",checkArray[n-1][0])#0番目の1個目 [0](0,1)
        #print("[n-2][1]",checkArray[n-2][1])#0番目の2個目
        #個数はNだけど配列の指定はそれより1小さいのでN-1となる
        if (checkArray[n-1][0]-checkArray[n-2][1])>=6:
            print("put抜けている")
            #checkArray[n-1][1]の後ろに挿入する
            texttmp=textout[:checkArray[n-2][1]+2]+ '0' + textout[checkArray[n-2][1]+2:]
            textout=texttmp
    output=textout
    return output
#end def

def outMojiMKIII(text):
    #空白を削除する前に、空白の個数を数える
    #株探の仕様が変わったらここを変える。2020/12/16
    kuro=re.compile('[  ]+')#半角と全角の空白置換 半角全角が[半角全角]として入っている
    
    if text.count(' ',0,15)>=13:
           #空白13個はプット
            opt='put'
            textout=text.strip()#先頭、末尾の空白、改行を削除する
    else:
            #コールの場合、2種類あるのでそれをチェックする
            textout=text.strip()#先頭、末尾の空白を削除する
            check=kuro.sub(',',textout)#半角全角の空白を置換
            count=check.split(",")
            #print ('len count:',len(count))
            if len(count)>=5:#配列が5個以上なら、call,putが含まれる       
                opt='callandput'
            else:
                opt='onlycall'
    pattern=re.compile('[0-9]+')#findで正規表現ができない
    if opt=='onlycall' or opt=='callandput':
        #次に、「call,putあり」OR「Callのみ」かをチェックする。
        #optSub='callandput' 'onlycall'
        #callのみを先に処理して、put側を調べる
        matchobj=re.search('[0-9]+',textout)#最初の数字を探す
        if matchobj:
            #print('マッチした文字列:'+matchobj.group())
            #print('マッチした文字列グループ:',matchobj.groups())
            #print( '開始位置'+str(matchobj.start()) )#先頭位置は0番として数える 3番目(4文字目)に見つかった
            #print( '終了位置'+str(matchobj.end()) )#終了位置は次の番目を含んでいるので実際は1を引いた数が終了位置
            #print(matchobj.span())#'マッチした文字列の (開始位置, 終了位置) のタプル'+
            #2番めの数字を探す
            secondMatch=pattern.search(textout,matchobj.end())#compileを使用してpatternで再度位置を指定して探す
            if secondMatch:
                #print( '開始位置2:'+str(secondMatch.start()) )#先頭から数えて10番目に次の数字が見つかった
                #1番目と2番めの文字数が5以上空いていたら数字が抜けている事がわかる。
                #ここに0を埋める処理を入れる
                if secondMatch.start()-matchobj.end() >=5:
                    print('値が抜けてる')
                    # hash = "355879ACB6"
                    # hash = hash[:4] + '-' + hash[4:]
                    #文字列の挿入。#1番目の文字の3文字目くらいに0を追加する。
                    texttmp=textout[:matchobj.end()+2]+ '0' + textout[matchobj.end()+2:]
                    textout=texttmp
        #put側のチェック。再度optでチェックする
        if opt=='onlycall':
            #置換して終わる
            output=kuro.sub(',',textout)+',,,'
        elif opt=='callandput':
            #print('callandputの処理')
            tmp=latterHalf(textout)#後半PUTの処理をして文字を返す
       
            #置換して終わる
            output=kuro.sub(',',tmp)
    elif opt=='put':
    #putのみの場合
        #3つのカンマを付ける
        tmp=latterHalf(textout)#後半PUTの処理をして文字を返す
        output=',,,'+kuro.sub(',',tmp)#>>,,,26250,285,-10,189
    #end if
 
    return output
### end def

def csvToMysql(difile,dtablename,doptionDate,dmonth):
#ここからSTART
#Mysqlに接続メソッドを入れる
# データベースへの接続とカーソルの生成
    connection = MySQLdb.connect(
        host='localhost',
        user='maseda',
        passwd='Test1030',#知られても問題ないパスワード
        db='Stock')
    cursor = connection.cursor()

    #csvファイル名
    ifile=difile
    
    #table
    tablename=dtablename#"Test_Table_StockOption"#テスト用テーブルを使用する

    #カラム名
    rowname="(Volume1,Change1,Price1,ExercisePrice,Price2,Change2,Volume2,Month,OptionDate,CreateDate,YOBI)"
    #VALUES (%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s)>>%dは%sにしないとエラーになった。

    #カラム変数
    month=dmonth#1#月限
    optionDate=doptionDate#"2020/12/22"#データ取得の日付、たいていCSVに記載の日付になる。
    
    dt_now=datetime.datetime.now()
    createDate=dt_now.strftime('%Y-%m-%d %H:%M:%S')#今日の日付時刻を入れて、取り込み実行の日付で良い。後で削除操作するときの目安くらいだから厳密ではない

    yobi=""#コメントがあればいれる。
    
    count=0
    #テーブルにデータを挿入する部分から書いていく
    #CSVを1行ごとに読み取り、列ごとにカラムに入れていく
    try:#ファイルが存在しないときのエラー処理try
        with open(ifile,'tr') as fin:
            for iline in fin:
                try:
                    #Mysqlに直接インサートするバージョンを作業する
                    # ここに実行したいコードを入力します

                    #cursor.execute("INSERT INTO Test_Table_StockOption (カラム,) VALUES(値,,,)")
                    #cursor.execute("INSERT INTO " + tablename + " " + rowname + " VALUES (%s,%s)", ("test1","test2"))
                    #count=count+1
                    tmp=iline.strip().split(",")#stripしてからsplit()だと理解している。 iline.split(",")のままだと改行が入ってくるのでstripで前後の空白と改行を削除する
                    #CSVのデータが空の場合は、値0を入れる
                    if tmp[0]=='':
                        tmp[0]=0
                    if tmp[1]=='':
                        tmp[1]=0
                    if tmp[2]=='':
                        tmp[2]=0
                    if tmp[3]=='':
                        tmp[3]=0
                    if tmp[4]=='':
                        tmp[4]=0 
                    if tmp[5]=='':
                        tmp[5]=0
                    if tmp[6]=='':
                        tmp[6]=0    
                    #テストテーブルにインサートする前に、確認する前に、Splitを確認する。
                    #print(count,tmp[0],tmp[1],tmp[2],tmp[3],tmp[4],tmp[5],tmp[6])
                    #%dにするとエラーになるのでINT型は%sにしておくとエラーにならない。なのでINTなのに%sとして記述してある。
                    cursor.execute("INSERT INTO " + tablename + " " + rowname + " VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)",\
                                   (tmp[0],tmp[1],tmp[2],tmp[3],tmp[4],tmp[5],tmp[6],month,optionDate,createDate,yobi))

                    #こっちだと、%dに値がないよとエラーになる。正しい記述のはずがパイソンではエラーになるようだ。
                    #cursor.execute("INSERT INTO " + tablename + " " + rowname + " VALUES (%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s)",\
                    #               (tmp[0],tmp[1],tmp[2],tmp[3],tmp[4],tmp[5],tmp[6],month,optionDate,createDate,yobi))

                except MySQLdb.Error as e:
                    print('MySQLdb.Error: ', e)
                    connection.rollback()#失敗したらもとに戻す。これだと途中で成功してもコミットされるので、1回でもエラーのときはBREAKのほうがいいかも。
                    print("強制終了MYSQL")
                    connection.close()
                    return
            #ofile.close()
        connection.commit()

    except FileNotFoundError as e: # FileNotFoundErrorは例外クラス名
        print("ファイルが見つかりません。パス、ファイル名を確認してください", e)
        ofile.close()
        sys.exit()#ファイルがなければ終了
    except Exception as e: # Exceptionは、それ以外の例外が発生した場合
       print(e)

    # 接続を閉じる
    connection.close()  

    print("Mysql書き込み終了")
#defここまで

#check file
def checkFile(filename):
    #他にもimport os os.listdir(path) というのもある
    files=glob.glob('./option_python_execute/*.txt')
    for file in files:
        #print(file)
        if filename in file:#ファイル名を含んでいればTRUE
            print('すでに取り込み済みのファイルです。')
            sys.exit()#return
#end def

def fileMove(file,path):
    shutil.move(file, path)#('./new.txt', './sample')
    print('file move',file)
#end def

def selectMysql(tablename):
# データベースへの接続とカーソルの生成
    connection = MySQLdb.connect(
        host='localhost',
        user='maseda',
        passwd='Test1030',#知られても問題ないパスワード
        db='Stock')
    cursor = connection.cursor()  
    try: 
        # ここに実行したいコードを入力します
        cursor.execute("SELECT SUM(Volume1) as callVolume1, ExercisePrice, SUM(Volume2) as putVolume2 FROM "+ tablename +\
                        " WHERE Month=1 GROUP BY ExercisePrice ORDER BY ExercisePrice Desc")

        #カラム名を取得
        #cursor.execute("show columns from Table_StockOption")

        # fetchall()で全件取り出し
        rows = cursor.fetchall()
        searchArray=[]#タプルで登録
        for row in rows:
          print(row[0],row[1],row[2])
          searchArray.append(row)  
            # print(row[Volume1]) ERROR

        #print(searchArray[0])#IDの情報:('ID', 'int', 'NO', 'PRI', None, 'auto_increment')
        #for srow in searchArray:
        #    print(srow)#
    
    except MySQLdb.Error as e:
        print('MySQLdb.Error: ', e)
    
    #表示
    connection.commit()
    connection.close()  
#end def

 

pythonでCSVをMysqlへのインサート処理

#pythonでCSVをMysqlへのインサート処理を入れたい
#2020/12/21
#CSVをMysqlにインサート
#Test_Table_StockOption
#CSVファイルを読み込んでMysqlのテーブルに登録を一括して行えるようにする
#
“””
考え方2020/12/22
TXTをCSVで出力
CSVファイルを読み込み
Mysqlに接続
ループしながらMysqlのテーブルに入れていく

現在はCSV出力まで終わっているので
CSVファイルを読み込み
テーブルにデータを挿入する部分から書いていく

・テーブルを作成例 Mysql

CREATE TABLE Test_Table_StockOption(
ID int(11) NOT NULL AUTO_INCREMENT,
Volume1 int(11),
Change1 int(11),
Price1 int(11),
ExercisePrice int(11) NOT NULL,
Price2 int(11),
Change2 int(11),
Volume2 int(11),
Month int(2),
OptionDate DATE,
CreateDate DATETIME,
YOBI text,
PRIMARY KEY (ID)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

・データを全部削除
delete from Table_StockOption;
・自動採番をリセット
ALTER TABLE Test_Table_StockOption AUTO_INCREMENT = 1;

#作業用動作確認用コード


# MySQLdbのインポート
import MySQLdb
import os
import re
import sys
import datetime


#TXTからCSV出力はここにあるとする。

#CSVファイルを読み込み
path='/Users/toshiromaseda/Documents/2020年株関連/kabu_python/'
os.chdir(path)#ディレクトリ変更
print("作業ディレクトリ:",os.getcwd())#ディレクトリ確認
ifile='c_2020年12月22日AM935.csv'#sys.argv[1] このスクリプトと同じ階層ならパスは不要 

#CSVの中身の例
#128,-5,29,27875,,,
#304,-5,40,27750,1530,0,1


#ここからSTART メソッドにするときは、ifileとtablename、optionDate、month月限を引数にしたほうがわかりやすい。
#Mysqlに接続メソッドを入れる
# データベースへの接続とカーソルの生成
connection = MySQLdb.connect(
    host='localhost',
    user='maseda',
    passwd='Test1030',#知られても問題ないパスワード
    db='Stock')
cursor = connection.cursor()

#table
tablename="Test_Table_StockOption"#テスト用テーブルを使用する

#カラム名
rowname="(Volume1,Change1,Price1,ExercisePrice,Price2,Change2,Volume2,Month,OptionDate,CreateDate,YOBI)"
#VALUES (%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s)

#カラム変数
month=1#月限
optionDate="2020/12/22"#データ取得の日付、たいていCSVに記載の日付になる。
dt_now=datetime.datetime.now()
createDate=dt_now.strftime('%Y-%m-%d %H:%M:%S')#今日の日付時刻を入れて、取り込み実行の日付で良い。後で削除操作するときの目安くらいだから厳密ではない

yobi=""#コメントがあればいれる。

count=0
#テーブルにデータを挿入する部分から書いていく
#CSVを1行ごとに読み取り、列ごとにカラムに入れていく
try:#ファイルが存在しないときのエラー処理try
    with open(ifile,'tr') as fin:
        for iline in fin:
            try:
                #Mysqlに直接インサートするバージョンを作業する
                # ここに実行したいコードを入力します
                
                #cursor.execute("INSERT INTO Test_Table_StockOption (カラム,) VALUES(値,,,)")
                #cursor.execute("INSERT INTO " + tablename + " " + rowname + " VALUES (%s,%s)", ("test1","test2"))
                count=count+1
                tmp=iline.strip().split(",")#stripしてからsplit()だと理解している。 iline.split(",")のままだと改行が入ってくるのでstripで前後の空白と改行を削除する
                #CSVのデータが空の場合は、値0を入れる
                if tmp[0]=='':
                    tmp[0]=0
                if tmp[1]=='':
                    tmp[1]=0
                if tmp[2]=='':
                    tmp[2]=0
                if tmp[3]=='':
                    tmp[3]=0
                if tmp[4]=='':
                    tmp[4]=0 
                if tmp[5]=='':
                    tmp[5]=0
                if tmp[6]=='':
                    tmp[6]=0    
                #テストテーブルにインサートする前に、確認する前に、Splitを確認する。
                #print(count,tmp[0],tmp[1],tmp[2],tmp[3],tmp[4],tmp[5],tmp[6])
                #%dにするとエラーになるのでINT型は%sにしておくとエラーにならない。なのでINTなのに%sとして記述してある。
                cursor.execute("INSERT INTO " + tablename + " " + rowname + " VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)",\
                               (tmp[0],tmp[1],tmp[2],tmp[3],tmp[4],tmp[5],tmp[6],month,optionDate,createDate,yobi))
                
                #こっちだと、%dに値がないよとエラーになる。正しい記述のはずがパイソンではエラーになるようだ。
                #cursor.execute("INSERT INTO " + tablename + " " + rowname + " VALUES (%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s)",\
                #               (tmp[0],tmp[1],tmp[2],tmp[3],tmp[4],tmp[5],tmp[6],month,optionDate,createDate,yobi))
                
                #print("count",len(tmp))#カンマがあれば全部カウントされる。全部7つ
                
            except MySQLdb.Error as e:
                print('MySQLdb.Error: ', e)
                connection.rollback()#失敗したらもとに戻す。これだと途中で成功してもコミットされるので、1回でもエラーのときはBREAKのほうがいいかも。
                
        #ofile.close()
    connection.commit()
    
except FileNotFoundError as e: # FileNotFoundErrorは例外クラス名
    print("ファイルが見つかりません。パス、ファイル名を確認してください", e)
    ofile.close()
except Exception as e: # Exceptionは、それ以外の例外が発生した場合
   print(e)

# 接続を閉じる
connection.close()  

print("Mysql書き込み終了")
##ここまで

 

pythonを使ってmatplotlibで表やグラフを表示する。

2020年12月21日
かなり設定が面倒。エクセルでも表の色を指定すると時間がかかるのと同じだろう。
#行セル、列セルで細かく色指定はやっかいだ。それでもスクリプトからテキストベースではない表を作成できるのは良いことかも。

環境:MacOS BigSur、Anaconda-Navigator、JupiterLab

もし、matplotlibの読み込みでエラーになったら、一度アンイストールしてから再度インストールするとよい

#参考

#https://www.delftstack.com/ja/howto/matplotlib/plot-table-using-matplotlib/
#Tableの構成がわかりやすい
#https://qiita.com/arakiii/items/5bece948dd459b53d0b8
#(A)コロンで区切った配列の初期化事例

#https://ai-inter1.com/pandas-dataframe_basic/

#(B)イコールを使った配列の事例

import pandas as pd
import matplotlib.pyplot as plt
#JupyterLabはこうするらしい
%matplotlib inline


data = {
    'Tokyo': [27, 23, 27, 24, 25, 23, 26],
    'Osaka': [26, 23, 27, 28, 24, 22, 27],
}

df = pd.DataFrame(data)

fig, ax = plt.subplots(figsize=(3, 3))

ax.axis('off')
ax.axis('tight')

tb = ax.table(cellText=df.values,
              colLabels=df.columns,#Tokyo,Osakaの見出しが表示、行の見出しを入れたいときはrowLabels=df.indexみたいにする
              bbox=[0, 0, 1, 1],
              )

tb[0, 0].set_facecolor('#363636')
tb[0, 1].set_facecolor('#363636')
tb[0, 0].set_text_props(color='w')
tb[0, 1].set_text_props(color='w')
print("A")
plt.show()


#(B)のサンプル
list1=[]
index1=[]
columns1=[]
list1=[[1,2,3], [21,22,23], [31,32,33]]
index1 = ["Row1", "Row2", "Row3"]
columns1 =["Col1", "Col2", "Col3"]
df=pd.DataFrame(data=list1, index=index1, columns=columns1)

    #(A)と同じ構成
fig, ax = plt.subplots(figsize=(5, 5))#大きくした

ax.axis('off')
ax.axis('tight')

tb = ax.table(cellText=df.values,
              colLabels=df.columns,#colum見出し
              rowLabels=df.index,#Row見出し
              bbox=[0, 0, 1, 1],
              )

tb[0, 0].set_facecolor('#363636')
tb[0, 1].set_facecolor('#363636')
tb[0, 2].set_facecolor('#363636')#3列目 バックカラー
tb[0, 0].set_text_props(color='w')
tb[0, 1].set_text_props(color='w')
tb[0, 2].set_text_props(color='w')#3列目

print("B")
plt.show()

python表

matplotlibがインストールできたけどAnaconda-Navigatorで使えない、メモ

環境 MacOS BigSur
Anaconda-Navigator JupiterLab
Python3

結論
matplotlibをアンイストールして再度インストールすればいいだけ。

2020/12/20、

環境Anaconda-Navigator Chrome
matplotlibインストール
でも
import matplotlib.pyplot as plt
とするとうまく行かない。

(base) ToshironoiMac:~ toshiromaseda$ python -c "import matplotlib;print(matplotlib.matplotlib_fname())"
/Users/toshiromaseda/opt/anaconda3/lib/python3.7/site-packages/matplotlib/mpl-data/matplotlibrc
これをViで修正
(base) ToshironoiMac:~ toshiromaseda$ vi /Users/toshiromaseda/opt/anaconda3/lib/python3.7/site-packages/matplotlib/mpl-data/matplotlibrc

backend : Agg

backend : TkAgg

そして
Anaconda-Navigatorでは
import matplotlib
print(matplotlib.__version__)
でバージョンが表示された3.1.3

Anaconda-Navigatorでは
import matplotlib.pyplot as plt
とするとうまく行かない。単にこれが原因のようだ
import matplotlibなら問題なさそう
#import pyplot ここでエラー、
PyQt5をインストール

pip install PyQt5
vi /Users/toshiromaseda/opt/anaconda3/lib/python3.7/site-packages/matplotlib/mpl-data/matplotlibrc

Viは、iキーを押すと入力モードになる。修正して、ESCキーを押して、:コロン、Wキー、Qキーで書き込んで抜ける

:wq

 

backend: Qt5Agg
に書き換えた

でもだめ

https://qiita.com/BitPositive/items/35c07cf7360d42a1b665
sudo apt install tk-dev python3-tk

(base) ToshironoiMac:~ toshiromaseda$ sudo apt install tk-dev python3-tk
Password:
The operation couldn’t be completed. Unable to locate a Java Runtime.
Please visit http://www.java.com for information on installing Java.

でもJAVAをインストールしろと言われる。

pip3 install PyQt5
インストール

だめ

そもそもAnaconda-Navigatorの環境で使えるのか?
Anaconda-Navigatorで使っている人をユーチューブで探してみる。
2020/12/20
いまここ

要するに
import matplotlib OK
import matplotlib.pyplot as plt だめ
matplotlibが入れば、pyplotが使えていいはず、、、、

Anaconda-NavigatorではなくてターミナルからPythonを実行して表を作るかどうか、、、

if __name__ == ‘__main__’:#直接自分自身のモジュールが実行されたときTRUEになる。

#Segmentation fault: 11 エラーになる。ターミナルでもエラーだ。なにか悪さしてるか

https://qiita.com/sage-git/items/aa3d2acd93cded4be2e8

conda install -c conda-forge opencv
(base) ToshironoiMac:kabu_python toshiromaseda$ python test.py
Segmentation fault: 11
(base) ToshironoiMac:kabu_python toshiromaseda$ python test.py
Segmentation fault: 11
(base) ToshironoiMac:kabu_python toshiromaseda$ conda install -c conda-forge opencv
Collecting package metadata (current_repodata.json): done
Solving environment: failed with initial frozen solve. Retrying with flexible solve.
Solving environment: failed with repodata from current_repodata.json, will retry with next repodata source.
Collecting package metadata (repodata.json): done
Solving environment: failed with initial frozen solve. Retrying with flexible solve.
>>>長いので中止にした。
Solving environment: / failed

CondaError: KeyboardInterrupt

 

もしかするとアンイストールして再度インストールすればいいのかもしれないと記載があった

pip uninstall matplotlib
pip install matplotlib

うまくいった。結局再度インストールかよ