Matplotlib Title location - python

i have this several plots and want to correct the title name location. I want to make the Vertical Acceleration (y) on the middle left vertically and the Flare Time (x) on the middle bot horizontally also the Test Title on middle top. Basically I want to be able to move the label location.
Below is the code
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import NullFormatter
x = ip.RESULTS
y = Vert
xy = np.vstack([x,y])
z = gaussian_kde(xy)(xy)
idx = z.argsort()
x, y, z = x[idx], y[idx], z[idx]
nullfmt = NullFormatter() # no labels
# definitions for the axes
left, width = 0.1, 0.65
bottom, height = 0.1, 0.65
bottom_h = left_h = left + width + 0.02
rect_scatter = [left, bottom, width, height]
rect_histx = [left, bottom_h, width, 0.2]
rect_histy = [left_h, bottom, 0.2, height]
# start with a rectangular Figure
plt.figure(1, figsize=(8, 8))
axScatter = plt.axes(rect_scatter)
#plt.plot(np.unique(x), np.poly1d(np.polyfit(x, y, 1))(np.unique(x)))
#plt.plot(np.unique(x), np.poly1d(np.polyfit(x, y, 1))(np.unique(x)))
axHistx = plt.axes(rect_histx)
axHisty = plt.axes(rect_histy)
# no labels
axHistx.xaxis.set_major_formatter(nullfmt)
axHisty.yaxis.set_major_formatter(nullfmt)
# the scatter plot:
axScatter.scatter(x, y, c=z, s=50, edgecolor='')
# now determine nice limits by hand:
binwidth = 1
xymax = np.max([np.max(np.fabs(x)), np.max(np.fabs(y))])
lim = (int(xymax/binwidth) + 1) * binwidth
bins = np.arange(-lim, lim + binwidth, binwidth)
axHistx.hist(x)
axHisty.hist(y, orientation='horizontal')
plt.title('test title', fontsize=20)
axHisty.set_xlabel("Vertical Acceleration")
axHistx.set_xlabel("Flare Time")
and the results look like this. Any help would be appreciated

You have three Axes objects (plot rectangles to say it sloppy) in your graph: axScatter is your main chart in the bottom left. axHisty is the histogram on the right and axHistx is the histogram on the top. Your axis titles belong on the y- and x-axis of axScatter. So just do:
axScatter.set_ylabel('Vertical Acceleration')
axScatter.set_xlabel('Flare Time')
Based on your vague question I have no idea where you want the "test title", but just figure out which Axes object is best and give it an xlabel, ylabel or title.

Related

How to create a horizontal histogram the other way around?

The gallery of matplotlib has a 2D scatter plot with two adjacent histograms for the marginal distribution of x and y values at the top and right, respectively. I want to modify that to show the histogram of y values on the left (instead of the right) but also oriented towards the scatter plot.
All I managed so far was to merely move it from the right to the left (see below), but not re-orientate it towards the scatter plot. How can I achieve that?
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
# some random data
x = np.random.randn(1000)
y = np.random.randn(1000)
def scatter_hist(x, y, ax, ax_histx, ax_histy):
# no labels
ax_histx.tick_params(axis="x", labelbottom=False)
ax_histy.tick_params(axis="y", labelleft=True,labelright=False)
ax.tick_params(axis="y", left=False,labelleft=False,right=True,labelright=True)
# the scatter plot:
ax.scatter(x, y)
# now determine nice limits by hand:
binwidth = 0.25
xymax = max(np.max(np.abs(x)), np.max(np.abs(y)))
lim = (int(xymax/binwidth) + 1) * binwidth
bins = np.arange(-lim, lim + binwidth, binwidth)
ax_histx.hist(x, bins=bins)
ax_histy.hist(y, bins=bins, orientation='horizontal')
# definitions for the axes
left, width = 0.3, 0.65
bottom, height = 0.1, 0.65
spacing = 0.005
rect_scatter = [left, bottom, width, height]
rect_histx = [left, bottom + height + spacing, width, 0.2]
rect_histy = [left-spacing-0.2, bottom, 0.2, height]
# start with a square Figure
fig = plt.figure(figsize=(8, 8))
ax = fig.add_axes(rect_scatter)
ax_histx = fig.add_axes(rect_histx, sharex=ax)
ax_histy = fig.add_axes(rect_histy, sharey=ax)
# use the previously defined function
scatter_hist(x, y, ax, ax_histx, ax_histy)
plt.show()
and here the result:
This can be achieved by setting the y-axis limit in the opposite direction.
ax_histy.hist(y, bins=bins, orientation='horizontal')
ax_histy.set_xlim(100,0) # add

Embed a small radarchart into matplotlib plot

