matplotlib spline adjustment changes tick label visibility - python-3.x

I've found some odd behavior with pyplot. When I run the following code:
#! /usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 100)
y = 2 * np.sin(x)
fig, (ax0, ax1) = plt.subplots(nrows = 2, sharex=True)
ax0.plot(x, y)
ax1.plot(x, y)
#ax0.spines['top'].set_position(('outward', 0))
plt.show()
it produces the plot
However, uncommenting the ax0.spines... line produces this plot
Note that on the top subplot, the x-axis has acquired labels on its ticks. Is this the expected behavior (and due to a misunderstanding on my part of the pyplot API), or is this a bug with pyplot?
Note that this is a minimized example of an issue I noticed with some more complex graph formatting code I'm working on. While the set_position() call in this case has no effect, in my code I'm actually bumping all spines outwards. I found with my testing, however, that the change in position seems not to have an effect -- rather, it's the fact of calling the set_position() function at all.

Turns out it was a problem localized to matplotlib 2.0.0 -- it's fixed in 2.1.0

Related

When plotting the Wigner function of a coherent state using QuTiP strange patterns appear

I noticed something strange this day when I plotted the Wigner function of a coherent state using the open source quantum toolbox QuTiP in python.
When I do the plot I noticed these strange patterns just around the edge of the plot that are not supposed to be there. I believe it's just some sort of numerical error but I don't know how I can get rid or minimize them or most impartant: what's causing them.
Here is the code
# import packages
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib as mpl
from matplotlib import cm
from qutip import *
N = 60 # number of levels in Hilbert space
# density matrix of a coherent state
rho_coherent = coherent_dm(N, 1-1j)
X = np.linspace(-3, 3, 300)
Y = np.linspace(-3, 3, 300)
# Wigner function
W = wigner(rho_coherent, X, Y, 'iterative', 2)
X, Y = np.meshgrid(X, Y)
# Color Normalization
class MidpointNormalize(colors.Normalize):
def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
self.midpoint = midpoint
colors.Normalize.__init__(self, vmin, vmax, clip)
def __call__(self, value, clip=None):
x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
return np.ma.masked_array(np.interp(value, x, y))
# contour plot
plt.subplot(111, aspect='equal')
plt.contourf(X, Y, W, 100, cmap = cm.RdBu_r, norm = MidpointNormalize(midpoint=0.))
plt.show()
and here is the plot
The blue spots as you can clearly see that's around the edges are not supposed to be there! The blue spots indicate that the Wigner function is negative at that point, but a coherent state should have a Wigner function thats positive everywhere!
I also noticed that when I reduce the linspace steps from 300 to 100 the blue parts disappear.
Would appreciate very much if someone can explain what's causing this problem to appear.
This is simply due to truncation. When using a finite number of modes (in your case N=60), the Wigner function will go negative at some point.
Reducing the linspace steps brings the negative regions you see on the plot into the zero value increment and displays these regions as zero. Reducing the linspace steps is probably the best solution to your problem. Your plot will only be as accurate as the errors introduced by truncation, so simply reduce the resolution until those errors disappear.

How to make a graph using matplotlib with equally spaced powers of 10? [duplicate]

