python crash when use xtics in PyQt5 [duplicate] - python

So I am trying to use Axes objects to control my matlibplot figure. I am not using plt (aka import matlibplot.pyplot as plt) because I am embedding the figure in my tkinter GUI per this.
However, I am also using subplots in the figure, so something like:
a = f.add_subplot(121)
a2 = f.add_subplot(122)
a.plot(fn2,mag)
a2.bar(range(0,10), magBin, width)
This is all well and good, I can use the axes properties to control things (i.e. a.axesMethod()), but I want string labels for my bar plots, per this, see code.
My dilemma is that I cannot use
plt.xticks(ind+width, ('G1', 'G2', 'G3', 'G4', 'G5') )
as in the example, because I cannot use plt if i want to embed it into my tkinter gui. I am limited to what I can do with Axes objects. I am trying to use
a2.set_xticks, but this does not allow for the string as ticks functionality I need for my bar chart.
Any help in this regard would be amazing!
Tyler

you can use instead:
axes.set_xticks(ticks, minor=False)
and
axes.set_xticklabels(labels, fontdict=None, minor=False)

Related

Seaborn plots, legend overlaps figure

Using Seaborn, my legend keeps overlapping the data, no matter what dataframe I use, or whether I use pairplots or jointgrids. I know I can work around this by removing Seaborn's legend and making a custom legend, however, that's not the "cleanest" route. How can I get Seaborn to create non-overlapping legends ?
Here some code:
g = sns.pairplot(df, kind="reg", plot_kws={"marker": "+"}, hue="experiment", palette="Set2", x_vars=["alpha [%]", "shelter [%]", "beta [%]"], y_vars=["final [%]"])
plt.show()
(btw I'm on Mac OS, Pycharm, Python 3.6seaborn 0.10.0 and matplotlib 3.3.3)
It seems you can not do it with pairplot. In the docs they say:
This is a high-level interface for PairGrid that is intended to make it easy to draw a few common styles. You should use PairGrid directly if you need more flexibility.
Taking this PairGrid example from the docs, you can pass the loc parameter to the add_legend() method.
g = sns.PairGrid(penguins, hue="species")
g.map_diag(sns.histplot)
g.map_offdiag(sns.scatterplot)
g.add_legend(loc=(0.9,0.2)) # or g.add_legend(loc="upper right");
plt.show()
The arguments you can pass to the loc parameter are listed in the Matplotlib docs.

How to update projection of GeoAxes using Cartopy?

I'm trying to make a somewhat interactive map plot with matplotlib utilizing a button added to the toolbar in Matplotlib's navigation Toolbar.
The objective:
The objective that I'm trying to achieve is to be able to change the axes projection on the fly without creating a new axes. There are many methods in the axes object that gets created by Matplotlib to change other aspects of the plot, but I want to be able to change projection from say,
PlateCarree to NorthPolarStereo and vice versa.
Some Source:
import os
import sys
import matplotlib.pyplot as plt
import matplotlib
import mpl_toolkits
import numpy as np
import cartopy
import cartopy.crs as ccrs
fig = plt.figure()
ax = plt.axes(projection=ccrs.NorthPolarStereo())
ax.stock_img()
ny_lon, ny_lat = -75, 43
delhi_lon, delhi_lat = 77.23, 28.61
plt.plot([ny_lon, delhi_lon], [ny_lat, delhi_lat],
color='blue', linewidth=2, marker='o',
transform=ccrs.Geodetic(),
)
plt.plot([ny_lon, delhi_lon], [ny_lat, delhi_lat],
color='gray', linestyle='--',
transform=ccrs.PlateCarree(),
)
ax.add_patch(matplotlib.patches.Polygon([[0,0],[20,0],[20,20],[0,20]],
fill = False,color='g',ls='--',
transform=ccrs.PlateCarree()))
ax.add_patch(matplotlib.patches.Circle([30,30],radius=10,color='g',ls='--',
transform=ccrs.PlateCarree()))
plt.text(ny_lon - 3, ny_lat - 12, 'New York',
horizontalalignment='right',
transform=ccrs.Geodetic())
plt.text(delhi_lon + 3, delhi_lat - 12, 'Delhi',
horizontalalignment='left',
transform=ccrs.Geodetic())
# ax.set_extent([-180,180,-90,90])
ax.set_global()
The problem:
As can be seen, the axes is created with a projection = ccrs.NorthPolarStereo().
The projection of the axes can be obtained by executing the following:
ax.projection
Then, I try setting the projection to ccrs.PlateCarree()
ax.projection = ccrs.PlateCaree()
This alone does not update the plot, however. I have noticed that in editing some of the properties you need to draw the canvas again with
ax.figure.canvas.draw()
however, this doesn't seem to have an effect. But if I do
ax.set_global()
to set the extent to the maximum, the axes updates and changes to the correct projection... however, the data on the plot does not get updated again. Yet calling
ax.projection
indicates that the projection is now a PlateCarree projection.
How can I update the children of the axes to reflect this new projection?
I have tried
ax.update(ax.properties())
as per the matplotlib dox, however, it throws an error.
Any Ideas?
Edit:
If it is not obvious... You will need to run this in an iPython console and run those extra commands while the figure is open in order to edit it. And it must be done this way in order to achieve what I want to do. I know I can just make a new axes with a new projection, however, the end goal of this project is to maintain this axes. This is for editing and different viewing purposes that my project requires. Also, I'm stuck using matplotlib and cartopy, so no new library recommendations for plotting, please.
In reading this question I notice that I use 'however' way too often.

how to make easy and efficient plots on Python

I use matplotlib for my plots, I find it great, but sometimes too much complicated. Here an example:
import matplotlib.pyplot as plt
import numpy as np
idx1 = -3
idx2 = 3
x = np.arange(-3, 3, 0.01)
y = np.sin(np.pi*x*7)/(np.pi*x*7)
major_ticks = np.arange(idx1, idx2, 1)
minor_ticks = np.arange(idx1, idx2, 0.1)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_ylim(-0.3, 1.2)
ax.set_xlim(idx1, idx2)
ax.set_xticks(major_ticks)
ax.set_xticks(minor_ticks, minor = True)
ax.grid(True, which = 'both')
ax.tick_params(axis = 'x', labelsize = 18)
ax.tick_params(axis = 'y', labelsize = 18)
ax.plot(x, y)
plt.show()
Is there anything implemented on matplotlib and/or seaborn in which I can provide all these plot settings just as argument of a function only? It may considerably reduce the number of code lines and make the script easier both to write and understand.
Matplotlib provides an object oriented API. This means that all the elements of the figure are acutally objects for which one can get and set properties and which can be easily manipulated. This makes matplotlib really flexible such that it can produce almost any plot you'd imagine.
Since a plot may consist of a hundred or more elements, a function that would allow the same flexibility would need that amount of possible arguments. It is not necessarily easier to remember all possible arguments of a function than all possible attributes of a class.
Having a single function call that does all of this, does not necessarily mean that you have to type in less characters. The commands would just be ordered differently.
Furthermore the object oriented approach allows to keep things seperate. Some properties of the axes, like the grid or the axis labels are completely independend on what you plot to the axes. So you wouldn't want to set the xticks in the call to plot, because they are simply not related and it may be very confusing to set twice the same ticklabels when plotting two lines in the same axes.
On the other hand, matplotlib is really easy. In order to produce a plot you need two lines
import matplotlib.pyplot as plt
plt.plot([1,2,3],[2,1,3])
which sets most of the parameters exactly as they are needed. The more you want to customize this plot, the more settings you have to apply. Which is fine as it allows the user himself to determine how much in depth he wants to control the appearance of the plot.
Most matplotlib codes can be separated into three parts.
Setting the style
Creating the plot
Customizing the plot
Setting the style in the case of the code from the question involves e.g. the ticklabel size and the use of a grid. Those properties can set as it's done in the code but it may indeed be that one always wants to use the same properities here and finds it annoying to type the same parameters in every time one creates a plot. Therefore matplotlib provides general style settings, called rcParams. They can be set at the beginning of a script, e.g.
plt.rcParams['lines.linewidth'] = 2
plt.rcParams['axes.grid '] = True
plt.rcParams['axes.labelsize'] = 18
and will be applied to all plots within the script. It is also possible to define a complete stylesheet using those parameters. For more information see the Customizing matplotlib article.
It is equally possible to use predefined stylesheets for certain applications.
Simply importing import seaborn is also a possible way to change the style.
Creating the plot can not be simplified much more. It's clear that one needs as many plotting commands as items to plot. Creating the figure and axes like
fig, ax = plt.subplots()
saves one line though.
Equally no simplification is possible if customizing ticks or tickmarks are required. One may however consider to use Tickers and Formatters for this purpose.
At the end one may of course consider to write a custom function which performs much of those tasks, but everyone can decide if that is useful for himself.
Browsing around I saw this wabe page.
This line of code can summarise many settings
import matplotlib as mpl
mpl.rc('lines', linewidth=2, color='r')
ax.set is very useful for this:
ax.set(xlim=(idx1, idx2), ylim=(-0.3, 1.2),
xticks=major_ticks, ...)
You can only set simple single-argument properties (e.g. those which don't need further keywords), but it's a nice timesaver.

Can matplotlib lib annotate / add arrow to a FIGURE not an AXIS?

Is it possible to add an arrow to a figure in matplotlib, rather than an axis please?
I have a multi-component figure containing numerous axes, and want to be able to draw arrows between them. However, if I do this manually by setting the ax.arrow() to extend out of the axis, then it is cropped and doesn't show.
Thanks
if you set clip_on = False for your ax.arrow, it should extend outside the axis
Heres a minimal example:
import matplotlib.pyplot as plt
fig,ax=plt.subplots(1)
ax.arrow(0.5,0.6,0.55,0.,fc='r',ec='r',clip_on=True)
ax.arrow(0.5,0.4,0.55,0.,fc='b',ec='b',clip_on=False)
plt.show()

Matplotlib can't suppress figure window

I'm having trouble with matplotlib insisting on displaying a figure wnidow even when I haven't called show().
The function in question is:
def make_plot(df):
fig, axes = plt.subplots(3, 1, figsize=(10, 6), sharex=True)
plt.subplots_adjust(hspace=0.2)
axes[0].plot(df["Date_Time"], df["T1"], df["Date_Time"], df["T2"])
axes[0].set_ylabel("Temperature (C)")
axes[0].legend(["T1", "T2"], bbox_to_anchor=(1.12, 1.1))
axes[1].semilogy(df["Date_Time"], df["IGP"], df["Date_Time"], df["IPP"])
axes[1].legend(["IGP", "IPP"], bbox_to_anchor=(1.12, 1.1))
axes[1].set_ylabel("Pressure (mBar)")
axes[2].plot(df["Date_Time"], df["Voltage"], "k")
axes[2].set_ylabel("Voltage (V)")
current_axes = axes[2].twinx()
current_axes.plot(df["Date_Time"], df["Current"], "r")
current_axes.set_ylabel("Current (mA)")
axes[2].legend(["V"], bbox_to_anchor=(1.15, 1.1))
current_axes.legend(["I"], bbox_to_anchor=(1.14, 0.9))
plt.savefig("static/data.png")
where df is a dataframe created using pandas. This is supposed to be in the background of a web server, so all I want is for this function to drop the file in the directory specified. However, when it executes it does this, and then pulls up a figure window and gets stuck in a loop, preventing me from reloading the page. Am I missing something obvious?
EDIT: Forgot to add, I am running python 2.7 on Windows 7, 64 bit.
Step 1
Check whether you're running in interactive mode. The default is non-interactive, but you may never know:
>>> import matplotlib as mpl
>>> mpl.is_interactive()
False
You can set the mode explicitly to non-interactive by using
>>> from matplotlib import pyplot as plt
>>> plt.ioff()
Since the default is non-interactive, this is probably not the problem.
Step 2
Make sure your backend is a non-gui backend. It's the difference between using Agg versus TkAgg, WXAgg, GTKAgg etc, the latter being gui backends, while Agg is a non-gui backend.
You can set the backend in a number of ways:
in your matplotlib configuration file; find the line starting with backend:
backend: Agg
at the top of your program with the global matplotlib function use:
matplotlib.use('Agg')
import the canvas directly from the correct backend; this is most useful in non-pyplot "mode" (OO-style), which is what I often use, and for a webserver style of use, that may in the end prove best (since this is a tad different than above, here's a full-blown short example):
import numpy as np
from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
figure = Figure()
canvas = FigureCanvas(figure)
axes = figure.add_subplot(1, 1, 1)
axes.plot(x, np.sin(x), 'k-')
canvas.print_figure('sine.png')
Perhaps just clear the axis, for example:
plt.savefig("static/data.png")
plt.close()
will not plot the output in inline mode. I can't work out if is really clearing the data though.
use below:
plt.rcParams['figure.subplot.hspace'] = 0.002
## The figure subplot parameters. All dimensions are a fraction of the figure width and height.
#figure.subplot.left: 0.125 # the left side of the subplots of the figure
#figure.subplot.right: 0.9 # the right side of the subplots of the figure
#figure.subplot.bottom: 0.11 # the bottom of the subplots of the figure
#figure.subplot.top: 0.88 # the top of the subplots of the figure
#figure.subplot.wspace: 0.2 # the amount of width reserved for space between subplots,
# expressed as a fraction of the average axis width
#figure.subplot.hspace: 0.2 # the amount of height reserved for space between subplots,
# expressed as a fraction of the average axis height
instead of
plt.subplots_adjust(hspace=0.2)
reference urls:
Customizing Matplotlib with style sheets and rcParams
matplotlib.pyplot.subplots_adjust

Categories

Resources