opencv find distance for every pixel in image from certain point? - numpy

I have white-black image,and i want to find euclidean distance for every white pixel to some point.
def remove_pixel(img,point,distance ):
rimg=np.copy(img)
for i in range(rimg.shape[0]):
for j in range(rimg.shape[1]):
if rimg[i,j]==1 and distance((i,j),point)<distance:
rimg[i,j]=0
return rimg
How I can do this with out using loops?

You could vectorize your function by using numpy.indices and numpy.where as follows:
import numpy as np
def remove_pixel(img, point, distance):
rows, cols = np.indices(img.shape)
mask = (rows - point[0])**2 + (cols - point[1])**2 < distance**2
return np.where(mask, 0, img)
Demo
In [36]: from skimage.data import checkerboard
In [37]: import matplotlib.pyplot as plt
In [38]: img = checkerboard()
In [39]: out = remove_pixel(img, [75, 75], 50)
In [40]: fig, (ax0, ax1) = plt.subplots(1, 2)
...: ax0.imshow(img, cmap='gray')
...: ax0.axis('off')
...: ax0.set_title('img')
...: ax1.imshow(out, cmap='gray')
...: ax1.axis('off')
...: ax1.set_title('out')
...: plt.show(fig)

Related

How to set values of a vertical stem plot as xticks labels?

I would like to reverse a grouped data and use group name as xtick label to draw it side by side. below demo mostly good but the label position not as expected.
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
def main():
data = [['AAAAAA',8],['AAAAAA',9],['AAAAAA',10],['BBBBBB',5],['BBBBBB',6],['BBBBBB',7],['CCCCCC',1],['CCCCCC',2],['CCCCCC',3],['CCCCCC',4]]
df = pd.DataFrame(data,columns=['name','value'])
dfg = df.groupby('name')
fig, ax = plt.subplots(figsize=(8, 4))
i = 0
ymin = df['value'].min()
c1='#ececec'
c2='#bcbcbc'
color=c1
for ix, row in reversed(tuple(dfg)):
print(ix,row)
n = len(row['name'])
x = np.linspace(i,i + n,n)
ax.stem(x,row['value'])
font_dict = {'family':'serif','color':'darkred', 'size':8}
ax.text(i + n/2,ymin,ix,ha='right',va='top',rotation=90, fontdict=font_dict)
if color == c1:
color = c2
else:
color = c1
plt.axvspan(i, i+n, facecolor=color, alpha=0.5)
i += len(row)
ax.xaxis.set_ticks_position('none')
plt.setp( ax.get_xticklabels(), visible=False)
ax.grid(axis='y',color='gray', linestyle='dashed', alpha=1)
ax.spines[["top", "right"]].set_visible(False)
fig.tight_layout()
plt.show()
return
main()
Output:
Welcome to comment any other proper way to do this, or how to improve the xticks down, use ymin properly not good way to do it.
If my understanding of what you are trying to achieve is correct, here is one way to do it:
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
df = pd.DataFrame(
[
["AAAAAA", 8],
["AAAAAA", 9],
["AAAAAA", 10],
["BBBBBB", 5],
["BBBBBB", 6],
["BBBBBB", 7],
["CCCCCC", 1],
["CCCCCC", 2],
["CCCCCC", 3],
["CCCCCC", 4],
],
columns=["name", "value"],
)
fig, ax = plt.subplots(figsize=(8, 4))
i = 0
c1 = "#ececec"
c2 = "#bcbcbc"
color = c1
ticks = {}
for ix, row in reversed(tuple(df.groupby("name"))):
# Create stem plot
n = len(row["name"])
x = np.linspace(i, i + n, n)
ax.stem(x, row["value"])
# Create axvspan plot
if color == c1:
color = c2
else:
color = c1
ax.axvspan(i, i + n, facecolor=color, alpha=0.5)
# Save positions and names in a dict
for key, name in zip(x, row["name"]):
if key not in ticks.keys():
ticks[key] = name
else:
# Deal with multiple names for same tick
ticks[key] += f"\n{name}"
i += len(row)
# Add ticks and ticks labels
ax.set_xticks(ticks=list(ticks.keys()))
ax.set_xticklabels(list(ticks.values()), fontsize=10, rotation="vertical")
# In Jupyter notebook
fig
Output:
And to avoid repeating the labels, you can, for instance, do:
ax.set_xticklabels(
[
"",
"CCCCCC",
"",
"CCCCCC\nBBBBBB",
"BBBBBB",
"BBBBBB\nAAAAAA",
" " * 20 + "AAAAAA",
"",
],
fontsize=10,
)
# In Jupyter notebook
fig
Output:

Apply 2 different masks to a seaborn heatmap or manually change the color of a cell

