Problem with Removing Vertical Lines using tricontour - matplotlib

I am plotting zero-level contours using tricontour (do not want to have to triangulate data) and I am having trouble with getting rid of the vertical lines that occur when the y data goes to the next column of my grid and the sign of my z-value changes. I have tried using mask, nan, and removing the data points for which this occurs, with no luck.
Here is the code that I am using
plt.title(case+ r" case: $\alpha={}$ - Zero-level Contour Plots of Re$(|M(\gamma)|)$ and Im$|M(\gamma)|$".format(alp_val), fontsize = 16)
plt.tricontour(xx,yy,redett, levels=[0], colors='red')
plt.tricontour(xx,yy,imdett, levels=[0], colors = 'blue', linestyles='dashed')
plt.xlabel(r"x", fontsize=24)
plt.ylabel(r"$y$", fontsize=24)
plt.legend(custom_lines, [r"Re$(|M(\gamma)|)$", r"Im$(|M(\gamma)|)$"])
plt.scatter(0,0, s = 45, color='white', edgecolor='black', label =r'Simple Eigenvalue $\gamma=0$')
plt.scatter(zeroes,np.zeros(len(zeroes)), s = 45, color = 'green', edgecolor='black', label = r'Zero of $\mathcal{E}(\gamma)$')
plt.grid()
plt.show()
Want to remove vertical lines on this

Related

changing the spacing between tick labels on Matplotlib Heatmap

I am using the following code to generate this heatmap:
h= np.vstack((aug2014, sep2014,oct2014, nov2014, dec2014, jan2015, feb2015, mar2015, apr2015, may2015, jun2015, jul2015, aug2015))
dim = np.arange(1, 32, 1)
fig, ax = plt.subplots(figsize=(9,3))
heatmap = ax.imshow(h, cmap=plt.cm.get_cmap('Blues', 4), aspect=0.5, clim=[1,144])
cbar = fig.colorbar(heatmap, ticks = [1, 36, 72, 108, 144], label = 'Number of valid records per day')
ax.set_xlabel("Days", fontsize=15)
ax.set_ylabel("Months", fontsize=15)
ax.set_title("Number of valid records per day", fontsize=20)
ax.set_xticks(range(0,31))
ax.set_xticklabels(dim, rotation=45, ha='center', minor=False)
ax.set_yticks(range(0,13,1))
ax.set_yticklabels(ylabel[7:20])
ax.grid(which = 'minor', color = 'w')
ax.set_facecolor('gray')
fig.show()
As you can see, the labels on the y-axis are not very readable. I was wondering whether there would be a way for me to either increase the dimension of the grid cell or change the scale on the axis to increase the space between the labels. I have tried changing the figsize but all it did was to make the colorbar much bigger than the heatmap. I also have have two subsidiary questions:
Can someone explain to me why the grid lines do not show on the figure although I have defined them?
How can I increase the font of the colorbar title?
Any help would be welcomed!

matplotlib asymmetric errorbar showing wrong information

I am trying to plot a grouped barplot with asymmetrical errobars. When the error bars a symmetrical, it's producing the correct chart. However, for the asymmetric version, the length of the error bar is wrong.
Here is a minimally reproducible code:
# test with code from documentation
men_means, men_std = (20, 35, 30, 35, 27), (2, 3, 4, 1, 2)
women_means, women_std = (25, 32, 34, 20, 25), (3, 5, 2, 3, 3)
# dummy dataframe similar to what I will be using
avg = [20, 35, 30, 35, 27]
men_std_l = [19,33,28,34,25]
men_std_u = [22,37,31,39,29]
df = pd.DataFrame({'avg' :avg, 'low':men_std_l, 'high':men_std_u})
ind = np.arange(df.shape[0]) # the x locations for the groups
width = 0.35 # the width of the bars
fig, ax = plt.subplots()
rects1 = ax.bar(ind - width/2, df['avg'], width, yerr=[df['low'].values,df['high'].values], label='Men')
rects2 = ax.bar(ind + width/2, women_means, width, yerr=women_std,label='Women')
# Add some text for labels, title and custom x-axis tick labels, etc.
ax.set_ylabel('Scores')
ax.set_title('error bar is wrong for asymmetrical, correct otherwise')
ax.legend()
fig.tight_layout()
plt.show()
I have tried the solutions from Asymmetrical errorbar with pandas (getting ValueError: In safezip, len(args[0])=5 but len(args1)=1) and plotting asymmetric errorbars using matplotlib (getting TypeError: Cannot cast array data from dtype('< U1') to dtype('float64') according to the rule 'safe')
Any help is much appreciated.
Answering my own question as I could not understand from the documentation what those lower and upper bounds of errors were. In the hindsight, it should have been clearer if I were not so used to with ggplot in r.
The matplotlib version of asymmetrical errorbar requires the the values to add and subtract from the height of the bars. It does not want the user to provide the upper and lower values, rather the numbers that should be added and subtracted. Therefore, I needed the following:
xel = df['avg'].values - df['low'].values
xeh = df['high'].values - df['avg'].values

