I have a bar chart, named 'b', plotted with a set of colors called color1. On a click event, I want the colours on the bar chart to be updated with a new set of colours called color2. I found that I have to enumerate through the BarContainer in order to change the colour. I was unable to just use b.set_color[color2]. Appreciate if anyone can tell me why is that so. Also, is there a pythonic way to do this besides to enumerate? Cheers.
This is the code:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df = pd.DataFrame(np.random.random(size=4),
index=[1992,1993,1994,1995])
color1 = ['black', 'darkgrey', 'blue', 'lightsteelblue']
color2 = ['darkred', 'red', 'salmon', 'lightsalmon']
fig = plt.figure()
ax = plt.gca()
b = plt.bar(df.index.astype(str), df[0], width = 0.5, color=color1)
def onclick(event):
# method 1 works
for index, bar in enumerate(b):
bar.set_color(color2[index])
# method 2 doesn't work
b.set_color(color2)
fig.canvas.draw_idle()
plt.gcf().canvas.mpl_connect('button_press_event', onclick)
plt.show()
Related
I'm trying to get a line plot to be over the bar plot. But no matter what I do to change the zorder, it seems like it keeps the bar on top of the line. Nothing I do to try to change zorder seems to work. Sometimes the bar plot just doesn't show up if zorder is <= 0.
import pandas as pd
import matplotlib.pyplot as plt
def tail_plot(tail):
plt.figure()
#line plot
ax1 = incidence[incidence['actual_inc'] != 0].tail(tail).plot(x='date', y=['R_t', 'upper 95% CI', 'lower 95% CI'], color = ['b', '#808080', '#808080'])
ax1.set_zorder(2)
ax2 = ax1.twinx()
inc = incidence[incidence['actual_inc'] != 0]['actual_inc'].tail(tail).values
dates = incidence[incidence['actual_inc'] != 0]['date'].tail(tail).values
#bar plot
ax2.bar(dates, inc, color ='red', zorder=1)
ax2.set_zorder(1)
Keeps giving me this:
The problem with the approach in the post is that ax1 has a white background which totally occludes the plot of ax2. To solve this, the background color can be set to 'none'.
Note that the plt.figure() in the example code of the post creates an empty plot because the pandas plot creates its own new figure (as no ax is given explicitly).
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({f'curve {i}': 20 + np.random.normal(.1, .5, 30).cumsum() for i in range(1, 6)})
# line plot
ax1 = df.plot()
ax1.set_zorder(2)
ax1.set_facecolor('none')
ax2 = ax1.twinx()
# bar plot
x = np.arange(30)
ax2.bar(x, np.random.randint(7 + x, 2 * x + 10), color='red', zorder=1)
ax2.set_zorder(1)
plt.show()
I want to draw a 3D scatter, in which the data is colored by group. Here is the data sample:
aa=pd.DataFrame({'a':[1,2,3,4,5],
'b':[2,3,4,5,6],
'c':[1,3,4,6,9],
'd':[0,0,1,2,3],
'e':['abc','sdf','ert','hgf','nhkm']})
Here, a, b, c are axis x, y, z. e is the text shown in the scatter. I need d to group the data and show different colors.
Here is my code:
fig = plt.figure()
ax = fig.gca(projection='3d')
zdirs = aa.loc[:,'e'].__array__()
xs = aa.loc[:,'a'].__array__()
ys = aa.loc[:,'b'].__array__()
zs = aa.loc[:,'c'].__array__()
colors = aa.loc[:,'d'].__array__()
colors1=np.where(colors==0,'grey',
np.where(colors==1,'yellow',
np.where(colors==2,'green',
np.where(colors==3,'pink','red'))))
for i in range(len(zdirs)): #plot each point + it's index as text above
ax.scatter(xs[i],ys[i],zs[i],color=colors1[i])
ax.text(xs[i],ys[i],zs[i], '%s' % (str(zdirs[i])), size=10, zorder=1, color='k')
ax.set_xlabel('a')
ax.set_ylabel('b')
ax.set_zlabel('c')
plt.show()
But I do not know how to put a legend on the plot. I hope my legend is like:
The colors and the numbers should match and be ordered.
Could anyone help me with how to customize the color bar?
First of all, I've taken the liberty to reduce your code a bit:
I'd suggest to create a ListedColormap to map integer->color, which allows you to pass the color column via c=aa['d'] (note it's c=, not color=!)
you don't need to use __array__() here, in the code below you can directly use aa['a']
finally, you can add an empty scatter plot for each color in the ListedColormap, and this can then be rendered correctly by ax.legend()
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from matplotlib.colors import ListedColormap
import matplotlib.patches as mpatches
aa=pd.DataFrame({'a':[1,2,3,4,5],
'b':[2,3,4,5,6],
'c':[1,3,4,6,9],
'd':[0,0,1,2,3],
'e':['abc','sdf','ert','hgf','nhkm']})
fig = plt.figure()
ax = fig.gca(projection='3d')
cmap = ListedColormap(['grey', 'yellow', 'green', 'pink','red'])
ax.scatter(aa['a'],aa['b'],aa['c'],c=aa['d'],cmap=cmap)
for x,y,z,label in zip(aa['a'],aa['b'],aa['c'],aa['e']):
ax.text(x,y,z,label,size=10,zorder=1)
# Create a legend through an *empty* scatter plot
[ax.scatter([], [], c=cmap(i), label=str(i)) for i in range(len(aa))]
ax.legend()
ax.set_xlabel('a')
ax.set_ylabel('b')
ax.set_zlabel('c')
plt.show()
I want to create boxplot of data in comparing, my plot looks like
how can I add color like
You can color the box following this example. Beyond that, you will need to map your data in mind to color on the "rainbow" colormap with this module. Here is an example with random test data. I map colors with means in this example.
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
# Random test data
test_data = [np.random.normal(mean, 1, 100) for mean in range(50)]
fig, axes = plt.subplots(figsize=(12, 16))
# Horizontal box plot
bplot = axes.boxplot(test_data,
vert=False, # vertical box aligmnent
patch_artist=True) # fill with color
# Fill with colors
cmap = cm.ScalarMappable(cmap='rainbow')
test_mean = [np.mean(x) for x in test_data]
for patch, color in zip(bplot['boxes'], cmap.to_rgba(test_mean)):
patch.set_facecolor(color)
plt.show()
You can use the cmap property to actually be a function, accepting values between 0 and 1, and call it "normalising" your data. Using matplotlib example on boxplots:
import matplotlib.pyplot as plt
import numpy as np
# Random test data
np.random.seed(123)
all_data = [np.random.normal(0, 5, 100) for std in range(1, 21)]
fig, ax = plt.subplots(nrows=1, figsize=(9, 4))
# rectangular box plot
bplot = ax.boxplot(all_data, 0, '', 0, patch_artist=True)
cm = plt.cm.get_cmap('rainbow')
colors = [cm(val/len(all_data)) for val in range(len(all_data))]
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
plt.show()
Some time ago I asked how to set line style through a function taking the plot axes instance as parameter
(matplotlib set all plots linewidth in a figure at once).
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(range(10))
ax.plot(2 * range(10))
solution suggested:
def bulk_lw_edjuster(ax, lw = 5)
for ln in ax.lines:
ln.set_linewidth(lw)
As shown above one suggested to use ax.lines in the function, but now I would like to know how to set other properties such as marker properties, colors ...
You can find information about the setting the properties of Lines2D here. Marker size and marker color can be set similarly to the line width:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(range(10))
ax.plot(2 * range(10))
#solution suggested:
def bulk_lw_edjuster(ax, lw = 5, markersize = 5, markerfacecolor = 'r'):
for ln in ax.lines:
ln.set_linewidth(lw)
ln.set_markersize(markersize) # set marker size
ln.set_markerfacecolor(markerfacecolor) # set marker color
# Change the plot properties.
bulk_lw_edjuster(ax, lw =10, markersize = 10, markerfacecolor = 'm')
plt.show()
I'm wondering why my matlibplot is currently graphing inside a button as shown below:
Code is shown below
from gui export Index
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button
fig, ax = plt.subplots()
plt.subplots_adjust(buttom-0.2)
pos_trim = plt.axes([0.20, 0.05, .1, 0.075])
b_trim = Button(pos_trim, 'Trim', hoverclor='0.25')
callback = Index(c)
b_trim.on_clicked(callback.autoTrim) # from gui.index
freqs = np.arange(2,20,3)
t = np.arange(0.0, 1.0, 0.05)
s = np.sin(2*np.pi*freqs[0]*t)
l, = plt.plot(t,s,lw=2)
plt.show()
Index class:
class Index:
def __init__(self, chart):
self.__chart = chart
def autoTrim(self, event):
print "Autotrim"
#self.__chart.autoTrim()
plt.draw()
Try changing your line where you plot the data to:
l, = ax.plot(t,s,lw=2)
That is, plot to the axes you created for the plot (ax). Otherwise, you're plotting to the last axes you created, which in this case, is the button.