Related
Given the following code:
import tensorflow as tf
def combine(x, y):
xx, yy = tf.meshgrid(x, y, indexing='ij')
combo = tf.stack([tf.reshape(xx, [-1]), tf.reshape(yy, [-1])], axis=1)
print(combo)
x = tf.constant([11, 0, 7, 1])
combine(x, x)
I want to clean combo vector in order to obtain the following tf vector [(11, 0), (11, 7), (11, 1), (0, 7), (0, 1), (7, 1)]. Is it possible to do this in Tensorflow?
You can introduce a mask, to do get the desired result-
def combine(x, y):
xx, yy = tf.meshgrid(x, y, indexing='ij')
#create a mask to take the strictly upper triangular matrix
ones = tf.ones_like(xx)
mask = tf.cast(tf.linalg.band_part(ones, 0, -1) - tf.linalg.band_part(ones, 0, 0) , dtype=tf.bool)
x = tf.boolean_mask(xx, mask)
y = tf.boolean_mask(yy, mask)
combo = tf.stack([x, y], axis=1)
print(combo)
x = tf.constant([11, 0, 7, 1])
a = combine(x, x)
#output
[[11 0]
[11 7]
[11 1]
[ 0 7]
[ 0 1]
[ 7 1]],
Suppose I have a 8-direction freeman chain code as follows, in a python list:
freeman_code = [3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5]
Where directions would be defined as follows:
I need to convert this to an image matrix of variable dimensions with valules of 1s and 0s where 1s would depict the shape, as follows, for example:
image_matrix = [
[0, 0, 1, 0, 0, 1],
[0, 0, 0, 1, 0, 1],
[0, 0, 0, 0, 1, 1]
]
Of course, the above is not an exact implementation of the above freeman code. Is there any implementation in python, or in any language that achieves this?
My idea (in python):
Use a defaultdict of defaultdicts with 0 as default:
ImgMatrixDict = defaultdict(lambda: defaultdict(lambda:0))
and then start at a midpoint, say ImgMatrixDict[25][25], and then change values to 1 depending on the freeman code values as I traverse. Afte tis I would convert ImgMatrixDict to a list of lists.
Is this a viable idea or are there any existing libraries or suggestions to implement this? Any idea/pseudo-code would be appreciated.
PS: On performance, yes it would not be important as I won't be doing this in realtime, but generally a code would be around 15-20 charactors in length. I assumed a 50*50 by matrix would suffice for this purpose.
If I am understanding your question correctly:
import numpy as np
import matplotlib.pyplot as plt
freeman_code = [3, 3, 3, 6, 6, 4, 6, 7, 7, 0, 0, 6]
img = np.zeros((10,10))
x, y = 4, 4
img[y][x] = 1
for direction in freeman_code:
if direction in [1,2,3]:
y -= 1
if direction in [5,6,7]:
y += 1
if direction in [3,4,5]:
x -= 1
if direction in [0,1,7]:
x += 1
img[y][x] = 1
plt.imshow(img, cmap='binary', vmin=0, vmax=1)
plt.show()
Here is a solution in python. A dictionary is not adapted to this problem, you would better use a list of list to simulate the table.
D = 10
# DY, DX
FREEMAN = [(0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (1, 0), (1, 1)]
freeman_code = [3, 3, 3, 3, 6, 6, 6, 6, 0, 0, 0, 0]
image = [[0]*D for x in range(D)]
y = D/2
x = D/2
image[y][x] = 1
for i in freeman_code:
dy, dx = FREEMAN[i]
y += dy
x += dx
image[y][x] = 1
print("freeman_code")
print(freeman_code)
print("image")
for line in image:
strline = "".join([str(x) for x in line])
print(strline)
>0000000000
>0100000000
>0110000000
>0101000000
>0100100000
>0111110000
>0000000000
>0000000000
>0000000000
>0000000000
Note that the image creation is a condensed expression of:
image = []
for y in range(D):
line = []
for x in range(D):
line.append(0)
image.append(line)
If one day, you need better performance for bigger images, there are solutions using numpy Library but requiring a good knowledge of basic python. Here is an example:
import numpy as np
D = 10
# DY, DX
FREEMAN = [(0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (1, 0), (1, 1)]
DX = np.array([1, 1, 0, -1, -1, -1, 0, 1])
DY = np.array([0, -1, -1, -1, 0, 1, 1, 1])
freeman_code = np.array([3, 3, 3, 3, 6, 6, 6, 6, 0, 0, 0, 0])
image = np.zeros((D, D), int)
y0 = D/2
x0 = D/2
image[y0, x0] = 1
dx = DX[freeman_code]
dy = DY[freeman_code]
xs = np.cumsum(dx)+x0
ys = np.cumsum(dy)+y0
print(xs)
print(ys)
image[ys, xs] = 1
print("freeman_code")
print(freeman_code)
print("image")
print(image)
Here, all loops built with 'for' on previous solution are fast-processed in C.
In my previous question, (How to Animate multiple columns as dots with matplotlib from pandas dataframe with NaN in python), I managed to animate multiple dots from a dataframe as an animation.
However, I wanted to set a background for the animation as a network graph, so that it seems that the dots are moving on the lines of the network.
Using the code from How to Animate multiple columns as dots with matplotlib from pandas dataframe with NaN in python
I've created a new MCV example,
the code is listed below:
import random
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
import math
import pandas as pd
from matplotlib import animation
#from JSAnimation import IPython_display
%matplotlib inline
# initialise graph object
G = nx.Graph()
color_map =[]
G.add_node(1, pos=(1, 0)); color_map.append('r')
G.add_node(2, pos=(2, 0)); color_map.append('r')
G.add_node(3, pos=(3, -1)); color_map.append('r')
G.add_node(4, pos=(3, 1)); color_map.append('r')
G.add_node(5, pos=(4, -1)) ;color_map.append('r')
G.add_node(6, pos=(4, 1)); color_map.append('r')
G.add_node(7, pos=(5, 0)); color_map.append('r')
G.add_node(8, pos=(6, 0)); color_map.append('r')
e = [(1, 2, 1),
(2, 3, 1),
(2, 4, 2),
(3, 5, 5),
(4, 6, 2),
(5, 7, 1),
(6, 7, 2),
(7, 8, 1)]
G.add_weighted_edges_from(e)
labels = nx.get_edge_attributes(G,'weight')
nx.draw(G,nx.get_node_attributes(G, 'pos'))
nx.draw_networkx_edge_labels(G,nx.get_node_attributes(G, 'pos'),edge_labels=labels)
nx.draw_networkx_labels(G,nx.get_node_attributes(G, 'pos'))
df_x = pd.DataFrame(data=
np.array(
[[np.NaN, np.NaN, np.NaN, np.NaN],
[1, np.nan, np.NaN,np.NaN],
[1.5, 4, np.NaN,np.NaN],
[2, 5, 3,4]]
), index= [1, 2, 3, 4], columns=[1, 2, 3, 4])
print(df_x)
df_y = pd.DataFrame(data=np.array(
[[np.NaN, np.NaN, np.NaN, np.NaN],
[0, np.nan, np.NaN,np.NaN],
[0, -1, np.NaN,np.NaN],
[0, 0, 1,1]]
), index= [1, 2, 3, 4], columns=[1, 2, 3, 4])
%matplotlib notebook
from matplotlib import animation
#from JSAnimation import IPython_display
#from IPython.display import HTML
fig = plt.figure(figsize=(10,10))
ax = plt.axes()
nx.draw(G,nx.get_node_attributes(G, 'pos'),node_size = 10)
n_steps = df_x.index
graph, = plt.plot([],[],'o')
def get_data_x(i):
return df_x.loc[i]
def get_data_y(i):
return df_y.loc[i]
def animate(i):
x = get_data_x(i)
y= get_data_y(i)
graph.set_data(x,y)
return graph,
animation.FuncAnimation(fig, animate, frames=n_steps, repeat=True, blit = True)
This creates a workable animation, which works. But however, when I use a very large dataset ( pandas dataframe index is ~8000 rows * 800 columns instead of the example pandas dataset I posted), the animation takes very long(hour or so) to render and most of the times my browser( google chrome) crashes.
So I thought is maybe due to it needs to redraw the networks graph each frame? How can I set the background as the networkx graph? From there on it is just plotting points right? My actual graph is a bit larger (~5000 nodes, ~6000 edges).
Hopes anyone can help me speed the rendering of the animation up!
After some digging around, I found no 'easy' solution to this problem when trying to animate large datasets into an animation with matplotlib in a jupyter notebook. I just decided to write everything to an mp4 file, which works just as good for animations.
My code for this including the MVC example:
import random
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
import math
import pandas as pd
from matplotlib import animation
#from JSAnimation import IPython_display
%matplotlib inline
# initialise graph object
G = nx.Graph()
color_map =[]
G.add_node(1, pos=(1, 0)); color_map.append('r')
G.add_node(2, pos=(2, 0)); color_map.append('r')
G.add_node(3, pos=(3, -1)); color_map.append('r')
G.add_node(4, pos=(3, 1)); color_map.append('r')
G.add_node(5, pos=(4, -1)) ;color_map.append('r')
G.add_node(6, pos=(4, 1)); color_map.append('r')
G.add_node(7, pos=(5, 0)); color_map.append('r')
G.add_node(8, pos=(6, 0)); color_map.append('r')
e = [(1, 2, 1),
(2, 3, 1),
(2, 4, 2),
(3, 5, 5),
(4, 6, 2),
(5, 7, 1),
(6, 7, 2),
(7, 8, 1)]
G.add_weighted_edges_from(e)
labels = nx.get_edge_attributes(G,'weight')
nx.draw(G,nx.get_node_attributes(G, 'pos'))
nx.draw_networkx_edge_labels(G,nx.get_node_attributes(G, 'pos'),edge_labels=labels)
nx.draw_networkx_labels(G,nx.get_node_attributes(G, 'pos'))
df_x = pd.DataFrame(data=
np.array(
[[np.NaN, np.NaN, np.NaN, np.NaN],
[1, np.nan, np.NaN,np.NaN],
[1.5, 4, np.NaN,np.NaN],
[2, 5, 3,4]]
), index= [1, 2, 3, 4], columns=[1, 2, 3, 4])
print(df_x)
df_y = pd.DataFrame(data=np.array(
[[np.NaN, np.NaN, np.NaN, np.NaN],
[0, np.nan, np.NaN,np.NaN],
[0, -1, np.NaN,np.NaN],
[0, 0, 1,1]]
), index= [1, 2, 3, 4], columns=[1, 2, 3, 4])
def get_data_x(i):
return df_x.loc[i]
def get_data_y(i):
return sdf_y.loc[i]
def animate(i):
x = get_data_x(i)
y= get_data_y(i)
graph.set_data(x,y)
return graph,
# Set up formatting for the movie files
Writer = animation.writers['ffmpeg']
writer = Writer(fps=15, metadata=dict(artist='Me'), bitrate=1800)
fig = plt.figure(figsize=(20,20))
ax = plt.axes()
nx.draw(G,nx.get_node_attributes(G, 'pos'),node_size = 1)
n_steps = df_x.index
graph, = plt.plot([],[],'o')
ani = animation.FuncAnimation(fig, animate, frames= n_steps, interval=1, repeat=True, blit = True)
ani.save('path/file.mp4', writer=writer)
I have some data that looks like:
data = [1,2,4,5,9] (random pattern of increasing integers)
And I want to plot it in a binary horizontal line so that y=1 for every x value specified in data and zero otherwise.
I have a few different data arrays that I'd like to stack, similar to this style (this is CCD clocking data but the plot format looks ideal)
I think I need to create a list of ones for my data array, but how do I specify the zero value for everything not in the array?
Thanks
You got the point. You can create a list with 1 in any position specified in data and 0 elsewhere. This can be done very easily with a list comprehension
def binary_data(data):
return [1 if x in data else 0 for x in range(data[-1] + 1)]
which will act like this:
>>> data = [1, 2, 4, 5, 9]
>>> bindata = binary_data(data)
>>> bindata
[0, 1, 1, 0, 1, 1, 0, 0, 0, 1]
Now all you have to do is plot it... or better step it since it's binary data and step() looks way better:
import numpy as np
from matplotlib.pyplot import step, show
def binary_data(data):
return [1 if x in data else 0 for x in range(data[-1] + 1)]
data = [1, 2, 4, 5, 9]
bindata = binary_data(data)
xaxis = np.arange(0, data[-1] + 1)
yaxis = np.array(bindata)
step(xaxis, yaxis)
show()
To plot multiple data arrays stacked on the same figure you could tweak binary_data() like this:
def binary_data(data, yshift=0):
return [yshift+1 if x in data else yshift for x in range(data[-1] + 1)]
so now you can set yshift parameter to shift data arrays on the y-axis. E.g,
>>> data = [1, 2, 4, 5, 9]
>>> bindata1 = binary_data(data)
>>> bindata1
[0, 1, 1, 0, 1, 1, 0, 0, 0, 1]
>>> bindata2 = binary_data(data, 2)
>>> bindata2
[2, 3, 3, 2, 3, 3, 2, 2, 2, 3]
Let's say you have data1, data2 and data3 to plot stacked, you'd go like:
import numpy as np
from matplotlib.pyplot import step, show
def binary_data(data, yshift=0):
return [yshift+1 if x in data else yshift for x in range(data[-1] + 1)]
data1 = [1, 2, 4, 5, 9]
bindata1 = binary_data(data1)
x1 = np.arange(0, data1[-1] + 1)
y1 = np.array(bindata1)
data2 = [1, 4, 9]
bindata2 = binary_data(data2, 2)
x2 = np.arange(0, data2[-1] + 1)
y2 = np.array(bindata2)
data3 = [1, 2, 8, 9]
bindata3 = binary_data(data3, 4)
x3 = np.arange(0, data3[-1] + 1)
y3 = np.array(bindata3)
step(x1, y1, x2, y2, x3, y3)
show()
that you can easily edit to make it work with an arbitrary amount of data arrays:
data = [ [1, 2, 4, 5, 9],
[1, 4, 9],
[1, 2, 8, 9] ]
for shift, d in enumerate(data):
bindata = binary_data(d, 2 * shift)
x = np.arange(0, d[-1] + 1)
y = np.array(bindata)
step(x, y)
show()
Finally if you are dealing with data arrays with different length (say [1,2] and [15,16]) and you don't like plots that vanish in the middle of the figure you can tweak binary_data() again to force its range to the maximum range of your data.
import numpy as np
from matplotlib.pyplot import step, show
def binary_data(data, limit, yshift=0):
return [yshift+1 if x in data else yshift for x in range(limit)]
data = [ [1, 2, 4, 5, 9, 12, 13, 14],
[1, 4, 10, 11, 20, 21, 22],
[1, 2, 3, 4, 15, 16, 17, 18] ]
# find out the longest data to plot
limit = max( [ x[-1] + 1 for x in data] )
x = np.arange(0, limit)
for shift, d in enumerate(data):
bindata = binary_data(d, limit, 2 * shift)
y = np.array(bindata)
step(x, y)
show()
Edit: As #ImportanceOfBeingErnest suggested, if you prefer to perform data to bindata conversion without having to define your own binary_data() function you could use numpy.zeros_like(). Just pay more attention when you stack them:
import numpy as np
from matplotlib.pyplot import step, show
data = [ [1, 2, 4, 5, 9, 12, 13, 14],
[1, 4, 10, 11, 20, 21, 22],
[1, 2, 3, 4, 15, 16, 17, 18] ]
# find out the longest data to plot
limit = max( [ x[-1] + 1 for x in data] )
x = np.arange(0, limit)
for shift, d in enumerate(data):
y = np.zeros_like(x)
y[d] = 1
# don't forget to shift
y += 2*shift
step(x, y)
show()
You can create an array with all zeros and assign 1 for those elements in data
import numpy as np
data = [1,2,4,5,9]
t = np.arange(0,data[-1]+1)
x = np.zeros_like(t)
x[data] = 1
You might then plot it with the step function
import matplotlib.pyplot as plt
plt.step(t,x, where="post")
plt.show()
or with where = "pre", depending on how to interprete your data
I'm attempting to use Python and Matplotlib to render a 3D surface of a polyhedron, given by
However my code (shown below) does not seem to draw it correctly. How should this be done instead?
Failed Attempt:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
delta = 0.1
def x_func(x):
return abs(x)
def y_func(y):
return abs(y)
def z_func(z):
return abs(z)
x = np.arange(-1, 1, delta)
x1 = x_func(x)
y = np.arange(-1, 1, delta)
y1 = y_func(y)
X, Y = meshgrid(x1, y1)
z = np.arange(-1, 1, delta)
Z = z_func(z)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_xlim([-1,1])
ax.set_ylim([-1,1])
ax.set_zlim([-1,1])
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.RdBu, linewidth=0.1)
Here's one solution:
import mpl_toolkits.mplot3d as a3
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import scipy as sp
# Vertex data
verts= [
(-1, -1, -1), (-1, -1, 1), (-1, 1, 1), (-1, 1, -1),
(1, -1, -1), (1, -1, 1), (1, 1, 1), (1, 1, -1)
]
# Face data
faces = np.array([
[0, 1, 2, 3], [4, 5, 6, 7], [0, 3, 7, 4], [1, 2, 6, 5],
[0, 1, 5, 4], [2, 3, 7, 6]
])
ax = a3.Axes3D(plt.figure())
ax.dist=30
ax.azim=-140
ax.elev=20
ax.set_xlim([-1,1])
ax.set_ylim([-1,1])
ax.set_zlim([-1,1])
for i in np.arange(len(faces)):
square=[ verts[faces[i,0]], verts[faces[i,1]], verts[faces[i, 2]], verts[faces[i, 3]]]
face = a3.art3d.Poly3DCollection([square])
face.set_color(colors.rgb2hex(sp.rand(3)))
face.set_edgecolor('k')
face.set_alpha(0.5)
ax.add_collection3d(face)
plt.show()
The figure output is this:
The surface of a cube