How to get blue points in front of the gray points, please? Why the order is not working?
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(10, 6))
ax3 = ax.twiny()
ax3.errorbar([1, 2, 3, 4], [1, 2, 3, 4], yerr = [1, 2, 3, 4], fmt='o', color='gray', zorder = 1)
ax3.plot([-1,4], [1,2], c = 'black', zorder = 2)
ax3.tick_params(axis='x')
ax3.tick_params(axis='x', colors='gray')
ax3.set_xlim(-1,4)
ax.tick_params(axis='x')
ax.tick_params(axis='x', colors='mediumblue')
ax.grid(color='grey', linestyle='-', linewidth=0.5, zorder = 1)
ax.errorbar([1.1, 2.1, 3.1, 4.1, 2.91], [1.1, 2.1, 3.1, 4.1,2], yerr = [1.1, 2.1, 3.1, 4.1,1], fmt='o', color='mediumblue', zorder = 4, capsize=0.1)
plt.tight_layout()
plt.show()
You can set the order using ax.set_zorder(ax3.get_zorder()+1); ax.patch.set_visible(False) which will help bring the blue line in front.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(10, 6))
ax3 = ax.twiny()
ax3.errorbar([1, 2, 3, 4], [1, 2, 3, 4], yerr = [1, 2, 3, 4], fmt='o', color='gray', zorder = 1)
ax3.plot([-1,4], [1,2], c = 'black', zorder = 2)
ax3.tick_params(axis='x')
ax3.tick_params(axis='x', colors='gray')
ax3.set_xlim(-1,4)
ax.tick_params(axis='x')
ax.tick_params(axis='x', colors='mediumblue')
ax.grid(color='grey', linestyle='-', linewidth=0.5, zorder = 1)
ax.errorbar([1.1, 2.1, 3.1, 4.1, 2.91], [1.1, 2.1, 3.1, 4.1,2], yerr = [1.1, 2.1, 3.1, 4.1,1], fmt='o', color='mediumblue', zorder = 4, capsize=0.1)
ax.grid(axis='y')
ax.set_zorder(ax3.get_zorder()+1)
ax.patch.set_visible(False)
plt.tight_layout()
plt.show()
Related
How to:
display symbols in the legend
colour markers in the same way as the errorbars (argument color gives an error: ValueError: RGBA sequence should have length 3 or 4
remove connecting lines - get only the scatter with errorbars
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D # for legend handle
fig, ax = plt.subplots(figsize = (10,10))
times = [1, 2, 3, 4, 5]
rvs = [2, 4, 2, 4, 7]
sigma = [0.564, 0.6, 0.8, 0.8, 0.4]
rv_telescopes = ['A', 'B', 'A', 'C', 'C']
d = {'rv_times': times, 'rv_rvs': rvs, 'rv_sigma': sigma, 'rv_telescopes': rv_telescopes }
df = pd.DataFrame(data=d)
colors = {'A':'#008f00', 'B':'#e36500', 'C':'red'}
plt.errorbar(df['rv_times'], df['rv_rvs'], df['rv_sigma'], marker = '_', ecolor = df['rv_telescopes'].map(colors), color = df['rv_telescopes'].map(colors), zorder = 1, ms = 30)
handles = [Line2D([0], [0], marker='_', color='w', markerfacecolor=v, label=k, markersize=10) for k, v in colors.items()]
ax.legend(handles=handles, loc='upper left', ncol = 2, fontsize=14)
plt.show()
After edit
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D # for legend handle
import pandas as pd
import numpy as np
times = [1, 2, 3, 4, 5]
rvs = [2, 4, 2, 4, 7]
sigma = [0.564, 0.6, 0.8, 0.8, 0.4]
rv_telescopes = ['A', 'B', 'A', 'C', 'C']
d = {'rv_times': times, 'rv_rvs': rvs, 'rv_sigma': sigma, 'rv_telescopes': rv_telescopes}
df = pd.DataFrame(data=d)
colors = {'A': '#008f00', 'B': '#e36500', 'C': 'red'}
fig, ax = plt.subplots(figsize=(10, 10))
ax.errorbar(df['rv_times'], df['rv_rvs'], df['rv_sigma'], color='none', ecolor=df['rv_telescopes'].map(colors) ,linewidth=1)
ax.scatter(df['rv_times'], df['rv_rvs'], marker='_', linewidth=3, color=df['rv_telescopes'].map(colors), s=1000)
for rv_teles in np.unique(df['rv_telescopes']):
color = colors[rv_teles]
df1 = df[df['rv_telescopes'] == rv_teles] # filter out rows corresponding to df['rv_telescopes']
ax.errorbar(df1['rv_times'], df1['rv_rvs'], df1['rv_sigma'],
color=color, ls='', marker='_', ms=30, linewidth=3, label=rv_teles)
ax.legend(loc='upper left', ncol=1, fontsize=14)
plt.show()
plt.errorbar() works very similar to plt.plot() with extra parameters. As such, it primarily draws a line graph, using a single color. The error bars can be given individual colors via the ecolor= parameter. The markers, however, get the same color as the line graph. The line graph can be suppressed via an empty linestyle. On top of that, plt.scatter() can draw markers with individual colors.
In order not the mix the 'object-oriented' with the 'functional interface', the following example code uses ax.errorbar() and ax.scatter().
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D # for legend handle
import pandas as pd
import numpy as np
times = [1, 2, 3, 4, 5]
rvs = [2, 4, 2, 4, 7]
sigma = [0.564, 0.6, 0.8, 0.8, 0.4]
rv_telescopes = ['A', 'B', 'A', 'C', 'C']
d = {'rv_times': times, 'rv_rvs': rvs, 'rv_sigma': sigma, 'rv_telescopes': rv_telescopes}
df = pd.DataFrame(data=d)
colors = {'A': '#008f00', 'B': '#e36500', 'C': 'red'}
fig, ax = plt.subplots(figsize=(10, 10))
ax.errorbar(df['rv_times'], df['rv_rvs'], df['rv_sigma'], color='none', ecolor=df['rv_telescopes'].map(colors))
ax.scatter(df['rv_times'], df['rv_rvs'], marker='_', color=df['rv_telescopes'].map(colors), s=100)
handles = [Line2D([0], [0], linestyle='', marker='_', color=v, label=k, markersize=10) for k, v in colors.items()]
ax.legend(handles=handles, loc='upper left', ncol=1, fontsize=14)
plt.show()
A far easier approach would be to call ax.errorbar() multiple times, once for each color. This would automatically create appropriate legend handles:
for rv_teles in np.unique(df['rv_telescopes']):
color = colors[rv_teles]
df1 = df[df['rv_telescopes'] == rv_teles] # filter out rows corresponding to df['rv_telescopes']
ax.errorbar(df1['rv_times'], df1['rv_rvs'], df1['rv_sigma'],
color=color, ls='', marker='_', ms=30, label=rv_teles)
ax.legend(loc='upper left', ncol=1, fontsize=14)
plt.show()
I have a 3d graph created using Mayavi and the edges have to be colored by a scalar value.
The following code creates the graph but I am not sure how to color the edges
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
from mayavi import mlab
def main(edge_color=(0.8, 0.8, 0.8), edge_size=0.02):
t = [1, 2, 4, 4, 5, 3, 5]
h = [2, 3, 6, 5, 6, 4, 1]
ed_ls = [(x, y) for x, y in zip(t, h)]
G = nx.OrderedGraph()
G.add_edges_from(ed_ls)
nx.draw(G)
plt.show()
graph_pos = nx.spring_layout(G, dim=3)
# numpy array of x,y,z positions in sorted node order
xyz = np.array([graph_pos[v] for v in sorted(G)])
mlab.figure(1)
mlab.clf()
pts = mlab.points3d(xyz[:, 0], xyz[:, 1], xyz[:, 2])
pts.mlab_source.dataset.lines = np.array(G.edges())
tube = mlab.pipeline.tube(pts, tube_radius=edge_size)
mlab.pipeline.surface(tube, color=edge_color)
mlab.show() # interactive window
main()
Scalar values to be used for coloring the edges
scalar = [0.1, 0.7, 0.3, 0.5, 0.9, 0.8, 0.2]
Any suggestions on how to do this will be really helpful.
I also see another problem in the 3d graph that has been created. One of the edges is not connected to a node.
EDIT: From what I understand, mlab.pipeline.surface(tube, color=edge_color)
is used to color the edge/tube .
Updated code:
def main(edge_color=(0.8, 0.2, 0.8), edge_size=0.02, graph_colormap='winter'):
t = [1, 2, 4, 4, 5, 3, 5]
h = [2, 3, 6, 5, 6, 4, 1]
ed_ls = [(x, y) for x, y in zip(t, h)]
G = nx.OrderedGraph()
G.add_edges_from(ed_ls)
nx.draw(G)
plt.show()
scalars = np.array(G.nodes())+5
pprint(scalars)
e_color = [(0.8, 0.2, 0.8), (0.8, 0.2, 0.8), (0.8, 0.2, 0.8),
(0.8, 0.2, 0.8), (0.8, 0.2, 0.8), (0.8, 0.2, 0.8),
(0.8, 0.2, 0.8)]
graph_pos = nx.spring_layout(G, dim=3)
# numpy array of x,y,z positions in sorted node order
xyz = np.array([graph_pos[v] for v in sorted(G)])
mlab.figure(1)
mlab.clf()
pts = mlab.points3d(xyz[:, 0], xyz[:, 1], xyz[:, 2],
scalars,
colormap=graph_colormap
)
pts.mlab_source.dataset.lines = np.array(G.edges())
tube = mlab.pipeline.tube(pts, tube_radius=edge_size)
#mlab.pipeline.surface(tube, color=e_color) # doesn't work
mlab.pipeline.surface(tube, color=edge_color) # doesn't work
mlab.show() # interactive window
But the problems is I am no able to assign different color for different edge/tube
A possible solution, not at all automated, but sufficient for a proof of concept.
import networkx as nx
import numpy as np
from mayavi import mlab
t = [1, 2, 4, 4, 5, 3, 5]
h = [2, 3, 6, 5, 6, 4, 1]
ed_ls = [(x, y) for x, y in zip(t, h)]
G = nx.OrderedGraph()
G.add_edges_from(ed_ls)
graph_pos = nx.spring_layout(G, dim=3)
xyz = np.array([graph_pos[v] for v in G])
print(xyz.shape)
mlab.points3d(xyz[:, 0], xyz[:, 1], xyz[:, 2],
np.linspace(1, 2, xyz.shape[0]),
colormap='winter', resolution=100, scale_factor=0.3)
smallTri = np.tile(xyz[-3:, :], (2, 1))[:4, :]
remEdges = np.vstack((xyz[-1, :], xyz[:-2, :]))
allEdges = np.vstack((smallTri, remEdges))
for i in range(allEdges.shape[0] - 1):
mlab.plot3d(allEdges[i:i + 2, 0], allEdges[i:i + 2, 1],
allEdges[i:i + 2, 2], color=(0.2, 1 - 0.1 * i, 0.8))
mlab.show()
I am struggling with tweaking a plot, I have been working on.
I am facing to two problems:
The plots should be adjacent and with 0 wspace and hspace. I set both values to zero but still there are some spaces between the plots.
I would like to have one colorbar for all the subplots (they all the same range). Right now, the code adds a colorbar to the last subplot as i understand that it needs the third return value of hist2D.
Here is my code so far:
def plot_panel(pannel_plot):
fig, ax = plt.subplots(3, 2, figsize=(7, 7), gridspec_kw={'hspace': 0.0, 'wspace': 0.0}, sharex=True, sharey=True)
fig.subplots_adjust(wspace=0.0)
ax = ax.flatten()
xmin = 0
ymin = 0
xmax = 0.19
ymax = 0.19
hist2_num = 0
h =[]
for i, j in zip(pannel_plot['x'].values(), pannel_plot['y'].values()):
h = ax[hist2_num].hist2d(i, j, bins=50, norm=LogNorm(vmin=1, vmax=5000), range=[[xmin, xmax], [ymin, ymax]])
ax[hist2_num].set_aspect('equal', 'box')
ax[hist2_num].tick_params(axis='both', top=False, bottom=True, left=True, right=False,
labelsize=10, direction='in')
ax[hist2_num].set_xticks(np.arange(xmin, xmax, 0.07))
ax[hist2_num].set_yticks(np.arange(ymin, ymax, 0.07))
hist2_num += 1
fig.colorbar(h[3], orientation='vertical', fraction=.1)
plt.show()
And the corrsiponding result:
Result
I would be glad for any heads up that i am missing!
You can use ImageGrid, which was designed to make this kind of things easier
data = np.vstack([
np.random.multivariate_normal([10, 10], [[3, 2], [2, 3]], size=100000),
np.random.multivariate_normal([30, 20], [[2, 3], [1, 3]], size=1000)
])
from mpl_toolkits.axes_grid1 import ImageGrid
fig = plt.figure(figsize=(4, 6))
grid = ImageGrid(fig, 111, # similar to subplot(111)
nrows_ncols=(3, 2), # creates 2x2 grid of axes
axes_pad=0.1, # pad between axes in inch.
cbar_mode="single",
cbar_location="right",
cbar_pad=0.1
)
for ax in grid:
h = ax.hist2d(data[:, 0], data[:, 1], bins=100)
fig.colorbar(h[3], cax=grid.cbar_axes[0], orientation='vertical')
or
data = np.vstack([
np.random.multivariate_normal([10, 10], [[3, 2], [2, 3]], size=100000),
np.random.multivariate_normal([30, 20], [[2, 3], [1, 3]], size=1000)
])
from mpl_toolkits.axes_grid1 import ImageGrid
fig = plt.figure(figsize=(4, 6))
grid = ImageGrid(fig, 111, # similar to subplot(111)
nrows_ncols=(3, 2), # creates 2x2 grid of axes
axes_pad=0.1, # pad between axes in inch.
cbar_mode="single",
cbar_location="top",
cbar_pad=0.1
)
for ax in grid:
h = ax.hist2d(data[:, 0], data[:, 1], bins=100)
fig.colorbar(h[3], cax=grid.cbar_axes[0], orientation='horizontal')
grid.cbar_axes[0].xaxis.set_ticks_position('top')
I am trying to create a series of graphs that share x and y labels. I can get the graphs to each have a label (explained well here!), but this is not what I am looking for.
I want one label that covers the y axis of both graphs, and same for the x axis.
I've been looking at the matplotlib and pandas documentation and I was unable to find anything that addresses this issues when the using by argument.
import matplotlib.pyplot as plt
import pandas as pd
df = pd.DataFrame({'A': [1, 2, 1, 2, 3, 4, 3, 4],
'B': [1, 7, 2, 4, 1, 4, 8, 3],
'C': [1, 4, 8, 3, 1, 7, 3, 4],
'D': [1, 2, 6, 5, 8, 3, 1, 7]},
index=[0, 1, 2, 3, 5, 6, 7, 8])
histo = df.hist(by=df['A'], sharey=True, sharex=True)
plt.ylabel('ylabel') # I assume the label is created on the 4th graph and then deleted?
plt.xlabel('xlabel') # Creates a label on the 4th graph.
plt.tight_layout()
plt.show()
The ouput looks like this.
Is there any way that I can create a Y Label that goes across the entire left side of the image (not each graph individually) and the same for the X Label.
As you can see, the x label only appears on the last graph created, and there is no y label.
Help?
This is one way to do it indirectly using the x- and y-labels as texts. I am not aware of a direct way using plt.xlabel or plt.ylabel. When passing an axis object to df.hist, the sharex and sharey arguments have to be passed in plt.subplots(). Here you can manually control/specify the position where you want to put the labels. For example, if you think the x-label is too close to the ticks, you can use 0.5, -0.02, 'X-label' to shift it slightly below.
import matplotlib.pyplot as plt
import pandas as pd
f, ax = plt.subplots(2, 2, figsize=(8, 6), sharex=True, sharey=True)
df = pd.DataFrame({'A': [1, 2, 1, 2, 3, 4, 3, 4],
'B': [1, 7, 2, 4, 1, 4, 8, 3],
'C': [1, 4, 8, 3, 1, 7, 3, 4],
'D': [1, 2, 6, 5, 8, 3, 1, 7]},
index=[0, 1, 2, 3, 5, 6, 7, 8])
histo = df.hist(by=df['A'], ax=ax)
f.text(0, 0.5, 'Y-label', ha='center', va='center', fontsize=20, rotation='vertical')
f.text(0.5, 0, 'X-label', ha='center', va='center', fontsize=20)
plt.tight_layout()
I fixed the issue with the variable number of sub-plots using something like this:
cols = 3
n = len(set(df['A']))
rows = int(n / cols) + (0 if n % cols == 0 else 1)
fig, axes = plt.subplots(rows, cols)
extra = rows * cols - n
if extra:
newaxes = []
count = 0
for row in range(rows):
for col in range(cols):
if count < n:
newaxes.append(axes[row][col])
else:
axes[row][col].axis('off')
count += 1
else:
newaxes = axes
hist = df.hist(by=df['A'], ax=newaxes)
I want to have a scatter plot with ticks as marginals:
x = [ 0, 1, 1.2, 1.3, 4, 5, 6, 7, 8.2, 9, 10]
y = [.2, .4, 2, 3, 4, 5, 5.1, 5.2, 4, 3, 8]
fig, ax1 = plt.subplots()
for spine in ax1.spines.values():
spine.set_visible(False)
ax1.scatter(x, y)
ax1.set_xticks(x)
ax1.set_xticklabels([])
ax1.set_yticks(y)
ax1.set_yticklabels([])
And on top of that, I want to have ticklabels at other positions, not determined by the ticks:
xticklabels = [0, 5, 10]
yticklabels = xticklabels
How could I possibly achieve that?
Matplotlib axes have major and minor ticks. You may use the minor ticks to show the marginal locations of the points. You may turn the major ticks off but show the ticklabels for them.
To set ticks at certain positions you can use a FixedLocator. To change the appearance of the ticks or turn them off, the axes has a tick_params method.
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
x = [ 0, 1, 1.2, 1.3, 4, 5, 6, 7, 8.2, 9, 10]
y = [.2, .4, 2, 3, 4, 5, 5.1, 5.2, 4, 3, 8]
xticklabels = [0, 5, 10]
yticklabels = xticklabels
fig, ax = plt.subplots()
for spine in ax.spines.values():
spine.set_visible(False)
ax.scatter(x, y)
ax.xaxis.set_major_locator(ticker.FixedLocator(xticklabels))
ax.yaxis.set_major_locator(ticker.FixedLocator(yticklabels))
ax.xaxis.set_minor_locator(ticker.FixedLocator(x))
ax.yaxis.set_minor_locator(ticker.FixedLocator(y))
ax.tick_params(axis="both", which="major", bottom="off", left="off")
ax.tick_params(axis="both", which="minor", length=4)
plt.show()
Note that I personally find this plot rather difficult to grasp and if I may, I would propose something more like this:
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
x = [ 0, 1, 1.2, 1.3, 4, 5, 6, 7, 8.2, 9, 10]
y = [.2, .4, 2, 3, 4, 5, 5.1, 5.2, 4, 3, 8]
xticklabels = [0, 5, 10]
yticklabels = xticklabels
fig, ax = plt.subplots()
ax.scatter(x, y)
ax.xaxis.set_minor_locator(ticker.FixedLocator(x))
ax.yaxis.set_minor_locator(ticker.FixedLocator(y))
c = "#aaaaaa"
ax.tick_params(axis="both", which="major", direction="out", color=c)
ax.tick_params(axis="both", which="minor", length=6, direction="in",
color="C0", width=1.5)
plt.setp(ax.spines.values(), color=c)
plt.setp(ax.get_xticklabels(), color=c)
plt.setp(ax.get_yticklabels(), color=c)
plt.show()