I have a dataframe and I want to plot the seaborn heatmap:
import seaborn as sns
res = sns.heatmap(df, cmap='flare',xticklabels=1, yticklabels=1,linecolor='white',linewidths=0.5,
cbar=True,mask=df.isnull(),cbar_kws={'shrink': 0.6},vmin=vmin, vmax=vmax)
I have applied a mask for NaN cells. Now, I want to change the color of few cells by a customized color which is not in the colormap, for example blue, to show that those cells belong to another category.
My question is:
Is it possible to apply 2 masks or more with different colors to a seaborn heatmap or manually change the color of a cell to totally another color?
It is unclear how the blue squares are represented. The following solution supposes they are represented as ones in a second matrix. The first heatmap is drawn as before. Then the second heatmap uses a special colormap (in this case with one color, but also a full range is possible), masking out all places where nothing should be drawn.
Note that masks can be combined via the logical or (symbol: |).
from matplotlib import pyplot as plt
from matplotlib.colors import ListedColormap
import seaborn as sns
import pandas as pd
import numpy as np
N = 10
data = np.random.uniform(0, 45, size=(N, N))
for x, y in np.random.randint(0, N, 50).reshape(-1, 2):
data[x, y] = np.nan # fill in some nans at random places
df = pd.DataFrame(data)
up_triang = np.triu(np.ones_like(data)).astype(bool)
ax = sns.heatmap(df, cmap='flare', xticklabels=True, yticklabels=True, square=True,
linecolor='white', linewidths=0.5,
cbar=True, mask=df.isnull() | up_triang, cbar_kws={'shrink': 0.6, 'pad': 0}, vmin=0, vmax=45)
data_special = np.random.randint(0, 5, size=(N, N)) // 4
sns.heatmap(data_special, cmap=ListedColormap(['cornflowerblue']), linecolor='white', linewidths=0.5,
square=True, cbar=False, mask=(data_special != 1) | up_triang, ax=ax)
ax.plot([0, N, 0, 0], [0, N, N, 0], clip_on=False, color='black', lw=2)
ax.tick_params(left=False, bottom=False)
plt.show()
An alternative approach, when there is only one color for the special cells, is to use an "under" color for the colormap, and give these cells negative values. An additional benefit is that the color can be shown in the colorbar. Here is some sample code:
N = 10
data = np.random.uniform(0, 45, size=(N, N))
for x, y in np.random.randint(0, N, 50).reshape(-1, 2):
data[x, y] = np.nan
data_special = np.random.randint(0, 5, size=(N, N)) // 4
data[data_special == 1] = -1
df = pd.DataFrame(data)
up_triang = np.triu(np.ones_like(data)).astype(bool)
cmap = sns.color_palette('mako', as_cmap=True).copy()
cmap.set_under('crimson ')
ax = sns.heatmap(df, cmap=cmap, xticklabels=True, yticklabels=True, square=True,
linecolor='white', linewidths=0.5, cbar=True, mask=df.isnull() | up_triang,
cbar_kws={'shrink': 0.6, 'pad': 0, 'extend': 'min', 'extendrect': True}, vmin=0, vmax=45)
ax.plot([0, N, 0, 0], [0, N, N, 0], clip_on=False, color='black', lw=2)
ax.tick_params(left=False, bottom=False)
plt.show()

Custom xticks labels in loglog plot

A simple example is as follows:
import numpy as np
import numpy.random as npr
import matplotlib.pyplot as plt
N = 1000
x = np.linspace(1, 5, N)
y = npr.randint(1e16, size = N) / 1e16
y = np.sort(y)
fig, ax = plt.subplots()
ax.loglog(x, y, '.')
ax.grid(True, 'both')
Where I want to replace the xticks. So far everything I tried, failed to work:
ax.set_xticks([2, 3, 4], ['a', 'b', 'c'])
ax.xaxis.set_ticks_position('none')
ax.set_xticks([])
None of the above showed any effect. My goal is to replace the ticks with custom defined ticks (strings or integers). So instead of 2 x 10⁰ it should only be 2. Similar for other xticks.
Probably this is what you're after:
import numpy as np
import matplotlib.pyplot as plt
N = 1000
x = np.linspace(1, 5, N)
y = np.random.rand(N)
y = np.sort(y)
fig, ax = plt.subplots()
ax.loglog(x, y, '.')
ax.grid(True, 'both')
ax.set_xticks([2, 3, 4])
ax.set_xticklabels(['a', 'b', 'c'])
ax.minorticks_off()
plt.show()

Setting xticklabels, x axis formatting in matplotlib

