Rectangular gradient in Compose - kotlin

I need to do a rectangular gradient border over an image, the edges should be of dark background color and closer to the center it should fade away to transparent. I was thinking about using radial gradient as I can make it transparent in the center.
val gradientBrush = Brush.radialGradient(
colors = listOf(Color.Transparent, MaterialTheme.colors.background)
)
Image(
painter = ...,
contentScale = ContentScale.Inside,
modifier = Modifier
.clip(RoundedCornerShape(48.dp))
.border(
180.dp,
gradientBrush ,
RoundedCornerShape(48.dp)
)
.wrapContentHeight()
.fillMaxWidth()
)
But this gives me a gradient in the form of a circle. I guess that with scaling I could make it oval. But I wonder is there any way I can make it rectangular? I was thinking along the lines of placing four gradients around the image, but they would overlap.

You can use linear gradient with stops, so middle part of your image will be transparent.
val gradientBrush = Brush.linearGradient(
0f to MaterialTheme.colors.background,
0.4f to Color.Transparent,
0.6f to Color.Transparent,
1f to MaterialTheme.colors.background,
)
By default it's horizontal, but you can use verticalGradient instead, or specify start/end parameters for custom direction.

Related

Python OpenCV Duplicate a transparent shape in the same image

I have an image of a circle, refer to the image attached below. I already retrieved the transparent circle and want to paste that circle back to the image to make some overlapped circles.
Below is my code but it led to the problem A, it's like a (transparent) hole in the image. I need to have circles on normal white background.
height, width, channels = circle.shape
original_image[60:60+height, 40:40+width] = circle
I used cv2.addWeighted but got blending issue, I need clear circles
circle = cv2.addWeighted(original_image[60:60+height, 40:40+width],0.5,circle,0.5,0)
original_image[60:60+rows, 40:40+cols] = circle
If you already have a transparent black circle, then in Python/OpenCV here is one way to do that.
- Read the transparent image unchanged
- Extract the bgr channels and the alpha channel
- Create a colored image of the background color and size desired
- Create similar sized white and black images
- Initialize a copy of the background color image for the output
- Define a list offset coordinates in the larger image
- Loop for over the list of offsets and do the following
- Insert the bgr image into a copy of the white image as the base image
- Insert the alpha channel into a copy of the black image for a mask
- composite the initialized output and base images using the mask image
- When finished with the loop, save the result
Input (transparent):
import cv2
import numpy as np
# load image with transparency
img = cv2.imread('black_circle_transp.png', cv2.IMREAD_UNCHANGED)
height, width = img.shape[:2]
print(img.shape)
# extract the bgr channels and the alpha channel
bgr = img[:,:,0:3]
aa = img[:,:,3]
aa = cv2.merge([aa,aa,aa])
# create whatever color background you want, in this case white
background=np.full((500,500,3), (255,255,255), dtype=np.float64)
# create white image of the size you want
white=np.full((500,500,3), (255,255,255), dtype=np.float64)
# create black image of the size you want
black=np.zeros((500,500,3), dtype=np.float64)
# initialize output
result = background.copy()
# define top left corner x,y locations for circle offsets
xy_offsets = [(100,100), (150,150), (200,200)]
# insert bgr and alpha into white and black images respectively of desired output size and composite
for offset in xy_offsets:
xoff = offset[0]
yoff = offset[1]
base = white.copy()
base[yoff:height+yoff, xoff:width+xoff] = bgr
mask = black.copy()
mask[yoff:height+yoff, xoff:width+xoff] = aa
result = (result * (255-mask) + base * mask)/255
result = result.clip(0,255).astype(np.uint8)
# save resulting masked image
cv2.imwrite('black_circle_composite.png', result)
# display result, though it won't show transparency
cv2.imshow("image", img)
cv2.imshow("aa", aa)
cv2.imshow("bgr", bgr)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:

Remove the border of a sf polygon when plotted with ggplot2 using geom_sf

I'm working with a shapefile converted from a raster with lots of little holes in it, therefore, the borders create big splodges in the shape when plotted.
I'm currently adding the polygon to the main plot with the below code. Despite setting the alpha value to 1 the colours are different even when both set to "red" which makes no sense to me.
geom_sf(data = filter(db, band == 9), aes(fill = "red"), colour = "red", alpha = 1)
Can I either:
Set the borders to the same colour as the fill?
Or remove the border entirely?
Or set the border colour to none?

How can the colors in a bar of a matplotlib stacked bar chart be specified individually?

