Import PDF Image From MatPlotLib to ReportLab - python-3.x

I am trying to insert a saved PDF image into a ReportLab flowable.
I have seen several answers to similar questions and many involve using Py2PDF like this:
import PyPDF2
import PIL
input1 = PyPDF2.PdfFileReader(open(path+"image.pdf", "rb"))
page0 = input1.getPage(0)
xObject = page0['/Resources']['/XObject'].getObject()
for obj in xObject:
#Do something here
The trouble I'm having is with a sample image I've saved from MatPlotLib as a PDF. When I try to access that saved image with the code above, it returns nothing under page0['/Resources']['/XObject'].
In fact, here's what I see when I look at page0 and /XObject:
'/XObject': {}
Here's the code I used to generate the PDF:
import matplotlib.pyplot as plt
import numpy as np
# Fixing random state for reproducibility
np.random.seed(19680801)
plt.rcdefaults()
fig, ax = plt.subplots()
# Example data
people = ('Tom', 'Dick', 'Harry', 'Slim', 'Jim')
y_pos = np.arange(len(people))
performance = 3 + 10 * np.random.rand(len(people))
error = np.random.rand(len(people))
ax.barh(y_pos, performance, xerr=error, align='center',
color='green', ecolor='black')
ax.set_yticks(y_pos)
ax.set_yticklabels(people)
ax.invert_yaxis() # labels read top-to-bottom
ax.set_xlabel('Performance')
ax.set_title('How fast do you want to go today?')
plt.savefig(path+'image.pdf',bbox_inches='tight')
Thanks in advance!

Related

How to extract only CR No only from image

Sample image
I need to extract CR No.from the sample image given above. Using Easyocr, I got the output in complex nested list form. How to update the code to filter out all the detected text/numbers and get only CR No. I am running out of ideas, and help will be appreciated. What I have tried so far-
#Import libraries
import os
import easyocr
import cv2
from matplotlib import pyplot as plt
import numpy as np
IMAGE_PATH = 'H://CDAC//Spyder_projects//CR_No//input_image//input7.jpg'
reader = easyocr.Reader(['en'])
result3 = reader.readtext(IMAGE_PATH)
result3
my_list2 = []
length = len(result3)
for i in range(length):
if (result3[i][1]) == 'CR No':
print(result3[i])
print(result3[i+1])
my_list2.append(result3[i+1]+result3[i])
print(my_list2)
print('The CR No is:', my_list2[0][1])
The expected output should be- 211022203481161

Why can't seaborn.pairplot finish drawing this plot?

I have a dataframe central
Then I want to plot the pairwise relationships between the columns with sns.pairplot(central). Could you please explain why the process just runs forever? I tried on both my laptop and Colab, but the problem persists.
import urllib3
%matplotlib inline
%config InlineBackend.figure_format = 'svg' # Change the image format to svg for better quality
import networkx as nx
import pandas as pd
import seaborn as sns
from scipy import stats
import matplotlib.pyplot as plt
## Import dataset
http = urllib3.PoolManager()
url = 'https://raw.githubusercontent.com/leanhdung1994/WebMining/main/airports.net'
f = http.request('GET', url)
open('airports.net', 'wb').write(f.data)
G = nx.read_pajek('airports.net', encoding = 'UTF-8')
G = nx.DiGraph(G)
## Compute measures of centrality
degree_central = nx.degree_centrality(G)
closeness_central = nx.closeness_centrality(G)
eigen_central = nx.eigenvector_centrality_numpy(G, max_iter = 200)
katz_central = nx.katz_centrality_numpy(G)
between_central = nx.betweenness_centrality(G)
pagerank = nx.pagerank_numpy(G)
[hub, authority] = nx.hits(G)
## Create a dataframe using with above calculated centralities
central = pd.DataFrame([degree_central, closeness_central, eigen_central, katz_central, between_central, hub, authority]).T
central.columns = ['degree', 'closeness', 'eigen', 'katz', 'between', 'hub', 'authority']
central
## Plot the pairwise relationships between centralities
sns.pairplot(central)
For reasons unknown to me, the histplot for column eigen_central has a problem determining a reasonable number of bins. The pairplot works with kde plots in the diagonal sns.pairplot(central, diag_kind="kde"), and the histplot for column eigen_central alone also does not work as expected. You can overcome this problem by defining the bin number:
sns.pairplot(central, diag_kws = {"bins": 10})
Output:
I will upvote any answer that can provide a reason why seaborn has problems defining the bins. This problem is seaborn-specific as plt.hist(central.eigen) works as expected but not sns.histplot(central.eigen).

Sending matplotlib image to pymsteams (cannot create new tag pymsteams)