I want to plot a graph with one logarithmic axis using matplotlib.
I've been reading the docs, but can't figure out the syntax. I know that it's probably something simple like 'scale=linear' in the plot arguments, but I can't seem to get it right
Sample program:
import pylab
import matplotlib.pyplot as plt
a = [pow(10, i) for i in range(10)]
fig = plt.figure()
ax = fig.add_subplot(2, 1, 1)
line, = ax.plot(a, color='blue', lw=2)
pylab.show()
You can use the Axes.set_yscale method. That allows you to change the scale after the Axes object is created. That would also allow you to build a control to let the user pick the scale if you needed to.
The relevant line to add is:
ax.set_yscale('log')
You can use 'linear' to switch back to a linear scale. Here's what your code would look like:
import pylab
import matplotlib.pyplot as plt
a = [pow(10, i) for i in range(10)]
fig = plt.figure()
ax = fig.add_subplot(2, 1, 1)
line, = ax.plot(a, color='blue', lw=2)
ax.set_yscale('log')
pylab.show()
First of all, it's not very tidy to mix pylab and pyplot code. What's more, pyplot style is preferred over using pylab.
Here is a slightly cleaned up code, using only pyplot functions:
from matplotlib import pyplot
a = [ pow(10,i) for i in range(10) ]
pyplot.subplot(2,1,1)
pyplot.plot(a, color='blue', lw=2)
pyplot.yscale('log')
pyplot.show()
The relevant function is pyplot.yscale(). If you use the object-oriented version, replace it by the method Axes.set_yscale(). Remember that you can also change the scale of X axis, using pyplot.xscale() (or Axes.set_xscale()).
Check my question What is the difference between ‘log’ and ‘symlog’? to see a few examples of the graph scales that matplotlib offers.
if you want to change the base of logarithm, just add:
plt.yscale('log',base=2)
Before Matplotlib 3.3, you would have to use basex/basey as the bases of log
You simply need to use semilogy instead of plot:
from pylab import *
import matplotlib.pyplot as pyplot
a = [ pow(10,i) for i in range(10) ]
fig = pyplot.figure()
ax = fig.add_subplot(2,1,1)
line, = ax.semilogy(a, color='blue', lw=2)
show()
I know this is slightly off-topic, since some comments mentioned the ax.set_yscale('log') to be "nicest" solution I thought a rebuttal could be due. I would not recommend using ax.set_yscale('log') for histograms and bar plots. In my version (0.99.1.1) i run into some rendering problems - not sure how general this issue is. However both bar and hist has optional arguments to set the y-scale to log, which work fine.
references:
http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.bar
http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.hist
So if you are simply using the unsophisticated API, like I often am (I use it in ipython a lot), then this is simply
yscale('log')
plot(...)
Hope this helps someone looking for a simple answer! :).

Matplotlib - Axes collision warning when setting aspect ratio

I am using matplotlib to plot a hexbin. As a simple example-
import matplotlib.pyplot as plt
import numpy as np
x = np.random.rand(100)
y = np.random.rand(100)
plt.hexbin(x, y, gridsize = 15, cmap='inferno')
plt.gca().invert_yaxis() # To make top left corner as origin
plt.axes().set_aspect('equal', 'datalim')
plt.show()
I get the following warning-
"MatplotlibDeprecationWarning: Adding an axes using the same arguments as a previous axes currently reuses the earlier instance."
I think it is due to the line-
plt.axes().set_aspect('equal', 'datalim')
How can I use different arguments in this case. The version of matplotlibis 2.1.1
It doesn't seem like you want to create a new axes anyways. So don't use plt.axes() here. Instead get the current axes in the usual way (plt.gca()) and use any of its methods.
plt.gca().set_aspect('equal', 'datalim')

Python matplotlib graphing [duplicate]