Matplotlib Axes Offset

Thanks in advance for your help.
I'm trying to rotate the axes for two overlayed plots. When I set the rotation to vertical then it lines up with the correct columns but when I rotate the x-axes then they become offset.
Here is my code:
ax = plt.subplot(111)
ax.bar(range(1, 24, 3), gender_factors[1:2][[i for i in range(8)]].values.T, tick_label=traits_8, align = 'center', color = '#00cccc', label='Men')
ax.bar(range(0, 24, 3), gender_factors[2:3][[i for i in range(8)]].values.T, tick_label=traits_8, align = 'center', color = '#990033', label='Women')
plt.title('Personality Traits by Gender')
ax.set_xticklabels(traits_8, rotation=60)
plt.xticks(range(0, 24, 3), traits_8, rotation='vertical')
plt.legend()
plt.show()
How can I fix the offset-ness? I've tried playing with range(0,24,3) to get it right but it isn't working.
This is the expected behavior. If you look closely at the bottom plot, the center of the text still lines up with the center of the bars.
To fix this, you can set the horizontal alignment to 'right' when you create them.
plt.xticks(range(0, 24, 3), traits_8, rotation=45, ha='right')

matplotlib + wxpython not sizing correctly with legend

I have a matplotlib figure embedded in a wxpython frame with a few sizers. Everything works fine until I include a legend but then the sizers don't seem to be working with the legend.
Even when I resize the window by dragging at the corner, the main figure changes size, but only the edge of the legend is ever shown.
That is, note that the legend is not visible in the wxFrame.
import wx
import matplotlib as mpl
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
from random import shuffle
class PlotFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, title="Plot", size=(-1, -1))
self.main_panel = wx.Panel(self, -1)
self.plot_panel = PlotPanel(self.main_panel)
s0 = wx.BoxSizer(wx.VERTICAL)
s0.Add(self.main_panel, 1, wx.EXPAND)
self.SetSizer(s0)
self.s0 = s0
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
self.main_sizer.Add(self.plot_panel, 1, wx.EXPAND)
self.main_panel.SetSizer(self.main_sizer)
class PlotPanel(wx.Panel):
def __init__(self, parent, id = -1, dpi = None, **kwargs):
wx.Panel.__init__(self, parent, id=id, **kwargs)
self.figure = mpl.figure.Figure(dpi=dpi, figsize=(2,2))
self.canvas = Canvas(self, -1, self.figure)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.canvas,1,wx.EXPAND)
self.SetSizer(sizer)
sizer.SetMinSize((600, 500))
self.sizer = sizer
def test(plot_panel):
axes = plot_panel.figure.gca()
for c in ['r', 'b', 'k']:
vals = [20, 30, 40, 50, 80, 20, 50, 60, 70, 70, 80]
shuffle(vals)
axes.plot(range(len(vals)), vals, "-o", color=c, label=c*10)
legend = axes.legend(loc='center left', bbox_to_anchor=(1.05, 0.5))
return legend
if __name__=="__main__":
app = wx.PySimpleApp()
frame = PlotFrame()
legend = test(frame.plot_panel)
frame.Fit()
print "legend frame pre show: ", legend.get_frame()
frame.Show(True)
print "legend frame post show:", legend.get_frame()
frame.Fit()
app.MainLoop()
Edit:
For a solution to be useful to me, I would like it to look good when the figure is automatically drawn by the program, so adjustment parameters can be hard coded in the program, or, for example, on a window resize event, but not adjusted by hand for each plot. The main things that I expect to change here are: 1) the lengths of the labels (from, say, 1 to 25 characters), 2) the windows size (usually by the user dragging around the corner, and 3) the number of points and lines. (Also, if it matters, eventually, I'll want to have dates on the bottom axis.)
I've put the legend outside of the axes so that it won't cover any data points, and I'd prefer that it stay to the right of the axes.
I'm using Python 2.6.6, wxPython 2.8.12.1, and matplotlib 1.1.0 and am stuck with these for now.
It is re-sizing correctly, you just didn't tell it to do what you want it to do.
The problem is this line:
axes.legend(loc='center left', bbox_to_anchor=(1.05, 0.5))
Pretty sure the bbox_to_anchor kwarg is over-ridding the loc kwarg and you are pegging the bottom left of the legend to (1.05, 0.5) in axes units. If the axes expands to fill your window, the left edge of the legend will always be 5% of the width axes to the right of the right edge of you axes, hence always out of view.
You either need to put your legend someplace else or shrink your axes (in figure fraction).
option 1 move the legend:
axes.legend(bbox_to_anchor=(0.5, 0.5)) #find a better place this is in the center
option 2 move the axes + resize the figure:
axes.set_position([.1, .1, .5, .8]) # units are in figure fraction
set_position
fig = figure()
axes = fig.add_subplot(111)
for c in ['r', 'b', 'k']:
vals = [20, 30, 40, 50, 80, 20, 50, 60, 70, 70, 80]
shuffle(vals)
axes.plot(range(len(vals)), vals, "-o", color=c, label=c*10)
legend = axes.legend(loc='center left', bbox_to_anchor=(1.05, 0.5))
# adjust the figure size (in inches)
fig.set_size_inches(fig.get_size_inches() * np.array([1.5, 1]), forward=True)
# and the axes size (in figure fraction)
# to (more-or-less) preserve the aspect ratio of the original axes
# and show the legend
pos = np.array(axes.get_position().bounds)
pos[2] = .66
axes.set_position(pos)
option 3: automate option 2
fig = figure() # use plt to set this up for demo purposes
axes = fig.add_subplot(111) # add a subplot
# control paramters
left_pad = .05
right_pad = .05
# plot data
for c in ['r', 'b', 'k']:
vals = [20, 30, 40, 50, 80, 20, 50, 60, 70, 70, 80]
shuffle(vals)
axes.plot(range(len(vals)), vals, "-o", color=c, label=c*10)
# set axes labels
axes.set_xlabel('test x')
axes.set_ylabel('test y')
# make the legend
legend = axes.legend(loc='center left', bbox_to_anchor=(1 + left_pad, 0.5))
# function to 'squeeze' the legend into place
def squeeze_legend(event):
fig.tight_layout()
right_frac = 1 - legend.get_window_extent().width / fig.get_window_extent().width - left_pad - right_pad
fig.subplots_adjust(right=right_frac)
fig.canvas.draw()
# call it so the first draw is right
squeeze_legend()
# use the resize event call-back to make sure it works even if the window is re-sized
fig.canvas.mpl_connect('resize_event', squeeze_legend)

small scatter plot markers in matplotlib are always black

I'm trying to use matplotlib to make a scatter plot with very small gray points. Because of the point density, the points need to be small. The problem is that the scatter() function's markers seem to have both a line and a fill. When the markers are small, only the line is visible, not the fill, and the line isn't the right colour (it's always black).
I can get exactly what I want using gnuplot: plot 'nodes' with points pt 0 lc rgb 'gray'
How can I make very small gray points using matplotlib scatterplot()?
scatter([1,2,3], [2,4,5], s=1, facecolor='0.5', lw = 0)
This sets the markersize to 1 (s=1), the facecolor to gray (facecolor='0.5'), and the linewidth to 0 (lw=0).
If the marker has no face (cannot be filled, e.g. '+','x'), then the edgecolor has to be set instead of c, and lw should not be 0:
scatter([1,2,3], [2,4,5], marker='+', edgecolor='r')
The following will no work
scatter([1,2,3], [2,4,5], s=1, marker='+', facecolor='0.5', lw = 0)
because the edge/line will not be displayed, so nothing will be displayed.
The absolute simplest answer to your question is: use the color parameter instead of the c parameter to set the color of the whole marker.
It's easy to see the difference when you compare the results:
from matplotlib import pyplot as plt
plt.scatter([1,2,3], [3,1,2], c='0.8') # marker not all gray
plt.scatter([1,2,3], [3,1,2], color='0.8') # marker all gray
Details:
For your simple use case where you just want to make your whole marker be the same shade of gray color, you really shouldn't have to worry about things like face color vs edge color, and whether your marker is defined as all edges or some edges and some fill. Instead, just use the color parameter and know that your whole marker will be set to the single color that you specify!
In response to zwol's question in comment - my reputation is not high enough to leave comments, so this will have to do: In the event that your colors come from a colormap (i.e., are from a "sequence of values to be mapped") you can use color = as demonstrated in the following:
from matplotlib import pyplot
x = [1,5,8,9,5]
y = [4,2,4,7,9]
numSides = [2,3,1,1,5]
cmap = pyplot.cm.get_cmap("copper_r")
min, max = min(numSides), max(numSides)
for i in range(len(x)):
if numSides[i] >= 2:
cax = pyplot.scatter(x[i], y[i], marker = '+', s = 100, c = numSides[i], cmap = cmap)
cax.set_clim(min, max)
elif numSides[i] == 1:
pyplot.scatter(x[i], y[i], marker = '.', s = 40, color = cmap(numSides[i]))
fig = pyplot.gcf()
fig.set_size_inches(8.4, 6)
fig.savefig('figure_test.png', dpi = 200)
pyplot.show()