Matplotlib: how to change alpha of edges only - python-2.7

I have a scatterplot:
x=[0.1,0.2,0.3,0.4]
y=[0.1,0.3,0.4,0.6]
I would like to plot it adding transparency in each point, so I used
plt.scatter(x,y,alpha =0.5, marker='o',color='g', markersize=12)
However, what happens is that I get circles filled with green colours and with a transpacency all over. What I would like to get is transparency only in the inner region, and edges really visible, so that if I have may points close to each other, I can always see the borders.
Is there a way?

You can specify the edge- and facecolor independently. For the facecolor you can choose a color with an alpha of less then 1. To specify such color use an RGBA (red,green,blue,alpha) tuple.
import matplotlib.pyplot as plt
x=[0.1, 0.105, 0.2, 0.3, 0.4]
y=[0.1, 0.095, 0.3, 0.4, 0.6]
plt.scatter(x,y, s=144, marker='o', edgecolor='g', facecolor=(0,1,0,0.5), )
plt.show()

Related

Which GL blend mode for blending the same color in source and destination, and getting the same color back?

I have an texture that is with a solid background (let's say navy blue, #000080) and white text on it. Even though the texture is a single file with both background and text, I'd like to cause just the text to fade out.
I've prepared a second texture, just solid navy blue without any text. I'd like to "fade" the text out by modifying the texture's alpha layer, until just the second texture (blue with no text) remains.
My problem is that when I start making the front layer (color + text) transparent, the text fades out as I expect, but the resulting blue is darker. The blue I see is the background color blue (#000080), tinted dark by the semitransparent layer in front of it. After some reading, it looks like I want to modify OpenGL's blend mode for this part.
I'm looking for a blend mode that generates:
#000080 + #000080*tranparency = #000080
#000080 + #FFFFFF*transparency = #FFFFFF*transparency
I've tried GL_MIN and GL_MAX, but those don't seem to be the ones I'm looking for here...
You shouldn't need anything more than just:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_ADD);
glEnable(GL_BLEND);
Which corresponds to the following:
original_pixel = [0, 0, 0.5, 1]
incoming_pixel = [0, 0, 0.5, 0.5]
final_pixel = incoming_pixel * 0.5 + original_pixel * (1 - 0.5);
Which should leave the colour intact.
You shouldn't need the second texture - just draw an untextured quad with the correct colour.

matplotlib legend bars and texts are not aligned

I use matplotlib in python2.7 to get a figure with multiple trajectories. I am getting this figure as the output of my code:
However, as you see the title of each trajectory is not aligned with the corresponding color line. I played with the options of legend, but did not figure out the solution.
Do you have any idea?
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
liste = range(1,13)
labels = ['3-3','3-4','3-5','3-6','4-3','4-4',
'4-5','4-6','5-3','5-4','5-5','5-6',
'6-3','6-4','6-5','6-6']
plt.figure(1)
plt.subplot(2,1,1)
for cnt, j in enumerate(labels):
a1 = range(100) # iter
a2 = np.random.randint(10,size=[100]) # dnn
a3 = np.ones((100)) # optimal
if cnt == 0:
plt.plot(a1,a3,label='BS', color='blue')
plt.plot(a1, np.divide(a3,a3), color='blue')
title_font = {'size':'11', 'color':'black', 'weight':'normal',
'verticalalignment':'bottom'}
plt.plot(a1,a2,label=j, color='red')
plt.xlabel('episode')
plt.ylabel('cost')
plt.grid(True)
lgd=plt.legend(bbox_to_anchor=(0., 1.0, 1.0, 0.102),
loc=3, ncol=len(liste), mode="expand", borderaxespad=0.)
plt.show()
The legend handles and labels do not fit into the legend box. You may see that when removing the mode="expand" label.
To get the legend entries take less space, use the handlelength, handletextpad and the columnspacing and play with the parameters until they fit. If that would still not be the case, using less columns is necessary. Set the ncols to a lower number.
E.g. with the following
lgd=plt.legend(bbox_to_anchor=(0., 1.02, 1.0, 0.102),
handlelength=0.9, handletextpad=0.3,columnspacing=0.7,
loc=3, ncol=9, mode="expand", borderaxespad=0.)
one would get an image with all legend entries fitting

Extracting a laser line in an image (using OpenCV)

i have a picture from a laser line and i would like to extract that line out of the image.
As the laser line is red, i take the red channel of the image and then searching for the highest intensity in every row:
The problem now is, that there are also some points which doesnt belong to the laser line (if you zoom into the second picture, you can see these points).
Does anyone have an idea for the next steps (to remove the single points and also to extract the lines)?
That was another approach to detect the line:
First i blurred out that "black-white" line with a kernel, then i thinned(skeleton) that blurred line to a thin line, then i applied an OpenCV function to detect the line.. the result is in the below image:
NEW:
Now i have another harder situation.
I have to extract a green laser light.
The problem here is that the colour range of the laser line is wider and changing.
On some parts of the laser line the pixel just have high green component, while on other parts the pixel have high blue component as well.
Getting the highest value in every row will always output a value, instead of ignoring when the value isn't high enough. Consider using a threshold too, so that you can discard ones that aren't high enough.
However, that's not a very efficient way to do this at all. A much better and easier solution would be to use the OpenCV function inRange(); define a lower and upper bound for the red color in all three channels, and this will return a binary image with white pixels where the image intensity is within that BGR range.
This is in python but it does the job, should be easy to see how to use the function:
import cv2
import numpy as np
img = cv2.imread('image.png')
lowerb = np.array([0, 0, 120])
upperb = np.array([100, 100, 255])
red_line = cv2.inRange(img, lowerb, upperb)
cv2.imshow('red', red_line)
cv2.waitKey(0)
This produces the output:
This could be further processed by finding contours or other methods to turn the points into a nice curve.
I'm really sorry for the short answer without any code, but I suggest you take contours and process them.
I dont know exact what you need, so here are two approaches for you:
just collect as much as possible contours on single line (use centers and try find straight line with smallest mean)
as first way, but trying heuristically combine separated lines.... it's much harder, but this may give you almost full laser line from image.
--
Some example for yours picture:
import cv2
import numpy as np
import math
img = cv2.imread('image.png')
hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
# filtering red area of hue
redHueArea = 15
redRange = ((hsv[:, :, 0] + 360 + redHueArea) % 360)
hsv[np.where((2 * redHueArea) > redRange)] = [0, 0, 0]
# filtering by saturation
hsv[np.where(hsv[:, :, 1] < 95)] = [0, 0, 0]
# convert to rgb
rgb = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB)
# select only red grayscaled channel with low threshold
gray = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY)
gray = cv2.threshold(gray, 15, 255, cv2.THRESH_BINARY)[1]
# contours processing
(_, contours, _) = cv2.findContours(gray.copy(), cv2.RETR_LIST, 1)
for c in contours:
area = cv2.contourArea(c)
if area < 8: continue
epsilon = 0.1 * cv2.arcLength(c, True) # tricky smoothing to a single line
approx = cv2.approxPolyDP(c, epsilon, True)
cv2.drawContours(img, [approx], -1, [255, 255, 255], -1)
cv2.imshow('result', img)
cv2.waitKey(0)
In your case it's work perfectly, but, as i already said, you will need to do much more work with contours.