I need help with setting the limits of y-axis on matplotlib. Here is the code that I tried, unsuccessfully.
import matplotlib.pyplot as plt
plt.figure(1, figsize = (8.5,11))
plt.suptitle('plot title')
ax = []
aPlot = plt.subplot(321, axisbg = 'w', title = "Year 1")
ax.append(aPlot)
plt.plot(paramValues,plotDataPrice[0], color = '#340B8C',
marker = 'o', ms = 5, mfc = '#EB1717')
plt.xticks(paramValues)
plt.ylabel('Average Price')
plt.xlabel('Mark-up')
plt.grid(True)
plt.ylim((25,250))
With the data I have for this plot, I get y-axis limits of 20 and 200. However, I want the limits 20 and 250.
Get current axis via plt.gca(), and then set its limits:
ax = plt.gca()
ax.set_xlim([xmin, xmax])
ax.set_ylim([ymin, ymax])
One thing you can do is to set your axis range by yourself by using matplotlib.pyplot.axis.
matplotlib.pyplot.axis
from matplotlib import pyplot as plt
plt.axis([0, 10, 0, 20])
0,10 is for x axis range.
0,20 is for y axis range.
or you can also use matplotlib.pyplot.xlim or matplotlib.pyplot.ylim
matplotlib.pyplot.ylim
plt.ylim(-2, 2)
plt.xlim(0,10)
Another workaround is to get the plot's axes and reassign changing only the y-values:
x1,x2,y1,y2 = plt.axis()
plt.axis((x1,x2,25,250))
You can instantiate an object from matplotlib.pyplot.axes and call the set_ylim() on it. It would be something like this:
import matplotlib.pyplot as plt
axes = plt.axes()
axes.set_ylim([0, 1])
Just for fine tuning. If you want to set only one of the boundaries of the axis and let the other boundary unchanged, you can choose one or more of the following statements
plt.xlim(right=xmax) #xmax is your value
plt.xlim(left=xmin) #xmin is your value
plt.ylim(top=ymax) #ymax is your value
plt.ylim(bottom=ymin) #ymin is your value
Take a look at the documentation for xlim and for ylim
This worked at least in matplotlib version 2.2.2:
plt.axis([None, None, 0, 100])
Probably this is a nice way to set up for example xmin and ymax only, etc.
To add to #Hima's answer, if you want to modify a current x or y limit you could use the following.
import numpy as np # you probably alredy do this so no extra overhead
fig, axes = plt.subplot()
axes.plot(data[:,0], data[:,1])
xlim = axes.get_xlim()
# example of how to zoomout by a factor of 0.1
factor = 0.1
new_xlim = (xlim[0] + xlim[1])/2 + np.array((-0.5, 0.5)) * (xlim[1] - xlim[0]) * (1 + factor)
axes.set_xlim(new_xlim)
I find this particularly useful when I want to zoom out or zoom in just a little from the default plot settings.
This should work. Your code works for me, like for Tamás and Manoj Govindan. It looks like you could try to update Matplotlib. If you can't update Matplotlib (for instance if you have insufficient administrative rights), maybe using a different backend with matplotlib.use() could help.

Take control of Seaborn marginal histograms?

Question 1:
How do I remove excess space in the plot, when plotting marginals? Answered below in first post.
Question 2:
How do I get more fine contorl over the margin histogram plots, e.g. to plot both histogram and decide kde parameters for the marginals? Answered below in second post, with JointGrid.
#!/usr/bin/env python3
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import pandas as pd
sns.set_palette("viridis")
sns.set(style="white", color_codes=True)
x = np.random.normal(0, 1, 1000)
y = np.random.normal(5, 1, 1000)
df = pd.DataFrame({"x":x, "y":y})
g = sns.jointplot(df["x"],df["y"], bw=0.15, shade=True, xlim=(-3,3), ylim=(2,8),cmap="coolwarm", kind="kde", stat_func=None)
# plt.tight_layout() # This will override seaborn parameters. Remember to exclude.
plt.show()
jointplot has a space parameter that determines the space between the mainplot and the marginplots.
Running this code:
g = sns.jointplot(df["x"],df["y"], bw=0.15, shade=True, xlim=(-3,3),
ylim=(2,8),cmap="coolwarm", kind="kde",
stat_func=None, space = 0)
plt.show()
results in this plot for me:
Please note that running with plt.tight_layout() will overrule the space argument for jointplot.
Edit:
To further specify the parameters of the marginal plot you can use marginal_kws. You must pass a dictionary that specifies the parameters of the kind of marginal plot you use.
In your example you use the kde plot as marginal plots. So I will continue to use that as an example:
Here I show how to change the kernel used to make the marginal plots.
g = sns.jointplot(df["x"],df["y"], bw=0.15, shade=True, xlim=(-3,3),
ylim=(2,8),cmap="coolwarm", kind="kde",
stat_func=None, space = 0, marginal_kws={'kernel': 'epa'})
plt.show()
resulting in this graph:
You can pass any parameter accepted by the kde plot as a key in the dictionary and the desired value for that parameter as the value of for that key.
Okay, so I'm going to go ahead and post an extra answer myself. It's not entirely apparent to me which parameters the extra marginal_kws can control. Instead, it might be more intuitive to build the plot layer-by-layer (especially coming from ggplot) using JointGrid:
g = sns.JointGrid(x="x", y="y", data=df) # Initiate multi-plot
g.plot_joint(sns.kdeplot) # Plot the center x/y plot as sns.kdeplot
g.plot_marginals(sns.distplot, kde=True) # Plot the edges as sns.distplot (histogram), where kde can be set to True

Resources