how to draw shapes (ellipses, rectange, circle, etc) with line width thicker than 1 pixel - width

The skimage.draw module has functions to draw circles, ellipses, lines, etc. However the line width seems to be fixed at 1 pixel. There doesn't appear to be a parameter to set the line width.
Stefan van der Walt suggested that there is hidden functionality in the skimage.measure submodule to draw thicker lines, but I had a look at the documentation and only saw the profile_line function which does have a linewidth parameter. I don't know if this what he meant, or how I can use that to draw an ellipse with width=3.
So how can I draw an ellipse with thickness of 3 pixels into a numpy image array (type float)? Preferably using skimage.

I would use draw to draw a 1-pixel thick line, then use skimage.morphology.dilation to "thicken" that line:
import numpy as np
import matplotlib.pyplot as plt
from skimage import draw, morphology
image = np.zeros((128, 128))
rr, cc = draw.ellipse_perimeter(64, 64, 20, 10)
image[rr, cc] = 1
dilated = morphology.dilation(image, morphology.disk(radius=1))
fig, (ax0, ax1) = plt.subplots(1, 2)
ax0.imshow(image)
ax1.imshow(dilated)

I am trying to do the same thing.
Fortunately I just need to draw a bounding box, so I do it iteratively this way.
Not sure whether this approach is applicable to other shape or not.
for i in range(0,thickness):
rect = skimage.draw.rectangle_perimeter(start=(b[1]-i,b[0]-i)
,end(b[3]+i,b[2]+i),shape=(1024,1024))
skimage.draw.set_color(img_with_box,rect,(1.0,-1,-1))

Related

problem on filing up the colour between two index values

I have a timeseries data timeseries.txt. First I select a index value (here 50) and put a red line mark on that selected index value. And I want to highlight portion before(idx-20) and after(idx+20) the red line index value on the timeseries.
I wrote this code however i am able to put the red line mark on the timeseries but while using fill_betweenx it doesnot work. I hope experts may help me overcoming this problem.Thanks.
import matplotlib.pyplot as plt
import numpy as np
input_data=np.loadtxt("timeseries.txt")
time=np.arange(len(input_data))
plt.plot(time,input_data)
idx = [50]
mark = [time[i] for i in idx]
plt.plot(idx,[input_data[i] for i in mark], marker="|",color='red',markerfacecolor='none',mew=0.4,ms=30,alpha=2.0)
plt.fill_betweenx(idx-20,idx+20 alpha=0.25,color='lightsteelblue')
plt.show()
If you are looking for just a semi-transparent rectangle, you can use patches.Rectangle to draw one. Refer here. I have updated your code to add a rectangle. See if this meets your requirement. I have used a sine wave as I didn't have your data.
import matplotlib.pyplot as plt
import numpy as np
## Create sine wave
x = np.arange(100)
input_data=np.sin(2*np.pi*3*x/100)
time=np.arange(len(input_data))
plt.plot(time,input_data)
idx = [50]
mark = [time[i] for i in idx]
plt.plot(idx,[input_data[i] for i in mark], marker="|", color='red', markerfacecolor='none', mew=0.4,ms=30,alpha=2.0)
#plt.fill_betweenx(mark,idx-20,0, alpha=0.25,color='lightsteelblue')
# Create a Rectangle patch
import matplotlib.patches as patches
from matplotlib.patches import Rectangle
plt.gca().add_patch(Rectangle((idx[0]-20, -0.15), 40, .3, facecolor = 'lightsteelblue',fill=True,alpha=0.25, lw=0))
plt.show()
EDIT
Please refer to the Rectangle documentation provided earlier in the response. You will need to adjust the start coordinates (x,y) and the height and width to see how big/small you need the Rectangle. For eg: changing the rectangle code like this...
plt.gca().add_patch(Rectangle((idx[0]-10, -0.40), 20, 0.8, facecolor = 'lightsteelblue',fill=True,alpha=0.25, lw=0))
will give you this plot.

How to combine two geometries into one plot in Python

Question background: I am trying to make two geometries in a one plot in python. I have made one geometry which is an object having mesh as shown in figure below. The respective code is also mentioned here.
df_1_new = pd.DataFrame()
df_1_new['X_coordinate']=pd.Series(x_new)
df_1_new['Y_coordinate']=pd.Series(y_new)
df_1_new['node_number'] = df_1_new.index
df_1_new = df_1_new[['node_number','X_coordinate','Y_coordinate']]
plt.scatter(x_new, y_new)
plt.show
The second geometry, which is a circle and I made this geometry running below code.
from matplotlib import pyplot as plt, patches
plt.rcParams["figure.figsize"] = [9.00, 6.50]
plt.rcParams["figure.autolayout"] = True
fig = plt.figure()
ax = fig.add_subplot()
circle1 = plt.Circle((2, 2), radius=5, fill = False)
ax.add_patch(circle1)
ax.axis('equal')
plt.show()
My question: How can I combine both geometries mentioned above in a one plot. I would like to place my circle around my geometry (object). Geometry has a centroid (2, 2) and I want to place my circle's centroid exactly on the centroid of geometry therefore I will be having a circle around my geometry. What code I should write. Kindly help me on this.
For your reference: I want my plot just like in below picture.
you need to do all the plotting between the subplot creation and before you issue the plt.show() command, as any command after it will create a new figure.
from matplotlib import pyplot as plt, patches
plt.rcParams["figure.figsize"] = [9.00, 6.50]
plt.rcParams["figure.autolayout"] = True
fig = plt.figure()
ax = fig.add_subplot()
# other plt.scatter or plt.plot here
plt.scatter([3,4,5,6,4],[5,4,2,3,2]) # example
circle1 = plt.Circle((2, 2), radius=5, fill = False)
ax.add_patch(circle1)
ax.axis('equal')
plt.show()
image example
to get the points inside the circle, you need to play with the circle radius and center till you get it right.
something you can do is to make the circle at the np.median of your x and y values, so you are sure about the center position.