Right now I can create a radarchart as follows. Note that I made it a function just so that I can simply insert the function into my larger scatterplot more cleanly.
Radar Chart
def radarChart(PlayerLastName):
playerdf = dg.loc[dg['Player Name'] == name].index.tolist()[0]
#print(playerdf)
labels=np.array(['SOG', 'SH', 'G', 'A'])
stats=dg.loc[playerdf,labels].values
#print(stats)
# Set the angle of polar axis.
# And here we need to use the np.concatenate to draw a closed plot in radar chart.
angles=np.linspace(0, 2*np.pi, len(labels), endpoint=False)
# close the plot
stats=np.concatenate((stats,[stats[0]]))
angles=np.concatenate((angles,[angles[0]]))
fig = plt.figure()
ax = fig.add_subplot(111, polar=True)
ax.plot(angles, stats, 'o-', linewidth=1)
ax.fill(angles, stats, alpha=0.3)
ax.set_thetagrids(angles * 180/np.pi, labels)
#plt.title(PlayerLastName + ' vs. ' + namegame)
ax.grid(True)
return
I then want to put this figure in the bottom right of my scatter plot I have elsewhere. This other article does not provide me with any way to do this since my plot is circular. Any help would be great!
When I call radarChart('someones name') I get
I would really like to not have to save it as an image first and then put it in the plot.
I am not sure, what your desired output is. You should always provide a Minimal, Complete, and Verifiable example. Apart from this, I don't know, why a polar plot would be different from any other plot to create an inset:
import matplotlib.pyplot as plt
import numpy as np
#function for the polar plot
def radarChart(Player = "SOG", left = .3, bottom = .6, width = .2, height = .2):
#labels and positions
labels = np.array(['SOG', 'SH', 'G', 'A'])
angles = np.linspace(0, 360, len(labels), endpoint = False)
#inset position
ax = plt.axes([left, bottom, width, height], facecolor = "lightblue", polar = True)
#label polar chart
ax.set_thetagrids(angles, labels)
#polar chart title
plt.title(Player, loc = "left")
return ax
#main figure
x = np.linspace (-3, 1, 1000)
y = 2 * np.exp(3 - x) - 1
plt.plot(x, y)
plt.xlabel("x values")
plt.ylabel("y values")
plt.title("figure with polar insets")
#inset 1
ax = radarChart(Player = "A")
plt.scatter(x[::50], y[::50])
#inset 2
ax = radarChart(left = .6, bottom = .4, width = .2, height = .2)
plt.plot(x, y)
plt.show()
Sample output:

Move x-axis tick labels one position to left [duplicate]

This question already has answers here:
Aligning rotated xticklabels with their respective xticks
(5 answers)
Closed 4 months ago.
I am making a bar chart and I want to move the x-axis tick labels one position to left. Here is the code of the plot:
matplotlib.rcParams.update(matplotlib.rcParamsDefault)
plt.style.use(['seaborn-white', 'bmh'])
fig1, ax = plt.subplots()
palette = ['#2a5495', '#07a64c', '#e979ad', '#d88432', '#2a5495',
'#b7040e', '#82c5db', '#b9c09b', '#cd065d', '#4b117f']
x = np.array(df.index)
y = np.array(df.loc[:, 2015])
width = 1.0
lefts = [x * width for x, _ in enumerate(y)]
ax.bar(left = lefts, height = y, width = width, tick_label = x, color = palette, label = ranked_univs)
ax.axis(ymin = 0, ymax = 200, xmin = -0.5, xmax = 9.5)
ax.tick_params(axis='x', which='major', labelsize=8)
ax.set_xticklabels(ax.xaxis.get_majorticklabels(), rotation=45)
fig1.tight_layout()
plt.show()
And here is the bar chart:
Any clue?
Your labels are correctly positioned, as shown by the fact that if you were to rotate them 90°, they would be perfectly aligned with your bars.
fig1, ax = plt.subplots()
palette = ['#2a5495', '#07a64c', '#e979ad', '#d88432', '#2a5495',
'#b7040e', '#82c5db', '#b9c09b', '#cd065d', '#4b117f']
labels = ['Long misaligned label {}'.format(i) for i in range(10)]
x = range(10)
y = 100+100*np.random.random((10,))
width = 1.0
lefts = [x * width for x, _ in enumerate(y)]
ax.bar(left = lefts, height = y, width = width, tick_label = labels, color = palette)
ax.axis(ymin = 0, ymax = 200, xmin = -0.5, xmax = 9.5)
ax.tick_params(axis='x', which='major', labelsize=8)
ax.set_xticklabels(ax.xaxis.get_majorticklabels(), rotation=90)
fig1.tight_layout()
plt.show()
The problem is that the labels are centered horizontally, so when you rotate them 45°, they appear to be aligned with the wrong bar. To fix this, align the labels to the right, and they'll get back to their correct (visual) position.
plt.setp(ax.xaxis.get_majorticklabels(), ha='right')
Another (maybe simpler) option is to use the helper function Figure.autofmt_xdate(), which handles all of this for you.
See this question: How can I rotate xticklabels in matplotlib so that the spacing between each xticklabel is equal?
There the solution is to align the labels to their right side:
ax.set_xticklabels(xticklabels, rotation = 45, ha="right")

