X and Y Ticks on a 4x4 multiplot using matplotlib in Python - python

I am using Python3.6.5 from an Anaconda install.
I have 16 data files containing two columns of data. I am trying to make a plot that shows all the data in one 4x4 plot. I have managed to get all the plots plotted on a large 4x4 plot, but can't adjust the X and Y ticks. The X values range from 0 to 2000 and the Y values range from 0 to 4.5.
This is my current script:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import math
ph_values = [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5]
all_xs = []
all_ys = []
for ph in ph_values:
xs = []
ys = []
with open('rmsd_ph' + str(ph) + '.dat', "r") as f:
for line in f:
if line[0] != "#":
x,y = line.split()
xs.append(float(x))
ys.append(float(y))
all_xs.append(xs)
all_ys.append(ys)
fig, axes = plt.subplots(nrows=math.ceil(len(ph_values)/4), ncols=4, figsize=(6,6))
axes = axes.flatten()
for index,ph in enumerate(ph_values):
axes[index].plot(np.asarray(all_xs[index]),np.asarray(all_ys[index]))
plt.xticks(np.arange(0, 2000, step=500))
plt.tight_layout()
plt.savefig('test.pdf')
plt.show()
Currently the script outputs something that looks like this.
As you can see the last plot has the X-axis adjusted. I have not tried to adjust the Y-axis yet because I have not not been successful with the y axis.
Overall, I would like 4 ticks on both the y and x axis.

This is what I found that answered the problem I was having.
fig, axes = plt.subplots(nrows=math.ceil(len(ph_values)/4), ncols=4, figsize=(9,9))
axes = axes.flatten()
for index,ph in enumerate(ph_values):
axes[index].scatter(np.asarray(all_xs[index]),np.asarray(all_ys[index]), s=1)
plt.sca(axes[index]) <------------------ Fixed Problem
plt.xticks([0, 500, 1000, 1500, 2000]) <- Fixed Problem
plt.yticks([0, 1, 2, 3, 4, 5]) <---------- Fixed Problem
plt.title('pH:' + str(ph))
if (index % 4 == 0):
plt.ylabel('RMSD [$\\rm{\\AA}$]')
if (index >= 12):
plt.xlabel('Steps')
plt.tight_layout()
plt.savefig(output)
plt.show()
Here is an image of the result.

If I understand right that you'd like to have all x-axes comparable the same and so the y-axes, too, I'd recommend to try shared axes:
fig, axes = plt.subplots(4, 4, sharex=True, sharey=True, figsize=(6,6))

Related

Weird matplotlib contour plot axis labels shows two sets of values

I'm using matplotlib 3.3.4 and generating a basic contour plot. But when I do so, the X and Y axis labels are showing my desired range (e.g. 0 to pi) but there's also an extra set of labels showing up that appear to be some sort of normalized values (0 to 1). The following code reproduces this:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, np.pi, 40)
y = np.linspace(0, np.pi, 40)
z = np.sin(x[:, None])**2 + np.sin(y)**2
fig, ax = plt.subplots(figsize=(10,10))
ax = fig.add_subplot(111)
ax.contour(x, y, z)
and produces a plot like the one below. I see axis labels at the expected values [0, 0.5, 1.0, 1.5, 2.0, 2.5, and 3.0]. But there's another set [0, 0.2, 0.4, 0.6, 0.8, 1.0] that's coming from somewhere.
After reviewing the contour() example at Contour Example I realize I should probably be calling np.meshgrid() rather than doing the extra axis stuff to produce z above.
Any clues as to what is causing this odd axis label behavior?
You're adding two subplots, one via plt.subplots, and one via add_subplot. Remove one of them and the figure will only have one set of ticks:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, np.pi, 40)
y = np.linspace(0, np.pi, 40)
z = np.sin(x[:, None])**2 + np.sin(y)**2
fig, ax = plt.subplots(figsize=(10,10))
ax.contour(x, y, z)

How to make these sequential histogram/density estimates plots

