plot with symbolic tick labels - sympy

I would like to draw plots which preserve symbolic meaning for certain numeric values.
In a isympy shell I can write:
T = Symbol('T')
plot(exp(x/T).subs(T, 5))
Which gives the following plot
I don't care much about the numeric tick labels in the plot. What I am interested in is where the x axis equals T=5 the y axis should equal e=2.718. In other words I want to discard all tick labels on both axis and only have one tick label on the x axis for T and one label on the y axis for e.
Is something like this possible?

According to Sympy and plotting, you can customize a sympy plot via accessing ._backend.ax. In my current version I needed ._backend.ax[0].
Here is how your plot could be adapted:
from sympy import Symbol, plot, exp
t_val = 5
T = Symbol('T')
plot1 = plot(exp(x / T).subs(T, t_val))
fig = plot1._backend.fig
ax = plot1._backend.ax[0]
ax.set_xticks([t_val])
ax.set_xticklabels([str(T)])
e_val = exp(1).evalf()
ax.set_yticks([e_val])
ax.set_yticklabels(["e"]) # or ax.set_yticklabels([f"{e_val:.3f}"]) ?
ax.plot([t_val, t_val, 0], [0, e_val, e_val], color='dodgerblue', ls='--')
fig.canvas.draw()

Related

Iterate Pandas Series to create a new chart legend

After grouping etc. I get a Series like in the example below. I would like to show the average numbers for each bar. The code below shows only one entry (of course, as I have only one "legend"). Could anyone one suggest a smart way of showing these numbers?
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib
matplotlib.style.use('ggplot')
import pandas
# create Series
dict_ = {"Business" : 104.04,"Economy":67.04, "Markets":58.56, "Companies":38.48}
s = pandas.Series(data=dict_)
# plot it
ax = s.plot(kind='bar', color='#43C6DB', stacked=True, figsize=(20, 10), legend=False)
plt.tick_params(axis='both', which='major', labelsize=14)
plt.xticks(rotation=30) #rotate labels
# Shrink current axis by 20%
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
#create new legend
legend = ['%s (%.1f a day)' %(i, row/7) for i, row in s.iteritems()]
# Put the legend to the right of the current axis
L = ax.legend(legend, loc='center left', bbox_to_anchor=(1, 0.5), fontsize=18)
plt.show()
The legend only has a single entry. This is a handle of a blue bar. Therefore even if you set the labels to a longer list, only the first element of that list is used as label for the existing handle.
The idea can be to duplicate the legend handle to have the same size as the labels
legend = ['%s (%.1f a day)' %(i, row/7) for i, row in s.iteritems()]
h,l = ax.get_legend_handles_labels()
L = ax.legend(handles = h*len(legend), labels=legend, loc='center left',
bbox_to_anchor=(1, 0.5), fontsize=18)

Plotting graph using pylab

I am trying to plot a graph. It has a list contains action name (text) and another list which contains action's frequency (int).
I want to plot a connected graph. This is the code I've written:
xTicks=np.array(action)
x=np.array(count)
y=np.array(freq)
pl.xticks(x,xTicks)
pl.xticks(rotation=90)
pl.plot(x,y)
pl.show()
In the list xTicks, I have actions and in the list y, I have their frequencies .
With the above code, I am getting this graph:
Why am I getting extra spaces on x axis? It should be symmetric and the size of lists are 130-135 so how can I scroll it?
You need to set x to an evenly spaced list in order to get your x ticks to be evenly spaced. The following is an example with some made up data:
import matplotlib.pyplot as plt
import numpy as np
action = ["test1", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9"]
freq = [5,3,7,4,8,3,5,1,12]
y=np.array(freq)
xTicks=np.array(action)
x = np.arange(0,len(action),1) # evenly spaced list with the same length as "freq"
plt.plot(x,y)
plt.xticks(x, xTicks, rotation=90)
plt.show()
This produces the following plot:
Update:
A simple example of a slider is shown below. You will have to make changes to this in order to get it exactly how you want but it will be a start:
from matplotlib.widgets import Slider
freq = [5,3,7,4,8,3,5,1,12,5,3,7,4,8,3,5,1,12,5,3,7,4,8,3,5,1,12,4,9,1]
y=np.array(freq)
x = np.arange(0,len(freq),1) # evenly spaced list with the same length as "action"
fig, ax = plt.subplots()
plt.subplots_adjust(left=0.25, bottom=0.25)
l, = plt.plot(x, y, lw=2, color='red')
axfreq = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor="lightblue")
sfreq = Slider(axfreq, 'Slider', 0.1, 10, valinit=3)
def update(val):
l.set_xdata(val* x)
fig.canvas.draw_idle()
sfreq.on_changed(update)
plt.show()
This produces the following graph which has a slider:

