Plotting the graph on the complex plain - python

I would like to plot the graphic of function: w(s) = 1/(1+s).
s is the product of the imaginary unit (1j) and the variable called omega; i.e. s = 1j*omega.
How I can plot that in the complex axis (Real and Imaginary) using Python (2.7 or 3.4) and matplotlib?

You're not clear in your question about what you want to plot, but assuming omega = x + iy is the number you wish to plot w(s) as a function of, you have to decide how to present the complex numbers w(s). You might choose a plot with Cartesian axes representing the real (x) and imaginary (y) axes and to plot the absolute value of w(s) as a colour, or you might choose to plot the real and imaginary parts separately.
For example,
import matplotlib as plt
import numpy as np
x = np.linspace(-0.5,0.5,100)
y = np.linspace(-3,0,100)
X, Y = np.meshgrid(x,y)
def f(x, y):
return 1./(1+1j*(x+1j*y))
import pylab
pylab.imshow(np.abs(f(X,Y)))
pylab.show()

Related

Python: Creating a Grid of X,Y coordinates and corresponding calculated Z values to result in a 3D array of XYZ

I have a function that calculates a z value from a given x and y coordinate. I then want to combine these values together to get a 3D array of x,y,z. I'm attempting to do this with the code below:
#import packages
import pandas as pd
import math
import numpy as np
import matplotlib.mlab as mlab
import matplotlib.tri as tri
import matplotlib.pyplot as plt
from matplotlib import rcParams
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable
from mpl_toolkits.mplot3d import Axes3D
#Define function to calculate z over a grid
def func(X, Y, x, y, Q):
return (Q / (2 * np.pi)) * np.arctan((y-Y)/(x-X))
#For initial testing just defining the IW explicitly, last step will be to read the input file and pull this data
X1=2417743.658
Y1=806346.704
Q1=5
X2=2417690.718
Y2=806343.693
Q2=5
X3=2417715.221
Y3=806309.685
Q3=5
#initiate the XY grid
xi = np.linspace(2417675,2417800,625)
yi = np.linspace(806300,806375,375)
#mesh the grid in to x,y space
x,y = np.meshgrid(xi,yi)
#calculate the values over the grid at every x,y using the defined function above
zi = (func(X1,Y1,x,y,Q1)+func(X2,Y2,x,y,Q2)+func(X3,Y3,x,y,Q3))
#reshape the xy space into 3d space - when i plot this grid it looks correct
xy = np.array([[(x, y) for x in xi] for y in yi])
#reshape z into 3d space - this appears to be where the issue begins
z = np.array(zi).reshape(xy.shape[0],xy.shape[1], -1)
#combined xyz into a single grid
xyz = np.concatenate((xy, z), axis = -1)
# Create figure and add axis
fig = plt.figure(figsize=(4,4))
ax = fig.add_subplot(111)
img = ax.imshow((xyz*255).astype(np.uint8))
output:
I do get an XYZ array and when i print it the values appear to be mapping correctly, however when I plot the data, it shows the y values "upside down" essentially. This is what the output should look like but "flipped" over the x over axis. Additionally the axes show node numbers and not the X,Y values. I want the 0,0 point to be the lower left hand corner like cartesian coordinates, and each x,y have a corresponding z which is calculated from that given x,y. I know there must be an easier way to go about this. Does anyone know a better way? or maybe what i'm doing wrong here?
Thanks
There is an option for ax.imshow() that allows to specify the origin point.
https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.imshow.html
origin{'upper', 'lower'}, default: rcParams["image.origin"] (default:
'upper') Place the [0, 0] index of the array in the upper left or
lower left corner of the Axes. The convention (the default) 'upper' is
typically used for matrices and images.
Note that the vertical axis points upward for 'lower' but downward for
'upper'.
See the origin and extent in imshow tutorial for examples and a more
detailed description.
Try to modify to this:
img = ax.imshow((xyz*255).astype(np.uint8), origin='lower')
For the axis labels they can be changed with the following commands
ax.set_xticks(LIST_OF_INDICIES)
ax.set_xticklabels(LIST_OF_VALUES)

