Two questions:
-My y axis values have a space from the x axis, and I want it to be closen
-How do I add a color to everything, background ofthe image and graph.
Thank you
You want to change the xmin and ymin properties of the axis.
Note the the function is almost invisible near the origin.
import numpy as np
import matplotlib.pyplot as plt
# oh yes, y is quite flat about the origin
t = np.linspace(0, 1.57, 158)
y = t**5*np.cos(t)
fig, ax = plt.subplots(layout='constrained')
# change the colors of the graph and of the figure
fig.set_facecolor('k')
ax.set_facecolor('C3')
# change the colors of the text elements
plt.rc('axes', labelcolor='w')
plt.rc('xtick', color='w')
plt.rc('ytick', color='w')
plt.rc('text', color='w')
# plot y and label it properly
ax.plot(t, y, color='xkcd:pink', lw=2)
plt.xlabel('X', size='xx-large')
plt.ylabel('Y', size='x-large')
plt.title('As You Like It', color='xkcd:pink', size='xx-large')
###############################################################
# remove the despised space ###################################
plt.axis(xmin=0, ymin=0) ######################################
###############################################################
plt.show()
I'd suggest to remove plt.axis(...) and use plt.grid(1), obtaining the figure below.
Related
I`d like to have a multiline figure with a dataframe.
Original data is as following:
from numpy.random import randn
import numpy as np
df=pd.DataFrame()
df['Years']=range(1995,2013)
np.random.seed(0)
df['Goverment']=randn(len(df.Years))
df['Household']=randn(len(df.Years))
df['Corporate']=randn(len(df.Years))
print(df)
and I want to set the legend along fully the bound pf figure box. I referred to the answer of #Joe Kington but this problem hasn`t been solved.
For plotting:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(10,6))
ax = plt.subplot(111)
ax.plot(df.Years, df.Government,ls='--',label='Goverment',color='black')
ax.plot(df.Years,df.Household,ls=':',label='Household',color='black')
ax.plot(df.Years,df.Corporate,ls='-',label='Corporate',color='black')
plt.xlabel("common X")
box = ax.get_position()
ax.set_position([box.x0, box.y0 + box.height * 0.1,
box.width, box.height * 1])
# Put a legend below current axis
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.1),borderaxespad=1,mode='expand',ncol=3)
plt.show()
and the following is my result. Apparently the mode='expand' doesn`t work here.
My questions are:
1. Why the values on X axis are not integral but floats?
2. How to expand the legend box into one line instrad fully along the bound of box?
The ideal legend box should be:
The difference is indeed that you use the mode='expand'. Now this will tell the legend to expand in its bounding box. However the bounding box has no extent, it is a single point. The legend will hence expand inside a zero-width box and hence become shrunk to zero width itself.
The solution is to specify a bounding box with 4 coordinates (i.e. a true box). In principle this should also be explained in my answer to the linked question. So here we would use axes coordinates for the bbox_transform and make the box one unit in axes coordinates wide.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig = plt.figure()
fig.subplots_adjust(bottom=0.2, top=0.95)
ax = plt.subplot(111)
for i in range(5):
line, = ax.plot(x, i * x, label='$y = %ix$'%i)
# Put a legend below current axis
ax.legend(loc="upper center", mode='expand',
bbox_to_anchor=(0,-0.2,1,.1), bbox_transform=ax.transAxes,
fancybox=True, shadow=True, ncol=5)
plt.show()
How can I add a string label to the horizontal red line showed in the following plot? I want to add something like "k=305" to the y-axis label next to the line. The blue dots are just some other data and the values do not matter. For recreation of this problem, you can plot any kind of data. My question is about the red line.
plt.plot((0,502),(305,305),'r-')
plt.title("ALS+REG")
A horizontal line can be drawn using Axes.axhline(y).
Adding a label would be done by using Axes.text(). THe tricky bit is to decide upon the coordinates at which to place that text. Since the y coordinate should be the data coordinate at which the line is drawn, but the x coordinate of the label should be the independent of the data (e.g. allow for differen axis scales), we can use a blended transform, where the x transform is the transform of the axis ylabels, and the y transform is the data coordinate system.
import matplotlib.pyplot as plt
import matplotlib.transforms as transforms
import numpy as np; np.random.seed(42)
N = 120
x = np.random.rand(N)
y = np.abs(np.random.normal(size=N))*1000
mean= np.mean(y)
fig, ax=plt.subplots()
ax.plot(x,y, ls="", marker="o", markersize=2)
ax.axhline(y=mean, color="red")
trans = transforms.blended_transform_factory(
ax.get_yticklabels()[0].get_transform(), ax.transData)
ax.text(0,mean, "{:.0f}".format(mean), color="red", transform=trans,
ha="right", va="center")
plt.show()
Is there any automatic way of manipulating legend in matplotlib to avoid overlapping data points and legend? I have lots of data points and fixed y axis range, can I instruct matplotlib move the legend to left or down if it's on datapoints. Thanks
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(1, 100)
y = -1/x
plt.plot(x,y, label='x and y', linewidth=30)
plt.legend()
plt.show()
You can manually position the legend to the position that you want it, the documentation can be found here.. You can also move it off the plotting area of the graph to avoid any chance of an overlap as shown in the code below:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(1, 100)
y = -1/x
plt.plot(x,y, label='x and y', linewidth=30)
#adjust the plot to allow the legend to fit nicely
plt.subplots_adjust(left=0.1,right = 0.75)
plt.legend(bbox_to_anchor=(1.01, 0.5), loc=2) # move the legend
plt.show()
The resulting image is shown below:
Note: If you plan on moving the legend outside of the plotting area then you may have to adjust your plots as I have done in the code above.
I am trying to plot a scatterplot matrix based on the code written by Joe Kington: Is there a function to make scatterplot matrices in matplotlib?
Some people already helped me: Thank you again (especially J.K.).
I am having a last problem: I cannot rotate the ticks of some axis for which numbers overlap (bottom left):
I would like to try to have them vertical but I cannot do it.... Here is my code:
import itertools
import numpy as np
import pylab as plot
import scipy
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import axis
import math
from matplotlib import rc
import os
import platform
def main():
FigSize=8.89
FontSize=8
np.random.seed(1977)
numvars, numdata = 4, 10
data = 10 * np.random.random((numvars, numdata))
fig = scatterplot_matrix(data, ['mpg', 'disp', 'drat', 'wt'], FigSize, FontSize,
linestyle='none', marker='o', color='black', mfc='none', markersize=3,)
fig.suptitle('Simple Scatterplot Matrix')
plt.savefig('Plots/ScatterplotMatrix/ScatterplotMatrix2.pdf',format='pdf', dpi=1000, transparent=True, bbox_inches='tight')
plt.show()
def scatterplot_matrix(data, names, FigSize, FontSize, **kwargs):
"""Plots a scatterplot matrix of subplots. Each row of "data" is plotted
against other rows, resulting in a nrows by nrows grid of subplots with the
diagonal subplots labeled with "names". Additional keyword arguments are
passed on to matplotlib's "plot" command. Returns the matplotlib figure
object containg the subplot grid."""
legend=['(kPa)','\%','\%','\%']
numvars, numdata = data.shape
fig, axes = plt.subplots(nrows=numvars, ncols=numvars, figsize=(FigSize/2.54,FigSize/2.54))
fig.subplots_adjust(hspace=0.05, wspace=0.05)
sub_labelx_top=[2,4]
sub_labelx_bottom=[13,15]
sub_labely_left=[5,13]
sub_labely_right=[4,12]
for i, ax in enumerate(axes.flat, start=1):
# Hide all ticks and labels
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
ax.xaxis.set_major_locator(MaxNLocator(prune='both',nbins=4))
ax.yaxis.set_major_locator(MaxNLocator(prune='both',nbins=4)) #http://matplotlib.org/api/ticker_api.html#matplotlib.ticker.MaxNLocator
# Set up ticks only on one side for the "edge" subplots...
if ax.is_first_col():
ax.yaxis.set_ticks_position('left')
ax.tick_params(direction='out')
ax.yaxis.set_tick_params(labelsize=0.75*FontSize)
if i in sub_labely_left:
ax.yaxis.set_label_position('left')
ax.set_ylabel('(\%)',fontsize=0.75*FontSize)
if ax.is_last_col():
ax.yaxis.set_ticks_position('right')
ax.tick_params(direction='out')
ax.yaxis.set_tick_params(labelsize=0.75*FontSize)
if i in sub_labely_right:
ax.yaxis.set_label_position('right')
if i==4:
ax.set_ylabel('(kPa)',fontsize=0.75*FontSize)
else:
ax.set_ylabel('(\%)',fontsize=0.75*FontSize)
if ax.is_first_row():
ax.xaxis.set_ticks_position('top')
ax.tick_params(direction='out')
ax.xaxis.set_tick_params(labelsize=0.75*FontSize)
if i in sub_labelx_top:
ax.xaxis.set_label_position('top')
ax.set_xlabel('(\%)',fontsize=0.75*FontSize)
if ax.is_last_row():
ax.xaxis.set_ticks_position('bottom')
ax.tick_params(direction='out')
ax.xaxis.set_tick_params(labelsize=0.75*FontSize)
if i in sub_labelx_bottom:
ax.xaxis.set_label_position('bottom')
if i==13:
ax.set_xlabel('(kPa)',fontsize=0.75*FontSize)
else:
ax.set_xlabel('(\%)',fontsize=0.75*FontSize)
# Plot the data.
for i, j in zip(*np.triu_indices_from(axes, k=1)):
for x, y in [(i,j), (j,i)]:
axes[x,y].plot(data[y], data[x], **kwargs)
# Label the diagonal subplots...
for i, label in enumerate(names):
axes[i,i].annotate(label, (0.5, 0.5), xycoords='axes fraction',
ha='center', va='center',fontsize=FontSize)
# Turn on the proper x or y axes ticks.
for i, j in zip(range(numvars), itertools.cycle((-1, 0))):
axes[j,i].xaxis.set_visible(True)
axes[i,j].yaxis.set_visible(True)
return fig
main()
My second question is more for the 'fun': how can I make the subplots perfectly squares?
I apologize to Joe Kington; I know my code is way less elegant than his... I just started few weeks ago. If you have any suggestions to improve mine, for example to make it more dynamic, I am very interesting.
You can rotate the xtick labels using setp.
from matplotlib.artist import setp
Then after you set the x tick positions for the top row and left column of subplot call:
setp(ax.get_xticklabels(), rotation=90)
To make the size of the subplots equal, you can fig.subplots_adjust to set the area of all the subplots to a square. Something like this:
gridSize = 0.6
leftBound = 0.5 - gridSize/2
bottomBound = 0.1
rightBound = leftBound + gridSize
topBound = bottomBound + gridSize
fig.subplots_adjust(hspace=0.05, wspace=0.05, left=leftBound,
bottom=bottomBound, right=rightBound, top=topBound)
If the figure size isn't square, you'll need to change the shape of the grid accordingly. Alternately, you could add each subplot axes individually with fig.add_axes. That will allow you to set the size directly but you'll also have to set the location.
Don't use bbox_inches='tight' to save the figure or you'll lose the title with these setting. You can save like this:
plt.savefig('ScatterplotMatrix.pdf',format='pdf', dpi=1000, transparent=True)
The resulting graph looks like this:
I am trying to work out how to set/correct the position of tick labels for a 3D matplotlib plot. Tick labels do not align with the ticks. The issue seems to be especially prominent when many tick labels are required.
I have modified an example (http://matplotlib.org/examples/mplot3d/polys3d_demo.html) from the matplotlib documentation to illustrate my question.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.collections import PolyCollection
from matplotlib.colors import colorConverter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(10,10))
ax = fig.gca(projection='3d')
cc = lambda arg: colorConverter.to_rgba(arg, alpha=0.6)
xs = np.arange(0, 10, 0.4)
verts = []
zs = np.arange(50)
for z in zs:
ys = np.ones(len(xs))*z
ys[0], ys[-1] = 0, 0
verts.append(list(zip(xs, ys)))
poly = PolyCollection(verts,facecolor='c')
poly.set_alpha(0.7)
ax.add_collection3d(poly, zs=zs, zdir='y')
ax.set_xlabel('X')
ax.set_xlim3d(0, 10)
ax.set_ylabel('Y')
ax.set_ylim3d(-1, len(zs))
ax.set_yticks(np.arange(len(zs)))
labels = {}
for l_c in zs:
labels[l_c] = 'This Looks Bad'
ax.set_yticklabels(labels,rotation=-15)
ax.set_zlabel('Z')
ax.set_zlim3d(0, ys.max())
plt.show()
So the question is: how can I get the tick labels to align with the tick positions?
By using these alignments, I get much better placements:
ax.set_yticklabels(labels,rotation=-15,
verticalalignment='baseline',
horizontalalignment='left')
I've modified the example with less tick markers so you can see the placement:
They do align, but with the horizontal position centered at the tick. Because of the 3D view this makes them appear a bit below where you would expect them to be. The effect is not related to the amount of ticks but to the width.
Specifically setting the alignment will help. Try adding:
ax.set_yticklabels(labels,rotation=-15, va='center', ha='left')
Play around a bit with the different alignments to see which you prefer, i think you're after ha='left'.
Reducing the padding, distance from the tick, might also help.
You can also set the pad argument as negative in the tick_params options for each axis. Like this:
ax.tick_params(axis='x', which='major', pad=-3)
This might help to adjust the distance between tick labels and axis.