SWISS-MODEL & PyMOL

Hands-on prediction and visualization of protein structure

Please note that the prediction of protein structure is generally very difficult and depends much on the amount of data of similar proteins stored in PDB (Protein Data Bank).

  1. Predict the structure of protein of your interest by SWISS-MODEL.

  2. Visualize it by PyMOL.

SWISS-MODEL

Requirements: Amino acid sequence of the protein of your interest.

  1. Go to SWISS-MODEL and start modelling.

f:id:dxsato:20200602121801p:plain

  1. Copy and paste the sequence into the window, fill in the project name and your email (optional; if you want) and start "Search For Templates".

f:id:dxsato:20200602121817p:plain

f:id:dxsato:20200602121847p:plain

  1. Then it starts searching for templates.

f:id:dxsato:20200602121859p:plain

  1. Then it generates the result. It lists similar proteins that are possibly useful for predicting your protein. Choose the best (top) one and click "Build Models". Here are some explanation about the meaning of each score.

f:id:dxsato:20200602121912p:plain

  1. The predicted model has been made now. You can download the pdb file.

f:id:dxsato:20200602121927p:plain

PyMOL

Requirements: Python3, .pdb file generated above

  1. You can install the pymol by conda. If you haven't installed conda yet, you can download the zipped file from here.
$ conda install -c schrodinger pymol-bundle
  1. Learn how to code pymol commands referring to here (Eng) or here (Jap). Here are some example scripts I made, which may be helpful to understand how it works.

1_visualize_model.py which visualizes the model and hightlight some regions and residues of interest by different colors.

$ python3 1_visualize_model.py model VMAT1 130 136 180 30 -100
import time
import re
import pymol
import sys

# sys.argv[1]: the name of the input model (pdb file)
# sys.argv[2]: the name of output figure (png)
# sys.argv[3]: the location of a residue interested
# sys.argv[4]: the location of a residue interested
# sys.argv[5]: the angle of x
# sys.argv[6]: the angle of y
# sys.argv[7]: the angle of z
# python3 1_visualize_model.py model VMAT1 130 136 180 30 -100

pymol_argv = ['pymol', '-qc']
pdb_file = '%s.pdb' % sys.argv[1] #input pdb file
out_png = '%s.png' % sys.argv[2] #output figure name

## Launch pymol
pymol.finish_launching()
pymol.cmd.load(pdb_file)
pymol.cmd.enable(pdb_file)

## Some visual settings of protein structure
pymol.cmd.show('cartoon')  #shown by cartoon
pymol.cmd.do('bg_color white') #make the background color transparent
pymol.cmd.do('set ray_shadow, off') #remove shadow
pymol.cmd.do('select tm1, (resi 19:48)') #select the region of interest and set its name as tm1
pymol.cmd.do('color skyblue, tm1') #change the color of tm1 to skyblue. You can check available colors here: https://pymolwiki.org/index.php/Color_Values
pymol.cmd.do('select tm2, (resi 136:163)') #select the second region of interest and set its name as tm2
pymol.cmd.do('color paleyellow, tm2') #change the color of tm2 to paleyellow
pymol.cmd.do('color white, not tm1 and not tm2') #change color of the other regions to white
pymol.cmd.do('color red, resi %i' % int(sys.argv[3])) #change the color of residue of interest set above
pymol.cmd.do('color red, resi %i' % int(sys.argv[4])) #change the color of another residue of interest set above

pymol.cmd.do('turn x, %i' % int(sys.argv[5])) #set the x angle
pymol.cmd.do('turn y, %i' % int(sys.argv[6])) #set the y angle
pymol.cmd.do('turn z, %i' % int(sys.argv[7])) #set the z angle

time.sleep(5)
pymol.cmd.do('ray 2000, 2000') #set the resolution. When using png as output, I recommend to set as much resolution as possible, though it takes a while.
pymol.cmd.png(out_png)

pymol.cmd.refresh()
pymol.cmd.quit()

f:id:dxsato:20200602121945p:plain

2_zoomin.py which zooms in the residues of interest (and mutates the residue if desired) and shows its side chain by sticks.

$ python3 2_zoomin.py model VMAT1_130Glu 130 GLU 180 30 -100
import time
import re
import pymol
import sys

# sys.argv[1]: name of the model (pdb file)
# sys.argv[2]: the name of output figure (png)
# sys.argv[3]: the location of a residue interested
# sys.argv[4]: the residue to be mutated (must be capital letters)
# sys.argv[5]: the angle of x
# sys.argv[6]: the angle of y
# sys.argv[7]: the angle of z
# python3 2_zoomin.py model VMAT1_130Glu 130 GLU 180 30 -100

pymol_argv = ['pymol', '-qc']
pdb_file = '%s.pdb' % sys.argv[1] #input pdb file
out_png = '%s.png' % sys.argv[2] #output figure name

## Launch pymol
pymol.finish_launching()
pymol.cmd.load(pdb_file)
pymol.cmd.enable(pdb_file)

## Some visual settings of protein structure
pymol.cmd.show('cartoon')  #shown by cartoon
pymol.cmd.do('bg_color white') #make the background color transparent
pymol.cmd.do('set ray_shadow, off') #remove shadow
pymol.cmd.do('set cartoon_color, white')

# let's mutate residue 130 to GLU
pymol.cmd.wizard("mutagenesis")
pymol.cmd.refresh_wizard()
pymol.cmd.get_wizard().do_select('%s/' % str(sys.argv[3]))
pymol.cmd.get_wizard().set_mode('%s' % str(sys.argv[4]))
pymol.cmd.get_wizard().apply()
pymol.cmd.set_wizard()

