Obtain plot data from JPEG or png file - python

I'm writing a program that obtains plot data from a graph(JPEG).
Vertical axis is logarithmic.
I successfully made a program that understands horizontal and vertical axes as linear (not logarithmic), see the code below:
%matplotlib inline
from PIL import Image
from scipy import *
from pylab import *
im = array(Image.open('fig1.jpg'))
hh = im.shape[0]
ww = im.shape[2]
imshow(im)
print(im[100,0,:])
Col = array([255,0,0])#赤
bnd = 30
yax = linspace(0.5,2e-4,hh)
xax = linspace(1,14,ww)
for i in range(hh):
for j in range(ww):
im[i,j,:] = 255*(any(im[i,j,:]>Col+bnd) or any(im[i,j,:]<Col-bnd))
mapim = abs(im[:,:,0]/255-1).astype(bool)
yval = array([average(yax[mapim[:,t]]) for t in range(ww)])
rlt = interp(range(100),xax,yval)
I have no idea how to modify it to make it understand logarithmic axis.
Please help me.

You just need to convert the y max and min to log scale:
ymax_lin = log10(0.5)
ymin_lin = log10(2e-4)
yax = linspace(ymax_lin,ymin_lin,hh)
and convert back to linear the yval values at the end:
yval = 10**yval
The full working code is here:
%matplotlib inline
from PIL import Image
from scipy import *
from pylab import *
im = array(Image.open('fig1.jpg'))
hh = im.shape[0]
ww = im.shape[1]
imshow(im)
print(im[100,0,:])
Col = array([255,0,0])
bnd = 30
ymax_lin = log10(0.5)
ymin_lin = log10(2e-4)
yax = linspace(ymax_lin,ymin_lin,hh)
xax = linspace(1,14,ww)
for i in range(hh):
for j in range(ww):
im[i,j,:] = 255*(any(im[i,j,:]>Col+bnd) or any(im[i,j,:]<Col-bnd))
mapim = abs(im[:,:,0]/255-1).astype(bool)
yval = array([average(yax[mapim[:,t]]) for t in range(ww)])
yval = 10**yval
rlt = interp(range(100),xax,yval)

Related

Is there a way to make a bit of gap between x-axis and the graph? (Python, bqplot)

I created a random number graph and I want to have a more gap between the x axis and the graph because it looks hard to read. Does anyone have a idea how to do that? Thank you so much. Here is my example code.
from bqplot import Axis, LinearScale, OrdinalScale, Scatter, Figure, Tooltip, DateScale, Lines, Bars
import bql
import pandas as pd
from numpy import nan, isnan
from numpy.random import randint
import numpy as np
x_sc_bar_fsa = OrdinalScale()
y_sc_bar_fsa = LinearScale()
tt_bar_fsa = Tooltip(fields=['x', 'y'], formats=['','.2f'])
bar_fsa = Bars(stroke = 'white',scales={'x': x_sc_bar_fsa, 'y': y_sc_bar_fsa},padding=0.5,\
tooltip=tt_bar_fsa, unhovered_style={'opacity': 0.9}, type = 'grouped')
ax_x_bar_fsa = Axis(scale=x_sc_bar_fsa)
ax_y_bar_fsa = Axis(scale=y_sc_bar_fsa, orientation='vertical',tick_format='0.2f')
#Final Output
fig_bar_fsa = Figure(title='Random Number Graph for Testing',marks=[], axes=[ax_x_bar_fsa, ax_y_bar_fsa],padding_x=0)
def plot_bars_fsa(x_data, y_data, label_data,colors=['darkblue','royalblue','darkgreen','darkred','red']):
if (len(x_data) == 0) | (len(y_data) == 0) | (len(label_data) == 0):
fig_bar_fsa.marks = [] #Creates empty list if x-data, y-data and label data is missing i.e. =0
else: #otherwise display
bar_fsa.x = x_data
bar_fsa.y = y_data
y_sc_bar_fsa.min = 0
y_sc_bar_fsa.max = np.nanmax([np.nanmax(x) for x in y_data]) * 1.1
bar_fsa.labels = label_data
bar_fsa.colors = colors # Defined above
ax_x_bar_fsa.tick_rotate = -90 # This is the angle of the letters on the graph
ax_x_bar_fsa.tick_style = {'text-anchor': 'end'}
fig_bar_fsa.marks = [bar_fsa] #links marks to bar chart
example_df = pd.DataFrame(data=randint(0, 100, size=(10, 5)),
columns=['column_' + str(i) for i in range(5)])
example_df.index = ['namenumber1253','namenumber26675','namenumber339', 'namenumber2556','namenumber3109', 'namenumber5894','namenumber1355','namenumber685890', 'namenumber397', 'namenumber85']
plot_bars_fsa(example_df.index.values,\
[example_df[x].values for x in ['column_0','column_1','column_2','column_3','column_4']],\
['column_0','column_1','column_2','column_3','column_4'])
fig_bar_fsa
enter image description here