I am making a "class prediction error" plot, wherein a model attempts to classify data into one of two classes. The plot shows the fraction of each class that is made up of the correct class and another class.
So, for the classes of signal and background, of those data classified as signal, most are correct, but some data are actually background, and of those data classified as background, most are correct, but some data are actually signal. Now, this means that I want to plot one bar for signal and to have signal (red) making up most of the bar and background (blue) making up the minority of the bar, and I want to plot one other bar for background and to have background (blue) making up most of the bar and signal (red) making up the minority of the bar.
I have the following code, but the order of the colors in the second bar (background) needs to be swapped. How might this be done? (I am also thinking of the possibility of having more than two classes.)
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
plt.rcParams["figure.figsize"] = [10, 10]
cc0 = 39695 # classified correctly background
ci0 = 18595 # classified incorrectly background
cc1 = 38801 # classified correctly signal
ci1 = 19556 # classified incorrectly signal
fractions_correct = (cc0, cc1)
fractions_incorrect = (ci0, ci1)
width = 0.9
ind = np.arange(2)
p1 = plt.bar(ind, fractions_correct, width, color='red')
p2 = plt.bar(ind, fractions_incorrect, width, bottom=fractions_correct, color='blue')
plt.xlabel('classification by model')
plt.ylabel('class case abundances')
plt.xticks(ind, ('signal', 'background'))
plt.yticks([])
plt.legend((p2[0], p1[0]), ('background', 'signal'), loc='center left', bbox_to_anchor=(1, 0.5));
plt.show()
You can pass color a list of parameter if the length of the list matches the number of bars.
color=["red","blue"]
p1 = plt.bar(ind, fractions_correct, width, color=color)
color=["blue","red"]
p2 = plt.bar(ind, fractions_incorrect, width, bottom=fractions_correct, color=color)
The fastest solution to this would be to add a list of colors to be mapped to the plot:
p1 = plt.bar(ind, fractions_correct, width, color=['red','blue'])
p2 = plt.bar(ind, fractions_incorrect, width, bottom=fractions_correct, color=['blue','red'])
A more comprehensive approach would be to change your approach for plotting, which I won't get into just yet because I don't know the scale of the problem you're trying to solve.

OpenGL glBlendFuncSeparate

I need some help with OpenGL textures masking. I have it working but need to find some other blending function parameters to work in other way.
Now I have:
//Background
...code...
glBlendFunc(GL_ONE, GL_ZERO);
...code
//Mask
...code...
glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ZERO);
...code...
//Foreground
...code
glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
...code
Now it sets foreground's opacity to 0 (fills with background texture) where mask is transparent. I need it to react to mask's colors. I mean something like setting foregrounds opacity depending on mask's color. For example if mask is black (0.0,0.0,0.0) then the opacity of that place in foreground is 0 (is filled with background), and if mask is white (1.0,1.0,1.0) then the opacity of foreground is 1 (not filled with background). It can be in reverse consequence (white = opacity 0, black = opacity 1). I just need it to work depending on color.
My current result's visualization bellow.
Background:
Mask (circle is transparent):
Foreground:
Result:
And I want it to work like this:
Background:
Mask (circle is white, background is black):
Foreground:
Result:
So that later it could be used like this:
Background:
Mask (circle is white, background is black):
Foreground:
Result:
Attempt with #Gigi solution:
Perhaps this is what you want:
1) Clear the destination image:
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
2) Draw the background, masking out the alpha channel:
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
3) Draw the "masking overlay", masking out the color channels:
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
4) Draw the foreground, enabling blending:
glEnable(GL_BLEND);
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE, GL_ZERO);
Note: The overlay image must have the alpha channel specified.

small scatter plot markers in matplotlib are always black

I'm trying to use matplotlib to make a scatter plot with very small gray points. Because of the point density, the points need to be small. The problem is that the scatter() function's markers seem to have both a line and a fill. When the markers are small, only the line is visible, not the fill, and the line isn't the right colour (it's always black).
I can get exactly what I want using gnuplot: plot 'nodes' with points pt 0 lc rgb 'gray'
How can I make very small gray points using matplotlib scatterplot()?
scatter([1,2,3], [2,4,5], s=1, facecolor='0.5', lw = 0)
This sets the markersize to 1 (s=1), the facecolor to gray (facecolor='0.5'), and the linewidth to 0 (lw=0).
If the marker has no face (cannot be filled, e.g. '+','x'), then the edgecolor has to be set instead of c, and lw should not be 0:
scatter([1,2,3], [2,4,5], marker='+', edgecolor='r')
The following will no work
scatter([1,2,3], [2,4,5], s=1, marker='+', facecolor='0.5', lw = 0)
because the edge/line will not be displayed, so nothing will be displayed.
The absolute simplest answer to your question is: use the color parameter instead of the c parameter to set the color of the whole marker.
It's easy to see the difference when you compare the results:
from matplotlib import pyplot as plt
plt.scatter([1,2,3], [3,1,2], c='0.8') # marker not all gray
plt.scatter([1,2,3], [3,1,2], color='0.8') # marker all gray
Details:
For your simple use case where you just want to make your whole marker be the same shade of gray color, you really shouldn't have to worry about things like face color vs edge color, and whether your marker is defined as all edges or some edges and some fill. Instead, just use the color parameter and know that your whole marker will be set to the single color that you specify!
In response to zwol's question in comment - my reputation is not high enough to leave comments, so this will have to do: In the event that your colors come from a colormap (i.e., are from a "sequence of values to be mapped") you can use color = as demonstrated in the following:
from matplotlib import pyplot
x = [1,5,8,9,5]
y = [4,2,4,7,9]
numSides = [2,3,1,1,5]
cmap = pyplot.cm.get_cmap("copper_r")
min, max = min(numSides), max(numSides)
for i in range(len(x)):
if numSides[i] >= 2:
cax = pyplot.scatter(x[i], y[i], marker = '+', s = 100, c = numSides[i], cmap = cmap)
cax.set_clim(min, max)
elif numSides[i] == 1:
pyplot.scatter(x[i], y[i], marker = '.', s = 40, color = cmap(numSides[i]))
fig = pyplot.gcf()
fig.set_size_inches(8.4, 6)
fig.savefig('figure_test.png', dpi = 200)
pyplot.show()