pymol.cmd.do('set stick_radius = 0.15')
pymol.cmd.do('set sphere_scale = 0.15')
pymol.cmd.do('select ri, byres (resi %s around 4)' % str(sys.argv[3]))  #set the region of interest (here it covers 4 amino acids around the residue of interest)
pymol.cmd.do('show stick, resi %s' % str(sys.argv[3]))  #show stick
pymol.cmd.do('set cartoon_transparency, 0.4') #set the cartoon transparent
pymol.cmd.do('zoom ri')  #zoom in around the residue of interest 
pymol.cmd.do('turn x, %i' % int(sys.argv[5]))
pymol.cmd.do('turn y, %i' % int(sys.argv[6]))
pymol.cmd.do('turn z, %i' % int(sys.argv[7]))

## Generate output
time.sleep(5)
pymol.cmd.do('ray 2000, 2000')
pymol.cmd.png(out_png)

## Finish pymol
pymol.cmd.refresh()
pymol.cmd.quit()

f:id:dxsato:20200602122002p:plain

ripgrep-allでどこかに保存した論文を探す

初めてblogっぽいことを書いてみる。

最近TL上でたまに流れてきて気になってはいたものの、podcastなるものにあまり馴染みがなく敬遠していたが、テーマにそそられて思い切って聞いてみた。 researchat.fm

2時間とめちゃくちゃ長いが、人の声に飢えているのか、作業しながらつい全部聞いてしまった。うるさい先輩たちが話しているような感じ(ごめんなさい)なんだけど、結構タメになる。3人が話しているだけで2時間のコンテンツとして成り立たせるなんてすごい。

この放送の中で、「 論文管理どうしてる?」という話題があり、「ぶっちゃけ無理っすね、必要な時に都度探します」という話になっていて(その時に言っていた「論文それ自体よりも、以前にそれを読むことにした過程を覚えていればたどり着ける」というのもなるほどと思った)、へぇそういうものか、と思ったのだけど(自分は基本Mendeleyで管理している)、そこで一人の方が言及していた ripgrep-allなるものに惹かれ、早速導入してみた。ので、本稿はその記録です。一般的な論文の探し方や読み方などの詳細は上のpodcastをお聞きください。

github.com

brewで超簡単にインストールできたので特に説明することもない。PDFを検索するのにpopplerというのも必要だったのでそれも合わせてインストールした。

$ brew install rga
$ brew install poppler

論文ディレクトリを対象に適当にcollective behaviorという文字列を含む論文を探してみた。

f:id:dxsato:20200519160438p:plain

速い。

さらにfzf (fuzzy-finder)と組み合わせると、より効率的に探せる。

# fzfのインストール
$ git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
$ ~/.fzf/install