Make colorbar compatible with gradient bar plot values

I want to make the values I plot to be compatible with the colorbar values. How can I do this? See more details below.
y1, y2, y3 values are : [-1.7 -1.62 -1.53 -1.43 -1.32 -1.2 -1.09 -0.97 -0.85],
[-1.43 -1.28 -1.09 -0.88 -0.66 -0.44 -0.21 0.03 0.27], [-3.65 -3.58 -3.48 -3.38 -3.27 -3.16 -3.04 -2.92 -2.8 ]
import matplotlib.pyplot as plt
import numpy as np
#plot
fig = plt.figure(figsize=(9.6,6), dpi=300, linewidth=3.0)
ax = fig.add_subplot(311)
y1 = y.transpose() #y should be the first data I gave out in the beginning
gradient = [ y1,y1 ]
plt.imshow(gradient, aspect='auto', cmap=plt.get_cmap('hot'))
ax.set_xticklabels(data[list[1]])
ax2 = fig.add_subplot(312)
y2 = y.transpose() #y should be the second data I gave out in the beginning
gradient = [ y2,y2 ]
plt.imshow(gradient, aspect='auto', cmap=plt.get_cmap('hot'))
ax2.set_xticklabels(data[list[5]])
ax3 = fig.add_subplot(313)
y3 = y.transpose() #y should be the third data I gave out in the beginning
gradient = [ y3,y3 ]
plt.imshow(gradient, aspect='auto', cmap=plt.get_cmap('hot'))
ax3.set_xticklabels(data[list[9]])
sm = plt.cm.ScalarMappable(cmap=plt.get_cmap('hot'),norm=plt.Normalize(-6.39,9.29))
sm._A = []
plt.colorbar(sm,ax=[ax,ax2,ax3])
#fig.set_tight_layout(True) #how can I use this? If I use this it generates a warning and the plot overlaps
plt.savefig('CuxOxi.png',dpi=300,format='png', orientation='landscape')
As you can see from the graph, the colorbar ranges from -6.39 to 9.29. Each subplot ranges only a fraction of the complete colorbar range. How can I make for example -1.62 to -1.2 to have the color range as defined in the colorbar (which is mostly red)
In each plot, you can add the vmin and vmax options to the plt.imshow function in order to set the color scale min and max for that plot. You can define these to be the same for each plot so that they all have the same scale.
vmin = -6
vmax = 9
plt.imshow(gradient, aspect='auto', cmap=plt.get_cmap('hot'),vmin=vmin,vmax=vmax)

Matplotlib - get value of autoscale

Is there a possibility to read the scale of the axis which are set by autoscale?
For example:
import matplotlib.pyplot as plt
x=[1,2,3,4,5]
y=[1,2,3,4,5]
plt.plot(x,y)
plt.grid(True)
fig = plt.gcf()
plt.show()
I want to get the scale of the x and the y axis. In this case it would be 0.5.
After the plotting, you can do
# calculate x scale
ax = fig.gca()
foo = ax.get_xmajorticklabels()
bar = [float(foo[i].get_text()) for i in range(len(foo))]
scale_x = bar[1]-bar[0]
# calculate y scale
foo = ax.get_ymajorticklabels()
bar = [float(foo[i].get_text()) for i in range(len(foo))]
scale_y = bar[1]-bar[0]
print scale_x, scale_y
This only works after plt.show() is called (unclear to me, maybe a separate question for SO), but it works. Just append those lines to your script.

how to set limts on x and y axis Openpyxl charts

I am working on script to plot data in excel sheets using openpyxl module i am able to plot the data , could not find a way to set limit on axis while plotting
here is my code
ws2 = ws2 = wb.create_sheet()
xvalues = Reference(ws2, (2, 1), (10, 1))
yvalues = Reference(ws2, (2,2), (10,2))
xseries = Series(xvalues, title="First series of values")
yseries = Series(yvalues, title="Second series of values",xvalues = xseries)
chart = ScatterChart()
chart.append(yseries)
ws2.add_chart(chart)
ws2.save("C5122_534_09112014.xlsx")
Initially the chart module was setup to calculate axes maxima and minima for you. You can override this by setting auto_axis=False when you create the chart. You can then set the maximum and minimum for an axis:
chart = ScatterChart(auto_axis=False)
chart.x_axis.min = 5
chart.x_axis.max = 10
chart.x_axis.unit = 1
In 2.2 the default will not be to try and be so clever.