how can I add two different images to my code? - python

I'm trying to add two different images (png) to my code and The result shows me the same image twice,I tried to add the different image to the same code but it showed me an error, I tried to change the names of the function but did not giveת I tried to download the image under a different name, how can I solve it?
this is my code :
from pptx import Presentation
from pptx.chart.data import CategoryChartData
from pptx.enum.chart import XL_CHART_TYPE
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.chart.data import ChartData
import matplotlib.pyplot as plt
import pandas as pd
import sys
from SQLConnector import SQLConnector
import seaborn as sns
from pptx.util import Inches
from PIL import Image
def px_to_inches(path):
im = Image.open(path)
width = im.width / im.info['dpi'][0]
height = im.height / im.info['dpi'][1]
return (width, height)
def sick_percentage():
bi_sql = SQLConnector(db='bi')
sql_query = "<some query>"
data_from_bi = bi_sql.query_by_str(sql_query)
return data_from_bi
df = sick_percentage()
prs = Presentation()
# create presentation with 1 slide ------
slide = prs.slides.add_slide(prs.slide_layouts[5])
# define chart data ---------------------
title = slide.shapes.title
title.text = "<title>"
# define chart data ---------------------
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
df.plot(x='date', y='positives', kind='bar', color='orange', ax=ax1)
df['percent_positive'].plot(x='date', kind='line', marker='d', ax=ax2)
ax1.yaxis.tick_right()
ax2.yaxis.tick_left()
plt.savefig('graph.png')
img = px_to_inches('graph.png')
slide_size = (16, 9)
left = Inches(slide_size[0] - img[0]) / 5.5
top = Inches(slide_size[1] - img[1]) / 2
pic = slide.shapes.add_picture('graph.png', left, top)
img = px_to_inches('pkar.png')
slide_size = (4,5)
left = Inches(slide_size[0] - img[0]) / 10
top = Inches(slide_size[1] - img[1]) / 2
pic = slide.shapes.add_picture('pkar.png', left, top)
prs.save('chart-01.pptx')

I don't know exactly how these modules work, but I think your problem is due to setting img and pic to the two different images.
I would guess that the presentation isn't saved until you call prs.save, and at that point it renders all of the slides. When this is called, img and pic both refer to pkar.png.
It might be a better practice to always name the pic/img based on the slide number, ie first slide has img1 and pic1, second slide has img2 and pic2, etc. Better yet, give them informative names, like "img_graph" and "pic_graph", or even better "img_pi_graph_users", etc. That way you aren't overwriting variables, and if you end up with much longer code, the variables are named in a way that you don't have to look back to what you set them to previously.

Related

Python: how could this image be properly segmented?

I would like to segment (isolate) the rod-like structures shown in this image:
The best I've managed to do is this
# Imports the libraries.
from skimage import io, filters
import matplotlib.pyplot as plt
import numpy as np
# Imports the image as a numpy array.
img = io.imread('C:/Users/lopez/Desktop/Test electron/test.tif')
# Thresholds the images using a local threshold.
thresh = filters.threshold_local(img,301,offset=0)
binary_local = img > thresh # Thresholds the image
binary_local = np.invert(binary_local) # inverts the thresholded image (True becomes False and vice versa).
# Shows the image.
plt.figure(figsize=(10,10))
plt.imshow(binary_local,cmap='Greys')
plt.axis('off')
plt.show()
Which produces this result
However, as you can see from the segmented image, I haven't managed to isolate the rods. What should be black background is filled with interconnected structures. Is there a way to neatly isolate the rod-like structures from all other elements in the image?
The original image can be downloaded from this website
https://dropoff.nbi.ac.uk/pickup.php
Claim ID: qMNrDHnfEn4nPwB8
Claim Passcode: UkwcYoYfXUfeDto8
Here is my attempt using a Meijering filter. The Meijering filter relies on symmetry when it looks for tubular structures and hence the regions where rods overlap (breaking the symmetry of the tubular shape) are not that well recovered, as can be seen in the overlay below.
Also, there is some random crap that I have trouble getting rid off digitally, but maybe you can clean your prep a bit more before imaging.
#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
from skimage.io import imread
from skimage.transform import rescale
from skimage.restoration import denoise_nl_means
from skimage.filters import meijering
from skimage.measure import label
from skimage.color import label2rgb
def remove_small_objects(binary_mask, size_threshold):
label_image = label(binary_mask)
object_sizes = np.bincount(label_image.ravel())
labels2keep, = np.where(object_sizes > size_threshold)
labels2keep = labels2keep[1:] # remove the first label, which corresponds to the background
clean = np.in1d(label_image.ravel(), labels2keep).reshape(label_image.shape)
return clean
if __name__ == '__main__':
raw = imread('test.tif')
raw -= raw.min()
raw /= raw.max()
# running everything on the large image took too long for my patience;
raw = rescale(raw, 0.25, anti_aliasing=True)
# smooth image while preserving edges
smoothed = denoise_nl_means(raw, h=0.05, fast_mode=True)
# filter for tubular shapes
sigmas = range(1, 5)
filtered = meijering(smoothed, sigmas=sigmas, black_ridges=False)
# Meijering filter always evaluates to high values at the image frame;
# we hence set the filtered image to zero at those locations
frame = np.ones_like(filtered, dtype=np.bool)
d = 2 * np.max(sigmas) + 1 # this is the theoretical minimum ...
d += 2 # ... but doesn't seem to be enough so we increase d
frame[d:-d, d:-d] = False
filtered[frame] = np.min(filtered)
thresholded = filtered > np.percentile(filtered, 80)
cleaned = remove_small_objects(thresholded, 200)
overlay = raw.copy()
overlay[np.invert(cleaned)] = overlay[np.invert(cleaned)] * 2/3
fig, axes = plt.subplots(2, 3, sharex=True, sharey=True)
axes = axes.ravel()
axes[0].imshow(raw, cmap='gray')
axes[1].imshow(smoothed, cmap='gray')
axes[2].imshow(filtered, cmap='gray')
axes[3].imshow(thresholded, cmap='gray')
axes[4].imshow(cleaned, cmap='gray')
axes[5].imshow(overlay, cmap='gray')
for ax in axes:
ax.axis('off')
fig, ax = plt.subplots()
ax.imshow(overlay, cmap='gray')
ax.axis('off')
plt.show()
If this code makes it into a paper, I want an acknowledgement and a copy of the paper. ;-)

