Python plot 2D array with black and white cells - python

I want to plot 2D array of 1's and 0's in Python with black and white cells using pyplot.imshow(). If there is '1' then the cell color should be black and if it's '0' the cell color should be white.
I tried this:
grid = np.zeros((4, 4, 4), int)
choices = np.random.choice(grid.size, 6, replace=False)
grid.ravel()[choices] = 1
plt.imshow(grid, cmap='gray')
plt.show()
This is how the output looks like with this code

If you meant to create a 3-dimensional grid, than you are probably interested in plotting all slices:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(2020)
grid = np.zeros((4, 4, 4), int)
choices = np.random.choice(grid.size, 6, replace=False)
grid.ravel()[choices] = 1
print(grid)
fig,ax=plt.subplots(2,2,figsize=(6,6))
for i,a in enumerate(ax.flatten()):
a.imshow(grid[i,:,:], cmap='gray_r',)
a.set_title(f"slice {i}")
plt.show()
yields:
[[[0 0 0 0]
[0 0 0 0]
[0 0 0 0]
[1 1 0 0]]
[[0 0 0 0]
[0 0 0 0]
[0 0 0 0]
[0 0 0 0]]
[[0 0 0 0]
[0 1 0 0]
[0 0 1 0]
[0 0 0 0]]
[[0 1 0 0]
[1 0 0 0]
[0 0 0 0]
[0 0 0 0]]]
and this image:
If, however, you wanted to plot in 2d, then use:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(2020)
grid = np.zeros((4, 4), int)
choices = np.random.choice(grid.size, 6, replace=False)
grid.ravel()[choices] = 1
print(grid)
plt.imshow(grid,cmap='gray_r')
plt.show()
yields:
[[0 1 1 0]
[1 0 0 0]
[0 1 1 0]
[1 0 0 0]]

Related

one hot encode with pandas get_dummies missing values

I have a dataset in the form of a DataFrame and each row has a label ranging from 1-5. I am doing a one hot encode using pd.get_dummies(). If my dataset has all 5 labels there is not problem. However not all sets contain all 5 numbers so the encode just skips the missing value and creates a problem for new datasets coming in. Can I set a range so that the one hot encode knows there should be 5 labels? Or would I have to append 1,2,3,4,5 to the end of the array before I perform the encode and then delete the last 5 entries?
Correct encode: values 1-5 are encoded
arr = np.array([1,2,5,3,1,5,1,4])
df = pd.DataFrame(arr, columns = ['test'])
hotarr = np.array(pd.get_dummies(df['test']))
>>>[[1 0 0 0 0]
[0 1 0 0 0]
[0 0 0 0 1]
[0 0 1 0 0]
[1 0 0 0 0]
[0 0 0 0 1]
[1 0 0 0 0]
[0 0 0 1 0]]
Missing value encode: this dataset is missing label 4.
arr = np.array([1,2,5,3,1,5,1,])
df = pd.DataFrame(arr, columns = ['test'])
hotarr = np.array(pd.get_dummies(df['test']))
>>>[[1 0 0 0]
[0 1 0 0]
[0 0 0 1]
[0 0 1 0]
[1 0 0 0]
[0 0 0 1]
[1 0 0 0]]
Set up the CategoricalDtype before encoding to ensure all categories are represented when getting dummies:
import numpy as np
import pandas as pd
arr = np.array([1, 2, 5, 3, 1, 5, 1])
df = pd.DataFrame(arr, columns=['test'])
# Setup Categorical Dtype
df['test'] = df['test'].astype(pd.CategoricalDtype(categories=[1, 2, 3, 4, 5]))
hotarr = np.array(pd.get_dummies(df['test']))
print(hotarr)
Alternatively can reindex after get_dummies with fill_value=0 to add the missing columns:
hotarr = np.array(pd.get_dummies(df['test'])
.reindex(columns=[1, 2, 3, 4, 5], fill_value=0))
Both produce hotarr with 5 columns even though input does not contain 4:
[[1 0 0 0 0]
[0 1 0 0 0]
[0 0 0 0 1]
[0 0 1 0 0]
[1 0 0 0 0]
[0 0 0 0 1]
[1 0 0 0 0]]