# rgaと組み合わせる
$ rga "collective behavior" ~/Dropbox/研究室/論文/2020.5/*.pdf | fzf

f:id:dxsato:20200519160257p:plain

というかfuzzy-finder便利だなこれ。ripgrep-allよりも、こっちの方が気になってきた。上の作業だけならspotlightとそこまで変わらない気がするので、もう少しここら辺の使い方を洗練させたい。

Juliaのファイル操作

書き込み

#書き込み(上書き)
julia> iow = open("text.txt","w")
julia> write(iow,"Hello world")
julia> close(iow)

#書き込み(追記)
julia> ioa = open("text.txt","a")
julia> write(ioa,"Append world")
julia> close(ioa)

doブロックを使えば自動的に閉じられるのでcloseは必要ない.

open("mytext.txt","w") do iow
  write(iow,"Hello world")
end

読み込み

doブロックの外側で宣言した変数を改変したいときは、globalスコープを使う必要がある.

julia> val = "aa"
"aa"
julia> val2 = "aa"
"aa"

julia> open("test.txt","r") do ior
         text = read(ior,String)
         text = replace(text,"\n" => "") #改行コードの除去
         global val = text
         val2 = text
       end
"Hello worldAppend world"

julia> println(val)
Hello worldAppend world

julia> println(val2)
aa

readlines関数

各行を文字列の配列にして返す.

julia> open("test.txt","r") do ior
           lines = readlines(ior)
           println(lines)
       end
["Hello world", "Append world"]

keepオプションをtrueにすると改行コードは保たれる.

julia> open("test.txt","r") do ior
           lines = readlines(ior,keep=true)
           println(lines)
       end
["Hello world\n", "Append world"]

eachline関数

ファイルを指定するだけ.

julia> for line in eachline("test.txt")
           println(line)
       end
Hello world
Append world

パス取得

pwd()homedir()がある.

julia> pwd()
"/Users/dxsato/Desktop/Julia/"

julia> homedir()
"/Users/dxsato"

ディレクトリ操作

mkdir()で新たなディレクトリを作成可能.

julia> mkdir("test")

readdir()ディレクトリの中身を取得.

julia> readdir("test")
0-element Array{String,1}

mkdir()は存在しないディレクトリの内側にさらに新たなディレクトリを作成することはできないが、mkpath()なら一気に作成可能.

mkpath("dir1/dir1_1")

cd()で移動可能.

julia> cd("test")

forwalkdir()を合わせると再帰的なディレクトリ情報の取得が可能.

julia> for (path, arr_dir, arr_file) in walkdir(pwd())
               println(path)
               [println(dir) for dir in arr_dir]
               [println(file) for file in arr_file]
       end
/Users/dxsato/Desktop/Julia/test/
dir1
test
dummy_SNPs.txt
dummy_microarray.txt
test.txt
text.txt
問題.pdf
/Users/dxsato/Desktop/Julia/test/dir1
dir1_1
/Users/dxsato/Desktop/Julia/test/dir1/dir1_1
/Users/dxsato/Desktop/Julia/test/test

filesize():ファイルサイズの取得.

basename():ベース名の取得.

dirname()ディレクトリ名の取得.

joinpath():パスの連結.

cp():コピー. force=trueを指定すると、コピー先を削除してからコピーできる.

mv():ファイルの移動.

rm():ファイルの削除.recursive=trueを指定するとディレクトリの中身も全て削除できる.

JuliaからRを使う

やはりggplotを使いたいという時がある.

]でパッケージモードに入り, addで追加.

(v1.4) pkg> add RCall
julia> using RCall, Distributions, Random, DataFrames

julia> Random.seed!(0)
MersenneTwister(UInt32[0x00000000], Random.DSFMT.DSFMT_state(Int32[748398797, 1073523691, -1738140313, 1073664641, -1492392947, 1073490074, -1625281839, 1073254801, 1875112882, 1073717145943540191, 1073626624, 1091647724, 1073372234, -1273625233, -823628301, 835224507, 991807863, 382, 0]), [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.00.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], UInt128[0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x000000000000000000000000000000000x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000, 0x00000000000000000000000000000000], 1002, 0)

julia> dat = rand(MvNormal([1 0.75; 0.75 1]), 1000)
2×1000 Array{Float64,2}:
 0.679107  -0.353007  0.586617   0.0649475  -0.51421   -0.688907  0.397482  -0.3463550.791341  -0.52823  -1.01701    0.300868  0.398911  0.831824  1.75993  -0.342151 
 1.05727   -0.353953  0.636632  -0.0233976   0.655664  -1.02123   0.834954  -0.383834     0.296767  -1.07364  -0.963753  -0.160464  0.109914  2.31958   1.47322   0.0729502

julia> df = DataFrame(permutedims(dat))

R""で内容を囲むと、R内で実行できる

julia> R"1+1"
RObject{RealSxp}
[1] 2

$を打つとRモードに入れる (なぜかこの機能はstartup.jlusing RCallを入れてREPLを起動しても働かない)

R> install.packages("viridis")

Rのライブラリを読み込む.

julia> @rlibrary ggplot2
julia> @rlibrary viridis

ggplotでプロットする.

julia> ggplot(df,aes(x=:x1,y=:x2)) + geom_point()

RDatasetsを使えば、irisデータ等も使える.

julia> using RDatasets
julia> iris = dataset("datasets", "iris")

julia> ggplot(iris,aes(x=:SepalWidth,y=:PetalWidth,size=:SepalLength,col=:Species)) + 
        geom_point()

f:id:dxsato:20200427124535j:plain

julia> ggplot(iris,aes(x=:SepalWidth,y=:PetalWidth,col=:SepalLength,shape=:Species)) + 
       geom_point(size=3,alpha=.5) +
       scale_color_viridis(option = "A",direction=-1) +
       theme_minimal()

f:id:dxsato:20200427124605j:plain

Julia特有の構文メモ2

ライブラリ

Juliaの関数は大きく3つに分けられる.

  • コアベースの関数
  • 標準ライブラリの関数
  • 外部ライブラリの関数

コアベースの関数

Core.関数

Core.ifelse 判定文が真なら1つ目、偽なら2つ目の引数を返す.

julia> Core.ifelse('a' < 'A', 'a', 'A')
'A': ASCII/Unicode U+0041 (category Lu: Letter, uppercase)

julia> Core.ifelse(10/3==10÷3, "same", "not same")
"not same"

#juliaのif判定はboolean型しか受け付けない.
julia> Core.ifelse(1, "one", "not one")
ERROR: TypeError: non-boolean (Int64) used in boolean context
Stacktrace:
 [1] top-level scope at REPL[4]:1

Core.applicable 引数が関数に適用可能か判定する.

julia> myfunc(a::Int64,b::Int64)=a*b
myfunc (generic function with 1 method)

#引数が一つだけでもダメ
julia> applicable(myfunc,2)
false

#片方がFloatでもダメ
julia> applicable(myfunc,2,2.5)
false

#2つが両方IntならOK
julia> applicable(myfunc,2,2)
true

Core.tuple タプルを作成する(関数がTupleではなくtuple).

julia> stationery=tuple("Pencil","Eraser","Ruler")
("Pencil", "Eraser", "Ruler")

julia> typeof(stationery)
Tuple{String,String,String}

参照渡しについて. 変数の代入は=で普通に値を渡すだけ. bの値を更新してもaは影響を受けない. 値が格納される参照先(アドレス)が別々だから.

julia> a = 2
2

julia> b = a
2

julia> b = 3
3

julia> a
2

一方でコレクションは参照渡しなので、 代入した後で更新すると、元のも更新される.

julia> arr_a = [1,2,3]
3-element Array{Int64,1}:
 1
 2
 3

julia> arr_b = arr_a
3-element Array{Int64,1}:
 1
 2
 3

julia> arr_b[2]=20
20

julia> arr_a
3-element Array{Int64,1}:
  1
 20
  3

Base.関数

Base.copy 浅いコピーcopyと深いコピーdeepcopyがある. 参照渡しでないコピーなので、値を更新しても互いに影響しない.

julia> ary_a = [1,2,3]
3-element Array{Int64,1}:
 1
 2
 3

julia> ary_cp = copy(ary_a)
3-element Array{Int64,1}:
 1
 2
 3
julia> ary_dpcp = deepcopy(ary_a)
3-element Array{Int64,1}:
 1
 2
 3

julia> ary_a[2] = 20
20

julia> ary_cp
3-element Array{Int64,1}:
 1
 2
 3

julia> ary_dpcp
3-element Array{Int64,1}:
 1
 2
 3

Base.pointer 配列や文字列のアドレスを出力する.

julia> pointer(ary_a)
Ptr{Int64} @0x0000000109e47a10

要素が配列になっている深い配列を考える. 浅いコピーではary_aの更新に伴って値が変わっている.

julia> ary_a = [[1,2,3],[4,5,6]]
2-element Array{Array{Int64,1},1}:
 [1, 2, 3]
 [4, 5, 6]

julia> ary_shallow = copy(ary_a)
2-element Array{Array{Int64,1},1}:
 [1, 2, 3]
 [4, 5, 6]

julia> ary_deep = deepcopy(ary_a)
2-element Array{Array{Int64,1},1}:
 [1, 2, 3]
 [4, 5, 6]

julia> ary_a[2][2] = 50
50

julia> ary_shallow
2-element Array{Array{Int64,1},1}:
 [1, 2, 3] 
 [4, 50, 6]

julia> ary_deep
2-element Array{Array{Int64,1},1}:
 [1, 2, 3]
 [4, 5, 6]

アドレスを見てみると、外枠は違うように見えるが、

julia> pointer(ary_a)
Ptr{Array{Int64,1}} @0x000000010a56d7f0

julia> pointer(ary_shallow)
Ptr{Array{Int64,1}} @0x0000000109b7b290

julia> pointer(ary_deep)
Ptr{Array{Int64,1}} @0x000000010a0a59d0

その要素は、浅いコピーでは元配列と同じ場所に格納されているらしい.

julia> pointer(ary_a[2])
Ptr{Int64} @0x00000001099c5a90

julia> pointer(ary_shallow[2])
Ptr{Int64} @0x00000001099c5a90

julia> pointer(ary_deep[2])
Ptr{Int64} @0x00000001099a2f90

Base.Core..の前を省略できるが、関数によって出来るものと出来ないものがある.

標準ライブラリの関数

Juliaインストール時からすでに用意されている関数. 使う際にはusingで関数名を宣言する必要がある.

Dates.関数

julia> Dates.now()
ERROR: UndefVarError: Dates not defined
Stacktrace:
 [1] top-level scope at REPL[43]:1

julia> using Dates

julia> Dates.now()
2019-10-25T20:51:38.306

Dates.を省略してもいい.

julia> now()
2019-10-25T20:54:06.016

now()関数はDateTime型、Data()関数はDate型を返す. year()関数は年を取得する. dayofweek()関数は曜日の値、dayname()関数は曜日の名前を返す.

julia> typeof(now())
DateTime

julia> Date(now())
2019-10-25

julia> year(now())
2019

julia> year(Date("2019-10-25"))
2019

julia> dayofweek(now())
5

julia> dayname(now())
"Friday"

Day()は日、Hour()は時間を取得する. それぞれDay型、Hour型.

julia> Day(now())
25 days

julia> Hour(now())
21 hours

足したり引いたり、計算もできる.

julia> Day(now() + Hour(3))
26 days

julia> Date("2019-10-25") + Day(1000)
2022-07-21

型が違う場合

#`==`は計算結果が同じならOK.
julia> Hour(1) == Minute(45) + Minute(15)
true

#`===`は型が同じでないとダメ.
julia> Hour(1) === Minute(45) + Minute(15)
false

外部ライブラリの関数

JSONを例に.

using JSON

#JSON形式にシリアライズするための辞書を用意する.
julia> stationery=Dict("Pencil"=>80,"Eraser"=>50,"Ruler"=>100)
Dict{String,Int64} with 3 entries:
  "Ruler"  => 100
  "Eraser" => 50
  "Pencil" => 80

julia> JSON.print(stationery)
{"Ruler":100,"Eraser":50,"Pencil":80}

#インデントの指定.4は4文字分ということ.
julia> JSON.print(stationery,4)
{
    "Ruler": 100,
    "Eraser": 50,
    "Pencil": 80
}

JSON形式にシリアライズした文字列の取得.

julia> stationery_json = JSON.json(stationery)
"{\"Ruler\":100,\"Eraser\":50,\"Pencil\":80}"

JSON形式のデータをパース.

julia> stationery_parse = JSON.parse(stationery_json)
Dict{String,Any} with 3 entries:
  "Ruler"  => 100
  "Eraser" => 50
  "Pencil" => 80

julia> println(stationery_parse)
Dict{String,Any}("Ruler" => 100,"Eraser" => 50,"Pencil" => 80)

#元々の辞書.
julia> println(stationery)
Dict("Ruler" => 100,"Eraser" => 50,"Pencil" => 80)

Julia特有の構文メモ

Symbol

Symbol("test") #のように使う

文字列を表すが、Symbolは常に同じオブジェクトであることが保証されるため、メモリ効率がいい. DataFrameのラベル名などに使われる.

ショートカット構文

条件 || 実行文 #左辺が偽のときだけ実行される
条件 && 実行文 #左辺が真のときだけ実行される

コメントアウト

#==#で囲うと複数行のコメントアウト.

レンジ

for i in 1:10 #1と10は生成される列に含まれる
  println("$i")
end

collect(10:-2:1) #ステップサイズは3組にして真ん中で指定
10
8
6
4
2

文字と文字列

julia> 'a' #chracter
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)

julia> "a" #string
"a"

julia> 'ab' #文字列(string)になっているのでエラーになる
ERROR: syntax: invalid character literal
Stacktrace:
 [1] top-level scope at REPL[26]:0

julia> "ab" #こちらは大丈夫
"ab"

julia> abcdef = "abcdef"
"abcdef"

julia> abcdef[2] #インデックス指定もできる(1オリジン)
'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)

julia> abcdef[3:end]
"cdef"

julia> abcdef[3:end-1]
"cde"

julia> abcdef[:4]
'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase)

julia> ghijk = "ghijk"
"ghijk"

julia> abcdef * ghijk #文字列の結合
"abcdefghijk"

julia> string(abcdef,ghijk) #これでもOK
"abcdefghijk"

julia> println(abcdef)
abcdef

julia> println("$abcdef") #文字列内での展開
abcdef

julia> println("$abcdef","$ghijk")
abcdefghijk

julia> println("1+2=$(1+2)") #カッコでくくると計算も展開できる
1+2=3

julia> raw"1+2=$(1+2)" #rawをつけるとraw文字列になる
"1+2=\$(1+2)"

if文

julia> x=3; y=5;

julia> if x < y
           println("$x is smaller than $y")
       end
3 is smaller than 5

julia> if x < y < 4 #3つ以上の項目を書ける
           println("$x < $y < 4 です")
       else
           println("$x < $y < 4 ではありません")
       end
3 < 5 < 4 ではありません

julia> if x < y < 4
           res_str = "$x < $y < 4 です"
       end

#ifブロック内のみの変数は、ifブロック内で使われなかった場合はエラーになる
julia> println(res_str)
ERROR: UndefVarError: res_str not defined
Stacktrace:
 [1] top-level scope at REPL[5]:1
 
 julia> if x < y < 4
           res_str = "$x < $y < 4 です"
       else
           res_str = "$x < $y < 4 ではありません"
       end
"3 < 5 < 4 ではありません"

#elseの中で使われているのでエラーにならない
julia> println(res_str)
3 < 5 < 4 ではありません

julia> x = 1; ifelse(x > 1, x + 1, x + 2) #trueだったら左、falseだったら右を返す
3

3項演算子

r = 5 > 3 ? 5 : 3 #?の左の式が真だったら:の左を出力、偽だったら右を出力
5

#こんなこともできる
julia> println(5 > 3 ? "5は3より大きい" : "5は3より大きくない")
53より大きい

#if-elseif-elseみたいにできる
julia> println(5 > 3 ? 5==3 ? "5は3に等しい" : "5は3より大きい" : "5は3より大きくない")
53より大きい

#関数の定義にも使える($aの後ろにはスペースが必要、エスケープもできなさそう)
julia> is_morethan(a,b) = println(a > b ? "$a$b より大きい" : "$a$b より大きくない")
is_morethan (generic function with 1 method)

julia> is_morethan(10,50)
1050 より大きくない

while文

julia> i = 1
1

#v1.0以降ではグローバルスコープの変数を書き換える場合はglobalを入れないとエラーになる
julia> while i <= 3
           println(i)
           i += 1
       end
ERROR: UndefVarError: i not defined
Stacktrace:
 [1] top-level scope at ./REPL[25]:2

#こうするとうまくいく
julia> while i <= 3
           println(i)
           global i += 1
       end
1
2
3

for文

julia> for j = 1:3 #:でもいい
           println(j)
       end
1
2
3

julia> for j in 1:3 #inでもいい
           println(j)
       end
1
2
3

julia> for j in [1,2,3] #配列を参照してもいい
           println(j)
       end
1
2
3

julia> for j in "123" #文字列を参照してもいい
           println(j)
       end
1
2
3

julia> for i = 1:2, j in "abc" #多重ループも1行で書ける
           println(i,j)
       end
1a
1b
1c
2a
2b
2c

julia> arr = [x for x = 1:3] #内包表記
3-element Array{Int64,1}:
 1
 2
 3
 
julia> [(i,j) for i = 1:2, j in "abc"] #複数要素をtupleに入れながら、2次元配列を返す
2×3 Array{Tuple{Int64,Char},2}:
 (1, 'a')  (1, 'b')  (1, 'c')
 (2, 'a')  (2, 'b')  (2, 'c')

julia> println([i for i in 1:200 if i % 16 == 0]) #if文を入れることもできる
[16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192]

julia> [3x + 5y for x = 1:3, y = 5:7] #こんなことも
3×3 Array{Int64,2}:
 28  33  38
 31  36  41
 34  39  44

配列

#Array{T,N}(undef,dims)と書く

#Int64型 2次元 1次元の要素数3,2次元の要素数3
#数字は勝手に適当なものが入る
julia> arrtwoint1 = Array{Int64,2}(undef,3,3)
3×3 Array{Int64,2}:
 4592616224  4592617456  4592618576
 4592616224  4592618576  4415784480
 4413668112  4592617456  4592618576

julia> arrtwoint1 = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
 1  2  3
 4  5  6
 7  8  9

julia> arrtwoint1[2,2] #[2][2]ではない
5

julia> arrtwoint1[2,3] #2行目3列
6

julia> arrtwoint1[1:3] #1:3行目1列
3-element Array{Int64,1}:
 1
 4
 7

julia> arrtwoint1[1:3,2] #1:3行目2列
3-element Array{Int64,1}:
 2
 5
 8

julia> arrtwoint1[2,1:3] #2行目1:3列
3-element Array{Int64,1}:
 4
 5
 6

julia> [[1,2,3],[4,5,6]] #これは2次元ではなく1次元配列なので注意
2-element Array{Array{Int64,1},1}:
 [1, 2, 3]
 [4, 5, 6]

julia> [1 2 3; 4 5 6] #正しくはこう書く(行列)
2×3 Array{Int64,2}:
 1  2  3
 4  5  6

文字列を配列にする.

julia> li = split(str, ",")

配列はカンマ区切り

julia> an = [1,2,3]
3-element Array{Int64,1}:
 1
 2
 3

julia> push!(an,4) #要素を追加
4-element Array{Int64,1}:
 1
 2
 3
 4

julia> pop!(an) #最後の要素を削除
4

julia> an
3-element Array{Int64,1}:
 1
 2
 3

行列はスペース区切り

julia> an = [1 2 3]
1×3 Array{Int64,2}:
 1  2  3

julia> an = [[1,2,3] [4,5,6] [7,8,9]] #要素の値に配列を入れれば2次元の行列になる
3×3 Array{Int64,2}:
 1  4  7
 2  5  8
 3  6  9

julia> an = [1 2 3; 4 5 6; 7 8 9] #こちらも行列. しかし格納の順番(方向)が異なる
3×3 Array{Int64,2}:
 1  2  3
 4  5  6
 7  8  9

#つまりJuliaではPythonのNumPyの機能が標準装備されている
julia> ([1,2,3] == [1 2 3], [1,2,3] == [1; 2; 3])
(false, true)

julia> (reshape([1,2,3,4,5,6],2,3) == [1 3 5; 2 4 6])
true

#行列の回転
julia> mtr = reshape([i for i in 1:16],4,4)
4×4 Array{Int64,2}:
 1  5   9  13
 2  6  10  14
 3  7  11  15
 4  8  12  16

julia> rot180(mtr) #180度回す
4×4 Array{Int64,2}:
 16  12  8  4
 15  11  7  3
 14  10  6  2
 13   9  5  1

julia> rotl90(mtr) #90度左(left)に回すrotl90関数. 右に回すrotr90もある
4×4 Array{Int64,2}:
 13  14  15  16
  9  10  11  12
  5   6   7   8
  1   2   3   4

julia> rotl90(mtr,3) #回転数の指定もできる
4×4 Array{Int64,2}:
  4   3   2   1
  8   7   6   5
 12  11  10   9
 16  15  14  13

#応用
julia> reshape([i for i in 1:64 if i % 4 ==0],4,4)
4×4 Array{Int64,2}:
  4  20  36  52
  8  24  40  56
 12  28  44  60
 16  32  48  64

辞書(Dict)型

Dict(:a => 1, :b => 2)

辞書型. Dict()関数で作成する. Pairと呼ばれる=>で区切られる構造を引数として与えることで、リテラルっぽく書くことができる.

dict = Dict{Int64,Int64}()
dict = Dict{Int64,Dict}() #valueを辞書型にすることもできる(これで2次元ハッシュみたいな).

初期宣言.

julia> Dict("a" => 1, "b" => 2)
Dict{String,Int64} with 2 entries:
  "b" => 2
  "a" => 1

julia> dict_test = Dict([("a",1),("b",2)]) #Tuple型の配列を入れてもいい
Dict{String,Int64} with 2 entries:
  "b" => 2
  "a" => 1

キーはStr,Int,Floatでもいいが、定義した型から外れる他の型は代入できない.

dict_test["a"] = "20"
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int64
Closest candidates are:
  convert(::Type{T<:Number}, ::T<:Number) where T<:Number at number.jl:6
  convert(::Type{T<:Number}, ::Number) where T<:Number at number.jl:7
  convert(::Type{T<:Integer}, ::Ptr) where T<:Integer at pointer.jl:23
  ...
Stacktrace:
 [1] setindex!(::Dict{String,Int64}, ::String, ::String) at ./dict.jl:380
 [2] top-level scope at REPL[76]:1
julia> dict_test["a"] = 20
20

forループでキーと値を取得 そのまま受けるとPair型のオブジェクト

julia> for item in dict_test
           println(item)
       end
"b" => 2
"a" => 20

(key, value)形式で受ける

julia> for(name,price) in dict_test
           println("$name : $price")
       end
b : 2
a : 20

特定の要素の有無を確認

julia> haskey(dict_test,"aa")
false

julia> haskey(dict_test,"a")
true

値を取得する: get(collection,key,default)

julia> get(dict_test,"a",120) #default(120の部分)はオプショナルでなく必須.
20

キーのイテレータ: keys(iterator)

julia> keys(dict_test)
Base.KeySet for a Dict{String,Int64} with 2 entries. Keys:
  "b"
  "a"

値のイテレータ: values(iterator)

julia> values(dict_test)
Base.ValueIterator for a Dict{String,Int64} with 2 entries. Values:
  2
  20

要素の削除: delete! (要素削除後の辞書を返す)

julia> res = delete!(dict_test,"b")
Dict{String,Int64} with 1 entry:
  "a" => 20

要素の削除: pop! (削除された要素の値を返す)

julia> dict_test["b"] = 4
4

julia> res = pop!(dict_test,"b")
4

二つの辞書をmergeする(後ろ優先になる)

julia> dict_test
Dict{String,Int64} with 3 entries:
  "c" => 10
  "b" => 4
  "a" => 20

julia> dict_test2
Dict{String,Int64} with 2 entries:
  "b" => 200
  "a" => 100

julia> println(merge(dict_test,dict_test2))
Dict("c" => 10,"b" => 200,"a" => 100)

julia> println(merge(dict_test2,dict_test))
Dict("c" => 10,"b" => 4,"a" => 20)

タプル(Tuple)型

配列や辞書型と同じく複数の値を入れておくことができるコレクションの一つだが、後から内容の変更ができない(イミュータブルと言う).

a = tuple("a","b","c")
a = ("a","b","c") #単に括弧でもいい

julia> typeof(a)
Tuple{String,String,String}

インデックス指定で値を取得できる

julia> a[1]
"a"

名前つきタプル(NamedTuple)

julia> test_tuple = (a = 1, b = 2, c = 3)
(a = 1, b = 2, c = 3)

julia> test_tuple.a #こういう指定ができる
1

julia> test_tuple[3] #もちろんインデックス指定もできる
3

ペア(Pair)型

辞書型の要素となる A => B . 値の更新はできない.

julia> item = "Pencil" => 80
"Pencil" => 80

julia> item.first #firstで最初の要素
"Pencil"

julia> item.second #secondで2番目の要素を指定できる
80

Dict()のなかにTuple型の配列を入れる場合でも、要素はPair型となる.

julia> stationary = Dict([("Pencil",80),("Eraser",50),("Ruler",100)])
Dict{String,Int64} with 3 entries:
  "Ruler"  => 100
  "Eraser" => 50
  "Pencil" => 80

julia> for item in stationary
           println("$(item.first) : $(item.second)")
       end
Ruler : 100
Eraser : 50
Pencil : 80

集合(Set)型

重複した要素を持たない. 順序がない. 和/積/差/対称差/部分集合/上位集合といった集合演算が使える.

julia> Set([3,1,2,3]) #重複した3は消える.
Set([2, 3, 1]) #順番も適当.

配列も入れられる.

julia> [3x+5y for x = 1:3,y=3:4]
3×2 Array{Int64,2}:
 18  23
 21  26
 24  29

julia> Set([3x+5y for x = 1:3,y=3:4])
Set([24, 23, 26, 29, 21, 18])

pushやpopも使える (順番はない).

julia> set_even = Set([2i for i in 1:3])
Set([4, 2, 6])

julia> push!(set_even,8)
Set([4, 2, 8, 6])

julia> pop!(set_even)
4

julia> set_even
Set([2, 8, 6])

存在確認 (in関数あるいは∈(\inをtab変換)や∋(\ni))

julia> in(6,set_even)
true

julia> in(5,set_even)
false

julia> 6 ∈ set_even
true

julia> set_even ∋ 9
false

和演算

julia> set_a = Set([1,2,3])
Set([2, 3, 1])

julia> set_b = Set([3,4,5])
Set([4, 3, 5])

julia> union(set_a,set_b)
Set([4, 2, 3, 5, 1])

julia> set_a ∪ set_b #\cupをtab変換
Set([4, 2, 3, 5, 1])

julia> set_a = Set([1,3,4])
Set([4, 3, 1])

julia> set_b = Set([2,3,4,5])
Set([4, 2, 3, 5])

julia> intersect(set_a,set_b)
Set([4, 3])

julia> set_a ∩ set_b #\capをtab変換
Set([4, 3])

#左辺のみに含まれる項を抽出
julia> setdiff(set_a,set_b)
Set([1])

julia> setdiff(set_b,set_a)
Set([2, 5])

#どちらかのみに含まれる項を抽出(対称差)
julia> symdiff(set_b,set_a)
Set([2, 5, 1])

部分集合 (右辺に左辺の値の全てが含まれているかの判定)

julia> set_a = Set([1,2,3])
Set([2, 3, 1])

julia> set_b = Set([1,3])
Set([3, 1])

julia> issubset(set_a,set_b)
false

julia> set_a ⊆ set_b #\subseteqをtab変換
false

julia> set_b ⊆ set_a
true

上位集合 (左辺に右辺の値の全てが含まれているかの判定)

julia> set_a ⊇ set_b #\supseteqをtab変換
true

関数

julia> function myfunc(a,b)
           return a*b
       end
myfunc (generic function with 1 method)

julia> myfunc(4,100)
400

#"return"がなくてもいい.
julia> function myfunc(a,b)
           a*b
           a/b #この場合は最後の式が返される.
       end
myfunc (generic function with 1 method)

julia> myfunc(3,2)
1.5

#簡単な書き方もできる.
julia> f(a,b)=a*b
f (generic function with 1 method)

julia> f(3,2)
6

default値(代入がなかった場合にそれを使う)を設定できる.

julia> f(a,b=5)=a*b
f (generic function with 2 methods)

julia> f(3,2)
6

julia> f(3)
15

引数を可変にする.

julia> function mf(a, b, v...)
           println(a)
           println(b)
           println(v)
       end
mf (generic function with 1 method)

julia> mf(3,2)
3
2
()

julia> mf(3,2,5,6,7)
3
2
(5, 6, 7)

キーワード引数の指定

julia> function mf(a, b ; item = "Pencil", price = 80)
           println("$a, $b, $item, $price")
       end
mf (generic function with 2 methods)

julia> mf(3,2,item="Note",price=50)
3, 2, Note, 50

引数の型指定

julia> af(a,b::Int64) = a*b
af (generic function with 1 method)

julia> af(2,3)
6

julia> af(2,3.5) #Float型を渡したのでエラーになる.
ERROR: MethodError: no method matching af(::Int64, ::Float64)
Closest candidates are:
  af(::Any, ::Int64) at REPL[55]:1
Stacktrace:
 [1] top-level scope at REPL[57]:1

戻り値の型指定

julia> af(a,b)::Int64 = a*b
af (generic function with 2 methods)

julia> af(2,3)
6

julia> af(2,3.5)
7

julia> af(2.5,3.5)
ERROR: InexactError: Int64(8.75)
Stacktrace:
 [1] Type at ./float.jl:703 [inlined]
 [2] convert at ./number.jl:7 [inlined]
 [3] af(::Float64, ::Float64) at ./REPL[58]:1
 [4] top-level scope at REPL[61]:1

複数の戻り値

julia> function myfunc(a,b)
           return a*b, a/b, 2a+3b
       end
myfunc (generic function with 1 method)

julia> myfunc(3,2)
(6, 1.5, 12)

受け取る側もカンマ区切りにするとタプルがアンパックされる.

julia> res_1, res_2, res_3 = myfunc(3,2)
(6, 1.5, 12)

julia> println("$res_1 : $res_2 : $res_3")
6 : 1.5 : 12

タプルで返すのであれば、インデックス指定もできる.

julia> myfunc(3,2)[2]
1.5

無名関数

julia> a -> a^3 + a*3
#10 (generic function with 1 method)

map関数と一緒に使う. もちろん普通に定義した関数も使えるが、簡単な式の場合は無名関数で十分.

#配列を渡す.
julia> map(a -> a^3 + a*3, [4, 2.5, -3])
3-element Array{Float64,1}:
  76.0  
  23.125
 -36.0

#タプルを渡す.
julia> map(a -> a^3 + a*3, (4, 2.5, -3))
(76, 23.125, -36)

無名関数を変数に格納することもできる.

julia> lambda = a -> a^3 + a*3
#18 (generic function with 1 method)

julia> map(lambda, (4, 2.5, -3))
(76, 23.125, -36)

多重ディスパッチ 複数のメソッドを同じ関数に入れることができる.

julia> function mf_dis(a::Int64)
           return a^3+a*3
       end
mf_dis (generic function with 1 method)

julia> function mf_dis(a::String)
           println("Argument : $a")
       end
mf_dis (generic function with 2 methods)

julia> function mf_dis(a,b)
           return a*b
       end
mf_dis (generic function with 3 methods)

渡す引数によってどれを実行するか選択できる.

julia> mf_dis(2)
14

julia> mf_dis("test")
Argument : test

julia> mf_dis(2,4)
8

構造体

イミュータブル(更新不可)のstuructと ミュータブル(更新課)のmutable structがある.

julia> struct Kitchenware
           item
           price::Int64
           stock
       end

インスタンスを作成する.

julia> Kitchenware1 = Kitchenware("Bowl",100,10)
Kitchenware("Bowl", 100, 10)

型は構造体名になる.

julia> typeof(Kitchenware1)
Kitchenware

メンバの型が宣言と合わないとエラーになる.

julia> Kitchenware2 = Kitchenware("Ladle",150.2,5)
ERROR: InexactError: Int64(150.2)
Stacktrace:
 [1] Type at ./float.jl:703 [inlined]
 [2] convert at ./number.jl:7 [inlined]
 [3] Kitchenware(::String, ::Float64, ::Int64) at ./REPL[82]:2
 [4] top-level scope at REPL[85]:1

値の参照は.メンバ名でする.

julia> Kitchenware1.item
"Bowl"

mutable struct

julia> mutable struct Tableware
           item::String
           price::Int64
           stock::Int64
       end

julia> tableware1 = Tableware("Cup",120,30)
Tableware("Cup", 120, 30)

julia> tableware1.item
"Cup"

julia> tableware1.price
120

値の更新ができる.

julia> tableware1.stock = 29
29

構造体の配列を作成する.

julia> arr_kitchenware = Array{Kitchenware}(undef,3)
3-element Array{Kitchenware,1}:
 #undef
 #undef
 #undef
julia> arr_kitchenware[1] = Kitchenware("Bowl",100,10)
Kitchenware("Bowl", 100, 10)

julia> arr_kitchenware[2] = Kitchenware("Ladle",150,5)
Kitchenware("Ladle", 150, 5)

julia> arr_kitchenware[3] = Kitchenware("Flying pan",3500,6)
Kitchenware("Flying pan", 3500, 6)

julia> arr_kitchenware[3].item
"Flying pan"

宣言した要素数以上入れようとするとエラーになる.

julia> arr_kitchenware[4] = Kitchenware("Kettle",1000,3)
ERROR: BoundsError: attempt to access 3-element Array{Kitchenware,1} at index [4]
Stacktrace:
 [1] setindex!(::Array{Kitchenware,1}, ::Kitchenware, ::Int64) at ./array.jl:766
 [2] top-level scope at REPL[97]:1

push!関数なら要素の追加ができる.

julia> push!(arr_kitchenware, Kitchenware("Kettle",1000,3))
4-element Array{Kitchenware,1}:
 Kitchenware("Bowl", 100, 10)      
 Kitchenware("Ladle", 150, 5)      
 Kitchenware("Flying pan", 3500, 6)
 Kitchenware("Kettle", 1000, 3) 

簡単な形式.

julia> mutable struct Tableware
           item::String
           price::Float64
           stock::Int64
       end

julia> arr_tableware = [Tableware("Cup",108.5,30),Tableware("Spoon",210.1,50),Tableware("Dish",1041.3,10)]
3-element Array{Tableware,1}:
 Tableware("Cup", 108.5, 30)  
 Tableware("Spoon", 210.1, 50)
 Tableware("Dish", 1041.3, 10)