Calculating NDVI from a NIR Image of a Plant

I'm trying to get the NDVI of a plant image. This is my first time doing this so I'm not sure if the steps I've taken are correct. In the second block, I added a colormap to the NIR Image and then split the channels so I can use the NDVI formula for the NIR channel and the Red channel. In the last block I applied the formula and plotted the image. The resulting values in the second block kinda look off to me, but I'm not sure how check if this is correct.
import os
from PIL import Image
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from IPython.display import display
import cv2
import cmapy
img_path = os.getcwd() + "/plant.png"
img = Image.open(img_path)
plt.figure(figsize = (10,10))
test_img = img
plt.imshow(test_img)
NIR Image:
test_img2 = cv2.imread(img_path)
img_c = cv2.applyColorMap(test_img2, cmapy.cmap('Reds')).astype(np.int)
_, R, NIR = cv2.split(img_c)
plt.figure(figsize = (10,10))
plt.imshow(img_c)
plt.show()
Adding colormap:
ndvi = (NIR-R)/(NIR+R+0.01)
print(ndvi.max()) 0.9999029220464032
print(ndvi.mean()) 0.10046810466714343
print(ndvi.min()) 0.01999960000799984
plt.figure(figsize = (10,10))
plt.imshow(ndvi)
plt.show()
After calculating NDVI:

Jupyter Lab interactive image display : issue with widgets arrangements using HBox

I am trying to change content of an image interactively using a slider (e.g. for applying a threshold operation with different values).
My code is as follows:
#%matplotlib ipympl
%matplotlib widget
import matplotlib.pyplot as plt
import cv2
import numpy as np
import ipywidgets as widgets
from ipywidgets import HBox, IntSlider
from IPython.display import Image
def update_lines(change):
ret,thresh2 = cv2.threshold(img_gray,change.new,255,cv2.THRESH_BINARY)
plt.imshow(thresh2)
fig.canvas.flush_events()
image = cv2.imread("Untitled.jpg")
img_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret,thresh2 = cv2.threshold(img_gray,30,255,cv2.THRESH_BINARY)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
slider = IntSlider(
orientation='vertical',
step=1,
value=127,
min=0,
max=255
)
display(HBox([slider, fig.canvas]))
slider.observe(update_lines, names='value')
When executing my code, I have an unexpected behavior: the figure is displayed twice, the first time when I do fig = plt.figure() and the second time when I do display(HBox([slider, fig.canvas])) => see The figure is displayed twice.
How can I display the image only into the HBox ?
When I change the value with the slider, I have the following result => After changing value
It seems that matplotlib cannot directly be persuaded to plot the figure at the figure() call, but it's possible to encapsulate it in an Output widget (taken from here):
output = widgets.Output()
with output:
fig = plt.figure()
# fill figure with content here
display(HBox([slider, output]))
That way, the plot is correctly displayed once.

Rendering a CSV with pixel values to an image with PyPlot

