Drawing an arrow with sharp edges in figure area - matplotlib

I am using matplotlib in python 2.7. I am trying to create an arrow in the figure area outside of the axes.
from matplotlib.pyplot import *
fig = figure()
ax1 = fig.add_axes([.1,.1,.6,.8])
ax1.annotate('',xy=(.8,.92),xycoords='figure fraction',xytext=(.8,.1)
arrowprops=dict(arrowstyle='->',fc='k',lw=10))
ax2 = fig.add_axes([.85,.1,.1,.8])
ax2.spines['top'].set_visible(False)
ax2.spines['bottom'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax2.spines['right'].set_visible(False)
ax2.tick_params(axis='both',which='both',
top='off',right='off',left='off',bottom='off',
labeltop='off',labelright='off',labelleft='off',labelbottom='off')
ax2.patch.set_facecolor('None')
ax2.set_xlim(0,1)
ax2.set_ylim(0,1)
ax2.arrow(.5,0,0,1,fc='k',ec='k',head_width=.25,
head_length=.05,width=.15,length_includes_head=True)
show()
Using
ax1.annotate(...)
gives me a 'blurry' looking arrow. The only way I can figure out how get a better looking arrow is by creating another axes just for adding the arrow and using
ax2.arrow(...)
(the website won't let me post an image, but copy and paste the code and you'll see what I'm talking about)
There's got to be a better way to do this though...

I think changing the arrowstyle will help here. For example, changing it to 'simple' from '->' gives a better looking arrow. You can change the width by playing with the mutation_scale. For example,
ax1.annotate('',xy=(.8,.92),xycoords='figure fraction',xytext=(.8,.1),
arrowprops=dict(arrowstyle="simple",fc="k", ec="k",mutation_scale=30))
Here's your script, with the above simple arrow plotted in blue. Note the difference to the black arrow plotted as a -> arrow with annotate.
from matplotlib.pyplot import *
fig = figure()
ax1 = fig.add_axes([.1,.1,.5,.8])
# Your original arrow (black)
ax1.annotate('',xy=(.7,.92),xycoords='figure fraction',xytext=(.7,.1),
arrowprops=dict(arrowstyle='->',fc='k',lw=10))
# "Simple" arrow (blue)
ax1.annotate('',xy=(.8,.92),xycoords='figure fraction',xytext=(.8,.1),
arrowprops=dict(arrowstyle="simple",fc="b", ec="k",mutation_scale=30))
ax2 = fig.add_axes([.85,.1,.1,.8])
ax2.spines['top'].set_visible(False)
ax2.spines['bottom'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax2.spines['right'].set_visible(False)
ax2.tick_params(axis='both',which='both',
top='off',right='off',left='off',bottom='off',
labeltop='off',labelright='off',labelleft='off',labelbottom='off')
ax2.patch.set_facecolor('None')
ax2.set_xlim(0,1)
ax2.set_ylim(0,1)
ax2.arrow(.5,0,0,1,fc='r',ec='k',head_width=.25,
head_length=.05,width=.15,length_includes_head=True)
show()

Related

Matplotlib issue x and y label for multi axes figure

import matplotlib
import matplotlib.pyplot as plt
import numpy as nm
x = nm.linspace(start=0,stop=20,num=30)
fig=plt.figure()
ax1 = fig.add_axes([0,0.6,0.6,0.4])
ax2 = fig.add_axes([0,0,0.8,0.4])
ax1.plot(x,nm.sin(x))
ax1.set_xlabel('x',fontsize=15,color='r')
ax1.set_ylabel('sin(x)',fontsize=15,color='r')
ax2.plot(x,nm.cos(x))
ax2.set_xlabel('x',fontsize=15,color='r')
ax2.set_ylabel('cos(x)',fontsize=15,color='r')
plt.show()
The output I am not able to see the xlabel for ax2 and not able to see both y label for ax1 and ax2..The image is present below:
enter code hereenter image description here
This is expected as you are asking to create an axes that is aligned with the left edge of the figure by using fig.add_axes([0,...]). Same thing for the bottom axes, which you have aligned to the bottom-left of the figure using fig.add_axes([0,0,...]).
Increase the first value e.g. fig.add_axes([0.125,...]) to leave room for the axes decorations on the left or bottom of the axes.
It is generally recommended to use the subplots functions (such as add_subplot, plt.subplots or GridSpec) so that these details are handled automatically.

White background when setting the plot background

The following creates a plot with a white background thereby ignoring set_facecolor.
import matplotlib.pyplot as plt
from descartes.patch import PolygonPatch
import cartopy.crs as ccrs
fig = plt.figure()
ax = fig.add_subplot(111, projection=ccrs.Mercator())
ax.set_facecolor((198/255, 236/255, 253/255))
plt.show()
If I remove where I set the projection, then the color is as expected. How can I set the background color?
I am plotting my own map using shapely polygons using ax.plot. I wish to set the color of the water by setting the background color since my polygons have holes for representing lakes.
Cartopy's projections create various new properties, including two extra patches, the background and outline patches.
It is likely that the background is the one you want to change, but without further example steps this is not certain. Here is how to set each one:
fig = plt.figure();
ax1 = fig.add_subplot(121, projection=ccrs.Mercator())
ax2 = fig.add_subplot(122, projection=ccrs.Mercator())
ax1.background_patch.set_facecolor((198/255, 236/255, 253/255))
ax2.outline_patch.set_facecolor((198/255., 236/255., 253/255.))
plt.show()
Also take care with your color commands -- the example you gave used integer divide, which results in (0,0,0) = black. On the 2nd suplot you see the color you presumably wanted.
For completeness, note that the regular axis patch is turned off, so changes to that patch will not be seen.

Offset text position in matplotlib [duplicate]

I'm losing my wits here with this 'simple' problem:
In the colorbar (illustrated in picture) in matplotlib I need to move offsetText (base multiplier) from top of the colorbar to bottom.
Code that I'm using for this plot is (using gridspec):
f.add_subplot(ax12)
ax10 = plt.Subplot(f, gs00[1, 0])
cb = plt.colorbar(h3,cax=ax10)
cb.formatter.set_scientific(True)
cb.formatter.set_powerlimits((0,0))
cb.ax.yaxis.offsetText.set(size=6)
cb.update_ticks()
ax10.yaxis.set_ticks_position('left')
ax10.tick_params(labelsize=6)
f.add_subplot(ax10)
Thanks in advance!
(Btw, Python version = 2.7.6, matplotlib version = 1.3.1 - upgrading currently not an option until I finish current project)
It's in general not possible to change the position of the offsetText label. This would still be an open issue.
A solution can therefor be to overwrite the yaxis' _update_offset_text_position method to position the offsetText on the bottom of the yaxis.
import matplotlib.pyplot as plt
import types
def bottom_offset(self, bboxes, bboxes2):
bottom = self.axes.bbox.ymin
self.offsetText.set(va="top", ha="left")
self.offsetText.set_position(
(0, bottom - self.OFFSETTEXTPAD * self.figure.dpi / 72.0))
fig, ax = plt.subplots()
im = ax.imshow([[1e5,2e5],[0.1e5,1e5]])
cb = plt.colorbar(im)
cb.formatter.set_scientific(True)
cb.formatter.set_powerlimits((0,0))
def register_bottom_offset(axis, func):
axis._update_offset_text_position = types.MethodType(func, axis)
register_bottom_offset(cb.ax.yaxis, bottom_offset)
cb.update_ticks()
plt.show()
If the colorbar is positioned on the left side of the plot the following might look better:
self.offsetText.set(va="top", ha="right")
self.offsetText.set_position(
(1, bottom - self.OFFSETTEXTPAD * self.figure.dpi / 72.0))
Hmmm... Apparently, it's not possible to move colorbar's scientific base multiplier up or down, just slightly left or right.
Workaround would be to hide it and just add (same) custom text that would be positioned at the bottom (in my case):
cb.ax.yaxis.get_offset_text().set_visible(False)
cb.ax.text(0.5, -0.1, '1e4', va='bottom', ha='center', size=6)
If someone has more elegant solution, I would be happy to see it!

Plt.Error Upper Limits Have Tail End of Arrow Point At My Coordinate

For two days I've been trying to solve this problem.
I'm plotting upper limits, so I need downward pointing arrows to point at my points. Among other things, I've now tried using Plt.Error to get these arrows. The problem is, the tail end of the arrow points at the point and not the tip.
Below, I show my code for plotting this data leaving out the portion where I read in the data. In addition, I've added two images. The first image is the resulting plot. The second image is of the yellow arrow in that plot that is referring to the point (10,.0076) where you can clearly see the tail end of the arrow is point at that coordinate.
import matplotlib.pyplot as plt
import numpy as np
import pylab
f1 = plt.figure(0)
plt.errorbar(days,fluxdensity,yerr=0.01,uplims=True,linestyle='none',markeredgewidth=5,elinewidth=5)
plt.errorbar(days2, fluxdensity2, yerr=0.01,uplims=True,linestyle='none',markeredgewidth=5,elinewidth=5)
plt.errorbar(days3, fluxdensity3, yerr=0.01,uplims=True,linestyle='none',markeredgewidth=5,elinewidth=5)
plt.errorbar(days4, fluxdensity4,yerr=0.01,uplims=True,linestyle='none',markeredgewidth=5,elinewidth=5)
plt.grid()
plt.xlabel('Days Since Explosion', fontsize=18)
plt.ylabel('Flux Density muJy', fontsize=16)
plt.savefig('2014dtflux.pdf',format='pdf')
plt.xlim((9.9,10.1))
plt.ylim((-.03,.12))
plt.show()
Full Plot
Example of One Point Showing That The Tail of the Arrow is Pointing at (10,.0076)
It seems you want to draw an arrow. To draw an arrow in matplotlib, one may use a FancyArrowPatch.
import matplotlib.pyplot as plt
import matplotlib.patches as patches
style="Simple,tail_width=2,head_width=5,head_length=7"
kw = dict(arrowstyle=style, color="k")
a1 = patches.FancyArrowPatch((0,0.7), (0,0.5),**kw )
a2 = patches.FancyArrowPatch((0,0.4), (0.0,0.3),**kw)
for a in [a1,a2]:
plt.gca().add_patch(a)
plt.xlim(-1,1)
plt.show()

matplotlib - changing rect colours on the fly

I am playing with matplotlib - I have a bar chart, and I want to highlight the bar which user clicks. I have a callback that goes through a rect collection (the one I got from self.axis.bar(...)) and finds out which one was clicked (looking at the coordinates). At this point I want to call something to change the colour of the current bar. Is it possible? How do I do that?
Edited: I guess the answer I am really looking for is if it's possible to make bars to have different colours.
You can set the color of individual bars using the Artist properties. Here's an example:
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(111)
bars = ax1.bar(range(1,10), range(1,10), color='blue', edgecolor='black')
bars[6].set_facecolor('red')
plt.show()