Matplotlib two X axis position switching - python

I would like to make a plot having two X-axis.
But I would like to set the host x axis to top and the other x axis to bottom.
I tried:
axs[i].barh(bins[:len(count_vol)], count_vol, align='edge', color='black', height = 10) # horizontal bar plot
axs[i].set_xlabel('concentration (n/m3)')
axs[i].set_ylabel('depth (m)')
axs[i].invert_yaxis()
axs[i].set_title(org, y =1.0) # subplot title
axs[i].xaxis.set_major_formatter(FormatStrFormatter('%.2f'))
axs[i].xaxis.tick_top() # x axis to top of the subplot
#plt.show()
# add environmental data
temp_ax = axs[i].twiny()
temp_ax.plot(temperature, depth, color='red')
temp_ax.set_xlabel('temperature', color='red')
temp_ax.xaxis.tick_bottom() x axis to botton of the subplot
When I activatd 'plt.show()' the host x axis was on the top which I wanted to plot.
But after I ran whole script above, both x axis are on the bottom.
What is the problem with my code?

There are various ways to add an extra xaxis on top.
ticks and labels are with the wrong position
I guess temp_ax.xaxis.tick_bottom() is rebundant.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
fig, axs = plt.subplots(1, 3)
# secondary axis
axs[0].plot(x)
axs[0].set_xlabel('label bottom')
secax = axs[0].secondary_xaxis('top')
secax.set_xlabel('label top')
# twiny()
axs[1].set_xlabel('label bottom')
twax = axs[1].twiny()
twax.set_xlabel('label top')
# handle properties
axs[2].xaxis.tick_top()
axs[2].xaxis.set_label_position('top')
axs[2].set_xlabel('label top')
plt.show()

Related

Matplotlib plot style

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.

matplotlib, show only positive numbers starting from 0 on both sides on the X axis

I want to draw a plot with matplotlib with cylindrical symmetry. it means on both sides on X-axes positive (absolute values) numbers similar to this plot.
Plot that I get, but numbers on the left side of X-axes negative (that need to be positive too):
You are trying to change the format of the matplotlib.xaxis.Tick object label. In matplotlib there are usually a lot of ways to do things and this is no exception.
Matplotlib figures out where the ticks should be with a tick locator. Then a tick formatter defines what kind of text should be in those tick labels. The default formatter for numerical data is ScalarFormatter.
An alternative locator or formatter is easy to define with the matplotlib ticker library. Once you get the hang of this, its actually quite easy. Here is an example that shows how to fix your problem.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import ticker
# define fig and axes
fig, axes = plt.subplots(ncols=1, nrows=2, figsize=(17.5,6))
axes = axes.flatten() # make axes a 1D array
x = np.linspace(-20,20) # make some x values between -20 and 20
y = np.sin(x/4) # make some y values that are sin(x/4)
for ax in axes:
ax.plot(x, y, linewidth=2.5) # plot x and y values
#Make a function that makes negative values positive (lots of ways to do this)
def neg_to_pos(n, position):
n = int(n)
if n < 0:
return str(n * -1)
else:
return str(n)
#access the bottom plot object xaxis object and set the
#major tick formatter to be a FunctionFormatter that uses
#the neg_to_pos function
xaxis_formatter = axes[1].xaxis.set_major_formatter(ticker.FuncFormatter(neg_to_pos))
#add titles, x labels, and y labels
title_ax0 = axes[0].set_title('Default formatter', fontsize=14, fontweight='bold')
title_ax1 = axes[1].set_title('FuncFormatter', fontsize=14, fontweight='bold')
xlabels = [ax.set_xlabel('x_values') for ax in axes]
ylabels = [ax.set_ylabel('y_values') for ax in axes]
plt.subplots_adjust(hspace = 0.5) #fix the vertical spacing between the plots
The links I placed above for locators and formatters are bookmarked for me and I refer to them often when working on axis tick problems.

How to align logarithmic scale ticks across subplots?