Putting text from one corner to the opposite one

I'd like my plot to have a background text to be stretched from one corner (say lower left) to the opposite corner. The x and y dimensions are not isometric and it's not a square plot, so a fixed angle of 45 degrees will not work.
So far I have the text starting in the correct corner. How can the text be rotated and stretched so it spans the entire plot?
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
# plot command not shown
ax.text(ax.get_xlim()[0], ax.get_ylim()[0] , 'PRELIMINARY' , rotation=45 )
To position something with respect to the subplot (the ax), it helps to work in axes coordinates. These go from 0,0 in the lower left to 1,1 in the top right. Putting the text at 0.5,0.5 would set it nicely centered.
To calculate the angle, one could divide the subplot's height in pixels by its width, then take the arc tangent, and convert from radians to degrees.
The optimal size for the text is harder to calculate. One would need to render it, measure it, change the font size and render it again. Or just manually try a few sizes until it looks OK.
Note that when the window size gets changed interactively, the text will stay nicely in the center, but the rotation will get a bit off.
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.text(0.5, 0.5, 'PRELIMINARY', transform=ax.transAxes, size=50,
rotation=np.degrees(np.arctan(ax.get_window_extent().height / ax.get_window_extent().width)),
ha='center', va='center')
plt.show()

Window size incorrect on matplotlib animation

Trying to get an animation of a rotating arrow in a Jupyter notebook.
Can't get the window size and circle display correct.
I'm trying to get an animation of a rotating arrow in matplotlib. This is part of a jupyter engineering mechanics book I'm building for my students.
The idea of the question is that the animation shows what the two dimensional force balance is of multiple vectors on a node (the black dot in the code).
The animation is based on the following three sources:
1) Drawing a shape
2) Matplotlib animation
3) Arrow animation
get_ipython().run_line_magic('matplotlib', 'inline')
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as patches
from matplotlib import animation, rc
from IPython.display import HTML
from math import degrees,radians,cos,sin,atan,acos,sqrt
# Create figure
fig, ax = plt.subplots()
# Axes labels and title are established
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_ylim(-100,100) #<---- This window size is not displayed
ax.set_xlim(-100,100) #<---- This window size is not displayed
ax.set_aspect('equal', adjustable='box')
#the circle
circle = plt.Circle((0, 0), radius=10, fc='black')
plt.gca().add_patch(circle) #<---- The circle is not displayed
#arrow1 (more arrows will me added)
arrow1x=[]
arrow1y=[]
arrow1dx=[]
arrow1dy=[]
for t in range(1000):
if t <= 250:
arrow1x.append(0)
arrow1y.append(0)
arrow1dx.append(t/250*100)
arrow1dy.append(0)
elif t <= 500:
arrow1x.append(0)
arrow1y.append(0)
arrow1dx.append(100)
arrow1dy.append(0)
elif t <= 750:
arrow1x.append(0)
arrow1y.append(0)
arrow1dx.append(100*cos(radians((t-500)/250*180.)))
arrow1dy.append(100*sin(radians((t-500)/250*180.)))
else:
arrow1x.append(0)
arrow1y.append(0)
arrow1dx.append((100-100*(t-750)/250)*-sin(radians((t-750)/250*180.)))
arrow1dy.append((100-100*(t-750)/250)*-sin(radians((t-750)/250*180.)))
patch = patches.Arrow(arrow1x[0], arrow1y[0], arrow1dx[0], arrow1dy[0])
#the animation (I have no idea how this works:)
def init():
ax.add_patch(patch)
return patch,
def animate(t):
ax.clear()
patch = plt.Arrow(arrow1x[t], arrow1y[t], arrow1dx[t], arrow1dy[t])
ax.add_patch(patch)
return patch,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=1000, interval=20,
blit=True)
HTML(anim.to_jshtml())
As a result of this code I would like to see a square screen with range (-100 x 100,-100 y 100), the black node and the arrow.
What I'm seeing is a square screen (0 x 1,0 y 1), the rotating arrow, and no black dot.
There is no error output in jupyter which makes this really difficult to follow. Additionally the code takes really long to compile, which is also something that is not desired for a webpage, if this keeps taking so long I think i should look in a pre-compiled image (any tips for that perhaps ?).
Thus for some reason the window size and the dot are not adopted, but as far as I'm seeing the code from the sources is adopted as depicted on the webpages.
You took inappropriate part of "Arrow animation". Since you have static elements on your plot, you don't want to fully clear your ax: you should remove one patch during execution of animate function. Just replace ax.clear() with the next lines:
global patch
ax.patches.remove(patch)

How to fill area under step curve using pyplot?

I have plotted two step curves using pyplot.step(), and I would like to shade in the area beneath these curves (ideally with transparent shading). pyplot.fill_between() assumes linear interpolation, whereas I want to see step interpolation, as displayed below:
How can I shade in the region beneath these curves? Transparent coloring would be great, as this would make clear where these curves overlap.
You can use the alpha value of the fill_between to make it semi-transparent.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,50,35)
y = np.random.exponential(1, len(x))
y2 = np.random.exponential(1, len(x))
plt.fill_between(x,y, step="pre", alpha=0.4)
plt.fill_between(x,y2, step="pre", alpha=0.4)
plt.plot(x,y, drawstyle="steps")
plt.plot(x,y2, drawstyle="steps")
plt.show()

Resources