ruby-igv 0.0.4 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +75 -13
- data/lib/igv/version.rb +3 -1
- data/lib/igv.rb +248 -54
- metadata +20 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ca8294136b5eab8a344a40bf1d5ebb6d8ebf08f2794a1c6e1f582f593432049
|
4
|
+
data.tar.gz: c36d4c09a163ade8bfd860519a50519a28ae3f93121a14c482bf1bceb6239cde
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a085655336dcd4d06db5b51269f6b72d8d7174767f0b2990796d29cd410fb90adc884b86df3cf97087e75b35d387f655ed557628145c3af9badf17d3b29c50e
|
7
|
+
data.tar.gz: d8e0741301b1504f7714077ef435a987b51c520fcc3788f85acaf42ad3785fcec7bf435e897666a5f9a16050d2f503cfab5daa68525a1fc86a18b5219018a6ed
|
data/README.md
CHANGED
@@ -1,34 +1,86 @@
|
|
1
|
-
#
|
1
|
+
# ruby-igv
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/ruby-igv)
|
4
4
|
[](https://rubydoc.info/gems/ruby-igv)
|
5
5
|
[](LICENSE.txt)
|
6
|
+
[](https://zenodo.org/badge/latestdoi/281373245)
|
6
7
|
|
7
|
-
Using [Integrative Genomics Viewer (IGV)](http://software.broadinstitute.org/software/igv/) with the Ruby language.
|
8
8
|
|
9
|
-
|
9
|
+
<img src="https://user-images.githubusercontent.com/5798442/182540876-c3ca2906-7d05-4c93-9107-ce4135ae9765.png" align="right">
|
10
10
|
|
11
11
|
## Installation
|
12
12
|
|
13
|
+
Requirement :
|
14
|
+
|
15
|
+
* [Ruby](https://github.com/ruby/ruby)
|
16
|
+
* [IGV (Integrative Genomics Viewer)](http://software.broadinstitute.org/software/igv/)
|
17
|
+
* [Enable IGV to listen on the port](https://software.broadinstitute.org/software/igv/Preferences#Advanced)
|
18
|
+
* View > Preference > Advanced > Enable port ☑
|
19
|
+
|
13
20
|
```ruby
|
14
21
|
gem install ruby-igv
|
15
22
|
```
|
16
23
|
|
24
|
+
## Quickstart
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require 'igv'
|
28
|
+
|
29
|
+
igv = IGV.start # This launch IGV
|
30
|
+
igv.genome 'hg19'
|
31
|
+
igv.load 'http://hgdownload.cse.ucsc.edu/goldenPath/hg19/encodeDCC/' \
|
32
|
+
'wgEncodeUwRepliSeq/wgEncodeUwRepliSeqK562G1AlnRep1.bam'
|
33
|
+
igv.go 'chr18:78,016,233-78,016,640'
|
34
|
+
igv.snapshot 'region.png'
|
35
|
+
igv.exit
|
36
|
+
```
|
37
|
+
|
17
38
|
## Usage
|
18
39
|
|
40
|
+
### docs
|
41
|
+
|
42
|
+
See [the list of Batch commands](https://github.com/igvteam/igv/wiki/Batch-commands).
|
43
|
+
|
19
44
|
```ruby
|
20
|
-
igv
|
21
|
-
igv.genome 'hg19'
|
22
|
-
igv.load 'http://hgdownload.cse.ucsc.edu/goldenPath/hg19/encodeDCC/wgEncodeUwRepliSeq/wgEncodeUwRepliSeqK562G1AlnRep1.bam'
|
23
|
-
igv.go 'chr18:78,016,233-78,016,640'
|
24
|
-
igv.save '/tmp/r/region.svg'
|
25
|
-
igv.save '/tmp/r/region.png'
|
26
|
-
igv.snapshot_dir = '/tmp/r2/'
|
27
|
-
igv.save 'region.jpg' # save to /tmp/r2/region.png
|
28
|
-
igv.send 'echo' # whatever you want
|
45
|
+
igv.commands # Show the IGV command reference in your browser
|
29
46
|
```
|
30
47
|
|
31
|
-
|
48
|
+
[docs](https://rubydoc.info/gems/ruby-igv)
|
49
|
+
|
50
|
+
### send
|
51
|
+
|
52
|
+
Not all commands are implemented in Ruby. Commands that are not implemented can be sent using the send method.
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
igv.send("maxPanelHeight", 10)
|
56
|
+
```
|
57
|
+
|
58
|
+
|
59
|
+
### Launch IGV
|
60
|
+
|
61
|
+
Launch IGV from Ruby scripot.
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
igv = IGV.start # launch IGV app using spawn
|
65
|
+
```
|
66
|
+
|
67
|
+
### Open socket connection to IGV
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
igv = IGV.new # create an IGV object. Then you will type `igv.connect`
|
71
|
+
igv = IGV.open # create an IGV object and connect it to an already activated IGV.
|
72
|
+
```
|
73
|
+
|
74
|
+
### Close IGV
|
75
|
+
|
76
|
+
The behavior of the following methods is different.
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
igv.close # close the socket connection
|
80
|
+
igv.exit # send exit command to IGV
|
81
|
+
igv.quit # alias method to exit
|
82
|
+
igv.kill # kill group pid created with IGV.start
|
83
|
+
```
|
32
84
|
|
33
85
|
## Contributing
|
34
86
|
|
@@ -37,6 +89,16 @@ igv.send 'echo' # whatever you want
|
|
37
89
|
* Write, clarify, or fix documentation
|
38
90
|
* Suggest or add new features
|
39
91
|
|
92
|
+
```
|
93
|
+
Do you need commit rights to my repository?
|
94
|
+
Do you want to get admin rights and take over the project?
|
95
|
+
If so, please feel free to contact me @kojix2.
|
96
|
+
```
|
97
|
+
|
98
|
+
## Acknowledgement
|
99
|
+
This gem is strongly inspired by a Python script developed by Brent Pedersen.
|
100
|
+
* [brentp/bio-playground/igv](https://github.com/brentp/bio-playground).
|
101
|
+
|
40
102
|
## License
|
41
103
|
|
42
104
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/lib/igv/version.rb
CHANGED
data/lib/igv.rb
CHANGED
@@ -1,106 +1,300 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'igv/version'
|
2
4
|
require 'socket'
|
3
5
|
require 'fileutils'
|
4
6
|
|
7
|
+
# The Integrative Genomics Viewer (IGV)
|
8
|
+
# https://software.broadinstitute.org/software/igv/
|
5
9
|
class IGV
|
6
10
|
class Error < StandardError; end
|
7
11
|
|
8
|
-
attr_reader :host, :port, :
|
12
|
+
attr_reader :host, :port, :history
|
13
|
+
|
9
14
|
def initialize(host: '127.0.0.1', port: 60_151, snapshot_dir: Dir.pwd)
|
10
15
|
@host = host
|
11
16
|
@port = port
|
17
|
+
@snapshot_dir = File.expand_path(snapshot_dir)
|
12
18
|
@history = []
|
13
|
-
connect
|
14
|
-
set_snapshot_dir(snapshot_dir)
|
15
19
|
end
|
16
20
|
|
17
|
-
|
18
|
-
|
21
|
+
def self.open(host: '127.0.0.1', port: 60_151, snapshot_dir: Dir.pwd)
|
22
|
+
igv = new(host: host, port: port, snapshot_dir: snapshot_dir)
|
23
|
+
igv.connect
|
24
|
+
return igv unless block_given?
|
25
|
+
|
26
|
+
begin
|
27
|
+
yield igv
|
28
|
+
ensure
|
29
|
+
@socket&.close
|
30
|
+
end
|
31
|
+
igv
|
32
|
+
end
|
33
|
+
|
34
|
+
# Launch IGV from ruby script
|
35
|
+
|
36
|
+
def self.start(port: 60_151, command: 'igv')
|
37
|
+
r, w = IO.pipe
|
38
|
+
pid_igv = spawn(command, '-p', port.to_s, pgroup: true, out: w, err: w)
|
39
|
+
pgid_igv = Process.getpgid(pid_igv)
|
40
|
+
Process.detach(pid_igv)
|
41
|
+
puts "\e[33m"
|
42
|
+
while (line = r.gets.chomp("\n"))
|
43
|
+
puts line
|
44
|
+
break if line.include? "Listening on port #{port}"
|
45
|
+
end
|
46
|
+
puts "\e[0m"
|
47
|
+
igv = open(port: port)
|
48
|
+
igv.instance_variable_set(:@pgid_igv, pgid_igv)
|
49
|
+
igv
|
50
|
+
end
|
51
|
+
|
52
|
+
# Kill IGV process by process group id
|
53
|
+
|
54
|
+
def kill
|
55
|
+
if instance_variable_defined?(:@pgid_igv)
|
56
|
+
warn \
|
57
|
+
'This method kills the process with the group ID specified at startup. ' \
|
58
|
+
'Please use exit or quit if possible.'
|
59
|
+
else
|
60
|
+
warn \
|
61
|
+
'The kill method terminates only IGV commands invoked by the start method.' \
|
62
|
+
'Otherwise, use exit or quit.'
|
63
|
+
return
|
64
|
+
end
|
65
|
+
pgid = @pgid_igv
|
66
|
+
Process.kill(:TERM, -pgid)
|
67
|
+
close
|
68
|
+
end
|
69
|
+
|
70
|
+
# Connect to IGV server
|
71
|
+
|
72
|
+
def connect(host2 = @host, port2 = @port, connect_timeout: nil)
|
73
|
+
@socket&.close
|
74
|
+
@socket = Socket.tcp(host2, port2, connect_timeout: connect_timeout)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Close the socket.
|
78
|
+
# This method dose not exit IGV.
|
19
79
|
|
20
|
-
def
|
80
|
+
def close
|
21
81
|
@socket&.close
|
22
|
-
@socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
|
23
|
-
addr = Socket.sockaddr_in(port, host)
|
24
|
-
@socket.connect(addr)
|
25
82
|
end
|
26
83
|
|
27
|
-
def
|
28
|
-
|
84
|
+
def closed?
|
85
|
+
return true if @socket.nil?
|
86
|
+
|
87
|
+
@socket.closed?
|
29
88
|
end
|
30
|
-
|
89
|
+
|
90
|
+
# Send batch commands to IGV.
|
91
|
+
# @param [String] cmds
|
92
|
+
|
93
|
+
def send(*cmds)
|
94
|
+
cmd = \
|
95
|
+
cmds
|
96
|
+
.compact
|
97
|
+
.map do |cmd|
|
98
|
+
case cmd
|
99
|
+
when String, Symbol, Numeric then cmd.to_s
|
100
|
+
when ->(c) { c.respond_to?(:to_str) } then cmd.to_str
|
101
|
+
else raise ArgumentError, "#{cmd.inspect} is not a string"
|
102
|
+
end.strip.encode(Encoding::UTF_8)
|
103
|
+
end
|
104
|
+
.join(' ')
|
105
|
+
@history << cmd
|
106
|
+
@socket.puts(cmd)
|
107
|
+
@socket.gets&.chomp("\n")
|
108
|
+
end
|
109
|
+
|
110
|
+
# Show IGV batch commands in the browser.
|
111
|
+
# https://github.com/igvteam/igv/wiki/Batch-commands
|
112
|
+
|
113
|
+
def commands
|
114
|
+
require 'launchy'
|
115
|
+
Launchy.open('https://github.com/igvteam/igv/wiki/Batch-commands')
|
116
|
+
end
|
117
|
+
|
118
|
+
# Writes the value of "param" back to the response
|
119
|
+
#
|
120
|
+
# @param param [String] The parameter to echo.
|
121
|
+
# @return [String] The value of "param". If param is not specified, "echo".
|
122
|
+
|
123
|
+
def echo(param = nil)
|
124
|
+
send :echo, param
|
125
|
+
end
|
126
|
+
|
127
|
+
# Selects a genome by id, or loads a genome (or indexed fasta) from the supplied path.
|
128
|
+
#
|
129
|
+
# @param name_or_path [String] The genome to load
|
31
130
|
|
32
131
|
def genome(name_or_path)
|
33
132
|
path = File.expand_path(name_or_path)
|
34
133
|
if File.exist?(path)
|
35
|
-
send
|
134
|
+
send :genome, path
|
36
135
|
else
|
37
|
-
send
|
136
|
+
send :genome, name_or_path
|
38
137
|
end
|
39
138
|
end
|
40
139
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
140
|
+
# Loads a data or session file by specifying a full path to a local file or a URL.
|
141
|
+
#
|
142
|
+
# @param path_or_url [String] The path to a local file or a URL
|
143
|
+
# @param index [String] The index of the file
|
144
|
+
|
145
|
+
def load(path_or_url, index: nil)
|
146
|
+
path_or_url = if URI.parse(path_or_url).scheme
|
147
|
+
path_or_url
|
148
|
+
else
|
149
|
+
File.expand_path(path_or_url)
|
150
|
+
end
|
151
|
+
index = "index=#{index}" if index
|
152
|
+
send :load, path_or_url, index
|
47
153
|
end
|
48
154
|
|
49
|
-
|
50
|
-
|
155
|
+
# Go to the specified location
|
156
|
+
#
|
157
|
+
# @param location [String] The location to go to.
|
158
|
+
|
159
|
+
def goto(position)
|
160
|
+
send :goto, position
|
161
|
+
end
|
162
|
+
alias go goto
|
163
|
+
|
164
|
+
# Defines a region of interest bounded by the two loci
|
165
|
+
#
|
166
|
+
# @param chr [String] The chromosome of the region
|
167
|
+
# @param start [Integer] The start position of the region
|
168
|
+
# @param end_ [Integer] The end position of the region
|
169
|
+
|
170
|
+
def region(chr, start, end_)
|
171
|
+
send :region, chr, start, end_
|
51
172
|
end
|
52
173
|
|
53
174
|
def sort(option = 'base')
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
175
|
+
vop = %w[base position strand quality sample readGroup]
|
176
|
+
raise "options is one of: #{vop.join(', ')}" unless vop.include? option
|
177
|
+
|
178
|
+
send :sort, option
|
59
179
|
end
|
60
180
|
|
61
|
-
|
62
|
-
|
181
|
+
# Expands the given track.
|
182
|
+
#
|
183
|
+
# @param track [String] The track to expand.
|
184
|
+
# If not specified, expands all tracks.
|
185
|
+
|
186
|
+
def expand(track = nil)
|
187
|
+
send :expand, track
|
63
188
|
end
|
64
189
|
|
65
|
-
|
66
|
-
|
190
|
+
# Collapses a given track.
|
191
|
+
#
|
192
|
+
# @param track [String] The track to collapse.
|
193
|
+
# If not specified, collapses all tracks.
|
194
|
+
|
195
|
+
def collapse(track = nil)
|
196
|
+
send :collapse, track
|
197
|
+
end
|
198
|
+
|
199
|
+
# Squish a given track.
|
200
|
+
#
|
201
|
+
# @param track [String] The track to squish.
|
202
|
+
# If not specified, squishes all tracks.
|
203
|
+
|
204
|
+
def squish(track = nil)
|
205
|
+
send :squish, track
|
206
|
+
end
|
207
|
+
|
208
|
+
# Set the display mode for an alignment track to "View as pairs".
|
209
|
+
#
|
210
|
+
# @param track [String] The track to set.
|
211
|
+
# If not specified, sets all tracks.
|
212
|
+
|
213
|
+
def viewaspairs(track = nil)
|
214
|
+
send :viewaspairs, track
|
67
215
|
end
|
68
216
|
|
69
217
|
def clear
|
70
|
-
send
|
218
|
+
send :clear
|
71
219
|
end
|
72
220
|
|
221
|
+
# Exit (close) the IGV application.
|
222
|
+
|
73
223
|
def exit
|
74
|
-
send
|
224
|
+
send :exit
|
225
|
+
@socket.close
|
75
226
|
end
|
76
227
|
alias quit exit
|
77
228
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
end
|
229
|
+
# Sets the directory in which to write images.
|
230
|
+
# Retruns the current snapshot directory if no argument is given.
|
231
|
+
#
|
232
|
+
# @param path [String] The path to the directory.
|
83
233
|
|
84
|
-
def snapshot_dir=
|
85
|
-
snapshot_dir
|
86
|
-
return if snapshot_dir == @snaphot_dir
|
234
|
+
def snapshot_dir(dir_path = nil)
|
235
|
+
return @snapshot_dir if dir_path.nil?
|
87
236
|
|
88
|
-
|
89
|
-
|
90
|
-
|
237
|
+
dir_path = File.expand_path(dir_path)
|
238
|
+
return if dir_path == @snapshot_dir
|
239
|
+
|
240
|
+
r = snapshot_dir_internal(dir_path)
|
241
|
+
@snapshot_dir = dir_path
|
242
|
+
r
|
91
243
|
end
|
92
|
-
alias set_snapshot_dir snapshot_dir=
|
93
244
|
|
94
|
-
def
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
245
|
+
private def snapshot_dir_internal(dir_path)
|
246
|
+
dir_path = File.expand_path(dir_path)
|
247
|
+
FileUtils.mkdir_p(dir_path)
|
248
|
+
send :snapshotDirectory, dir_path
|
249
|
+
end
|
250
|
+
|
251
|
+
# Saves a snapshot of the IGV window to an image file.
|
252
|
+
# If filename is omitted, writes a PNG file with a filename generated based on the locus.
|
253
|
+
# If filename is specified, the filename extension determines the image file format,
|
254
|
+
# which must be either .png or .svg.
|
255
|
+
# @note In Ruby-IGV, it is possible to pass absolute or relative paths as well as file names;
|
256
|
+
# the Snapshot directory is set to Dir.pwd by default.
|
257
|
+
#
|
258
|
+
# @param file_path [String] The path to the image file.
|
259
|
+
|
260
|
+
def snapshot(file_path = nil)
|
261
|
+
return send(:snapshot) if file_path.nil?
|
262
|
+
|
263
|
+
dir_path = File.dirname(file_path)
|
264
|
+
filename = File.basename(file_path)
|
265
|
+
if dir_path != @snapshot_dir
|
266
|
+
snapshot_dir_internal(dir_path)
|
267
|
+
r = send :snapshot, filename
|
268
|
+
snapshot_dir_internal(@snapshot_dir)
|
269
|
+
r
|
101
270
|
else
|
102
|
-
send
|
271
|
+
send :snapshot, filename
|
103
272
|
end
|
104
273
|
end
|
105
|
-
|
274
|
+
|
275
|
+
# Temporarily set the preference named key to the specified value.
|
276
|
+
#
|
277
|
+
# @param key [String] The preference name
|
278
|
+
# @param value [String] The preference value
|
279
|
+
|
280
|
+
def preferences(key, value)
|
281
|
+
send :preferences, key, value
|
282
|
+
end
|
283
|
+
|
284
|
+
# Show "preference.tab" in your browser.
|
285
|
+
|
286
|
+
def show_preferences_table
|
287
|
+
require 'launchy'
|
288
|
+
Launchy.open('https://raw.githubusercontent.com/igvteam/igv/master/src/main/resources/org/broad/igv/prefs/preferences.tab')
|
289
|
+
end
|
290
|
+
|
291
|
+
# Save the current session.
|
292
|
+
# It is recommended that a full path be used for filename. IGV release 2.11.1
|
293
|
+
#
|
294
|
+
# @param filename [String] The path to the session file
|
295
|
+
|
296
|
+
def save_session(file_path)
|
297
|
+
file_path = File.expand_path(file_path)
|
298
|
+
send :saveSession, file_path
|
299
|
+
end
|
106
300
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-igv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kojix2
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-08-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: launchy
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,7 +80,7 @@ dependencies:
|
|
66
80
|
- - ">="
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '0'
|
69
|
-
description:
|
83
|
+
description: Control IGV (Integrative Genomics Viewer) with Ruby.
|
70
84
|
email:
|
71
85
|
- 2xijok@gmail.com
|
72
86
|
executables: []
|
@@ -89,15 +103,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
103
|
requirements:
|
90
104
|
- - ">="
|
91
105
|
- !ruby/object:Gem::Version
|
92
|
-
version: 2.
|
106
|
+
version: '2.4'
|
93
107
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
108
|
requirements:
|
95
109
|
- - ">="
|
96
110
|
- !ruby/object:Gem::Version
|
97
111
|
version: '0'
|
98
112
|
requirements: []
|
99
|
-
rubygems_version: 3.
|
113
|
+
rubygems_version: 3.3.7
|
100
114
|
signing_key:
|
101
115
|
specification_version: 4
|
102
|
-
summary:
|
116
|
+
summary: Control IGV (Integrative Genomics Viewer) with Ruby.
|
103
117
|
test_files: []
|