Difference between plt.subplots() and plt.figure()

In python matplotlib, there are two convention used to draw plots:
1.
plt.figure(1,figsize=(400,8))
2.
fig,ax = plt.subplots()
fig.set_size_inches(400,8)
Both have different ways of doing the same thing. eg defining axis label.
Which one is better to use? What is the advantage of one over the other?
Or what is the "Good Practice" for plotting a graph using matplotlib?
Although #tacaswell already gave a brief comment on the key difference. I will add more to this question only from my own experience with matplotlib.
plt.figure just creates a Figure (but with no Axes in it), this means you have to specify the ax to place your data (lines, scatter points, images). Minimum code should look like this:
import numpy as np
import matplotlib.pyplot as plt
# create a figure
fig = plt.figure(figsize=(7.2, 7.2))
# generate ax1
ax1 = fig.add_axes([0.1, 0.1, 0.5, 0.5])
# generate ax2, make it red to distinguish
ax2 = fig.add_axes([0.6, 0.6, 0.3, 0.3], fc='red')
# add data
x = np.linspace(0, 2*np.pi, 20)
y = np.sin(x)
ax1.plot(x, y)
ax2.scatter(x, y)
In the case of plt.subplots(nrows=, ncols=), you will get Figure and an array of Axes(AxesSubplot). It is mostly used for generating many subplots at the same time. Some example code:
def display_axes(axes):
for i, ax in enumerate(axes.ravel()):
ax.text(0.5, 0.5, s='ax{}'.format(i+1), transform=ax.transAxes)
# create figures and (2x2) axes array
fig, axes = plt.subplots(2, 2, figsize=(7.2, 7.2))
# four (2*2=4) axes
ax1, ax2, ax3, ax4 = axes.ravel()
# for illustration purpose
display_axes(axes)
Summary:
plt.figure() is usually used when you want more customization to you axes, such as positions, sizes, colors and etc. You can see artist tutorial for more details. (I personally prefer this for individual plot).
plt.subplots() is recommended for generating multiple subplots in grids. You can also achieve higher flexibility using 'gridspec' and 'subplots', see details here.