I want to fix the position of the ticks on the logarithmic scale, such that they are the same in each subplot (see red annotation in image).
My code looks like this:
ax = fig.add_subplot(2,2, axis)
ax2 = ax.twinx()
ax2.set_yscale('log')
ax2.set_ylim(0,100)
Right now, set_yscale=('log') optimizes the tick spacing for each subplot. I prefer to adopt the tick spacing of the upper right subplot.
You can achieve this by getting the limits of the left twin axis and setting it as the limits of the right twin axis.
Consider the following working example. Follow this procedure for the subplots you want to align the axes of.
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 3))
axl = fig.add_subplot(121)
axr = fig.add_subplot(122)
ax1 = axl.twinx()
ax1.plot(np.logspace(-2, 3, 5))
ax1.set_yscale('log')
ax2 = axr.twinx()
ax2.plot(np.logspace(0, 3, 5))
ax2.set_yscale('log')
ax2.set_ylim(ax1.get_ylim()) # <-- This is the key line
plt.tight_layout()
plt.show()
OP's solution:
Plot a dummy curve and set alpha=0. Make sure the curve spans y_min and y_max.
fig = plt.figure()
axes = [1,2,3,4]
for axis in axes:
ax = fig.add_subplot(2,2, axis)
ax2 = ax.twinx()
ax2.set_yscale('log')
ax2.plot(x_dummy, y_dummy, alpha=0) # <-- dummy plot
x_real, y_real = func_that_loads_data() # <-- your interesting plot
curve1 = ax2.plot(x_real, y_real)
plt.show()
The solution provided by Sheldore was impractical to implement because I plot my data using a for-loop (unavoidable unless I escalate the number of variables).
Since I overwrite the ax variable on every iteration, I would have to save the y-limit as a global variable. Read here why global variables should be avoided.
ax = fig.add_subplot(2,2, axis)
ax2 = ax.twinx()
ax2.set_yscale('log')
if axis == 1:
global yscale
yscale = ax2.get_ylim() # <-- where the magic happens
elif axis > 1:
ax2.set_ylim(yscale)

plot changes not affecting all subplots [duplicate]

Im trying to plot a scatter matrix. I'm building on the example given in this thread Is there a function to make scatterplot matrices in matplotlib?. Here I have just modified the code slightly to make the axis visible for all the subplots. The modified code is given below
import itertools
import numpy as np
import matplotlib.pyplot as plt
def main():
np.random.seed(1977)
numvars, numdata = 4, 10
data = 10 * np.random.random((numvars, numdata))
fig = scatterplot_matrix(data, ['mpg', 'disp', 'drat', 'wt'],
linestyle='none', marker='o', color='black', mfc='none')
fig.suptitle('Simple Scatterplot Matrix')
plt.show()
def scatterplot_matrix(data, names, **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."""
numvars, numdata = data.shape
fig, axes = plt.subplots(nrows=numvars, ncols=numvars, figsize=(8,8))
fig.subplots_adjust(hspace=0.05, wspace=0.05)
for ax in axes.flat:
# Hide all ticks and labels
ax.xaxis.set_visible(True)
ax.yaxis.set_visible(True)
# # Set up ticks only on one side for the "edge" subplots...
# if ax.is_first_col():
# ax.yaxis.set_ticks_position('left')
# if ax.is_last_col():
# ax.yaxis.set_ticks_position('right')
# if ax.is_first_row():
# ax.xaxis.set_ticks_position('top')
# if ax.is_last_row():
# ax.xaxis.set_ticks_position('bottom')
# 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[x], data[y], **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')
# 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)
fig.tight_layout()
plt.xticks(rotation=45)
fig.show()
return fig
main()
I cant seem to be able to rotate the x-axis text of all the subplots. As it can be seen, i have tried the plt.xticks(rotation=45) trick. But this seems to perform the rotation for the last subplot alone.
Just iterate through the axes tied to the figure, set the active axes to the iterated object, and modify:
for ax in fig.axes:
matplotlib.pyplot.sca(ax)
plt.xticks(rotation=90)
plt only acts on the current active axes. You should bring it inside your last loop where you set some of the labels visibility to True:
# 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)
for tick in axes[i,j].get_xticklabels():
tick.set_rotation(45)
for tick in axes[j,i].get_xticklabels():
tick.set_rotation(45)
for ax in fig.axes:
ax.tick_params(labelrotation=90)

Tick properties for scatterplot matrices with Matplotlib

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:

Categories

Resources