To plot graph non linear function

I want to plot graph of this function:
y = 2[1-e^(-x+1)]^2-2
When I plot a linear function, I used this code :
import matplotlib.pyplot as plt
import numpy as np
x = np.array(...)
y = np.array(...)
z = np.polyfit(x, y, 2)
p = np.poly1d(z)
xp = np.linspace(...)
_ = plt.plot(x, y, '.', xp, p(xp), '-')
plt.ylim(0, 200)
plt.show()
When the function is non-linear, it does not works
becasue it hard to find each x,y value.
How can I plot a non-linear function?
I hate to be the one to break this news to you, but polynomials of order greater than one are technically nonlinear too.
When you plot in matplotlib, you're really supplying discreet x and y values at a resolution sufficient to be visually pleasing. In this case, you've chosen xp to determine the points you plot for the parabola. You then call p(xp) to generate an array of y-values at those locations.
There nothing stopping you from generating y-values for your formula of interest using simple numpy functions:
y = 2 * (1 - np.exp(1 - xp))**2 - 2

How do I set an exact float as the scaling factor for my y-axis limits on Matplotlib?

The number 1.67845714e-12 is an important result from my physics project. I want to plot graphs where the y-axis limit revolves around this result as a scaling factor.
In the following example:
import numpy as np
import matplotlib.pyplot as plt
plt.ion()
import random
x = np.arange(0,100)
y = np.zeros(len(x))
for i in range(len(x)):
y[i] = 1.67845714e-12*random.random() - (4.20e-14)*x[i]
plt.ylim(float(-3*1.67845714e-12), float(3*1.67845714e-12)) #The important line
plt.plot(x,y)
The resulting plot has a y-axis going from -5*e-12 to 5*e-12 , instead of a y-axis going from -3*1.67845714e-12 to 3*1.67845714e-12
How can I get Matplotlib to display the step of 1.67845714e-12 on the top left corner of the graph with a scale of -3 to 3 displayed on the y axis like I intended? And if this is impossible because for example, the step is too long, can I give my step a nickname (such as "Result") to make this work?
I've tried using other commands like ax.set_yticks() , ax=plt.gta() or
ax.set_ylim() but nothing I've searched seems to work.
I am trying to answer based on what I understood you wanted to do. As I see it, you want to have a y axis from -3*1.67845714e-12 up until 3*1.67845714e-12 but each step/tick would be of size 1.67845714e-12.
Note I created a variable named scalingFactor to hold 1.67845714e-12. I think this answers one of your questions. You can use it then instead of writing the whole number.
Ok, to generate the ticks so you can use numpy.arange(inf, sup, step) function. It returns evenly spaced values within a given interval [inf;sup). So we are going to generate ticks from -3*scalingFactor up until 3*scalingFactor using a 1.67845714e-12 step. You may notice in the code that sup=4*scalingFactor. It is because numpy.arange() exclude the upper limit of the interval.
To get the whole number on the axis and not rounded, you can force it to have 8 decimal places using plt.gca().yaxis.set_major_formatter(mtick.FormatStrFormatter('%.8e')). This function formats the labels for the ticks of the axis and it uses in this case this string format %.8e.
import numpy as np
import matplotlib.pyplot as plt
plt.ion()
import random
import matplotlib.ticker as mtick
x = np.arange(0,100)
y = np.zeros(len(x))
scalingFactor = 1.67845714e-12
for i in range(len(x)):
y[i] = scalingFactor*random.random() - (4.20e-14)*x[i]
inf = -3*scalingFactor
sup = 4*scalingFactor
plt.plot(x, y)
plt.ylim(inf, sup)
plt.yticks(np.arange(inf, sup, scalingFactor))
plt.subplots_adjust(left=0.24) # Squash the plot from the left so the ticks labels can be seen
plt.gca().yaxis.set_major_formatter(mtick.FormatStrFormatter('%.8e'))
plt.show()
Outputs
EDIT:
Well, I was actually, in fact, struggling with what you wanted cause I've never needed to do that. However I came up with a very ad-hoc solution for your problem based on what you needed cause it seems all of your data would be in that range and you wanted a scaling factor of 1.67845714e-12.
There are formatter classes that can format tick values and handle offset value (the scale value on top left corner). So we can create a ModScalarFormatterthat inherits from ScalarFormatter and override some functions to set manually the offset and ticks we want without letting matplotlib computing it:
import numpy as np
import matplotlib.pyplot as plt
plt.ion()
import random
import math
import matplotlib.ticker as mtick
class ModScalarFormatter(mtick.ScalarFormatter):
def __init__(self, useOffset=None, useMathText=None, useLocale=None):
mtick.ScalarFormatter.__init__(self, useOffset, useMathText, useLocale)
# Create the ticks we want
self.ticks = [i for i in range(-3, 4)]
def _set_offset(self, text):
self.offset = text # Set the offset text we want
def get_offset(self, txt=''):
return self.offset # Return the offset value
def __call__(self, x, pos=None):
# The __call__ returns the tick on position `pos` from the
# ticks we specified
return self.ticks[pos]
x = np.arange(0,100)
y = np.zeros(len(x))
scalingFactor = 1.67845714e-12
for i in range(len(x)):
y[i] = scalingFactor*random.random() - (4.20e-14)*x[i]
inf = -3*scalingFactor
sup = 3*scalingFactor
plt.plot(x, y)
plt.yticks(np.linspace(inf, sup, 7))
# Create and use a Custom Scalar Formatter Class
sf = ModScalarFormatter(useOffset=1.67845714e-12)
plt.gca().yaxis.set_major_formatter(sf)
plt.ylim(inf, sup)
plt.show()
Outputs:
NOTE: I am pretty sure there should be a more elegant way to achieve this, but this is my way of helping you with and ad-hoc solution for your specific problem.
Hope this helps.

