want matplotlib slider plot called from class [duplicate] - python-3.x

I am trying to draw a scatter plot with a point that moves based on a parameter adjusted by a slider. I need the parameter to be the position in a list of the coordinates. I have it so the scatter plot gets drawn and I can manually move the point by change the position, but when I try to implement the slider it is displayed, but can not be drug to update the plot. Any help would be great. What I have so far is below. Thanks.
%pylab
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import animation
def on_change(val):
p=int(val)/1
def chart():
x=[0,0.5,1]
y=[0,0.5,1]
z=[0,0.5,1]
p=0
fig = pyplot.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot([0,0,0,0,0,1,1,0,0,1,1,1,1,1,1,0],[0,1,1,0,0,0,0,0,1,1,0,0,1,1,1,1],[0,0,1,1,0,0,1,1,1,1,1,0,0,1,0,0],c='black',zorder=10)
ax.scatter(x[p],y[p],z[p],zorder=0)
ax.set_xlabel('Width')
ax.set_ylabel('Depth')
ax.set_zlabel('Height')
slider_ax = plt.axes([0.15, 0.05, 0.7, 0.02])
slider = Slider(slider_ax, "min", 0, 2, valinit=1, color='blue')
pyplot.show()
chart()

You have to keep a reference to the Slider object around or it (and it's call backs) get garbage collected. See long discussion at https://github.com/matplotlib/matplotlib/issues/3105.
The documentation on this has been clarified for 1.4.

Related

How to combine two geometries into one plot in Python

Question background: I am trying to make two geometries in a one plot in python. I have made one geometry which is an object having mesh as shown in figure below. The respective code is also mentioned here.
df_1_new = pd.DataFrame()
df_1_new['X_coordinate']=pd.Series(x_new)
df_1_new['Y_coordinate']=pd.Series(y_new)
df_1_new['node_number'] = df_1_new.index
df_1_new = df_1_new[['node_number','X_coordinate','Y_coordinate']]
plt.scatter(x_new, y_new)
plt.show
The second geometry, which is a circle and I made this geometry running below code.
from matplotlib import pyplot as plt, patches
plt.rcParams["figure.figsize"] = [9.00, 6.50]
plt.rcParams["figure.autolayout"] = True
fig = plt.figure()
ax = fig.add_subplot()
circle1 = plt.Circle((2, 2), radius=5, fill = False)
ax.add_patch(circle1)
ax.axis('equal')
plt.show()
My question: How can I combine both geometries mentioned above in a one plot. I would like to place my circle around my geometry (object). Geometry has a centroid (2, 2) and I want to place my circle's centroid exactly on the centroid of geometry therefore I will be having a circle around my geometry. What code I should write. Kindly help me on this.
For your reference: I want my plot just like in below picture.
you need to do all the plotting between the subplot creation and before you issue the plt.show() command, as any command after it will create a new figure.
from matplotlib import pyplot as plt, patches
plt.rcParams["figure.figsize"] = [9.00, 6.50]
plt.rcParams["figure.autolayout"] = True
fig = plt.figure()
ax = fig.add_subplot()
# other plt.scatter or plt.plot here
plt.scatter([3,4,5,6,4],[5,4,2,3,2]) # example
circle1 = plt.Circle((2, 2), radius=5, fill = False)
ax.add_patch(circle1)
ax.axis('equal')
plt.show()
image example
to get the points inside the circle, you need to play with the circle radius and center till you get it right.
something you can do is to make the circle at the np.median of your x and y values, so you are sure about the center position.

Using "hue" for a Seaborn visual: how to get legend in one graph?

I created a scatter plot in seaborn using seaborn.relplot, but am having trouble putting the legend all in one graph.
When I do this simple way, everything works fine:
import pandas as pd
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
import seaborn as sns
df2 = df[df.ln_amt_000s < 700]
sns.relplot(x='ln_amt_000s', y='hud_med_fm_inc', hue='outcome', size='outcome', legend='brief', ax=ax, data=df2)
The result is a scatter plot as desired, with the legend on the right hand side.
However, when I try to generate a matplotlib figure and axes objects ahead of time to specify the figure dimensions I run into problems:
a4_dims = (10, 10) # generating a matplotlib figure and axes objects ahead of time to specify figure dimensions
df2 = df[df.ln_amt_000s < 700]
fig, ax = plt.subplots(figsize = a4_dims)
sns.relplot(x='ln_amt_000s', y='hud_med_fm_inc', hue='outcome', size='outcome', legend='brief', ax=ax, data=df2)
The result is two graphs -- one that has the scatter plots as expected but missing the legend, and another one below it that is all blank except for the legend on the right hand side.
How do I fix this such? My desired result is one graph where I can specify the figure dimensions and have the legend at the bottom in two rows, below the x-axis (if that is too difficult, or not supported, then the default legend position to the right on the same graph would work too)? I know the problem lies with "ax=ax", and in the way I am specifying the dimensions as matplotlib figure, but I'd like to know specifically why this causes a problem so I can learn from this.
Thank you for your time.
The issue is that sns.relplot is a "Figure-level interface for drawing relational plots onto a FacetGrid" (see the API page). With a simple sns.scatterplot (the default type of plot used by sns.relplot), your code works (changed to use reproducible data):
df = pd.read_csv("https://vincentarelbundock.github.io/Rdatasets/csv/datasets/iris.csv", index_col=0)
fig, ax = plt.subplots(figsize = (5,5))
sns.scatterplot(x = 'Sepal.Length', y = 'Sepal.Width',
hue = 'Species', legend = 'brief',
ax=ax, data = df)
plt.show()
Further edits to legend
Seaborn's legends are a bit finicky. Some tweaks you may want to employ:
Remove the default seaborn title, which is actually a legend entry, by getting and slicing the handles and labels
Set a new title that is actually a title
Move the location and make use of bbox_to_anchor to move outside the plot area (note that the bbox parameters need some tweaking depending on your plot size)
Specify the number of columns
fig, ax = plt.subplots(figsize = (5,5))
sns.scatterplot(x = 'Sepal.Length', y = 'Sepal.Width',
hue = 'Species', legend = 'brief',
ax=ax, data = df)
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles=handles[1:], labels=labels[1:], loc=8,
ncol=2, bbox_to_anchor=[0.5,-.3,0,0])
plt.show()

