Related
I have a function, which produces polar plot with matplotlib.
from math import pi
import matplotlib as mpl
import matplotlib.pyplot as plt
first_arg = {
'Introversion': 17, 'Intuition': 34, 'Feeling': 29, 'Perceiving': 18,
'Extraversion': 27, 'Sensing': 25, 'Thinking': 23, 'Judging': 16
}
second_arg = {
'Introversion': 16, 'Intuition': 25, 'Feeling': 31, 'Perceiving': 15,
'Extraversion': 22, 'Sensing': 29, 'Thinking': 23, 'Judging': 23
}
def plot_scales_chart(*args):
scales = [
'Introversion', 'Intuition', 'Feeling', 'Perceiving',
'Extraversion', 'Sensing', 'Thinking', 'Judging'
]
angles = [n / float(len(scales)) * 2 * pi for n in range(len(scales))]
angles += angles[:1]
mpl.use('agg')
ax = plt.subplot(polar=True)
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
plt.xticks(angles[:-1], scales)
ax.set_rlabel_position(0)
plt.yticks([15, 25], ["15", "25"], color="grey", size=8)
plt.ylim(0, 35)
colors = ['#5159be', '#86e5c7']
for i, arg in enumerate(args):
values = []
for scale in scales:
values.append(arg[scale])
values += values[:1]
ax.plot(angles, values, alpha=0.7, color=colors[i], linewidth=0, linestyle='solid')
ax.fill(angles, values, colors[i], alpha=0.7)
plt.savefig('chart.png')
I want to move xaxis labels so as not to cross the circle.
How to set label position of particularly one scale or is that possible to move all labels further from the center? What is the best practice there?
You can use ax.tick_params to add padding to move the labels 'away' from the center. Adding the line ax.tick_params(axis='x', which='major', pad=15) after you set the xticks in plt.xticks() does the trick.
from math import pi
import matplotlib as mpl
import matplotlib.pyplot as plt
first_arg = {
'Introversion': 17, 'Intuition': 34, 'Feeling': 29, 'Perceiving': 18,
'Extraversion': 27, 'Sensing': 25, 'Thinking': 23, 'Judging': 16
}
second_arg = {
'Introversion': 16, 'Intuition': 25, 'Feeling': 31, 'Perceiving': 15,
'Extraversion': 22, 'Sensing': 29, 'Thinking': 23, 'Judging': 23
}
def plot_scales_chart(*args):
scales = [
'Introversion', 'Intuition', 'Feeling', 'Perceiving',
'Extraversion', 'Sensing', 'Thinking', 'Judging'
]
angles = [n / float(len(scales)) * 2 * pi for n in range(len(scales))]
angles += angles[:1]
mpl.use('agg')
ax = plt.subplot(polar=True)
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
plt.xticks(angles[:-1], scales)
ax.tick_params(axis='x', which='major', pad=15)
ax.set_rlabel_position(0)
plt.yticks([15, 25], ["15", "25"], color="grey", size=8)
plt.ylim(0, 35)
colors = ['#5159be', '#86e5c7']
for i, arg in enumerate(args):
values = []
for scale in scales:
values.append(arg[scale])
values += values[:1]
ax.plot(angles, values, alpha=0.7, color=colors[i], linewidth=0, linestyle='solid')
ax.fill(angles, values, colors[i], alpha=0.7)
plt.savefig('chart.png')
import matplotlib.pyplot as plt
import numpy as np
x = np.array([6, 15, 24, 33, 41, 52, 59, 66, 73, 81])
y = np.array([5, 10, 15, 20, 25, 30, 35, 40, 45, 50])
coef = np.polyfit(x, y, 1)
poly1d_fn = np.poly1d(coef) # to create a linear function with coefficients
plt.plot(x, y, 'ro', x, poly1d_fn(x), '-b')
plt.errorbar(x, poly1d_fn(x), yerr=poly1d_fn(x) - y, fmt='.k')
plt.show()
I have a working code which produces based upon my input a graph with error bars and the regression line. That's all fine. Now what I wanted to do is add a text box below and once a user inputs a number, e.g. 12 it outputs the according value (re regression line).
left, bottom, width, height = 0.15, 0.02, 0.7, 0.10
plt.subplots_adjust(left=left, bottom=0.25) # Make space for the slider
input_field = plt.axes([left, bottom, width, height])
box = TextBox(input_field, 'value')
I tried it with this approach. Though being unsuccessful: I can't get it to take a value and output it on the GUI interface matplotlib provides. The field would need to be checked for every input. Matplotlib offers on_text_change(self, func)or on_submit(self, func), so that might be working - but how to output?
Does anyone have an idea?
I would use a simple Text artist to display the result. But being fancy, I would also display lines on the graph showing the input and output values.
import matplotlib.pyplot as plt
import numpy as np
x = np.array([6, 15, 24, 33, 41, 52, 59, 66, 73, 81])
y = np.array([5, 10, 15, 20, 25, 30, 35, 40, 45, 50])
coef = np.polyfit(x, y, 1)
poly1d_fn = np.poly1d(coef) # to create a linear function with coefficients
def submit(val):
try:
x = float(val)
y = poly1d_fn(x)
ax.annotate('', xy=(x,0), xycoords=('data','axes fraction'),
xytext=(x,y), textcoords='data',
arrowprops=dict(arrowstyle='-', ls='--'))
ax.annotate(f'{x:.2f}', xy=(x,0), xycoords=('data','axes fraction'))
ax.annotate('', xy=(0,y), xycoords=('axes fraction','data'),
xytext=(x,y), textcoords='data',
arrowprops=dict(arrowstyle='-', ls='--'))
ax.annotate(f'{y:.2f}', xy=(0,y), xycoords=('axes fraction','data'))
output_box.set_text(f'Result = {y:.2f}')
plt.draw()
except ValueError:
pass
fig, ax = plt.subplots()
ax.plot(x, y, 'ro', x, poly1d_fn(x), '-b')
ax.errorbar(x, poly1d_fn(x), yerr=poly1d_fn(x) - y, fmt='.k')
left, bottom, width, height, pad = 0.15, 0.02, 0.3, 0.10, 0.1
fig.subplots_adjust(left=left, bottom=0.25) # Make space for the slider
input_field = fig.add_axes([left, bottom, width, height])
text_box = matplotlib.widgets.TextBox(input_field, 'value')
text_box.on_submit(submit)
output_box = fig.text(left+width+pad, bottom+height/2, s='Result = ', va='center')
I'm trying to use seaborn to create a colored bubbleplot of 3-D points (x,y,z), each coordinate being an integer in range [0,255]. I want the axes to represent x and y, and the hue color and size of the scatter bubbles to represent the z-coordinate.
The code:
import seaborn
seaborn.set()
import pandas
import matplotlib.pyplot
x = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200]
y = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200]
z = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200]
df = pandas.DataFrame(list(zip(x, y, z)), columns =['x', 'y', 'z'])
ax = seaborn.scatterplot(x="x", y="y",
hue="z",
data=df)
matplotlib.pyplot.xlim(0,255)
matplotlib.pyplot.ylim(0,255)
matplotlib.pyplot.show()
gets me pretty much what I want:
This however makes the hue range be based on the data in z. I instead want to set the range according to the range of the min and max z values (as 0,255), and then let the color of the actual points map onto that range accordingly (so if a point has z-value 50, then that should be mapped onto the color represented by the value 50 in the range [0,255]).
My summarized question:
How to manually set the hue color range of a numerical variable in a scatterplot using seaborn?
I've looked thoroughly online on many tutorials and forums, but have not found an answer. I'm not sure I've used the right terminology. I hope my message got across.
Following #JohanC's suggestion of using hue_norm was the solution. I first tried doing so by removing the [hue=] parameter and only using the [hue_norm=] parameter, which didn't produce any colors at all (which makes sense).
Naturally one should use both the [hue=] and the [hue_norm=] parameters.
import seaborn
seaborn.set()
import pandas
import matplotlib.pyplot
x = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200]
y = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200]
z = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 255]
df = pandas.DataFrame(list(zip(x, y, z, my_sizes)), columns =['x', 'y', 'z'])
ax = seaborn.scatterplot(x="x", y="y",
hue="z",
hue_norm=(0,255), # <------- the solution
data=df)
matplotlib.pyplot.xlim(0,255)
matplotlib.pyplot.ylim(0,255)
matplotlib.pyplot.show()
I'm to Python and learning it by doing. I want to make two plots with matplotlib in Python. The second plot keeps the limits of first one. Wonder how I can change the limits of each next plot from previous. Any help, please. What is the recommended method?
X1 = [80, 100, 120, 140, 160, 180, 200, 220, 240, 260]
Y1 = [70, 65, 90, 95, 110, 115, 120, 140, 155, 150]
from matplotlib import pyplot as plt
plt.plot(
X1
, Y1
, color = "green"
, marker = "o"
, linestyle = "solid"
)
plt.show()
X2 = [80, 100, 120, 140, 160, 180, 200]
Y2 = [70, 65, 90, 95, 110, 115, 120]
plt.plot(
X2
, Y2
, color = "green"
, marker = "o"
, linestyle = "solid"
)
plt.show()
There are two ways:
The quick and easy way; set the x and y limits in each plot to what you want.
plt.xlim(60,200)
plt.ylim(60,200)
(for example). Just paste those two lines just before both plt.show() and they'll be the same.
The harder, but better way and this is using subplots.
# create a figure object
fig = plt.figure()
# create two axes within the figure and arrange them on the grid 1x2
ax1 = fig.add_Subplot(121)
# ax2 is the second set of axes so it is 1x2, 2nd plot (hence 122)
# they won't have the same limits this way because they are set up as separate objects, whereas in your example they are the same object that is being re-purposed each time!
ax2 = fig.add_Subplot(122)
ax1.plot(X1,Y1)
ax2.plot(X2,Y2)
Here is one way for you using subplot where plt.subplot(1, 2, 1) means a figure with 1 row (first value) and 2 columns (second value) and 1st subfigure (third value in the bracket, meaning left column in this case). plt.subplot(1, 2, 2) means subplot in the 2nd column (right column in this case).
This way, each figure will adjust the x- and y-limits according to the data. There are another ways to do the same thing. Here is a SO link for you.
from matplotlib import pyplot as plt
fig = plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
X1 = [80, 100, 120, 140, 160, 180, 200, 220, 240, 260]
Y1 = [70, 65, 90, 95, 110, 115, 120, 140, 155, 150]
plt.plot(X1, Y1, color = "green", marker = "o", linestyle = "solid")
# plt.plot(X1, Y1, '-go') Another alternative to plot in the same style
plt.subplot(1, 2, 2)
X2 = [80, 100, 120, 140, 160, 180, 200]
Y2 = [70, 65, 90, 95, 110, 115, 120]
plt.plot(X2, Y2, color = "green", marker = "o", linestyle = "solid")
# plt.plot(X2, Y2, '-go') Another alternative to plot in the same style
Output
So I've got some data which I wish to plot via a frequency density (unequal class width) histogram, and via some searching online, I've created this to allow me to do this.
import numpy as np
import matplotlib.pyplot as plt
plt.xkcd()
freqs = np.array([3221, 1890, 866, 529, 434, 494, 382, 92, 32, 7, 7])
bins = np.array([0, 5, 10, 15, 20, 30, 50, 100, 200, 500, 1000, 1500])
widths = bins[1:] - bins[:-1]
heights = freqs.astype(np.float)/widths
plt.xlabel('Cost in Pounds')
plt.ylabel('Frequency Density')
plt.fill_between(bins.repeat(2)[1:-1], heights.repeat(2), facecolor='steelblue')
plt.show()
As you may see however, this data stretches into the thousands on the x axis and on the y axis (density) goes from tiny data (<1) to vast data (>100). To solve this I will need to break both axis. The closest to help I've found so far is this, which I've found hard to use. Would you be able to help?
Thanks, Aj.
You could just use a bar plot. Setting the xtick labels to represent the bin values.
With logarithmic y scale
import numpy as np
import matplotlib.pyplot as plt
plt.xkcd()
fig, ax = plt.subplots()
freqs = np.array([3221, 1890, 866, 529, 434, 494, 382, 92, 32, 7, 7])
freqs = np.log10(freqs)
bins = np.array([0, 5, 10, 15, 20, 30, 50, 100, 200, 500, 1000, 1500])
width = 0.35
ind = np.arange(len(freqs))
rects1 = ax.bar(ind, freqs, width)
plt.xlabel('Cost in Pounds')
plt.ylabel('Frequency Density')
tick_labels = [ '{0} - {1}'.format(*bin) for bin in zip(bins[:-1], bins[1:])]
ax.set_xticks(ind+width)
ax.set_xticklabels(tick_labels)
fig.autofmt_xdate()
plt.show()