Python 3D plotting of measurement data

I have captured 3D measurement data on a sphere (this is an antenna radiation pattern, so the measurement antenna captured the radiation intensity from each phi,theta direction and logged this value as a function of phi,theta).
I am having great difficulty getting the data represented.
I have tried multiple options. This is the last one I am now trying:
import numpy as np
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
nElevationPoints = 16
nAzimuthPoints = 40
stepSizeRad = 0.05 * np.pi
def r(phi,theta):
radius = 1
return radius
phi = np.arange(0,nAzimuthPoints*stepSizeRad,stepSizeRad)
theta = np.arange(0,nElevationPoints*stepSizeRad,stepSizeRad)
x = (r(phi,theta)*np.outer(r(phi,theta)*np.cos(phi), np.sin(theta)))
y = (-r(phi,theta)*np.outer(np.sin(phi), np.sin(theta)))
z = (r(phi,theta)*np.outer(np.ones(np.size(phi)), np.cos(theta)))
fig = plt.figure(1)
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x, y, z, rstride=4, cstride=4, color='b')
plt.ioff()
plt.show()
This code in itself is working, and it plots a sphere. Now the thing is, that in accordance with the measurement data, I would actually need the radius not be a constant "1", but corresponding with the radiation intensity measured. So it needs to be a function of phi,theta.
However, as soon as I change the "r" function to anything containing the phi or theta parameter, I get an error about operands that could not be broadcast.
If there's any work around that loops through phi,theta that would be perfectly fine as well.
But I'm stuck now, so I'd appreciate any help :-)
BTW, the reason I went for the above approach is because I couldn't make sense of how the x,y,z should be defined in order to be acceptable to the plot_surface function.
I did manage to generate a scatter plot, by calculating the actual positions (x,y,z) from the phi,theta,intensity data, but this is only a representation by individual points and doesn't generate any well visible antenna radiation pattern plot. For this I assume that a contour plot would be better, but then again I am stuck at either the "r" function call or by understanding how x,y,z should be formatted (the documentation refers to x,y,z needing to be 2D-arrays, but this is beyond my comprehension as x,y,z usually are one dimensional arrays in themselves).
Anyway, looking forward to any help anyone may be willing to give.
-- EDIT --
With #M4rtini 's suggested changes I come to the following:
import numpy as np
from mayavi import mlab
def r(phi,theta):
r = np.sin(phi)**2
return r
phi, theta = np.mgrid[0:2*np.pi:201j, 0:np.pi:101j]
x = r(phi,theta)*np.sin(phi)*np.cos(theta)
y = r(phi,theta)*np.sin(phi)*np.sin(theta)
z = r(phi,theta)*np.cos(phi)
intensity = phi * theta
obj = mlab.mesh(x, y, z, scalars=intensity, colormap='jet')
obj.enable_contours = True
obj.contour.filled_contours = True
obj.contour.number_of_contours = 20
mlab.show()
This works, thanks, #M4rtini, and I now am able to have a phi,theta dependent "r" function.
However, noted that the example now ensures phi and theta to be of the same length (due to the mgrid function). This is not the case in my measurement. When declaring phi and theta separately and of different dimensions, it doesn't work still. So I now will have a look into measurement interpolation.
This might not be the exact answer you were looking for, but if you can accept using intensity values as a mapping of a color, this should work.
Actually, you could probably calculate a specific r here also. But i did not test that.
Using mayavi since it is, in my opinion, far superior than matplotlib for 3D.
import numpy as np
from mayavi import mlab
r = 1.0
phi, theta = np.mgrid[0:np.pi:200j, 0:2*np.pi:101j]
x = r*np.sin(phi)*np.cos(theta)
y = r*np.sin(phi)*np.sin(theta)
z = r*np.cos(phi)
intensity = phi * theta
obj = mlab.mesh(x, y, z, scalars=intensity, colormap='jet')
obj.enable_contours = True
obj.contour.filled_contours = True
obj.contour.number_of_contours = 20
mlab.show()
Output of example script, now this is in a interactive gui. so you can rotate, translate, scale as you please. And even interactively manipulate the data, and the representation options.