Does anyone know how to make these sequential histogram/density estimates plots (source) in R or Python? I think I've also heard them called "waterfall" plots and "cascade" plots. It also kind of looks like the cover art of Joy Division's "Unknown Pleasures" album (c.f. that very popular t-shirt).
Here's another example, from a book I like:
As a python example from [matplotlib examples][1]https://matplotlib.org/examples/mplot3d/polys3d_demo.html
"""
=============================================
Generate polygons to fill under 3D line graph
=============================================
Demonstrate how to create polygons which fill the space under a line
graph. In this example polygons are semi-transparent, creating a sort
of 'jagged stained glass' effect.
"""
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.collections import PolyCollection
import matplotlib.pyplot as plt
from matplotlib import colors as mcolors
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
def cc(arg):
return mcolors.to_rgba(arg, alpha=0.6)
xs = np.arange(0, 10, 0.4)
verts = []
zs = [0.0, 1.0, 2.0, 3.0]
for z in zs:
ys = np.random.rand(len(xs))
ys[0], ys[-1] = 0, 0
verts.append(list(zip(xs, ys)))
poly = PolyCollection(verts, facecolors=[cc('r'), cc('g'), cc('b'),
cc('y')])
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, 4)
ax.set_zlabel('Z')
ax.set_zlim3d(0, 1)
plt.show()
The idea is to create the 3d line plot line by line and let each line define a polygone with a semi-transperent color to achieve a nice effect. To make it look even more like the one in your example, simple switch the color values and make the offset between the lines a little smaller.
EDIT:
I made an example for you based on the original code:
xs = np.arange(0, 10, 0.4)
verts = []
zs = np.arange(0, 5, 0.2)
for z in zs:
r=[int(np.random.normal(5,5)) for i in range(0,10000)]
ys = np.histogram(r,len(xs))[0]/10000
ys[0], ys[-1] = 0, 0
verts.append(list(zip(xs, ys)))
poly = PolyCollection(verts,facecolor='white')
poly.set_edgecolor('black')
This should come quite close to the effect you are looking for.

python2.7 draw simple polygon without self-intersection

I want to draw simple polygon that means there is no self-intersecting in the polygon using x & y locations. But what I got for the result is butterfly shape of polygon.
I know that if I change li_feasible_points to [[0,2],[2,2],[4,0],[2,0]] in order to draw simple polygon IN THIS TIME.
But WHAT I WANT is to draw simple polygon without self-intersecting by ANY list of corner points locations. Is there any way to solve this problem?
Here is my code and my result below.
from matplotlib import pyplot as plt
fig, ax = plt.subplots(figsize=(6, 6))
x_lim = 5
y_lim = 10
x = np.linspace(0, x_lim)
y = np.linspace(0, y_lim)
li_feasible_points = [[0.0, 2.0], [4.0, 0.0], [2.0, 0.0], [2.0, 2.0]]
line = plt.Polygon(li_feasible_points, closed=False, color='r', fill=True, edgecolor='r')
plt.gca().add_line(line)
plt.xlabel(li_var_names[0])
plt.ylabel(li_var_names[1])
plt.xlim(0, x_lim)
plt.ylim(0, y_lim)
plt.show()
I look forward to your help. Thank you.

How can i set the location of minor ticks in matplotlib

I want to draw a grid on the x-axis in a matplotlib plot at the positions of the minor ticks but not at the positions of the major ticks. My mayor ticks are at the positions 0, 1, 2, 3, 4, 5 and have to remain there. I want the grid at 0.5, 1.5, 2.5, 3.5, 4.5.
....
from matplotlib.ticker import MultipleLocator
....
minorLocator = MultipleLocator(0.5)
ax.xaxis.set_minor_locator(minorLocator)
plt.grid(which='minor')
The code above does not work since it gives the locations at 0.5, 1.0, 1.5, ... How can I set the positions of the minor ticks manually?
You can use matplotlib.ticker.AutoMinorLocator. This will automatically place N-1 minor ticks at locations spaced equally between your major ticks.
For example, if you used AutoMinorLocator(5) then that will place 4 minor ticks equally spaced between each pair of major ticks. For your use case you want AutoMinorLocator(2) to just place one at the mid-point.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import AutoMinorLocator
N = 1000
x = np.linspace(0, 5, N)
y = x**2
fig, ax = plt.subplots()
ax.plot(x, y)
minor_locator = AutoMinorLocator(2)
ax.xaxis.set_minor_locator(minor_locator)
plt.grid(which='minor')
plt.show()
Using AutoMinorLocator has the advantage that should you need to scale your data up, for example so your major ticks are at [0, 10, 20, 30, 40, 50], then your minor ticks will scale up to positions [5, 15, 25, 35, 45].
If you really need hard-set locations, even after scaling/changing, then look up matplotlib.ticker.FixedLocator. With this you can pass a fixed list, for example FixedLocator([0.5, 1.5, 2.5, 3.5, 4.5]).

Multiple imshow-subplots, each with colorbar