Inverted svg image with svgpathtools

I'm trying to plot an svg image but it's showing up inverted, would anyone know how to fix this?
Input
<img src="https://static.wikia.nocookie.net/ptstarwars/images/9/9d/Jedi_symbol.svg" alt="drawing" style="width:200px;"/>
Code
import svgpathtools
import numpy as np
import matplotlib.pyplot as plt
svgpaths, attributes = svgpathtools.svg2paths('./jedi_symbol.svg')
paths = []
for n, (attrs, svgpath) in enumerate(zip(attributes, svgpaths)):
path = []
for segment in svgpath:
num_steps = int(segment.length()/0.5)
tt = np.linspace(0, 1, num_steps)
xy = np.array([segment.point(t) for t in tt])
if len(xy) > 0:
if path and xy[0] == path[-1]:
xy = xy[1:]
path.extend(xy)
paths.append(np.array(path))
paths = np.array(paths)
x_table, y_table = paths[0].real, paths[0].imag
# Simple method to center the image
x_table = x_table - min(x_table)
y_table = y_table - min(y_table)
x_table = x_table - max(x_table) / 2
y_table = y_table - max(y_table) / 2
fig, ax = plt.subplots(figsize=(5, 5))
ax.set_aspect('equal', 'datalim')
ax.plot(x_table, y_table)
Output
It just multiply the y by -1
ax.plot(x_table, -1*y_table)

ValueError: Invalid RGBA argument: What is the reason of this error?

