Reputation: 1165
How to:
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()
Upvotes: 0
Views: 3263
Reputation: 80449
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()
Upvotes: 1