Skip to content

Commit 7c40e76

Browse files
committed
Write an ImageWriter in Python.
1 parent 21dfc75 commit 7c40e76

26 files changed

+700
-164
lines changed

.pre-commit.git

+21-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ colors
66
GOFMT=`which gofmt`
77

88
if [[ ! -x "$GOFMT" ]]; then
9-
printf "\t\033[41mPlease install gofmt.\033[0m"
9+
printf "$fg[red]"
10+
printf "Please install gofmt"
11+
printf "$fg[default]"
1012
exit 1
1113
fi
1214

@@ -15,17 +17,30 @@ find . \( -name "*.go" ! -name "*.pb.go" \) -exec $GOFMT -w {} \;
1517
REVIVE=`which revive`
1618

1719
if [[ ! -x "$REVIVE" ]]; then
18-
printf "\t\033[41mPlease install revive (https://github.com/mgechev/revive).\033[0m"
20+
printf "$fg[red]"
21+
printf "Please install revive (https://github.com/mgechev/revive)"
22+
printf "$fg[default]"
1923
exit 1
2024
fi
2125

2226
PIPENV=`which pipenv`
2327

2428
if [[ ! -x "$PIPENV" ]]; then
25-
printf "\t\033[41mPlease install pipenv (https://pipenv.pypa.io/en/latest/install/).\033[0m"
29+
printf "$fg[red]"
30+
printf "Please install pipenv (https://pipenv.pypa.io/en/latest/install/)"
31+
printf "$fg[default]"
2632
exit 1
2733
fi
2834

35+
ADDLICENSE=`which addlicense`
36+
37+
if [[ ! -x "$ADDLICENSE" ]]; then
38+
printf "$fg[red]"
39+
printf "Please install addlicence with:\n"
40+
printf "go install github.com/google/addlicense@latest\n"
41+
printf "$fg[default]"
42+
exit 1
43+
fi
2944

3045
FOLDERS=`find . -type f -name "*.go" -exec dirname "{}" \; | awk -F "/" '{print $2}' | awk 'NF' | sort -u`
3146

@@ -103,6 +118,9 @@ else
103118
PASS=false
104119
fi
105120

121+
# Add license to every file.
122+
addlicense -c "DeepMind Technologies Limited" .
123+
106124
# Disable python test because python seems unreliable on MacOS.
107125
if [[ -z "$ENABLE_PYTHON_CHECKS" ]]; then
108126
# Cleanup python:

clients/python/Pipfile

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ six = "1.16.0"
1515
termcolor = "2.3.0"
1616
pytype = "2023.6.2"
1717
typing-extensions = "4.6.3"
18+
pillow = "10.0.0"
1819

1920
[dev-packages]
2021
yapf = "0.40.1"

clients/python/Pipfile.lock

+229-157
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