I am trying to create a 2D colored bar chart
import numpy as np
import matplotlib.pyplot as plt
import pickle
from graphviz import Digraph
from torch.autograd import Variable
import argparse
def make_dot(var):
'''
Visualization of the computation graph
Taken from : https://github.com/szagoruyko/functional-zoo/blob/master/visualize.py
'''
node_attr = dict(style='filled',
shape='box',
align='left',
fontsize='12',
ranksep='0.1',
height='0.2')
dot = Digraph(node_attr=node_attr, graph_attr=dict(size="12,12"))
seen = set()
def add_nodes(var):
if var not in seen:
if isinstance(var, Variable):
value = '('+(', ').join(['%d' % v for v in var.size()])+')'
dot.node(str(id(var)), str(value), fillcolor='lightblue')
else:
dot.node(str(id(var)), str(type(var).__name__))
seen.add(var)
if hasattr(var, 'previous_functions'):
for u in var.previous_functions:
dot.edge(str(id(u[0])), str(id(var)))
add_nodes(u[0])
add_nodes(var.creator)
return dot
def plot_trajectories(true_trajs, pred_trajs, nodesPresent, obs_length, name, plot_directory, withBackground=False):
'''
Parameters
==========
true_trajs : Numpy matrix of shape seq_length x numNodes x 2
Contains the true trajectories of the nodes
pred_trajs : Numpy matrix of shape seq_length x numNodes x 2
Contains the predicted trajectories of the nodes
nodesPresent : A list of lists, of size seq_length
Each list contains the nodeIDs present at that time-step
obs_length : Length of observed trajectory
name : Name of the plot
withBackground : Include background or not
'''
traj_length, numNodes, _ = true_trajs.shape
# Initialize figure
plt.figure()
# Load the background
# im = plt.imread('plot/background.png')
# if withBackground:
# implot = plt.imshow(im)
# width_true = im.shape[0]
# height_true = im.shape[1]
# if withBackground:
# width = width_true
# height = height_true
# else:
width = 1
height = 1
traj_data = {}
for tstep in range(traj_length):
pred_pos = pred_trajs[tstep, :]
true_pos = true_trajs[tstep, :]
for ped in range(numNodes):
if ped not in traj_data and tstep < obs_length:
traj_data[ped] = [[], []]
if ped in nodesPresent[tstep]:
traj_data[ped][0].append(true_pos[ped, :])
traj_data[ped][1].append(pred_pos[ped, :])
for j in traj_data:
c = np.random.rand(3, 1)
true_traj_ped = traj_data[j][0] # List of [x,y] elements
pred_traj_ped = traj_data[j][1]
true_x = [(p[0]+1)/2*height for p in true_traj_ped]
true_y = [(p[1]+1)/2*width for p in true_traj_ped]
pred_x = [(p[0]+1)/2*height for p in pred_traj_ped]
pred_y = [(p[1]+1)/2*width for p in pred_traj_ped]
plt.plot(true_x, true_y, color=c, linestyle='solid', marker='o')
plt.plot(pred_x, pred_y, color=c, linestyle='dashed', marker='x')
if not withBackground:
plt.ylim((1, 0))
plt.xlim((0, 1))
# plt.show()
if withBackground:
plt.savefig('plot_with_background/'+name+'.png')
else:
plt.savefig(plot_directory+'/'+name+'.png')
plt.gcf().clear()
plt.close()
def main():
parser = argparse.ArgumentParser()
# Experiments
parser.add_argument('--test_dataset', type=int, default=0,
help='test dataset index')
# Parse the parameters
args = parser.parse_args()
# Save directory
save_directory = 'save/'
save_directory += str(args.test_dataset) + '/'
plot_directory = 'plot/'
f = open(save_directory+'/results.pkl', 'rb')
results = pickle.load(f)
# print "Enter 0 (or) 1 for without/with background"
# withBackground = int(input())
withBackground = 1
for i in range(len(results)):
print i
name = 'sequence' + str(i)
plot_trajectories(results[i][0], results[i][1], results[i][2], results[i][3], name, plot_directory, withBackground)
if __name__ == '__main__':
main()
Now I am unable to debug the Invalid RGBA argument because I don't understand what is causing the error. I even tried to use random colors instead with colors = np.random.rand(91,91,4) and still the error persists.
I have checked Stack Overflow posts regarding Invalid RGBA argument (for example this, this, this and this) and none of them seems to answer my problem.
I want to know what could be causing this error. I am using the standard Anaconda distribution for Python on Ubuntu Mate 16.
Could it be that due to recent updates in Python, the solution as in the original Stack Overflow post becomes obsolete?
Just replace
c = np.random.rand(3, 1)
with this:
c = np.random.rand(3)
It removes the error. matplotlib expects (3,) or (4,) shape for the c argument.

Creating a 2D Gaussian random field from a given 2D variance