How to change the font weight of individual colorbar labels?

I would like to have different font weights for each of my colorbar labels.
I have tried to let LaTeX format the labels in the following way:
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
im = ax.imshow(np.random.rand(50, 50)/20)
cbar = ax.figure.colorbar(im, ticks=np.arange(0, 0.05, 0.01))
cbar.ax.set_yticklabels([r'{\fontsize{50pt}{3em}\selectfont{}{0}}',
r'{\fontsize{40pt}{3em}\selectfont{}{0.01}}',
r'{\fontsize{30pt}{3em}\selectfont{}{0.03}}',
r'{\fontsize{20pt}{3em}\selectfont{}{0.03}}',
r'{\fontsize{10pt}{3em}\selectfont{}{0.04}}',
r'{\fontsize{1pt}{3em}\selectfont{}{0.05}}', ])
but this only updates the text of the labels to the whole string (e.g., {\fontsize{50pt}{3em}\selectfont{}{0}}). The pyplot TeX demo works for me. Even if this solution would work it would not be ideal as I would probably need to specify everything manually.
Much more convenient would be something like in this question. There, I learned that the font size of single labels of the regular x and y axis can be updated by calling
label = axes.yaxis.get_major_ticks()[2].label
label.set_fontsize(size)
replacing set_fontsize by set_fontweight correctly updates the weight of the selected label.
Unfortunately I could not find the equivalent of axes.yaxis.get_major_ticks()[2].label for the colorbar.
Is it possible to change the font weight of individual labels of the colorbar directly? With directly I mean without using a workaround like plotting some new text above existing labels.
If this is not possible a solution plotting text above existing labels which automatically uses the position and content the previous labels and only adjusts the font weight would also be appreciated.
Thanks!
As pointed out by #ImportanceOfBingErnest , set_fontweight works for setting the weight of single colorbar labels too.
I had to try a couple of things to find which call would give me the text objects defining the colorbar labels. They are accessible in cbar.ax.get_yticklabels().
The code snippet below now properly changes the weight of the second colorbar label:
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
im = ax.imshow(np.random.rand(50, 50)/20)
cbar = ax.figure.colorbar(im, ticks=np.arange(0, 0.05, 0.01))
cbar.ax.get_yticklabels()[1].set_fontweight(1000)
plt.show()
Output of code (not enough reputation for inline images)

How to position a mpl_toolkits's "AnchoredSizeBar" outside its given axes