Hatch filling becomes faint in postcript matplotlib

(i) I needed to show 3 overlapping bands, which IS NOT GOOD if three colours (with controlled opacity) are used.
(ii) Then I needed hatch fill_between for one band. The code is given below. (iii) Now I am facing problems with opacity of colours while exporting in .ps or .eps. Pdf output looks fine, but while put in paper (latex;kile) they appear fainter. Anyway I only need the fig in .ps or .eps format. It can be got using 'pdf2ps' but the output .ps file in this case looks vanishingly faint in the paper (latex). PLEASE suggest a way to get .ps or .eps (vector format only) output from this. Thanks.
from matplotlib import rc
rc('font',**{'family':'sans-serif','sans-serif':['Helvetica']})
## for Palatino and other serif fonts use:
#rc('font',**{'family':'serif','serif':['Palatino']})
rc('text', usetex=True)
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
lcrit=0.5-np.sqrt(5)/6
l,r1,r2,r3,r4,r5,r6,zn2=np.loadtxt("stiff_reso.d",usecols=(0,1,2,3,4,5,6,7),unpack=True)
plt.plot(l,r1,linewidth=2,color="green")
plt.plot(l,r2,linewidth=2,color="green")
plt.plot(l,r3,linewidth=2,color="black")
plt.plot(l,r4,linewidth=2,color="black")
plt.plot(l,r5,linewidth=2,color="red")
plt.plot(l,r6,linewidth=2,color="red")
plt.fill_between(l,r2,r1, color='green',alpha=0.4)
plt.fill_between(l,r4,r3, color="none",hatch="/",edgecolor="k")
plt.fill_between(l,r6,r5, color='red',alpha=0.4)
plt.plot([lcrit,lcrit], [0,25], color='purple', linestyle='dashed', linewidth=2)
plt.ylabel(r"$(a_-/a_E)$",fontsize=20)
plt.xlabel(r"$\Lambda/(\kappa \rho_c)$",fontsize=20)
ax= plt.gca()
plt.xlim([0,0.14])
plt.ylim([1,5.5])
plt.text(0.122, 2.0, r'$\Lambda=\Lambda_{crit}$',rotation='vertical', fontsize=16)
p1 = Rectangle((0, 0), 1, 1, fc="green",alpha=0.4)
p2 = Rectangle((0, 0), 1, 1,hatch="//",edgecolor="k")
p3 = Rectangle((0, 0), 1, 1, fc="red",alpha=0.4)
plt.legend([p1,p2,p3], ["1st resonance band","2nd resonance band","3rd resonance band"],loc=2)
#plt.savefig("reso_stiff.eps")
plt.savefig("reso_stiff.pdf")
plt.show()