I've been trying to create a 2D map of blobs of matter (Gaussian random field) using a variance I have calculated. This variance is a 2D array. I have tried using numpy.random.normal since it allows for a 2D input of the variance, but it doesn't really create a map with the trend I expect from the input parameters. One of the important input constants lambda_c should manifest itself as the physical size (diameter) of the blobs. However, when I change my lambda_c, the size of the blobs does not change if at all. For example, if I set lambda_c = 40 parsecs, the map needs blobs that are 40 parsecs in diameter. A MWE to produce the map using my variance:
import numpy as np
import random
import matplotlib.pyplot as plt
from matplotlib.pyplot import show, plot
import scipy.integrate as integrate
from scipy.interpolate import RectBivariateSpline
n = 300
c = 3e8
G = 6.67e-11
M_sun = 1.989e30
pc = 3.086e16 # parsec
Dds = 1097.07889283e6*pc
Ds = 1726.62069147e6*pc
Dd = 1259e6*pc
FOV_arcsec_original = 5.
FOV_arcmin = FOV_arcsec_original/60.
pix2rad = ((FOV_arcmin/60.)/float(n))*np.pi/180.
rad2pix = 1./pix2rad
x_pix = np.linspace(-FOV_arcsec_original/2/pix2rad/180.*np.pi/3600.,FOV_arcsec_original/2/pix2rad/180.*np.pi/3600.,n)
y_pix = np.linspace(-FOV_arcsec_original/2/pix2rad/180.*np.pi/3600.,FOV_arcsec_original/2/pix2rad/180.*np.pi/3600.,n)
X_pix,Y_pix = np.meshgrid(x_pix,y_pix)
conc = 10.
M = 1e13*M_sun
r_s = 18*1e3*pc
lambda_c = 40*pc ### The important parameter that doesn't seem to manifest itself in the map when changed
rho_s = M/((4*np.pi*r_s**3)*(np.log(1+conc) - (conc/(1+conc))))
sigma_crit = (c**2*Ds)/(4*np.pi*G*Dd*Dds)
k_s = rho_s*r_s/sigma_crit
theta_s = r_s/Dd
Renorm = (4*G/c**2)*(Dds/(Dd*Ds))
#### Here I just interpolate and zoom into my field of view to get better resolutions
A = np.sqrt(X_pix**2 + Y_pix**2)*pix2rad/theta_s
A_1 = A[100:200,0:100]
n_x = n_y = 100
FOV_arcsec_x = FOV_arcsec_original*(100./300)
FOV_arcmin_x = FOV_arcsec_x/60.
pix2rad_x = ((FOV_arcmin_x/60.)/float(n_x))*np.pi/180.
rad2pix_x = 1./pix2rad_x
FOV_arcsec_y = FOV_arcsec_original*(100./300)
FOV_arcmin_y = FOV_arcsec_y/60.
pix2rad_y = ((FOV_arcmin_y/60.)/float(n_y))*np.pi/180.
rad2pix_y = 1./pix2rad_y
x1 = np.linspace(-FOV_arcsec_x/2/pix2rad_x/180.*np.pi/3600.,FOV_arcsec_x/2/pix2rad_x/180.*np.pi/3600.,n_x)
y1 = np.linspace(-FOV_arcsec_y/2/pix2rad_y/180.*np.pi/3600.,FOV_arcsec_y/2/pix2rad_y/180.*np.pi/3600.,n_y)
X1,Y1 = np.meshgrid(x1,y1)
n_x_2 = 500
n_y_2 = 500
x2 = np.linspace(-FOV_arcsec_x/2/pix2rad_x/180.*np.pi/3600.,FOV_arcsec_x/2/pix2rad_x/180.*np.pi/3600.,n_x_2)
y2 = np.linspace(-FOV_arcsec_y/2/pix2rad_y/180.*np.pi/3600.,FOV_arcsec_y/2/pix2rad_y/180.*np.pi/3600.,n_y_2)
X2,Y2 = np.meshgrid(x2,y2)
interp_spline = RectBivariateSpline(y1,x1,A_1)
A_2 = interp_spline(y2,x2)
A_3 = A_2[50:450,0:400]
n_x_3 = n_y_3 = 400
FOV_arcsec_x = FOV_arcsec_original*(100./300)*400./500.
FOV_arcmin_x = FOV_arcsec_x/60.
pix2rad_x = ((FOV_arcmin_x/60.)/float(n_x_3))*np.pi/180.
rad2pix_x = 1./pix2rad_x
FOV_arcsec_y = FOV_arcsec_original*(100./300)*400./500.
FOV_arcmin_y = FOV_arcsec_y/60.
pix2rad_y = ((FOV_arcmin_y/60.)/float(n_y_3))*np.pi/180.
rad2pix_y = 1./pix2rad_y
x3 = np.linspace(-FOV_arcsec_x/2/pix2rad_x/180.*np.pi/3600.,FOV_arcsec_x/2/pix2rad_x/180.*np.pi/3600.,n_x_3)
y3 = np.linspace(-FOV_arcsec_y/2/pix2rad_y/180.*np.pi/3600.,FOV_arcsec_y/2/pix2rad_y/180.*np.pi/3600.,n_y_3)
X3,Y3 = np.meshgrid(x3,y3)
n_x_4 = 1000
n_y_4 = 1000
x4 = np.linspace(-FOV_arcsec_x/2/pix2rad_x/180.*np.pi/3600.,FOV_arcsec_x/2/pix2rad_x/180.*np.pi/3600.,n_x_4)
y4 = np.linspace(-FOV_arcsec_y/2/pix2rad_y/180.*np.pi/3600.,FOV_arcsec_y/2/pix2rad_y/180.*np.pi/3600.,n_y_4)
X4,Y4 = np.meshgrid(x4,y4)
interp_spline = RectBivariateSpline(y3,x3,A_3)
A_4 = interp_spline(y4,x4)
############### Function to calculate variance
variance = np.zeros((len(A_4),len(A_4)))
def variance_fluctuations(x):
for i in xrange(len(x)):
for j in xrange(len(x)):
if x[j][i] < 1.:
variance[j][i] = (k_s**2)*(lambda_c/r_s)*((np.pi/x[j][i]) - (1./(x[j][i]**2 -1)**3.)*(((6.*x[j][i]**4. - 17.*x[j][i]**2. + 26)/3.)+ (((2.*x[j][i]**6. - 7.*x[j][i]**4. + 8.*x[j][i]**2. - 8)*np.arccosh(1./x[j][i]))/(np.sqrt(1-x[j][i]**2.)))))
elif x[j][i] > 1.:
variance[j][i] = (k_s**2)*(lambda_c/r_s)*((np.pi/x[j][i]) - (1./(x[j][i]**2 -1)**3.)*(((6.*x[j][i]**4. - 17.*x[j][i]**2. + 26)/3.)+ (((2.*x[j][i]**6. - 7.*x[j][i]**4. + 8.*x[j][i]**2. - 8)*np.arccos(1./x[j][i]))/(np.sqrt(x[j][i]**2.-1)))))
variance_fluctuations(A_4)
#### Creating the map
mean = 0
delta_kappa = np.random.normal(0,variance,A_4.shape)
xfinal = np.linspace(-FOV_arcsec_x*np.pi/180./3600.*Dd/pc/2,FOV_arcsec_x*np.pi/180./3600.*Dd/pc/2,1000)
yfinal = np.linspace(-FOV_arcsec_x*np.pi/180./3600.*Dd/pc/2,FOV_arcsec_x*np.pi/180./3600.*Dd/pc/2,1000)
Xfinal, Yfinal = np.meshgrid(xfinal,yfinal)
plt.contourf(Xfinal,Yfinal,delta_kappa,100)
plt.show()
The map looks like this, with the density of blobs increasing towards the right. However, the size of the blobs don't change and the map looks virtually the same whether I use lambda_c = 40*pc or lambda_c = 400*pc.
I'm wondering if the np.random.normal function isn't really doing what I expect it to do? I feel like the pixel scale of the map and the way samples are drawn make no link to the size of the blobs. Maybe there is a better way to create the map using the variance, would appreciate any insight.
I expect the map to look something like this , the blob sizes change based on the input parameters for my variance :
This is quite a well visited problem in (surprise surprise) astronomy and cosmology.
You could use lenstool: https://lenstools.readthedocs.io/en/latest/examples/gaussian_random_field.html
You could also try here:
https://andrewwalker.github.io/statefultransitions/post/gaussian-fields
Not to mention:
https://github.com/bsciolla/gaussian-random-fields
I am not reproducing code here because all credit goes to the above authors. However, they did just all come right out a google search :/
Easiest of all is probably a python module FyeldGenerator, apparently designed for this exact purpose:
https://github.com/cphyc/FyeldGenerator
So (adapted from github example):
pip install FyeldGenerator
from FyeldGenerator import generate_field
from matplotlib import use
use('Agg')
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
# Helper that generates power-law power spectrum
def Pkgen(n):
def Pk(k):
return np.power(k, -n)
return Pk
# Draw samples from a normal distribution
def distrib(shape):
a = np.random.normal(loc=0, scale=1, size=shape)
b = np.random.normal(loc=0, scale=1, size=shape)
return a + 1j * b
shape = (512, 512)
field = generate_field(distrib, Pkgen(2), shape)
plt.imshow(field, cmap='jet')
plt.savefig('field.png',dpi=400)
plt.close())
This gives:
Looks pretty straightforward to me :)
PS: FoV implied a telescope observation of the gaussian random field :)
A completely different and much quicker way may be just to blur the delta_kappa array with gaussian filter. Try adjusting sigma parameter to alter the blobs size.
from scipy.ndimage.filters import gaussian_filter
dk_gf = gaussian_filter(delta_kappa, sigma=20)
Xfinal, Yfinal = np.meshgrid(xfinal,yfinal)
plt.contourf(Xfinal,Yfinal,dk_ma,100, cmap='jet')
plt.show();
this is image with sigma=20
this is image with sigma=2.5
ThunderFlash, try this code to draw the map:
# function to produce blobs:
from scipy.stats import multivariate_normal
def blob (positions, mean=(0,0), var=1):
cov = [[var,0],[0,var]]
return multivariate_normal(mean, cov).pdf(positions)
"""
now prepare for blobs generation.
note that I use less dense grid to pick blobs centers (regulated by `step`)
this makes blobs more pronounced and saves calculation time.
use this part instead of your code section below comment #### Creating the map
"""
delta_kappa = np.random.normal(0,variance,A_4.shape) # same
step = 10 #
dk2 = delta_kappa[::step,::step] # taking every 10th element
x2, y2 = xfinal[::step],yfinal[::step]
field = np.dstack((Xfinal,Yfinal))
print (field.shape, dk2.shape, x2.shape, y2.shape)
>> (1000, 1000, 2), (100, 100), (100,), (100,)
result = np.zeros(field.shape[:2])
for x in range (len(x2)):
for y in range (len(y2)):
res2 = blob(field, mean = (x2[x], y2[y]), var=10000)*dk2[x,y]
result += res2
# the cycle above took over 20 minutes on Ryzen 2700X. It could be accelerated by vectorization presumably.
plt.contourf(Xfinal,Yfinal,result,100)
plt.show()
you may want to play with var parameter in blob() to smoothen the image and with step to make it more compressed.
Here is the image that I got using your code (somehow axes are flipped and more dense areas on the top):

