I'm rather new with regard to Matplotlib which want to use for making (multiple) histograms of data counts with float intervals on the x-axis in a tkinter toplevel window. See below a highly simplified part of my code. Because I use float intervals, I need to apply a ax2.hist(...) call in stead of the ax1.bar(...) call. See my code below. However, the result from ax2.hist(...) is not what I want. I would like tot have the counts at the y-axis as is the case in ax1. With other words, how do I get a histogram with y-axis from ax1 and the x-axis from ax2?
I hope somebody can suggest how to deal with this. I couldn't find it on the matplotlib site, sofar.
import tkinter as tk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np
import random
root = tk.Tk()
panel = tk.Toplevel()
panel.title('Title')
lijst = []
for i in range(100):
a = random.randrange(100)
a=a/10
lijst.append(a)
nplijst = np.array(lijst)
counts, bins = np.histogram(nplijst)
names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' ,'i', 'j']
print(counts)
print(bins)[![resulting ax1 bar graph and ax2 histogram][1]][1]
fig1 = plt.Figure()
ax1 = fig1.add_subplot(121)
ax2 = fig1.add_subplot(122)
ax1.bar(names, counts, width = 1, edgecolor="k")
ax2.hist(counts, bins = bins, edgecolor="k")
ax1.set_title('ax1')
ax2.set_title('ax2')
chart_type1 = FigureCanvasTkAgg(fig1, panel)
chart_type1.get_tk_widget().pack()
You can use the sharey keyword in plt.subplots like so:
fig1, axs = plt.subplots(1, 2, sharey=True) # create a 1x2 grid of plots
axs[0].bar(names, counts, width = 1, edgecolor="k")
axs[1].hist(counts, bins = bins, edgecolor="k")
axs[0].set_title('ax1')
axs[1].set_title('ax2')
If you want the tick labels back on the second plot, add
for ax in axs:
ax.yaxis.set_tick_params(labelleft=True)
Related
Please let me know how I could increase the size of the chart and space out the bars for a neater presentation. The code I have used is duly uploaded.
You can do one of the following:
Increase the size of your image:
fig, ax = plt.subplots(figsize=[10, 4]) # This sets the size of the output to be 10x4.
Set xlabels
locations = np.arange(len(names))
labels = ['Ben', 'John', 'Jack'] #sample, note that length of labels SHOULD match len of locations.
plt.xticks(locations, labels, rotation=45) #rotation is optional
Rotate the xticklabels
plt.xticks(rotations=90) # Rotating the ticks by 90 degree
you can use rwidth in plt.hist .
see this :
import numpy as np
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
x = [21,22,23,4,5,6,77,8,9,10,31,32,33,34,35,36,37,18,49,50,100]
num_bins = 5
n, bins, patches = plt.hist(x, num_bins, facecolor='blue', alpha=0.5, rwidth=0.5)
plt.show()
output:
and if you want to use plt.bar, you can use this sample :
import matplotlib.pyplot as plt
height =[21,22,23,4,5]
bars = ('A', 'B', 'C', 'D', 'E')
x_pos = [0, 1, 2, 3, 4]
plt.bar(x_pos, height,width=0.5)
plt.xticks(x_pos, bars)
plt.show()
Output :
I am trying to make a stacked histogram using matplotlib by looping through the categories in the dataframe and assigning the bar color based on a dictionary.
I get this error on the ax1.hist() call. How should I fix it?
AttributeError: 'numpy.ndarray' object has no attribute 'hist'
Reproducible Example
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
%matplotlib inline
plt.style.use('seaborn-whitegrid')
y = [1,5,9,2,4,2,5,6,1]
cat = ['A','B','B','B','A','B','B','B','B']
df = pd.DataFrame(list(zip(y,cat)), columns =['y', 'cat'])
fig, axes = plt.subplots(3,3, figsize=(5,5), constrained_layout=True)
fig.suptitle('Histograms')
ax1 = axes[0]
mycolorsdict = {'A':'magenta', 'B':'blue'}
for key, batch in df.groupby(['cat']):
ax1.hist(batch.y, label=key, color=mycolorsdict[key],
density=False, cumulative=False, edgecolor='black',
orientation='horizontal', stacked=True)
Updated effort, still not working
This is close, but it is not stacking (should see stacks at y=5); I think maybe because of the loop?
mycolorsdict = {'A':'magenta', 'B':'blue'}
for ii, ax in enumerate(axes.flat):
for key, batch in df.groupby(['cat']):
ax.hist(batch.y,
label=key, color=mycolorsdict[key],density=False, edgecolor='black',
cumulative=False, orientation='horizontal', stacked=True)
To draw on a specific subplot, two indices are needed (row, column), so axes[0,0] for the first subplot. The error message comes from using ax1 = axes[0] instead of ax1 = axes[0,0].
Now, to create a stacked histogram via ax.hist(), all the y-data need to be provided at the same time. The code below shows how this can be done starting from the result of groupby. Also note, that when your values are discrete, it is important to explicitly set the bin boundaries making sure that the values fall precisely between these boundaries. Setting the boundaries at the halves is one way.
Things can be simplified a lot using seaborn's histplot(). Here is a breakdown of the parameters used:
data=df the dataframe
y='y' gives the dataframe column for histogram. Use x= (instead of y=) for a vertical histogram.
hue='cat' gives the dataframe column to create mulitple groups
palette=mycolorsdict; the palette defines the coloring; there are many ways to assign a palette, one of which is a dictionary on the hue values
discrete=True: when working with discrete data, seaborn sets the appropriate bin boundaries
multiple='stack' creates a stacked histogram, depending on the hue categories
alpha=1: default seaborn sets an alpha of 0.75; optionally this can be changed
ax=axes[0, 1]: draw on the 2nd subplot of the 1st row
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use('seaborn-whitegrid')
y = [1, 5, 9, 2, 4, 2, 5, 6, 1]
cat = ['A', 'B', 'B', 'B', 'A', 'B', 'B', 'B', 'B']
df = pd.DataFrame({'y':y, 'cat':cat})
fig, axes = plt.subplots(3, 3, figsize=(20, 10), constrained_layout=True)
fig.suptitle('Histograms')
mycolorsdict = {'A': 'magenta', 'B': 'blue'}
groups = df.groupby(['cat'])
axes[0, 0].hist([batch.y for _, batch in groups],
label=[key for key, _ in groups], color=[mycolorsdict[key] for key, _ in groups], density=False,
edgecolor='black',
cumulative=False, orientation='horizontal', stacked=True, bins=np.arange(0.5, 10))
axes[0, 0].legend()
sns.histplot(data=df, y='y', hue='cat', palette=mycolorsdict, discrete=True, multiple='stack', alpha=1, ax=axes[0, 1])
plt.show()
I'd like to manipulate the ticks of every plot in my subplots. When plotting a single plot I get the desired result by using:
import matplotlib.pyplot as plt
import numpy as np
# ...
# some data acquisition
# ...
ax.imshow(data[i], cmap=plt.cm.jet, origin='bottom')
ax.contour(x, y, dataFitted[i].reshape(2*crop, 2*crop), 3, colors='white')
# adjust scale from pixel to micrometers on heat maps
pixelSize = 5.5 # micrometer/pxl
scaleEnd = crop * pixelSize
wishedTicks = np.array([-150, -100, -50, 0, 50, 100, 150])
originalTicks = (wishedTicks + scaleEnd) / pixelSize
plt.xticks(originalTicks, wishedTicks)
plt.yticks(originalTicks, wishedTicks)
So far, so good, but if I use
fig, ax = plt.subplots(nrows=5, ncols=4)
to create subplots, the function plt.xticks() is not available any more to my understanding.
Is there a way to receive the same result by
either globally (for all figures) manipulating the axis in the same way I did for a single plot
or
manipulating each subplot individually in the desired way as above?
Always work with an explicit axes, for plotting, as for setting the ticks/labels.
fig, axs = plt.subplots(5,4, figsize=(9,7))
for ax in axs.flat:
ax.plot(...)
ax.set_xticks(ticks)
ax.set_xticklabels(labels)
Using plt.subplot (documentation) instead of plt.subplots might suit your needs.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
x_labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k']
y = np.arange(0, 20, 2)
for i in range(1, 5):
ax = plt.subplot(2, 2, i)
plt.plot(x, y)
plt.xticks(x, x_labels)
plt.show()
Produces this:
Also recommend reading this article on subplots to see some more neat stuff you can do with them.
With reference to this stackoverflow thread Specifying values on x-axis, following figure is generated .
I want to add interval name in the above figure like this way.
How to add such interval group name in every interval group in y-axis?
This is one way of doing it by creating a twin axis and modifying its tick labels and positions. Trick here is to find the middle positions loc_new between the existing ticks for placing your strings Interval i. You just need to play around a bit to get exactly the figure you want.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
x = np.array([0,1,2,3])
y = np.array([0.650, 0.660, 0.675, 0.685])
my_xticks = ['a', 'b', 'c', 'd']
plt.xticks(x, my_xticks)
plt.yticks(np.arange(y.min(), y.max(), 0.005))
plt.plot(x, y)
plt.grid(axis='y', linestyle='-')
ax2 = ax.twinx()
ax2.set_ylim(ax.get_ylim())
loc = ax2.get_yticks()
loc_new = ((loc[1:]+loc[:-1])/2)[1:-1]
ax2.set_yticks(loc_new)
labels = ['Interval %s' %(i+1) for i in range(len(loc_new))]
ax2.set_yticklabels(labels)
ax2.tick_params(right=False) # This hides the ticks on the right hand y-axis
plt.show()
I have the following code:
import matplotlib.pyplot as plt
import numpy as np
xticks = ['A','B','C']
Scores = np.array([[5,7],[4,6],[8,3]])
colors = ['red','blue']
fig, ax = plt.subplots()
ax.hist(Scores,bins=3,density=True,histtype='bar',color=colors)
plt.show()
Which gives the following output:
I have two questions:
How can I make the height of bars represent the values in Scores e.g. the left most red column should be of height 5 and left most blue column should be of height 7, and so on.
How can I assign values across x-axis from xticks list e.g. the left two columns should have 'A' written under them, the next two 'B' and so on.
You confound a histogram with a bar plot. Here you want a bar plot. If you want to use pandas, this is going to be very easy:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
xticks = ['A','B','C']
Scores = np.array([[5,7],[4,6],[8,3]])
colors = ['red','blue']
names = ["Cat", "Dog"]
fig, ax = plt.subplots()
pd.DataFrame(Scores, index=xticks, columns=names).plot.bar(color=colors, ax=ax)
plt.show()
If using matplotlib alone, it's slighlty more complicated, because each column needs to be plotted independently,
import matplotlib.pyplot as plt
import numpy as np
xticks = ['A','B','C']
Scores = np.array([[5,7],[4,6],[8,3]])
colors = ['red','blue']
names = ["Cat", "Dog"]
fig, ax = plt.subplots()
x = np.arange(len(Scores))
ax.bar(x-0.2, Scores[:,0], color=colors[0], width=0.4, label=names[0])
ax.bar(x+0.2, Scores[:,1], color=colors[1], width=0.4, label=names[1])
ax.set(xticks=x, xticklabels=xticks)
ax.legend()
plt.show()
You already did a lot of the work for the histogram. Now you just need some bar plots.
import matplotlib.pyplot as plt
import numpy as np
xticks = ['A','B','C']
Scores = np.array([[5,7],[4,6],[8,3]])
colors = ['red','blue']
fig, ax = plt.subplots()
# Width of bars
w=.2
# Plot both separately
ax.bar([1,2,3],Scores[:,0],width=w,color=colors[0])
ax.bar(np.add([1,2,3],w),Scores[:,1],width=w,color=colors[1])
# Assumes you want ticks in the middle
ax.set_xticks(ticks=np.add([1,2,3],w/2))
ax.set_xticklabels(xticks)
plt.show()
plt.xticks(range(0, 6), ('A', 'A', 'B', 'B', 'C', 'C')) would work to answer question part 2 I believe. I'm not sure about the heights, as I haven't made histograms.