I want to have a figure consisting of, let's say, four subplots. Two of them are usual line-plots, two of them imshow-images.
I can format the imshow-images to proper plots itself, because every single one of them needs its own colorbar, a modified axis and the other axis removed.
This, however, seems to be absolutely useless for the subplotting. Can anyone help me with that?
I use this for displaying the data of the "regular" plots above as a colormap (by scaling the input-array i to [ i, i, i, i, i, i ] for 2D and calling imshow() with it).
The following code first displays what I need as a subplot and the second one shows all I can do, which is not sufficient.
#!/usr/bin/env python
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
s = { 't':1, 'x':[1,2,3,4,5,6,7,8], 'D':[0.3,0.5,0.2,0.3,0.5,0.5,0.3,0.4] }
width = 40
# how I do it in just one plot
tot = []
for i in range(width):
tot.append(s['D'])
plt.imshow(tot, norm=LogNorm(vmin=0.001, vmax=1))
plt.colorbar()
plt.axes().axes.get_xaxis().set_visible(False)
plt.yticks([0, 2, 4, 6], [s['x'][0], s['x'][2], s['x'][4], s['x'][6]])
plt.show()
f = plt.figure(figsize=(20,20))
plt.subplot(211)
plt.plot(s['x'], s['D'])
plt.ylim([0, 1])
#colorplot
sp = f.add_subplot(212)
#reshape (just necessary to see something)
tot = []
for i in range(width):
tot.append(s['D'])
sp.imshow(tot, norm=LogNorm(vmin=0.001, vmax=1))
#what I can't do now but needs to be done:
#sp.colorbar()
#sp.axes().axes.get_xaxis().set_visible(False)
#sp.yticks([0, 200, 400, 600, 800, 1000], [s['x'][0], s['x'][200], s['x'][400], s['x'][600], s['x'][800], s['x'][1000]])
plt.show()
You can make use of matplotlibs object oriented interface rather than the state-machine interace in order to get better control over each axes. Also, to get control over the height/width of the colorbar you can make use of the AxesGrid toolkit of matplotlib.
For example:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.colors import LogNorm
from matplotlib.ticker import MultipleLocator
s = {'t': 1,
'x': [1, 2, 3, 4, 5, 6, 7, 8],
'T': [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8],
'D': [0.3, 0.5, 0.2, 0.3, 0.5, 0.5, 0.3, 0.4]}
width = 40
tot = np.repeat(s['D'],width).reshape(len(s['D']), width)
tot2 = np.repeat(s['T'],width).reshape(len(s['D']), width)
fig, (ax1, ax2, ax3, ax4) = plt.subplots(1,4)
fig.suptitle('Title of figure', fontsize=20)
# Line plots
ax1.set_title('Title of ax1')
ax1.plot(s['x'], s['T'])
ax1.set_ylim(0,1)
ax2.set_title('Title of ax2')
ax2.plot(s['x'], s['D'])
# Set locations of ticks on y-axis (at every multiple of 0.25)
ax2.yaxis.set_major_locator(MultipleLocator(0.25))
# Set locations of ticks on x-axis (at every multiple of 2)
ax2.xaxis.set_major_locator(MultipleLocator(2))
ax2.set_ylim(0,1)
ax3.set_title('Title of ax3')
# Display image, `aspect='auto'` makes it fill the whole `axes` (ax3)
im3 = ax3.imshow(tot, norm=LogNorm(vmin=0.001, vmax=1), aspect='auto')
# Create divider for existing axes instance
divider3 = make_axes_locatable(ax3)
# Append axes to the right of ax3, with 20% width of ax3
cax3 = divider3.append_axes("right", size="20%", pad=0.05)
# Create colorbar in the appended axes
# Tick locations can be set with the kwarg `ticks`
# and the format of the ticklabels with kwarg `format`
cbar3 = plt.colorbar(im3, cax=cax3, ticks=MultipleLocator(0.2), format="%.2f")
# Remove xticks from ax3
ax3.xaxis.set_visible(False)
# Manually set ticklocations
ax3.set_yticks([0.0, 2.5, 3.14, 4.0, 5.2, 7.0])
ax4.set_title('Title of ax4')
im4 = ax4.imshow(tot2, norm=LogNorm(vmin=0.001, vmax=1), aspect='auto')
divider4 = make_axes_locatable(ax4)
cax4 = divider4.append_axes("right", size="20%", pad=0.05)
cbar4 = plt.colorbar(im4, cax=cax4)
ax4.xaxis.set_visible(False)
# Manually set ticklabels (not ticklocations, they remain unchanged)
ax4.set_yticklabels([0, 50, 30, 'foo', 'bar', 'baz'])
plt.tight_layout()
# Make space for title
plt.subplots_adjust(top=0.85)
plt.show()
You can change the locations and labels of the ticks on either axis with the set_ticks and set_ticklabels methods as in the example above.
As for what the make_axes_locatable function does, from the matplotlib site about the AxesGrid toolkit:
The axes_divider module provides a helper function
make_axes_locatable, which can be useful. It takes a existing axes
instance and create a divider for it.
ax = subplot(1,1,1)
divider = make_axes_locatable(ax)
make_axes_locatable returns an instance of the AxesLocator class,
derived from the Locator. It provides append_axes method that creates
a new axes on the given side of (“top”, “right”, “bottom” and “left”)
of the original axes.

Categories