How to index List/ numpy array in order to plot the data with matplotlib

I have a function f(x,t) = cos(t)*t + x and i want to display the change of the result over the width x and time t at discretised time steps t_i and discretised width steps x_j.
Now I am a while here on SX and feel really embarrassed to only can post such little code or in other words nothing (since nothing worked I have done...):
Nevertheless if someone has the time to help, I`d appreciate it.
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as pyplot
from astropy.io.ascii.latex import AASTex
def func(xi, ti):
res = np.cos(ti)*ti + xi
return res
timeSpacing = 100
timeStart = 0
timeEnd = 1
time = np.linspace(timeStart, timeEnd, timeSpacing)
widthSpacing = 300
widthStart = 0
widthEnd = 3
width = np.linspace(widthStart, widthEnd, widthSpacing)
resultList = [None]*timeSpacing
resultListInner = [None]*widthSpacing
for i, ithTime in enumerate(time):
for j, jthWidth in enumerate(width):
aas = np.zeros_like(width)
aas.fill(ithTime)
resultListInner[j] = ithTime, jthWidth, func(jthWidth, aas)
resultList[i] = resultListInner
So how do I correctly index the list and array and plot my data using matplotlib?
My plot should look like this:
where in my case the aperature should be the width x, the sky annulus is my time t and the RMS is my func(x,t).
A couple of points:
Numpy provides a very nice function for doing differences of array elements: diff
Matplotlib uses plot_wireframe for creating a plot that you would want (also using Numpy's meshgrid)
Now, combining these into what you may want would look something like this.
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
def func(xi, ti):
res = np.cos(ti)*np.sin(xi)
return res
timeSpacing = 20
timeStart = 0
timeEnd = 1
time = np.linspace(timeStart, timeEnd, timeSpacing)
widthSpacing = 50
widthStart = 0
widthEnd = 3
width = np.linspace(widthStart, widthEnd, widthSpacing)
X,T = np.meshgrid(width,time)
F = func(X,T)
DF = np.diff(np.diff(F,axis=0),axis=1)
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
ax.plot_wireframe(X[:-1,:-1],T[:-1,:-1],DF)
plt.show()
Note that diff is applied twice: once in each dimension axis= . I have also changed the toy function you provided to something that actually looks decent in this case.
For your more general use, it seems that you would want to just collect all of your F data into a 2D array, then proceed from the DF = line.

Categories

Resources