How to plot complex numbers (Argand Diagram) using matplotlib

I'd like to create an Argand Diagram from a set of complex numbers using matplotlib.
Are there any pre-built functions to help me do this?
Can anyone recommend an approach?
Image by LeonardoG, CC-SA-3.0
I'm not sure exactly what you're after here...you have a set of complex numbers, and want to map them to the plane by using their real part as the x coordinate and the imaginary part as y?
If so you can get the real part of any python imaginary number with number.real and the imaginary part with number.imag. If you're using numpy, it also provides a set of helper functions numpy.real and numpy.imag etc. which work on numpy arrays.
So for instance if you had an array of complex numbers stored something like this:
In [13]: a = n.arange(5) + 1j*n.arange(6,11)
In [14]: a
Out[14]: array([ 0. +6.j, 1. +7.j, 2. +8.j, 3. +9.j, 4.+10.j])
...you can just do
In [15]: fig,ax = subplots()
In [16]: ax.scatter(a.real,a.imag)
This plots dots on an argand diagram for each point.
edit: For the plotting part, you must of course have imported matplotlib.pyplot via from matplotlib.pyplot import * or (as I did) use the ipython shell in pylab mode.
To follow up #inclement's answer; the following function produces an argand plot that is centred around 0,0 and scaled to the maximum absolute value in the set of complex numbers.
I used the plot function and specified solid lines from (0,0). These can be removed by replacing ro- with ro.
def argand(a):
import matplotlib.pyplot as plt
import numpy as np
for x in range(len(a)):
plt.plot([0,a[x].real],[0,a[x].imag],'ro-',label='python')
limit=np.max(np.ceil(np.absolute(a))) # set limits for axis
plt.xlim((-limit,limit))
plt.ylim((-limit,limit))
plt.ylabel('Imaginary')
plt.xlabel('Real')
plt.show()
For example:
>>> a = n.arange(5) + 1j*n.arange(6,11)
>>> from argand import argand
>>> argand(a)
produces:
EDIT:
I have just realised there is also a polar plot function:
for x in a:
plt.polar([0,angle(x)],[0,abs(x)],marker='o')
If you prefer a plot like the one below
one type of plot
or this one second type of plot
you can do this simply by these two lines (as an example for the plots above):
z=[20+10j,15,-10-10j,5+15j] # array of complex values
complex_plane2(z,1) # function to be called
by using a simple jupyter code from here
https://github.com/osnove/other/blob/master/complex_plane.py
I have written it for my own purposes. Even better it it helps to others.
To get that:
You can use:
cmath.polar to convert a complex number to polar rho-theta coordinates. In the code below this function is first vectorized in order to process an array of complex numbers instead of a single number, this is just to prevent the use an explicit loop.
A pyplot axis with its projection type set to polar. Plot can be done using pyplot.stem or pyplot.scatter.
In order to plot horizontal and vertical lines for Cartesian coordinates there are two possibilities:
Add a Cartesian axis and plot Cartesian coordinates. This solution is described in this question. I don't think it's an easy solution as the Cartesian axis won't be centered, nor it will have the correct scaling factor.
Use the polar axis, and translate Cartesian coordinates for projections into polar coordinates. This is the solution I used to plot the graph above. To not clutter the graph I've shown only one point with its projected Cartesian coordinates.
Code used for the plot above:
from cmath import pi, e, polar
from numpy import linspace, vectorize, sin, cos
from numpy.random import rand
from matplotlib import pyplot as plt
# Arrays of evenly spaced angles, and random lengths
angles = linspace(0, 2*pi, 12, endpoint=False)
lengths = 3*rand(*angles.shape)
# Create an array of complex numbers in Cartesian form
z = lengths * e ** (1j*angles)
# Convert back to polar form
vect_polar = vectorize(polar)
rho_theta = vect_polar(z)
# Plot numbers on polar projection
fig, ax = plt.subplots(subplot_kw={'projection': 'polar'})
ax.stem(rho_theta[1], rho_theta[0])
# Get a number, find projections on axes
n = 11
rho, theta = rho_theta[0][n], rho_theta[1][n]
a = cos(theta)
b = sin(theta)
rho_h, theta_h = abs(a)*rho, 0 if a >= 0 else -pi
rho_v, theta_v = abs(b)*rho, pi/2 if b >= 0 else -pi/2
# Plot h/v lines on polar projection
ax.plot((theta_h, theta), (rho_h, rho), c='r', ls='--')
ax.plot((theta, theta_v), (rho, rho_v), c='g', ls='--')
import matplotlib.pyplot as plt
from numpy import *
'''
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
This draws the axis for argand diagram
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
'''
r = 1
Y = [r*exp(1j*theta) for theta in linspace(0,2*pi, 200)]
Y = array(Y)
plt.plot(real(Y), imag(Y), 'r')
plt.ylabel('Imaginary')
plt.xlabel('Real')
plt.axhline(y=0,color='black')
plt.axvline(x=0, color='black')
def argand(complex_number):
'''
This function takes a complex number.
'''
y = complex_number
x1,y1 = [0,real(y)], [0, imag(y)]
x2,y2 = [real(y), real(y)], [0, imag(y)]
plt.plot(x1,y1, 'r') # Draw the hypotenuse
plt.plot(x2,y2, 'r') # Draw the projection on real-axis
plt.plot(real(y), imag(y), 'bo')
[argand(r*exp(1j*theta)) for theta in linspace(0,2*pi,100)]
plt.show()
https://github.com/QuantumNovice/Matplotlib-Argand-Diagram/blob/master/argand.py

Categories

Resources