I would like to format my x axis with the legend values at the mid point of each bar whilst retaining the gender group identification. I'd like lower the gender groups to sit below the other xticklabels for clarity.
To this point, I've added xticks but actually labeling them correctly and neatly is proving trickier.
from itertools import chain, cycle
import logging
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from pandas import DataFrame, Series
matplotlib.style.use("ggplot")
m = {"Males" : {"Yes": 2, "No": 8}}
w = {"Females": {"Yes": 3, "No": 7}}
data = {**m, **w}
df = DataFrame(data)
# relative freq table
df_ft = (df / df.sum() * 100).T
ax = plt.subplot(111)
df_ft.plot(ax=ax, kind="bar", ylim=(0, 90),
title="Would you prefer to work at home? (10 males, 10 females)",
rot=0)
plt.ylabel("Relative Frequency (%)")
midp = 0.125 # standard bar width/2
t_l = ax.get_xticks().tolist()
ticks = list(chain.from_iterable((t - midp, t + midp) for t in t_l))
ax.set_xticks(t_l + ticks)
plt.show()
The following might be what you're looking for.
from itertools import chain
import matplotlib
import matplotlib.pyplot as plt
from pandas import DataFrame
matplotlib.style.use("ggplot")
df = DataFrame({'Males': {'Yes': 2, 'No': 8}, 'Females': {'Yes': 3, 'No': 7}})
df_ft = (df / df.sum() * 100).T
ax = plt.subplot(111)
df_ft.plot(ax=ax, kind="bar", ylim=(0, 90),
title="Would you prefer to work at home? (10 males, 10 females)",
rot=0)
plt.ylabel("Relative Frequency (%)")
midp = 0.125 # standard bar width/2
t_l = ax.get_xticks().tolist()
ticks = list(chain.from_iterable((t - midp, t + midp) for t in t_l))
ax.set_xticks(t_l + ticks)
labels = [l for l in ax.get_xticklabels()]
for i,l in enumerate(labels[len(df_ft):]):
l.set_text(df_ft.columns[i % len(df_ft.columns)])
for i,l in enumerate(labels[:len(df_ft)]):
l.set_text("\n"+l.get_text())
ax.set_xticklabels(labels)
plt.savefig(__file__+".png")
plt.show()
Altair would do a great job here.
from altair import *
from pandas import DataFrame
df = DataFrame({'Males': {'Yes': 2, 'No': 8}, 'Females': {'Yes': 3, 'No': 7}})
df = df.stack().reset_index()
df.columns=['response','gender','count']
Vis #1
Chart(df).mark_bar().encode(x='gender',y='count',color='response').configure_cell(width=200, height=200)
Vis 2
Chart(df).mark_bar().encode(x=X('response', axis=False),
y=Y('count', axis=Axis(grid=False)),
color='response',
column=Column('gender', axis=Axis(axisWidth=1.0, offset=-8.0, orient='bottom'),scale=Scale(padding=30.0))).configure_cell(width=200, height=200).configure_facet_cell(strokeWidth=0)

Getting Colorbar instance of scatter plot in pandas/matplotlib

How do I get the internally created colorbar instance of a plot created by pandas.DataFrame.plot?
Here is an example for generating a colored scatter plot:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import itertools as it
# [ (0,0), (0,1), ..., (9,9) ]
xy_positions = list( it.product( range(10), range(10) ) )
df = pd.DataFrame( xy_positions, columns=['x','y'] )
# draw 100 floats
df['score'] = np.random.random( 100 )
ax = df.plot( kind='scatter',
x='x',
y='y',
c='score',
s=500)
ax.set_xlim( [-0.5,9.5] )
ax.set_ylim( [-0.5,9.5] )
plt.show()
which gives me a figure like this:
How do I get the colorbar instance in order to manipulate it, for instance for changing the label or setting the ticks?
pandas does not return the axis for the colorbar, therefore we have to locate it:
1st, let's get the figure instance: i.e., use plt.gcf()
In [61]:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import itertools as it
# [ (0,0), (0,1), ..., (9,9) ]
xy_positions = list( it.product( range(10), range(10) ) )
df = pd.DataFrame( xy_positions, columns=['x','y'] )
# draw 100 floats
df['score'] = np.random.random( 100 )
ax = df.plot( kind='scatter',
x='x',
y='y',
c='score',
s=500)
ax.set_xlim( [-0.5,9.5] )
ax.set_ylim( [-0.5,9.5] )
f = plt.gcf()
2, how many axes does this figure have?
In [62]:
f.get_axes()
Out[62]:
[<matplotlib.axes._subplots.AxesSubplot at 0x120a4d450>,
<matplotlib.axes._subplots.AxesSubplot at 0x120ad0050>]
3, The first axes (that is, the first one created), contains the plot
In [63]:
ax
Out[63]:
<matplotlib.axes._subplots.AxesSubplot at 0x120a4d450>
4, Therefore, the second axis is the colorbar axes
In [64]:
cax = f.get_axes()[1]
#and we can modify it, i.e.:
cax.set_ylabel('test')
It's not quite the same but you could just plot using matplotlib:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import itertools as it
# [ (0,0), (0,1), ..., (9,9) ]
xy_positions = list( it.product( range(10), range(10) ) )
df = pd.DataFrame( xy_positions, columns=['x','y'] )
# draw 100 floats
df['score'] = np.random.random( 100 )
fig = plt.figure()
ax = fig.add_subplot(111)
s = ax.scatter(df.x, df.y, c=df.score, s=500)
cb = plt.colorbar(s)
cb.set_label('desired_label')
ax.set_xlim( [-0.5,9.5] )
ax.set_ylim( [-0.5,9.5] )
plt.show()