How to customize bar graph (matplotlib)? - python

My code:
import matplotlib.pyplot as plt
import numpy as np
f = plt.figure()
production_level = [54, 83, 21, 3] #list_of_prod
periods = [x+1 for x in range(len(production_level))] #list_of_order
plt.bar(periods, production_level, color='orange')
plt.title('Dynamic lot-size problem chart')
plt.ylabel('Units')
plt.xlabel('Periods')
plt.grid(True)
plt.show()
f.savefig("bar.png", bbox_inches='tight')
Output:
How can I have just whole numbers on x axis (1,2,3,4) without 0,5; 1,5; 2,5 etc.? How can add bars' value on them or above them?

Add text by using plt.text() and tweaking the coordinates (hint, hardcoding these values might not be the best idea).
Change ticks by using plt.xticks() (see also this question).

Related

How do I cluster values of y axis against x axis in scatterplot?

Lets say I've 2 arrays
x = [1,2,3,4,5,6,7]
y = [1,2,2,2,3,4,5]
its scatter plot looks like this
what I want to do is that I want my x axis to look like this in the plot
0,4,8
as a result of which values of y in each piece of x should come closer .
The similar behavior I've seen is bar plots where this is called clustering , how do I do the same in case of scatter plot , or is there any other plot I should be using ?
I hope my question is clear/understandable .
All the help is appreciated
With you plot, try this, before you display the plot.
plt.xticks([0,4,8]))
or
import numpy as np
plt.xticks(np.arange(0, 8+1, step=4))
Then to change the scale you can try something like this,
plt.xticks([0,4,8]))
plt.rcParams["figure.figsize"] = (10,5)
I got this with my example,
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 30)
y = np.sin(x)
plt.xticks([0,4,8])
plt.rcParams["figure.figsize"] = (7,3)
plt.plot(x, y, 'o', color='black')
output
I think what you are looking for is close to swarmplots and stripplots in Seaborn. However, Seaborn's swarmplot and stripplot are purely categorical on one of the axes, which means that they wouldn't preserve the relative x-axis order of your elements inside each category.
One way to do what you want would be to increase the space in your x-axis between categories ([0,4,8]) and modify your xticks accordingly.
Below is an example of this where I assign the data to 3 different categories: [-2,2[, [2,6[, [6,10[. And each bar is dil_k away from its directly neighboring bars.
import matplotlib.pyplot as plt
import numpy as np
#Generating data
x= np.random.choice(8,size=(100))
y= np.random.choice(8,size=(100))
dil_k=20
#Creating the spacing between categories
x[np.logical_and(x<6, x>=2)]+=dil_k
x[np.logical_and(x<10, x>=6)]+=2*dil_k
#Plotting
ax=plt.scatter(x,y)
#Modifying axes accordingly
plt.xticks([0,2,22,24,26,46,48,50],[0,2,2,4,6,6,8,10])
plt.show()
And the output gives:
Alternatively, if you don't care about keeping the order of your elements along the x-axis inside each category, then you can use swarmplot directly.
The code can be seen below:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
#Generating data
x= np.random.choice(8,size=(100))
y= np.random.choice(8,size=(100))
#Creating the spacing between categories
x[np.logical_and(x<2,x>=-2)]=0
x[np.logical_and(x<6, x>=2)]=4
x[np.logical_and(x<10, x>=6)]=8
#Plotting
sns.swarmplot(x=x,y=y)
plt.show()
And the output gives:

How to draw a bar range plot with matplotlib?

I am trying to create a bar range plot with a temporal x-axis with matplotlib. As an example see the following :
As far as I see, Matplotlib doesn't directly support this kind of plot.
What is the best way to achieve this?
Maybe its possible to adjust a boxplot or a fill_between plot?
just pass the bottom parameter to bar, e.g:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y_bot = np.linspace(30, 50, 10)
y_dif = np.linspace(10, 5, 10)
plt.bar(x, y_dif, bottom=y_bot)

Matplotlib displaying histogram with a specific value on x and y axis

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
value = [8904,8953,8977,9147,9243,9320]
bin = np.arange(0,70,10)
ax.hist(value, bins=bin)
plt.grid(True)
plt.show()
I am trying to plot a histogram with the value array on the x-axis and the y-axis will be the bin. But when I run the code I get an empty chart. Could anyone please help me out. Thank you
First thing I see is that in your values array, your data points aren't separated by commas.
Second thing, your values are outside the ranges of your bins. All your values are well into the thousands, and your bins' range is between 0 and 70.
Here is my edited version of your code (I included my import statements to make things clear). I changed the values to being within your bin ranges:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
value = [7, 8, 15, 45, 50, 80]
bin = np.arange(0,70,10)
ax.hist(value, bins=bin)
plt.grid(True)
plt.show()
The result I get is this image, which illustrates what's going on. The data point 80 is outside the bin range, and therefore isn't shown at all, just like the data points you originally had. Other than that, all data points are shown in the histogram.
Hope this helps!
Edit: you said in a comment to this answer that you want it to be horizontal, not vertical. You add orientation="horizontal" to your ax.hist statement as an argument. New code looks like this:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
value = [7, 8, 15, 45, 50, 80]
bin = np.arange(0,70,10)
ax.hist(value, bins=bin, orientation="horizontal")
plt.grid(True)
plt.show()
Your plot should now look like this.

How to force matplotlib to expand range for at least two ticks

I can't get any tick marks to appear when I have a narrow range of data and log formatting. I found a similar problem that talked about forcing a minimum number of ticks and tried that solution, but it did not seem to help.
What I want to do is have the Y range be automatically expanded until at least two ticks can be included, including one major tick (so it gets a label). I can't do anything to manual or custom because a lot of different data goes through this routine and it is only rarely that the range is so tight that no labels appear.
Here is an example that preserves as much of my local environment as possible:
import matplotlib
import numpy as np
import pylab as plt
fig=plt.figure(figsize=(15, 20))
locmin = matplotlib.ticker.LogLocator(base=10.0,subs=(.1,.2,.3,.4,.5,.6,.7,.8,.9),numticks=15)
ax6 = plt.subplot(616)
plt.plot(np.random.random(1000)*4+14, 'b')
plt.plot(np.random.random(1000)*4+14, 'r')
plt.minorticks_on()
plt.ylabel('Y')
plt.yscale('log')
ax6.yaxis.set_minor_locator(locmin)
ax6.yaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())
plt.show()
The result is this plot here, which has no Y labels...
You can get the array of major_ticks and minor_ticklocs. Then find the bounds for the given scaled y limits. Then you can explicitly set the ylim of the plot. Since the values in the example scales between 10 and 20, the 10 from major_ticks and 20 from minor_ticks are shown. Consider below code:
import matplotlib
import numpy as np
import pylab as plt
fig=plt.figure(figsize=(15, 20))
locmin = matplotlib.ticker.LogLocator(base=10.0,subs=(.1,.2,.3,.4,.5,.6,.7,.8,.9),numticks=15)
ax6 = plt.subplot(616)
plt.plot(np.random.random(1000)*4+14, 'b')
plt.plot(np.random.random(1000)*4+14, 'r')
plt.minorticks_on()
plt.ylabel('Y')
plt.yscale('log')
ax6.yaxis.set_minor_locator(locmin)
ax6.yaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())
plt.tick_params(axis='y', which='minor')
ax6.yaxis.set_minor_formatter(matplotlib.ticker.FormatStrFormatter("%.1f"))
tickArr = np.concatenate((plt.yticks()[0], ax6.yaxis.get_minorticklocs()))
ylim_min = tickArr[tickArr < plt.ylim()[0]].max()
ylim_max = tickArr[tickArr > plt.ylim()[1]].min()
plt.ylim([ylim_min, ylim_max])
plt.show()

x axis with duplicate values (loading profile) plot in matplotlib

i have load profile data where x axis is load profile such that for multiple same values of x (constant load) i have different values for y.
till now in excel i used to line plot y and right click graph->selec data->change hoizontal axis data by providing it range o x axis data and that used to give me the graph
the problem i have is when i try to give
plot(x,y), matplotlib plots y for unique vals of x ie it neglects out all the remaining value of for same value of x.
and when i plot with plot(y) i get sequence numbers on x axis
i tried xticks([0,5,10,15]) for checking out but couldn't get the required result.
my question is
is it possible to plot a graph in a similar fashion as of excel
the other alternative i could think of was plotting plot(y and plot (x) with same horizontal axis it atleast gives a pictorial idea but is there any means to do it the excel way??
From your description, it sounds to me like you want to use the "scatter" plotting command instead of the "plot" plotting command. This will allow the use of redundant x-values. Sample code:
import numpy as np
import matplotlib.pyplot as plt
# Generate some data that has non-unique x-values
x1 = np.linspace(1,50)
y1 = x1**2
y2 = 2*x1
x3 = np.append(x1,x1)
y3 = np.append(y1,y2)
# Now plot it using the scatter command
# Note that some of the abbreviations that work with plot,
# such as 'ro' for red circles don't work with scatter
plt.scatter(x3,y3,color='red',marker='o')
As I mentioned in the comments, some of the handy "plot" shortcuts don't work with "scatter" so you may want to check the documentation: http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.scatter
If you want to plot y-values for a given x-values, you need to get the index which has same x-values. If you are working with numpy then you can try
import pylab as plt
import numpy as np
x=np.array([1]*5+[2]*5+[3]*5)
y=np.array([1,2,3,4,5]*3)
idx=(x==1) # Get the index where x-values are 1
plt.plot(y[idx],'o-')
plt.show()
If you are working with lists you can get the index by
# Get the index where x-values are 1
idx=[i for i, j in enumerate(x) if j == 1]
just answering own question,found this around when i had posted this question years back :)
def plotter(y1,y2,y1name,y2name):
averageY1=float(sum(y1)/len(y1))
averageY2=float(sum(y2)/len(y2))
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(y1,'b-',linewidth=2.0)
ax1.set_xlabel("SNo")
# Make the y2-axis label and tick labels match the line color.
ax1.set_ylabel(y1name, color='b')
for tl in ax1.get_yticklabels():
tl.set_color('b')
ax1.axis([0,len(y2),0,max(y1)+50])
ax2 = ax1.twinx()
ax2.plot(y2, 'r-')
ax2.axis([0,len(y2),0,max(y2)+50])
ax2.set_ylabel(y2name, color='r')
for tl in ax2.get_yticklabels():
tl.set_color('r')
plt.title(y1name + " vs " + y2name)
#plt.fill_between(y2,1,y1)
plt.grid(True,linestyle='-',color='0.75')
plt.savefig(y1name+"VS"+y2name+".png",dpi=200)
You can use
import numpy as np
import matplotlib.pyplot as plt
x = np.array([1, 1, 1, 2, 2, 2])
y = np.array([1, 2, 1, 5, 6, 7])
fig, ax = plt.subplots()
ax.plot(np.arange(len(x)), y)
ax.set_xticklabels(x)
plt.show()

Categories

Resources