Legend combined with Text, how to find the legend width and height

I would like to set legend and text boxes locations and styles exactly same, the latter especially to make text aligned.
import matplotlib.pyplot as plt
x = np.arange(10)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
for i in range(3):
ax.plot(x, i * x ** 2, label = '$y = %i x^2$'%i)
ax.set_title('example plot')
# Shrink the axis by 20% to put legend and text at the bottom
#+ of the figure
vspace = .2
box = ax.get_position()
ax.set_position([box.x0, box.y0 + box.height * vspace,
box.width, box.height * (1 - vspace)])
# Put a legend to the bottom left of the current axis
x, y = 0, 0
# First solution
leg = ax.legend(loc = 'lower left', bbox_to_anchor = (x, y), \
bbox_transform = plt.gcf().transFigure)
# Second solution
#leg = ax.legend(loc = (x, y)) , bbox_transform = plt.gcf().transFigure)
# getting the legend location and size properties using a code line I found
#+ somewhere in SoF
bb = leg.legendPatch.get_bbox().inverse_transformed(ax.transAxes)
ax.text(x + bb.width, y, 'some text', transform = plt.gcf().transFigure, \
bbox = dict(boxstyle = 'square', ec = (0, 0, 0), fc = (1, 1, 1)))
plt.show()
This should place the text at the right of the legend box but that's not what it does. And the two boxes are not vertically aligned.
The second solution does not actually anchoring the legend to the figure, but to the axes instead.
You can use the frame data to get the right width in order to position the Text() object correctly.
In the example below I had to apply a 1.1 factor for the width (this value I haven't found how to get, and if you don't apply the factor the text clashes with the legend).
Note also that you must plt.draw() before getting the right width value.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig = plt.figure(figsize=(3, 2))
ax = fig.add_subplot(1, 1, 1)
for i in range(3):
ax.plot(x, i*x**2, label=r'$y = %i \cdot x^2$'%i)
ax.set_title('example plot')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
x, y = 0.2, 0.5
leg = ax.legend(loc='lower left', bbox_to_anchor=(x, y),
bbox_transform=fig.transFigure, fontsize=8)
plt.draw()
f = leg.get_frame()
w0, h0 = f.get_width(), f.get_height()
inv = fig.transFigure.inverted()
w, h = inv.transform((w0, h0))
ax.text(x+w*1.1, y+h/2., 'some text', transform=fig.transFigure,
bbox=dict(boxstyle='square', ec=(0, 0, 0), fc=(1, 1, 1)),
fontsize=7)
fig.savefig('test.jpg', bbox_inches='tight')
for x, y = 0.2, 0.5:
for x, y = -0.3, -0.3:

How do I offset lines in matplotlib by X points

I'm using matplotlib to plot some data that I wish to annotate with arrows (distance markers). These arrows should be offset by several points so as not to overlap with the plotted data:
import matplotlib.pyplot as plt
import matplotlib.transforms as transforms
fig, ax = plt.subplots()
x = [0, 1]
y = [0, 0]
# Plot horizontal line
ax.plot(x, y)
dy = 5/72
offset = transforms.ScaledTranslation(0, dy, ax.get_figure().dpi_scale_trans)
verttrans = ax.transData+offset
# Plot horizontal line 5 points above (works!)
ax.plot(x, y, transform = verttrans)
# Draw arrow 5 points above line (doesn't work--not vertically translated)
ax.annotate("", (0,0), (1,0),
size = 10,
transform=verttrans,
arrowprops = dict(arrowstyle = '<|-|>'))
plt.show()
Is there any way to make lines drawn by ax.annotate() be offset by X points? I wish to use absolute coordinates (e.g., points or inches) instead of data coordinates because the axis limits are prone to changing.
Thanks!
The following code does what I desired. It uses ax.transData and figure.get_dpi():
import matplotlib.pyplot as plt
import matplotlib.transforms as transforms
fig, ax = plt.subplots()
x = [0, 1]
y = [0, 0]
ax.plot(x, y)
dy = 5/72
i = 1 # 0 for dx
tmp = ax.transData.transform([(0,0), (1,1)])
tmp = tmp[1,i] - tmp[0,i] # 1 unit in display coords
tmp = 1/tmp # 1 pixel in display coords
tmp = tmp*dy*ax.get_figure().get_dpi() # shift pixels in display coords
ax.plot(x, y)
ax.annotate("", [0,tmp], [1,tmp],
size = 10,
arrowprops = dict(arrowstyle = '<|-|>'))
plt.show()
What's your expected output? If you're just looking to move the arrow you're drawing vertically, the API for annotate is
annotate(s, xy, xytext=None, ...)
so you can draw something like
ax.annotate("", (0,0.01), (1,0.01),
size = 10,
arrowprops = dict(arrowstyle = '<|-|>'))
which is moved up by 0.01 in data coordinates in the y direction. You can also specify coordinates as a fraction of the total figure size in annotate (see doc). Is that what you wanted?

Categories

Resources