clients/python/examples/image.py

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Copyright 2023 DeepMind Technologies Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""image provides an example for streaming a greyscale image."""
15+
16+
from absl import app
17+
import numpy as np
18+
19+
from examples import common
20+
import multiscope
21+
22+
23+
class Board(object):
24+
"""Board class that scans a rectangle top left -> bottom right (wrapping).
25+
26+
A NumPy array like np.ones((10, 5)) has 10 rows and 5 columns.
27+
If you print it, it will be 10 rows tall, and 5 columns wide.
28+
It will print downwards, so [0, 0] will be the top left.
29+
30+
This is like np.ones((height, width)).
31+
If trying to index as Cartesian coordinates, it is my_array[y, x].
32+
33+
This can be confusing.
34+
35+
This example is meant to demonstrate top/bottom left/right.
36+
"""
37+
38+
def __init__(self, width, height):
39+
super(Board, self).__init__()
40+
self.width = width
41+
self.height = height
42+
self.pos_x = self.pos_y = 0
43+
# 2D array will be rendered as grayscale. All values should be in [0, 255].
44+
self.img = np.zeros([self.height, self.width], dtype=np.uint8)
45+
46+
def step(self):
47+
"""Step makes the pixel move one step."""
48+
self.pos_x += 1
49+
if self.pos_x == self.width:
50+
self.pos_x = 0
51+
self.pos_y += 1
52+
if self.pos_y == self.height:
53+
self.pos_y = 0
54+
self.img.fill(0)
55+
self.img[self.pos_y, self.pos_x] = 255
56+
57+
58+
class Box(object):
59+
"""Box class containing a square ball."""
60+
61+
def __init__(self, size_y, size_x, ball_size):
62+
super(Box, self).__init__()
63+
self.size_x = size_x
64+
self.size_y = size_y
65+
self.pos_x = size_x / 2
66+
self.pos_y = size_y / 2
67+
self.vel_x = 3
68+
self.vel_y = 5
69+
self.ball_size = ball_size
70+
self.img = np.zeros([size_y, size_x], dtype=np.uint8)
71+
72+
def step(self):
73+
"""Step makes the box move one step."""
74+
self.pos_x += self.vel_x
75+
if self.pos_x < 0:
76+
self.pos_x = 0
77+
self.vel_x *= -1
78+
if self.pos_x + self.ball_size > self.size_x - 1:
79+
self.pos_x = self.size_x - self.ball_size - 1
80+
self.vel_x *= -1
81+
82+
self.pos_y += self.vel_y
83+
if self.pos_y < 0:
84+
self.pos_y = 0
85+
self.vel_y *= -1
86+
if self.pos_y + self.ball_size > self.size_y - 1:
87+
self.pos_y = self.size_y - self.ball_size - 1
88+
self.vel_y *= -1
89+
90+
self.img.fill(0)
91+
for ix in range(self.ball_size):
92+
for iy in range(self.ball_size):
93+
self.img[int(self.pos_y + iy), int(self.pos_x + ix)] = 255
94+
95+
96+
def main(_):
97+
multiscope.start_server()
98+
box = Box(100, 200, 10)
99+
board = Board(width=5, height=10)
100+
clock = multiscope.Ticker("main")
101+
board_writer = multiscope.ImageWriter("Scanner", clock)
102+
box_writer = multiscope.ImageWriter("Box", clock)
103+
for _ in common.step():
104+
box_writer.write(box.img)
105+
board_writer.write(board.img)
106+
box.step()
107+
board.step()
108+
clock.tick()
109+
110+
111+
if __name__ == "__main__":
112+
app.run(main)

clients/python/examples/sincos.py

+13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
# Copyright 2023 DeepMind Technologies Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
114
"""sincos provides an example for plotting two time-series in one chart."""
215

316
import math

clients/python/multiscope/__init__.py

+6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from multiscope.remote.server import server_address
2929
from multiscope.remote.server import start_server
3030
from multiscope.remote.writers import base
31+
from multiscope.remote.writers import image
3132
from multiscope.remote.writers import scalar
3233
from multiscope.remote.writers import tensor
3334
from multiscope.remote.writers import text
@@ -46,6 +47,11 @@ def global_client():
4647
return stream_client.GlobalClient()
4748

4849

50+
def ImageWriter(name: str, parent: Optional[group.ParentNode] = None):
51+
return image.ImageWriter(
52+
py_client=stream_client.GlobalClient(), name=name, parent=parent)
53+
54+
4955
def Player(name: str,
5056
parent: Optional[group.ParentNode] = None,
5157
stoppable: bool = True):

clients/python/multiscope/protos/base_pb2.py

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2023 DeepMind Technologies Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
# -*- coding: utf-8 -*-
216
# Generated by the protocol buffer compiler. DO NOT EDIT!
317
# source: multiscope/protos/base.proto

clients/python/multiscope/protos/base_pb2_grpc.py

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2023 DeepMind Technologies Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
216
"""Client and server classes corresponding to protobuf-defined services."""
317
import grpc

clients/python/multiscope/protos/plot_pb2.py

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2023 DeepMind Technologies Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
# -*- coding: utf-8 -*-
216
# Generated by the protocol buffer compiler. DO NOT EDIT!
317
# source: multiscope/protos/plot.proto

clients/python/multiscope/protos/plot_pb2_grpc.py

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2023 DeepMind Technologies Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
216
"""Client and server classes corresponding to protobuf-defined services."""
317
import grpc

clients/python/multiscope/protos/root_pb2.py

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2023 DeepMind Technologies Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
# -*- coding: utf-8 -*-
216
# Generated by the protocol buffer compiler. DO NOT EDIT!
317
# source: multiscope/protos/root.proto

clients/python/multiscope/protos/root_pb2_grpc.py

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2023 DeepMind Technologies Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
216
"""Client and server classes corresponding to protobuf-defined services."""
317
import grpc

clients/python/multiscope/protos/scalar_pb2.py

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2023 DeepMind Technologies Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
# -*- coding: utf-8 -*-
216
# Generated by the protocol buffer compiler. DO NOT EDIT!
317
# source: multiscope/protos/scalar.proto

clients/python/multiscope/protos/scalar_pb2_grpc.py

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2023 DeepMind Technologies Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
216
"""Client and server classes corresponding to protobuf-defined services."""
317
import grpc

clients/python/multiscope/protos/tensor_pb2.py

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2023 DeepMind Technologies Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
# -*- coding: utf-8 -*-
216
# Generated by the protocol buffer compiler. DO NOT EDIT!
317
# source: multiscope/protos/tensor.proto

clients/python/multiscope/protos/tensor_pb2_grpc.py

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2023 DeepMind Technologies Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
216
"""Client and server classes corresponding to protobuf-defined services."""
317
import grpc

0 commit comments

Comments
 (0)