I try to draw white black line picture as the raw data in CSV.
1 is black and 0 is white.
So I can modify value between 1~0 to draw gray level picture in the future.
I encounter a problem. The output picture resolution does not follow raw data.
Original raw data has 1080*2160 value between 1~0. 1*1 scale is a pixel.
import matplotlib.pyplot as plt
data = pd.read_csv('python line.csv', encoding='big5')
fig, ax = plt.subplots()
heatmap = ax.pcolor(data, cmap=plt.cm.Greys)
ax.invert_yaxis()
ax.xaxis.tick_top()
I think that everything is fine with your code, but the size of the pyplot figure forces the irregular "bands" you are seeing in your image.
If you increase the figure size, this might help your image quality. To do that, you do plt.figure(figsize=(10,20)) for a 10 inch x 20 inch image. The example I have below uses a smaller image, but you should be able to scale it by changing the values.
I suggest you use the Python Image Library (PIL). Here's how I would implement this with tools available in the Anaconda distribution:
from PIL import Image
import random
import pandas as pd
import matplotlib.pyplot as plt
import math
import random
%matplotlib inline
df = pd.DataFrame()
for i in range(200):
#df[i] = [1 if i % 2 == 0 else 0 for i in range(100)]
df[i] = [random.uniform(0, 1) for i in range(100)]
df.to_csv('data.csv', index=False)
df1 = pd.read_csv('data.csv')
im1 = Image.new('RGBA', (200,100),'white')
pixels = []
white = (255,255,255)
black = (0,0,0)
for i, row in df1.iterrows():
for j in range(df1.shape[1]):
c = math.floor(float(row[j])*255)
pixels.append((c,c,c))
im1.putdata(pixels)
plt.figure(figsize=(10,5))
imgplot = plt.imshow(im1)

Multiple matplotlib plots in reportlab

I'm trying to put a matplotlib graph onto a reportlab canvas. I can do a simple graph with the code from this question: How to drawImage a matplotlib figure in a reportlab canvas?
But when I try to use subplots or use multiple plots it will not work properly. Doing it this way causes the same image to be plotted twice even when I added things like imgdata.close() or deleting the figure:
from matplotlib.figure import Figure
import cStringIO
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
can = canvas.Canvas()
self.f = Figure()
plot(x,y)
xlabel(xlbl)
ylabel(ylbl)
imgdata=cStringIO.StringIO()
savefig(imgdata,format='png')
imgdata.seek(0)
Image = ImageReader(imgdata)
can.drawImage(Image,100,250, width=400,height=350)
self.g = Figure()
plot(x,y)
xlabel(xlbl)
ylabel(ylbl)
secondimgdata = cStringIO.StringIO()
savefig(secondimgdata,format='png')
secondimgdata.seek(0)
Image2 = ImageReader(secondimgdata)
can.drawImage(Image2,100,150, width=400,height=350)
When trying with subplots it simply produces a blank graph and I did not know where to go with it:
self.f = Figure()
self.a = self.f.add_subplot(111)
self.a.plot(x,y)
self.a2 =self.a.twinx()
self.a2.plot(x,y2,'r')
self.a2.set_ylabel(ylbl2)
self.a.set_xlabel(xlbl)
self.a.set_ylabel(ylbl)
Any solution or advice to this problem would be very much appreciated.
The key is that you must use plt.close() after you're done adding images. Here's a quick example that works for me using seaborn and barplot. Assume I have a dataframe with different data that I want plotted over a few figures.
import matplotlib.pyplot as plt
import seaborn as sns
import cStringIO
from reportlab.platypus import Image
my_df = <some dataframe>
cols_to_plot = <[specific columns to plot]>
plots = []
def create_barplot(col):
sns_plot = sns.barplot(x='col1', y=col, hue='col2', data=my_df)
imgdata = cStringIO.StringIO()
sns_plot.figure.savefig(imgdata, format='png')
imgdata.seek(0)
plots.append(Image(imgdata))
plt.close() # This is the key!!!
for col in cols_to_plot:
create_barplot(col)
for barplot in plots:
story.append(barplot)
This isn't an ideal solution as it has to save the file as an image instead of using StringIO but it works.
import Image as image
from matplotlib.pyplot import figure
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
can = canvas.Canvas()
self.f = figure()
self.a = self.f.add_subplot(2,1,1)
self.a.plot(x,y)
self.a2 =self.a.twinx()
self.a2.plot(x,y2,'r')
self.a2.set_ylabel(ylbl2,color='r')
self.a.set_xlabel(xlbl)
self.a.set_ylabel(ylbl,color='b')
self.f.savefig('plot.png',format='png')
image.open('plot.png').save('plot.png','PNG')
can.drawImage('plot.png',100,250, width=400,height=350)

Categories