applying conditions to arrays with different channels

I have the following simple program
import numpy as np
thepixels = np.array([[0, 5 ], [5, 0 ]])
print(thepixels.shape)
cnd= thepixels[:]>3
print(cnd)
print(thepixels[cnd])
layer4= np.zeros((2,2,4),dtype=np.uint8)
print("the array")
print(layer4)
print("the info")
print(layer4.dtype)
print(layer4.shape)
Which gives the output
(2, 2)
[[False True]
[ True False]]
[5 5]
the array
[[[0 0 0 0]
[0 0 0 0]]
[[0 0 0 0]
[0 0 0 0]]]
the info
uint8
(2, 2, 4)
you can see that there is an array of shape (2,2) which serves me to find a condition that I want to apply to my zero array of shape (2,2,4)
What I am scratching my head to do (with numpy) is:
Given:
a channel number: nchannel
a value: value
apply the condition so that I can have the value in the array on the `nchannel.
For example:
nchannel= 1
value=10
What I want to get is
[[[0 0 0 0]
[0 10 0 0]]
[[0 10 0 0]
[0 0 0 0]]]
or if value is 50 and nchannel is 4 then
[[[0 0 0 0]
[0 0 0 50]]
[[0 0 0 50]
[0 0 0 0]]]
How can I apply the condition to get these arrays?
P.S. I know that by doing layer4[:,:,nchannel]=value I can apply the value unconditionally to the channel, but how do I apply it depending on the condition?
Your question is not crystal clear to me, but at least this gives me your expected results.
...
layer4[cnd, nchannel] = new_value
...

Numpy and Matplotlib, Printing a matrix with imshow or pcolor Problem

I have a question, the question text is :
Make a function plot_list(Xs, n_per_row) that takes in input a list of numpy 2-dimensional arrays and a parameter n_per_row to set the number of elements display in a single row.
The output associated to the following list of 4 arrays should be as indicated in the figure below.
plot_list(Xs, n_per_row=2)
Xs =[
[[1 0 0 0]
[1 0 0 0]
[0 0 0 0]
[0 0 0 0]]
,
[[0 0 0 0]
[0 0 0 0]
[0 1 0 0]
[0 1 0 0]]
,
[[0 0 1 1]
[0 0 0 0]
[0 0 0 0]
[0 0 0 0]]
,
[[0 0 0 0]
[0 0 0 0]
[0 0 0 0]
[0 0 1 1]]
]
Xs=np.array(Xs)
should output an image like;
I have written the following function
def plot_list(Xs, n_per_row=5):
'''Takes an input of 4 arrays only, n_per_row'''
a= np.array(Xs)
fig, axs = plt.subplots(nrows=a.shape[0]//n_per_row, ncols=n_per_row ,figsize=(10,10))
for i, ax in enumerate(fig.axes):
if a.ndim==3:
ax.pcolormesh(a[i],cmap='Greys')
elif a.ndim<3:
ax.pcolormesh(a,cmap='Greys')
ax.grid(True, lw=1)
ax.set_ylim(ax.get_ylim()[::-1])
plt.show()
which when called as plot_list(Xs, n_per_row=2)
produces the following output ( notice the grids, not aligned the way I intended )
However, when I call the function to produce 4 results in one row instead of 2 results in the abomination below; plot_list(Xs, n_per_row=4)
notice the y axis is 8 unit long but x is 4. Anyone know how to fix this issue? The grid alignment and the shortening of the X axis?
Thanks
Few things that needs improvement:
Change the figure size according to the layout
use set_major_locator to force the grid
from matplotlib import ticker as mticker
def plot_list(Xs, n_per_row=5):
'''Takes an input of 4 arrays only, n_per_row'''
a= np.array(Xs)
nrows = a.shape[0]//n_per_row
fig, axs = plt.subplots(nrows=nrows, ncols=n_per_row ,
figsize=(n_per_row*5,nrows*5)) # adjust the figsize here
for i, ax in enumerate(fig.axes):
if a.ndim==3:
ax.pcolormesh(a[i],cmap='Greys')
elif a.ndim<3:
ax.pcolormesh(a,cmap='Greys')
ax.grid(True, lw=1)
# set locator here
ax.xaxis.set_major_locator(mticker.MultipleLocator(1))
ax.yaxis.set_major_locator(mticker.MultipleLocator(1))
ax.set_ylim(ax.get_ylim()[::-1])
ax.set_aspect('equal')
plt.show()
Then output:
and plot_list(Xs, n_per_row=4) gives:

cv2.connectedComponents doesn't work properly

I want to use the function cv2.connectedComponents to connect components on a binary image, like the following...
.
Everything works, except the outputted labels array. In this array are only zeros and not sequential numbers as indicated, according to the identified components.
import cv2
import numpy as np
img = cv2.imread('eGaIy.jpg', 0)
img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)[1] # ensure binary
ret, labels = cv2.connectedComponents(img)
# Map component labels to hue val
label_hue = np.uint8(179*labels/np.max(labels))
blank_ch = 255*np.ones_like(label_hue)
labeled_img = cv2.merge([label_hue, blank_ch, blank_ch])
# cvt to BGR for display
labeled_img = cv2.cvtColor(labeled_img, cv2.COLOR_HSV2BGR)
# set bg label to black
labeled_img[label_hue==0] = 0
cv2.imshow('labeled.png', labeled_img)
cv2.waitKey()
outputted labels --> labels.shape: (256L, 250L)
[[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]
...,
[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]]
It works for me:
And you should be careful that the function only find the component of nonzero. In the source image, the components are the edges. And the returned are labeled image as the same size of source.
The output of
[[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]
...,
[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]]
only represent the 4 corner regions(3x3) are all zeros, but it doesn't mean all elements are zeros.
If you call this after you call the cv2.connectedComponents:
print(set(labels.reshape(-1).tolist()))
You will get:
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
It means there exist 14 components(edges), and 1 background(0).

Find out indices of an array elements

I have this array as a result of subtracting two images after getting there RGB integer values as an arrays
arr = img1 - img2
[[[0 0 0]
[0 0 0]
[0 0 0]
...,
[0 0 0]
[0 0 0]
[0 0 0]]
...,
[[0 0 0]
[0 0 0]
[0 0 0]
...,
[0 0 0]
[0 0 0]
[0 0 0]]]
i used these lines of code to change the shape of array to add the indices of each pixel subtraction
x, y, z = arr.shape
indices = np.vstack(np.unravel_index(np.arange(x*y), (y, x))).T
result = np.hstack((arr.reshape(x*y, z), indices))
and here what the result looks like:
[[ 0 0 0 0 0]
[ 0 0 0 0 1]
[ 0 0 0 0 2]
...,
[ 0 0 0 511 509]
[ 0 0 0 511 510]
[ 0 0 0 511 511]]
the first three values in each row is the RGB difference and the last two values is the X and Y indices
my question here, is there an efficient way to find the indices of the non zero values?
If I understand what you're saying correctly, you want them per list in your list of lists...
Saying this is your list:
l=[[0,0,0,0,0],[0,0,0,0,1],[0,0,0,0,2],[0,0,0,511,509],[0,0,0,511,510],[0,0,0,511,511]]
try running:
import numpy as np
ans=[np.nonzero(l[i])[0] for i in range(1,len(l))]
print ans
returns:
[array([4]), array([4]), array([3, 4]), array([3, 4]), array([3, 4])]
So it's an array containing arrays that have the indices of each non-zero element in each list. Since it uses list comprehension it runs pretty quickly and accession is as simple as using the indices. It will just be ans[list in list of lists][number of non-zero indices] like so:
ans[2][1]
4

Categories

Resources