I am facing serious difficulties in placing a AnchoredSizeBar outside its given axes. From the AnchoredSizeBar reference, the loc attribute accepts only 'string' methods that are relative to the given axes used for the AnchoredSizeBar creation.
Therefore, if I wanted to set the AnchoredSizeBar position outside the given axes, the loc attribute wouldn't work. In fact, it would raise an error message.
Would someone knows a way to circumvent that problem?
If possible, I would like to create a AnchoredSizeBar, whose bar size is yet relative to a given axes in the figure, but the AnchoredSizeBar location can be placed anywhere inside the figure instance.
Here is a code snipped of what I would like:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.anchored_artists import AnchoredSizeBar
fig, ax = plt.subplots(figsize=(3, 3))
x_position = 0.15
y_position = 0.35
Figure_location = (x_position, y_position) # figure xy locations relative to fig.transFigure.
axes_width_to_size_bar = 0.3
bar0 = AnchoredSizeBar(ax.transData, axes_width_to_size_bar, 'unfilled', loc=Figure_location, frameon=False, size_vertical=0.05, fill_bar=False)
ax.add_artist(bar0)
bar0_extent = bar0.get_extent()
fig.show()
I thank you for your time. Sincerely yours,
Philipe Riskalla Leal
AnchoredSizeBar subclasses matplotlib.offsetbox.AnchoredOffsetbox. Additional arguments are hence passed on to AnchoredOffsetbox. This provides arguments bbox_to_anchor and bbox_transform. Those are the same as you have for legends, so for explanations see any legend example, e.g. How to put the legend out of the plot.
For example, to put the AnchoredSizeBar in the upper right corner of the figure,
import matplotlib.pyplot as plt
def draw_sizebar(ax):
from mpl_toolkits.axes_grid1.anchored_artists import AnchoredSizeBar
from matplotlib.transforms import Bbox
asb = AnchoredSizeBar(ax.transData,
0.1,
"5 warp units",
loc='upper right',
pad=0.1, borderpad=0.5, sep=5,
frameon=False,
bbox_to_anchor=Bbox.from_bounds(0, 0, 1, 1),
bbox_transform=ax.figure.transFigure)
ax.add_artist(asb)
fig, ax = plt.subplots()
draw_sizebar(ax)
plt.show()

Adding pie chart at given coordinates to cartopy projection

I am a beginner in data visualization, and even more with cartopy, I know for most of people my question would be obvious. I am trying to get familiar with cartopy and I successfully plot text and point. But I couldn't achieve it for pie chart.
I just want to plot pie chart on a particular projection. But I am really confuse, despite the documentation of cartopy. I have first try this:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
ax = plt.axes(projection=ccrs.Robinson())
ax.coastlines(resolution='110m') # 110, 50, 10
ax.stock_img()
lat, long = 30, 30 # the latitude longitude
ax.pie(long, lat, [0.25, 0.75], transform=ccrs.PlateCarree())
That do not work, So I have checked and I found this Cartopy coastlines hidden by inset_axes use of Axes.pie but I do not understand what happend under the hood and furthermore it seems limited to PlateCarre(). I have try to modified it but I do not managed to get it work properly.
So my very simple question is How can I add several pie chart to a specific projection given latitude and longitude? If you can develop your answer you will be really welcome.
You can use an inset_axes to place a new axes into the plot, which will allow to host the pie chart. The position of the inset_axes is determined by the bbox_to_anchor argument. To have this argument use the coordinates of the projection of the cartopy axes (ax), you need to set the bbox_transform=ax.transData.
If you have your coordinates in a different coordinate system, you need to convert them to the one in use using the projection's .transform_point method first.
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
ax = plt.axes(projection=ccrs.Robinson())
ax.coastlines(resolution='110m')
ax.stock_img()
def plot_pie_inset(data,ilon,ilat,ax,width):
ax_sub= inset_axes(ax, width=width, height=width, loc=10,
bbox_to_anchor=(ilon, ilat),
bbox_transform=ax.transData,
borderpad=0)
wedges,texts= ax_sub.pie(data)
ax_sub.set_aspect("equal")
lon,lat = 90,30
lonr,latr = ccrs.Robinson().transform_point(lon,lat, ccrs.PlateCarree())
plot_pie_inset([0.25, 0.75],lonr,latr,ax,0.5)
plt.show()

Resources