I am using matplotlib to plot my image.
import pandas as pd
from matplotlib import pyplot as plt
x = ['09:30', '09:33', '09:40', '09:43', '09:50', '09:53', '10:00', '10:03', '10:10', '10:13']
y = ['3010.910000', '3011.650000', '3009.130000', '3011.500000', '3010.460000', '3010.950000', '3012.830000', '3013.120000', '3011.730000', '3010.130000']
matrix = pd.DataFrame({'Time': x, 'Quote': y})
matrix['Quote'] = matrix['Quote'].astype(float)
plt.plot('Time', 'Quote', data=matrix, color='mediumvioletred')
Here is the challenge now:
import pymsteams
web_hook = 'My Microsoft Teams URL https://outlook.office.com/webhook/blahblah'
teams_message = pymsteams.connectorcard(web_hook)
msg_section = pymsteams.cardsection()
msg_section.title('Title')
msg_section.addImage(image) #I want to add that plt image here
teams_message.addSection(msg_section)
teams_message.text("Some Message")
self.teams_message.send()
I have tried this (and I want this approach, using cache):
buf = io.BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
msg_section.addImage(buf.read())
I did try saving the image to local drive 'c:/temp/'. The code did not give any error msg, but the image on Teams was a blank image, even though the image is correct in c:/temp
In summary. A PNG image has to be converted to base64 string.
Please see the example below.
Note that I'm using Python 3.6.
Additionally image width seems to be limited in a Connector Card.
import numpy as np
import matplotlib.pyplot as plt
import base64
from io import BytesIO
import pymsteams
# generate fig
fig, ax = plt.subplots(1,1,figsize=(20,6))
ax.hist(np.random.normal(0, 1, 1000), bins=51, edgecolor='k', alpha=0.5);
buf = BytesIO()
fig.savefig(buf, format="png")
# get base64 string
data = base64.b64encode(buf.getbuffer()).decode("ascii")
encoded_fig = f"data:image/png;base64,{data}"
# send encoded_fig via webhook
web_hook = 'YOUR_WEBHOOK'
teams_message = pymsteams.connectorcard(web_hook)
msg_section = pymsteams.cardsection()
msg_section.title('Title')
msg_section.addImage(encoded_fig) #I want to add that plt image here
teams_message.addSection(msg_section)
teams_message.text("Some Message")
teams_message.send()
image_file = open('img/icon.png'), "rb").read()
ICON = "data:image/png;base64,{data}".format(data=b64encode(image_file).decode("ascii"))
#And in your Teams alert creation, you call:
section.activityImage(ICON)

How to convert bokeh plots to BytesIO object to encode the plot with base64 module

I have a plot object of bokeh where I plot sin(x) curve.
from math import *
from io import BytesIO
from bokeh.plotting import (figure, output_file, show)
from bokeh.io import (export_png, export_svgs)
import base64
import numpy as np
plot = figure(plot_width=1000, plot_height=500)
x = np.linspace(-2*np.pi, 2*np.pi, 1000)
y = np.array([sin(i) for i in x])
plot.line(x, y, line_width=1)
Now, instead of saving it to some html file by some name, output_file('sine.html') I want to create a BytesIO() object so that I can further do base64 encoding.
I kindly need community help.
The reason why I desire is in matplotlib I can export an image as BytesIO() object and work with it smoothly rendering it back in Flask or Dash app like this,
figfile = BytesIO()
plt.savefig(figfile, format='png')
plt.clf()
figfile.seek(0)
figdata_png = base64.b64encode(figfile.getvalue())
return figdata_png.decode('UTF-8')
and I want the same applicability with bokeh.
Please guide me with this.
Bokeh provides this functionality in bokeh.io.export.get_screenshot_as_png:
from bokeh.io.export import get_screenshot_as_png
img = get_screenshot_as_png(plot)
img is a PIL image instance which contains the image.
Off-topic: This can also be used to have the plot displayed as a PNG in JupyterLab. Just call get_screenshot_as_png(plot) and you are done.

Matplotlib.animation.FuncAnimation using pcolormesh

Python 3.5, windows 10 Pro.
I'm trying to continuously plot an 8x8 array of pixels (for the sake of the question I'll just use random data, but in the real thing I'm reading from a serial port).
I can do it using a while loop, but I need to switch over to matplotlib.animation.FuncAnimation and I can't get it to work. I've tried looking at the help files and tried to follow examples from matplotlib.org here, but I've not been able to follow it.
Can someone help me figure out how to continuously plot an 8x8 array of pixels using FuncAnimation and pcolormesh? Here is what I've got so far:
import scipy as sp
import matplotlib.pyplot as plt
from matplotlib import animation
plt.close('all')
y = sp.rand(64).reshape([8,8])
def do_something():
y = sp.rand(64).reshape([8,8])
fig_plot.set_data(y)
return fig_plot,
fig1 = plt.figure(1,facecolor = 'w')
plt.clf()
fig_plot = plt.pcolormesh(y)
fig_ani = animation.FuncAnimation(fig1,do_something)
plt.show()
If you want to see the while loop code, just so you know exactly what I'm trying to reproduce, see below.
import scipy as sp
import matplotlib.pyplot as plt
plt.figure(1)
plt.clf()
while True:
y = sp.rand(64).reshape([8,8])
plt.pcolormesh(y)
plt.show()
plt.pause(.000001)
I was able to find a solution using imshow instead of pcolormesh. In case anyone else is struggling with the same issues I had, I've posted the working code below.
import scipy as sp
import matplotlib.pyplot as plt
import matplotlib.animation as animation
Hz = sp.rand(64).reshape([8,8]) # initalize with random data
fig = plt.figure(1,facecolor='w')
ax = plt.axes()
im = ax.imshow(Hz)
im.set_data(sp.zeros(Hz.shape))
def update_data(n):
Hz = sp.rand(64).reshape([8,8]) # More random data
im.set_data(Hz)
return
ani = animation.FuncAnimation(fig, update_data, interval = 10, blit = False, repeat = False)
fig.show()

Resources