I am using the below python codes so as to generates a square wave at one specific position. For Eg: you enter 0, the signal is high1 only between 0 and 1[Odd=High]. You enter 1, the output is high1 only between 1 and 2 [Even = High]. How do you extend the below python codes so as to generate odd or even square wave throughout the time span rather that at a single position. Here I am facing problem with 2*n+1 formula.Could anyone help me in this?
Please refer the image below
import numpy as np
import matplotlib.pyplot as plt
def SquareWave(n):
xmin=0;
xmax=10;
ymin=-2;
ymax=2;
Nx=1000;
offset=1;
x=np.linspace(xmin, xmax, Nx);
y=np.sign(x+n)*offset;
y[(x<n)]=0;
y[(x>n+1)]=0;
plt.plot(x, y);
plt.axis([xmin, xmax, ymin, ymax]);
plt.grid()
plt.show()
Don't use ;.
import numpy as np
import matplotlib.pyplot as plt
def SquareWave(n,xmin=0,xmax=10,ymin=-2,Nx=1000,ymax=2,offset=1):
x=np.sort(np.concatenate([np.arange(xmin, xmax)-1E-6,np.arange(xmin, xmax)+1E-6]))
#You can use np.linspace(xmin,xmax,Nx) if you want the intermediate points
y=np.array(x+n+offset,dtype=int)%2
plt.plot(x, y)
plt.axis([xmin, xmax, ymin, ymax])
plt.grid()
plt.show()
Related
The example here
What is the difference between 'log' and 'symlog'?
nicely shows how a linear scale at the origin can be used with a log scale elsewhere. I want to go the other way around. I want to have a a log scale from 1-100 and then a linear! scale from 100-1000. What are my options? Like the figure above
This attempt did not work
import matplotlib.pyplot as plt
plt.figure()
plt.errorbar(x, y, yerr=yerrors)
plt.xscale('symlog', linthreshx= (100,1000))
The problem seems to be that linthreshx is defined to take the range (-x,x). So if x if 5 we would get a linear scale on (-5,5). One is confined to the origin. I thought simply choosing a different range should work but it does not. Any ideas?
From the response of user1318806 to cphlewis:
Thank you. Actually I wanted a combination of log+linear on the x axis not y. But I assume your code should be easily adaptable.
Hello! If you wanted a combination of log+linear on the x-axis (patterned from the code of Duncan Watts and CubeJockey):
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
# Numbers from -50 to 50, with 0.1 as step
xdomain = np.arange(-50,50, 0.1)
axMain = plt.subplot(111)
axMain.plot(np.sin(xdomain), xdomain)
axMain.set_xscale('linear')
axMain.set_xlim((0.5, 1.5))
axMain.spines['left'].set_visible(False)
axMain.yaxis.set_ticks_position('right')
axMain.yaxis.set_visible(False)
divider = make_axes_locatable(axMain)
axLin = divider.append_axes("left", size=2.0, pad=0, sharey=axMain)
axLin.set_xscale('log')
axLin.set_xlim((0.01, 0.5))
axLin.plot(np.sin(xdomain), xdomain)
axLin.spines['right'].set_visible(False)
axLin.yaxis.set_ticks_position('left')
plt.setp(axLin.get_xticklabels(), visible=True)
plt.title('Linear right, log left')
The code above yields:
(MISCELLANEOUS) Here's a very minor fix for the title and the absence of tick marks on the right side:
# Fix for: title + no tick marks on the right side of the plot
ax2 = axLin.twinx()
ax2.spines['left'].set_visible(False)
ax2.tick_params(axis='y',which='both',labelright='off')
Adding these lines will give you this:
pythonmatplotlib
I assume you want linear near the origin, log farther -- since `symlog' does it the other way around -- I couldn't come up with data that looked good like this, but you can put it together with the axes_grid:
# linear and log axes for the same plot?
# starting with the histogram example from
# http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
# Numbers from -50 to 50, with 0.1 as step
xdomain = np.arange(-50,50, 0.1)
axMain = plt.subplot(111)
axMain.plot(xdomain, np.sin(xdomain))
axMain.set_yscale('log')
axMain.set_ylim((0.01, 0.5))
divider = make_axes_locatable(axMain)
axLin = divider.append_axes("top", size=2.0, pad=0.02, sharex=axMain)
axLin.plot(xdomain, np.sin(xdomain))
axLin.set_xscale('linear')
axLin.set_ylim((0.5, 1.5))
plt.title('Linear above, log below')
plt.show()
This solution makes an addition to cphlewis's answer so that there is a smooth transition, and the plot appears to have consistent tick markers. My change adds these three lines:
axLin.spines['bottom'].set_visible(False)
axLin.xaxis.set_ticks_position('top')
plt.setp(axLin.get_xticklabels(), visible=False)
In total, the code is
# linear and log axes for the same plot?
# starting with the histogram example from
# http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
# Numbers from -50 to 50, with 0.1 as step
xdomain = np.arange(-50,50, 0.1)
axMain = plt.subplot(111)
axMain.plot(xdomain, np.sin(xdomain))
axMain.set_yscale('log')
axMain.set_ylim((0.01, 0.5))
axMain.spines['top'].set_visible(False)
axMain.xaxis.set_ticks_position('bottom')
divider = make_axes_locatable(axMain)
axLin = divider.append_axes("top", size=2.0, pad=0, sharex=axMain)
axLin.plot(xdomain, np.sin(xdomain))
axLin.set_xscale('linear')
axLin.set_ylim((0.5, 1.5))
# Removes bottom axis line
axLin.spines['bottom'].set_visible(False)
axLin.xaxis.set_ticks_position('top')
plt.setp(axLin.get_xticklabels(), visible=False)
plt.title('Linear above, log below')
plt.show()
I cannot understand how to use fill_betweenx() in matplotlib. How it is different from fill_between()? After reading the documentation of fill_betweenx() I tried to implement it:
x=np.linspace(0,2*3.14,50)
y=np.sin(x)
plt.figure(figsize=(10,5))
plt.fill_betweenx(y,2,3,color='b')
plt.plot(x,y)
As per my understanding, it should have filled the sine curve between x=2 and x=3 with a blue color, but I got:
Can anyone explain to me why it wasn't filled?
It seems you want to fill the sine curve, e.g. between y=0 and the sine. You may limit this fill to a range of x coordinates using where.
import matplotlib.pyplot as plt
import numpy as np
x=np.linspace(0,2*3.14,50)
y=np.sin(x)
plt.fill_between(x,y,0,where=(x>2) & (x<=3),color='b')
plt.plot(x,y)
In contrast you would use fill_betweenx if you wanted to fill between a curve in x direction. E.g.
plt.fill_betweenx(x,y,where=(x>2) & (x<=3), color='b')
plt.plot(y,x)
For the code below, besides having the relevant modules installed, you will need to download and unpack the file "nationp010g.shp.tar.gz" that can be found here. This file is a shape file of the United States. If anyone has a better way of displaying these boundaries, by all means suggest it!
For my test case below, I have succeeded in colouring in the united states blue. What I want to do is to plot contour plots as if only the land portions of the USA are allowed. Im not sure how this can be accomplished without using a tedious for loop which loops through all the coordinates and checks whether the coordinate in question is inside the polygon given by the shape file. What is the best way to accomplish what I want? Here is the result:
from __future__ import print_function
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap as Basemap
from matplotlib.colors import rgb2hex
from matplotlib.patches import Polygon
m = Basemap(llcrnrlon=-119,llcrnrlat=22,urcrnrlon=-64,urcrnrlat=49,
projection='lcc',lat_1=33,lat_2=45,lon_0=-95)
shp_info = m.readshapefile('nationp010g/nationp010g', 'borders', drawbounds=True)
print(dir(m)) #List all attributes of an object
ax = plt.gca()
color = 'blue'
for nshape,seg in enumerate(m.borders):
poly = Polygon(seg,facecolor=color,edgecolor=color)
ax.add_patch(poly)
xmax, ymax = m(m.lonmax, m.latmax )
xmin, ymin = m(m.lonmin, m.latmin)
y = np.linspace(ymin,ymax,100)
x = np.linspace(xmin, xmax, 100)
X, Y = np.meshgrid(x, y)
Z = (X-(xmax-xmin)/2)**2+(Y-(ymax-ymin)/2)**2
ax.contour(X,Y, Z, cmap=plt.get_cmap('coolwarm'))
plt.show()
I would like to zoom a portion of data/image and plot it inside the same figure. It looks something like this figure.
Is it possible to insert a portion of zoomed image inside the same plot. I think it is possible to draw another figure with subplot but it draws two different figures. I also read to add patch to insert rectangle/circle but not sure if it is useful to insert a portion of image into the figure. I basically load data from the text file and plot it using a simple plot commands shown below.
I found one related example from matplotlib image gallery here but not sure how it works. Your help is much appreciated.
from numpy import *
import os
import matplotlib.pyplot as plt
data = loadtxt(os.getcwd()+txtfl[0], skiprows=1)
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.semilogx(data[:,1],data[:,2])
plt.show()
Playing with runnable code is one of the
fastest ways to learn Python.
So let's start with the code from the matplotlib example gallery.
Given the comments in the code, it appears the code is broken up into 4 main stanzas.
The first stanza generates some data, the second stanza generates the main plot,
the third and fourth stanzas create the inset axes.
We know how to generate data and plot the main plot, so let's focus on the third stanza:
a = axes([.65, .6, .2, .2], axisbg='y')
n, bins, patches = hist(s, 400, normed=1)
title('Probability')
setp(a, xticks=[], yticks=[])
Copy the example code into a new file, called, say, test.py.
What happens if we change the .65 to .3?
a = axes([.35, .6, .2, .2], axisbg='y')
Run the script:
python test.py
You'll find the "Probability" inset moved to the left.
So the axes function controls the placement of the inset.
If you play some more with the numbers you'll figure out that (.35, .6) is the
location of the lower left corner of the inset, and (.2, .2) is the width and
height of the inset. The numbers go from 0 to 1 and (0,0) is the located at the
lower left corner of the figure.
Okay, now we're cooking. On to the next line we have:
n, bins, patches = hist(s, 400, normed=1)
You might recognize this as the matplotlib command for drawing a histogram, but
if not, changing the number 400 to, say, 10, will produce an image with a much
chunkier histogram, so again by playing with the numbers you'll soon figure out
that this line has something to do with the image inside the inset.
You'll want to call semilogx(data[3:8,1],data[3:8,2]) here.
The line title('Probability')
obviously generates the text above the inset.
Finally we come to setp(a, xticks=[], yticks=[]). There are no numbers to play with,
so what happens if we just comment out the whole line by placing a # at the beginning of the line:
# setp(a, xticks=[], yticks=[])
Rerun the script. Oh! now there are lots of tick marks and tick labels on the inset axes.
Fine. So now we know that setp(a, xticks=[], yticks=[]) removes the tick marks and labels from the axes a.
Now, in theory you have enough information to apply this code to your problem.
But there is one more potential stumbling block: The matplotlib example uses
from pylab import *
whereas you use import matplotlib.pyplot as plt.
The matplotlib FAQ says import matplotlib.pyplot as plt
is the recommended way to use matplotlib when writing scripts, while
from pylab import * is for use in interactive sessions. So you are doing it the right way, (though I would recommend using import numpy as np instead of from numpy import * too).
So how do we convert the matplotlib example to run with import matplotlib.pyplot as plt?
Doing the conversion takes some experience with matplotlib. Generally, you just
add plt. in front of bare names like axes and setp, but sometimes the
function come from numpy, and sometimes the call should come from an axes
object, not from the module plt. It takes experience to know where all these
functions come from. Googling the names of functions along with "matplotlib" can help.
Reading example code can builds experience, but there is no easy shortcut.
So, the converted code becomes
ax2 = plt.axes([.65, .6, .2, .2], axisbg='y')
ax2.semilogx(t[3:8],s[3:8])
plt.setp(ax2, xticks=[], yticks=[])
And you could use it in your code like this:
from numpy import *
import os
import matplotlib.pyplot as plt
data = loadtxt(os.getcwd()+txtfl[0], skiprows=1)
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.semilogx(data[:,1],data[:,2])
ax2 = plt.axes([.65, .6, .2, .2], axisbg='y')
ax2.semilogx(data[3:8,1],data[3:8,2])
plt.setp(ax2, xticks=[], yticks=[])
plt.show()
The simplest way is to combine "zoomed_inset_axes" and "mark_inset", whose description and
related examples could be found here:
Overview of AxesGrid toolkit
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
import numpy as np
def get_demo_image():
from matplotlib.cbook import get_sample_data
import numpy as np
f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False)
z = np.load(f)
# z is a numpy array of 15x15
return z, (-3,4,-4,3)
fig, ax = plt.subplots(figsize=[5,4])
# prepare the demo image
Z, extent = get_demo_image()
Z2 = np.zeros([150, 150], dtype="d")
ny, nx = Z.shape
Z2[30:30+ny, 30:30+nx] = Z
# extent = [-3, 4, -4, 3]
ax.imshow(Z2, extent=extent, interpolation="nearest",
origin="lower")
axins = zoomed_inset_axes(ax, 6, loc=1) # zoom = 6
axins.imshow(Z2, extent=extent, interpolation="nearest",
origin="lower")
# sub region of the original image
x1, x2, y1, y2 = -1.5, -0.9, -2.5, -1.9
axins.set_xlim(x1, x2)
axins.set_ylim(y1, y2)
plt.xticks(visible=False)
plt.yticks(visible=False)
# draw a bbox of the region of the inset axes in the parent axes and
# connecting lines between the bbox and the inset axes area
mark_inset(ax, axins, loc1=2, loc2=4, fc="none", ec="0.5")
plt.draw()
plt.show()
The nicest way I know of to do this is to use mpl_toolkits.axes_grid1.inset_locator (part of matplotlib).
There is a great example with source code here: https://github.com/NelleV/jhepc/tree/master/2013/entry10
The basic steps to zoom up a portion of a figure with matplotlib
import numpy as np
from matplotlib import pyplot as plt
# Generate the main data
X = np.linspace(-6, 6, 1024)
Y = np.sinc(X)
# Generate data for the zoomed portion
X_detail = np.linspace(-3, 3, 1024)
Y_detail = np.sinc(X_detail)
# plot the main figure
plt.plot(X, Y, c = 'k')
# location for the zoomed portion
sub_axes = plt.axes([.6, .6, .25, .25])
# plot the zoomed portion
sub_axes.plot(X_detail, Y_detail, c = 'k')
# insert the zoomed figure
# plt.setp(sub_axes)
plt.show()
I've been looking high and low for a solution to this simple problem but I can't find it anywhere! There are a loads of posts detailing semilog / loglog plotting of data in 2D e.g. plt.setxscale('log') however I'm interested in using log scales on a 3d plot(mplot3d).
I don't have the exact code to hand and so can't post it here, however the simple example below should be enough to explain the situation. I'm currently using Matplotlib 0.99.1 but should shortly be updating to 1.0.0 - I know I'll have to update my code for the mplot3d implementation.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FixedLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = Axes3D(fig)
X = np.arange(-5, 5, 0.025)
Y = np.arange(-5, 5, 0.025)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet, extend3d=True)
ax.set_zlim3d(-1.01, 1.01)
ax.w_zaxis.set_major_locator(LinearLocator(10))
ax.w_zaxis.set_major_formatter(FormatStrFormatter('%.03f'))
fig.colorbar(surf)
plt.show()
The above code will plot fine in 3D, however the three scales (X, Y, Z) are all linear. My 'Y' data spans several orders of magnitude (like 9!), so it would be very useful to plot it on a log scale. I can work around this by taking the log of the 'Y', recreating the numpy array and plotting the log(Y) on a linear scale, but in true python style I'm looking for smarter solution which will plot the data on a log scale.
Is it possible to produce a 3D surface plot of my XYZ data using log scales, ideally I'd like X & Z on linear scales and Y on a log scale?
Any help would be greatly appreciated. Please forgive any obvious mistakes in the above example, as mentioned I don't have my exact code to have and so have altered a matplotlib gallery example from my memory.
Thanks
Since I encountered the same question and Alejandros answer did not produced the desired Results here is what I found out so far.
The log scaling for Axes in 3D is an ongoing issue in matplotlib. Currently you can only relabel the axes with:
ax.yaxis.set_scale('log')
This will however not cause the axes to be scaled logarithmic but labeled logarithmic.
ax.set_yscale('log') will cause an exception in 3D
See on github issue 209
Therefore you still have to recreate the numpy array
I came up with a nice and easy solution taking inspiration from Issue 209. You define a small formatter function in which you set your own notation.
import matplotlib.ticker as mticker
# My axis should display 10⁻¹ but you can switch to e-notation 1.00e+01
def log_tick_formatter(val, pos=None):
return f"$10^{{{int(val)}}}$" # remove int() if you don't use MaxNLocator
# return f"{10**val:.2e}" # e-Notation
ax.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))
ax.zaxis.set_major_locator(mticker.MaxNLocator(integer=True))
set_major_locator sets the exponential to only use integers 10⁻¹, 10⁻² without 10^-1.5 etc. Source
Important! remove the cast int() in the return statement if you don't use set_major_locator and you want to display 10^-1.5 otherwise it will still print 10⁻¹ instead of 10^-1.5.
Example:
Try it yourself!
from mpl_toolkits.mplot3d import axes3d
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
fig = plt.figure(figsize=(11,8))
ax1 = fig.add_subplot(121,projection="3d")
# Grab some test data.
X, Y, Z = axes3d.get_test_data(0.05)
# Now Z has a range from 10⁻³ until 10³, so 6 magnitudes
Z = (np.full((120, 120), 10)) ** (Z / 20)
ax1.plot_wireframe(X, Y, Z, rstride=10, cstride=10)
ax1.set(title="Linear z-axis (small values not visible)")
def log_tick_formatter(val, pos=None):
return f"$10^{{{int(val)}}}$"
ax2 = fig.add_subplot(122,projection="3d")
# You still have to take log10(Z) but thats just one operation
ax2.plot_wireframe(X, Y, np.log10(Z), rstride=10, cstride=10)
ax2.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))
ax2.zaxis.set_major_locator(mticker.MaxNLocator(integer=True))
ax2.set(title="Logarithmic z-axis (much better)")
plt.savefig("LinearLog.png", bbox_inches='tight')
plt.show()
in osx: ran ax.zaxis._set_scale('log') (notice the underscore)
There is no solution because of the issue 209. However, you can try doing this:
ax.plot_surface(X, np.log10(Y), Z, cmap='jet', linewidth=0.5)
If in "Y" there is a 0, it is going to appear a warning but still works. Because of this warning color maps don´t work, so try to avoid 0 and negative numbers. For example:
Y[Y != 0] = np.log10(Y[Y != 0])
ax.plot_surface(X, Y, Z, cmap='jet', linewidth=0.5)
I wanted a symlog plot and, since I fill the data array by hand, I just made a custom function to calculate the log to avoid having negative bars in the bar3d if the data is < 1:
import math as math
def manual_log(data):
if data < 10: # Linear scaling up to 1
return data/10
else: # Log scale above 1
return math.log10(data)
Since I have no negative values, I did not implement handling this values in this function, but it should not be hard to change it.